xref: /freebsd/sys/netgraph/ng_async.c (revision f0184ff8e3b84a1c7273492d8854cfaa012060b5)
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 
629c8c302fSJulian Elischer #ifdef NG_SEPARATE_MALLOC
639c8c302fSJulian Elischer MALLOC_DEFINE(M_NETGRAPH_ASYNC, "netgraph_async", "netgraph async node ");
649c8c302fSJulian Elischer #else
659c8c302fSJulian Elischer #define M_NETGRAPH_ASYNC M_NETGRAPH
669c8c302fSJulian Elischer #endif
679c8c302fSJulian Elischer 
689c8c302fSJulian Elischer 
694cf49a43SJulian Elischer /* Async decode state */
704cf49a43SJulian Elischer #define MODE_HUNT	0
714cf49a43SJulian Elischer #define MODE_NORMAL	1
724cf49a43SJulian Elischer #define MODE_ESC	2
734cf49a43SJulian Elischer 
744cf49a43SJulian Elischer /* Private data structure */
7519a52c59SArchie Cobbs struct ng_async_private {
764cf49a43SJulian Elischer 	node_p  	node;		/* Our node */
774cf49a43SJulian Elischer 	hook_p  	async;		/* Asynchronous side */
784cf49a43SJulian Elischer 	hook_p  	sync;		/* Synchronous side */
794cf49a43SJulian Elischer 	u_char  	amode;		/* Async hunt/esape mode */
804cf49a43SJulian Elischer 	u_int16_t	fcs;		/* Decoded async FCS (so far) */
814cf49a43SJulian Elischer 	u_char	       *abuf;		/* Buffer to encode sync into */
824cf49a43SJulian Elischer 	u_char	       *sbuf;		/* Buffer to decode async into */
834cf49a43SJulian Elischer 	u_int		slen;		/* Length of data in sbuf */
844cf49a43SJulian Elischer 	long		lasttime;	/* Time of last async packet sent */
854cf49a43SJulian Elischer 	struct		ng_async_cfg	cfg;	/* Configuration */
864cf49a43SJulian Elischer 	struct		ng_async_stat	stats;	/* Statistics */
874cf49a43SJulian Elischer };
8819a52c59SArchie Cobbs typedef struct ng_async_private *sc_p;
894cf49a43SJulian Elischer 
904cf49a43SJulian Elischer /* Useful macros */
914cf49a43SJulian Elischer #define ASYNC_BUF_SIZE(smru)	(2 * (smru) + 10)
924cf49a43SJulian Elischer #define SYNC_BUF_SIZE(amru)	((amru) + 10)
934cf49a43SJulian Elischer #define ERROUT(x)		do { error = (x); goto done; } while (0)
944cf49a43SJulian Elischer 
954cf49a43SJulian Elischer /* Netgraph methods */
9674f5c6aaSJulian Elischer static ng_constructor_t		nga_constructor;
9774f5c6aaSJulian Elischer static ng_rcvdata_t		nga_rcvdata;
9874f5c6aaSJulian Elischer static ng_rcvmsg_t		nga_rcvmsg;
9974f5c6aaSJulian Elischer static ng_shutdown_t		nga_shutdown;
10074f5c6aaSJulian Elischer static ng_newhook_t		nga_newhook;
10174f5c6aaSJulian Elischer static ng_disconnect_t		nga_disconnect;
1024cf49a43SJulian Elischer 
1034cf49a43SJulian Elischer /* Helper stuff */
104069154d5SJulian Elischer static int	nga_rcv_sync(const sc_p sc, item_p item);
105069154d5SJulian Elischer static int	nga_rcv_async(const sc_p sc, item_p item);
1064cf49a43SJulian Elischer 
107f8307e12SArchie Cobbs /* Parse type for struct ng_async_cfg */
108f0184ff8SArchie Cobbs static const struct ng_parse_struct_field nga_config_type_fields[]
109f0184ff8SArchie Cobbs 	= NG_ASYNC_CONFIG_TYPE_INFO;
110f8307e12SArchie Cobbs static const struct ng_parse_type nga_config_type = {
111f8307e12SArchie Cobbs 	&ng_parse_struct_type,
112f0184ff8SArchie Cobbs 	&nga_config_type_fields
113f8307e12SArchie Cobbs };
114f8307e12SArchie Cobbs 
115f8307e12SArchie Cobbs /* Parse type for struct ng_async_stat */
116f0184ff8SArchie Cobbs static const struct ng_parse_struct_field nga_stats_type_fields[]
117f0184ff8SArchie Cobbs 	= NG_ASYNC_STATS_TYPE_INFO;
118f8307e12SArchie Cobbs static const struct ng_parse_type nga_stats_type = {
119f8307e12SArchie Cobbs 	&ng_parse_struct_type,
120f0184ff8SArchie Cobbs 	&nga_stats_type_fields
121f8307e12SArchie Cobbs };
122f8307e12SArchie Cobbs 
123f8307e12SArchie Cobbs /* List of commands and how to convert arguments to/from ASCII */
124f8307e12SArchie Cobbs static const struct ng_cmdlist nga_cmdlist[] = {
125f8307e12SArchie Cobbs 	{
126f8307e12SArchie Cobbs 	  NGM_ASYNC_COOKIE,
127f8307e12SArchie Cobbs 	  NGM_ASYNC_CMD_SET_CONFIG,
128f8307e12SArchie Cobbs 	  "setconfig",
129f8307e12SArchie Cobbs 	  &nga_config_type,
130f8307e12SArchie Cobbs 	  NULL
131f8307e12SArchie Cobbs 	},
132f8307e12SArchie Cobbs 	{
133f8307e12SArchie Cobbs 	  NGM_ASYNC_COOKIE,
134f8307e12SArchie Cobbs 	  NGM_ASYNC_CMD_GET_CONFIG,
135f8307e12SArchie Cobbs 	  "getconfig",
136f8307e12SArchie Cobbs 	  NULL,
137f8307e12SArchie Cobbs 	  &nga_config_type
138f8307e12SArchie Cobbs 	},
139f8307e12SArchie Cobbs 	{
140f8307e12SArchie Cobbs 	  NGM_ASYNC_COOKIE,
141f8307e12SArchie Cobbs 	  NGM_ASYNC_CMD_GET_STATS,
142f8307e12SArchie Cobbs 	  "getstats",
143f8307e12SArchie Cobbs 	  NULL,
144f8307e12SArchie Cobbs 	  &nga_stats_type
145f8307e12SArchie Cobbs 	},
146f8307e12SArchie Cobbs 	{
147f8307e12SArchie Cobbs 	  NGM_ASYNC_COOKIE,
148f8307e12SArchie Cobbs 	  NGM_ASYNC_CMD_CLR_STATS,
149f8307e12SArchie Cobbs 	  "clrstats",
150f8307e12SArchie Cobbs 	  &nga_stats_type,
151f8307e12SArchie Cobbs 	  NULL
152f8307e12SArchie Cobbs 	},
153f8307e12SArchie Cobbs 	{ 0 }
154f8307e12SArchie Cobbs };
155f8307e12SArchie Cobbs 
1564cf49a43SJulian Elischer /* Define the netgraph node type */
1574cf49a43SJulian Elischer static struct ng_type typestruct = {
158589f6ed8SJulian Elischer 	NG_ABI_VERSION,
1594cf49a43SJulian Elischer 	NG_ASYNC_NODE_TYPE,
1604cf49a43SJulian Elischer 	NULL,
1614cf49a43SJulian Elischer 	nga_constructor,
1624cf49a43SJulian Elischer 	nga_rcvmsg,
1634cf49a43SJulian Elischer 	nga_shutdown,
1644cf49a43SJulian Elischer 	nga_newhook,
1654cf49a43SJulian Elischer 	NULL,
1664cf49a43SJulian Elischer 	NULL,
1674cf49a43SJulian Elischer 	nga_rcvdata,
168f8307e12SArchie Cobbs 	nga_disconnect,
169f8307e12SArchie Cobbs 	nga_cmdlist
1704cf49a43SJulian Elischer };
1714cf49a43SJulian Elischer NETGRAPH_INIT(async, &typestruct);
1724cf49a43SJulian Elischer 
1734cf49a43SJulian Elischer /* CRC table */
1744cf49a43SJulian Elischer static const u_int16_t fcstab[];
1754cf49a43SJulian Elischer 
1764cf49a43SJulian Elischer /******************************************************************
1774cf49a43SJulian Elischer 		    NETGRAPH NODE METHODS
1784cf49a43SJulian Elischer ******************************************************************/
1794cf49a43SJulian Elischer 
1804cf49a43SJulian Elischer /*
1814cf49a43SJulian Elischer  * Initialize a new node
1824cf49a43SJulian Elischer  */
1834cf49a43SJulian Elischer static int
184069154d5SJulian Elischer nga_constructor(node_p node)
1854cf49a43SJulian Elischer {
1864cf49a43SJulian Elischer 	sc_p sc;
1874cf49a43SJulian Elischer 
1889c8c302fSJulian Elischer 	MALLOC(sc, sc_p, sizeof(*sc), M_NETGRAPH_ASYNC, M_NOWAIT | M_ZERO);
1894cf49a43SJulian Elischer 	if (sc == NULL)
1904cf49a43SJulian Elischer 		return (ENOMEM);
1914cf49a43SJulian Elischer 	sc->amode = MODE_HUNT;
1924cf49a43SJulian Elischer 	sc->cfg.accm = ~0;
1934cf49a43SJulian Elischer 	sc->cfg.amru = NG_ASYNC_DEFAULT_MRU;
1944cf49a43SJulian Elischer 	sc->cfg.smru = NG_ASYNC_DEFAULT_MRU;
1954cf49a43SJulian Elischer 	MALLOC(sc->abuf, u_char *,
1969c8c302fSJulian Elischer 	    ASYNC_BUF_SIZE(sc->cfg.smru), M_NETGRAPH_ASYNC, M_NOWAIT);
1974cf49a43SJulian Elischer 	if (sc->abuf == NULL)
1984cf49a43SJulian Elischer 		goto fail;
1994cf49a43SJulian Elischer 	MALLOC(sc->sbuf, u_char *,
2009c8c302fSJulian Elischer 	    SYNC_BUF_SIZE(sc->cfg.amru), M_NETGRAPH_ASYNC, M_NOWAIT);
2014cf49a43SJulian Elischer 	if (sc->sbuf == NULL) {
2029c8c302fSJulian Elischer 		FREE(sc->abuf, M_NETGRAPH_ASYNC);
2034cf49a43SJulian Elischer fail:
2049c8c302fSJulian Elischer 		FREE(sc, M_NETGRAPH_ASYNC);
2054cf49a43SJulian Elischer 		return (ENOMEM);
2064cf49a43SJulian Elischer 	}
20730400f03SJulian Elischer 	NG_NODE_SET_PRIVATE(node, sc);
208069154d5SJulian Elischer 	sc->node = node;
2094cf49a43SJulian Elischer 	return (0);
2104cf49a43SJulian Elischer }
2114cf49a43SJulian Elischer 
2124cf49a43SJulian Elischer /*
2134cf49a43SJulian Elischer  * Reserve a hook for a pending connection
2144cf49a43SJulian Elischer  */
2154cf49a43SJulian Elischer static int
2164cf49a43SJulian Elischer nga_newhook(node_p node, hook_p hook, const char *name)
2174cf49a43SJulian Elischer {
21830400f03SJulian Elischer 	const sc_p sc = NG_NODE_PRIVATE(node);
2194cf49a43SJulian Elischer 	hook_p *hookp;
2204cf49a43SJulian Elischer 
221069154d5SJulian Elischer 	if (!strcmp(name, NG_ASYNC_HOOK_ASYNC)) {
222069154d5SJulian Elischer 		/*
223069154d5SJulian Elischer 		 * We use a static buffer here so only one packet
224069154d5SJulian Elischer 		 * at a time can be allowed to travel in this direction.
225069154d5SJulian Elischer 		 * Force Writer semantics.
226069154d5SJulian Elischer 		 */
22730400f03SJulian Elischer 		NG_HOOK_FORCE_WRITER(hook);
2284cf49a43SJulian Elischer 		hookp = &sc->async;
229069154d5SJulian Elischer 	} else if (!strcmp(name, NG_ASYNC_HOOK_SYNC)) {
230069154d5SJulian Elischer 		/*
231069154d5SJulian Elischer 		 * We use a static state here so only one packet
232069154d5SJulian Elischer 		 * at a time can be allowed to travel in this direction.
233069154d5SJulian Elischer 		 * Force Writer semantics.
234069154d5SJulian Elischer 		 * Since we set this for both directions
235069154d5SJulian Elischer 		 * we might as well set it for the whole node
236069154d5SJulian Elischer 		 * bit I haven;t done that (yet).
237069154d5SJulian Elischer 		 */
23830400f03SJulian Elischer 		NG_HOOK_FORCE_WRITER(hook);
2394cf49a43SJulian Elischer 		hookp = &sc->sync;
240069154d5SJulian Elischer 	} else {
2414cf49a43SJulian Elischer 		return (EINVAL);
242069154d5SJulian Elischer 	}
243069154d5SJulian Elischer 	if (*hookp) /* actually can't happen I think [JRE] */
2444cf49a43SJulian Elischer 		return (EISCONN);
2454cf49a43SJulian Elischer 	*hookp = hook;
2464cf49a43SJulian Elischer 	return (0);
2474cf49a43SJulian Elischer }
2484cf49a43SJulian Elischer 
2494cf49a43SJulian Elischer /*
2504cf49a43SJulian Elischer  * Receive incoming data
2514cf49a43SJulian Elischer  */
2524cf49a43SJulian Elischer static int
253069154d5SJulian Elischer nga_rcvdata(hook_p hook, item_p item)
2544cf49a43SJulian Elischer {
25530400f03SJulian Elischer 	const sc_p sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
2564cf49a43SJulian Elischer 
2574cf49a43SJulian Elischer 	if (hook == sc->sync)
258069154d5SJulian Elischer 		return (nga_rcv_sync(sc, item));
259a8e9726dSArchie Cobbs 	if (hook == sc->async)
260069154d5SJulian Elischer 		return (nga_rcv_async(sc, item));
2616e551fb6SDavid E. O'Brien 	panic(__func__);
2624cf49a43SJulian Elischer }
2634cf49a43SJulian Elischer 
2644cf49a43SJulian Elischer /*
2654cf49a43SJulian Elischer  * Receive incoming control message
2664cf49a43SJulian Elischer  */
2674cf49a43SJulian Elischer static int
268069154d5SJulian Elischer nga_rcvmsg(node_p node, item_p item, hook_p lasthook)
2694cf49a43SJulian Elischer {
27030400f03SJulian Elischer 	const sc_p sc = NG_NODE_PRIVATE(node);
2714cf49a43SJulian Elischer 	struct ng_mesg *resp = NULL;
2724cf49a43SJulian Elischer 	int error = 0;
273069154d5SJulian Elischer 	struct ng_mesg *msg;
2744cf49a43SJulian Elischer 
275069154d5SJulian Elischer 	NGI_GET_MSG(item, msg);
2764cf49a43SJulian Elischer 	switch (msg->header.typecookie) {
2774cf49a43SJulian Elischer 	case NGM_ASYNC_COOKIE:
2784cf49a43SJulian Elischer 		switch (msg->header.cmd) {
2794cf49a43SJulian Elischer 		case NGM_ASYNC_CMD_GET_STATS:
2804cf49a43SJulian Elischer 			NG_MKRESPONSE(resp, msg, sizeof(sc->stats), M_NOWAIT);
2814cf49a43SJulian Elischer 			if (resp == NULL)
2824cf49a43SJulian Elischer 				ERROUT(ENOMEM);
2834cf49a43SJulian Elischer 			*((struct ng_async_stat *) resp->data) = sc->stats;
2844cf49a43SJulian Elischer 			break;
2854cf49a43SJulian Elischer 		case NGM_ASYNC_CMD_CLR_STATS:
2864cf49a43SJulian Elischer 			bzero(&sc->stats, sizeof(sc->stats));
2874cf49a43SJulian Elischer 			break;
2884cf49a43SJulian Elischer 		case NGM_ASYNC_CMD_SET_CONFIG:
2894cf49a43SJulian Elischer 		    {
2904cf49a43SJulian Elischer 			struct ng_async_cfg *const cfg =
2914cf49a43SJulian Elischer 				(struct ng_async_cfg *) msg->data;
2924cf49a43SJulian Elischer 			u_char *buf;
2934cf49a43SJulian Elischer 
2944cf49a43SJulian Elischer 			if (msg->header.arglen != sizeof(*cfg))
2954cf49a43SJulian Elischer 				ERROUT(EINVAL);
2964cf49a43SJulian Elischer 			if (cfg->amru < NG_ASYNC_MIN_MRU
2974cf49a43SJulian Elischer 			    || cfg->amru > NG_ASYNC_MAX_MRU
2984cf49a43SJulian Elischer 			    || cfg->smru < NG_ASYNC_MIN_MRU
2994cf49a43SJulian Elischer 			    || cfg->smru > NG_ASYNC_MAX_MRU)
3004cf49a43SJulian Elischer 				ERROUT(EINVAL);
3014cf49a43SJulian Elischer 			cfg->enabled = !!cfg->enabled;	/* normalize */
3024cf49a43SJulian Elischer 			if (cfg->smru > sc->cfg.smru) {	/* reallocate buffer */
3034cf49a43SJulian Elischer 				MALLOC(buf, u_char *, ASYNC_BUF_SIZE(cfg->smru),
3049c8c302fSJulian Elischer 				    M_NETGRAPH_ASYNC, M_NOWAIT);
3054cf49a43SJulian Elischer 				if (!buf)
3064cf49a43SJulian Elischer 					ERROUT(ENOMEM);
3079c8c302fSJulian Elischer 				FREE(sc->abuf, M_NETGRAPH_ASYNC);
3084cf49a43SJulian Elischer 				sc->abuf = buf;
3094cf49a43SJulian Elischer 			}
3104cf49a43SJulian Elischer 			if (cfg->amru > sc->cfg.amru) {	/* reallocate buffer */
3114cf49a43SJulian Elischer 				MALLOC(buf, u_char *, SYNC_BUF_SIZE(cfg->amru),
3129c8c302fSJulian Elischer 				    M_NETGRAPH_ASYNC, M_NOWAIT);
3134cf49a43SJulian Elischer 				if (!buf)
3144cf49a43SJulian Elischer 					ERROUT(ENOMEM);
3159c8c302fSJulian Elischer 				FREE(sc->sbuf, M_NETGRAPH_ASYNC);
3164cf49a43SJulian Elischer 				sc->sbuf = buf;
3174cf49a43SJulian Elischer 				sc->amode = MODE_HUNT;
3184cf49a43SJulian Elischer 				sc->slen = 0;
3194cf49a43SJulian Elischer 			}
3204cf49a43SJulian Elischer 			if (!cfg->enabled) {
3214cf49a43SJulian Elischer 				sc->amode = MODE_HUNT;
3224cf49a43SJulian Elischer 				sc->slen = 0;
3234cf49a43SJulian Elischer 			}
3244cf49a43SJulian Elischer 			sc->cfg = *cfg;
3254cf49a43SJulian Elischer 			break;
3264cf49a43SJulian Elischer 		    }
3274cf49a43SJulian Elischer 		case NGM_ASYNC_CMD_GET_CONFIG:
3284cf49a43SJulian Elischer 			NG_MKRESPONSE(resp, msg, sizeof(sc->cfg), M_NOWAIT);
3294cf49a43SJulian Elischer 			if (!resp)
3304cf49a43SJulian Elischer 				ERROUT(ENOMEM);
3314cf49a43SJulian Elischer 			*((struct ng_async_cfg *) resp->data) = sc->cfg;
3324cf49a43SJulian Elischer 			break;
3334cf49a43SJulian Elischer 		default:
3344cf49a43SJulian Elischer 			ERROUT(EINVAL);
3354cf49a43SJulian Elischer 		}
3364cf49a43SJulian Elischer 		break;
3374cf49a43SJulian Elischer 	default:
3384cf49a43SJulian Elischer 		ERROUT(EINVAL);
3394cf49a43SJulian Elischer 	}
3404cf49a43SJulian Elischer done:
341069154d5SJulian Elischer 	NG_RESPOND_MSG(error, node, item, resp);
342069154d5SJulian Elischer 	NG_FREE_MSG(msg);
3434cf49a43SJulian Elischer 	return (error);
3444cf49a43SJulian Elischer }
3454cf49a43SJulian Elischer 
3464cf49a43SJulian Elischer /*
3474cf49a43SJulian Elischer  * Shutdown this node
3484cf49a43SJulian Elischer  */
3494cf49a43SJulian Elischer static int
3504cf49a43SJulian Elischer nga_shutdown(node_p node)
3514cf49a43SJulian Elischer {
35230400f03SJulian Elischer 	const sc_p sc = NG_NODE_PRIVATE(node);
3534cf49a43SJulian Elischer 
3549c8c302fSJulian Elischer 	FREE(sc->abuf, M_NETGRAPH_ASYNC);
3559c8c302fSJulian Elischer 	FREE(sc->sbuf, M_NETGRAPH_ASYNC);
3564cf49a43SJulian Elischer 	bzero(sc, sizeof(*sc));
3579c8c302fSJulian Elischer 	FREE(sc, M_NETGRAPH_ASYNC);
35830400f03SJulian Elischer 	NG_NODE_SET_PRIVATE(node, NULL);
35930400f03SJulian Elischer 	NG_NODE_UNREF(node);
3604cf49a43SJulian Elischer 	return (0);
3614cf49a43SJulian Elischer }
3624cf49a43SJulian Elischer 
3634cf49a43SJulian Elischer /*
3644cf49a43SJulian Elischer  * Lose a hook. When both hooks go away, we disappear.
3654cf49a43SJulian Elischer  */
3664cf49a43SJulian Elischer static int
3674cf49a43SJulian Elischer nga_disconnect(hook_p hook)
3684cf49a43SJulian Elischer {
36930400f03SJulian Elischer 	const sc_p sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
3704cf49a43SJulian Elischer 	hook_p *hookp;
3714cf49a43SJulian Elischer 
3724cf49a43SJulian Elischer 	if (hook == sc->async)
3734cf49a43SJulian Elischer 		hookp = &sc->async;
3744cf49a43SJulian Elischer 	else if (hook == sc->sync)
3754cf49a43SJulian Elischer 		hookp = &sc->sync;
3764cf49a43SJulian Elischer 	else
3776e551fb6SDavid E. O'Brien 		panic(__func__);
3784cf49a43SJulian Elischer 	if (!*hookp)
3796e551fb6SDavid E. O'Brien 		panic("%s 2", __func__);
3804cf49a43SJulian Elischer 	*hookp = NULL;
3814cf49a43SJulian Elischer 	bzero(&sc->stats, sizeof(sc->stats));
3824cf49a43SJulian Elischer 	sc->lasttime = 0;
38330400f03SJulian Elischer 	if ((NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0)
38430400f03SJulian Elischer 	&& (NG_NODE_IS_VALID(NG_HOOK_NODE(hook))))
38530400f03SJulian Elischer 		ng_rmnode_self(NG_HOOK_NODE(hook));
3864cf49a43SJulian Elischer 	return (0);
3874cf49a43SJulian Elischer }
3884cf49a43SJulian Elischer 
3894cf49a43SJulian Elischer /******************************************************************
3904cf49a43SJulian Elischer 		    INTERNAL HELPER STUFF
3914cf49a43SJulian Elischer ******************************************************************/
3924cf49a43SJulian Elischer 
3934cf49a43SJulian Elischer /*
3944cf49a43SJulian Elischer  * Encode a byte into the async buffer
3954cf49a43SJulian Elischer  */
3964cf49a43SJulian Elischer static __inline__ void
3974cf49a43SJulian Elischer nga_async_add(const sc_p sc, u_int16_t *fcs, u_int32_t accm, int *len, u_char x)
3984cf49a43SJulian Elischer {
3994cf49a43SJulian Elischer 	*fcs = PPP_FCS(*fcs, x);
4004cf49a43SJulian Elischer 	if ((x < 32 && ((1 << x) & accm))
4014cf49a43SJulian Elischer 	    || (x == PPP_ESCAPE)
4024cf49a43SJulian Elischer 	    || (x == PPP_FLAG)) {
4034cf49a43SJulian Elischer 		sc->abuf[(*len)++] = PPP_ESCAPE;
4044cf49a43SJulian Elischer 		x ^= PPP_TRANS;
4054cf49a43SJulian Elischer 	}
4064cf49a43SJulian Elischer 	sc->abuf[(*len)++] = x;
4074cf49a43SJulian Elischer }
4084cf49a43SJulian Elischer 
4094cf49a43SJulian Elischer /*
410a8e9726dSArchie Cobbs  * Receive incoming synchronous data.
4114cf49a43SJulian Elischer  */
4124cf49a43SJulian Elischer static int
413069154d5SJulian Elischer nga_rcv_sync(const sc_p sc, item_p item)
4144cf49a43SJulian Elischer {
415069154d5SJulian Elischer 	struct ifnet *rcvif;
41619a52c59SArchie Cobbs 	int alen, error = 0;
417a8e9726dSArchie Cobbs 	struct timeval time;
4184cf49a43SJulian Elischer 	u_int16_t fcs, fcs0;
419a8e9726dSArchie Cobbs 	u_int32_t accm;
420069154d5SJulian Elischer 	struct mbuf *m;
421069154d5SJulian Elischer 
4224cf49a43SJulian Elischer 
423a8e9726dSArchie Cobbs #define ADD_BYTE(x)	nga_async_add(sc, &fcs, accm, &alen, (x))
4244cf49a43SJulian Elischer 
425a8e9726dSArchie Cobbs 	/* Check for bypass mode */
4264cf49a43SJulian Elischer 	if (!sc->cfg.enabled) {
42730400f03SJulian Elischer 		NG_FWD_ITEM_HOOK(error, item, sc->async );
4284cf49a43SJulian Elischer 		return (error);
4294cf49a43SJulian Elischer 	}
430069154d5SJulian Elischer 	NGI_GET_M(item, m);
431069154d5SJulian Elischer 
432069154d5SJulian Elischer 	rcvif = m->m_pkthdr.rcvif;
433a8e9726dSArchie Cobbs 
43419a52c59SArchie Cobbs 	/* Get ACCM; special case LCP frames, which use full ACCM */
435a8e9726dSArchie Cobbs 	accm = sc->cfg.accm;
43619a52c59SArchie Cobbs 	if (m->m_pkthdr.len >= 4) {
43719a52c59SArchie Cobbs 		static const u_char lcphdr[4] = {
43819a52c59SArchie Cobbs 		    PPP_ALLSTATIONS,
43919a52c59SArchie Cobbs 		    PPP_UI,
44019a52c59SArchie Cobbs 		    (u_char)(PPP_LCP >> 8),
44119a52c59SArchie Cobbs 		    (u_char)(PPP_LCP & 0xff)
44219a52c59SArchie Cobbs 		};
44319a52c59SArchie Cobbs 		u_char buf[4];
444a8e9726dSArchie Cobbs 
44519a52c59SArchie Cobbs 		m_copydata(m, 0, 4, (caddr_t)buf);
44619a52c59SArchie Cobbs 		if (bcmp(buf, &lcphdr, 4) == 0)
447a8e9726dSArchie Cobbs 			accm = ~0;
448a8e9726dSArchie Cobbs 	}
449a8e9726dSArchie Cobbs 
450a8e9726dSArchie Cobbs 	/* Check for overflow */
4514cf49a43SJulian Elischer 	if (m->m_pkthdr.len > sc->cfg.smru) {
4524cf49a43SJulian Elischer 		sc->stats.syncOverflows++;
453069154d5SJulian Elischer 		NG_FREE_M(m);
454069154d5SJulian Elischer 		NG_FREE_ITEM(item);
4554cf49a43SJulian Elischer 		return (EMSGSIZE);
4564cf49a43SJulian Elischer 	}
457a8e9726dSArchie Cobbs 
458a8e9726dSArchie Cobbs 	/* Update stats */
4594cf49a43SJulian Elischer 	sc->stats.syncFrames++;
4604cf49a43SJulian Elischer 	sc->stats.syncOctets += m->m_pkthdr.len;
4614cf49a43SJulian Elischer 
4624cf49a43SJulian Elischer 	/* Initialize async encoded version of input mbuf */
4634cf49a43SJulian Elischer 	alen = 0;
4644cf49a43SJulian Elischer 	fcs = PPP_INITFCS;
4654cf49a43SJulian Elischer 
4664cf49a43SJulian Elischer 	/* Add beginning sync flag if it's been long enough to need one */
4674cf49a43SJulian Elischer 	getmicrotime(&time);
468a8e9726dSArchie Cobbs 	if (time.tv_sec >= sc->lasttime + 1) {
4694cf49a43SJulian Elischer 		sc->abuf[alen++] = PPP_FLAG;
4704cf49a43SJulian Elischer 		sc->lasttime = time.tv_sec;
4714cf49a43SJulian Elischer 	}
4724cf49a43SJulian Elischer 
47319a52c59SArchie Cobbs 	/* Add packet payload */
474a8e9726dSArchie Cobbs 	while (m != NULL) {
4754cf49a43SJulian Elischer 		while (m->m_len > 0) {
476a8e9726dSArchie Cobbs 			ADD_BYTE(*mtod(m, u_char *));
4774cf49a43SJulian Elischer 			m->m_data++;
4784cf49a43SJulian Elischer 			m->m_len--;
4794cf49a43SJulian Elischer 		}
480ecde8f7cSMatthew Dillon 		m = m_free(m);
4814cf49a43SJulian Elischer 	}
4824cf49a43SJulian Elischer 
4834cf49a43SJulian Elischer 	/* Add checksum and final sync flag */
4844cf49a43SJulian Elischer 	fcs0 = fcs;
4854cf49a43SJulian Elischer 	ADD_BYTE(~fcs0 & 0xff);
4864cf49a43SJulian Elischer 	ADD_BYTE(~fcs0 >> 8);
4874cf49a43SJulian Elischer 	sc->abuf[alen++] = PPP_FLAG;
4884cf49a43SJulian Elischer 
4894cf49a43SJulian Elischer 	/* Put frame in an mbuf and ship it off */
490a8e9726dSArchie Cobbs 	if (!(m = m_devget(sc->abuf, alen, 0, rcvif, NULL))) {
491069154d5SJulian Elischer 		NG_FREE_ITEM(item);
4924cf49a43SJulian Elischer 		error = ENOBUFS;
493069154d5SJulian Elischer 	} else {
494069154d5SJulian Elischer 		NG_FWD_NEW_DATA(error, item, sc->async, m);
495069154d5SJulian Elischer 	}
4964cf49a43SJulian Elischer 	return (error);
4974cf49a43SJulian Elischer }
4984cf49a43SJulian Elischer 
4994cf49a43SJulian Elischer /*
5004cf49a43SJulian Elischer  * Receive incoming asynchronous data
501a8e9726dSArchie Cobbs  * XXX Technically, we should strip out incoming characters
502a8e9726dSArchie Cobbs  *     that are in our ACCM. Not sure if this is good or not.
5034cf49a43SJulian Elischer  */
5044cf49a43SJulian Elischer static int
505069154d5SJulian Elischer nga_rcv_async(const sc_p sc, item_p item)
5064cf49a43SJulian Elischer {
507069154d5SJulian Elischer 	struct ifnet *rcvif;
5084cf49a43SJulian Elischer 	int error;
509069154d5SJulian Elischer 	struct mbuf *m;
5104cf49a43SJulian Elischer 
5114cf49a43SJulian Elischer 	if (!sc->cfg.enabled) {
51230400f03SJulian Elischer 		NG_FWD_ITEM_HOOK(error, item,  sc->sync);
5134cf49a43SJulian Elischer 		return (error);
5144cf49a43SJulian Elischer 	}
515069154d5SJulian Elischer 	NGI_GET_M(item, m);
516069154d5SJulian Elischer 	rcvif = m->m_pkthdr.rcvif;
5174cf49a43SJulian Elischer 	while (m) {
5184cf49a43SJulian Elischer 		struct mbuf *n;
5194cf49a43SJulian Elischer 
5204cf49a43SJulian Elischer 		for (; m->m_len > 0; m->m_data++, m->m_len--) {
5214cf49a43SJulian Elischer 			u_char  ch = *mtod(m, u_char *);
5224cf49a43SJulian Elischer 
5234cf49a43SJulian Elischer 			sc->stats.asyncOctets++;
5244cf49a43SJulian Elischer 			if (ch == PPP_FLAG) {	/* Flag overrides everything */
5254cf49a43SJulian Elischer 				int     skip = 0;
5264cf49a43SJulian Elischer 
5274cf49a43SJulian Elischer 				/* Check for runts */
5284cf49a43SJulian Elischer 				if (sc->slen < 2) {
5294cf49a43SJulian Elischer 					if (sc->slen > 0)
5304cf49a43SJulian Elischer 						sc->stats.asyncRunts++;
5314cf49a43SJulian Elischer 					goto reset;
5324cf49a43SJulian Elischer 				}
5334cf49a43SJulian Elischer 
5344cf49a43SJulian Elischer 				/* Verify CRC */
5354cf49a43SJulian Elischer 				if (sc->fcs != PPP_GOODFCS) {
5364cf49a43SJulian Elischer 					sc->stats.asyncBadCheckSums++;
5374cf49a43SJulian Elischer 					goto reset;
5384cf49a43SJulian Elischer 				}
5394cf49a43SJulian Elischer 				sc->slen -= 2;
5404cf49a43SJulian Elischer 
5414cf49a43SJulian Elischer 				/* Strip address and control fields */
5424cf49a43SJulian Elischer 				if (sc->slen >= 2
5434cf49a43SJulian Elischer 				    && sc->sbuf[0] == PPP_ALLSTATIONS
5444cf49a43SJulian Elischer 				    && sc->sbuf[1] == PPP_UI)
5454cf49a43SJulian Elischer 					skip = 2;
5464cf49a43SJulian Elischer 
5474cf49a43SJulian Elischer 				/* Check for frame too big */
5484cf49a43SJulian Elischer 				if (sc->slen - skip > sc->cfg.amru) {
5494cf49a43SJulian Elischer 					sc->stats.asyncOverflows++;
5504cf49a43SJulian Elischer 					goto reset;
5514cf49a43SJulian Elischer 				}
5524cf49a43SJulian Elischer 
5534cf49a43SJulian Elischer 				/* OK, ship it out */
5544cf49a43SJulian Elischer 				if ((n = m_devget(sc->sbuf + skip,
555069154d5SJulian Elischer 					   sc->slen - skip, 0, rcvif, NULL))) {
556069154d5SJulian Elischer 					if (item) { /* sets NULL -> item */
557069154d5SJulian Elischer 						NG_FWD_NEW_DATA(error, item,
558069154d5SJulian Elischer 							sc->sync, n);
559069154d5SJulian Elischer 					} else {
560069154d5SJulian Elischer 						NG_SEND_DATA_ONLY(error,
561069154d5SJulian Elischer 							sc->sync ,n);
562069154d5SJulian Elischer 					}
563069154d5SJulian Elischer 				}
5644cf49a43SJulian Elischer 				sc->stats.asyncFrames++;
5654cf49a43SJulian Elischer reset:
5664cf49a43SJulian Elischer 				sc->amode = MODE_NORMAL;
5674cf49a43SJulian Elischer 				sc->fcs = PPP_INITFCS;
5684cf49a43SJulian Elischer 				sc->slen = 0;
5694cf49a43SJulian Elischer 				continue;
5704cf49a43SJulian Elischer 			}
5714cf49a43SJulian Elischer 			switch (sc->amode) {
5724cf49a43SJulian Elischer 			case MODE_NORMAL:
5734cf49a43SJulian Elischer 				if (ch == PPP_ESCAPE) {
5744cf49a43SJulian Elischer 					sc->amode = MODE_ESC;
5754cf49a43SJulian Elischer 					continue;
5764cf49a43SJulian Elischer 				}
5774cf49a43SJulian Elischer 				break;
5784cf49a43SJulian Elischer 			case MODE_ESC:
5794cf49a43SJulian Elischer 				ch ^= PPP_TRANS;
5804cf49a43SJulian Elischer 				sc->amode = MODE_NORMAL;
5814cf49a43SJulian Elischer 				break;
5824cf49a43SJulian Elischer 			case MODE_HUNT:
5834cf49a43SJulian Elischer 			default:
5844cf49a43SJulian Elischer 				continue;
5854cf49a43SJulian Elischer 			}
5864cf49a43SJulian Elischer 
5874cf49a43SJulian Elischer 			/* Add byte to frame */
5884cf49a43SJulian Elischer 			if (sc->slen >= SYNC_BUF_SIZE(sc->cfg.amru)) {
5894cf49a43SJulian Elischer 				sc->stats.asyncOverflows++;
5904cf49a43SJulian Elischer 				sc->amode = MODE_HUNT;
5914cf49a43SJulian Elischer 				sc->slen = 0;
5924cf49a43SJulian Elischer 			} else {
5934cf49a43SJulian Elischer 				sc->sbuf[sc->slen++] = ch;
5944cf49a43SJulian Elischer 				sc->fcs = PPP_FCS(sc->fcs, ch);
5954cf49a43SJulian Elischer 			}
5964cf49a43SJulian Elischer 		}
597ecde8f7cSMatthew Dillon 		m = m_free(m);
5984cf49a43SJulian Elischer 	}
599069154d5SJulian Elischer 	if (item)
600069154d5SJulian Elischer 		NG_FREE_ITEM(item);
6014cf49a43SJulian Elischer 	return (0);
6024cf49a43SJulian Elischer }
6034cf49a43SJulian Elischer 
6044cf49a43SJulian Elischer /*
6054cf49a43SJulian Elischer  * CRC table
6064cf49a43SJulian Elischer  *
6074cf49a43SJulian Elischer  * Taken from RFC 1171 Appendix B
6084cf49a43SJulian Elischer  */
6094cf49a43SJulian Elischer static const u_int16_t fcstab[256] = {
6104cf49a43SJulian Elischer 	 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
6114cf49a43SJulian Elischer 	 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
6124cf49a43SJulian Elischer 	 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
6134cf49a43SJulian Elischer 	 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
6144cf49a43SJulian Elischer 	 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
6154cf49a43SJulian Elischer 	 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
6164cf49a43SJulian Elischer 	 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
6174cf49a43SJulian Elischer 	 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
6184cf49a43SJulian Elischer 	 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
6194cf49a43SJulian Elischer 	 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
6204cf49a43SJulian Elischer 	 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
6214cf49a43SJulian Elischer 	 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
6224cf49a43SJulian Elischer 	 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
6234cf49a43SJulian Elischer 	 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
6244cf49a43SJulian Elischer 	 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
6254cf49a43SJulian Elischer 	 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
6264cf49a43SJulian Elischer 	 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
6274cf49a43SJulian Elischer 	 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
6284cf49a43SJulian Elischer 	 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
6294cf49a43SJulian Elischer 	 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
6304cf49a43SJulian Elischer 	 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
6314cf49a43SJulian Elischer 	 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
6324cf49a43SJulian Elischer 	 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
6334cf49a43SJulian Elischer 	 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
6344cf49a43SJulian Elischer 	 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
6354cf49a43SJulian Elischer 	 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
6364cf49a43SJulian Elischer 	 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
6374cf49a43SJulian Elischer 	 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
6384cf49a43SJulian Elischer 	 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
6394cf49a43SJulian Elischer 	 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
6404cf49a43SJulian Elischer 	 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
6414cf49a43SJulian Elischer 	 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
6424cf49a43SJulian Elischer };
643