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