ng_async.c revision 129823
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 *
3767506Sjulian * Author: Archie Cobbs <archie@freebsd.org>
3852419Sjulian *
3952419Sjulian * $FreeBSD: head/sys/netgraph/ng_async.c 129823 2004-05-29 00:51:19Z julian $
4052752Sjulian * $Whistle: ng_async.c,v 1.17 1999/11/01 09:24:51 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/mbuf.h>
5252419Sjulian#include <sys/malloc.h>
5352419Sjulian#include <sys/errno.h>
5452419Sjulian
5552419Sjulian#include <netgraph/ng_message.h>
5652419Sjulian#include <netgraph/netgraph.h>
5752419Sjulian#include <netgraph/ng_async.h>
5853913Sarchie#include <netgraph/ng_parse.h>
5952419Sjulian
6052419Sjulian#include <net/ppp_defs.h>
6152419Sjulian
6270870Sjulian#ifdef NG_SEPARATE_MALLOC
6370870SjulianMALLOC_DEFINE(M_NETGRAPH_ASYNC, "netgraph_async", "netgraph async node ");
6470870Sjulian#else
6570870Sjulian#define M_NETGRAPH_ASYNC M_NETGRAPH
6670870Sjulian#endif
6770870Sjulian
6870870Sjulian
6952419Sjulian/* Async decode state */
7052419Sjulian#define MODE_HUNT	0
7152419Sjulian#define MODE_NORMAL	1
7252419Sjulian#define MODE_ESC	2
7352419Sjulian
7452419Sjulian/* Private data structure */
7553394Sarchiestruct ng_async_private {
7652419Sjulian	node_p  	node;		/* Our node */
7752419Sjulian	hook_p  	async;		/* Asynchronous side */
7852419Sjulian	hook_p  	sync;		/* Synchronous side */
7952419Sjulian	u_char  	amode;		/* Async hunt/esape mode */
8052419Sjulian	u_int16_t	fcs;		/* Decoded async FCS (so far) */
8152419Sjulian	u_char	       *abuf;		/* Buffer to encode sync into */
8252419Sjulian	u_char	       *sbuf;		/* Buffer to decode async into */
8352419Sjulian	u_int		slen;		/* Length of data in sbuf */
8452419Sjulian	long		lasttime;	/* Time of last async packet sent */
8552419Sjulian	struct		ng_async_cfg	cfg;	/* Configuration */
8652419Sjulian	struct		ng_async_stat	stats;	/* Statistics */
8752419Sjulian};
8853394Sarchietypedef struct ng_async_private *sc_p;
8952419Sjulian
9052419Sjulian/* Useful macros */
9152419Sjulian#define ASYNC_BUF_SIZE(smru)	(2 * (smru) + 10)
9252419Sjulian#define SYNC_BUF_SIZE(amru)	((amru) + 10)
9352419Sjulian#define ERROUT(x)		do { error = (x); goto done; } while (0)
9452419Sjulian
9552419Sjulian/* Netgraph methods */
9653913Sarchiestatic ng_constructor_t		nga_constructor;
9752752Sjulianstatic ng_rcvdata_t		nga_rcvdata;
9852752Sjulianstatic ng_rcvmsg_t		nga_rcvmsg;
9952752Sjulianstatic ng_shutdown_t		nga_shutdown;
10052752Sjulianstatic ng_newhook_t		nga_newhook;
10152752Sjulianstatic ng_disconnect_t		nga_disconnect;
10252419Sjulian
10352419Sjulian/* Helper stuff */
10470700Sjulianstatic int	nga_rcv_sync(const sc_p sc, item_p item);
10570700Sjulianstatic int	nga_rcv_async(const sc_p sc, item_p item);
10652419Sjulian
10753913Sarchie/* Parse type for struct ng_async_cfg */
10897685Sarchiestatic const struct ng_parse_struct_field nga_config_type_fields[]
10997685Sarchie	= NG_ASYNC_CONFIG_TYPE_INFO;
11053913Sarchiestatic const struct ng_parse_type nga_config_type = {
11153913Sarchie	&ng_parse_struct_type,
11297685Sarchie	&nga_config_type_fields
11353913Sarchie};
11453913Sarchie
11553913Sarchie/* Parse type for struct ng_async_stat */
11697685Sarchiestatic const struct ng_parse_struct_field nga_stats_type_fields[]
11797685Sarchie	= NG_ASYNC_STATS_TYPE_INFO;
11853913Sarchiestatic const struct ng_parse_type nga_stats_type = {
11953913Sarchie	&ng_parse_struct_type,
12097685Sarchie	&nga_stats_type_fields
12153913Sarchie};
12253913Sarchie
12353913Sarchie/* List of commands and how to convert arguments to/from ASCII */
12453913Sarchiestatic const struct ng_cmdlist nga_cmdlist[] = {
12553913Sarchie	{
12653913Sarchie	  NGM_ASYNC_COOKIE,
12753913Sarchie	  NGM_ASYNC_CMD_SET_CONFIG,
12853913Sarchie	  "setconfig",
12953913Sarchie	  &nga_config_type,
13053913Sarchie	  NULL
13153913Sarchie	},
13253913Sarchie	{
13353913Sarchie	  NGM_ASYNC_COOKIE,
13453913Sarchie	  NGM_ASYNC_CMD_GET_CONFIG,
13553913Sarchie	  "getconfig",
13653913Sarchie	  NULL,
13753913Sarchie	  &nga_config_type
13853913Sarchie	},
13953913Sarchie	{
14053913Sarchie	  NGM_ASYNC_COOKIE,
14153913Sarchie	  NGM_ASYNC_CMD_GET_STATS,
14253913Sarchie	  "getstats",
14353913Sarchie	  NULL,
14453913Sarchie	  &nga_stats_type
14553913Sarchie	},
14653913Sarchie	{
14753913Sarchie	  NGM_ASYNC_COOKIE,
14853913Sarchie	  NGM_ASYNC_CMD_CLR_STATS,
14953913Sarchie	  "clrstats",
15053913Sarchie	  &nga_stats_type,
15153913Sarchie	  NULL
15253913Sarchie	},
15353913Sarchie	{ 0 }
15453913Sarchie};
15553913Sarchie
15652419Sjulian/* Define the netgraph node type */
15752419Sjulianstatic struct ng_type typestruct = {
158129823Sjulian	.version =	NG_ABI_VERSION,
159129823Sjulian	.name =		NG_ASYNC_NODE_TYPE,
160129823Sjulian	.constructor =	nga_constructor,
161129823Sjulian	.rcvmsg =	nga_rcvmsg,
162129823Sjulian	.shutdown = 	nga_shutdown,
163129823Sjulian	.newhook =	nga_newhook,
164129823Sjulian	.rcvdata =	nga_rcvdata,
165129823Sjulian	.disconnect =	nga_disconnect,
166129823Sjulian	.cmdlist =	nga_cmdlist
16752419Sjulian};
16852419SjulianNETGRAPH_INIT(async, &typestruct);
16952419Sjulian
17052419Sjulian/* CRC table */
17152419Sjulianstatic const u_int16_t fcstab[];
17252419Sjulian
17352419Sjulian/******************************************************************
17452419Sjulian		    NETGRAPH NODE METHODS
17552419Sjulian******************************************************************/
17652419Sjulian
17752419Sjulian/*
17852419Sjulian * Initialize a new node
17952419Sjulian */
18052419Sjulianstatic int
18170700Sjuliannga_constructor(node_p node)
18252419Sjulian{
18352419Sjulian	sc_p sc;
18452419Sjulian
18570870Sjulian	MALLOC(sc, sc_p, sizeof(*sc), M_NETGRAPH_ASYNC, M_NOWAIT | M_ZERO);
18652419Sjulian	if (sc == NULL)
18752419Sjulian		return (ENOMEM);
18852419Sjulian	sc->amode = MODE_HUNT;
18952419Sjulian	sc->cfg.accm = ~0;
19052419Sjulian	sc->cfg.amru = NG_ASYNC_DEFAULT_MRU;
19152419Sjulian	sc->cfg.smru = NG_ASYNC_DEFAULT_MRU;
19252419Sjulian	MALLOC(sc->abuf, u_char *,
19370870Sjulian	    ASYNC_BUF_SIZE(sc->cfg.smru), M_NETGRAPH_ASYNC, M_NOWAIT);
19452419Sjulian	if (sc->abuf == NULL)
19552419Sjulian		goto fail;
19652419Sjulian	MALLOC(sc->sbuf, u_char *,
19770870Sjulian	    SYNC_BUF_SIZE(sc->cfg.amru), M_NETGRAPH_ASYNC, M_NOWAIT);
19852419Sjulian	if (sc->sbuf == NULL) {
19970870Sjulian		FREE(sc->abuf, M_NETGRAPH_ASYNC);
20052419Sjulianfail:
20170870Sjulian		FREE(sc, M_NETGRAPH_ASYNC);
20252419Sjulian		return (ENOMEM);
20352419Sjulian	}
20470784Sjulian	NG_NODE_SET_PRIVATE(node, sc);
20570700Sjulian	sc->node = node;
20652419Sjulian	return (0);
20752419Sjulian}
20852419Sjulian
20952419Sjulian/*
21052419Sjulian * Reserve a hook for a pending connection
21152419Sjulian */
21252419Sjulianstatic int
21352419Sjuliannga_newhook(node_p node, hook_p hook, const char *name)
21452419Sjulian{
21570784Sjulian	const sc_p sc = NG_NODE_PRIVATE(node);
21652419Sjulian	hook_p *hookp;
21752419Sjulian
21870700Sjulian	if (!strcmp(name, NG_ASYNC_HOOK_ASYNC)) {
21970700Sjulian		/*
22070700Sjulian		 * We use a static buffer here so only one packet
22170700Sjulian		 * at a time can be allowed to travel in this direction.
22270700Sjulian		 * Force Writer semantics.
22370700Sjulian		 */
22470784Sjulian		NG_HOOK_FORCE_WRITER(hook);
22552419Sjulian		hookp = &sc->async;
22670700Sjulian	} else if (!strcmp(name, NG_ASYNC_HOOK_SYNC)) {
22770700Sjulian		/*
22870700Sjulian		 * We use a static state here so only one packet
22970700Sjulian		 * at a time can be allowed to travel in this direction.
23070700Sjulian		 * Force Writer semantics.
23170700Sjulian		 * Since we set this for both directions
23270700Sjulian		 * we might as well set it for the whole node
23370700Sjulian		 * bit I haven;t done that (yet).
23470700Sjulian		 */
23570784Sjulian		NG_HOOK_FORCE_WRITER(hook);
23652419Sjulian		hookp = &sc->sync;
23770700Sjulian	} else {
23852419Sjulian		return (EINVAL);
23970700Sjulian	}
24070700Sjulian	if (*hookp) /* actually can't happen I think [JRE] */
24152419Sjulian		return (EISCONN);
24252419Sjulian	*hookp = hook;
24352419Sjulian	return (0);
24452419Sjulian}
24552419Sjulian
24652419Sjulian/*
24752419Sjulian * Receive incoming data
24852419Sjulian */
24952419Sjulianstatic int
25070700Sjuliannga_rcvdata(hook_p hook, item_p item)
25152419Sjulian{
25270784Sjulian	const sc_p sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
25352419Sjulian
25452419Sjulian	if (hook == sc->sync)
25570700Sjulian		return (nga_rcv_sync(sc, item));
25652976Sarchie	if (hook == sc->async)
25770700Sjulian		return (nga_rcv_async(sc, item));
25887599Sobrien	panic(__func__);
25952419Sjulian}
26052419Sjulian
26152419Sjulian/*
26252419Sjulian * Receive incoming control message
26352419Sjulian */
26452419Sjulianstatic int
26570700Sjuliannga_rcvmsg(node_p node, item_p item, hook_p lasthook)
26652419Sjulian{
26770784Sjulian	const sc_p sc = NG_NODE_PRIVATE(node);
26852419Sjulian	struct ng_mesg *resp = NULL;
26952419Sjulian	int error = 0;
27070700Sjulian	struct ng_mesg *msg;
27170700Sjulian
27270700Sjulian	NGI_GET_MSG(item, msg);
27352419Sjulian	switch (msg->header.typecookie) {
27452419Sjulian	case NGM_ASYNC_COOKIE:
27552419Sjulian		switch (msg->header.cmd) {
27652419Sjulian		case NGM_ASYNC_CMD_GET_STATS:
27752419Sjulian			NG_MKRESPONSE(resp, msg, sizeof(sc->stats), M_NOWAIT);
27852419Sjulian			if (resp == NULL)
27952419Sjulian				ERROUT(ENOMEM);
28052419Sjulian			*((struct ng_async_stat *) resp->data) = sc->stats;
28152419Sjulian			break;
28252419Sjulian		case NGM_ASYNC_CMD_CLR_STATS:
28352419Sjulian			bzero(&sc->stats, sizeof(sc->stats));
28452419Sjulian			break;
28552419Sjulian		case NGM_ASYNC_CMD_SET_CONFIG:
28652419Sjulian		    {
28752419Sjulian			struct ng_async_cfg *const cfg =
28852419Sjulian				(struct ng_async_cfg *) msg->data;
28952419Sjulian			u_char *buf;
29052419Sjulian
29152419Sjulian			if (msg->header.arglen != sizeof(*cfg))
29252419Sjulian				ERROUT(EINVAL);
29352419Sjulian			if (cfg->amru < NG_ASYNC_MIN_MRU
29452419Sjulian			    || cfg->amru > NG_ASYNC_MAX_MRU
29552419Sjulian			    || cfg->smru < NG_ASYNC_MIN_MRU
29652419Sjulian			    || cfg->smru > NG_ASYNC_MAX_MRU)
29752419Sjulian				ERROUT(EINVAL);
29852419Sjulian			cfg->enabled = !!cfg->enabled;	/* normalize */
29952419Sjulian			if (cfg->smru > sc->cfg.smru) {	/* reallocate buffer */
30052419Sjulian				MALLOC(buf, u_char *, ASYNC_BUF_SIZE(cfg->smru),
30170870Sjulian				    M_NETGRAPH_ASYNC, M_NOWAIT);
30252419Sjulian				if (!buf)
30352419Sjulian					ERROUT(ENOMEM);
30470870Sjulian				FREE(sc->abuf, M_NETGRAPH_ASYNC);
30552419Sjulian				sc->abuf = buf;
30652419Sjulian			}
30752419Sjulian			if (cfg->amru > sc->cfg.amru) {	/* reallocate buffer */
30852419Sjulian				MALLOC(buf, u_char *, SYNC_BUF_SIZE(cfg->amru),
30970870Sjulian				    M_NETGRAPH_ASYNC, M_NOWAIT);
31052419Sjulian				if (!buf)
31152419Sjulian					ERROUT(ENOMEM);
31270870Sjulian				FREE(sc->sbuf, M_NETGRAPH_ASYNC);
31352419Sjulian				sc->sbuf = buf;
31452419Sjulian				sc->amode = MODE_HUNT;
31552419Sjulian				sc->slen = 0;
31652419Sjulian			}
31752419Sjulian			if (!cfg->enabled) {
31852419Sjulian				sc->amode = MODE_HUNT;
31952419Sjulian				sc->slen = 0;
32052419Sjulian			}
32152419Sjulian			sc->cfg = *cfg;
32252419Sjulian			break;
32352419Sjulian		    }
32452419Sjulian		case NGM_ASYNC_CMD_GET_CONFIG:
32552419Sjulian			NG_MKRESPONSE(resp, msg, sizeof(sc->cfg), M_NOWAIT);
32652419Sjulian			if (!resp)
32752419Sjulian				ERROUT(ENOMEM);
32852419Sjulian			*((struct ng_async_cfg *) resp->data) = sc->cfg;
32952419Sjulian			break;
33052419Sjulian		default:
33152419Sjulian			ERROUT(EINVAL);
33252419Sjulian		}
33352419Sjulian		break;
33452419Sjulian	default:
33552419Sjulian		ERROUT(EINVAL);
33652419Sjulian	}
33752419Sjuliandone:
33870700Sjulian	NG_RESPOND_MSG(error, node, item, resp);
33970700Sjulian	NG_FREE_MSG(msg);
34052419Sjulian	return (error);
34152419Sjulian}
34252419Sjulian
34352419Sjulian/*
34452419Sjulian * Shutdown this node
34552419Sjulian */
34652419Sjulianstatic int
34752419Sjuliannga_shutdown(node_p node)
34852419Sjulian{
34970784Sjulian	const sc_p sc = NG_NODE_PRIVATE(node);
35052419Sjulian
35170870Sjulian	FREE(sc->abuf, M_NETGRAPH_ASYNC);
35270870Sjulian	FREE(sc->sbuf, M_NETGRAPH_ASYNC);
35352419Sjulian	bzero(sc, sizeof(*sc));
35470870Sjulian	FREE(sc, M_NETGRAPH_ASYNC);
35570784Sjulian	NG_NODE_SET_PRIVATE(node, NULL);
35670784Sjulian	NG_NODE_UNREF(node);
35752419Sjulian	return (0);
35852419Sjulian}
35952419Sjulian
36052419Sjulian/*
36152419Sjulian * Lose a hook. When both hooks go away, we disappear.
36252419Sjulian */
36352419Sjulianstatic int
36452419Sjuliannga_disconnect(hook_p hook)
36552419Sjulian{
36670784Sjulian	const sc_p sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
36752419Sjulian	hook_p *hookp;
36852419Sjulian
36952419Sjulian	if (hook == sc->async)
37052419Sjulian		hookp = &sc->async;
37152419Sjulian	else if (hook == sc->sync)
37252419Sjulian		hookp = &sc->sync;
37352419Sjulian	else
37487599Sobrien		panic(__func__);
37552419Sjulian	if (!*hookp)
37687599Sobrien		panic("%s 2", __func__);
37752419Sjulian	*hookp = NULL;
37852419Sjulian	bzero(&sc->stats, sizeof(sc->stats));
37952419Sjulian	sc->lasttime = 0;
38070784Sjulian	if ((NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0)
38170784Sjulian	&& (NG_NODE_IS_VALID(NG_HOOK_NODE(hook))))
38270784Sjulian		ng_rmnode_self(NG_HOOK_NODE(hook));
38352419Sjulian	return (0);
38452419Sjulian}
38552419Sjulian
38652419Sjulian/******************************************************************
38752419Sjulian		    INTERNAL HELPER STUFF
38852419Sjulian******************************************************************/
38952419Sjulian
39052419Sjulian/*
39152419Sjulian * Encode a byte into the async buffer
39252419Sjulian */
39352419Sjulianstatic __inline__ void
39452419Sjuliannga_async_add(const sc_p sc, u_int16_t *fcs, u_int32_t accm, int *len, u_char x)
39552419Sjulian{
39652419Sjulian	*fcs = PPP_FCS(*fcs, x);
39752419Sjulian	if ((x < 32 && ((1 << x) & accm))
39852419Sjulian	    || (x == PPP_ESCAPE)
39952419Sjulian	    || (x == PPP_FLAG)) {
40052419Sjulian		sc->abuf[(*len)++] = PPP_ESCAPE;
40152419Sjulian		x ^= PPP_TRANS;
40252419Sjulian	}
40352419Sjulian	sc->abuf[(*len)++] = x;
40452419Sjulian}
40552419Sjulian
40652419Sjulian/*
40752976Sarchie * Receive incoming synchronous data.
40852419Sjulian */
40952419Sjulianstatic int
41070700Sjuliannga_rcv_sync(const sc_p sc, item_p item)
41152419Sjulian{
41270700Sjulian	struct ifnet *rcvif;
41353394Sarchie	int alen, error = 0;
41452976Sarchie	struct timeval time;
41552419Sjulian	u_int16_t fcs, fcs0;
41652976Sarchie	u_int32_t accm;
41770700Sjulian	struct mbuf *m;
41852419Sjulian
41970700Sjulian
42052976Sarchie#define ADD_BYTE(x)	nga_async_add(sc, &fcs, accm, &alen, (x))
42152419Sjulian
42252976Sarchie	/* Check for bypass mode */
42352419Sjulian	if (!sc->cfg.enabled) {
42470784Sjulian		NG_FWD_ITEM_HOOK(error, item, sc->async );
42552419Sjulian		return (error);
42652419Sjulian	}
42770700Sjulian	NGI_GET_M(item, m);
42852976Sarchie
42970700Sjulian	rcvif = m->m_pkthdr.rcvif;
43070700Sjulian
43153394Sarchie	/* Get ACCM; special case LCP frames, which use full ACCM */
43252976Sarchie	accm = sc->cfg.accm;
43353394Sarchie	if (m->m_pkthdr.len >= 4) {
43453394Sarchie		static const u_char lcphdr[4] = {
43553394Sarchie		    PPP_ALLSTATIONS,
43653394Sarchie		    PPP_UI,
43753394Sarchie		    (u_char)(PPP_LCP >> 8),
43853394Sarchie		    (u_char)(PPP_LCP & 0xff)
43953394Sarchie		};
44053394Sarchie		u_char buf[4];
44152976Sarchie
44253394Sarchie		m_copydata(m, 0, 4, (caddr_t)buf);
44353394Sarchie		if (bcmp(buf, &lcphdr, 4) == 0)
44452976Sarchie			accm = ~0;
44552976Sarchie	}
44652976Sarchie
44752976Sarchie	/* Check for overflow */
44852419Sjulian	if (m->m_pkthdr.len > sc->cfg.smru) {
44952419Sjulian		sc->stats.syncOverflows++;
45070700Sjulian		NG_FREE_M(m);
45170700Sjulian		NG_FREE_ITEM(item);
45252419Sjulian		return (EMSGSIZE);
45352419Sjulian	}
45452976Sarchie
45552976Sarchie	/* Update stats */
45652419Sjulian	sc->stats.syncFrames++;
45752419Sjulian	sc->stats.syncOctets += m->m_pkthdr.len;
45852419Sjulian
45952419Sjulian	/* Initialize async encoded version of input mbuf */
46052419Sjulian	alen = 0;
46152419Sjulian	fcs = PPP_INITFCS;
46252419Sjulian
46352419Sjulian	/* Add beginning sync flag if it's been long enough to need one */
46452976Sarchie	getmicrotime(&time);
46552976Sarchie	if (time.tv_sec >= sc->lasttime + 1) {
46652976Sarchie		sc->abuf[alen++] = PPP_FLAG;
46752976Sarchie		sc->lasttime = time.tv_sec;
46852419Sjulian	}
46952419Sjulian
47053394Sarchie	/* Add packet payload */
47152976Sarchie	while (m != NULL) {
47252419Sjulian		while (m->m_len > 0) {
47352976Sarchie			ADD_BYTE(*mtod(m, u_char *));
47452419Sjulian			m->m_data++;
47552419Sjulian			m->m_len--;
47652419Sjulian		}
47790227Sdillon		m = m_free(m);
47852419Sjulian	}
47952419Sjulian
48052419Sjulian	/* Add checksum and final sync flag */
48152419Sjulian	fcs0 = fcs;
48252419Sjulian	ADD_BYTE(~fcs0 & 0xff);
48352419Sjulian	ADD_BYTE(~fcs0 >> 8);
48452419Sjulian	sc->abuf[alen++] = PPP_FLAG;
48552419Sjulian
48652419Sjulian	/* Put frame in an mbuf and ship it off */
48752976Sarchie	if (!(m = m_devget(sc->abuf, alen, 0, rcvif, NULL))) {
48870700Sjulian		NG_FREE_ITEM(item);
48952419Sjulian		error = ENOBUFS;
49070700Sjulian	} else {
49170700Sjulian		NG_FWD_NEW_DATA(error, item, sc->async, m);
49270700Sjulian	}
49352419Sjulian	return (error);
49452419Sjulian}
49552419Sjulian
49652419Sjulian/*
49752419Sjulian * Receive incoming asynchronous data
49852976Sarchie * XXX Technically, we should strip out incoming characters
49952976Sarchie *     that are in our ACCM. Not sure if this is good or not.
50052419Sjulian */
50152419Sjulianstatic int
50270700Sjuliannga_rcv_async(const sc_p sc, item_p item)
50352419Sjulian{
50470700Sjulian	struct ifnet *rcvif;
50552419Sjulian	int error;
50670700Sjulian	struct mbuf *m;
50752419Sjulian
50852419Sjulian	if (!sc->cfg.enabled) {
50970784Sjulian		NG_FWD_ITEM_HOOK(error, item,  sc->sync);
51052419Sjulian		return (error);
51152419Sjulian	}
51270700Sjulian	NGI_GET_M(item, m);
51370700Sjulian	rcvif = m->m_pkthdr.rcvif;
51452419Sjulian	while (m) {
51552419Sjulian		struct mbuf *n;
51652419Sjulian
51752419Sjulian		for (; m->m_len > 0; m->m_data++, m->m_len--) {
51852419Sjulian			u_char  ch = *mtod(m, u_char *);
51952419Sjulian
52052419Sjulian			sc->stats.asyncOctets++;
52152419Sjulian			if (ch == PPP_FLAG) {	/* Flag overrides everything */
52252419Sjulian				int     skip = 0;
52352419Sjulian
52452419Sjulian				/* Check for runts */
52552419Sjulian				if (sc->slen < 2) {
52652419Sjulian					if (sc->slen > 0)
52752419Sjulian						sc->stats.asyncRunts++;
52852419Sjulian					goto reset;
52952419Sjulian				}
53052419Sjulian
53152419Sjulian				/* Verify CRC */
53252419Sjulian				if (sc->fcs != PPP_GOODFCS) {
53352419Sjulian					sc->stats.asyncBadCheckSums++;
53452419Sjulian					goto reset;
53552419Sjulian				}
53652419Sjulian				sc->slen -= 2;
53752419Sjulian
53852419Sjulian				/* Strip address and control fields */
53952419Sjulian				if (sc->slen >= 2
54052419Sjulian				    && sc->sbuf[0] == PPP_ALLSTATIONS
54152419Sjulian				    && sc->sbuf[1] == PPP_UI)
54252419Sjulian					skip = 2;
54352419Sjulian
54452419Sjulian				/* Check for frame too big */
54552419Sjulian				if (sc->slen - skip > sc->cfg.amru) {
54652419Sjulian					sc->stats.asyncOverflows++;
54752419Sjulian					goto reset;
54852419Sjulian				}
54952419Sjulian
55052419Sjulian				/* OK, ship it out */
55152419Sjulian				if ((n = m_devget(sc->sbuf + skip,
55270700Sjulian					   sc->slen - skip, 0, rcvif, NULL))) {
55370700Sjulian					if (item) { /* sets NULL -> item */
55470700Sjulian						NG_FWD_NEW_DATA(error, item,
55570700Sjulian							sc->sync, n);
55670700Sjulian					} else {
55770700Sjulian						NG_SEND_DATA_ONLY(error,
55870700Sjulian							sc->sync ,n);
55970700Sjulian					}
56070700Sjulian				}
56152419Sjulian				sc->stats.asyncFrames++;
56252419Sjulianreset:
56352419Sjulian				sc->amode = MODE_NORMAL;
56452419Sjulian				sc->fcs = PPP_INITFCS;
56552419Sjulian				sc->slen = 0;
56652419Sjulian				continue;
56752419Sjulian			}
56852419Sjulian			switch (sc->amode) {
56952419Sjulian			case MODE_NORMAL:
57052419Sjulian				if (ch == PPP_ESCAPE) {
57152419Sjulian					sc->amode = MODE_ESC;
57252419Sjulian					continue;
57352419Sjulian				}
57452419Sjulian				break;
57552419Sjulian			case MODE_ESC:
57652419Sjulian				ch ^= PPP_TRANS;
57752419Sjulian				sc->amode = MODE_NORMAL;
57852419Sjulian				break;
57952419Sjulian			case MODE_HUNT:
58052419Sjulian			default:
58152419Sjulian				continue;
58252419Sjulian			}
58352419Sjulian
58452419Sjulian			/* Add byte to frame */
58552419Sjulian			if (sc->slen >= SYNC_BUF_SIZE(sc->cfg.amru)) {
58652419Sjulian				sc->stats.asyncOverflows++;
58752419Sjulian				sc->amode = MODE_HUNT;
58852419Sjulian				sc->slen = 0;
58952419Sjulian			} else {
59052419Sjulian				sc->sbuf[sc->slen++] = ch;
59152419Sjulian				sc->fcs = PPP_FCS(sc->fcs, ch);
59252419Sjulian			}
59352419Sjulian		}
59490227Sdillon		m = m_free(m);
59552419Sjulian	}
59670700Sjulian	if (item)
59770700Sjulian		NG_FREE_ITEM(item);
59852419Sjulian	return (0);
59952419Sjulian}
60052419Sjulian
60152419Sjulian/*
60252419Sjulian * CRC table
60352419Sjulian *
60452419Sjulian * Taken from RFC 1171 Appendix B
60552419Sjulian */
60652419Sjulianstatic const u_int16_t fcstab[256] = {
60752419Sjulian	 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
60852419Sjulian	 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
60952419Sjulian	 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
61052419Sjulian	 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
61152419Sjulian	 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
61252419Sjulian	 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
61352419Sjulian	 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
61452419Sjulian	 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
61552419Sjulian	 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
61652419Sjulian	 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
61752419Sjulian	 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
61852419Sjulian	 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
61952419Sjulian	 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
62052419Sjulian	 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
62152419Sjulian	 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
62252419Sjulian	 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
62352419Sjulian	 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
62452419Sjulian	 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
62552419Sjulian	 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
62652419Sjulian	 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
62752419Sjulian	 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
62852419Sjulian	 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
62952419Sjulian	 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
63052419Sjulian	 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
63152419Sjulian	 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
63252419Sjulian	 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
63352419Sjulian	 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
63452419Sjulian	 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
63552419Sjulian	 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
63652419Sjulian	 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
63752419Sjulian	 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
63852419Sjulian	 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
63952419Sjulian};
640