ng_async.c revision 90227
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 90227 2002-02-05 02:00:56Z dillon $
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 */
10853913Sarchiestatic const struct ng_parse_struct_info
10953913Sarchie	nga_config_type_info = NG_ASYNC_CONFIG_TYPE_INFO;
11053913Sarchiestatic const struct ng_parse_type nga_config_type = {
11153913Sarchie	&ng_parse_struct_type,
11253913Sarchie	&nga_config_type_info
11353913Sarchie};
11453913Sarchie
11553913Sarchie/* Parse type for struct ng_async_stat */
11653913Sarchiestatic const struct ng_parse_struct_info
11753913Sarchie	nga_stats_type_info = NG_ASYNC_STATS_TYPE_INFO;
11853913Sarchiestatic const struct ng_parse_type nga_stats_type = {
11953913Sarchie	&ng_parse_struct_type,
12053913Sarchie	&nga_stats_type_info,
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 = {
15870159Sjulian	NG_ABI_VERSION,
15952419Sjulian	NG_ASYNC_NODE_TYPE,
16052419Sjulian	NULL,
16152419Sjulian	nga_constructor,
16252419Sjulian	nga_rcvmsg,
16352419Sjulian	nga_shutdown,
16452419Sjulian	nga_newhook,
16552419Sjulian	NULL,
16652419Sjulian	NULL,
16752419Sjulian	nga_rcvdata,
16853913Sarchie	nga_disconnect,
16953913Sarchie	nga_cmdlist
17052419Sjulian};
17152419SjulianNETGRAPH_INIT(async, &typestruct);
17252419Sjulian
17352419Sjulian/* CRC table */
17452419Sjulianstatic const u_int16_t fcstab[];
17552419Sjulian
17652419Sjulian/******************************************************************
17752419Sjulian		    NETGRAPH NODE METHODS
17852419Sjulian******************************************************************/
17952419Sjulian
18052419Sjulian/*
18152419Sjulian * Initialize a new node
18252419Sjulian */
18352419Sjulianstatic int
18470700Sjuliannga_constructor(node_p node)
18552419Sjulian{
18652419Sjulian	sc_p sc;
18752419Sjulian
18870870Sjulian	MALLOC(sc, sc_p, sizeof(*sc), M_NETGRAPH_ASYNC, M_NOWAIT | M_ZERO);
18952419Sjulian	if (sc == NULL)
19052419Sjulian		return (ENOMEM);
19152419Sjulian	sc->amode = MODE_HUNT;
19252419Sjulian	sc->cfg.accm = ~0;
19352419Sjulian	sc->cfg.amru = NG_ASYNC_DEFAULT_MRU;
19452419Sjulian	sc->cfg.smru = NG_ASYNC_DEFAULT_MRU;
19552419Sjulian	MALLOC(sc->abuf, u_char *,
19670870Sjulian	    ASYNC_BUF_SIZE(sc->cfg.smru), M_NETGRAPH_ASYNC, M_NOWAIT);
19752419Sjulian	if (sc->abuf == NULL)
19852419Sjulian		goto fail;
19952419Sjulian	MALLOC(sc->sbuf, u_char *,
20070870Sjulian	    SYNC_BUF_SIZE(sc->cfg.amru), M_NETGRAPH_ASYNC, M_NOWAIT);
20152419Sjulian	if (sc->sbuf == NULL) {
20270870Sjulian		FREE(sc->abuf, M_NETGRAPH_ASYNC);
20352419Sjulianfail:
20470870Sjulian		FREE(sc, M_NETGRAPH_ASYNC);
20552419Sjulian		return (ENOMEM);
20652419Sjulian	}
20770784Sjulian	NG_NODE_SET_PRIVATE(node, sc);
20870700Sjulian	sc->node = node;
20952419Sjulian	return (0);
21052419Sjulian}
21152419Sjulian
21252419Sjulian/*
21352419Sjulian * Reserve a hook for a pending connection
21452419Sjulian */
21552419Sjulianstatic int
21652419Sjuliannga_newhook(node_p node, hook_p hook, const char *name)
21752419Sjulian{
21870784Sjulian	const sc_p sc = NG_NODE_PRIVATE(node);
21952419Sjulian	hook_p *hookp;
22052419Sjulian
22170700Sjulian	if (!strcmp(name, NG_ASYNC_HOOK_ASYNC)) {
22270700Sjulian		/*
22370700Sjulian		 * We use a static buffer here so only one packet
22470700Sjulian		 * at a time can be allowed to travel in this direction.
22570700Sjulian		 * Force Writer semantics.
22670700Sjulian		 */
22770784Sjulian		NG_HOOK_FORCE_WRITER(hook);
22852419Sjulian		hookp = &sc->async;
22970700Sjulian	} else if (!strcmp(name, NG_ASYNC_HOOK_SYNC)) {
23070700Sjulian		/*
23170700Sjulian		 * We use a static state here so only one packet
23270700Sjulian		 * at a time can be allowed to travel in this direction.
23370700Sjulian		 * Force Writer semantics.
23470700Sjulian		 * Since we set this for both directions
23570700Sjulian		 * we might as well set it for the whole node
23670700Sjulian		 * bit I haven;t done that (yet).
23770700Sjulian		 */
23870784Sjulian		NG_HOOK_FORCE_WRITER(hook);
23952419Sjulian		hookp = &sc->sync;
24070700Sjulian	} else {
24152419Sjulian		return (EINVAL);
24270700Sjulian	}
24370700Sjulian	if (*hookp) /* actually can't happen I think [JRE] */
24452419Sjulian		return (EISCONN);
24552419Sjulian	*hookp = hook;
24652419Sjulian	return (0);
24752419Sjulian}
24852419Sjulian
24952419Sjulian/*
25052419Sjulian * Receive incoming data
25152419Sjulian */
25252419Sjulianstatic int
25370700Sjuliannga_rcvdata(hook_p hook, item_p item)
25452419Sjulian{
25570784Sjulian	const sc_p sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
25652419Sjulian
25752419Sjulian	if (hook == sc->sync)
25870700Sjulian		return (nga_rcv_sync(sc, item));
25952976Sarchie	if (hook == sc->async)
26070700Sjulian		return (nga_rcv_async(sc, item));
26187599Sobrien	panic(__func__);
26252419Sjulian}
26352419Sjulian
26452419Sjulian/*
26552419Sjulian * Receive incoming control message
26652419Sjulian */
26752419Sjulianstatic int
26870700Sjuliannga_rcvmsg(node_p node, item_p item, hook_p lasthook)
26952419Sjulian{
27070784Sjulian	const sc_p sc = NG_NODE_PRIVATE(node);
27152419Sjulian	struct ng_mesg *resp = NULL;
27252419Sjulian	int error = 0;
27370700Sjulian	struct ng_mesg *msg;
27470700Sjulian
27570700Sjulian	NGI_GET_MSG(item, msg);
27652419Sjulian	switch (msg->header.typecookie) {
27752419Sjulian	case NGM_ASYNC_COOKIE:
27852419Sjulian		switch (msg->header.cmd) {
27952419Sjulian		case NGM_ASYNC_CMD_GET_STATS:
28052419Sjulian			NG_MKRESPONSE(resp, msg, sizeof(sc->stats), M_NOWAIT);
28152419Sjulian			if (resp == NULL)
28252419Sjulian				ERROUT(ENOMEM);
28352419Sjulian			*((struct ng_async_stat *) resp->data) = sc->stats;
28452419Sjulian			break;
28552419Sjulian		case NGM_ASYNC_CMD_CLR_STATS:
28652419Sjulian			bzero(&sc->stats, sizeof(sc->stats));
28752419Sjulian			break;
28852419Sjulian		case NGM_ASYNC_CMD_SET_CONFIG:
28952419Sjulian		    {
29052419Sjulian			struct ng_async_cfg *const cfg =
29152419Sjulian				(struct ng_async_cfg *) msg->data;
29252419Sjulian			u_char *buf;
29352419Sjulian
29452419Sjulian			if (msg->header.arglen != sizeof(*cfg))
29552419Sjulian				ERROUT(EINVAL);
29652419Sjulian			if (cfg->amru < NG_ASYNC_MIN_MRU
29752419Sjulian			    || cfg->amru > NG_ASYNC_MAX_MRU
29852419Sjulian			    || cfg->smru < NG_ASYNC_MIN_MRU
29952419Sjulian			    || cfg->smru > NG_ASYNC_MAX_MRU)
30052419Sjulian				ERROUT(EINVAL);
30152419Sjulian			cfg->enabled = !!cfg->enabled;	/* normalize */
30252419Sjulian			if (cfg->smru > sc->cfg.smru) {	/* reallocate buffer */
30352419Sjulian				MALLOC(buf, u_char *, ASYNC_BUF_SIZE(cfg->smru),
30470870Sjulian				    M_NETGRAPH_ASYNC, M_NOWAIT);
30552419Sjulian				if (!buf)
30652419Sjulian					ERROUT(ENOMEM);
30770870Sjulian				FREE(sc->abuf, M_NETGRAPH_ASYNC);
30852419Sjulian				sc->abuf = buf;
30952419Sjulian			}
31052419Sjulian			if (cfg->amru > sc->cfg.amru) {	/* reallocate buffer */
31152419Sjulian				MALLOC(buf, u_char *, SYNC_BUF_SIZE(cfg->amru),
31270870Sjulian				    M_NETGRAPH_ASYNC, M_NOWAIT);
31352419Sjulian				if (!buf)
31452419Sjulian					ERROUT(ENOMEM);
31570870Sjulian				FREE(sc->sbuf, M_NETGRAPH_ASYNC);
31652419Sjulian				sc->sbuf = buf;
31752419Sjulian				sc->amode = MODE_HUNT;
31852419Sjulian				sc->slen = 0;
31952419Sjulian			}
32052419Sjulian			if (!cfg->enabled) {
32152419Sjulian				sc->amode = MODE_HUNT;
32252419Sjulian				sc->slen = 0;
32352419Sjulian			}
32452419Sjulian			sc->cfg = *cfg;
32552419Sjulian			break;
32652419Sjulian		    }
32752419Sjulian		case NGM_ASYNC_CMD_GET_CONFIG:
32852419Sjulian			NG_MKRESPONSE(resp, msg, sizeof(sc->cfg), M_NOWAIT);
32952419Sjulian			if (!resp)
33052419Sjulian				ERROUT(ENOMEM);
33152419Sjulian			*((struct ng_async_cfg *) resp->data) = sc->cfg;
33252419Sjulian			break;
33352419Sjulian		default:
33452419Sjulian			ERROUT(EINVAL);
33552419Sjulian		}
33652419Sjulian		break;
33752419Sjulian	default:
33852419Sjulian		ERROUT(EINVAL);
33952419Sjulian	}
34052419Sjuliandone:
34170700Sjulian	NG_RESPOND_MSG(error, node, item, resp);
34270700Sjulian	NG_FREE_MSG(msg);
34352419Sjulian	return (error);
34452419Sjulian}
34552419Sjulian
34652419Sjulian/*
34752419Sjulian * Shutdown this node
34852419Sjulian */
34952419Sjulianstatic int
35052419Sjuliannga_shutdown(node_p node)
35152419Sjulian{
35270784Sjulian	const sc_p sc = NG_NODE_PRIVATE(node);
35352419Sjulian
35470870Sjulian	FREE(sc->abuf, M_NETGRAPH_ASYNC);
35570870Sjulian	FREE(sc->sbuf, M_NETGRAPH_ASYNC);
35652419Sjulian	bzero(sc, sizeof(*sc));
35770870Sjulian	FREE(sc, M_NETGRAPH_ASYNC);
35870784Sjulian	NG_NODE_SET_PRIVATE(node, NULL);
35970784Sjulian	NG_NODE_UNREF(node);
36052419Sjulian	return (0);
36152419Sjulian}
36252419Sjulian
36352419Sjulian/*
36452419Sjulian * Lose a hook. When both hooks go away, we disappear.
36552419Sjulian */
36652419Sjulianstatic int
36752419Sjuliannga_disconnect(hook_p hook)
36852419Sjulian{
36970784Sjulian	const sc_p sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
37052419Sjulian	hook_p *hookp;
37152419Sjulian
37252419Sjulian	if (hook == sc->async)
37352419Sjulian		hookp = &sc->async;
37452419Sjulian	else if (hook == sc->sync)
37552419Sjulian		hookp = &sc->sync;
37652419Sjulian	else
37787599Sobrien		panic(__func__);
37852419Sjulian	if (!*hookp)
37987599Sobrien		panic("%s 2", __func__);
38052419Sjulian	*hookp = NULL;
38152419Sjulian	bzero(&sc->stats, sizeof(sc->stats));
38252419Sjulian	sc->lasttime = 0;
38370784Sjulian	if ((NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0)
38470784Sjulian	&& (NG_NODE_IS_VALID(NG_HOOK_NODE(hook))))
38570784Sjulian		ng_rmnode_self(NG_HOOK_NODE(hook));
38652419Sjulian	return (0);
38752419Sjulian}
38852419Sjulian
38952419Sjulian/******************************************************************
39052419Sjulian		    INTERNAL HELPER STUFF
39152419Sjulian******************************************************************/
39252419Sjulian
39352419Sjulian/*
39452419Sjulian * Encode a byte into the async buffer
39552419Sjulian */
39652419Sjulianstatic __inline__ void
39752419Sjuliannga_async_add(const sc_p sc, u_int16_t *fcs, u_int32_t accm, int *len, u_char x)
39852419Sjulian{
39952419Sjulian	*fcs = PPP_FCS(*fcs, x);
40052419Sjulian	if ((x < 32 && ((1 << x) & accm))
40152419Sjulian	    || (x == PPP_ESCAPE)
40252419Sjulian	    || (x == PPP_FLAG)) {
40352419Sjulian		sc->abuf[(*len)++] = PPP_ESCAPE;
40452419Sjulian		x ^= PPP_TRANS;
40552419Sjulian	}
40652419Sjulian	sc->abuf[(*len)++] = x;
40752419Sjulian}
40852419Sjulian
40952419Sjulian/*
41052976Sarchie * Receive incoming synchronous data.
41152419Sjulian */
41252419Sjulianstatic int
41370700Sjuliannga_rcv_sync(const sc_p sc, item_p item)
41452419Sjulian{
41570700Sjulian	struct ifnet *rcvif;
41653394Sarchie	int alen, error = 0;
41752976Sarchie	struct timeval time;
41852419Sjulian	u_int16_t fcs, fcs0;
41952976Sarchie	u_int32_t accm;
42070700Sjulian	struct mbuf *m;
42152419Sjulian
42270700Sjulian
42352976Sarchie#define ADD_BYTE(x)	nga_async_add(sc, &fcs, accm, &alen, (x))
42452419Sjulian
42552976Sarchie	/* Check for bypass mode */
42652419Sjulian	if (!sc->cfg.enabled) {
42770784Sjulian		NG_FWD_ITEM_HOOK(error, item, sc->async );
42852419Sjulian		return (error);
42952419Sjulian	}
43070700Sjulian	NGI_GET_M(item, m);
43152976Sarchie
43270700Sjulian	rcvif = m->m_pkthdr.rcvif;
43370700Sjulian
43453394Sarchie	/* Get ACCM; special case LCP frames, which use full ACCM */
43552976Sarchie	accm = sc->cfg.accm;
43653394Sarchie	if (m->m_pkthdr.len >= 4) {
43753394Sarchie		static const u_char lcphdr[4] = {
43853394Sarchie		    PPP_ALLSTATIONS,
43953394Sarchie		    PPP_UI,
44053394Sarchie		    (u_char)(PPP_LCP >> 8),
44153394Sarchie		    (u_char)(PPP_LCP & 0xff)
44253394Sarchie		};
44353394Sarchie		u_char buf[4];
44452976Sarchie
44553394Sarchie		m_copydata(m, 0, 4, (caddr_t)buf);
44653394Sarchie		if (bcmp(buf, &lcphdr, 4) == 0)
44752976Sarchie			accm = ~0;
44852976Sarchie	}
44952976Sarchie
45052976Sarchie	/* Check for overflow */
45152419Sjulian	if (m->m_pkthdr.len > sc->cfg.smru) {
45252419Sjulian		sc->stats.syncOverflows++;
45370700Sjulian		NG_FREE_M(m);
45470700Sjulian		NG_FREE_ITEM(item);
45552419Sjulian		return (EMSGSIZE);
45652419Sjulian	}
45752976Sarchie
45852976Sarchie	/* Update stats */
45952419Sjulian	sc->stats.syncFrames++;
46052419Sjulian	sc->stats.syncOctets += m->m_pkthdr.len;
46152419Sjulian
46252419Sjulian	/* Initialize async encoded version of input mbuf */
46352419Sjulian	alen = 0;
46452419Sjulian	fcs = PPP_INITFCS;
46552419Sjulian
46652419Sjulian	/* Add beginning sync flag if it's been long enough to need one */
46752976Sarchie	getmicrotime(&time);
46852976Sarchie	if (time.tv_sec >= sc->lasttime + 1) {
46952976Sarchie		sc->abuf[alen++] = PPP_FLAG;
47052976Sarchie		sc->lasttime = time.tv_sec;
47152419Sjulian	}
47252419Sjulian
47353394Sarchie	/* Add packet payload */
47452976Sarchie	while (m != NULL) {
47552419Sjulian		while (m->m_len > 0) {
47652976Sarchie			ADD_BYTE(*mtod(m, u_char *));
47752419Sjulian			m->m_data++;
47852419Sjulian			m->m_len--;
47952419Sjulian		}
48090227Sdillon		m = m_free(m);
48152419Sjulian	}
48252419Sjulian
48352419Sjulian	/* Add checksum and final sync flag */
48452419Sjulian	fcs0 = fcs;
48552419Sjulian	ADD_BYTE(~fcs0 & 0xff);
48652419Sjulian	ADD_BYTE(~fcs0 >> 8);
48752419Sjulian	sc->abuf[alen++] = PPP_FLAG;
48852419Sjulian
48952419Sjulian	/* Put frame in an mbuf and ship it off */
49052976Sarchie	if (!(m = m_devget(sc->abuf, alen, 0, rcvif, NULL))) {
49170700Sjulian		NG_FREE_ITEM(item);
49252419Sjulian		error = ENOBUFS;
49370700Sjulian	} else {
49470700Sjulian		NG_FWD_NEW_DATA(error, item, sc->async, m);
49570700Sjulian	}
49652419Sjulian	return (error);
49752419Sjulian}
49852419Sjulian
49952419Sjulian/*
50052419Sjulian * Receive incoming asynchronous data
50152976Sarchie * XXX Technically, we should strip out incoming characters
50252976Sarchie *     that are in our ACCM. Not sure if this is good or not.
50352419Sjulian */
50452419Sjulianstatic int
50570700Sjuliannga_rcv_async(const sc_p sc, item_p item)
50652419Sjulian{
50770700Sjulian	struct ifnet *rcvif;
50852419Sjulian	int error;
50970700Sjulian	struct mbuf *m;
51052419Sjulian
51152419Sjulian	if (!sc->cfg.enabled) {
51270784Sjulian		NG_FWD_ITEM_HOOK(error, item,  sc->sync);
51352419Sjulian		return (error);
51452419Sjulian	}
51570700Sjulian	NGI_GET_M(item, m);
51670700Sjulian	rcvif = m->m_pkthdr.rcvif;
51752419Sjulian	while (m) {
51852419Sjulian		struct mbuf *n;
51952419Sjulian
52052419Sjulian		for (; m->m_len > 0; m->m_data++, m->m_len--) {
52152419Sjulian			u_char  ch = *mtod(m, u_char *);
52252419Sjulian
52352419Sjulian			sc->stats.asyncOctets++;
52452419Sjulian			if (ch == PPP_FLAG) {	/* Flag overrides everything */
52552419Sjulian				int     skip = 0;
52652419Sjulian
52752419Sjulian				/* Check for runts */
52852419Sjulian				if (sc->slen < 2) {
52952419Sjulian					if (sc->slen > 0)
53052419Sjulian						sc->stats.asyncRunts++;
53152419Sjulian					goto reset;
53252419Sjulian				}
53352419Sjulian
53452419Sjulian				/* Verify CRC */
53552419Sjulian				if (sc->fcs != PPP_GOODFCS) {
53652419Sjulian					sc->stats.asyncBadCheckSums++;
53752419Sjulian					goto reset;
53852419Sjulian				}
53952419Sjulian				sc->slen -= 2;
54052419Sjulian
54152419Sjulian				/* Strip address and control fields */
54252419Sjulian				if (sc->slen >= 2
54352419Sjulian				    && sc->sbuf[0] == PPP_ALLSTATIONS
54452419Sjulian				    && sc->sbuf[1] == PPP_UI)
54552419Sjulian					skip = 2;
54652419Sjulian
54752419Sjulian				/* Check for frame too big */
54852419Sjulian				if (sc->slen - skip > sc->cfg.amru) {
54952419Sjulian					sc->stats.asyncOverflows++;
55052419Sjulian					goto reset;
55152419Sjulian				}
55252419Sjulian
55352419Sjulian				/* OK, ship it out */
55452419Sjulian				if ((n = m_devget(sc->sbuf + skip,
55570700Sjulian					   sc->slen - skip, 0, rcvif, NULL))) {
55670700Sjulian					if (item) { /* sets NULL -> item */
55770700Sjulian						NG_FWD_NEW_DATA(error, item,
55870700Sjulian							sc->sync, n);
55970700Sjulian					} else {
56070700Sjulian						NG_SEND_DATA_ONLY(error,
56170700Sjulian							sc->sync ,n);
56270700Sjulian					}
56370700Sjulian				}
56452419Sjulian				sc->stats.asyncFrames++;
56552419Sjulianreset:
56652419Sjulian				sc->amode = MODE_NORMAL;
56752419Sjulian				sc->fcs = PPP_INITFCS;
56852419Sjulian				sc->slen = 0;
56952419Sjulian				continue;
57052419Sjulian			}
57152419Sjulian			switch (sc->amode) {
57252419Sjulian			case MODE_NORMAL:
57352419Sjulian				if (ch == PPP_ESCAPE) {
57452419Sjulian					sc->amode = MODE_ESC;
57552419Sjulian					continue;
57652419Sjulian				}
57752419Sjulian				break;
57852419Sjulian			case MODE_ESC:
57952419Sjulian				ch ^= PPP_TRANS;
58052419Sjulian				sc->amode = MODE_NORMAL;
58152419Sjulian				break;
58252419Sjulian			case MODE_HUNT:
58352419Sjulian			default:
58452419Sjulian				continue;
58552419Sjulian			}
58652419Sjulian
58752419Sjulian			/* Add byte to frame */
58852419Sjulian			if (sc->slen >= SYNC_BUF_SIZE(sc->cfg.amru)) {
58952419Sjulian				sc->stats.asyncOverflows++;
59052419Sjulian				sc->amode = MODE_HUNT;
59152419Sjulian				sc->slen = 0;
59252419Sjulian			} else {
59352419Sjulian				sc->sbuf[sc->slen++] = ch;
59452419Sjulian				sc->fcs = PPP_FCS(sc->fcs, ch);
59552419Sjulian			}
59652419Sjulian		}
59790227Sdillon		m = m_free(m);
59852419Sjulian	}
59970700Sjulian	if (item)
60070700Sjulian		NG_FREE_ITEM(item);
60152419Sjulian	return (0);
60252419Sjulian}
60352419Sjulian
60452419Sjulian/*
60552419Sjulian * CRC table
60652419Sjulian *
60752419Sjulian * Taken from RFC 1171 Appendix B
60852419Sjulian */
60952419Sjulianstatic const u_int16_t fcstab[256] = {
61052419Sjulian	 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
61152419Sjulian	 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
61252419Sjulian	 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
61352419Sjulian	 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
61452419Sjulian	 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
61552419Sjulian	 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
61652419Sjulian	 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
61752419Sjulian	 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
61852419Sjulian	 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
61952419Sjulian	 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
62052419Sjulian	 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
62152419Sjulian	 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
62252419Sjulian	 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
62352419Sjulian	 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
62452419Sjulian	 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
62552419Sjulian	 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
62652419Sjulian	 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
62752419Sjulian	 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
62852419Sjulian	 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
62952419Sjulian	 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
63052419Sjulian	 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
63152419Sjulian	 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
63252419Sjulian	 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
63352419Sjulian	 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
63452419Sjulian	 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
63552419Sjulian	 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
63652419Sjulian	 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
63752419Sjulian	 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
63852419Sjulian	 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
63952419Sjulian	 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
64052419Sjulian	 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
64152419Sjulian	 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
64252419Sjulian};
643