xref: /freebsd/sys/netgraph/ng_async.c (revision cc3bbd68c54fab5539ff1cfa5f7bfb454633239c)
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  *
37cc3bbd68SJulian Elischer  * Author: Archie Cobbs <archie@freebsd.org>
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/mbuf.h>
524cf49a43SJulian Elischer #include <sys/malloc.h>
534cf49a43SJulian Elischer #include <sys/errno.h>
544cf49a43SJulian Elischer 
554cf49a43SJulian Elischer #include <netgraph/ng_message.h>
564cf49a43SJulian Elischer #include <netgraph/netgraph.h>
574cf49a43SJulian Elischer #include <netgraph/ng_async.h>
58f8307e12SArchie Cobbs #include <netgraph/ng_parse.h>
594cf49a43SJulian Elischer 
604cf49a43SJulian Elischer #include <net/ppp_defs.h>
614cf49a43SJulian Elischer 
624cf49a43SJulian Elischer /* Async decode state */
634cf49a43SJulian Elischer #define MODE_HUNT	0
644cf49a43SJulian Elischer #define MODE_NORMAL	1
654cf49a43SJulian Elischer #define MODE_ESC	2
664cf49a43SJulian Elischer 
674cf49a43SJulian Elischer /* Private data structure */
6819a52c59SArchie Cobbs struct ng_async_private {
694cf49a43SJulian Elischer 	node_p  	node;		/* Our node */
704cf49a43SJulian Elischer 	hook_p  	async;		/* Asynchronous side */
714cf49a43SJulian Elischer 	hook_p  	sync;		/* Synchronous side */
724cf49a43SJulian Elischer 	u_char  	amode;		/* Async hunt/esape mode */
734cf49a43SJulian Elischer 	u_int16_t	fcs;		/* Decoded async FCS (so far) */
744cf49a43SJulian Elischer 	u_char	       *abuf;		/* Buffer to encode sync into */
754cf49a43SJulian Elischer 	u_char	       *sbuf;		/* Buffer to decode async into */
764cf49a43SJulian Elischer 	u_int		slen;		/* Length of data in sbuf */
774cf49a43SJulian Elischer 	long		lasttime;	/* Time of last async packet sent */
784cf49a43SJulian Elischer 	struct		ng_async_cfg	cfg;	/* Configuration */
794cf49a43SJulian Elischer 	struct		ng_async_stat	stats;	/* Statistics */
804cf49a43SJulian Elischer };
8119a52c59SArchie Cobbs typedef struct ng_async_private *sc_p;
824cf49a43SJulian Elischer 
834cf49a43SJulian Elischer /* Useful macros */
844cf49a43SJulian Elischer #define ASYNC_BUF_SIZE(smru)	(2 * (smru) + 10)
854cf49a43SJulian Elischer #define SYNC_BUF_SIZE(amru)	((amru) + 10)
864cf49a43SJulian Elischer #define ERROUT(x)		do { error = (x); goto done; } while (0)
874cf49a43SJulian Elischer 
884cf49a43SJulian Elischer /* Netgraph methods */
8974f5c6aaSJulian Elischer static ng_constructor_t		nga_constructor;
9074f5c6aaSJulian Elischer static ng_rcvdata_t		nga_rcvdata;
9174f5c6aaSJulian Elischer static ng_rcvmsg_t		nga_rcvmsg;
9274f5c6aaSJulian Elischer static ng_shutdown_t		nga_shutdown;
9374f5c6aaSJulian Elischer static ng_newhook_t		nga_newhook;
9474f5c6aaSJulian Elischer static ng_disconnect_t		nga_disconnect;
954cf49a43SJulian Elischer 
964cf49a43SJulian Elischer /* Helper stuff */
974cf49a43SJulian Elischer static int	nga_rcv_sync(const sc_p sc, struct mbuf *m, meta_p meta);
984cf49a43SJulian Elischer static int	nga_rcv_async(const sc_p sc, struct mbuf *m, meta_p meta);
994cf49a43SJulian Elischer 
100f8307e12SArchie Cobbs /* Parse type for struct ng_async_cfg */
101f8307e12SArchie Cobbs static const struct ng_parse_struct_info
102f8307e12SArchie Cobbs 	nga_config_type_info = NG_ASYNC_CONFIG_TYPE_INFO;
103f8307e12SArchie Cobbs static const struct ng_parse_type nga_config_type = {
104f8307e12SArchie Cobbs 	&ng_parse_struct_type,
105f8307e12SArchie Cobbs 	&nga_config_type_info
106f8307e12SArchie Cobbs };
107f8307e12SArchie Cobbs 
108f8307e12SArchie Cobbs /* Parse type for struct ng_async_stat */
109f8307e12SArchie Cobbs static const struct ng_parse_struct_info
110f8307e12SArchie Cobbs 	nga_stats_type_info = NG_ASYNC_STATS_TYPE_INFO;
111f8307e12SArchie Cobbs static const struct ng_parse_type nga_stats_type = {
112f8307e12SArchie Cobbs 	&ng_parse_struct_type,
113f8307e12SArchie Cobbs 	&nga_stats_type_info,
114f8307e12SArchie Cobbs };
115f8307e12SArchie Cobbs 
116f8307e12SArchie Cobbs /* List of commands and how to convert arguments to/from ASCII */
117f8307e12SArchie Cobbs static const struct ng_cmdlist nga_cmdlist[] = {
118f8307e12SArchie Cobbs 	{
119f8307e12SArchie Cobbs 	  NGM_ASYNC_COOKIE,
120f8307e12SArchie Cobbs 	  NGM_ASYNC_CMD_SET_CONFIG,
121f8307e12SArchie Cobbs 	  "setconfig",
122f8307e12SArchie Cobbs 	  &nga_config_type,
123f8307e12SArchie Cobbs 	  NULL
124f8307e12SArchie Cobbs 	},
125f8307e12SArchie Cobbs 	{
126f8307e12SArchie Cobbs 	  NGM_ASYNC_COOKIE,
127f8307e12SArchie Cobbs 	  NGM_ASYNC_CMD_GET_CONFIG,
128f8307e12SArchie Cobbs 	  "getconfig",
129f8307e12SArchie Cobbs 	  NULL,
130f8307e12SArchie Cobbs 	  &nga_config_type
131f8307e12SArchie Cobbs 	},
132f8307e12SArchie Cobbs 	{
133f8307e12SArchie Cobbs 	  NGM_ASYNC_COOKIE,
134f8307e12SArchie Cobbs 	  NGM_ASYNC_CMD_GET_STATS,
135f8307e12SArchie Cobbs 	  "getstats",
136f8307e12SArchie Cobbs 	  NULL,
137f8307e12SArchie Cobbs 	  &nga_stats_type
138f8307e12SArchie Cobbs 	},
139f8307e12SArchie Cobbs 	{
140f8307e12SArchie Cobbs 	  NGM_ASYNC_COOKIE,
141f8307e12SArchie Cobbs 	  NGM_ASYNC_CMD_CLR_STATS,
142f8307e12SArchie Cobbs 	  "clrstats",
143f8307e12SArchie Cobbs 	  &nga_stats_type,
144f8307e12SArchie Cobbs 	  NULL
145f8307e12SArchie Cobbs 	},
146f8307e12SArchie Cobbs 	{ 0 }
147f8307e12SArchie Cobbs };
148f8307e12SArchie Cobbs 
1494cf49a43SJulian Elischer /* Define the netgraph node type */
1504cf49a43SJulian Elischer static struct ng_type typestruct = {
1514cf49a43SJulian Elischer 	NG_VERSION,
1524cf49a43SJulian Elischer 	NG_ASYNC_NODE_TYPE,
1534cf49a43SJulian Elischer 	NULL,
1544cf49a43SJulian Elischer 	nga_constructor,
1554cf49a43SJulian Elischer 	nga_rcvmsg,
1564cf49a43SJulian Elischer 	nga_shutdown,
1574cf49a43SJulian Elischer 	nga_newhook,
1584cf49a43SJulian Elischer 	NULL,
1594cf49a43SJulian Elischer 	NULL,
1604cf49a43SJulian Elischer 	nga_rcvdata,
1614cf49a43SJulian Elischer 	nga_rcvdata,
162f8307e12SArchie Cobbs 	nga_disconnect,
163f8307e12SArchie Cobbs 	nga_cmdlist
1644cf49a43SJulian Elischer };
1654cf49a43SJulian Elischer NETGRAPH_INIT(async, &typestruct);
1664cf49a43SJulian Elischer 
1674cf49a43SJulian Elischer /* CRC table */
1684cf49a43SJulian Elischer static const u_int16_t fcstab[];
1694cf49a43SJulian Elischer 
1704cf49a43SJulian Elischer /******************************************************************
1714cf49a43SJulian Elischer 		    NETGRAPH NODE METHODS
1724cf49a43SJulian Elischer ******************************************************************/
1734cf49a43SJulian Elischer 
1744cf49a43SJulian Elischer /*
1754cf49a43SJulian Elischer  * Initialize a new node
1764cf49a43SJulian Elischer  */
1774cf49a43SJulian Elischer static int
1784cf49a43SJulian Elischer nga_constructor(node_p *nodep)
1794cf49a43SJulian Elischer {
1804cf49a43SJulian Elischer 	sc_p sc;
1814cf49a43SJulian Elischer 	int error;
1824cf49a43SJulian Elischer 
1834cf49a43SJulian Elischer 	if ((error = ng_make_node_common(&typestruct, nodep)))
1844cf49a43SJulian Elischer 		return (error);
18565b9a0daSArchie Cobbs 	MALLOC(sc, sc_p, sizeof(*sc), M_NETGRAPH, M_NOWAIT);
1864cf49a43SJulian Elischer 	if (sc == NULL)
1874cf49a43SJulian Elischer 		return (ENOMEM);
1884cf49a43SJulian Elischer 	bzero(sc, sizeof(*sc));
1894cf49a43SJulian Elischer 	sc->amode = MODE_HUNT;
1904cf49a43SJulian Elischer 	sc->cfg.accm = ~0;
1914cf49a43SJulian Elischer 	sc->cfg.amru = NG_ASYNC_DEFAULT_MRU;
1924cf49a43SJulian Elischer 	sc->cfg.smru = NG_ASYNC_DEFAULT_MRU;
1934cf49a43SJulian Elischer 	MALLOC(sc->abuf, u_char *,
19465b9a0daSArchie Cobbs 	    ASYNC_BUF_SIZE(sc->cfg.smru), M_NETGRAPH, M_NOWAIT);
1954cf49a43SJulian Elischer 	if (sc->abuf == NULL)
1964cf49a43SJulian Elischer 		goto fail;
1974cf49a43SJulian Elischer 	MALLOC(sc->sbuf, u_char *,
19865b9a0daSArchie Cobbs 	    SYNC_BUF_SIZE(sc->cfg.amru), M_NETGRAPH, M_NOWAIT);
1994cf49a43SJulian Elischer 	if (sc->sbuf == NULL) {
2004cf49a43SJulian Elischer 		FREE(sc->abuf, M_NETGRAPH);
2014cf49a43SJulian Elischer fail:
2024cf49a43SJulian Elischer 		FREE(sc, M_NETGRAPH);
2034cf49a43SJulian Elischer 		return (ENOMEM);
2044cf49a43SJulian Elischer 	}
2054cf49a43SJulian Elischer 	(*nodep)->private = sc;
2064cf49a43SJulian Elischer 	sc->node = *nodep;
2074cf49a43SJulian Elischer 	return (0);
2084cf49a43SJulian Elischer }
2094cf49a43SJulian Elischer 
2104cf49a43SJulian Elischer /*
2114cf49a43SJulian Elischer  * Reserve a hook for a pending connection
2124cf49a43SJulian Elischer  */
2134cf49a43SJulian Elischer static int
2144cf49a43SJulian Elischer nga_newhook(node_p node, hook_p hook, const char *name)
2154cf49a43SJulian Elischer {
2164cf49a43SJulian Elischer 	const sc_p sc = node->private;
2174cf49a43SJulian Elischer 	hook_p *hookp;
2184cf49a43SJulian Elischer 
2194cf49a43SJulian Elischer 	if (!strcmp(name, NG_ASYNC_HOOK_ASYNC))
2204cf49a43SJulian Elischer 		hookp = &sc->async;
2214cf49a43SJulian Elischer 	else if (!strcmp(name, NG_ASYNC_HOOK_SYNC))
2224cf49a43SJulian Elischer 		hookp = &sc->sync;
2234cf49a43SJulian Elischer 	else
2244cf49a43SJulian Elischer 		return (EINVAL);
2254cf49a43SJulian Elischer 	if (*hookp)
2264cf49a43SJulian Elischer 		return (EISCONN);
2274cf49a43SJulian Elischer 	*hookp = hook;
2284cf49a43SJulian Elischer 	return (0);
2294cf49a43SJulian Elischer }
2304cf49a43SJulian Elischer 
2314cf49a43SJulian Elischer /*
2324cf49a43SJulian Elischer  * Receive incoming data
2334cf49a43SJulian Elischer  */
2344cf49a43SJulian Elischer static int
235a4ec03cfSJulian Elischer nga_rcvdata(hook_p hook, struct mbuf *m, meta_p meta,
236a4ec03cfSJulian Elischer 		struct mbuf **ret_m, meta_p *ret_meta)
2374cf49a43SJulian Elischer {
2384cf49a43SJulian Elischer 	const sc_p sc = hook->node->private;
2394cf49a43SJulian Elischer 
2404cf49a43SJulian Elischer 	if (hook == sc->sync)
2414cf49a43SJulian Elischer 		return (nga_rcv_sync(sc, m, meta));
242a8e9726dSArchie Cobbs 	if (hook == sc->async)
2434cf49a43SJulian Elischer 		return (nga_rcv_async(sc, m, meta));
2444cf49a43SJulian Elischer 	panic(__FUNCTION__);
2454cf49a43SJulian Elischer }
2464cf49a43SJulian Elischer 
2474cf49a43SJulian Elischer /*
2484cf49a43SJulian Elischer  * Receive incoming control message
2494cf49a43SJulian Elischer  */
2504cf49a43SJulian Elischer static int
2514cf49a43SJulian Elischer nga_rcvmsg(node_p node, struct ng_mesg *msg,
252a4ec03cfSJulian Elischer 	const char *rtn, struct ng_mesg **rptr, hook_p lasthook)
2534cf49a43SJulian Elischer {
2544cf49a43SJulian Elischer 	const sc_p sc = (sc_p) node->private;
2554cf49a43SJulian Elischer 	struct ng_mesg *resp = NULL;
2564cf49a43SJulian Elischer 	int error = 0;
2574cf49a43SJulian Elischer 
2584cf49a43SJulian Elischer 	switch (msg->header.typecookie) {
2594cf49a43SJulian Elischer 	case NGM_ASYNC_COOKIE:
2604cf49a43SJulian Elischer 		switch (msg->header.cmd) {
2614cf49a43SJulian Elischer 		case NGM_ASYNC_CMD_GET_STATS:
2624cf49a43SJulian Elischer 			NG_MKRESPONSE(resp, msg, sizeof(sc->stats), M_NOWAIT);
2634cf49a43SJulian Elischer 			if (resp == NULL)
2644cf49a43SJulian Elischer 				ERROUT(ENOMEM);
2654cf49a43SJulian Elischer 			*((struct ng_async_stat *) resp->data) = sc->stats;
2664cf49a43SJulian Elischer 			break;
2674cf49a43SJulian Elischer 		case NGM_ASYNC_CMD_CLR_STATS:
2684cf49a43SJulian Elischer 			bzero(&sc->stats, sizeof(sc->stats));
2694cf49a43SJulian Elischer 			break;
2704cf49a43SJulian Elischer 		case NGM_ASYNC_CMD_SET_CONFIG:
2714cf49a43SJulian Elischer 		    {
2724cf49a43SJulian Elischer 			struct ng_async_cfg *const cfg =
2734cf49a43SJulian Elischer 				(struct ng_async_cfg *) msg->data;
2744cf49a43SJulian Elischer 			u_char *buf;
2754cf49a43SJulian Elischer 
2764cf49a43SJulian Elischer 			if (msg->header.arglen != sizeof(*cfg))
2774cf49a43SJulian Elischer 				ERROUT(EINVAL);
2784cf49a43SJulian Elischer 			if (cfg->amru < NG_ASYNC_MIN_MRU
2794cf49a43SJulian Elischer 			    || cfg->amru > NG_ASYNC_MAX_MRU
2804cf49a43SJulian Elischer 			    || cfg->smru < NG_ASYNC_MIN_MRU
2814cf49a43SJulian Elischer 			    || cfg->smru > NG_ASYNC_MAX_MRU)
2824cf49a43SJulian Elischer 				ERROUT(EINVAL);
2834cf49a43SJulian Elischer 			cfg->enabled = !!cfg->enabled;	/* normalize */
2844cf49a43SJulian Elischer 			if (cfg->smru > sc->cfg.smru) {	/* reallocate buffer */
2854cf49a43SJulian Elischer 				MALLOC(buf, u_char *, ASYNC_BUF_SIZE(cfg->smru),
2864cf49a43SJulian Elischer 				    M_NETGRAPH, M_NOWAIT);
2874cf49a43SJulian Elischer 				if (!buf)
2884cf49a43SJulian Elischer 					ERROUT(ENOMEM);
2894cf49a43SJulian Elischer 				FREE(sc->abuf, M_NETGRAPH);
2904cf49a43SJulian Elischer 				sc->abuf = buf;
2914cf49a43SJulian Elischer 			}
2924cf49a43SJulian Elischer 			if (cfg->amru > sc->cfg.amru) {	/* reallocate buffer */
2934cf49a43SJulian Elischer 				MALLOC(buf, u_char *, SYNC_BUF_SIZE(cfg->amru),
2944cf49a43SJulian Elischer 				    M_NETGRAPH, M_NOWAIT);
2954cf49a43SJulian Elischer 				if (!buf)
2964cf49a43SJulian Elischer 					ERROUT(ENOMEM);
2974cf49a43SJulian Elischer 				FREE(sc->sbuf, M_NETGRAPH);
2984cf49a43SJulian Elischer 				sc->sbuf = buf;
2994cf49a43SJulian Elischer 				sc->amode = MODE_HUNT;
3004cf49a43SJulian Elischer 				sc->slen = 0;
3014cf49a43SJulian Elischer 			}
3024cf49a43SJulian Elischer 			if (!cfg->enabled) {
3034cf49a43SJulian Elischer 				sc->amode = MODE_HUNT;
3044cf49a43SJulian Elischer 				sc->slen = 0;
3054cf49a43SJulian Elischer 			}
3064cf49a43SJulian Elischer 			sc->cfg = *cfg;
3074cf49a43SJulian Elischer 			break;
3084cf49a43SJulian Elischer 		    }
3094cf49a43SJulian Elischer 		case NGM_ASYNC_CMD_GET_CONFIG:
3104cf49a43SJulian Elischer 			NG_MKRESPONSE(resp, msg, sizeof(sc->cfg), M_NOWAIT);
3114cf49a43SJulian Elischer 			if (!resp)
3124cf49a43SJulian Elischer 				ERROUT(ENOMEM);
3134cf49a43SJulian Elischer 			*((struct ng_async_cfg *) resp->data) = sc->cfg;
3144cf49a43SJulian Elischer 			break;
3154cf49a43SJulian Elischer 		default:
3164cf49a43SJulian Elischer 			ERROUT(EINVAL);
3174cf49a43SJulian Elischer 		}
3184cf49a43SJulian Elischer 		break;
3194cf49a43SJulian Elischer 	default:
3204cf49a43SJulian Elischer 		ERROUT(EINVAL);
3214cf49a43SJulian Elischer 	}
3224cf49a43SJulian Elischer 	if (rptr)
3234cf49a43SJulian Elischer 		*rptr = resp;
3244cf49a43SJulian Elischer 	else if (resp)
3254cf49a43SJulian Elischer 		FREE(resp, M_NETGRAPH);
3264cf49a43SJulian Elischer 
3274cf49a43SJulian Elischer done:
3284cf49a43SJulian Elischer 	FREE(msg, M_NETGRAPH);
3294cf49a43SJulian Elischer 	return (error);
3304cf49a43SJulian Elischer }
3314cf49a43SJulian Elischer 
3324cf49a43SJulian Elischer /*
3334cf49a43SJulian Elischer  * Shutdown this node
3344cf49a43SJulian Elischer  */
3354cf49a43SJulian Elischer static int
3364cf49a43SJulian Elischer nga_shutdown(node_p node)
3374cf49a43SJulian Elischer {
3384cf49a43SJulian Elischer 	const sc_p sc = node->private;
3394cf49a43SJulian Elischer 
3404cf49a43SJulian Elischer 	ng_cutlinks(node);
3414cf49a43SJulian Elischer 	ng_unname(node);
3424cf49a43SJulian Elischer 	FREE(sc->abuf, M_NETGRAPH);
3434cf49a43SJulian Elischer 	FREE(sc->sbuf, M_NETGRAPH);
3444cf49a43SJulian Elischer 	bzero(sc, sizeof(*sc));
3454cf49a43SJulian Elischer 	FREE(sc, M_NETGRAPH);
3464cf49a43SJulian Elischer 	node->private = NULL;
3474cf49a43SJulian Elischer 	ng_unref(node);
3484cf49a43SJulian Elischer 	return (0);
3494cf49a43SJulian Elischer }
3504cf49a43SJulian Elischer 
3514cf49a43SJulian Elischer /*
3524cf49a43SJulian Elischer  * Lose a hook. When both hooks go away, we disappear.
3534cf49a43SJulian Elischer  */
3544cf49a43SJulian Elischer static int
3554cf49a43SJulian Elischer nga_disconnect(hook_p hook)
3564cf49a43SJulian Elischer {
3574cf49a43SJulian Elischer 	const sc_p sc = hook->node->private;
3584cf49a43SJulian Elischer 	hook_p *hookp;
3594cf49a43SJulian Elischer 
3604cf49a43SJulian Elischer 	if (hook == sc->async)
3614cf49a43SJulian Elischer 		hookp = &sc->async;
3624cf49a43SJulian Elischer 	else if (hook == sc->sync)
3634cf49a43SJulian Elischer 		hookp = &sc->sync;
3644cf49a43SJulian Elischer 	else
3654cf49a43SJulian Elischer 		panic(__FUNCTION__);
3664cf49a43SJulian Elischer 	if (!*hookp)
3674cf49a43SJulian Elischer 		panic(__FUNCTION__ "2");
3684cf49a43SJulian Elischer 	*hookp = NULL;
3694cf49a43SJulian Elischer 	bzero(&sc->stats, sizeof(sc->stats));
3704cf49a43SJulian Elischer 	sc->lasttime = 0;
3714cf49a43SJulian Elischer 	if (hook->node->numhooks == 0)
3724cf49a43SJulian Elischer 		ng_rmnode(hook->node);
3734cf49a43SJulian Elischer 	return (0);
3744cf49a43SJulian Elischer }
3754cf49a43SJulian Elischer 
3764cf49a43SJulian Elischer /******************************************************************
3774cf49a43SJulian Elischer 		    INTERNAL HELPER STUFF
3784cf49a43SJulian Elischer ******************************************************************/
3794cf49a43SJulian Elischer 
3804cf49a43SJulian Elischer /*
3814cf49a43SJulian Elischer  * Encode a byte into the async buffer
3824cf49a43SJulian Elischer  */
3834cf49a43SJulian Elischer static __inline__ void
3844cf49a43SJulian Elischer nga_async_add(const sc_p sc, u_int16_t *fcs, u_int32_t accm, int *len, u_char x)
3854cf49a43SJulian Elischer {
3864cf49a43SJulian Elischer 	*fcs = PPP_FCS(*fcs, x);
3874cf49a43SJulian Elischer 	if ((x < 32 && ((1 << x) & accm))
3884cf49a43SJulian Elischer 	    || (x == PPP_ESCAPE)
3894cf49a43SJulian Elischer 	    || (x == PPP_FLAG)) {
3904cf49a43SJulian Elischer 		sc->abuf[(*len)++] = PPP_ESCAPE;
3914cf49a43SJulian Elischer 		x ^= PPP_TRANS;
3924cf49a43SJulian Elischer 	}
3934cf49a43SJulian Elischer 	sc->abuf[(*len)++] = x;
3944cf49a43SJulian Elischer }
3954cf49a43SJulian Elischer 
3964cf49a43SJulian Elischer /*
397a8e9726dSArchie Cobbs  * Receive incoming synchronous data.
3984cf49a43SJulian Elischer  */
3994cf49a43SJulian Elischer static int
4004cf49a43SJulian Elischer nga_rcv_sync(const sc_p sc, struct mbuf *m, meta_p meta)
4014cf49a43SJulian Elischer {
4024cf49a43SJulian Elischer 	struct ifnet *const rcvif = m->m_pkthdr.rcvif;
40319a52c59SArchie Cobbs 	int alen, error = 0;
404a8e9726dSArchie Cobbs 	struct timeval time;
4054cf49a43SJulian Elischer 	u_int16_t fcs, fcs0;
406a8e9726dSArchie Cobbs 	u_int32_t accm;
4074cf49a43SJulian Elischer 
408a8e9726dSArchie Cobbs #define ADD_BYTE(x)	nga_async_add(sc, &fcs, accm, &alen, (x))
4094cf49a43SJulian Elischer 
410a8e9726dSArchie Cobbs 	/* Check for bypass mode */
4114cf49a43SJulian Elischer 	if (!sc->cfg.enabled) {
4124cf49a43SJulian Elischer 		NG_SEND_DATA(error, sc->async, m, meta);
4134cf49a43SJulian Elischer 		return (error);
4144cf49a43SJulian Elischer 	}
415a8e9726dSArchie Cobbs 
41619a52c59SArchie Cobbs 	/* Get ACCM; special case LCP frames, which use full ACCM */
417a8e9726dSArchie Cobbs 	accm = sc->cfg.accm;
41819a52c59SArchie Cobbs 	if (m->m_pkthdr.len >= 4) {
41919a52c59SArchie Cobbs 		static const u_char lcphdr[4] = {
42019a52c59SArchie Cobbs 		    PPP_ALLSTATIONS,
42119a52c59SArchie Cobbs 		    PPP_UI,
42219a52c59SArchie Cobbs 		    (u_char)(PPP_LCP >> 8),
42319a52c59SArchie Cobbs 		    (u_char)(PPP_LCP & 0xff)
42419a52c59SArchie Cobbs 		};
42519a52c59SArchie Cobbs 		u_char buf[4];
426a8e9726dSArchie Cobbs 
42719a52c59SArchie Cobbs 		m_copydata(m, 0, 4, (caddr_t)buf);
42819a52c59SArchie Cobbs 		if (bcmp(buf, &lcphdr, 4) == 0)
429a8e9726dSArchie Cobbs 			accm = ~0;
430a8e9726dSArchie Cobbs 	}
431a8e9726dSArchie Cobbs 
432a8e9726dSArchie Cobbs 	/* Check for overflow */
4334cf49a43SJulian Elischer 	if (m->m_pkthdr.len > sc->cfg.smru) {
4344cf49a43SJulian Elischer 		sc->stats.syncOverflows++;
4354cf49a43SJulian Elischer 		NG_FREE_DATA(m, meta);
4364cf49a43SJulian Elischer 		return (EMSGSIZE);
4374cf49a43SJulian Elischer 	}
438a8e9726dSArchie Cobbs 
439a8e9726dSArchie Cobbs 	/* Update stats */
4404cf49a43SJulian Elischer 	sc->stats.syncFrames++;
4414cf49a43SJulian Elischer 	sc->stats.syncOctets += m->m_pkthdr.len;
4424cf49a43SJulian Elischer 
4434cf49a43SJulian Elischer 	/* Initialize async encoded version of input mbuf */
4444cf49a43SJulian Elischer 	alen = 0;
4454cf49a43SJulian Elischer 	fcs = PPP_INITFCS;
4464cf49a43SJulian Elischer 
4474cf49a43SJulian Elischer 	/* Add beginning sync flag if it's been long enough to need one */
4484cf49a43SJulian Elischer 	getmicrotime(&time);
449a8e9726dSArchie Cobbs 	if (time.tv_sec >= sc->lasttime + 1) {
4504cf49a43SJulian Elischer 		sc->abuf[alen++] = PPP_FLAG;
4514cf49a43SJulian Elischer 		sc->lasttime = time.tv_sec;
4524cf49a43SJulian Elischer 	}
4534cf49a43SJulian Elischer 
45419a52c59SArchie Cobbs 	/* Add packet payload */
455a8e9726dSArchie Cobbs 	while (m != NULL) {
4564cf49a43SJulian Elischer 		struct mbuf *n;
4574cf49a43SJulian Elischer 
4584cf49a43SJulian Elischer 		while (m->m_len > 0) {
459a8e9726dSArchie Cobbs 			ADD_BYTE(*mtod(m, u_char *));
4604cf49a43SJulian Elischer 			m->m_data++;
4614cf49a43SJulian Elischer 			m->m_len--;
4624cf49a43SJulian Elischer 		}
4634cf49a43SJulian Elischer 		MFREE(m, n);
4644cf49a43SJulian Elischer 		m = n;
4654cf49a43SJulian Elischer 	}
4664cf49a43SJulian Elischer 
4674cf49a43SJulian Elischer 	/* Add checksum and final sync flag */
4684cf49a43SJulian Elischer 	fcs0 = fcs;
4694cf49a43SJulian Elischer 	ADD_BYTE(~fcs0 & 0xff);
4704cf49a43SJulian Elischer 	ADD_BYTE(~fcs0 >> 8);
4714cf49a43SJulian Elischer 	sc->abuf[alen++] = PPP_FLAG;
4724cf49a43SJulian Elischer 
4734cf49a43SJulian Elischer 	/* Put frame in an mbuf and ship it off */
474a8e9726dSArchie Cobbs 	if (!(m = m_devget(sc->abuf, alen, 0, rcvif, NULL))) {
4754cf49a43SJulian Elischer 		NG_FREE_META(meta);
4764cf49a43SJulian Elischer 		error = ENOBUFS;
477a8e9726dSArchie Cobbs 	} else
4784cf49a43SJulian Elischer 		NG_SEND_DATA(error, sc->async, m, meta);
4794cf49a43SJulian Elischer 	return (error);
4804cf49a43SJulian Elischer }
4814cf49a43SJulian Elischer 
4824cf49a43SJulian Elischer /*
4834cf49a43SJulian Elischer  * Receive incoming asynchronous data
484a8e9726dSArchie Cobbs  * XXX Technically, we should strip out incoming characters
485a8e9726dSArchie Cobbs  *     that are in our ACCM. Not sure if this is good or not.
4864cf49a43SJulian Elischer  */
4874cf49a43SJulian Elischer static int
4884cf49a43SJulian Elischer nga_rcv_async(const sc_p sc, struct mbuf * m, meta_p meta)
4894cf49a43SJulian Elischer {
4904cf49a43SJulian Elischer 	struct ifnet *const rcvif = m->m_pkthdr.rcvif;
4914cf49a43SJulian Elischer 	int error;
4924cf49a43SJulian Elischer 
4934cf49a43SJulian Elischer 	if (!sc->cfg.enabled) {
4944cf49a43SJulian Elischer 		NG_SEND_DATA(error, sc->sync, m, meta);
4954cf49a43SJulian Elischer 		return (error);
4964cf49a43SJulian Elischer 	}
4974cf49a43SJulian Elischer 	NG_FREE_META(meta);
4984cf49a43SJulian Elischer 	while (m) {
4994cf49a43SJulian Elischer 		struct mbuf *n;
5004cf49a43SJulian Elischer 
5014cf49a43SJulian Elischer 		for (; m->m_len > 0; m->m_data++, m->m_len--) {
5024cf49a43SJulian Elischer 			u_char  ch = *mtod(m, u_char *);
5034cf49a43SJulian Elischer 
5044cf49a43SJulian Elischer 			sc->stats.asyncOctets++;
5054cf49a43SJulian Elischer 			if (ch == PPP_FLAG) {	/* Flag overrides everything */
5064cf49a43SJulian Elischer 				int     skip = 0;
5074cf49a43SJulian Elischer 
5084cf49a43SJulian Elischer 				/* Check for runts */
5094cf49a43SJulian Elischer 				if (sc->slen < 2) {
5104cf49a43SJulian Elischer 					if (sc->slen > 0)
5114cf49a43SJulian Elischer 						sc->stats.asyncRunts++;
5124cf49a43SJulian Elischer 					goto reset;
5134cf49a43SJulian Elischer 				}
5144cf49a43SJulian Elischer 
5154cf49a43SJulian Elischer 				/* Verify CRC */
5164cf49a43SJulian Elischer 				if (sc->fcs != PPP_GOODFCS) {
5174cf49a43SJulian Elischer 					sc->stats.asyncBadCheckSums++;
5184cf49a43SJulian Elischer 					goto reset;
5194cf49a43SJulian Elischer 				}
5204cf49a43SJulian Elischer 				sc->slen -= 2;
5214cf49a43SJulian Elischer 
5224cf49a43SJulian Elischer 				/* Strip address and control fields */
5234cf49a43SJulian Elischer 				if (sc->slen >= 2
5244cf49a43SJulian Elischer 				    && sc->sbuf[0] == PPP_ALLSTATIONS
5254cf49a43SJulian Elischer 				    && sc->sbuf[1] == PPP_UI)
5264cf49a43SJulian Elischer 					skip = 2;
5274cf49a43SJulian Elischer 
5284cf49a43SJulian Elischer 				/* Check for frame too big */
5294cf49a43SJulian Elischer 				if (sc->slen - skip > sc->cfg.amru) {
5304cf49a43SJulian Elischer 					sc->stats.asyncOverflows++;
5314cf49a43SJulian Elischer 					goto reset;
5324cf49a43SJulian Elischer 				}
5334cf49a43SJulian Elischer 
5344cf49a43SJulian Elischer 				/* OK, ship it out */
5354cf49a43SJulian Elischer 				if ((n = m_devget(sc->sbuf + skip,
5364cf49a43SJulian Elischer 					   sc->slen - skip, 0, rcvif, NULL)))
5374cf49a43SJulian Elischer 					NG_SEND_DATA(error, sc->sync, n, meta);
5384cf49a43SJulian Elischer 				sc->stats.asyncFrames++;
5394cf49a43SJulian Elischer reset:
5404cf49a43SJulian Elischer 				sc->amode = MODE_NORMAL;
5414cf49a43SJulian Elischer 				sc->fcs = PPP_INITFCS;
5424cf49a43SJulian Elischer 				sc->slen = 0;
5434cf49a43SJulian Elischer 				continue;
5444cf49a43SJulian Elischer 			}
5454cf49a43SJulian Elischer 			switch (sc->amode) {
5464cf49a43SJulian Elischer 			case MODE_NORMAL:
5474cf49a43SJulian Elischer 				if (ch == PPP_ESCAPE) {
5484cf49a43SJulian Elischer 					sc->amode = MODE_ESC;
5494cf49a43SJulian Elischer 					continue;
5504cf49a43SJulian Elischer 				}
5514cf49a43SJulian Elischer 				break;
5524cf49a43SJulian Elischer 			case MODE_ESC:
5534cf49a43SJulian Elischer 				ch ^= PPP_TRANS;
5544cf49a43SJulian Elischer 				sc->amode = MODE_NORMAL;
5554cf49a43SJulian Elischer 				break;
5564cf49a43SJulian Elischer 			case MODE_HUNT:
5574cf49a43SJulian Elischer 			default:
5584cf49a43SJulian Elischer 				continue;
5594cf49a43SJulian Elischer 			}
5604cf49a43SJulian Elischer 
5614cf49a43SJulian Elischer 			/* Add byte to frame */
5624cf49a43SJulian Elischer 			if (sc->slen >= SYNC_BUF_SIZE(sc->cfg.amru)) {
5634cf49a43SJulian Elischer 				sc->stats.asyncOverflows++;
5644cf49a43SJulian Elischer 				sc->amode = MODE_HUNT;
5654cf49a43SJulian Elischer 				sc->slen = 0;
5664cf49a43SJulian Elischer 			} else {
5674cf49a43SJulian Elischer 				sc->sbuf[sc->slen++] = ch;
5684cf49a43SJulian Elischer 				sc->fcs = PPP_FCS(sc->fcs, ch);
5694cf49a43SJulian Elischer 			}
5704cf49a43SJulian Elischer 		}
5714cf49a43SJulian Elischer 		MFREE(m, n);
5724cf49a43SJulian Elischer 		m = n;
5734cf49a43SJulian Elischer 	}
5744cf49a43SJulian Elischer 	return (0);
5754cf49a43SJulian Elischer }
5764cf49a43SJulian Elischer 
5774cf49a43SJulian Elischer /*
5784cf49a43SJulian Elischer  * CRC table
5794cf49a43SJulian Elischer  *
5804cf49a43SJulian Elischer  * Taken from RFC 1171 Appendix B
5814cf49a43SJulian Elischer  */
5824cf49a43SJulian Elischer static const u_int16_t fcstab[256] = {
5834cf49a43SJulian Elischer 	 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
5844cf49a43SJulian Elischer 	 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
5854cf49a43SJulian Elischer 	 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
5864cf49a43SJulian Elischer 	 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
5874cf49a43SJulian Elischer 	 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
5884cf49a43SJulian Elischer 	 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
5894cf49a43SJulian Elischer 	 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
5904cf49a43SJulian Elischer 	 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
5914cf49a43SJulian Elischer 	 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
5924cf49a43SJulian Elischer 	 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
5934cf49a43SJulian Elischer 	 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
5944cf49a43SJulian Elischer 	 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
5954cf49a43SJulian Elischer 	 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
5964cf49a43SJulian Elischer 	 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
5974cf49a43SJulian Elischer 	 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
5984cf49a43SJulian Elischer 	 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
5994cf49a43SJulian Elischer 	 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
6004cf49a43SJulian Elischer 	 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
6014cf49a43SJulian Elischer 	 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
6024cf49a43SJulian Elischer 	 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
6034cf49a43SJulian Elischer 	 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
6044cf49a43SJulian Elischer 	 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
6054cf49a43SJulian Elischer 	 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
6064cf49a43SJulian Elischer 	 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
6074cf49a43SJulian Elischer 	 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
6084cf49a43SJulian Elischer 	 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
6094cf49a43SJulian Elischer 	 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
6104cf49a43SJulian Elischer 	 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
6114cf49a43SJulian Elischer 	 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
6124cf49a43SJulian Elischer 	 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
6134cf49a43SJulian Elischer 	 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
6144cf49a43SJulian Elischer 	 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
6154cf49a43SJulian Elischer };
616