ng_async.c revision 213794
152419Sjulian/*
252419Sjulian * ng_async.c
3139823Simp */
4139823Simp
5139823Simp/*-
652419Sjulian * Copyright (c) 1996-1999 Whistle Communications, Inc.
752419Sjulian * All rights reserved.
852419Sjulian *
952419Sjulian * Subject to the following obligations and disclaimer of warranty, use and
1052419Sjulian * redistribution of this software, in source or object code forms, with or
1152419Sjulian * without modifications are expressly permitted by Whistle Communications;
1252419Sjulian * provided, however, that:
1352419Sjulian * 1. Any and all reproductions of the source or object code must include the
1452419Sjulian *    copyright notice above and the following disclaimer of warranties; and
1552419Sjulian * 2. No rights are granted, in any manner or form, to use Whistle
1652419Sjulian *    Communications, Inc. trademarks, including the mark "WHISTLE
1752419Sjulian *    COMMUNICATIONS" on advertising, endorsements, or otherwise except as
1852419Sjulian *    such appears in the above copyright notice or in the software.
1952419Sjulian *
2052419Sjulian * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
2152419Sjulian * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
2252419Sjulian * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
2352419Sjulian * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
2452419Sjulian * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
2552419Sjulian * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
2652419Sjulian * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
2752419Sjulian * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
2852419Sjulian * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
2952419Sjulian * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
3052419Sjulian * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
3152419Sjulian * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
3252419Sjulian * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
3352419Sjulian * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3452419Sjulian * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
3552419Sjulian * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
3652419Sjulian * OF SUCH DAMAGE.
3752419Sjulian *
3867506Sjulian * Author: Archie Cobbs <archie@freebsd.org>
3952419Sjulian *
4052419Sjulian * $FreeBSD: head/sys/netgraph/ng_async.c 213794 2010-10-13 17:21:21Z rpaulo $
4152752Sjulian * $Whistle: ng_async.c,v 1.17 1999/11/01 09:24:51 julian Exp $
4252419Sjulian */
4352419Sjulian
4452419Sjulian/*
4552419Sjulian * This node type implements a PPP style sync <-> async converter.
4652419Sjulian * See RFC 1661 for details of how asynchronous encoding works.
4752419Sjulian */
4852419Sjulian
4952419Sjulian#include <sys/param.h>
5052419Sjulian#include <sys/systm.h>
5152419Sjulian#include <sys/kernel.h>
5252419Sjulian#include <sys/mbuf.h>
5352419Sjulian#include <sys/malloc.h>
5452419Sjulian#include <sys/errno.h>
5552419Sjulian
5652419Sjulian#include <netgraph/ng_message.h>
5752419Sjulian#include <netgraph/netgraph.h>
5852419Sjulian#include <netgraph/ng_async.h>
5953913Sarchie#include <netgraph/ng_parse.h>
6052419Sjulian
6152419Sjulian#include <net/ppp_defs.h>
6252419Sjulian
6370870Sjulian#ifdef NG_SEPARATE_MALLOC
6470870SjulianMALLOC_DEFINE(M_NETGRAPH_ASYNC, "netgraph_async", "netgraph async node ");
6570870Sjulian#else
6670870Sjulian#define M_NETGRAPH_ASYNC M_NETGRAPH
6770870Sjulian#endif
6870870Sjulian
6970870Sjulian
7052419Sjulian/* Async decode state */
7152419Sjulian#define MODE_HUNT	0
7252419Sjulian#define MODE_NORMAL	1
7352419Sjulian#define MODE_ESC	2
7452419Sjulian
7552419Sjulian/* Private data structure */
7653394Sarchiestruct ng_async_private {
7752419Sjulian	node_p  	node;		/* Our node */
7852419Sjulian	hook_p  	async;		/* Asynchronous side */
7952419Sjulian	hook_p  	sync;		/* Synchronous side */
8052419Sjulian	u_char  	amode;		/* Async hunt/esape mode */
8152419Sjulian	u_int16_t	fcs;		/* Decoded async FCS (so far) */
8252419Sjulian	u_char	       *abuf;		/* Buffer to encode sync into */
8352419Sjulian	u_char	       *sbuf;		/* Buffer to decode async into */
8452419Sjulian	u_int		slen;		/* Length of data in sbuf */
8552419Sjulian	long		lasttime;	/* Time of last async packet sent */
8652419Sjulian	struct		ng_async_cfg	cfg;	/* Configuration */
8752419Sjulian	struct		ng_async_stat	stats;	/* Statistics */
8852419Sjulian};
8953394Sarchietypedef struct ng_async_private *sc_p;
9052419Sjulian
9152419Sjulian/* Useful macros */
9252419Sjulian#define ASYNC_BUF_SIZE(smru)	(2 * (smru) + 10)
9352419Sjulian#define SYNC_BUF_SIZE(amru)	((amru) + 10)
9452419Sjulian#define ERROUT(x)		do { error = (x); goto done; } while (0)
9552419Sjulian
9652419Sjulian/* Netgraph methods */
9753913Sarchiestatic ng_constructor_t		nga_constructor;
9852752Sjulianstatic ng_rcvdata_t		nga_rcvdata;
9952752Sjulianstatic ng_rcvmsg_t		nga_rcvmsg;
10052752Sjulianstatic ng_shutdown_t		nga_shutdown;
10152752Sjulianstatic ng_newhook_t		nga_newhook;
10252752Sjulianstatic ng_disconnect_t		nga_disconnect;
10352419Sjulian
10452419Sjulian/* Helper stuff */
10570700Sjulianstatic int	nga_rcv_sync(const sc_p sc, item_p item);
10670700Sjulianstatic int	nga_rcv_async(const sc_p sc, item_p item);
10752419Sjulian
10853913Sarchie/* Parse type for struct ng_async_cfg */
10997685Sarchiestatic const struct ng_parse_struct_field nga_config_type_fields[]
11097685Sarchie	= NG_ASYNC_CONFIG_TYPE_INFO;
11153913Sarchiestatic const struct ng_parse_type nga_config_type = {
11253913Sarchie	&ng_parse_struct_type,
11397685Sarchie	&nga_config_type_fields
11453913Sarchie};
11553913Sarchie
11653913Sarchie/* Parse type for struct ng_async_stat */
11797685Sarchiestatic const struct ng_parse_struct_field nga_stats_type_fields[]
11897685Sarchie	= NG_ASYNC_STATS_TYPE_INFO;
11953913Sarchiestatic const struct ng_parse_type nga_stats_type = {
12053913Sarchie	&ng_parse_struct_type,
12197685Sarchie	&nga_stats_type_fields
12253913Sarchie};
12353913Sarchie
12453913Sarchie/* List of commands and how to convert arguments to/from ASCII */
12553913Sarchiestatic const struct ng_cmdlist nga_cmdlist[] = {
12653913Sarchie	{
12753913Sarchie	  NGM_ASYNC_COOKIE,
12853913Sarchie	  NGM_ASYNC_CMD_SET_CONFIG,
12953913Sarchie	  "setconfig",
13053913Sarchie	  &nga_config_type,
13153913Sarchie	  NULL
13253913Sarchie	},
13353913Sarchie	{
13453913Sarchie	  NGM_ASYNC_COOKIE,
13553913Sarchie	  NGM_ASYNC_CMD_GET_CONFIG,
13653913Sarchie	  "getconfig",
13753913Sarchie	  NULL,
13853913Sarchie	  &nga_config_type
13953913Sarchie	},
14053913Sarchie	{
14153913Sarchie	  NGM_ASYNC_COOKIE,
14253913Sarchie	  NGM_ASYNC_CMD_GET_STATS,
14353913Sarchie	  "getstats",
14453913Sarchie	  NULL,
14553913Sarchie	  &nga_stats_type
14653913Sarchie	},
14753913Sarchie	{
14853913Sarchie	  NGM_ASYNC_COOKIE,
14953913Sarchie	  NGM_ASYNC_CMD_CLR_STATS,
15053913Sarchie	  "clrstats",
15153913Sarchie	  &nga_stats_type,
15253913Sarchie	  NULL
15353913Sarchie	},
15453913Sarchie	{ 0 }
15553913Sarchie};
15653913Sarchie
15752419Sjulian/* Define the netgraph node type */
15852419Sjulianstatic struct ng_type typestruct = {
159129823Sjulian	.version =	NG_ABI_VERSION,
160129823Sjulian	.name =		NG_ASYNC_NODE_TYPE,
161129823Sjulian	.constructor =	nga_constructor,
162129823Sjulian	.rcvmsg =	nga_rcvmsg,
163129823Sjulian	.shutdown = 	nga_shutdown,
164129823Sjulian	.newhook =	nga_newhook,
165129823Sjulian	.rcvdata =	nga_rcvdata,
166129823Sjulian	.disconnect =	nga_disconnect,
167129823Sjulian	.cmdlist =	nga_cmdlist
16852419Sjulian};
16952419SjulianNETGRAPH_INIT(async, &typestruct);
17052419Sjulian
17152419Sjulian/* CRC table */
17252419Sjulianstatic const u_int16_t fcstab[];
17352419Sjulian
17452419Sjulian/******************************************************************
17552419Sjulian		    NETGRAPH NODE METHODS
17652419Sjulian******************************************************************/
17752419Sjulian
17852419Sjulian/*
17952419Sjulian * Initialize a new node
18052419Sjulian */
18152419Sjulianstatic int
18270700Sjuliannga_constructor(node_p node)
18352419Sjulian{
18452419Sjulian	sc_p sc;
18552419Sjulian
186184205Sdes	sc = malloc(sizeof(*sc), M_NETGRAPH_ASYNC, M_NOWAIT | M_ZERO);
18752419Sjulian	if (sc == NULL)
18852419Sjulian		return (ENOMEM);
18952419Sjulian	sc->amode = MODE_HUNT;
19052419Sjulian	sc->cfg.accm = ~0;
19152419Sjulian	sc->cfg.amru = NG_ASYNC_DEFAULT_MRU;
19252419Sjulian	sc->cfg.smru = NG_ASYNC_DEFAULT_MRU;
193184214Sdes	sc->abuf = malloc(ASYNC_BUF_SIZE(sc->cfg.smru),
194184214Sdes	    M_NETGRAPH_ASYNC, M_NOWAIT);
19552419Sjulian	if (sc->abuf == NULL)
19652419Sjulian		goto fail;
197184214Sdes	sc->sbuf = malloc(SYNC_BUF_SIZE(sc->cfg.amru),
198184214Sdes	    M_NETGRAPH_ASYNC, M_NOWAIT);
19952419Sjulian	if (sc->sbuf == NULL) {
200184205Sdes		free(sc->abuf, M_NETGRAPH_ASYNC);
20152419Sjulianfail:
202184205Sdes		free(sc, M_NETGRAPH_ASYNC);
20352419Sjulian		return (ENOMEM);
20452419Sjulian	}
20570784Sjulian	NG_NODE_SET_PRIVATE(node, sc);
20670700Sjulian	sc->node = node;
20752419Sjulian	return (0);
20852419Sjulian}
20952419Sjulian
21052419Sjulian/*
21152419Sjulian * Reserve a hook for a pending connection
21252419Sjulian */
21352419Sjulianstatic int
21452419Sjuliannga_newhook(node_p node, hook_p hook, const char *name)
21552419Sjulian{
21670784Sjulian	const sc_p sc = NG_NODE_PRIVATE(node);
21752419Sjulian	hook_p *hookp;
21852419Sjulian
21970700Sjulian	if (!strcmp(name, NG_ASYNC_HOOK_ASYNC)) {
22070700Sjulian		/*
22170700Sjulian		 * We use a static buffer here so only one packet
22270700Sjulian		 * at a time can be allowed to travel in this direction.
22370700Sjulian		 * Force Writer semantics.
22470700Sjulian		 */
22570784Sjulian		NG_HOOK_FORCE_WRITER(hook);
22652419Sjulian		hookp = &sc->async;
22770700Sjulian	} else if (!strcmp(name, NG_ASYNC_HOOK_SYNC)) {
22870700Sjulian		/*
22970700Sjulian		 * We use a static state here so only one packet
23070700Sjulian		 * at a time can be allowed to travel in this direction.
23170700Sjulian		 * Force Writer semantics.
23270700Sjulian		 * Since we set this for both directions
23370700Sjulian		 * we might as well set it for the whole node
23470700Sjulian		 * bit I haven;t done that (yet).
23570700Sjulian		 */
23670784Sjulian		NG_HOOK_FORCE_WRITER(hook);
23752419Sjulian		hookp = &sc->sync;
23870700Sjulian	} else {
23952419Sjulian		return (EINVAL);
24070700Sjulian	}
24170700Sjulian	if (*hookp) /* actually can't happen I think [JRE] */
24252419Sjulian		return (EISCONN);
24352419Sjulian	*hookp = hook;
24452419Sjulian	return (0);
24552419Sjulian}
24652419Sjulian
24752419Sjulian/*
24852419Sjulian * Receive incoming data
24952419Sjulian */
25052419Sjulianstatic int
25170700Sjuliannga_rcvdata(hook_p hook, item_p item)
25252419Sjulian{
25370784Sjulian	const sc_p sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
25452419Sjulian
25552419Sjulian	if (hook == sc->sync)
25670700Sjulian		return (nga_rcv_sync(sc, item));
25752976Sarchie	if (hook == sc->async)
25870700Sjulian		return (nga_rcv_async(sc, item));
259213794Srpaulo	panic("%s", __func__);
26052419Sjulian}
26152419Sjulian
26252419Sjulian/*
26352419Sjulian * Receive incoming control message
26452419Sjulian */
26552419Sjulianstatic int
26670700Sjuliannga_rcvmsg(node_p node, item_p item, hook_p lasthook)
26752419Sjulian{
26870784Sjulian	const sc_p sc = NG_NODE_PRIVATE(node);
26952419Sjulian	struct ng_mesg *resp = NULL;
27052419Sjulian	int error = 0;
27170700Sjulian	struct ng_mesg *msg;
27270700Sjulian
27370700Sjulian	NGI_GET_MSG(item, msg);
27452419Sjulian	switch (msg->header.typecookie) {
27552419Sjulian	case NGM_ASYNC_COOKIE:
27652419Sjulian		switch (msg->header.cmd) {
27752419Sjulian		case NGM_ASYNC_CMD_GET_STATS:
27852419Sjulian			NG_MKRESPONSE(resp, msg, sizeof(sc->stats), M_NOWAIT);
27952419Sjulian			if (resp == NULL)
28052419Sjulian				ERROUT(ENOMEM);
28152419Sjulian			*((struct ng_async_stat *) resp->data) = sc->stats;
28252419Sjulian			break;
28352419Sjulian		case NGM_ASYNC_CMD_CLR_STATS:
28452419Sjulian			bzero(&sc->stats, sizeof(sc->stats));
28552419Sjulian			break;
28652419Sjulian		case NGM_ASYNC_CMD_SET_CONFIG:
28752419Sjulian		    {
28852419Sjulian			struct ng_async_cfg *const cfg =
28952419Sjulian				(struct ng_async_cfg *) msg->data;
29052419Sjulian			u_char *buf;
29152419Sjulian
29252419Sjulian			if (msg->header.arglen != sizeof(*cfg))
29352419Sjulian				ERROUT(EINVAL);
29452419Sjulian			if (cfg->amru < NG_ASYNC_MIN_MRU
29552419Sjulian			    || cfg->amru > NG_ASYNC_MAX_MRU
29652419Sjulian			    || cfg->smru < NG_ASYNC_MIN_MRU
29752419Sjulian			    || cfg->smru > NG_ASYNC_MAX_MRU)
29852419Sjulian				ERROUT(EINVAL);
29952419Sjulian			cfg->enabled = !!cfg->enabled;	/* normalize */
30052419Sjulian			if (cfg->smru > sc->cfg.smru) {	/* reallocate buffer */
301184205Sdes				buf = malloc(ASYNC_BUF_SIZE(cfg->smru),
30270870Sjulian				    M_NETGRAPH_ASYNC, M_NOWAIT);
30352419Sjulian				if (!buf)
30452419Sjulian					ERROUT(ENOMEM);
305184205Sdes				free(sc->abuf, M_NETGRAPH_ASYNC);
30652419Sjulian				sc->abuf = buf;
30752419Sjulian			}
30852419Sjulian			if (cfg->amru > sc->cfg.amru) {	/* reallocate buffer */
309184205Sdes				buf = malloc(SYNC_BUF_SIZE(cfg->amru),
31070870Sjulian				    M_NETGRAPH_ASYNC, M_NOWAIT);
31152419Sjulian				if (!buf)
31252419Sjulian					ERROUT(ENOMEM);
313184205Sdes				free(sc->sbuf, M_NETGRAPH_ASYNC);
31452419Sjulian				sc->sbuf = buf;
31552419Sjulian				sc->amode = MODE_HUNT;
31652419Sjulian				sc->slen = 0;
31752419Sjulian			}
31852419Sjulian			if (!cfg->enabled) {
31952419Sjulian				sc->amode = MODE_HUNT;
32052419Sjulian				sc->slen = 0;
32152419Sjulian			}
32252419Sjulian			sc->cfg = *cfg;
32352419Sjulian			break;
32452419Sjulian		    }
32552419Sjulian		case NGM_ASYNC_CMD_GET_CONFIG:
32652419Sjulian			NG_MKRESPONSE(resp, msg, sizeof(sc->cfg), M_NOWAIT);
32752419Sjulian			if (!resp)
32852419Sjulian				ERROUT(ENOMEM);
32952419Sjulian			*((struct ng_async_cfg *) resp->data) = sc->cfg;
33052419Sjulian			break;
33152419Sjulian		default:
33252419Sjulian			ERROUT(EINVAL);
33352419Sjulian		}
33452419Sjulian		break;
33552419Sjulian	default:
33652419Sjulian		ERROUT(EINVAL);
33752419Sjulian	}
33852419Sjuliandone:
33970700Sjulian	NG_RESPOND_MSG(error, node, item, resp);
34070700Sjulian	NG_FREE_MSG(msg);
34152419Sjulian	return (error);
34252419Sjulian}
34352419Sjulian
34452419Sjulian/*
34552419Sjulian * Shutdown this node
34652419Sjulian */
34752419Sjulianstatic int
34852419Sjuliannga_shutdown(node_p node)
34952419Sjulian{
35070784Sjulian	const sc_p sc = NG_NODE_PRIVATE(node);
35152419Sjulian
352184205Sdes	free(sc->abuf, M_NETGRAPH_ASYNC);
353184205Sdes	free(sc->sbuf, M_NETGRAPH_ASYNC);
35452419Sjulian	bzero(sc, sizeof(*sc));
355184205Sdes	free(sc, M_NETGRAPH_ASYNC);
35670784Sjulian	NG_NODE_SET_PRIVATE(node, NULL);
35770784Sjulian	NG_NODE_UNREF(node);
35852419Sjulian	return (0);
35952419Sjulian}
36052419Sjulian
36152419Sjulian/*
36252419Sjulian * Lose a hook. When both hooks go away, we disappear.
36352419Sjulian */
36452419Sjulianstatic int
36552419Sjuliannga_disconnect(hook_p hook)
36652419Sjulian{
36770784Sjulian	const sc_p sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
36852419Sjulian	hook_p *hookp;
36952419Sjulian
37052419Sjulian	if (hook == sc->async)
37152419Sjulian		hookp = &sc->async;
37252419Sjulian	else if (hook == sc->sync)
37352419Sjulian		hookp = &sc->sync;
37452419Sjulian	else
375213794Srpaulo		panic("%s", __func__);
37652419Sjulian	if (!*hookp)
37787599Sobrien		panic("%s 2", __func__);
37852419Sjulian	*hookp = NULL;
37952419Sjulian	bzero(&sc->stats, sizeof(sc->stats));
38052419Sjulian	sc->lasttime = 0;
38170784Sjulian	if ((NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0)
38270784Sjulian	&& (NG_NODE_IS_VALID(NG_HOOK_NODE(hook))))
38370784Sjulian		ng_rmnode_self(NG_HOOK_NODE(hook));
38452419Sjulian	return (0);
38552419Sjulian}
38652419Sjulian
38752419Sjulian/******************************************************************
38852419Sjulian		    INTERNAL HELPER STUFF
38952419Sjulian******************************************************************/
39052419Sjulian
39152419Sjulian/*
39252419Sjulian * Encode a byte into the async buffer
39352419Sjulian */
394131575Sstefanfstatic __inline void
39552419Sjuliannga_async_add(const sc_p sc, u_int16_t *fcs, u_int32_t accm, int *len, u_char x)
39652419Sjulian{
39752419Sjulian	*fcs = PPP_FCS(*fcs, x);
39852419Sjulian	if ((x < 32 && ((1 << x) & accm))
39952419Sjulian	    || (x == PPP_ESCAPE)
40052419Sjulian	    || (x == PPP_FLAG)) {
40152419Sjulian		sc->abuf[(*len)++] = PPP_ESCAPE;
40252419Sjulian		x ^= PPP_TRANS;
40352419Sjulian	}
40452419Sjulian	sc->abuf[(*len)++] = x;
40552419Sjulian}
40652419Sjulian
40752419Sjulian/*
40852976Sarchie * Receive incoming synchronous data.
40952419Sjulian */
41052419Sjulianstatic int
41170700Sjuliannga_rcv_sync(const sc_p sc, item_p item)
41252419Sjulian{
41370700Sjulian	struct ifnet *rcvif;
41453394Sarchie	int alen, error = 0;
41552976Sarchie	struct timeval time;
41652419Sjulian	u_int16_t fcs, fcs0;
41752976Sarchie	u_int32_t accm;
41870700Sjulian	struct mbuf *m;
41952419Sjulian
42070700Sjulian
42152976Sarchie#define ADD_BYTE(x)	nga_async_add(sc, &fcs, accm, &alen, (x))
42252419Sjulian
42352976Sarchie	/* Check for bypass mode */
42452419Sjulian	if (!sc->cfg.enabled) {
42570784Sjulian		NG_FWD_ITEM_HOOK(error, item, sc->async );
42652419Sjulian		return (error);
42752419Sjulian	}
42870700Sjulian	NGI_GET_M(item, m);
42952976Sarchie
43070700Sjulian	rcvif = m->m_pkthdr.rcvif;
43170700Sjulian
43253394Sarchie	/* Get ACCM; special case LCP frames, which use full ACCM */
43352976Sarchie	accm = sc->cfg.accm;
43453394Sarchie	if (m->m_pkthdr.len >= 4) {
43553394Sarchie		static const u_char lcphdr[4] = {
43653394Sarchie		    PPP_ALLSTATIONS,
43753394Sarchie		    PPP_UI,
43853394Sarchie		    (u_char)(PPP_LCP >> 8),
43953394Sarchie		    (u_char)(PPP_LCP & 0xff)
44053394Sarchie		};
44153394Sarchie		u_char buf[4];
44252976Sarchie
44353394Sarchie		m_copydata(m, 0, 4, (caddr_t)buf);
44453394Sarchie		if (bcmp(buf, &lcphdr, 4) == 0)
44552976Sarchie			accm = ~0;
44652976Sarchie	}
44752976Sarchie
44852976Sarchie	/* Check for overflow */
44952419Sjulian	if (m->m_pkthdr.len > sc->cfg.smru) {
45052419Sjulian		sc->stats.syncOverflows++;
45170700Sjulian		NG_FREE_M(m);
45270700Sjulian		NG_FREE_ITEM(item);
45352419Sjulian		return (EMSGSIZE);
45452419Sjulian	}
45552976Sarchie
45652976Sarchie	/* Update stats */
45752419Sjulian	sc->stats.syncFrames++;
45852419Sjulian	sc->stats.syncOctets += m->m_pkthdr.len;
45952419Sjulian
46052419Sjulian	/* Initialize async encoded version of input mbuf */
46152419Sjulian	alen = 0;
46252419Sjulian	fcs = PPP_INITFCS;
46352419Sjulian
46452419Sjulian	/* Add beginning sync flag if it's been long enough to need one */
46552976Sarchie	getmicrotime(&time);
46652976Sarchie	if (time.tv_sec >= sc->lasttime + 1) {
46752976Sarchie		sc->abuf[alen++] = PPP_FLAG;
46852976Sarchie		sc->lasttime = time.tv_sec;
46952419Sjulian	}
47052419Sjulian
47153394Sarchie	/* Add packet payload */
47252976Sarchie	while (m != NULL) {
47352419Sjulian		while (m->m_len > 0) {
47452976Sarchie			ADD_BYTE(*mtod(m, u_char *));
47552419Sjulian			m->m_data++;
47652419Sjulian			m->m_len--;
47752419Sjulian		}
47890227Sdillon		m = m_free(m);
47952419Sjulian	}
48052419Sjulian
48152419Sjulian	/* Add checksum and final sync flag */
48252419Sjulian	fcs0 = fcs;
48352419Sjulian	ADD_BYTE(~fcs0 & 0xff);
48452419Sjulian	ADD_BYTE(~fcs0 >> 8);
48552419Sjulian	sc->abuf[alen++] = PPP_FLAG;
48652419Sjulian
48752419Sjulian	/* Put frame in an mbuf and ship it off */
48852976Sarchie	if (!(m = m_devget(sc->abuf, alen, 0, rcvif, NULL))) {
48970700Sjulian		NG_FREE_ITEM(item);
49052419Sjulian		error = ENOBUFS;
49170700Sjulian	} else {
49270700Sjulian		NG_FWD_NEW_DATA(error, item, sc->async, m);
49370700Sjulian	}
49452419Sjulian	return (error);
49552419Sjulian}
49652419Sjulian
49752419Sjulian/*
49852419Sjulian * Receive incoming asynchronous data
49952976Sarchie * XXX Technically, we should strip out incoming characters
50052976Sarchie *     that are in our ACCM. Not sure if this is good or not.
50152419Sjulian */
50252419Sjulianstatic int
50370700Sjuliannga_rcv_async(const sc_p sc, item_p item)
50452419Sjulian{
50570700Sjulian	struct ifnet *rcvif;
50652419Sjulian	int error;
50770700Sjulian	struct mbuf *m;
50852419Sjulian
50952419Sjulian	if (!sc->cfg.enabled) {
51070784Sjulian		NG_FWD_ITEM_HOOK(error, item,  sc->sync);
51152419Sjulian		return (error);
51252419Sjulian	}
51370700Sjulian	NGI_GET_M(item, m);
51470700Sjulian	rcvif = m->m_pkthdr.rcvif;
51552419Sjulian	while (m) {
51652419Sjulian		struct mbuf *n;
51752419Sjulian
51852419Sjulian		for (; m->m_len > 0; m->m_data++, m->m_len--) {
51952419Sjulian			u_char  ch = *mtod(m, u_char *);
52052419Sjulian
52152419Sjulian			sc->stats.asyncOctets++;
52252419Sjulian			if (ch == PPP_FLAG) {	/* Flag overrides everything */
52352419Sjulian				int     skip = 0;
52452419Sjulian
52552419Sjulian				/* Check for runts */
52652419Sjulian				if (sc->slen < 2) {
52752419Sjulian					if (sc->slen > 0)
52852419Sjulian						sc->stats.asyncRunts++;
52952419Sjulian					goto reset;
53052419Sjulian				}
53152419Sjulian
53252419Sjulian				/* Verify CRC */
53352419Sjulian				if (sc->fcs != PPP_GOODFCS) {
53452419Sjulian					sc->stats.asyncBadCheckSums++;
53552419Sjulian					goto reset;
53652419Sjulian				}
53752419Sjulian				sc->slen -= 2;
53852419Sjulian
53952419Sjulian				/* Strip address and control fields */
54052419Sjulian				if (sc->slen >= 2
54152419Sjulian				    && sc->sbuf[0] == PPP_ALLSTATIONS
54252419Sjulian				    && sc->sbuf[1] == PPP_UI)
54352419Sjulian					skip = 2;
54452419Sjulian
54552419Sjulian				/* Check for frame too big */
54652419Sjulian				if (sc->slen - skip > sc->cfg.amru) {
54752419Sjulian					sc->stats.asyncOverflows++;
54852419Sjulian					goto reset;
54952419Sjulian				}
55052419Sjulian
55152419Sjulian				/* OK, ship it out */
55252419Sjulian				if ((n = m_devget(sc->sbuf + skip,
55370700Sjulian					   sc->slen - skip, 0, rcvif, NULL))) {
55470700Sjulian					if (item) { /* sets NULL -> item */
55570700Sjulian						NG_FWD_NEW_DATA(error, item,
55670700Sjulian							sc->sync, n);
55770700Sjulian					} else {
55870700Sjulian						NG_SEND_DATA_ONLY(error,
55970700Sjulian							sc->sync ,n);
56070700Sjulian					}
56170700Sjulian				}
56252419Sjulian				sc->stats.asyncFrames++;
56352419Sjulianreset:
56452419Sjulian				sc->amode = MODE_NORMAL;
56552419Sjulian				sc->fcs = PPP_INITFCS;
56652419Sjulian				sc->slen = 0;
56752419Sjulian				continue;
56852419Sjulian			}
56952419Sjulian			switch (sc->amode) {
57052419Sjulian			case MODE_NORMAL:
57152419Sjulian				if (ch == PPP_ESCAPE) {
57252419Sjulian					sc->amode = MODE_ESC;
57352419Sjulian					continue;
57452419Sjulian				}
57552419Sjulian				break;
57652419Sjulian			case MODE_ESC:
57752419Sjulian				ch ^= PPP_TRANS;
57852419Sjulian				sc->amode = MODE_NORMAL;
57952419Sjulian				break;
58052419Sjulian			case MODE_HUNT:
58152419Sjulian			default:
58252419Sjulian				continue;
58352419Sjulian			}
58452419Sjulian
58552419Sjulian			/* Add byte to frame */
58652419Sjulian			if (sc->slen >= SYNC_BUF_SIZE(sc->cfg.amru)) {
58752419Sjulian				sc->stats.asyncOverflows++;
58852419Sjulian				sc->amode = MODE_HUNT;
58952419Sjulian				sc->slen = 0;
59052419Sjulian			} else {
59152419Sjulian				sc->sbuf[sc->slen++] = ch;
59252419Sjulian				sc->fcs = PPP_FCS(sc->fcs, ch);
59352419Sjulian			}
59452419Sjulian		}
59590227Sdillon		m = m_free(m);
59652419Sjulian	}
59770700Sjulian	if (item)
59870700Sjulian		NG_FREE_ITEM(item);
59952419Sjulian	return (0);
60052419Sjulian}
60152419Sjulian
60252419Sjulian/*
60352419Sjulian * CRC table
60452419Sjulian *
60552419Sjulian * Taken from RFC 1171 Appendix B
60652419Sjulian */
60752419Sjulianstatic const u_int16_t fcstab[256] = {
60852419Sjulian	 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
60952419Sjulian	 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
61052419Sjulian	 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
61152419Sjulian	 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
61252419Sjulian	 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
61352419Sjulian	 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
61452419Sjulian	 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
61552419Sjulian	 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
61652419Sjulian	 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
61752419Sjulian	 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
61852419Sjulian	 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
61952419Sjulian	 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
62052419Sjulian	 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
62152419Sjulian	 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
62252419Sjulian	 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
62352419Sjulian	 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
62452419Sjulian	 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
62552419Sjulian	 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
62652419Sjulian	 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
62752419Sjulian	 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
62852419Sjulian	 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
62952419Sjulian	 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
63052419Sjulian	 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
63152419Sjulian	 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
63252419Sjulian	 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
63352419Sjulian	 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
63452419Sjulian	 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
63552419Sjulian	 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
63652419Sjulian	 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
63752419Sjulian	 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
63852419Sjulian	 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
63952419Sjulian	 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
64052419Sjulian};
641