xref: /freebsd/sys/netgraph/ng_async.c (revision 674d86bf9177ff80b5f38f7191951f303a816cac)
14cf49a43SJulian Elischer /*
24cf49a43SJulian Elischer  * ng_async.c
3c398230bSWarner Losh  */
4c398230bSWarner Losh 
5c398230bSWarner Losh /*-
64cf49a43SJulian Elischer  * Copyright (c) 1996-1999 Whistle Communications, Inc.
74cf49a43SJulian Elischer  * All rights reserved.
84cf49a43SJulian Elischer  *
94cf49a43SJulian Elischer  * Subject to the following obligations and disclaimer of warranty, use and
104cf49a43SJulian Elischer  * redistribution of this software, in source or object code forms, with or
114cf49a43SJulian Elischer  * without modifications are expressly permitted by Whistle Communications;
124cf49a43SJulian Elischer  * provided, however, that:
134cf49a43SJulian Elischer  * 1. Any and all reproductions of the source or object code must include the
144cf49a43SJulian Elischer  *    copyright notice above and the following disclaimer of warranties; and
154cf49a43SJulian Elischer  * 2. No rights are granted, in any manner or form, to use Whistle
164cf49a43SJulian Elischer  *    Communications, Inc. trademarks, including the mark "WHISTLE
174cf49a43SJulian Elischer  *    COMMUNICATIONS" on advertising, endorsements, or otherwise except as
184cf49a43SJulian Elischer  *    such appears in the above copyright notice or in the software.
194cf49a43SJulian Elischer  *
204cf49a43SJulian Elischer  * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
214cf49a43SJulian Elischer  * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
224cf49a43SJulian Elischer  * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
234cf49a43SJulian Elischer  * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
244cf49a43SJulian Elischer  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
254cf49a43SJulian Elischer  * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
264cf49a43SJulian Elischer  * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
274cf49a43SJulian Elischer  * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
284cf49a43SJulian Elischer  * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
294cf49a43SJulian Elischer  * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
304cf49a43SJulian Elischer  * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
314cf49a43SJulian Elischer  * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
324cf49a43SJulian Elischer  * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
334cf49a43SJulian Elischer  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
344cf49a43SJulian Elischer  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
354cf49a43SJulian Elischer  * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
364cf49a43SJulian Elischer  * OF SUCH DAMAGE.
374cf49a43SJulian Elischer  *
38cc3bbd68SJulian Elischer  * Author: Archie Cobbs <archie@freebsd.org>
394cf49a43SJulian Elischer  *
404cf49a43SJulian Elischer  * $FreeBSD$
4174f5c6aaSJulian Elischer  * $Whistle: ng_async.c,v 1.17 1999/11/01 09:24:51 julian Exp $
424cf49a43SJulian Elischer  */
434cf49a43SJulian Elischer 
444cf49a43SJulian Elischer /*
454cf49a43SJulian Elischer  * This node type implements a PPP style sync <-> async converter.
464cf49a43SJulian Elischer  * See RFC 1661 for details of how asynchronous encoding works.
474cf49a43SJulian Elischer  */
484cf49a43SJulian Elischer 
494cf49a43SJulian Elischer #include <sys/param.h>
504cf49a43SJulian Elischer #include <sys/systm.h>
514cf49a43SJulian Elischer #include <sys/kernel.h>
524cf49a43SJulian Elischer #include <sys/mbuf.h>
534cf49a43SJulian Elischer #include <sys/malloc.h>
544cf49a43SJulian Elischer #include <sys/errno.h>
554cf49a43SJulian Elischer 
564cf49a43SJulian Elischer #include <netgraph/ng_message.h>
574cf49a43SJulian Elischer #include <netgraph/netgraph.h>
584cf49a43SJulian Elischer #include <netgraph/ng_async.h>
59f8307e12SArchie Cobbs #include <netgraph/ng_parse.h>
604cf49a43SJulian Elischer 
614cf49a43SJulian Elischer #include <net/ppp_defs.h>
624cf49a43SJulian Elischer 
639c8c302fSJulian Elischer #ifdef NG_SEPARATE_MALLOC
649c8c302fSJulian Elischer MALLOC_DEFINE(M_NETGRAPH_ASYNC, "netgraph_async", "netgraph async node ");
659c8c302fSJulian Elischer #else
669c8c302fSJulian Elischer #define M_NETGRAPH_ASYNC M_NETGRAPH
679c8c302fSJulian Elischer #endif
689c8c302fSJulian Elischer 
699c8c302fSJulian 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 */
7619a52c59SArchie Cobbs struct ng_async_private {
774cf49a43SJulian Elischer 	node_p  	node;		/* Our node */
784cf49a43SJulian Elischer 	hook_p  	async;		/* Asynchronous side */
794cf49a43SJulian Elischer 	hook_p  	sync;		/* Synchronous side */
804cf49a43SJulian Elischer 	u_char  	amode;		/* Async hunt/esape mode */
814cf49a43SJulian Elischer 	u_int16_t	fcs;		/* Decoded async FCS (so far) */
824cf49a43SJulian Elischer 	u_char	       *abuf;		/* Buffer to encode sync into */
834cf49a43SJulian Elischer 	u_char	       *sbuf;		/* Buffer to decode async into */
844cf49a43SJulian Elischer 	u_int		slen;		/* Length of data in sbuf */
854cf49a43SJulian Elischer 	long		lasttime;	/* Time of last async packet sent */
864cf49a43SJulian Elischer 	struct		ng_async_cfg	cfg;	/* Configuration */
874cf49a43SJulian Elischer 	struct		ng_async_stat	stats;	/* Statistics */
884cf49a43SJulian Elischer };
8919a52c59SArchie Cobbs typedef struct ng_async_private *sc_p;
904cf49a43SJulian Elischer 
914cf49a43SJulian Elischer /* Useful macros */
924cf49a43SJulian Elischer #define ASYNC_BUF_SIZE(smru)	(2 * (smru) + 10)
934cf49a43SJulian Elischer #define SYNC_BUF_SIZE(amru)	((amru) + 10)
944cf49a43SJulian Elischer #define ERROUT(x)		do { error = (x); goto done; } while (0)
954cf49a43SJulian Elischer 
964cf49a43SJulian Elischer /* Netgraph methods */
9774f5c6aaSJulian Elischer static ng_constructor_t		nga_constructor;
9874f5c6aaSJulian Elischer static ng_rcvdata_t		nga_rcvdata;
9974f5c6aaSJulian Elischer static ng_rcvmsg_t		nga_rcvmsg;
10074f5c6aaSJulian Elischer static ng_shutdown_t		nga_shutdown;
10174f5c6aaSJulian Elischer static ng_newhook_t		nga_newhook;
10274f5c6aaSJulian Elischer static ng_disconnect_t		nga_disconnect;
1034cf49a43SJulian Elischer 
1044cf49a43SJulian Elischer /* Helper stuff */
105069154d5SJulian Elischer static int	nga_rcv_sync(const sc_p sc, item_p item);
106069154d5SJulian Elischer static int	nga_rcv_async(const sc_p sc, item_p item);
1074cf49a43SJulian Elischer 
108f8307e12SArchie Cobbs /* Parse type for struct ng_async_cfg */
109f0184ff8SArchie Cobbs static const struct ng_parse_struct_field nga_config_type_fields[]
110f0184ff8SArchie Cobbs 	= NG_ASYNC_CONFIG_TYPE_INFO;
111f8307e12SArchie Cobbs static const struct ng_parse_type nga_config_type = {
112f8307e12SArchie Cobbs 	&ng_parse_struct_type,
113f0184ff8SArchie Cobbs 	&nga_config_type_fields
114f8307e12SArchie Cobbs };
115f8307e12SArchie Cobbs 
116f8307e12SArchie Cobbs /* Parse type for struct ng_async_stat */
117f0184ff8SArchie Cobbs static const struct ng_parse_struct_field nga_stats_type_fields[]
118f0184ff8SArchie Cobbs 	= NG_ASYNC_STATS_TYPE_INFO;
119f8307e12SArchie Cobbs static const struct ng_parse_type nga_stats_type = {
120f8307e12SArchie Cobbs 	&ng_parse_struct_type,
121f0184ff8SArchie Cobbs 	&nga_stats_type_fields
122f8307e12SArchie Cobbs };
123f8307e12SArchie Cobbs 
124f8307e12SArchie Cobbs /* List of commands and how to convert arguments to/from ASCII */
125f8307e12SArchie Cobbs static const struct ng_cmdlist nga_cmdlist[] = {
126f8307e12SArchie Cobbs 	{
127f8307e12SArchie Cobbs 	  NGM_ASYNC_COOKIE,
128f8307e12SArchie Cobbs 	  NGM_ASYNC_CMD_SET_CONFIG,
129f8307e12SArchie Cobbs 	  "setconfig",
130f8307e12SArchie Cobbs 	  &nga_config_type,
131f8307e12SArchie Cobbs 	  NULL
132f8307e12SArchie Cobbs 	},
133f8307e12SArchie Cobbs 	{
134f8307e12SArchie Cobbs 	  NGM_ASYNC_COOKIE,
135f8307e12SArchie Cobbs 	  NGM_ASYNC_CMD_GET_CONFIG,
136f8307e12SArchie Cobbs 	  "getconfig",
137f8307e12SArchie Cobbs 	  NULL,
138f8307e12SArchie Cobbs 	  &nga_config_type
139f8307e12SArchie Cobbs 	},
140f8307e12SArchie Cobbs 	{
141f8307e12SArchie Cobbs 	  NGM_ASYNC_COOKIE,
142f8307e12SArchie Cobbs 	  NGM_ASYNC_CMD_GET_STATS,
143f8307e12SArchie Cobbs 	  "getstats",
144f8307e12SArchie Cobbs 	  NULL,
145f8307e12SArchie Cobbs 	  &nga_stats_type
146f8307e12SArchie Cobbs 	},
147f8307e12SArchie Cobbs 	{
148f8307e12SArchie Cobbs 	  NGM_ASYNC_COOKIE,
149f8307e12SArchie Cobbs 	  NGM_ASYNC_CMD_CLR_STATS,
150f8307e12SArchie Cobbs 	  "clrstats",
151f8307e12SArchie Cobbs 	  &nga_stats_type,
152f8307e12SArchie Cobbs 	  NULL
153f8307e12SArchie Cobbs 	},
154f8307e12SArchie Cobbs 	{ 0 }
155f8307e12SArchie Cobbs };
156f8307e12SArchie Cobbs 
1574cf49a43SJulian Elischer /* Define the netgraph node type */
1584cf49a43SJulian Elischer static struct ng_type typestruct = {
159f8aae777SJulian Elischer 	.version =	NG_ABI_VERSION,
160f8aae777SJulian Elischer 	.name =		NG_ASYNC_NODE_TYPE,
161f8aae777SJulian Elischer 	.constructor =	nga_constructor,
162f8aae777SJulian Elischer 	.rcvmsg =	nga_rcvmsg,
163f8aae777SJulian Elischer 	.shutdown = 	nga_shutdown,
164f8aae777SJulian Elischer 	.newhook =	nga_newhook,
165f8aae777SJulian Elischer 	.rcvdata =	nga_rcvdata,
166f8aae777SJulian Elischer 	.disconnect =	nga_disconnect,
167f8aae777SJulian Elischer 	.cmdlist =	nga_cmdlist
1684cf49a43SJulian Elischer };
1694cf49a43SJulian Elischer NETGRAPH_INIT(async, &typestruct);
1704cf49a43SJulian Elischer 
1714cf49a43SJulian Elischer /* CRC table */
1724cf49a43SJulian Elischer static const u_int16_t fcstab[];
1734cf49a43SJulian Elischer 
1744cf49a43SJulian Elischer /******************************************************************
1754cf49a43SJulian Elischer 		    NETGRAPH NODE METHODS
1764cf49a43SJulian Elischer ******************************************************************/
1774cf49a43SJulian Elischer 
1784cf49a43SJulian Elischer /*
1794cf49a43SJulian Elischer  * Initialize a new node
1804cf49a43SJulian Elischer  */
1814cf49a43SJulian Elischer static int
182069154d5SJulian Elischer nga_constructor(node_p node)
1834cf49a43SJulian Elischer {
1844cf49a43SJulian Elischer 	sc_p sc;
1854cf49a43SJulian Elischer 
186*674d86bfSGleb Smirnoff 	sc = malloc(sizeof(*sc), M_NETGRAPH_ASYNC, M_WAITOK | M_ZERO);
1874cf49a43SJulian Elischer 	sc->amode = MODE_HUNT;
1884cf49a43SJulian Elischer 	sc->cfg.accm = ~0;
1894cf49a43SJulian Elischer 	sc->cfg.amru = NG_ASYNC_DEFAULT_MRU;
1904cf49a43SJulian Elischer 	sc->cfg.smru = NG_ASYNC_DEFAULT_MRU;
191e11e3f18SDag-Erling Smørgrav 	sc->abuf = malloc(ASYNC_BUF_SIZE(sc->cfg.smru),
192*674d86bfSGleb Smirnoff 	    M_NETGRAPH_ASYNC, M_WAITOK);
193e11e3f18SDag-Erling Smørgrav 	sc->sbuf = malloc(SYNC_BUF_SIZE(sc->cfg.amru),
194*674d86bfSGleb Smirnoff 	    M_NETGRAPH_ASYNC, M_WAITOK);
19530400f03SJulian Elischer 	NG_NODE_SET_PRIVATE(node, sc);
196069154d5SJulian Elischer 	sc->node = node;
1974cf49a43SJulian Elischer 	return (0);
1984cf49a43SJulian Elischer }
1994cf49a43SJulian Elischer 
2004cf49a43SJulian Elischer /*
2014cf49a43SJulian Elischer  * Reserve a hook for a pending connection
2024cf49a43SJulian Elischer  */
2034cf49a43SJulian Elischer static int
2044cf49a43SJulian Elischer nga_newhook(node_p node, hook_p hook, const char *name)
2054cf49a43SJulian Elischer {
20630400f03SJulian Elischer 	const sc_p sc = NG_NODE_PRIVATE(node);
2074cf49a43SJulian Elischer 	hook_p *hookp;
2084cf49a43SJulian Elischer 
209069154d5SJulian Elischer 	if (!strcmp(name, NG_ASYNC_HOOK_ASYNC)) {
210069154d5SJulian Elischer 		/*
211069154d5SJulian Elischer 		 * We use a static buffer here so only one packet
212069154d5SJulian Elischer 		 * at a time can be allowed to travel in this direction.
213069154d5SJulian Elischer 		 * Force Writer semantics.
214069154d5SJulian Elischer 		 */
21530400f03SJulian Elischer 		NG_HOOK_FORCE_WRITER(hook);
2164cf49a43SJulian Elischer 		hookp = &sc->async;
217069154d5SJulian Elischer 	} else if (!strcmp(name, NG_ASYNC_HOOK_SYNC)) {
218069154d5SJulian Elischer 		/*
219069154d5SJulian Elischer 		 * We use a static state here so only one packet
220069154d5SJulian Elischer 		 * at a time can be allowed to travel in this direction.
221069154d5SJulian Elischer 		 * Force Writer semantics.
222069154d5SJulian Elischer 		 * Since we set this for both directions
223069154d5SJulian Elischer 		 * we might as well set it for the whole node
224069154d5SJulian Elischer 		 * bit I haven;t done that (yet).
225069154d5SJulian Elischer 		 */
22630400f03SJulian Elischer 		NG_HOOK_FORCE_WRITER(hook);
2274cf49a43SJulian Elischer 		hookp = &sc->sync;
228069154d5SJulian Elischer 	} else {
2294cf49a43SJulian Elischer 		return (EINVAL);
230069154d5SJulian Elischer 	}
231069154d5SJulian Elischer 	if (*hookp) /* actually can't happen I think [JRE] */
2324cf49a43SJulian Elischer 		return (EISCONN);
2334cf49a43SJulian Elischer 	*hookp = hook;
2344cf49a43SJulian Elischer 	return (0);
2354cf49a43SJulian Elischer }
2364cf49a43SJulian Elischer 
2374cf49a43SJulian Elischer /*
2384cf49a43SJulian Elischer  * Receive incoming data
2394cf49a43SJulian Elischer  */
2404cf49a43SJulian Elischer static int
241069154d5SJulian Elischer nga_rcvdata(hook_p hook, item_p item)
2424cf49a43SJulian Elischer {
24330400f03SJulian Elischer 	const sc_p sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
2444cf49a43SJulian Elischer 
2454cf49a43SJulian Elischer 	if (hook == sc->sync)
246069154d5SJulian Elischer 		return (nga_rcv_sync(sc, item));
247a8e9726dSArchie Cobbs 	if (hook == sc->async)
248069154d5SJulian Elischer 		return (nga_rcv_async(sc, item));
249d28843a4SRui Paulo 	panic("%s", __func__);
2504cf49a43SJulian Elischer }
2514cf49a43SJulian Elischer 
2524cf49a43SJulian Elischer /*
2534cf49a43SJulian Elischer  * Receive incoming control message
2544cf49a43SJulian Elischer  */
2554cf49a43SJulian Elischer static int
256069154d5SJulian Elischer nga_rcvmsg(node_p node, item_p item, hook_p lasthook)
2574cf49a43SJulian Elischer {
25830400f03SJulian Elischer 	const sc_p sc = NG_NODE_PRIVATE(node);
2594cf49a43SJulian Elischer 	struct ng_mesg *resp = NULL;
2604cf49a43SJulian Elischer 	int error = 0;
261069154d5SJulian Elischer 	struct ng_mesg *msg;
2624cf49a43SJulian Elischer 
263069154d5SJulian Elischer 	NGI_GET_MSG(item, msg);
2644cf49a43SJulian Elischer 	switch (msg->header.typecookie) {
2654cf49a43SJulian Elischer 	case NGM_ASYNC_COOKIE:
2664cf49a43SJulian Elischer 		switch (msg->header.cmd) {
2674cf49a43SJulian Elischer 		case NGM_ASYNC_CMD_GET_STATS:
2684cf49a43SJulian Elischer 			NG_MKRESPONSE(resp, msg, sizeof(sc->stats), M_NOWAIT);
2694cf49a43SJulian Elischer 			if (resp == NULL)
2704cf49a43SJulian Elischer 				ERROUT(ENOMEM);
2714cf49a43SJulian Elischer 			*((struct ng_async_stat *) resp->data) = sc->stats;
2724cf49a43SJulian Elischer 			break;
2734cf49a43SJulian Elischer 		case NGM_ASYNC_CMD_CLR_STATS:
2744cf49a43SJulian Elischer 			bzero(&sc->stats, sizeof(sc->stats));
2754cf49a43SJulian Elischer 			break;
2764cf49a43SJulian Elischer 		case NGM_ASYNC_CMD_SET_CONFIG:
2774cf49a43SJulian Elischer 		    {
2784cf49a43SJulian Elischer 			struct ng_async_cfg *const cfg =
2794cf49a43SJulian Elischer 				(struct ng_async_cfg *) msg->data;
2804cf49a43SJulian Elischer 			u_char *buf;
2814cf49a43SJulian Elischer 
2824cf49a43SJulian Elischer 			if (msg->header.arglen != sizeof(*cfg))
2834cf49a43SJulian Elischer 				ERROUT(EINVAL);
2844cf49a43SJulian Elischer 			if (cfg->amru < NG_ASYNC_MIN_MRU
2854cf49a43SJulian Elischer 			    || cfg->amru > NG_ASYNC_MAX_MRU
2864cf49a43SJulian Elischer 			    || cfg->smru < NG_ASYNC_MIN_MRU
2874cf49a43SJulian Elischer 			    || cfg->smru > NG_ASYNC_MAX_MRU)
2884cf49a43SJulian Elischer 				ERROUT(EINVAL);
2894cf49a43SJulian Elischer 			cfg->enabled = !!cfg->enabled;	/* normalize */
2904cf49a43SJulian Elischer 			if (cfg->smru > sc->cfg.smru) {	/* reallocate buffer */
2911ede983cSDag-Erling Smørgrav 				buf = malloc(ASYNC_BUF_SIZE(cfg->smru),
2929c8c302fSJulian Elischer 				    M_NETGRAPH_ASYNC, M_NOWAIT);
2934cf49a43SJulian Elischer 				if (!buf)
2944cf49a43SJulian Elischer 					ERROUT(ENOMEM);
2951ede983cSDag-Erling Smørgrav 				free(sc->abuf, M_NETGRAPH_ASYNC);
2964cf49a43SJulian Elischer 				sc->abuf = buf;
2974cf49a43SJulian Elischer 			}
2984cf49a43SJulian Elischer 			if (cfg->amru > sc->cfg.amru) {	/* reallocate buffer */
2991ede983cSDag-Erling Smørgrav 				buf = malloc(SYNC_BUF_SIZE(cfg->amru),
3009c8c302fSJulian Elischer 				    M_NETGRAPH_ASYNC, M_NOWAIT);
3014cf49a43SJulian Elischer 				if (!buf)
3024cf49a43SJulian Elischer 					ERROUT(ENOMEM);
3031ede983cSDag-Erling Smørgrav 				free(sc->sbuf, M_NETGRAPH_ASYNC);
3044cf49a43SJulian Elischer 				sc->sbuf = buf;
3054cf49a43SJulian Elischer 				sc->amode = MODE_HUNT;
3064cf49a43SJulian Elischer 				sc->slen = 0;
3074cf49a43SJulian Elischer 			}
3084cf49a43SJulian Elischer 			if (!cfg->enabled) {
3094cf49a43SJulian Elischer 				sc->amode = MODE_HUNT;
3104cf49a43SJulian Elischer 				sc->slen = 0;
3114cf49a43SJulian Elischer 			}
3124cf49a43SJulian Elischer 			sc->cfg = *cfg;
3134cf49a43SJulian Elischer 			break;
3144cf49a43SJulian Elischer 		    }
3154cf49a43SJulian Elischer 		case NGM_ASYNC_CMD_GET_CONFIG:
3164cf49a43SJulian Elischer 			NG_MKRESPONSE(resp, msg, sizeof(sc->cfg), M_NOWAIT);
3174cf49a43SJulian Elischer 			if (!resp)
3184cf49a43SJulian Elischer 				ERROUT(ENOMEM);
3194cf49a43SJulian Elischer 			*((struct ng_async_cfg *) resp->data) = sc->cfg;
3204cf49a43SJulian Elischer 			break;
3214cf49a43SJulian Elischer 		default:
3224cf49a43SJulian Elischer 			ERROUT(EINVAL);
3234cf49a43SJulian Elischer 		}
3244cf49a43SJulian Elischer 		break;
3254cf49a43SJulian Elischer 	default:
3264cf49a43SJulian Elischer 		ERROUT(EINVAL);
3274cf49a43SJulian Elischer 	}
3284cf49a43SJulian Elischer done:
329069154d5SJulian Elischer 	NG_RESPOND_MSG(error, node, item, resp);
330069154d5SJulian Elischer 	NG_FREE_MSG(msg);
3314cf49a43SJulian Elischer 	return (error);
3324cf49a43SJulian Elischer }
3334cf49a43SJulian Elischer 
3344cf49a43SJulian Elischer /*
3354cf49a43SJulian Elischer  * Shutdown this node
3364cf49a43SJulian Elischer  */
3374cf49a43SJulian Elischer static int
3384cf49a43SJulian Elischer nga_shutdown(node_p node)
3394cf49a43SJulian Elischer {
34030400f03SJulian Elischer 	const sc_p sc = NG_NODE_PRIVATE(node);
3414cf49a43SJulian Elischer 
3421ede983cSDag-Erling Smørgrav 	free(sc->abuf, M_NETGRAPH_ASYNC);
3431ede983cSDag-Erling Smørgrav 	free(sc->sbuf, M_NETGRAPH_ASYNC);
3444cf49a43SJulian Elischer 	bzero(sc, sizeof(*sc));
3451ede983cSDag-Erling Smørgrav 	free(sc, M_NETGRAPH_ASYNC);
34630400f03SJulian Elischer 	NG_NODE_SET_PRIVATE(node, NULL);
34730400f03SJulian Elischer 	NG_NODE_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 {
35730400f03SJulian Elischer 	const sc_p sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
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
365d28843a4SRui Paulo 		panic("%s", __func__);
3664cf49a43SJulian Elischer 	if (!*hookp)
3676e551fb6SDavid E. O'Brien 		panic("%s 2", __func__);
3684cf49a43SJulian Elischer 	*hookp = NULL;
3694cf49a43SJulian Elischer 	bzero(&sc->stats, sizeof(sc->stats));
3704cf49a43SJulian Elischer 	sc->lasttime = 0;
37130400f03SJulian Elischer 	if ((NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0)
37230400f03SJulian Elischer 	&& (NG_NODE_IS_VALID(NG_HOOK_NODE(hook))))
37330400f03SJulian Elischer 		ng_rmnode_self(NG_HOOK_NODE(hook));
3744cf49a43SJulian Elischer 	return (0);
3754cf49a43SJulian Elischer }
3764cf49a43SJulian Elischer 
3774cf49a43SJulian Elischer /******************************************************************
3784cf49a43SJulian Elischer 		    INTERNAL HELPER STUFF
3794cf49a43SJulian Elischer ******************************************************************/
3804cf49a43SJulian Elischer 
3814cf49a43SJulian Elischer /*
3824cf49a43SJulian Elischer  * Encode a byte into the async buffer
3834cf49a43SJulian Elischer  */
3845908d366SStefan Farfeleder static __inline void
3854cf49a43SJulian Elischer nga_async_add(const sc_p sc, u_int16_t *fcs, u_int32_t accm, int *len, u_char x)
3864cf49a43SJulian Elischer {
3874cf49a43SJulian Elischer 	*fcs = PPP_FCS(*fcs, x);
3884cf49a43SJulian Elischer 	if ((x < 32 && ((1 << x) & accm))
3894cf49a43SJulian Elischer 	    || (x == PPP_ESCAPE)
3904cf49a43SJulian Elischer 	    || (x == PPP_FLAG)) {
3914cf49a43SJulian Elischer 		sc->abuf[(*len)++] = PPP_ESCAPE;
3924cf49a43SJulian Elischer 		x ^= PPP_TRANS;
3934cf49a43SJulian Elischer 	}
3944cf49a43SJulian Elischer 	sc->abuf[(*len)++] = x;
3954cf49a43SJulian Elischer }
3964cf49a43SJulian Elischer 
3974cf49a43SJulian Elischer /*
398a8e9726dSArchie Cobbs  * Receive incoming synchronous data.
3994cf49a43SJulian Elischer  */
4004cf49a43SJulian Elischer static int
401069154d5SJulian Elischer nga_rcv_sync(const sc_p sc, item_p item)
4024cf49a43SJulian Elischer {
403069154d5SJulian Elischer 	struct ifnet *rcvif;
40419a52c59SArchie Cobbs 	int alen, error = 0;
405a8e9726dSArchie Cobbs 	struct timeval time;
4064cf49a43SJulian Elischer 	u_int16_t fcs, fcs0;
407a8e9726dSArchie Cobbs 	u_int32_t accm;
408069154d5SJulian Elischer 	struct mbuf *m;
409069154d5SJulian Elischer 
4104cf49a43SJulian Elischer 
411a8e9726dSArchie Cobbs #define ADD_BYTE(x)	nga_async_add(sc, &fcs, accm, &alen, (x))
4124cf49a43SJulian Elischer 
413a8e9726dSArchie Cobbs 	/* Check for bypass mode */
4144cf49a43SJulian Elischer 	if (!sc->cfg.enabled) {
41530400f03SJulian Elischer 		NG_FWD_ITEM_HOOK(error, item, sc->async );
4164cf49a43SJulian Elischer 		return (error);
4174cf49a43SJulian Elischer 	}
418069154d5SJulian Elischer 	NGI_GET_M(item, m);
419069154d5SJulian Elischer 
420069154d5SJulian Elischer 	rcvif = m->m_pkthdr.rcvif;
421a8e9726dSArchie Cobbs 
42219a52c59SArchie Cobbs 	/* Get ACCM; special case LCP frames, which use full ACCM */
423a8e9726dSArchie Cobbs 	accm = sc->cfg.accm;
42419a52c59SArchie Cobbs 	if (m->m_pkthdr.len >= 4) {
42519a52c59SArchie Cobbs 		static const u_char lcphdr[4] = {
42619a52c59SArchie Cobbs 		    PPP_ALLSTATIONS,
42719a52c59SArchie Cobbs 		    PPP_UI,
42819a52c59SArchie Cobbs 		    (u_char)(PPP_LCP >> 8),
42919a52c59SArchie Cobbs 		    (u_char)(PPP_LCP & 0xff)
43019a52c59SArchie Cobbs 		};
43119a52c59SArchie Cobbs 		u_char buf[4];
432a8e9726dSArchie Cobbs 
43319a52c59SArchie Cobbs 		m_copydata(m, 0, 4, (caddr_t)buf);
43419a52c59SArchie Cobbs 		if (bcmp(buf, &lcphdr, 4) == 0)
435a8e9726dSArchie Cobbs 			accm = ~0;
436a8e9726dSArchie Cobbs 	}
437a8e9726dSArchie Cobbs 
438a8e9726dSArchie Cobbs 	/* Check for overflow */
4394cf49a43SJulian Elischer 	if (m->m_pkthdr.len > sc->cfg.smru) {
4404cf49a43SJulian Elischer 		sc->stats.syncOverflows++;
441069154d5SJulian Elischer 		NG_FREE_M(m);
442069154d5SJulian Elischer 		NG_FREE_ITEM(item);
4434cf49a43SJulian Elischer 		return (EMSGSIZE);
4444cf49a43SJulian Elischer 	}
445a8e9726dSArchie Cobbs 
446a8e9726dSArchie Cobbs 	/* Update stats */
4474cf49a43SJulian Elischer 	sc->stats.syncFrames++;
4484cf49a43SJulian Elischer 	sc->stats.syncOctets += m->m_pkthdr.len;
4494cf49a43SJulian Elischer 
4504cf49a43SJulian Elischer 	/* Initialize async encoded version of input mbuf */
4514cf49a43SJulian Elischer 	alen = 0;
4524cf49a43SJulian Elischer 	fcs = PPP_INITFCS;
4534cf49a43SJulian Elischer 
4544cf49a43SJulian Elischer 	/* Add beginning sync flag if it's been long enough to need one */
4554cf49a43SJulian Elischer 	getmicrotime(&time);
456a8e9726dSArchie Cobbs 	if (time.tv_sec >= sc->lasttime + 1) {
4574cf49a43SJulian Elischer 		sc->abuf[alen++] = PPP_FLAG;
4584cf49a43SJulian Elischer 		sc->lasttime = time.tv_sec;
4594cf49a43SJulian Elischer 	}
4604cf49a43SJulian Elischer 
46119a52c59SArchie Cobbs 	/* Add packet payload */
462a8e9726dSArchie Cobbs 	while (m != NULL) {
4634cf49a43SJulian Elischer 		while (m->m_len > 0) {
464a8e9726dSArchie Cobbs 			ADD_BYTE(*mtod(m, u_char *));
4654cf49a43SJulian Elischer 			m->m_data++;
4664cf49a43SJulian Elischer 			m->m_len--;
4674cf49a43SJulian Elischer 		}
468ecde8f7cSMatthew Dillon 		m = m_free(m);
4694cf49a43SJulian Elischer 	}
4704cf49a43SJulian Elischer 
4714cf49a43SJulian Elischer 	/* Add checksum and final sync flag */
4724cf49a43SJulian Elischer 	fcs0 = fcs;
4734cf49a43SJulian Elischer 	ADD_BYTE(~fcs0 & 0xff);
4744cf49a43SJulian Elischer 	ADD_BYTE(~fcs0 >> 8);
4754cf49a43SJulian Elischer 	sc->abuf[alen++] = PPP_FLAG;
4764cf49a43SJulian Elischer 
4774cf49a43SJulian Elischer 	/* Put frame in an mbuf and ship it off */
478a8e9726dSArchie Cobbs 	if (!(m = m_devget(sc->abuf, alen, 0, rcvif, NULL))) {
479069154d5SJulian Elischer 		NG_FREE_ITEM(item);
4804cf49a43SJulian Elischer 		error = ENOBUFS;
481069154d5SJulian Elischer 	} else {
482069154d5SJulian Elischer 		NG_FWD_NEW_DATA(error, item, sc->async, m);
483069154d5SJulian Elischer 	}
4844cf49a43SJulian Elischer 	return (error);
4854cf49a43SJulian Elischer }
4864cf49a43SJulian Elischer 
4874cf49a43SJulian Elischer /*
4884cf49a43SJulian Elischer  * Receive incoming asynchronous data
489a8e9726dSArchie Cobbs  * XXX Technically, we should strip out incoming characters
490a8e9726dSArchie Cobbs  *     that are in our ACCM. Not sure if this is good or not.
4914cf49a43SJulian Elischer  */
4924cf49a43SJulian Elischer static int
493069154d5SJulian Elischer nga_rcv_async(const sc_p sc, item_p item)
4944cf49a43SJulian Elischer {
495069154d5SJulian Elischer 	struct ifnet *rcvif;
4964cf49a43SJulian Elischer 	int error;
497069154d5SJulian Elischer 	struct mbuf *m;
4984cf49a43SJulian Elischer 
4994cf49a43SJulian Elischer 	if (!sc->cfg.enabled) {
50030400f03SJulian Elischer 		NG_FWD_ITEM_HOOK(error, item,  sc->sync);
5014cf49a43SJulian Elischer 		return (error);
5024cf49a43SJulian Elischer 	}
503069154d5SJulian Elischer 	NGI_GET_M(item, m);
504069154d5SJulian Elischer 	rcvif = m->m_pkthdr.rcvif;
5054cf49a43SJulian Elischer 	while (m) {
5064cf49a43SJulian Elischer 		struct mbuf *n;
5074cf49a43SJulian Elischer 
5084cf49a43SJulian Elischer 		for (; m->m_len > 0; m->m_data++, m->m_len--) {
5094cf49a43SJulian Elischer 			u_char  ch = *mtod(m, u_char *);
5104cf49a43SJulian Elischer 
5114cf49a43SJulian Elischer 			sc->stats.asyncOctets++;
5124cf49a43SJulian Elischer 			if (ch == PPP_FLAG) {	/* Flag overrides everything */
5134cf49a43SJulian Elischer 				int     skip = 0;
5144cf49a43SJulian Elischer 
5154cf49a43SJulian Elischer 				/* Check for runts */
5164cf49a43SJulian Elischer 				if (sc->slen < 2) {
5174cf49a43SJulian Elischer 					if (sc->slen > 0)
5184cf49a43SJulian Elischer 						sc->stats.asyncRunts++;
5194cf49a43SJulian Elischer 					goto reset;
5204cf49a43SJulian Elischer 				}
5214cf49a43SJulian Elischer 
5224cf49a43SJulian Elischer 				/* Verify CRC */
5234cf49a43SJulian Elischer 				if (sc->fcs != PPP_GOODFCS) {
5244cf49a43SJulian Elischer 					sc->stats.asyncBadCheckSums++;
5254cf49a43SJulian Elischer 					goto reset;
5264cf49a43SJulian Elischer 				}
5274cf49a43SJulian Elischer 				sc->slen -= 2;
5284cf49a43SJulian Elischer 
5294cf49a43SJulian Elischer 				/* Strip address and control fields */
5304cf49a43SJulian Elischer 				if (sc->slen >= 2
5314cf49a43SJulian Elischer 				    && sc->sbuf[0] == PPP_ALLSTATIONS
5324cf49a43SJulian Elischer 				    && sc->sbuf[1] == PPP_UI)
5334cf49a43SJulian Elischer 					skip = 2;
5344cf49a43SJulian Elischer 
5354cf49a43SJulian Elischer 				/* Check for frame too big */
5364cf49a43SJulian Elischer 				if (sc->slen - skip > sc->cfg.amru) {
5374cf49a43SJulian Elischer 					sc->stats.asyncOverflows++;
5384cf49a43SJulian Elischer 					goto reset;
5394cf49a43SJulian Elischer 				}
5404cf49a43SJulian Elischer 
5414cf49a43SJulian Elischer 				/* OK, ship it out */
5424cf49a43SJulian Elischer 				if ((n = m_devget(sc->sbuf + skip,
543069154d5SJulian Elischer 					   sc->slen - skip, 0, rcvif, NULL))) {
544069154d5SJulian Elischer 					if (item) { /* sets NULL -> item */
545069154d5SJulian Elischer 						NG_FWD_NEW_DATA(error, item,
546069154d5SJulian Elischer 							sc->sync, n);
547069154d5SJulian Elischer 					} else {
548069154d5SJulian Elischer 						NG_SEND_DATA_ONLY(error,
549069154d5SJulian Elischer 							sc->sync ,n);
550069154d5SJulian Elischer 					}
551069154d5SJulian Elischer 				}
5524cf49a43SJulian Elischer 				sc->stats.asyncFrames++;
5534cf49a43SJulian Elischer reset:
5544cf49a43SJulian Elischer 				sc->amode = MODE_NORMAL;
5554cf49a43SJulian Elischer 				sc->fcs = PPP_INITFCS;
5564cf49a43SJulian Elischer 				sc->slen = 0;
5574cf49a43SJulian Elischer 				continue;
5584cf49a43SJulian Elischer 			}
5594cf49a43SJulian Elischer 			switch (sc->amode) {
5604cf49a43SJulian Elischer 			case MODE_NORMAL:
5614cf49a43SJulian Elischer 				if (ch == PPP_ESCAPE) {
5624cf49a43SJulian Elischer 					sc->amode = MODE_ESC;
5634cf49a43SJulian Elischer 					continue;
5644cf49a43SJulian Elischer 				}
5654cf49a43SJulian Elischer 				break;
5664cf49a43SJulian Elischer 			case MODE_ESC:
5674cf49a43SJulian Elischer 				ch ^= PPP_TRANS;
5684cf49a43SJulian Elischer 				sc->amode = MODE_NORMAL;
5694cf49a43SJulian Elischer 				break;
5704cf49a43SJulian Elischer 			case MODE_HUNT:
5714cf49a43SJulian Elischer 			default:
5724cf49a43SJulian Elischer 				continue;
5734cf49a43SJulian Elischer 			}
5744cf49a43SJulian Elischer 
5754cf49a43SJulian Elischer 			/* Add byte to frame */
5764cf49a43SJulian Elischer 			if (sc->slen >= SYNC_BUF_SIZE(sc->cfg.amru)) {
5774cf49a43SJulian Elischer 				sc->stats.asyncOverflows++;
5784cf49a43SJulian Elischer 				sc->amode = MODE_HUNT;
5794cf49a43SJulian Elischer 				sc->slen = 0;
5804cf49a43SJulian Elischer 			} else {
5814cf49a43SJulian Elischer 				sc->sbuf[sc->slen++] = ch;
5824cf49a43SJulian Elischer 				sc->fcs = PPP_FCS(sc->fcs, ch);
5834cf49a43SJulian Elischer 			}
5844cf49a43SJulian Elischer 		}
585ecde8f7cSMatthew Dillon 		m = m_free(m);
5864cf49a43SJulian Elischer 	}
587069154d5SJulian Elischer 	if (item)
588069154d5SJulian Elischer 		NG_FREE_ITEM(item);
5894cf49a43SJulian Elischer 	return (0);
5904cf49a43SJulian Elischer }
5914cf49a43SJulian Elischer 
5924cf49a43SJulian Elischer /*
5934cf49a43SJulian Elischer  * CRC table
5944cf49a43SJulian Elischer  *
5954cf49a43SJulian Elischer  * Taken from RFC 1171 Appendix B
5964cf49a43SJulian Elischer  */
5974cf49a43SJulian Elischer static const u_int16_t fcstab[256] = {
5984cf49a43SJulian Elischer 	 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
5994cf49a43SJulian Elischer 	 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
6004cf49a43SJulian Elischer 	 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
6014cf49a43SJulian Elischer 	 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
6024cf49a43SJulian Elischer 	 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
6034cf49a43SJulian Elischer 	 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
6044cf49a43SJulian Elischer 	 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
6054cf49a43SJulian Elischer 	 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
6064cf49a43SJulian Elischer 	 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
6074cf49a43SJulian Elischer 	 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
6084cf49a43SJulian Elischer 	 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
6094cf49a43SJulian Elischer 	 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
6104cf49a43SJulian Elischer 	 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
6114cf49a43SJulian Elischer 	 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
6124cf49a43SJulian Elischer 	 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
6134cf49a43SJulian Elischer 	 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
6144cf49a43SJulian Elischer 	 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
6154cf49a43SJulian Elischer 	 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
6164cf49a43SJulian Elischer 	 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
6174cf49a43SJulian Elischer 	 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
6184cf49a43SJulian Elischer 	 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
6194cf49a43SJulian Elischer 	 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
6204cf49a43SJulian Elischer 	 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
6214cf49a43SJulian Elischer 	 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
6224cf49a43SJulian Elischer 	 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
6234cf49a43SJulian Elischer 	 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
6244cf49a43SJulian Elischer 	 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
6254cf49a43SJulian Elischer 	 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
6264cf49a43SJulian Elischer 	 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
6274cf49a43SJulian Elischer 	 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
6284cf49a43SJulian Elischer 	 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
6294cf49a43SJulian Elischer 	 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
6304cf49a43SJulian Elischer };
631