ng_async.c revision 52419
152419Sjulian
252419Sjulian/*
352419Sjulian * ng_async.c
452419Sjulian *
552419Sjulian * Copyright (c) 1996-1999 Whistle Communications, Inc.
652419Sjulian * All rights reserved.
752419Sjulian *
852419Sjulian * Subject to the following obligations and disclaimer of warranty, use and
952419Sjulian * redistribution of this software, in source or object code forms, with or
1052419Sjulian * without modifications are expressly permitted by Whistle Communications;
1152419Sjulian * provided, however, that:
1252419Sjulian * 1. Any and all reproductions of the source or object code must include the
1352419Sjulian *    copyright notice above and the following disclaimer of warranties; and
1452419Sjulian * 2. No rights are granted, in any manner or form, to use Whistle
1552419Sjulian *    Communications, Inc. trademarks, including the mark "WHISTLE
1652419Sjulian *    COMMUNICATIONS" on advertising, endorsements, or otherwise except as
1752419Sjulian *    such appears in the above copyright notice or in the software.
1852419Sjulian *
1952419Sjulian * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
2052419Sjulian * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
2152419Sjulian * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
2252419Sjulian * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
2352419Sjulian * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
2452419Sjulian * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
2552419Sjulian * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
2652419Sjulian * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
2752419Sjulian * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
2852419Sjulian * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
2952419Sjulian * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
3052419Sjulian * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
3152419Sjulian * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
3252419Sjulian * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3352419Sjulian * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
3452419Sjulian * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
3552419Sjulian * OF SUCH DAMAGE.
3652419Sjulian *
3752419Sjulian * Author: Archie Cobbs <archie@whistle.com>
3852419Sjulian *
3952419Sjulian * $FreeBSD: head/sys/netgraph/ng_async.c 52419 1999-10-21 09:06:11Z julian $
4052419Sjulian * $Whistle: ng_async.c,v 1.15 1999/01/28 23:54:52 julian Exp $
4152419Sjulian */
4252419Sjulian
4352419Sjulian/*
4452419Sjulian * This node type implements a PPP style sync <-> async converter.
4552419Sjulian * See RFC 1661 for details of how asynchronous encoding works.
4652419Sjulian */
4752419Sjulian
4852419Sjulian#include <sys/param.h>
4952419Sjulian#include <sys/systm.h>
5052419Sjulian#include <sys/kernel.h>
5152419Sjulian#include <sys/conf.h>
5252419Sjulian#include <sys/proc.h>
5352419Sjulian#include <sys/mbuf.h>
5452419Sjulian#include <sys/malloc.h>
5552419Sjulian#include <sys/socket.h>
5652419Sjulian#include <sys/file.h>
5752419Sjulian#include <sys/tty.h>
5852419Sjulian#include <sys/syslog.h>
5952419Sjulian#include <sys/errno.h>
6052419Sjulian
6152419Sjulian#include <netgraph/ng_message.h>
6252419Sjulian#include <netgraph/netgraph.h>
6352419Sjulian#include <netgraph/ng_async.h>
6452419Sjulian
6552419Sjulian#include <net/ppp_defs.h>
6652419Sjulian
6752419Sjulian/* Optimize opening and closing flags into one? Set to max # seconds delay */
6852419Sjulian#define SYNC_OPT_TIME	1	/* one second maximum */
6952419Sjulian
7052419Sjulian/* Async decode state */
7152419Sjulian#define MODE_HUNT	0
7252419Sjulian#define MODE_NORMAL	1
7352419Sjulian#define MODE_ESC	2
7452419Sjulian
7552419Sjulian/* Private data structure */
7652419Sjulianstruct private {
7752419Sjulian	node_p  	node;		/* Our node */
7852419Sjulian	hook_p  	async;		/* Asynchronous side */
7952419Sjulian	hook_p  	sync;		/* Synchronous side */
8052419Sjulian	hook_p  	sync2;		/* Synchronous side, full escapes */
8152419Sjulian	u_char  	amode;		/* Async hunt/esape mode */
8252419Sjulian	u_int16_t	fcs;		/* Decoded async FCS (so far) */
8352419Sjulian	u_char	       *abuf;		/* Buffer to encode sync into */
8452419Sjulian	u_char	       *sbuf;		/* Buffer to decode async into */
8552419Sjulian	u_int		slen;		/* Length of data in sbuf */
8652419Sjulian#if SYNC_OPT_TIME
8752419Sjulian	long		lasttime;	/* Time of last async packet sent */
8852419Sjulian#endif
8952419Sjulian	struct		ng_async_cfg	cfg;	/* Configuration */
9052419Sjulian	struct		ng_async_stat	stats;	/* Statistics */
9152419Sjulian};
9252419Sjuliantypedef struct private *sc_p;
9352419Sjulian
9452419Sjulian/* Useful macros */
9552419Sjulian#define ASYNC_BUF_SIZE(smru)	(2 * (smru) + 10)
9652419Sjulian#define SYNC_BUF_SIZE(amru)	((amru) + 10)
9752419Sjulian#define ERROUT(x)		do { error = (x); goto done; } while (0)
9852419Sjulian
9952419Sjulian/* Netgraph methods */
10052419Sjulianstatic int	nga_constructor(node_p *node);
10152419Sjulianstatic int	nga_rcvdata(hook_p hook, struct mbuf *m, meta_p meta);
10252419Sjulianstatic int	nga_rcvmsg(node_p node, struct ng_mesg *msg,
10352419Sjulian		    const char *rtn, struct ng_mesg **resp);
10452419Sjulianstatic int	nga_shutdown(node_p node);
10552419Sjulianstatic int	nga_newhook(node_p node, hook_p hook, const char *name);
10652419Sjulianstatic int	nga_disconnect(hook_p hook);
10752419Sjulian
10852419Sjulian/* Helper stuff */
10952419Sjulianstatic int	nga_rcv_sync(const sc_p sc, struct mbuf *m, meta_p meta);
11052419Sjulianstatic int	nga_rcv_async(const sc_p sc, struct mbuf *m, meta_p meta);
11152419Sjulian
11252419Sjulian/* Define the netgraph node type */
11352419Sjulianstatic struct ng_type typestruct = {
11452419Sjulian	NG_VERSION,
11552419Sjulian	NG_ASYNC_NODE_TYPE,
11652419Sjulian	NULL,
11752419Sjulian	nga_constructor,
11852419Sjulian	nga_rcvmsg,
11952419Sjulian	nga_shutdown,
12052419Sjulian	nga_newhook,
12152419Sjulian	NULL,
12252419Sjulian	NULL,
12352419Sjulian	nga_rcvdata,
12452419Sjulian	nga_rcvdata,
12552419Sjulian	nga_disconnect
12652419Sjulian};
12752419SjulianNETGRAPH_INIT(async, &typestruct);
12852419Sjulian
12952419Sjulian/* CRC table */
13052419Sjulianstatic const u_int16_t fcstab[];
13152419Sjulian
13252419Sjulian/******************************************************************
13352419Sjulian		    NETGRAPH NODE METHODS
13452419Sjulian******************************************************************/
13552419Sjulian
13652419Sjulian/*
13752419Sjulian * Initialize a new node
13852419Sjulian */
13952419Sjulianstatic int
14052419Sjuliannga_constructor(node_p *nodep)
14152419Sjulian{
14252419Sjulian	sc_p sc;
14352419Sjulian	int error;
14452419Sjulian
14552419Sjulian	if ((error = ng_make_node_common(&typestruct, nodep)))
14652419Sjulian		return (error);
14752419Sjulian	MALLOC(sc, sc_p, sizeof(*sc), M_NETGRAPH, M_WAITOK);
14852419Sjulian	if (sc == NULL)
14952419Sjulian		return (ENOMEM);
15052419Sjulian	bzero(sc, sizeof(*sc));
15152419Sjulian	sc->amode = MODE_HUNT;
15252419Sjulian	sc->cfg.accm = ~0;
15352419Sjulian	sc->cfg.amru = NG_ASYNC_DEFAULT_MRU;
15452419Sjulian	sc->cfg.smru = NG_ASYNC_DEFAULT_MRU;
15552419Sjulian	MALLOC(sc->abuf, u_char *,
15652419Sjulian	    ASYNC_BUF_SIZE(sc->cfg.smru), M_NETGRAPH, M_WAITOK);
15752419Sjulian	if (sc->abuf == NULL)
15852419Sjulian		goto fail;
15952419Sjulian	MALLOC(sc->sbuf, u_char *,
16052419Sjulian	    SYNC_BUF_SIZE(sc->cfg.amru), M_NETGRAPH, M_WAITOK);
16152419Sjulian	if (sc->sbuf == NULL) {
16252419Sjulian		FREE(sc->abuf, M_NETGRAPH);
16352419Sjulianfail:
16452419Sjulian		FREE(sc, M_NETGRAPH);
16552419Sjulian		return (ENOMEM);
16652419Sjulian	}
16752419Sjulian	(*nodep)->private = sc;
16852419Sjulian	sc->node = *nodep;
16952419Sjulian	return (0);
17052419Sjulian}
17152419Sjulian
17252419Sjulian/*
17352419Sjulian * Reserve a hook for a pending connection
17452419Sjulian */
17552419Sjulianstatic int
17652419Sjuliannga_newhook(node_p node, hook_p hook, const char *name)
17752419Sjulian{
17852419Sjulian	const sc_p sc = node->private;
17952419Sjulian	hook_p *hookp;
18052419Sjulian
18152419Sjulian	if (!strcmp(name, NG_ASYNC_HOOK_ASYNC))
18252419Sjulian		hookp = &sc->async;
18352419Sjulian	else if (!strcmp(name, NG_ASYNC_HOOK_SYNC))
18452419Sjulian		hookp = &sc->sync;
18552419Sjulian	else if (!strcmp(name, NG_ASYNC_HOOK_SYNC2))
18652419Sjulian		hookp = &sc->sync2;
18752419Sjulian	else
18852419Sjulian		return (EINVAL);
18952419Sjulian	if (*hookp)
19052419Sjulian		return (EISCONN);
19152419Sjulian	*hookp = hook;
19252419Sjulian	return (0);
19352419Sjulian}
19452419Sjulian
19552419Sjulian/*
19652419Sjulian * Receive incoming data
19752419Sjulian */
19852419Sjulianstatic int
19952419Sjuliannga_rcvdata(hook_p hook, struct mbuf *m, meta_p meta)
20052419Sjulian{
20152419Sjulian	const sc_p sc = hook->node->private;
20252419Sjulian
20352419Sjulian	if (hook == sc->sync)
20452419Sjulian		return (nga_rcv_sync(sc, m, meta));
20552419Sjulian	else if (hook == sc->sync2) {
20652419Sjulian		const u_char acfcompSave = sc->cfg.acfcomp;
20752419Sjulian		const u_int32_t accmSave = sc->cfg.accm;
20852419Sjulian		int     rtn;
20952419Sjulian
21052419Sjulian		sc->cfg.acfcomp = 0;
21152419Sjulian		sc->cfg.accm = ~0;
21252419Sjulian		rtn = nga_rcv_sync(sc, m, meta);
21352419Sjulian		sc->cfg.acfcomp = acfcompSave;
21452419Sjulian		sc->cfg.accm = accmSave;
21552419Sjulian		return (rtn);
21652419Sjulian	} else if (hook == sc->async)
21752419Sjulian		return (nga_rcv_async(sc, m, meta));
21852419Sjulian	panic(__FUNCTION__);
21952419Sjulian}
22052419Sjulian
22152419Sjulian/*
22252419Sjulian * Receive incoming control message
22352419Sjulian */
22452419Sjulianstatic int
22552419Sjuliannga_rcvmsg(node_p node, struct ng_mesg *msg,
22652419Sjulian	const char *rtn, struct ng_mesg **rptr)
22752419Sjulian{
22852419Sjulian	const sc_p sc = (sc_p) node->private;
22952419Sjulian	struct ng_mesg *resp = NULL;
23052419Sjulian	int error = 0;
23152419Sjulian
23252419Sjulian	switch (msg->header.typecookie) {
23352419Sjulian	case NGM_ASYNC_COOKIE:
23452419Sjulian		switch (msg->header.cmd) {
23552419Sjulian		case NGM_ASYNC_CMD_GET_STATS:
23652419Sjulian			NG_MKRESPONSE(resp, msg, sizeof(sc->stats), M_NOWAIT);
23752419Sjulian			if (resp == NULL)
23852419Sjulian				ERROUT(ENOMEM);
23952419Sjulian			*((struct ng_async_stat *) resp->data) = sc->stats;
24052419Sjulian			break;
24152419Sjulian		case NGM_ASYNC_CMD_CLR_STATS:
24252419Sjulian			bzero(&sc->stats, sizeof(sc->stats));
24352419Sjulian			break;
24452419Sjulian		case NGM_ASYNC_CMD_SET_CONFIG:
24552419Sjulian		    {
24652419Sjulian			struct ng_async_cfg *const cfg =
24752419Sjulian				(struct ng_async_cfg *) msg->data;
24852419Sjulian			u_char *buf;
24952419Sjulian
25052419Sjulian			if (msg->header.arglen != sizeof(*cfg))
25152419Sjulian				ERROUT(EINVAL);
25252419Sjulian			if (cfg->amru < NG_ASYNC_MIN_MRU
25352419Sjulian			    || cfg->amru > NG_ASYNC_MAX_MRU
25452419Sjulian			    || cfg->smru < NG_ASYNC_MIN_MRU
25552419Sjulian			    || cfg->smru > NG_ASYNC_MAX_MRU)
25652419Sjulian				ERROUT(EINVAL);
25752419Sjulian			cfg->enabled = !!cfg->enabled;	/* normalize */
25852419Sjulian			cfg->acfcomp = !!cfg->acfcomp;	/* normalize */
25952419Sjulian			if (cfg->smru > sc->cfg.smru) {	/* reallocate buffer */
26052419Sjulian				MALLOC(buf, u_char *, ASYNC_BUF_SIZE(cfg->smru),
26152419Sjulian				    M_NETGRAPH, M_NOWAIT);
26252419Sjulian				if (!buf)
26352419Sjulian					ERROUT(ENOMEM);
26452419Sjulian				FREE(sc->abuf, M_NETGRAPH);
26552419Sjulian				sc->abuf = buf;
26652419Sjulian			}
26752419Sjulian			if (cfg->amru > sc->cfg.amru) {	/* reallocate buffer */
26852419Sjulian				MALLOC(buf, u_char *, SYNC_BUF_SIZE(cfg->amru),
26952419Sjulian				    M_NETGRAPH, M_NOWAIT);
27052419Sjulian				if (!buf)
27152419Sjulian					ERROUT(ENOMEM);
27252419Sjulian				FREE(sc->sbuf, M_NETGRAPH);
27352419Sjulian				sc->sbuf = buf;
27452419Sjulian				sc->amode = MODE_HUNT;
27552419Sjulian				sc->slen = 0;
27652419Sjulian			}
27752419Sjulian			if (!cfg->enabled) {
27852419Sjulian				sc->amode = MODE_HUNT;
27952419Sjulian				sc->slen = 0;
28052419Sjulian			}
28152419Sjulian			sc->cfg = *cfg;
28252419Sjulian			break;
28352419Sjulian		    }
28452419Sjulian		case NGM_ASYNC_CMD_GET_CONFIG:
28552419Sjulian			NG_MKRESPONSE(resp, msg, sizeof(sc->cfg), M_NOWAIT);
28652419Sjulian			if (!resp)
28752419Sjulian				ERROUT(ENOMEM);
28852419Sjulian			*((struct ng_async_cfg *) resp->data) = sc->cfg;
28952419Sjulian			break;
29052419Sjulian		default:
29152419Sjulian			ERROUT(EINVAL);
29252419Sjulian		}
29352419Sjulian		break;
29452419Sjulian	default:
29552419Sjulian		ERROUT(EINVAL);
29652419Sjulian	}
29752419Sjulian	if (rptr)
29852419Sjulian		*rptr = resp;
29952419Sjulian	else if (resp)
30052419Sjulian		FREE(resp, M_NETGRAPH);
30152419Sjulian
30252419Sjuliandone:
30352419Sjulian	FREE(msg, M_NETGRAPH);
30452419Sjulian	return (error);
30552419Sjulian}
30652419Sjulian
30752419Sjulian/*
30852419Sjulian * Shutdown this node
30952419Sjulian */
31052419Sjulianstatic int
31152419Sjuliannga_shutdown(node_p node)
31252419Sjulian{
31352419Sjulian	const sc_p sc = node->private;
31452419Sjulian
31552419Sjulian	ng_cutlinks(node);
31652419Sjulian	ng_unname(node);
31752419Sjulian	FREE(sc->abuf, M_NETGRAPH);
31852419Sjulian	FREE(sc->sbuf, M_NETGRAPH);
31952419Sjulian	bzero(sc, sizeof(*sc));
32052419Sjulian	FREE(sc, M_NETGRAPH);
32152419Sjulian	node->private = NULL;
32252419Sjulian	ng_unref(node);
32352419Sjulian	return (0);
32452419Sjulian}
32552419Sjulian
32652419Sjulian/*
32752419Sjulian * Lose a hook. When both hooks go away, we disappear.
32852419Sjulian */
32952419Sjulianstatic int
33052419Sjuliannga_disconnect(hook_p hook)
33152419Sjulian{
33252419Sjulian	const sc_p sc = hook->node->private;
33352419Sjulian	hook_p *hookp;
33452419Sjulian
33552419Sjulian	if (hook == sc->async)
33652419Sjulian		hookp = &sc->async;
33752419Sjulian	else if (hook == sc->sync)
33852419Sjulian		hookp = &sc->sync;
33952419Sjulian	else if (hook == sc->sync2)
34052419Sjulian		hookp = &sc->sync2;
34152419Sjulian	else
34252419Sjulian		panic(__FUNCTION__);
34352419Sjulian	if (!*hookp)
34452419Sjulian		panic(__FUNCTION__ "2");
34552419Sjulian	*hookp = NULL;
34652419Sjulian	bzero(&sc->stats, sizeof(sc->stats));
34752419Sjulian#if SYNC_OPT_TIME
34852419Sjulian	sc->lasttime = 0;
34952419Sjulian#endif
35052419Sjulian	if (hook->node->numhooks == 0)
35152419Sjulian		ng_rmnode(hook->node);
35252419Sjulian	return (0);
35352419Sjulian}
35452419Sjulian
35552419Sjulian/******************************************************************
35652419Sjulian		    INTERNAL HELPER STUFF
35752419Sjulian******************************************************************/
35852419Sjulian
35952419Sjulian/*
36052419Sjulian * Encode a byte into the async buffer
36152419Sjulian */
36252419Sjulianstatic __inline__ void
36352419Sjuliannga_async_add(const sc_p sc, u_int16_t *fcs, u_int32_t accm, int *len, u_char x)
36452419Sjulian{
36552419Sjulian	*fcs = PPP_FCS(*fcs, x);
36652419Sjulian	if ((x < 32 && ((1 << x) & accm))
36752419Sjulian	    || (x == PPP_ESCAPE)
36852419Sjulian	    || (x == PPP_FLAG)) {
36952419Sjulian		sc->abuf[(*len)++] = PPP_ESCAPE;
37052419Sjulian		x ^= PPP_TRANS;
37152419Sjulian	}
37252419Sjulian	sc->abuf[(*len)++] = x;
37352419Sjulian}
37452419Sjulian
37552419Sjulian/*
37652419Sjulian * Receive incoming synchronous data. Any "meta" information means
37752419Sjulian * for us to apply full ACCM to this frame.
37852419Sjulian */
37952419Sjulianstatic int
38052419Sjuliannga_rcv_sync(const sc_p sc, struct mbuf *m, meta_p meta)
38152419Sjulian{
38252419Sjulian	struct ifnet *const rcvif = m->m_pkthdr.rcvif;
38352419Sjulian	u_int16_t fcs, fcs0;
38452419Sjulian	int alen, error = 0;
38552419Sjulian
38652419Sjulian#define ADD_BYTE(x)	\
38752419Sjulian  nga_async_add(sc, &fcs, meta ? ~0 : sc->cfg.accm, &alen, (x))
38852419Sjulian
38952419Sjulian	if (!sc->cfg.enabled) {
39052419Sjulian		NG_SEND_DATA(error, sc->async, m, meta);
39152419Sjulian		return (error);
39252419Sjulian	}
39352419Sjulian	if (m->m_pkthdr.len > sc->cfg.smru) {
39452419Sjulian		sc->stats.syncOverflows++;
39552419Sjulian		NG_FREE_DATA(m, meta);
39652419Sjulian		return (EMSGSIZE);
39752419Sjulian	}
39852419Sjulian	sc->stats.syncFrames++;
39952419Sjulian	sc->stats.syncOctets += m->m_pkthdr.len;
40052419Sjulian
40152419Sjulian	/* Initialize async encoded version of input mbuf */
40252419Sjulian	alen = 0;
40352419Sjulian	fcs = PPP_INITFCS;
40452419Sjulian
40552419Sjulian	/* Add beginning sync flag if it's been long enough to need one */
40652419Sjulian#if SYNC_OPT_TIME
40752419Sjulian	{
40852419Sjulian		struct timeval time;
40952419Sjulian
41052419Sjulian		getmicrotime(&time);
41152419Sjulian		if (time.tv_sec >= sc->lasttime + SYNC_OPT_TIME) {
41252419Sjulian			sc->abuf[alen++] = PPP_FLAG;
41352419Sjulian			sc->lasttime = time.tv_sec;
41452419Sjulian		}
41552419Sjulian	}
41652419Sjulian#else
41752419Sjulian	sc->abuf[alen++] = PPP_FLAG;
41852419Sjulian#endif
41952419Sjulian
42052419Sjulian	/* Add option address and control fields, then packet payload */
42152419Sjulian	if (!sc->cfg.acfcomp || meta) {
42252419Sjulian		ADD_BYTE(PPP_ALLSTATIONS);
42352419Sjulian		ADD_BYTE(PPP_UI);
42452419Sjulian	}
42552419Sjulian	while (m) {
42652419Sjulian		struct mbuf *n;
42752419Sjulian
42852419Sjulian		while (m->m_len > 0) {
42952419Sjulian			u_char const ch = *mtod(m, u_char *);
43052419Sjulian
43152419Sjulian			ADD_BYTE(ch);
43252419Sjulian			m->m_data++;
43352419Sjulian			m->m_len--;
43452419Sjulian		}
43552419Sjulian		MFREE(m, n);
43652419Sjulian		m = n;
43752419Sjulian	}
43852419Sjulian
43952419Sjulian	/* Add checksum and final sync flag */
44052419Sjulian	fcs0 = fcs;
44152419Sjulian	ADD_BYTE(~fcs0 & 0xff);
44252419Sjulian	ADD_BYTE(~fcs0 >> 8);
44352419Sjulian	sc->abuf[alen++] = PPP_FLAG;
44452419Sjulian
44552419Sjulian	/* Put frame in an mbuf and ship it off */
44652419Sjulian	NG_FREE_META(meta);
44752419Sjulian	if (!(m = m_devget(sc->abuf, alen, 0, rcvif, NULL)))
44852419Sjulian		error = ENOBUFS;
44952419Sjulian	else
45052419Sjulian		NG_SEND_DATA(error, sc->async, m, meta);
45152419Sjulian	return (error);
45252419Sjulian}
45352419Sjulian
45452419Sjulian/*
45552419Sjulian * Receive incoming asynchronous data
45652419Sjulian * XXX technically, we should strip out supposedly escaped characters
45752419Sjulian */
45852419Sjulianstatic int
45952419Sjuliannga_rcv_async(const sc_p sc, struct mbuf * m, meta_p meta)
46052419Sjulian{
46152419Sjulian	struct ifnet *const rcvif = m->m_pkthdr.rcvif;
46252419Sjulian	int error;
46352419Sjulian
46452419Sjulian	if (!sc->cfg.enabled) {
46552419Sjulian		NG_SEND_DATA(error, sc->sync, m, meta);
46652419Sjulian		return (error);
46752419Sjulian	}
46852419Sjulian	NG_FREE_META(meta);
46952419Sjulian	while (m) {
47052419Sjulian		struct mbuf *n;
47152419Sjulian
47252419Sjulian		for (; m->m_len > 0; m->m_data++, m->m_len--) {
47352419Sjulian			u_char  ch = *mtod(m, u_char *);
47452419Sjulian
47552419Sjulian			sc->stats.asyncOctets++;
47652419Sjulian			if (ch == PPP_FLAG) {	/* Flag overrides everything */
47752419Sjulian				int     skip = 0;
47852419Sjulian
47952419Sjulian				/* Check for runts */
48052419Sjulian				if (sc->slen < 2) {
48152419Sjulian					if (sc->slen > 0)
48252419Sjulian						sc->stats.asyncRunts++;
48352419Sjulian					goto reset;
48452419Sjulian				}
48552419Sjulian
48652419Sjulian				/* Verify CRC */
48752419Sjulian				if (sc->fcs != PPP_GOODFCS) {
48852419Sjulian					sc->stats.asyncBadCheckSums++;
48952419Sjulian					goto reset;
49052419Sjulian				}
49152419Sjulian				sc->slen -= 2;
49252419Sjulian
49352419Sjulian				/* Strip address and control fields */
49452419Sjulian				if (sc->slen >= 2
49552419Sjulian				    && sc->sbuf[0] == PPP_ALLSTATIONS
49652419Sjulian				    && sc->sbuf[1] == PPP_UI)
49752419Sjulian					skip = 2;
49852419Sjulian
49952419Sjulian				/* Check for frame too big */
50052419Sjulian				if (sc->slen - skip > sc->cfg.amru) {
50152419Sjulian					sc->stats.asyncOverflows++;
50252419Sjulian					goto reset;
50352419Sjulian				}
50452419Sjulian
50552419Sjulian				/* OK, ship it out */
50652419Sjulian				if ((n = m_devget(sc->sbuf + skip,
50752419Sjulian					   sc->slen - skip, 0, rcvif, NULL)))
50852419Sjulian					NG_SEND_DATA(error, sc->sync, n, meta);
50952419Sjulian				sc->stats.asyncFrames++;
51052419Sjulianreset:
51152419Sjulian				sc->amode = MODE_NORMAL;
51252419Sjulian				sc->fcs = PPP_INITFCS;
51352419Sjulian				sc->slen = 0;
51452419Sjulian				continue;
51552419Sjulian			}
51652419Sjulian			switch (sc->amode) {
51752419Sjulian			case MODE_NORMAL:
51852419Sjulian				if (ch == PPP_ESCAPE) {
51952419Sjulian					sc->amode = MODE_ESC;
52052419Sjulian					continue;
52152419Sjulian				}
52252419Sjulian				break;
52352419Sjulian			case MODE_ESC:
52452419Sjulian				ch ^= PPP_TRANS;
52552419Sjulian				sc->amode = MODE_NORMAL;
52652419Sjulian				break;
52752419Sjulian			case MODE_HUNT:
52852419Sjulian			default:
52952419Sjulian				continue;
53052419Sjulian			}
53152419Sjulian
53252419Sjulian			/* Add byte to frame */
53352419Sjulian			if (sc->slen >= SYNC_BUF_SIZE(sc->cfg.amru)) {
53452419Sjulian				sc->stats.asyncOverflows++;
53552419Sjulian				sc->amode = MODE_HUNT;
53652419Sjulian				sc->slen = 0;
53752419Sjulian			} else {
53852419Sjulian				sc->sbuf[sc->slen++] = ch;
53952419Sjulian				sc->fcs = PPP_FCS(sc->fcs, ch);
54052419Sjulian			}
54152419Sjulian		}
54252419Sjulian		MFREE(m, n);
54352419Sjulian		m = n;
54452419Sjulian	}
54552419Sjulian	return (0);
54652419Sjulian}
54752419Sjulian
54852419Sjulian/*
54952419Sjulian * CRC table
55052419Sjulian *
55152419Sjulian * Taken from RFC 1171 Appendix B
55252419Sjulian */
55352419Sjulianstatic const u_int16_t fcstab[256] = {
55452419Sjulian	 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
55552419Sjulian	 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
55652419Sjulian	 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
55752419Sjulian	 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
55852419Sjulian	 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
55952419Sjulian	 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
56052419Sjulian	 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
56152419Sjulian	 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
56252419Sjulian	 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
56352419Sjulian	 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
56452419Sjulian	 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
56552419Sjulian	 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
56652419Sjulian	 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
56752419Sjulian	 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
56852419Sjulian	 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
56952419Sjulian	 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
57052419Sjulian	 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
57152419Sjulian	 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
57252419Sjulian	 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
57352419Sjulian	 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
57452419Sjulian	 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
57552419Sjulian	 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
57652419Sjulian	 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
57752419Sjulian	 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
57852419Sjulian	 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
57952419Sjulian	 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
58052419Sjulian	 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
58152419Sjulian	 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
58252419Sjulian	 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
58352419Sjulian	 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
58452419Sjulian	 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
58552419Sjulian	 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
58652419Sjulian};
587