ng_async.c revision 131575
165123Speter
265123Speter/*
365123Speter * ng_async.c
465123Speter *
565123Speter * Copyright (c) 1996-1999 Whistle Communications, Inc.
665123Speter * All rights reserved.
765123Speter *
865123Speter * Subject to the following obligations and disclaimer of warranty, use and
965123Speter * redistribution of this software, in source or object code forms, with or
1065123Speter * without modifications are expressly permitted by Whistle Communications;
1165123Speter * provided, however, that:
1265123Speter * 1. Any and all reproductions of the source or object code must include the
1365123Speter *    copyright notice above and the following disclaimer of warranties; and
1465123Speter * 2. No rights are granted, in any manner or form, to use Whistle
1565123Speter *    Communications, Inc. trademarks, including the mark "WHISTLE
1665123Speter *    COMMUNICATIONS" on advertising, endorsements, or otherwise except as
1765123Speter *    such appears in the above copyright notice or in the software.
1865123Speter *
1965123Speter * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
2065123Speter * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
2165123Speter * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
2265123Speter * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
2365123Speter * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
2465123Speter * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
2565123Speter * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
2665123Speter * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
2765123Speter * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
2865123Speter * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
2965123Speter * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
3065123Speter * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
3165123Speter * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
3265123Speter * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3365123Speter * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
3465123Speter * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
3565123Speter * OF SUCH DAMAGE.
3665123Speter *
3765123Speter * Author: Archie Cobbs <archie@freebsd.org>
3865123Speter *
3965123Speter * $FreeBSD: head/sys/netgraph/ng_async.c 131575 2004-07-04 16:11:03Z stefanf $
4065123Speter * $Whistle: ng_async.c,v 1.17 1999/11/01 09:24:51 julian Exp $
4165123Speter */
4265123Speter
4365123Speter/*
4465123Speter * This node type implements a PPP style sync <-> async converter.
4565123Speter * See RFC 1661 for details of how asynchronous encoding works.
4665123Speter */
4765123Speter
4865123Speter#include <sys/param.h>
4965123Speter#include <sys/systm.h>
5065123Speter#include <sys/kernel.h>
5165123Speter#include <sys/mbuf.h>
5265123Speter#include <sys/malloc.h>
5365123Speter#include <sys/errno.h>
5465123Speter
5565123Speter#include <netgraph/ng_message.h>
5665123Speter#include <netgraph/netgraph.h>
5765123Speter#include <netgraph/ng_async.h>
5865123Speter#include <netgraph/ng_parse.h>
5965123Speter
6065123Speter#include <net/ppp_defs.h>
6165123Speter
6265123Speter#ifdef NG_SEPARATE_MALLOC
6365123SpeterMALLOC_DEFINE(M_NETGRAPH_ASYNC, "netgraph_async", "netgraph async node ");
6465123Speter#else
6565123Speter#define M_NETGRAPH_ASYNC M_NETGRAPH
6665126Speter#endif
6765123Speter
6865123Speter
6965123Speter/* Async decode state */
7065123Speter#define MODE_HUNT	0
7165123Speter#define MODE_NORMAL	1
7265123Speter#define MODE_ESC	2
7365123Speter
7465123Speter/* Private data structure */
7565123Speterstruct ng_async_private {
7665123Speter	node_p  	node;		/* Our node */
7765123Speter	hook_p  	async;		/* Asynchronous side */
7865123Speter	hook_p  	sync;		/* Synchronous side */
7965123Speter	u_char  	amode;		/* Async hunt/esape mode */
8065123Speter	u_int16_t	fcs;		/* Decoded async FCS (so far) */
8165123Speter	u_char	       *abuf;		/* Buffer to encode sync into */
8265123Speter	u_char	       *sbuf;		/* Buffer to decode async into */
8365123Speter	u_int		slen;		/* Length of data in sbuf */
8465123Speter	long		lasttime;	/* Time of last async packet sent */
8565123Speter	struct		ng_async_cfg	cfg;	/* Configuration */
8665123Speter	struct		ng_async_stat	stats;	/* Statistics */
8765123Speter};
8865123Spetertypedef struct ng_async_private *sc_p;
8965123Speter
9065123Speter/* Useful macros */
9165123Speter#define ASYNC_BUF_SIZE(smru)	(2 * (smru) + 10)
9265123Speter#define SYNC_BUF_SIZE(amru)	((amru) + 10)
9365123Speter#define ERROUT(x)		do { error = (x); goto done; } while (0)
9465123Speter
9565123Speter/* Netgraph methods */
9665123Speterstatic ng_constructor_t		nga_constructor;
9765123Speterstatic ng_rcvdata_t		nga_rcvdata;
9865123Speterstatic ng_rcvmsg_t		nga_rcvmsg;
9965123Speterstatic ng_shutdown_t		nga_shutdown;
10065123Speterstatic ng_newhook_t		nga_newhook;
10165123Speterstatic ng_disconnect_t		nga_disconnect;
10265123Speter
10365127Speter/* Helper stuff */
10465123Speterstatic int	nga_rcv_sync(const sc_p sc, item_p item);
10565123Speterstatic int	nga_rcv_async(const sc_p sc, item_p item);
10665123Speter
10765123Speter/* Parse type for struct ng_async_cfg */
10865123Speterstatic const struct ng_parse_struct_field nga_config_type_fields[]
10965123Speter	= NG_ASYNC_CONFIG_TYPE_INFO;
11065123Speterstatic const struct ng_parse_type nga_config_type = {
11165123Speter	&ng_parse_struct_type,
11265123Speter	&nga_config_type_fields
11365123Speter};
11465123Speter
11565123Speter/* Parse type for struct ng_async_stat */
11665123Speterstatic const struct ng_parse_struct_field nga_stats_type_fields[]
11765123Speter	= NG_ASYNC_STATS_TYPE_INFO;
11865123Speterstatic const struct ng_parse_type nga_stats_type = {
11965123Speter	&ng_parse_struct_type,
12065123Speter	&nga_stats_type_fields
12165123Speter};
12265127Speter
12365123Speter/* List of commands and how to convert arguments to/from ASCII */
12465123Speterstatic const struct ng_cmdlist nga_cmdlist[] = {
12565123Speter	{
12665123Speter	  NGM_ASYNC_COOKIE,
12765123Speter	  NGM_ASYNC_CMD_SET_CONFIG,
12865123Speter	  "setconfig",
12965123Speter	  &nga_config_type,
13065123Speter	  NULL
13165123Speter	},
13265123Speter	{
13365123Speter	  NGM_ASYNC_COOKIE,
13465123Speter	  NGM_ASYNC_CMD_GET_CONFIG,
13565123Speter	  "getconfig",
13665123Speter	  NULL,
13765123Speter	  &nga_config_type
13865123Speter	},
13965123Speter	{
14065123Speter	  NGM_ASYNC_COOKIE,
14165123Speter	  NGM_ASYNC_CMD_GET_STATS,
14265123Speter	  "getstats",
14365123Speter	  NULL,
14465123Speter	  &nga_stats_type
14565123Speter	},
14665123Speter	{
14765123Speter	  NGM_ASYNC_COOKIE,
14865123Speter	  NGM_ASYNC_CMD_CLR_STATS,
14965123Speter	  "clrstats",
15065123Speter	  &nga_stats_type,
15165123Speter	  NULL
15265123Speter	},
15365123Speter	{ 0 }
15465123Speter};
15565123Speter
15665123Speter/* Define the netgraph node type */
15765123Speterstatic struct ng_type typestruct = {
15865123Speter	.version =	NG_ABI_VERSION,
15965123Speter	.name =		NG_ASYNC_NODE_TYPE,
16065123Speter	.constructor =	nga_constructor,
16165123Speter	.rcvmsg =	nga_rcvmsg,
16265123Speter	.shutdown = 	nga_shutdown,
16365123Speter	.newhook =	nga_newhook,
16465123Speter	.rcvdata =	nga_rcvdata,
16565123Speter	.disconnect =	nga_disconnect,
16665123Speter	.cmdlist =	nga_cmdlist
16765123Speter};
16865123SpeterNETGRAPH_INIT(async, &typestruct);
16965123Speter
17065123Speter/* CRC table */
17165123Speterstatic const u_int16_t fcstab[];
17265123Speter
17365123Speter/******************************************************************
17465123Speter		    NETGRAPH NODE METHODS
17565123Speter******************************************************************/
17665123Speter
17765123Speter/*
17865123Speter * Initialize a new node
17965123Speter */
18065123Speterstatic int
18165123Speternga_constructor(node_p node)
18265123Speter{
18365123Speter	sc_p sc;
18465123Speter
18565123Speter	MALLOC(sc, sc_p, sizeof(*sc), M_NETGRAPH_ASYNC, M_NOWAIT | M_ZERO);
18665123Speter	if (sc == NULL)
18765123Speter		return (ENOMEM);
18865123Speter	sc->amode = MODE_HUNT;
18965123Speter	sc->cfg.accm = ~0;
19065123Speter	sc->cfg.amru = NG_ASYNC_DEFAULT_MRU;
19165123Speter	sc->cfg.smru = NG_ASYNC_DEFAULT_MRU;
19265123Speter	MALLOC(sc->abuf, u_char *,
19365123Speter	    ASYNC_BUF_SIZE(sc->cfg.smru), M_NETGRAPH_ASYNC, M_NOWAIT);
19465123Speter	if (sc->abuf == NULL)
19565123Speter		goto fail;
19665123Speter	MALLOC(sc->sbuf, u_char *,
19765123Speter	    SYNC_BUF_SIZE(sc->cfg.amru), M_NETGRAPH_ASYNC, M_NOWAIT);
19865123Speter	if (sc->sbuf == NULL) {
19965123Speter		FREE(sc->abuf, M_NETGRAPH_ASYNC);
20065123Speterfail:
20165123Speter		FREE(sc, M_NETGRAPH_ASYNC);
20265123Speter		return (ENOMEM);
20365123Speter	}
20465123Speter	NG_NODE_SET_PRIVATE(node, sc);
20565123Speter	sc->node = node;
20665123Speter	return (0);
20765123Speter}
20865123Speter
20965123Speter/*
21065123Speter * Reserve a hook for a pending connection
21165123Speter */
21265123Speterstatic int
21365123Speternga_newhook(node_p node, hook_p hook, const char *name)
21465123Speter{
21565123Speter	const sc_p sc = NG_NODE_PRIVATE(node);
21665123Speter	hook_p *hookp;
21765123Speter
21865123Speter	if (!strcmp(name, NG_ASYNC_HOOK_ASYNC)) {
21965123Speter		/*
22065123Speter		 * We use a static buffer here so only one packet
22165123Speter		 * at a time can be allowed to travel in this direction.
22265123Speter		 * Force Writer semantics.
22365123Speter		 */
22465123Speter		NG_HOOK_FORCE_WRITER(hook);
22565123Speter		hookp = &sc->async;
22665123Speter	} else if (!strcmp(name, NG_ASYNC_HOOK_SYNC)) {
22765123Speter		/*
22865123Speter		 * We use a static state here so only one packet
22965123Speter		 * at a time can be allowed to travel in this direction.
23065123Speter		 * Force Writer semantics.
23165123Speter		 * Since we set this for both directions
23265123Speter		 * we might as well set it for the whole node
23365123Speter		 * bit I haven;t done that (yet).
23465123Speter		 */
23565123Speter		NG_HOOK_FORCE_WRITER(hook);
23665123Speter		hookp = &sc->sync;
23765123Speter	} else {
23865123Speter		return (EINVAL);
23965123Speter	}
24065123Speter	if (*hookp) /* actually can't happen I think [JRE] */
24165123Speter		return (EISCONN);
24265123Speter	*hookp = hook;
24365123Speter	return (0);
24465123Speter}
24565123Speter
24665123Speter/*
24765123Speter * Receive incoming data
24865123Speter */
24965123Speterstatic int
25065123Speternga_rcvdata(hook_p hook, item_p item)
25165123Speter{
25265123Speter	const sc_p sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
25365123Speter
25465123Speter	if (hook == sc->sync)
25565123Speter		return (nga_rcv_sync(sc, item));
25665123Speter	if (hook == sc->async)
25765123Speter		return (nga_rcv_async(sc, item));
25865123Speter	panic(__func__);
25965123Speter}
26065123Speter
26165123Speter/*
26265123Speter * Receive incoming control message
26365123Speter */
26465123Speterstatic int
26565123Speternga_rcvmsg(node_p node, item_p item, hook_p lasthook)
26665123Speter{
26765123Speter	const sc_p sc = NG_NODE_PRIVATE(node);
26865123Speter	struct ng_mesg *resp = NULL;
26965123Speter	int error = 0;
27065123Speter	struct ng_mesg *msg;
27165123Speter
27265123Speter	NGI_GET_MSG(item, msg);
27365123Speter	switch (msg->header.typecookie) {
27465123Speter	case NGM_ASYNC_COOKIE:
27565123Speter		switch (msg->header.cmd) {
27665123Speter		case NGM_ASYNC_CMD_GET_STATS:
27765123Speter			NG_MKRESPONSE(resp, msg, sizeof(sc->stats), M_NOWAIT);
27865123Speter			if (resp == NULL)
27965123Speter				ERROUT(ENOMEM);
28065123Speter			*((struct ng_async_stat *) resp->data) = sc->stats;
28165123Speter			break;
28265123Speter		case NGM_ASYNC_CMD_CLR_STATS:
28365123Speter			bzero(&sc->stats, sizeof(sc->stats));
28465123Speter			break;
28565123Speter		case NGM_ASYNC_CMD_SET_CONFIG:
28665123Speter		    {
28765123Speter			struct ng_async_cfg *const cfg =
28865123Speter				(struct ng_async_cfg *) msg->data;
28965123Speter			u_char *buf;
29065123Speter
29165123Speter			if (msg->header.arglen != sizeof(*cfg))
29265123Speter				ERROUT(EINVAL);
29365123Speter			if (cfg->amru < NG_ASYNC_MIN_MRU
29465123Speter			    || cfg->amru > NG_ASYNC_MAX_MRU
29565123Speter			    || cfg->smru < NG_ASYNC_MIN_MRU
29665123Speter			    || cfg->smru > NG_ASYNC_MAX_MRU)
29765123Speter				ERROUT(EINVAL);
29865123Speter			cfg->enabled = !!cfg->enabled;	/* normalize */
29965123Speter			if (cfg->smru > sc->cfg.smru) {	/* reallocate buffer */
30065123Speter				MALLOC(buf, u_char *, ASYNC_BUF_SIZE(cfg->smru),
30165123Speter				    M_NETGRAPH_ASYNC, M_NOWAIT);
30265123Speter				if (!buf)
30365123Speter					ERROUT(ENOMEM);
30465123Speter				FREE(sc->abuf, M_NETGRAPH_ASYNC);
30565123Speter				sc->abuf = buf;
30665123Speter			}
30765123Speter			if (cfg->amru > sc->cfg.amru) {	/* reallocate buffer */
30865123Speter				MALLOC(buf, u_char *, SYNC_BUF_SIZE(cfg->amru),
30965123Speter				    M_NETGRAPH_ASYNC, M_NOWAIT);
31065123Speter				if (!buf)
31165123Speter					ERROUT(ENOMEM);
31265123Speter				FREE(sc->sbuf, M_NETGRAPH_ASYNC);
31365123Speter				sc->sbuf = buf;
31465123Speter				sc->amode = MODE_HUNT;
31565123Speter				sc->slen = 0;
31665123Speter			}
31765123Speter			if (!cfg->enabled) {
31865123Speter				sc->amode = MODE_HUNT;
31965123Speter				sc->slen = 0;
32065123Speter			}
32165123Speter			sc->cfg = *cfg;
32265123Speter			break;
32365123Speter		    }
32465123Speter		case NGM_ASYNC_CMD_GET_CONFIG:
32565123Speter			NG_MKRESPONSE(resp, msg, sizeof(sc->cfg), M_NOWAIT);
32665123Speter			if (!resp)
32765123Speter				ERROUT(ENOMEM);
32865123Speter			*((struct ng_async_cfg *) resp->data) = sc->cfg;
32965123Speter			break;
33065123Speter		default:
33165123Speter			ERROUT(EINVAL);
33265123Speter		}
33365123Speter		break;
33465123Speter	default:
33565123Speter		ERROUT(EINVAL);
33665123Speter	}
33765123Speterdone:
33865123Speter	NG_RESPOND_MSG(error, node, item, resp);
33965123Speter	NG_FREE_MSG(msg);
34065123Speter	return (error);
34165123Speter}
34265123Speter
34365123Speter/*
34465123Speter * Shutdown this node
34565123Speter */
34665123Speterstatic int
34765123Speternga_shutdown(node_p node)
34865123Speter{
34965123Speter	const sc_p sc = NG_NODE_PRIVATE(node);
35065123Speter
35165123Speter	FREE(sc->abuf, M_NETGRAPH_ASYNC);
35265123Speter	FREE(sc->sbuf, M_NETGRAPH_ASYNC);
35365123Speter	bzero(sc, sizeof(*sc));
35465123Speter	FREE(sc, M_NETGRAPH_ASYNC);
35565123Speter	NG_NODE_SET_PRIVATE(node, NULL);
35665123Speter	NG_NODE_UNREF(node);
35765125Speter	return (0);
35865123Speter}
35965123Speter
36065123Speter/*
36165123Speter * Lose a hook. When both hooks go away, we disappear.
36265123Speter */
36365123Speterstatic int
36465123Speternga_disconnect(hook_p hook)
36565123Speter{
36665123Speter	const sc_p sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
36765123Speter	hook_p *hookp;
36865123Speter
36965123Speter	if (hook == sc->async)
370		hookp = &sc->async;
371	else if (hook == sc->sync)
372		hookp = &sc->sync;
373	else
374		panic(__func__);
375	if (!*hookp)
376		panic("%s 2", __func__);
377	*hookp = NULL;
378	bzero(&sc->stats, sizeof(sc->stats));
379	sc->lasttime = 0;
380	if ((NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0)
381	&& (NG_NODE_IS_VALID(NG_HOOK_NODE(hook))))
382		ng_rmnode_self(NG_HOOK_NODE(hook));
383	return (0);
384}
385
386/******************************************************************
387		    INTERNAL HELPER STUFF
388******************************************************************/
389
390/*
391 * Encode a byte into the async buffer
392 */
393static __inline void
394nga_async_add(const sc_p sc, u_int16_t *fcs, u_int32_t accm, int *len, u_char x)
395{
396	*fcs = PPP_FCS(*fcs, x);
397	if ((x < 32 && ((1 << x) & accm))
398	    || (x == PPP_ESCAPE)
399	    || (x == PPP_FLAG)) {
400		sc->abuf[(*len)++] = PPP_ESCAPE;
401		x ^= PPP_TRANS;
402	}
403	sc->abuf[(*len)++] = x;
404}
405
406/*
407 * Receive incoming synchronous data.
408 */
409static int
410nga_rcv_sync(const sc_p sc, item_p item)
411{
412	struct ifnet *rcvif;
413	int alen, error = 0;
414	struct timeval time;
415	u_int16_t fcs, fcs0;
416	u_int32_t accm;
417	struct mbuf *m;
418
419
420#define ADD_BYTE(x)	nga_async_add(sc, &fcs, accm, &alen, (x))
421
422	/* Check for bypass mode */
423	if (!sc->cfg.enabled) {
424		NG_FWD_ITEM_HOOK(error, item, sc->async );
425		return (error);
426	}
427	NGI_GET_M(item, m);
428
429	rcvif = m->m_pkthdr.rcvif;
430
431	/* Get ACCM; special case LCP frames, which use full ACCM */
432	accm = sc->cfg.accm;
433	if (m->m_pkthdr.len >= 4) {
434		static const u_char lcphdr[4] = {
435		    PPP_ALLSTATIONS,
436		    PPP_UI,
437		    (u_char)(PPP_LCP >> 8),
438		    (u_char)(PPP_LCP & 0xff)
439		};
440		u_char buf[4];
441
442		m_copydata(m, 0, 4, (caddr_t)buf);
443		if (bcmp(buf, &lcphdr, 4) == 0)
444			accm = ~0;
445	}
446
447	/* Check for overflow */
448	if (m->m_pkthdr.len > sc->cfg.smru) {
449		sc->stats.syncOverflows++;
450		NG_FREE_M(m);
451		NG_FREE_ITEM(item);
452		return (EMSGSIZE);
453	}
454
455	/* Update stats */
456	sc->stats.syncFrames++;
457	sc->stats.syncOctets += m->m_pkthdr.len;
458
459	/* Initialize async encoded version of input mbuf */
460	alen = 0;
461	fcs = PPP_INITFCS;
462
463	/* Add beginning sync flag if it's been long enough to need one */
464	getmicrotime(&time);
465	if (time.tv_sec >= sc->lasttime + 1) {
466		sc->abuf[alen++] = PPP_FLAG;
467		sc->lasttime = time.tv_sec;
468	}
469
470	/* Add packet payload */
471	while (m != NULL) {
472		while (m->m_len > 0) {
473			ADD_BYTE(*mtod(m, u_char *));
474			m->m_data++;
475			m->m_len--;
476		}
477		m = m_free(m);
478	}
479
480	/* Add checksum and final sync flag */
481	fcs0 = fcs;
482	ADD_BYTE(~fcs0 & 0xff);
483	ADD_BYTE(~fcs0 >> 8);
484	sc->abuf[alen++] = PPP_FLAG;
485
486	/* Put frame in an mbuf and ship it off */
487	if (!(m = m_devget(sc->abuf, alen, 0, rcvif, NULL))) {
488		NG_FREE_ITEM(item);
489		error = ENOBUFS;
490	} else {
491		NG_FWD_NEW_DATA(error, item, sc->async, m);
492	}
493	return (error);
494}
495
496/*
497 * Receive incoming asynchronous data
498 * XXX Technically, we should strip out incoming characters
499 *     that are in our ACCM. Not sure if this is good or not.
500 */
501static int
502nga_rcv_async(const sc_p sc, item_p item)
503{
504	struct ifnet *rcvif;
505	int error;
506	struct mbuf *m;
507
508	if (!sc->cfg.enabled) {
509		NG_FWD_ITEM_HOOK(error, item,  sc->sync);
510		return (error);
511	}
512	NGI_GET_M(item, m);
513	rcvif = m->m_pkthdr.rcvif;
514	while (m) {
515		struct mbuf *n;
516
517		for (; m->m_len > 0; m->m_data++, m->m_len--) {
518			u_char  ch = *mtod(m, u_char *);
519
520			sc->stats.asyncOctets++;
521			if (ch == PPP_FLAG) {	/* Flag overrides everything */
522				int     skip = 0;
523
524				/* Check for runts */
525				if (sc->slen < 2) {
526					if (sc->slen > 0)
527						sc->stats.asyncRunts++;
528					goto reset;
529				}
530
531				/* Verify CRC */
532				if (sc->fcs != PPP_GOODFCS) {
533					sc->stats.asyncBadCheckSums++;
534					goto reset;
535				}
536				sc->slen -= 2;
537
538				/* Strip address and control fields */
539				if (sc->slen >= 2
540				    && sc->sbuf[0] == PPP_ALLSTATIONS
541				    && sc->sbuf[1] == PPP_UI)
542					skip = 2;
543
544				/* Check for frame too big */
545				if (sc->slen - skip > sc->cfg.amru) {
546					sc->stats.asyncOverflows++;
547					goto reset;
548				}
549
550				/* OK, ship it out */
551				if ((n = m_devget(sc->sbuf + skip,
552					   sc->slen - skip, 0, rcvif, NULL))) {
553					if (item) { /* sets NULL -> item */
554						NG_FWD_NEW_DATA(error, item,
555							sc->sync, n);
556					} else {
557						NG_SEND_DATA_ONLY(error,
558							sc->sync ,n);
559					}
560				}
561				sc->stats.asyncFrames++;
562reset:
563				sc->amode = MODE_NORMAL;
564				sc->fcs = PPP_INITFCS;
565				sc->slen = 0;
566				continue;
567			}
568			switch (sc->amode) {
569			case MODE_NORMAL:
570				if (ch == PPP_ESCAPE) {
571					sc->amode = MODE_ESC;
572					continue;
573				}
574				break;
575			case MODE_ESC:
576				ch ^= PPP_TRANS;
577				sc->amode = MODE_NORMAL;
578				break;
579			case MODE_HUNT:
580			default:
581				continue;
582			}
583
584			/* Add byte to frame */
585			if (sc->slen >= SYNC_BUF_SIZE(sc->cfg.amru)) {
586				sc->stats.asyncOverflows++;
587				sc->amode = MODE_HUNT;
588				sc->slen = 0;
589			} else {
590				sc->sbuf[sc->slen++] = ch;
591				sc->fcs = PPP_FCS(sc->fcs, ch);
592			}
593		}
594		m = m_free(m);
595	}
596	if (item)
597		NG_FREE_ITEM(item);
598	return (0);
599}
600
601/*
602 * CRC table
603 *
604 * Taken from RFC 1171 Appendix B
605 */
606static const u_int16_t fcstab[256] = {
607	 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
608	 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
609	 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
610	 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
611	 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
612	 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
613	 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
614	 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
615	 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
616	 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
617	 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
618	 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
619	 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
620	 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
621	 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
622	 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
623	 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
624	 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
625	 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
626	 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
627	 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
628	 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
629	 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
630	 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
631	 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
632	 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
633	 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
634	 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
635	 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
636	 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
637	 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
638	 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
639};
640