ng_async.c revision 52419
1234370Sjasone
2234370Sjasone/*
3234370Sjasone * ng_async.c
4234370Sjasone *
5234370Sjasone * Copyright (c) 1996-1999 Whistle Communications, Inc.
6234370Sjasone * All rights reserved.
7234370Sjasone *
8234370Sjasone * Subject to the following obligations and disclaimer of warranty, use and
9234370Sjasone * redistribution of this software, in source or object code forms, with or
10234370Sjasone * without modifications are expressly permitted by Whistle Communications;
11234370Sjasone * provided, however, that:
12234370Sjasone * 1. Any and all reproductions of the source or object code must include the
13234370Sjasone *    copyright notice above and the following disclaimer of warranties; and
14234370Sjasone * 2. No rights are granted, in any manner or form, to use Whistle
15234370Sjasone *    Communications, Inc. trademarks, including the mark "WHISTLE
16234370Sjasone *    COMMUNICATIONS" on advertising, endorsements, or otherwise except as
17234370Sjasone *    such appears in the above copyright notice or in the software.
18234370Sjasone *
19234370Sjasone * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
20234370Sjasone * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
21234543Sjasone * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
22234543Sjasone * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
23234543Sjasone * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
24234543Sjasone * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
25234543Sjasone * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
26234543Sjasone * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
27235238Sjasone * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
28235238Sjasone * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
29235238Sjasone * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
30235238Sjasone * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
31235238Sjasone * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
32235238Sjasone * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33235238Sjasone * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
34235238Sjasone * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
35235238Sjasone * OF SUCH DAMAGE.
36235238Sjasone *
37235238Sjasone * Author: Archie Cobbs <archie@whistle.com>
38235238Sjasone *
39235238Sjasone * $FreeBSD: head/sys/netgraph/ng_async.c 52419 1999-10-21 09:06:11Z julian $
40235238Sjasone * $Whistle: ng_async.c,v 1.15 1999/01/28 23:54:52 julian Exp $
41235238Sjasone */
42235238Sjasone
43235238Sjasone/*
44235238Sjasone * This node type implements a PPP style sync <-> async converter.
45235238Sjasone * See RFC 1661 for details of how asynchronous encoding works.
46235238Sjasone */
47235238Sjasone
48235238Sjasone#include <sys/param.h>
49235238Sjasone#include <sys/systm.h>
50235238Sjasone#include <sys/kernel.h>
51235238Sjasone#include <sys/conf.h>
52235238Sjasone#include <sys/proc.h>
53235238Sjasone#include <sys/mbuf.h>
54235238Sjasone#include <sys/malloc.h>
55235238Sjasone#include <sys/socket.h>
56235238Sjasone#include <sys/file.h>
57235238Sjasone#include <sys/tty.h>
58235238Sjasone#include <sys/syslog.h>
59235238Sjasone#include <sys/errno.h>
60235238Sjasone
61235238Sjasone#include <netgraph/ng_message.h>
62235238Sjasone#include <netgraph/netgraph.h>
63235238Sjasone#include <netgraph/ng_async.h>
64235238Sjasone
65235238Sjasone#include <net/ppp_defs.h>
66235238Sjasone
67234370Sjasone/* Optimize opening and closing flags into one? Set to max # seconds delay */
68234370Sjasone#define SYNC_OPT_TIME	1	/* one second maximum */
69234370Sjasone
70234370Sjasone/* Async decode state */
71234370Sjasone#define MODE_HUNT	0
72234370Sjasone#define MODE_NORMAL	1
73234370Sjasone#define MODE_ESC	2
74234370Sjasone
75234370Sjasone/* Private data structure */
76234370Sjasonestruct private {
77234370Sjasone	node_p  	node;		/* Our node */
78234370Sjasone	hook_p  	async;		/* Asynchronous side */
79234370Sjasone	hook_p  	sync;		/* Synchronous side */
80234370Sjasone	hook_p  	sync2;		/* Synchronous side, full escapes */
81234370Sjasone	u_char  	amode;		/* Async hunt/esape mode */
82234370Sjasone	u_int16_t	fcs;		/* Decoded async FCS (so far) */
83234370Sjasone	u_char	       *abuf;		/* Buffer to encode sync into */
84234370Sjasone	u_char	       *sbuf;		/* Buffer to decode async into */
85234370Sjasone	u_int		slen;		/* Length of data in sbuf */
86234370Sjasone#if SYNC_OPT_TIME
87234370Sjasone	long		lasttime;	/* Time of last async packet sent */
88234370Sjasone#endif
89234370Sjasone	struct		ng_async_cfg	cfg;	/* Configuration */
90234370Sjasone	struct		ng_async_stat	stats;	/* Statistics */
91234370Sjasone};
92234370Sjasonetypedef struct private *sc_p;
93234370Sjasone
94234370Sjasone/* Useful macros */
95234370Sjasone#define ASYNC_BUF_SIZE(smru)	(2 * (smru) + 10)
96234370Sjasone#define SYNC_BUF_SIZE(amru)	((amru) + 10)
97234370Sjasone#define ERROUT(x)		do { error = (x); goto done; } while (0)
98234370Sjasone
99234370Sjasone/* Netgraph methods */
100251300Sjasonestatic int	nga_constructor(node_p *node);
101251300Sjasonestatic int	nga_rcvdata(hook_p hook, struct mbuf *m, meta_p meta);
102234370Sjasonestatic int	nga_rcvmsg(node_p node, struct ng_mesg *msg,
103234370Sjasone		    const char *rtn, struct ng_mesg **resp);
104234370Sjasonestatic int	nga_shutdown(node_p node);
105234370Sjasonestatic int	nga_newhook(node_p node, hook_p hook, const char *name);
106234370Sjasonestatic int	nga_disconnect(hook_p hook);
107234370Sjasone
108234370Sjasone/* Helper stuff */
109234370Sjasonestatic int	nga_rcv_sync(const sc_p sc, struct mbuf *m, meta_p meta);
110234370Sjasonestatic int	nga_rcv_async(const sc_p sc, struct mbuf *m, meta_p meta);
111234370Sjasone
112234370Sjasone/* Define the netgraph node type */
113234370Sjasonestatic struct ng_type typestruct = {
114234370Sjasone	NG_VERSION,
115234370Sjasone	NG_ASYNC_NODE_TYPE,
116234370Sjasone	NULL,
117234370Sjasone	nga_constructor,
118234370Sjasone	nga_rcvmsg,
119234370Sjasone	nga_shutdown,
120234370Sjasone	nga_newhook,
121234370Sjasone	NULL,
122235238Sjasone	NULL,
123234370Sjasone	nga_rcvdata,
124234370Sjasone	nga_rcvdata,
125234370Sjasone	nga_disconnect
126234370Sjasone};
127235238SjasoneNETGRAPH_INIT(async, &typestruct);
128235238Sjasone
129234370Sjasone/* CRC table */
130234370Sjasonestatic const u_int16_t fcstab[];
131234370Sjasone
132234370Sjasone/******************************************************************
133234370Sjasone		    NETGRAPH NODE METHODS
134234370Sjasone******************************************************************/
135234370Sjasone
136234370Sjasone/*
137234370Sjasone * Initialize a new node
138234370Sjasone */
139234370Sjasonestatic int
140234370Sjasonenga_constructor(node_p *nodep)
141234370Sjasone{
142234370Sjasone	sc_p sc;
143234370Sjasone	int error;
144234370Sjasone
145234370Sjasone	if ((error = ng_make_node_common(&typestruct, nodep)))
146234370Sjasone		return (error);
147234370Sjasone	MALLOC(sc, sc_p, sizeof(*sc), M_NETGRAPH, M_WAITOK);
148234370Sjasone	if (sc == NULL)
149234370Sjasone		return (ENOMEM);
150234370Sjasone	bzero(sc, sizeof(*sc));
151234370Sjasone	sc->amode = MODE_HUNT;
152234370Sjasone	sc->cfg.accm = ~0;
153234370Sjasone	sc->cfg.amru = NG_ASYNC_DEFAULT_MRU;
154234370Sjasone	sc->cfg.smru = NG_ASYNC_DEFAULT_MRU;
155234370Sjasone	MALLOC(sc->abuf, u_char *,
156234370Sjasone	    ASYNC_BUF_SIZE(sc->cfg.smru), M_NETGRAPH, M_WAITOK);
157234370Sjasone	if (sc->abuf == NULL)
158234370Sjasone		goto fail;
159234370Sjasone	MALLOC(sc->sbuf, u_char *,
160234370Sjasone	    SYNC_BUF_SIZE(sc->cfg.amru), M_NETGRAPH, M_WAITOK);
161234370Sjasone	if (sc->sbuf == NULL) {
162234370Sjasone		FREE(sc->abuf, M_NETGRAPH);
163234370Sjasonefail:
164234370Sjasone		FREE(sc, M_NETGRAPH);
165234370Sjasone		return (ENOMEM);
166234370Sjasone	}
167234370Sjasone	(*nodep)->private = sc;
168234370Sjasone	sc->node = *nodep;
169234370Sjasone	return (0);
170234370Sjasone}
171234370Sjasone
172234370Sjasone/*
173234370Sjasone * Reserve a hook for a pending connection
174234370Sjasone */
175234370Sjasonestatic int
176234370Sjasonenga_newhook(node_p node, hook_p hook, const char *name)
177234370Sjasone{
178251300Sjasone	const sc_p sc = node->private;
179234370Sjasone	hook_p *hookp;
180251300Sjasone
181251300Sjasone	if (!strcmp(name, NG_ASYNC_HOOK_ASYNC))
182234370Sjasone		hookp = &sc->async;
183234370Sjasone	else if (!strcmp(name, NG_ASYNC_HOOK_SYNC))
184234370Sjasone		hookp = &sc->sync;
185251300Sjasone	else if (!strcmp(name, NG_ASYNC_HOOK_SYNC2))
186234370Sjasone		hookp = &sc->sync2;
187234370Sjasone	else
188234370Sjasone		return (EINVAL);
189234370Sjasone	if (*hookp)
190234370Sjasone		return (EISCONN);
191234370Sjasone	*hookp = hook;
192234370Sjasone	return (0);
193234370Sjasone}
194234370Sjasone
195234370Sjasone/*
196234370Sjasone * Receive incoming data
197234370Sjasone */
198234370Sjasonestatic int
199234370Sjasonenga_rcvdata(hook_p hook, struct mbuf *m, meta_p meta)
200234370Sjasone{
201234370Sjasone	const sc_p sc = hook->node->private;
202234370Sjasone
203234370Sjasone	if (hook == sc->sync)
204235238Sjasone		return (nga_rcv_sync(sc, m, meta));
205234370Sjasone	else if (hook == sc->sync2) {
206234370Sjasone		const u_char acfcompSave = sc->cfg.acfcomp;
207234370Sjasone		const u_int32_t accmSave = sc->cfg.accm;
208234370Sjasone		int     rtn;
209234370Sjasone
210234370Sjasone		sc->cfg.acfcomp = 0;
211234370Sjasone		sc->cfg.accm = ~0;
212234370Sjasone		rtn = nga_rcv_sync(sc, m, meta);
213234370Sjasone		sc->cfg.acfcomp = acfcompSave;
214234370Sjasone		sc->cfg.accm = accmSave;
215234370Sjasone		return (rtn);
216234370Sjasone	} else if (hook == sc->async)
217251300Sjasone		return (nga_rcv_async(sc, m, meta));
218251300Sjasone	panic(__FUNCTION__);
219234370Sjasone}
220234370Sjasone
221234370Sjasone/*
222234370Sjasone * Receive incoming control message
223234370Sjasone */
224234370Sjasonestatic int
225234370Sjasonenga_rcvmsg(node_p node, struct ng_mesg *msg,
226234370Sjasone	const char *rtn, struct ng_mesg **rptr)
227234370Sjasone{
228234370Sjasone	const sc_p sc = (sc_p) node->private;
229234370Sjasone	struct ng_mesg *resp = NULL;
230234370Sjasone	int error = 0;
231234370Sjasone
232234370Sjasone	switch (msg->header.typecookie) {
233234370Sjasone	case NGM_ASYNC_COOKIE:
234234370Sjasone		switch (msg->header.cmd) {
235234370Sjasone		case NGM_ASYNC_CMD_GET_STATS:
236234370Sjasone			NG_MKRESPONSE(resp, msg, sizeof(sc->stats), M_NOWAIT);
237234370Sjasone			if (resp == NULL)
238234370Sjasone				ERROUT(ENOMEM);
239234370Sjasone			*((struct ng_async_stat *) resp->data) = sc->stats;
240234370Sjasone			break;
241234370Sjasone		case NGM_ASYNC_CMD_CLR_STATS:
242234370Sjasone			bzero(&sc->stats, sizeof(sc->stats));
243234370Sjasone			break;
244234370Sjasone		case NGM_ASYNC_CMD_SET_CONFIG:
245234370Sjasone		    {
246234370Sjasone			struct ng_async_cfg *const cfg =
247234370Sjasone				(struct ng_async_cfg *) msg->data;
248234370Sjasone			u_char *buf;
249234370Sjasone
250234370Sjasone			if (msg->header.arglen != sizeof(*cfg))
251234370Sjasone				ERROUT(EINVAL);
252234370Sjasone			if (cfg->amru < NG_ASYNC_MIN_MRU
253234370Sjasone			    || cfg->amru > NG_ASYNC_MAX_MRU
254234370Sjasone			    || cfg->smru < NG_ASYNC_MIN_MRU
255234370Sjasone			    || cfg->smru > NG_ASYNC_MAX_MRU)
256234370Sjasone				ERROUT(EINVAL);
257234370Sjasone			cfg->enabled = !!cfg->enabled;	/* normalize */
258234370Sjasone			cfg->acfcomp = !!cfg->acfcomp;	/* normalize */
259234370Sjasone			if (cfg->smru > sc->cfg.smru) {	/* reallocate buffer */
260234370Sjasone				MALLOC(buf, u_char *, ASYNC_BUF_SIZE(cfg->smru),
261234370Sjasone				    M_NETGRAPH, M_NOWAIT);
262234370Sjasone				if (!buf)
263234370Sjasone					ERROUT(ENOMEM);
264234370Sjasone				FREE(sc->abuf, M_NETGRAPH);
265234370Sjasone				sc->abuf = buf;
266234370Sjasone			}
267234370Sjasone			if (cfg->amru > sc->cfg.amru) {	/* reallocate buffer */
268234370Sjasone				MALLOC(buf, u_char *, SYNC_BUF_SIZE(cfg->amru),
269234370Sjasone				    M_NETGRAPH, M_NOWAIT);
270234370Sjasone				if (!buf)
271234370Sjasone					ERROUT(ENOMEM);
272234370Sjasone				FREE(sc->sbuf, M_NETGRAPH);
273234370Sjasone				sc->sbuf = buf;
274234370Sjasone				sc->amode = MODE_HUNT;
275234370Sjasone				sc->slen = 0;
276234370Sjasone			}
277234370Sjasone			if (!cfg->enabled) {
278234370Sjasone				sc->amode = MODE_HUNT;
279234370Sjasone				sc->slen = 0;
280234370Sjasone			}
281234370Sjasone			sc->cfg = *cfg;
282234370Sjasone			break;
283234370Sjasone		    }
284234370Sjasone		case NGM_ASYNC_CMD_GET_CONFIG:
285234370Sjasone			NG_MKRESPONSE(resp, msg, sizeof(sc->cfg), M_NOWAIT);
286234370Sjasone			if (!resp)
287234370Sjasone				ERROUT(ENOMEM);
288234370Sjasone			*((struct ng_async_cfg *) resp->data) = sc->cfg;
289234370Sjasone			break;
290234370Sjasone		default:
291234370Sjasone			ERROUT(EINVAL);
292234370Sjasone		}
293234370Sjasone		break;
294234370Sjasone	default:
295242844Sjasone		ERROUT(EINVAL);
296234370Sjasone	}
297234370Sjasone	if (rptr)
298234370Sjasone		*rptr = resp;
299234370Sjasone	else if (resp)
300234370Sjasone		FREE(resp, M_NETGRAPH);
301234370Sjasone
302234370Sjasonedone:
303234370Sjasone	FREE(msg, M_NETGRAPH);
304234370Sjasone	return (error);
305234370Sjasone}
306234370Sjasone
307234370Sjasone/*
308234370Sjasone * Shutdown this node
309234370Sjasone */
310234370Sjasonestatic int
311234370Sjasonenga_shutdown(node_p node)
312234370Sjasone{
313234370Sjasone	const sc_p sc = node->private;
314234370Sjasone
315234370Sjasone	ng_cutlinks(node);
316234370Sjasone	ng_unname(node);
317234370Sjasone	FREE(sc->abuf, M_NETGRAPH);
318234370Sjasone	FREE(sc->sbuf, M_NETGRAPH);
319234370Sjasone	bzero(sc, sizeof(*sc));
320234370Sjasone	FREE(sc, M_NETGRAPH);
321234370Sjasone	node->private = NULL;
322234370Sjasone	ng_unref(node);
323234370Sjasone	return (0);
324234370Sjasone}
325234370Sjasone
326234370Sjasone/*
327234370Sjasone * Lose a hook. When both hooks go away, we disappear.
328234370Sjasone */
329234370Sjasonestatic int
330234370Sjasonenga_disconnect(hook_p hook)
331234370Sjasone{
332234370Sjasone	const sc_p sc = hook->node->private;
333234370Sjasone	hook_p *hookp;
334234370Sjasone
335234370Sjasone	if (hook == sc->async)
336234370Sjasone		hookp = &sc->async;
337234370Sjasone	else if (hook == sc->sync)
338234370Sjasone		hookp = &sc->sync;
339234370Sjasone	else if (hook == sc->sync2)
340234370Sjasone		hookp = &sc->sync2;
341234370Sjasone	else
342234370Sjasone		panic(__FUNCTION__);
343234370Sjasone	if (!*hookp)
344234370Sjasone		panic(__FUNCTION__ "2");
345234370Sjasone	*hookp = NULL;
346234370Sjasone	bzero(&sc->stats, sizeof(sc->stats));
347234370Sjasone#if SYNC_OPT_TIME
348234370Sjasone	sc->lasttime = 0;
349234370Sjasone#endif
350251300Sjasone	if (hook->node->numhooks == 0)
351251300Sjasone		ng_rmnode(hook->node);
352251300Sjasone	return (0);
353234370Sjasone}
354234370Sjasone
355234370Sjasone/******************************************************************
356234370Sjasone		    INTERNAL HELPER STUFF
357234370Sjasone******************************************************************/
358234370Sjasone
359234370Sjasone/*
360235238Sjasone * Encode a byte into the async buffer
361234370Sjasone */
362235238Sjasonestatic __inline__ void
363234370Sjasonenga_async_add(const sc_p sc, u_int16_t *fcs, u_int32_t accm, int *len, u_char x)
364234370Sjasone{
365234370Sjasone	*fcs = PPP_FCS(*fcs, x);
366234370Sjasone	if ((x < 32 && ((1 << x) & accm))
367234370Sjasone	    || (x == PPP_ESCAPE)
368234370Sjasone	    || (x == PPP_FLAG)) {
369242844Sjasone		sc->abuf[(*len)++] = PPP_ESCAPE;
370234370Sjasone		x ^= PPP_TRANS;
371234370Sjasone	}
372234370Sjasone	sc->abuf[(*len)++] = x;
373234370Sjasone}
374234370Sjasone
375234370Sjasone/*
376234370Sjasone * Receive incoming synchronous data. Any "meta" information means
377234370Sjasone * for us to apply full ACCM to this frame.
378234370Sjasone */
379234370Sjasonestatic int
380234370Sjasonenga_rcv_sync(const sc_p sc, struct mbuf *m, meta_p meta)
381234370Sjasone{
382234370Sjasone	struct ifnet *const rcvif = m->m_pkthdr.rcvif;
383234370Sjasone	u_int16_t fcs, fcs0;
384234370Sjasone	int alen, error = 0;
385234370Sjasone
386234370Sjasone#define ADD_BYTE(x)	\
387234370Sjasone  nga_async_add(sc, &fcs, meta ? ~0 : sc->cfg.accm, &alen, (x))
388234370Sjasone
389234370Sjasone	if (!sc->cfg.enabled) {
390234370Sjasone		NG_SEND_DATA(error, sc->async, m, meta);
391234370Sjasone		return (error);
392234370Sjasone	}
393234370Sjasone	if (m->m_pkthdr.len > sc->cfg.smru) {
394234370Sjasone		sc->stats.syncOverflows++;
395234370Sjasone		NG_FREE_DATA(m, meta);
396234370Sjasone		return (EMSGSIZE);
397234370Sjasone	}
398234370Sjasone	sc->stats.syncFrames++;
399234370Sjasone	sc->stats.syncOctets += m->m_pkthdr.len;
400234370Sjasone
401234370Sjasone	/* Initialize async encoded version of input mbuf */
402234370Sjasone	alen = 0;
403234370Sjasone	fcs = PPP_INITFCS;
404234370Sjasone
405234370Sjasone	/* Add beginning sync flag if it's been long enough to need one */
406234370Sjasone#if SYNC_OPT_TIME
407234370Sjasone	{
408234370Sjasone		struct timeval time;
409234370Sjasone
410234370Sjasone		getmicrotime(&time);
411234370Sjasone		if (time.tv_sec >= sc->lasttime + SYNC_OPT_TIME) {
412234370Sjasone			sc->abuf[alen++] = PPP_FLAG;
413234370Sjasone			sc->lasttime = time.tv_sec;
414234370Sjasone		}
415234370Sjasone	}
416234370Sjasone#else
417234370Sjasone	sc->abuf[alen++] = PPP_FLAG;
418234370Sjasone#endif
419234370Sjasone
420234370Sjasone	/* Add option address and control fields, then packet payload */
421234370Sjasone	if (!sc->cfg.acfcomp || meta) {
422234370Sjasone		ADD_BYTE(PPP_ALLSTATIONS);
423234370Sjasone		ADD_BYTE(PPP_UI);
424234370Sjasone	}
425234370Sjasone	while (m) {
426234370Sjasone		struct mbuf *n;
427234370Sjasone
428234370Sjasone		while (m->m_len > 0) {
429234370Sjasone			u_char const ch = *mtod(m, u_char *);
430234370Sjasone
431234370Sjasone			ADD_BYTE(ch);
432234370Sjasone			m->m_data++;
433234370Sjasone			m->m_len--;
434234370Sjasone		}
435234370Sjasone		MFREE(m, n);
436234370Sjasone		m = n;
437234370Sjasone	}
438234370Sjasone
439234370Sjasone	/* Add checksum and final sync flag */
440234370Sjasone	fcs0 = fcs;
441234370Sjasone	ADD_BYTE(~fcs0 & 0xff);
442234370Sjasone	ADD_BYTE(~fcs0 >> 8);
443234370Sjasone	sc->abuf[alen++] = PPP_FLAG;
444234370Sjasone
445234370Sjasone	/* Put frame in an mbuf and ship it off */
446234370Sjasone	NG_FREE_META(meta);
447234370Sjasone	if (!(m = m_devget(sc->abuf, alen, 0, rcvif, NULL)))
448234370Sjasone		error = ENOBUFS;
449234370Sjasone	else
450234370Sjasone		NG_SEND_DATA(error, sc->async, m, meta);
451234370Sjasone	return (error);
452234370Sjasone}
453234370Sjasone
454234370Sjasone/*
455234370Sjasone * Receive incoming asynchronous data
456234370Sjasone * XXX technically, we should strip out supposedly escaped characters
457234370Sjasone */
458234370Sjasonestatic int
459234370Sjasonenga_rcv_async(const sc_p sc, struct mbuf * m, meta_p meta)
460234370Sjasone{
461234370Sjasone	struct ifnet *const rcvif = m->m_pkthdr.rcvif;
462234370Sjasone	int error;
463234370Sjasone
464234370Sjasone	if (!sc->cfg.enabled) {
465234370Sjasone		NG_SEND_DATA(error, sc->sync, m, meta);
466234370Sjasone		return (error);
467234370Sjasone	}
468234370Sjasone	NG_FREE_META(meta);
469234370Sjasone	while (m) {
470234370Sjasone		struct mbuf *n;
471234370Sjasone
472234370Sjasone		for (; m->m_len > 0; m->m_data++, m->m_len--) {
473234370Sjasone			u_char  ch = *mtod(m, u_char *);
474234370Sjasone
475234370Sjasone			sc->stats.asyncOctets++;
476234370Sjasone			if (ch == PPP_FLAG) {	/* Flag overrides everything */
477				int     skip = 0;
478
479				/* Check for runts */
480				if (sc->slen < 2) {
481					if (sc->slen > 0)
482						sc->stats.asyncRunts++;
483					goto reset;
484				}
485
486				/* Verify CRC */
487				if (sc->fcs != PPP_GOODFCS) {
488					sc->stats.asyncBadCheckSums++;
489					goto reset;
490				}
491				sc->slen -= 2;
492
493				/* Strip address and control fields */
494				if (sc->slen >= 2
495				    && sc->sbuf[0] == PPP_ALLSTATIONS
496				    && sc->sbuf[1] == PPP_UI)
497					skip = 2;
498
499				/* Check for frame too big */
500				if (sc->slen - skip > sc->cfg.amru) {
501					sc->stats.asyncOverflows++;
502					goto reset;
503				}
504
505				/* OK, ship it out */
506				if ((n = m_devget(sc->sbuf + skip,
507					   sc->slen - skip, 0, rcvif, NULL)))
508					NG_SEND_DATA(error, sc->sync, n, meta);
509				sc->stats.asyncFrames++;
510reset:
511				sc->amode = MODE_NORMAL;
512				sc->fcs = PPP_INITFCS;
513				sc->slen = 0;
514				continue;
515			}
516			switch (sc->amode) {
517			case MODE_NORMAL:
518				if (ch == PPP_ESCAPE) {
519					sc->amode = MODE_ESC;
520					continue;
521				}
522				break;
523			case MODE_ESC:
524				ch ^= PPP_TRANS;
525				sc->amode = MODE_NORMAL;
526				break;
527			case MODE_HUNT:
528			default:
529				continue;
530			}
531
532			/* Add byte to frame */
533			if (sc->slen >= SYNC_BUF_SIZE(sc->cfg.amru)) {
534				sc->stats.asyncOverflows++;
535				sc->amode = MODE_HUNT;
536				sc->slen = 0;
537			} else {
538				sc->sbuf[sc->slen++] = ch;
539				sc->fcs = PPP_FCS(sc->fcs, ch);
540			}
541		}
542		MFREE(m, n);
543		m = n;
544	}
545	return (0);
546}
547
548/*
549 * CRC table
550 *
551 * Taken from RFC 1171 Appendix B
552 */
553static const u_int16_t fcstab[256] = {
554	 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
555	 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
556	 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
557	 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
558	 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
559	 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
560	 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
561	 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
562	 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
563	 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
564	 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
565	 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
566	 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
567	 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
568	 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
569	 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
570	 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
571	 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
572	 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
573	 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
574	 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
575	 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
576	 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
577	 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
578	 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
579	 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
580	 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
581	 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
582	 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
583	 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
584	 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
585	 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
586};
587