xref: /freebsd/sys/netgraph/ng_async.c (revision 74f5c6aa25752d28460c90aefa625ec0f75e3505)
14cf49a43SJulian Elischer 
24cf49a43SJulian Elischer /*
34cf49a43SJulian Elischer  * ng_async.c
44cf49a43SJulian Elischer  *
54cf49a43SJulian Elischer  * Copyright (c) 1996-1999 Whistle Communications, Inc.
64cf49a43SJulian Elischer  * All rights reserved.
74cf49a43SJulian Elischer  *
84cf49a43SJulian Elischer  * Subject to the following obligations and disclaimer of warranty, use and
94cf49a43SJulian Elischer  * redistribution of this software, in source or object code forms, with or
104cf49a43SJulian Elischer  * without modifications are expressly permitted by Whistle Communications;
114cf49a43SJulian Elischer  * provided, however, that:
124cf49a43SJulian Elischer  * 1. Any and all reproductions of the source or object code must include the
134cf49a43SJulian Elischer  *    copyright notice above and the following disclaimer of warranties; and
144cf49a43SJulian Elischer  * 2. No rights are granted, in any manner or form, to use Whistle
154cf49a43SJulian Elischer  *    Communications, Inc. trademarks, including the mark "WHISTLE
164cf49a43SJulian Elischer  *    COMMUNICATIONS" on advertising, endorsements, or otherwise except as
174cf49a43SJulian Elischer  *    such appears in the above copyright notice or in the software.
184cf49a43SJulian Elischer  *
194cf49a43SJulian Elischer  * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
204cf49a43SJulian Elischer  * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
214cf49a43SJulian Elischer  * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
224cf49a43SJulian Elischer  * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
234cf49a43SJulian Elischer  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
244cf49a43SJulian Elischer  * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
254cf49a43SJulian Elischer  * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
264cf49a43SJulian Elischer  * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
274cf49a43SJulian Elischer  * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
284cf49a43SJulian Elischer  * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
294cf49a43SJulian Elischer  * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
304cf49a43SJulian Elischer  * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
314cf49a43SJulian Elischer  * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
324cf49a43SJulian Elischer  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
334cf49a43SJulian Elischer  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
344cf49a43SJulian Elischer  * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
354cf49a43SJulian Elischer  * OF SUCH DAMAGE.
364cf49a43SJulian Elischer  *
374cf49a43SJulian Elischer  * Author: Archie Cobbs <archie@whistle.com>
384cf49a43SJulian Elischer  *
394cf49a43SJulian Elischer  * $FreeBSD$
4074f5c6aaSJulian Elischer  * $Whistle: ng_async.c,v 1.17 1999/11/01 09:24:51 julian Exp $
414cf49a43SJulian Elischer  */
424cf49a43SJulian Elischer 
434cf49a43SJulian Elischer /*
444cf49a43SJulian Elischer  * This node type implements a PPP style sync <-> async converter.
454cf49a43SJulian Elischer  * See RFC 1661 for details of how asynchronous encoding works.
464cf49a43SJulian Elischer  */
474cf49a43SJulian Elischer 
484cf49a43SJulian Elischer #include <sys/param.h>
494cf49a43SJulian Elischer #include <sys/systm.h>
504cf49a43SJulian Elischer #include <sys/kernel.h>
514cf49a43SJulian Elischer #include <sys/conf.h>
524cf49a43SJulian Elischer #include <sys/proc.h>
534cf49a43SJulian Elischer #include <sys/mbuf.h>
544cf49a43SJulian Elischer #include <sys/malloc.h>
554cf49a43SJulian Elischer #include <sys/socket.h>
564cf49a43SJulian Elischer #include <sys/file.h>
574cf49a43SJulian Elischer #include <sys/tty.h>
584cf49a43SJulian Elischer #include <sys/syslog.h>
594cf49a43SJulian Elischer #include <sys/errno.h>
604cf49a43SJulian Elischer 
614cf49a43SJulian Elischer #include <netgraph/ng_message.h>
624cf49a43SJulian Elischer #include <netgraph/netgraph.h>
634cf49a43SJulian Elischer #include <netgraph/ng_async.h>
644cf49a43SJulian Elischer 
654cf49a43SJulian Elischer #include <net/ppp_defs.h>
664cf49a43SJulian Elischer 
674cf49a43SJulian Elischer /* Optimize opening and closing flags into one? Set to max # seconds delay */
684cf49a43SJulian Elischer #define SYNC_OPT_TIME	1	/* one second maximum */
694cf49a43SJulian Elischer 
704cf49a43SJulian Elischer /* Async decode state */
714cf49a43SJulian Elischer #define MODE_HUNT	0
724cf49a43SJulian Elischer #define MODE_NORMAL	1
734cf49a43SJulian Elischer #define MODE_ESC	2
744cf49a43SJulian Elischer 
754cf49a43SJulian Elischer /* Private data structure */
764cf49a43SJulian Elischer struct private {
774cf49a43SJulian Elischer 	node_p  	node;		/* Our node */
784cf49a43SJulian Elischer 	hook_p  	async;		/* Asynchronous side */
794cf49a43SJulian Elischer 	hook_p  	sync;		/* Synchronous side */
804cf49a43SJulian Elischer 	hook_p  	sync2;		/* Synchronous side, full escapes */
814cf49a43SJulian Elischer 	u_char  	amode;		/* Async hunt/esape mode */
824cf49a43SJulian Elischer 	u_int16_t	fcs;		/* Decoded async FCS (so far) */
834cf49a43SJulian Elischer 	u_char	       *abuf;		/* Buffer to encode sync into */
844cf49a43SJulian Elischer 	u_char	       *sbuf;		/* Buffer to decode async into */
854cf49a43SJulian Elischer 	u_int		slen;		/* Length of data in sbuf */
864cf49a43SJulian Elischer #if SYNC_OPT_TIME
874cf49a43SJulian Elischer 	long		lasttime;	/* Time of last async packet sent */
884cf49a43SJulian Elischer #endif
894cf49a43SJulian Elischer 	struct		ng_async_cfg	cfg;	/* Configuration */
904cf49a43SJulian Elischer 	struct		ng_async_stat	stats;	/* Statistics */
914cf49a43SJulian Elischer };
924cf49a43SJulian Elischer typedef struct private *sc_p;
934cf49a43SJulian Elischer 
944cf49a43SJulian Elischer /* Useful macros */
954cf49a43SJulian Elischer #define ASYNC_BUF_SIZE(smru)	(2 * (smru) + 10)
964cf49a43SJulian Elischer #define SYNC_BUF_SIZE(amru)	((amru) + 10)
974cf49a43SJulian Elischer #define ERROUT(x)		do { error = (x); goto done; } while (0)
984cf49a43SJulian Elischer 
994cf49a43SJulian Elischer /* Netgraph methods */
10074f5c6aaSJulian Elischer static ng_constructor_t	nga_constructor;
10174f5c6aaSJulian Elischer static ng_rcvdata_t		nga_rcvdata;
10274f5c6aaSJulian Elischer static ng_rcvmsg_t		nga_rcvmsg;
10374f5c6aaSJulian Elischer static ng_shutdown_t		nga_shutdown;
10474f5c6aaSJulian Elischer static ng_newhook_t		nga_newhook;
10574f5c6aaSJulian Elischer static ng_disconnect_t		nga_disconnect;
1064cf49a43SJulian Elischer 
1074cf49a43SJulian Elischer /* Helper stuff */
1084cf49a43SJulian Elischer static int	nga_rcv_sync(const sc_p sc, struct mbuf *m, meta_p meta);
1094cf49a43SJulian Elischer static int	nga_rcv_async(const sc_p sc, struct mbuf *m, meta_p meta);
1104cf49a43SJulian Elischer 
1114cf49a43SJulian Elischer /* Define the netgraph node type */
1124cf49a43SJulian Elischer static struct ng_type typestruct = {
1134cf49a43SJulian Elischer 	NG_VERSION,
1144cf49a43SJulian Elischer 	NG_ASYNC_NODE_TYPE,
1154cf49a43SJulian Elischer 	NULL,
1164cf49a43SJulian Elischer 	nga_constructor,
1174cf49a43SJulian Elischer 	nga_rcvmsg,
1184cf49a43SJulian Elischer 	nga_shutdown,
1194cf49a43SJulian Elischer 	nga_newhook,
1204cf49a43SJulian Elischer 	NULL,
1214cf49a43SJulian Elischer 	NULL,
1224cf49a43SJulian Elischer 	nga_rcvdata,
1234cf49a43SJulian Elischer 	nga_rcvdata,
1244cf49a43SJulian Elischer 	nga_disconnect
1254cf49a43SJulian Elischer };
1264cf49a43SJulian Elischer NETGRAPH_INIT(async, &typestruct);
1274cf49a43SJulian Elischer 
1284cf49a43SJulian Elischer /* CRC table */
1294cf49a43SJulian Elischer static const u_int16_t fcstab[];
1304cf49a43SJulian Elischer 
1314cf49a43SJulian Elischer /******************************************************************
1324cf49a43SJulian Elischer 		    NETGRAPH NODE METHODS
1334cf49a43SJulian Elischer ******************************************************************/
1344cf49a43SJulian Elischer 
1354cf49a43SJulian Elischer /*
1364cf49a43SJulian Elischer  * Initialize a new node
1374cf49a43SJulian Elischer  */
1384cf49a43SJulian Elischer static int
1394cf49a43SJulian Elischer nga_constructor(node_p *nodep)
1404cf49a43SJulian Elischer {
1414cf49a43SJulian Elischer 	sc_p sc;
1424cf49a43SJulian Elischer 	int error;
1434cf49a43SJulian Elischer 
1444cf49a43SJulian Elischer 	if ((error = ng_make_node_common(&typestruct, nodep)))
1454cf49a43SJulian Elischer 		return (error);
1464cf49a43SJulian Elischer 	MALLOC(sc, sc_p, sizeof(*sc), M_NETGRAPH, M_WAITOK);
1474cf49a43SJulian Elischer 	if (sc == NULL)
1484cf49a43SJulian Elischer 		return (ENOMEM);
1494cf49a43SJulian Elischer 	bzero(sc, sizeof(*sc));
1504cf49a43SJulian Elischer 	sc->amode = MODE_HUNT;
1514cf49a43SJulian Elischer 	sc->cfg.accm = ~0;
1524cf49a43SJulian Elischer 	sc->cfg.amru = NG_ASYNC_DEFAULT_MRU;
1534cf49a43SJulian Elischer 	sc->cfg.smru = NG_ASYNC_DEFAULT_MRU;
1544cf49a43SJulian Elischer 	MALLOC(sc->abuf, u_char *,
1554cf49a43SJulian Elischer 	    ASYNC_BUF_SIZE(sc->cfg.smru), M_NETGRAPH, M_WAITOK);
1564cf49a43SJulian Elischer 	if (sc->abuf == NULL)
1574cf49a43SJulian Elischer 		goto fail;
1584cf49a43SJulian Elischer 	MALLOC(sc->sbuf, u_char *,
1594cf49a43SJulian Elischer 	    SYNC_BUF_SIZE(sc->cfg.amru), M_NETGRAPH, M_WAITOK);
1604cf49a43SJulian Elischer 	if (sc->sbuf == NULL) {
1614cf49a43SJulian Elischer 		FREE(sc->abuf, M_NETGRAPH);
1624cf49a43SJulian Elischer fail:
1634cf49a43SJulian Elischer 		FREE(sc, M_NETGRAPH);
1644cf49a43SJulian Elischer 		return (ENOMEM);
1654cf49a43SJulian Elischer 	}
1664cf49a43SJulian Elischer 	(*nodep)->private = sc;
1674cf49a43SJulian Elischer 	sc->node = *nodep;
1684cf49a43SJulian Elischer 	return (0);
1694cf49a43SJulian Elischer }
1704cf49a43SJulian Elischer 
1714cf49a43SJulian Elischer /*
1724cf49a43SJulian Elischer  * Reserve a hook for a pending connection
1734cf49a43SJulian Elischer  */
1744cf49a43SJulian Elischer static int
1754cf49a43SJulian Elischer nga_newhook(node_p node, hook_p hook, const char *name)
1764cf49a43SJulian Elischer {
1774cf49a43SJulian Elischer 	const sc_p sc = node->private;
1784cf49a43SJulian Elischer 	hook_p *hookp;
1794cf49a43SJulian Elischer 
1804cf49a43SJulian Elischer 	if (!strcmp(name, NG_ASYNC_HOOK_ASYNC))
1814cf49a43SJulian Elischer 		hookp = &sc->async;
1824cf49a43SJulian Elischer 	else if (!strcmp(name, NG_ASYNC_HOOK_SYNC))
1834cf49a43SJulian Elischer 		hookp = &sc->sync;
1844cf49a43SJulian Elischer 	else if (!strcmp(name, NG_ASYNC_HOOK_SYNC2))
1854cf49a43SJulian Elischer 		hookp = &sc->sync2;
1864cf49a43SJulian Elischer 	else
1874cf49a43SJulian Elischer 		return (EINVAL);
1884cf49a43SJulian Elischer 	if (*hookp)
1894cf49a43SJulian Elischer 		return (EISCONN);
1904cf49a43SJulian Elischer 	*hookp = hook;
1914cf49a43SJulian Elischer 	return (0);
1924cf49a43SJulian Elischer }
1934cf49a43SJulian Elischer 
1944cf49a43SJulian Elischer /*
1954cf49a43SJulian Elischer  * Receive incoming data
1964cf49a43SJulian Elischer  */
1974cf49a43SJulian Elischer static int
1984cf49a43SJulian Elischer nga_rcvdata(hook_p hook, struct mbuf *m, meta_p meta)
1994cf49a43SJulian Elischer {
2004cf49a43SJulian Elischer 	const sc_p sc = hook->node->private;
2014cf49a43SJulian Elischer 
2024cf49a43SJulian Elischer 	if (hook == sc->sync)
2034cf49a43SJulian Elischer 		return (nga_rcv_sync(sc, m, meta));
2044cf49a43SJulian Elischer 	else if (hook == sc->sync2) {
2054cf49a43SJulian Elischer 		const u_char acfcompSave = sc->cfg.acfcomp;
2064cf49a43SJulian Elischer 		const u_int32_t accmSave = sc->cfg.accm;
2074cf49a43SJulian Elischer 		int     rtn;
2084cf49a43SJulian Elischer 
2094cf49a43SJulian Elischer 		sc->cfg.acfcomp = 0;
2104cf49a43SJulian Elischer 		sc->cfg.accm = ~0;
2114cf49a43SJulian Elischer 		rtn = nga_rcv_sync(sc, m, meta);
2124cf49a43SJulian Elischer 		sc->cfg.acfcomp = acfcompSave;
2134cf49a43SJulian Elischer 		sc->cfg.accm = accmSave;
2144cf49a43SJulian Elischer 		return (rtn);
2154cf49a43SJulian Elischer 	} else if (hook == sc->async)
2164cf49a43SJulian Elischer 		return (nga_rcv_async(sc, m, meta));
2174cf49a43SJulian Elischer 	panic(__FUNCTION__);
2184cf49a43SJulian Elischer }
2194cf49a43SJulian Elischer 
2204cf49a43SJulian Elischer /*
2214cf49a43SJulian Elischer  * Receive incoming control message
2224cf49a43SJulian Elischer  */
2234cf49a43SJulian Elischer static int
2244cf49a43SJulian Elischer nga_rcvmsg(node_p node, struct ng_mesg *msg,
2254cf49a43SJulian Elischer 	const char *rtn, struct ng_mesg **rptr)
2264cf49a43SJulian Elischer {
2274cf49a43SJulian Elischer 	const sc_p sc = (sc_p) node->private;
2284cf49a43SJulian Elischer 	struct ng_mesg *resp = NULL;
2294cf49a43SJulian Elischer 	int error = 0;
2304cf49a43SJulian Elischer 
2314cf49a43SJulian Elischer 	switch (msg->header.typecookie) {
2324cf49a43SJulian Elischer 	case NGM_ASYNC_COOKIE:
2334cf49a43SJulian Elischer 		switch (msg->header.cmd) {
2344cf49a43SJulian Elischer 		case NGM_ASYNC_CMD_GET_STATS:
2354cf49a43SJulian Elischer 			NG_MKRESPONSE(resp, msg, sizeof(sc->stats), M_NOWAIT);
2364cf49a43SJulian Elischer 			if (resp == NULL)
2374cf49a43SJulian Elischer 				ERROUT(ENOMEM);
2384cf49a43SJulian Elischer 			*((struct ng_async_stat *) resp->data) = sc->stats;
2394cf49a43SJulian Elischer 			break;
2404cf49a43SJulian Elischer 		case NGM_ASYNC_CMD_CLR_STATS:
2414cf49a43SJulian Elischer 			bzero(&sc->stats, sizeof(sc->stats));
2424cf49a43SJulian Elischer 			break;
2434cf49a43SJulian Elischer 		case NGM_ASYNC_CMD_SET_CONFIG:
2444cf49a43SJulian Elischer 		    {
2454cf49a43SJulian Elischer 			struct ng_async_cfg *const cfg =
2464cf49a43SJulian Elischer 				(struct ng_async_cfg *) msg->data;
2474cf49a43SJulian Elischer 			u_char *buf;
2484cf49a43SJulian Elischer 
2494cf49a43SJulian Elischer 			if (msg->header.arglen != sizeof(*cfg))
2504cf49a43SJulian Elischer 				ERROUT(EINVAL);
2514cf49a43SJulian Elischer 			if (cfg->amru < NG_ASYNC_MIN_MRU
2524cf49a43SJulian Elischer 			    || cfg->amru > NG_ASYNC_MAX_MRU
2534cf49a43SJulian Elischer 			    || cfg->smru < NG_ASYNC_MIN_MRU
2544cf49a43SJulian Elischer 			    || cfg->smru > NG_ASYNC_MAX_MRU)
2554cf49a43SJulian Elischer 				ERROUT(EINVAL);
2564cf49a43SJulian Elischer 			cfg->enabled = !!cfg->enabled;	/* normalize */
2574cf49a43SJulian Elischer 			cfg->acfcomp = !!cfg->acfcomp;	/* normalize */
2584cf49a43SJulian Elischer 			if (cfg->smru > sc->cfg.smru) {	/* reallocate buffer */
2594cf49a43SJulian Elischer 				MALLOC(buf, u_char *, ASYNC_BUF_SIZE(cfg->smru),
2604cf49a43SJulian Elischer 				    M_NETGRAPH, M_NOWAIT);
2614cf49a43SJulian Elischer 				if (!buf)
2624cf49a43SJulian Elischer 					ERROUT(ENOMEM);
2634cf49a43SJulian Elischer 				FREE(sc->abuf, M_NETGRAPH);
2644cf49a43SJulian Elischer 				sc->abuf = buf;
2654cf49a43SJulian Elischer 			}
2664cf49a43SJulian Elischer 			if (cfg->amru > sc->cfg.amru) {	/* reallocate buffer */
2674cf49a43SJulian Elischer 				MALLOC(buf, u_char *, SYNC_BUF_SIZE(cfg->amru),
2684cf49a43SJulian Elischer 				    M_NETGRAPH, M_NOWAIT);
2694cf49a43SJulian Elischer 				if (!buf)
2704cf49a43SJulian Elischer 					ERROUT(ENOMEM);
2714cf49a43SJulian Elischer 				FREE(sc->sbuf, M_NETGRAPH);
2724cf49a43SJulian Elischer 				sc->sbuf = buf;
2734cf49a43SJulian Elischer 				sc->amode = MODE_HUNT;
2744cf49a43SJulian Elischer 				sc->slen = 0;
2754cf49a43SJulian Elischer 			}
2764cf49a43SJulian Elischer 			if (!cfg->enabled) {
2774cf49a43SJulian Elischer 				sc->amode = MODE_HUNT;
2784cf49a43SJulian Elischer 				sc->slen = 0;
2794cf49a43SJulian Elischer 			}
2804cf49a43SJulian Elischer 			sc->cfg = *cfg;
2814cf49a43SJulian Elischer 			break;
2824cf49a43SJulian Elischer 		    }
2834cf49a43SJulian Elischer 		case NGM_ASYNC_CMD_GET_CONFIG:
2844cf49a43SJulian Elischer 			NG_MKRESPONSE(resp, msg, sizeof(sc->cfg), M_NOWAIT);
2854cf49a43SJulian Elischer 			if (!resp)
2864cf49a43SJulian Elischer 				ERROUT(ENOMEM);
2874cf49a43SJulian Elischer 			*((struct ng_async_cfg *) resp->data) = sc->cfg;
2884cf49a43SJulian Elischer 			break;
2894cf49a43SJulian Elischer 		default:
2904cf49a43SJulian Elischer 			ERROUT(EINVAL);
2914cf49a43SJulian Elischer 		}
2924cf49a43SJulian Elischer 		break;
2934cf49a43SJulian Elischer 	default:
2944cf49a43SJulian Elischer 		ERROUT(EINVAL);
2954cf49a43SJulian Elischer 	}
2964cf49a43SJulian Elischer 	if (rptr)
2974cf49a43SJulian Elischer 		*rptr = resp;
2984cf49a43SJulian Elischer 	else if (resp)
2994cf49a43SJulian Elischer 		FREE(resp, M_NETGRAPH);
3004cf49a43SJulian Elischer 
3014cf49a43SJulian Elischer done:
3024cf49a43SJulian Elischer 	FREE(msg, M_NETGRAPH);
3034cf49a43SJulian Elischer 	return (error);
3044cf49a43SJulian Elischer }
3054cf49a43SJulian Elischer 
3064cf49a43SJulian Elischer /*
3074cf49a43SJulian Elischer  * Shutdown this node
3084cf49a43SJulian Elischer  */
3094cf49a43SJulian Elischer static int
3104cf49a43SJulian Elischer nga_shutdown(node_p node)
3114cf49a43SJulian Elischer {
3124cf49a43SJulian Elischer 	const sc_p sc = node->private;
3134cf49a43SJulian Elischer 
3144cf49a43SJulian Elischer 	ng_cutlinks(node);
3154cf49a43SJulian Elischer 	ng_unname(node);
3164cf49a43SJulian Elischer 	FREE(sc->abuf, M_NETGRAPH);
3174cf49a43SJulian Elischer 	FREE(sc->sbuf, M_NETGRAPH);
3184cf49a43SJulian Elischer 	bzero(sc, sizeof(*sc));
3194cf49a43SJulian Elischer 	FREE(sc, M_NETGRAPH);
3204cf49a43SJulian Elischer 	node->private = NULL;
3214cf49a43SJulian Elischer 	ng_unref(node);
3224cf49a43SJulian Elischer 	return (0);
3234cf49a43SJulian Elischer }
3244cf49a43SJulian Elischer 
3254cf49a43SJulian Elischer /*
3264cf49a43SJulian Elischer  * Lose a hook. When both hooks go away, we disappear.
3274cf49a43SJulian Elischer  */
3284cf49a43SJulian Elischer static int
3294cf49a43SJulian Elischer nga_disconnect(hook_p hook)
3304cf49a43SJulian Elischer {
3314cf49a43SJulian Elischer 	const sc_p sc = hook->node->private;
3324cf49a43SJulian Elischer 	hook_p *hookp;
3334cf49a43SJulian Elischer 
3344cf49a43SJulian Elischer 	if (hook == sc->async)
3354cf49a43SJulian Elischer 		hookp = &sc->async;
3364cf49a43SJulian Elischer 	else if (hook == sc->sync)
3374cf49a43SJulian Elischer 		hookp = &sc->sync;
3384cf49a43SJulian Elischer 	else if (hook == sc->sync2)
3394cf49a43SJulian Elischer 		hookp = &sc->sync2;
3404cf49a43SJulian Elischer 	else
3414cf49a43SJulian Elischer 		panic(__FUNCTION__);
3424cf49a43SJulian Elischer 	if (!*hookp)
3434cf49a43SJulian Elischer 		panic(__FUNCTION__ "2");
3444cf49a43SJulian Elischer 	*hookp = NULL;
3454cf49a43SJulian Elischer 	bzero(&sc->stats, sizeof(sc->stats));
3464cf49a43SJulian Elischer #if SYNC_OPT_TIME
3474cf49a43SJulian Elischer 	sc->lasttime = 0;
3484cf49a43SJulian Elischer #endif
3494cf49a43SJulian Elischer 	if (hook->node->numhooks == 0)
3504cf49a43SJulian Elischer 		ng_rmnode(hook->node);
3514cf49a43SJulian Elischer 	return (0);
3524cf49a43SJulian Elischer }
3534cf49a43SJulian Elischer 
3544cf49a43SJulian Elischer /******************************************************************
3554cf49a43SJulian Elischer 		    INTERNAL HELPER STUFF
3564cf49a43SJulian Elischer ******************************************************************/
3574cf49a43SJulian Elischer 
3584cf49a43SJulian Elischer /*
3594cf49a43SJulian Elischer  * Encode a byte into the async buffer
3604cf49a43SJulian Elischer  */
3614cf49a43SJulian Elischer static __inline__ void
3624cf49a43SJulian Elischer nga_async_add(const sc_p sc, u_int16_t *fcs, u_int32_t accm, int *len, u_char x)
3634cf49a43SJulian Elischer {
3644cf49a43SJulian Elischer 	*fcs = PPP_FCS(*fcs, x);
3654cf49a43SJulian Elischer 	if ((x < 32 && ((1 << x) & accm))
3664cf49a43SJulian Elischer 	    || (x == PPP_ESCAPE)
3674cf49a43SJulian Elischer 	    || (x == PPP_FLAG)) {
3684cf49a43SJulian Elischer 		sc->abuf[(*len)++] = PPP_ESCAPE;
3694cf49a43SJulian Elischer 		x ^= PPP_TRANS;
3704cf49a43SJulian Elischer 	}
3714cf49a43SJulian Elischer 	sc->abuf[(*len)++] = x;
3724cf49a43SJulian Elischer }
3734cf49a43SJulian Elischer 
3744cf49a43SJulian Elischer /*
3754cf49a43SJulian Elischer  * Receive incoming synchronous data. Any "meta" information means
3764cf49a43SJulian Elischer  * for us to apply full ACCM to this frame.
3774cf49a43SJulian Elischer  */
3784cf49a43SJulian Elischer static int
3794cf49a43SJulian Elischer nga_rcv_sync(const sc_p sc, struct mbuf *m, meta_p meta)
3804cf49a43SJulian Elischer {
3814cf49a43SJulian Elischer 	struct ifnet *const rcvif = m->m_pkthdr.rcvif;
3824cf49a43SJulian Elischer 	u_int16_t fcs, fcs0;
3834cf49a43SJulian Elischer 	int alen, error = 0;
3844cf49a43SJulian Elischer 
3854cf49a43SJulian Elischer #define ADD_BYTE(x)	\
3864cf49a43SJulian Elischer   nga_async_add(sc, &fcs, meta ? ~0 : sc->cfg.accm, &alen, (x))
3874cf49a43SJulian Elischer 
3884cf49a43SJulian Elischer 	if (!sc->cfg.enabled) {
3894cf49a43SJulian Elischer 		NG_SEND_DATA(error, sc->async, m, meta);
3904cf49a43SJulian Elischer 		return (error);
3914cf49a43SJulian Elischer 	}
3924cf49a43SJulian Elischer 	if (m->m_pkthdr.len > sc->cfg.smru) {
3934cf49a43SJulian Elischer 		sc->stats.syncOverflows++;
3944cf49a43SJulian Elischer 		NG_FREE_DATA(m, meta);
3954cf49a43SJulian Elischer 		return (EMSGSIZE);
3964cf49a43SJulian Elischer 	}
3974cf49a43SJulian Elischer 	sc->stats.syncFrames++;
3984cf49a43SJulian Elischer 	sc->stats.syncOctets += m->m_pkthdr.len;
3994cf49a43SJulian Elischer 
4004cf49a43SJulian Elischer 	/* Initialize async encoded version of input mbuf */
4014cf49a43SJulian Elischer 	alen = 0;
4024cf49a43SJulian Elischer 	fcs = PPP_INITFCS;
4034cf49a43SJulian Elischer 
4044cf49a43SJulian Elischer 	/* Add beginning sync flag if it's been long enough to need one */
4054cf49a43SJulian Elischer #if SYNC_OPT_TIME
4064cf49a43SJulian Elischer 	{
4074cf49a43SJulian Elischer 		struct timeval time;
4084cf49a43SJulian Elischer 
4094cf49a43SJulian Elischer 		getmicrotime(&time);
4104cf49a43SJulian Elischer 		if (time.tv_sec >= sc->lasttime + SYNC_OPT_TIME) {
4114cf49a43SJulian Elischer 			sc->abuf[alen++] = PPP_FLAG;
4124cf49a43SJulian Elischer 			sc->lasttime = time.tv_sec;
4134cf49a43SJulian Elischer 		}
4144cf49a43SJulian Elischer 	}
4154cf49a43SJulian Elischer #else
4164cf49a43SJulian Elischer 	sc->abuf[alen++] = PPP_FLAG;
4174cf49a43SJulian Elischer #endif
4184cf49a43SJulian Elischer 
4194cf49a43SJulian Elischer 	/* Add option address and control fields, then packet payload */
4204cf49a43SJulian Elischer 	if (!sc->cfg.acfcomp || meta) {
4214cf49a43SJulian Elischer 		ADD_BYTE(PPP_ALLSTATIONS);
4224cf49a43SJulian Elischer 		ADD_BYTE(PPP_UI);
4234cf49a43SJulian Elischer 	}
4244cf49a43SJulian Elischer 	while (m) {
4254cf49a43SJulian Elischer 		struct mbuf *n;
4264cf49a43SJulian Elischer 
4274cf49a43SJulian Elischer 		while (m->m_len > 0) {
4284cf49a43SJulian Elischer 			u_char const ch = *mtod(m, u_char *);
4294cf49a43SJulian Elischer 
4304cf49a43SJulian Elischer 			ADD_BYTE(ch);
4314cf49a43SJulian Elischer 			m->m_data++;
4324cf49a43SJulian Elischer 			m->m_len--;
4334cf49a43SJulian Elischer 		}
4344cf49a43SJulian Elischer 		MFREE(m, n);
4354cf49a43SJulian Elischer 		m = n;
4364cf49a43SJulian Elischer 	}
4374cf49a43SJulian Elischer 
4384cf49a43SJulian Elischer 	/* Add checksum and final sync flag */
4394cf49a43SJulian Elischer 	fcs0 = fcs;
4404cf49a43SJulian Elischer 	ADD_BYTE(~fcs0 & 0xff);
4414cf49a43SJulian Elischer 	ADD_BYTE(~fcs0 >> 8);
4424cf49a43SJulian Elischer 	sc->abuf[alen++] = PPP_FLAG;
4434cf49a43SJulian Elischer 
4444cf49a43SJulian Elischer 	/* Put frame in an mbuf and ship it off */
4454cf49a43SJulian Elischer 	NG_FREE_META(meta);
4464cf49a43SJulian Elischer 	if (!(m = m_devget(sc->abuf, alen, 0, rcvif, NULL)))
4474cf49a43SJulian Elischer 		error = ENOBUFS;
4484cf49a43SJulian Elischer 	else
4494cf49a43SJulian Elischer 		NG_SEND_DATA(error, sc->async, m, meta);
4504cf49a43SJulian Elischer 	return (error);
4514cf49a43SJulian Elischer }
4524cf49a43SJulian Elischer 
4534cf49a43SJulian Elischer /*
4544cf49a43SJulian Elischer  * Receive incoming asynchronous data
4554cf49a43SJulian Elischer  * XXX technically, we should strip out supposedly escaped characters
4564cf49a43SJulian Elischer  */
4574cf49a43SJulian Elischer static int
4584cf49a43SJulian Elischer nga_rcv_async(const sc_p sc, struct mbuf * m, meta_p meta)
4594cf49a43SJulian Elischer {
4604cf49a43SJulian Elischer 	struct ifnet *const rcvif = m->m_pkthdr.rcvif;
4614cf49a43SJulian Elischer 	int error;
4624cf49a43SJulian Elischer 
4634cf49a43SJulian Elischer 	if (!sc->cfg.enabled) {
4644cf49a43SJulian Elischer 		NG_SEND_DATA(error, sc->sync, m, meta);
4654cf49a43SJulian Elischer 		return (error);
4664cf49a43SJulian Elischer 	}
4674cf49a43SJulian Elischer 	NG_FREE_META(meta);
4684cf49a43SJulian Elischer 	while (m) {
4694cf49a43SJulian Elischer 		struct mbuf *n;
4704cf49a43SJulian Elischer 
4714cf49a43SJulian Elischer 		for (; m->m_len > 0; m->m_data++, m->m_len--) {
4724cf49a43SJulian Elischer 			u_char  ch = *mtod(m, u_char *);
4734cf49a43SJulian Elischer 
4744cf49a43SJulian Elischer 			sc->stats.asyncOctets++;
4754cf49a43SJulian Elischer 			if (ch == PPP_FLAG) {	/* Flag overrides everything */
4764cf49a43SJulian Elischer 				int     skip = 0;
4774cf49a43SJulian Elischer 
4784cf49a43SJulian Elischer 				/* Check for runts */
4794cf49a43SJulian Elischer 				if (sc->slen < 2) {
4804cf49a43SJulian Elischer 					if (sc->slen > 0)
4814cf49a43SJulian Elischer 						sc->stats.asyncRunts++;
4824cf49a43SJulian Elischer 					goto reset;
4834cf49a43SJulian Elischer 				}
4844cf49a43SJulian Elischer 
4854cf49a43SJulian Elischer 				/* Verify CRC */
4864cf49a43SJulian Elischer 				if (sc->fcs != PPP_GOODFCS) {
4874cf49a43SJulian Elischer 					sc->stats.asyncBadCheckSums++;
4884cf49a43SJulian Elischer 					goto reset;
4894cf49a43SJulian Elischer 				}
4904cf49a43SJulian Elischer 				sc->slen -= 2;
4914cf49a43SJulian Elischer 
4924cf49a43SJulian Elischer 				/* Strip address and control fields */
4934cf49a43SJulian Elischer 				if (sc->slen >= 2
4944cf49a43SJulian Elischer 				    && sc->sbuf[0] == PPP_ALLSTATIONS
4954cf49a43SJulian Elischer 				    && sc->sbuf[1] == PPP_UI)
4964cf49a43SJulian Elischer 					skip = 2;
4974cf49a43SJulian Elischer 
4984cf49a43SJulian Elischer 				/* Check for frame too big */
4994cf49a43SJulian Elischer 				if (sc->slen - skip > sc->cfg.amru) {
5004cf49a43SJulian Elischer 					sc->stats.asyncOverflows++;
5014cf49a43SJulian Elischer 					goto reset;
5024cf49a43SJulian Elischer 				}
5034cf49a43SJulian Elischer 
5044cf49a43SJulian Elischer 				/* OK, ship it out */
5054cf49a43SJulian Elischer 				if ((n = m_devget(sc->sbuf + skip,
5064cf49a43SJulian Elischer 					   sc->slen - skip, 0, rcvif, NULL)))
5074cf49a43SJulian Elischer 					NG_SEND_DATA(error, sc->sync, n, meta);
5084cf49a43SJulian Elischer 				sc->stats.asyncFrames++;
5094cf49a43SJulian Elischer reset:
5104cf49a43SJulian Elischer 				sc->amode = MODE_NORMAL;
5114cf49a43SJulian Elischer 				sc->fcs = PPP_INITFCS;
5124cf49a43SJulian Elischer 				sc->slen = 0;
5134cf49a43SJulian Elischer 				continue;
5144cf49a43SJulian Elischer 			}
5154cf49a43SJulian Elischer 			switch (sc->amode) {
5164cf49a43SJulian Elischer 			case MODE_NORMAL:
5174cf49a43SJulian Elischer 				if (ch == PPP_ESCAPE) {
5184cf49a43SJulian Elischer 					sc->amode = MODE_ESC;
5194cf49a43SJulian Elischer 					continue;
5204cf49a43SJulian Elischer 				}
5214cf49a43SJulian Elischer 				break;
5224cf49a43SJulian Elischer 			case MODE_ESC:
5234cf49a43SJulian Elischer 				ch ^= PPP_TRANS;
5244cf49a43SJulian Elischer 				sc->amode = MODE_NORMAL;
5254cf49a43SJulian Elischer 				break;
5264cf49a43SJulian Elischer 			case MODE_HUNT:
5274cf49a43SJulian Elischer 			default:
5284cf49a43SJulian Elischer 				continue;
5294cf49a43SJulian Elischer 			}
5304cf49a43SJulian Elischer 
5314cf49a43SJulian Elischer 			/* Add byte to frame */
5324cf49a43SJulian Elischer 			if (sc->slen >= SYNC_BUF_SIZE(sc->cfg.amru)) {
5334cf49a43SJulian Elischer 				sc->stats.asyncOverflows++;
5344cf49a43SJulian Elischer 				sc->amode = MODE_HUNT;
5354cf49a43SJulian Elischer 				sc->slen = 0;
5364cf49a43SJulian Elischer 			} else {
5374cf49a43SJulian Elischer 				sc->sbuf[sc->slen++] = ch;
5384cf49a43SJulian Elischer 				sc->fcs = PPP_FCS(sc->fcs, ch);
5394cf49a43SJulian Elischer 			}
5404cf49a43SJulian Elischer 		}
5414cf49a43SJulian Elischer 		MFREE(m, n);
5424cf49a43SJulian Elischer 		m = n;
5434cf49a43SJulian Elischer 	}
5444cf49a43SJulian Elischer 	return (0);
5454cf49a43SJulian Elischer }
5464cf49a43SJulian Elischer 
5474cf49a43SJulian Elischer /*
5484cf49a43SJulian Elischer  * CRC table
5494cf49a43SJulian Elischer  *
5504cf49a43SJulian Elischer  * Taken from RFC 1171 Appendix B
5514cf49a43SJulian Elischer  */
5524cf49a43SJulian Elischer static const u_int16_t fcstab[256] = {
5534cf49a43SJulian Elischer 	 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
5544cf49a43SJulian Elischer 	 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
5554cf49a43SJulian Elischer 	 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
5564cf49a43SJulian Elischer 	 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
5574cf49a43SJulian Elischer 	 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
5584cf49a43SJulian Elischer 	 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
5594cf49a43SJulian Elischer 	 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
5604cf49a43SJulian Elischer 	 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
5614cf49a43SJulian Elischer 	 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
5624cf49a43SJulian Elischer 	 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
5634cf49a43SJulian Elischer 	 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
5644cf49a43SJulian Elischer 	 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
5654cf49a43SJulian Elischer 	 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
5664cf49a43SJulian Elischer 	 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
5674cf49a43SJulian Elischer 	 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
5684cf49a43SJulian Elischer 	 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
5694cf49a43SJulian Elischer 	 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
5704cf49a43SJulian Elischer 	 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
5714cf49a43SJulian Elischer 	 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
5724cf49a43SJulian Elischer 	 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
5734cf49a43SJulian Elischer 	 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
5744cf49a43SJulian Elischer 	 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
5754cf49a43SJulian Elischer 	 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
5764cf49a43SJulian Elischer 	 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
5774cf49a43SJulian Elischer 	 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
5784cf49a43SJulian Elischer 	 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
5794cf49a43SJulian Elischer 	 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
5804cf49a43SJulian Elischer 	 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
5814cf49a43SJulian Elischer 	 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
5824cf49a43SJulian Elischer 	 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
5834cf49a43SJulian Elischer 	 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
5844cf49a43SJulian Elischer 	 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
5854cf49a43SJulian Elischer };
586