ng_async.c revision 70159
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 70159 2000-12-18 20:03:32Z 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 6252419Sjulian/* Async decode state */ 6352419Sjulian#define MODE_HUNT 0 6452419Sjulian#define MODE_NORMAL 1 6552419Sjulian#define MODE_ESC 2 6652419Sjulian 6752419Sjulian/* Private data structure */ 6853394Sarchiestruct ng_async_private { 6952419Sjulian node_p node; /* Our node */ 7052419Sjulian hook_p async; /* Asynchronous side */ 7152419Sjulian hook_p sync; /* Synchronous side */ 7252419Sjulian u_char amode; /* Async hunt/esape mode */ 7352419Sjulian u_int16_t fcs; /* Decoded async FCS (so far) */ 7452419Sjulian u_char *abuf; /* Buffer to encode sync into */ 7552419Sjulian u_char *sbuf; /* Buffer to decode async into */ 7652419Sjulian u_int slen; /* Length of data in sbuf */ 7752419Sjulian long lasttime; /* Time of last async packet sent */ 7852419Sjulian struct ng_async_cfg cfg; /* Configuration */ 7952419Sjulian struct ng_async_stat stats; /* Statistics */ 8052419Sjulian}; 8153394Sarchietypedef struct ng_async_private *sc_p; 8252419Sjulian 8352419Sjulian/* Useful macros */ 8452419Sjulian#define ASYNC_BUF_SIZE(smru) (2 * (smru) + 10) 8552419Sjulian#define SYNC_BUF_SIZE(amru) ((amru) + 10) 8652419Sjulian#define ERROUT(x) do { error = (x); goto done; } while (0) 8752419Sjulian 8852419Sjulian/* Netgraph methods */ 8953913Sarchiestatic ng_constructor_t nga_constructor; 9052752Sjulianstatic ng_rcvdata_t nga_rcvdata; 9152752Sjulianstatic ng_rcvmsg_t nga_rcvmsg; 9252752Sjulianstatic ng_shutdown_t nga_shutdown; 9352752Sjulianstatic ng_newhook_t nga_newhook; 9452752Sjulianstatic ng_disconnect_t nga_disconnect; 9552419Sjulian 9652419Sjulian/* Helper stuff */ 9752419Sjulianstatic int nga_rcv_sync(const sc_p sc, struct mbuf *m, meta_p meta); 9852419Sjulianstatic int nga_rcv_async(const sc_p sc, struct mbuf *m, meta_p meta); 9952419Sjulian 10053913Sarchie/* Parse type for struct ng_async_cfg */ 10153913Sarchiestatic const struct ng_parse_struct_info 10253913Sarchie nga_config_type_info = NG_ASYNC_CONFIG_TYPE_INFO; 10353913Sarchiestatic const struct ng_parse_type nga_config_type = { 10453913Sarchie &ng_parse_struct_type, 10553913Sarchie &nga_config_type_info 10653913Sarchie}; 10753913Sarchie 10853913Sarchie/* Parse type for struct ng_async_stat */ 10953913Sarchiestatic const struct ng_parse_struct_info 11053913Sarchie nga_stats_type_info = NG_ASYNC_STATS_TYPE_INFO; 11153913Sarchiestatic const struct ng_parse_type nga_stats_type = { 11253913Sarchie &ng_parse_struct_type, 11353913Sarchie &nga_stats_type_info, 11453913Sarchie}; 11553913Sarchie 11653913Sarchie/* List of commands and how to convert arguments to/from ASCII */ 11753913Sarchiestatic const struct ng_cmdlist nga_cmdlist[] = { 11853913Sarchie { 11953913Sarchie NGM_ASYNC_COOKIE, 12053913Sarchie NGM_ASYNC_CMD_SET_CONFIG, 12153913Sarchie "setconfig", 12253913Sarchie &nga_config_type, 12353913Sarchie NULL 12453913Sarchie }, 12553913Sarchie { 12653913Sarchie NGM_ASYNC_COOKIE, 12753913Sarchie NGM_ASYNC_CMD_GET_CONFIG, 12853913Sarchie "getconfig", 12953913Sarchie NULL, 13053913Sarchie &nga_config_type 13153913Sarchie }, 13253913Sarchie { 13353913Sarchie NGM_ASYNC_COOKIE, 13453913Sarchie NGM_ASYNC_CMD_GET_STATS, 13553913Sarchie "getstats", 13653913Sarchie NULL, 13753913Sarchie &nga_stats_type 13853913Sarchie }, 13953913Sarchie { 14053913Sarchie NGM_ASYNC_COOKIE, 14153913Sarchie NGM_ASYNC_CMD_CLR_STATS, 14253913Sarchie "clrstats", 14353913Sarchie &nga_stats_type, 14453913Sarchie NULL 14553913Sarchie }, 14653913Sarchie { 0 } 14753913Sarchie}; 14853913Sarchie 14952419Sjulian/* Define the netgraph node type */ 15052419Sjulianstatic struct ng_type typestruct = { 15170159Sjulian NG_ABI_VERSION, 15252419Sjulian NG_ASYNC_NODE_TYPE, 15352419Sjulian NULL, 15452419Sjulian nga_constructor, 15552419Sjulian nga_rcvmsg, 15652419Sjulian nga_shutdown, 15752419Sjulian nga_newhook, 15852419Sjulian NULL, 15952419Sjulian NULL, 16052419Sjulian nga_rcvdata, 16153913Sarchie nga_disconnect, 16253913Sarchie nga_cmdlist 16352419Sjulian}; 16452419SjulianNETGRAPH_INIT(async, &typestruct); 16552419Sjulian 16652419Sjulian/* CRC table */ 16752419Sjulianstatic const u_int16_t fcstab[]; 16852419Sjulian 16952419Sjulian/****************************************************************** 17052419Sjulian NETGRAPH NODE METHODS 17152419Sjulian******************************************************************/ 17252419Sjulian 17352419Sjulian/* 17452419Sjulian * Initialize a new node 17552419Sjulian */ 17652419Sjulianstatic int 17752419Sjuliannga_constructor(node_p *nodep) 17852419Sjulian{ 17952419Sjulian sc_p sc; 18052419Sjulian int error; 18152419Sjulian 18252419Sjulian if ((error = ng_make_node_common(&typestruct, nodep))) 18352419Sjulian return (error); 18468876Sdwmalone MALLOC(sc, sc_p, sizeof(*sc), M_NETGRAPH, M_NOWAIT | M_ZERO); 18552419Sjulian if (sc == NULL) 18652419Sjulian return (ENOMEM); 18752419Sjulian sc->amode = MODE_HUNT; 18852419Sjulian sc->cfg.accm = ~0; 18952419Sjulian sc->cfg.amru = NG_ASYNC_DEFAULT_MRU; 19052419Sjulian sc->cfg.smru = NG_ASYNC_DEFAULT_MRU; 19152419Sjulian MALLOC(sc->abuf, u_char *, 19266182Sarchie ASYNC_BUF_SIZE(sc->cfg.smru), M_NETGRAPH, M_NOWAIT); 19352419Sjulian if (sc->abuf == NULL) 19452419Sjulian goto fail; 19552419Sjulian MALLOC(sc->sbuf, u_char *, 19666182Sarchie SYNC_BUF_SIZE(sc->cfg.amru), M_NETGRAPH, M_NOWAIT); 19752419Sjulian if (sc->sbuf == NULL) { 19852419Sjulian FREE(sc->abuf, M_NETGRAPH); 19952419Sjulianfail: 20052419Sjulian FREE(sc, M_NETGRAPH); 20152419Sjulian return (ENOMEM); 20252419Sjulian } 20352419Sjulian (*nodep)->private = sc; 20452419Sjulian sc->node = *nodep; 20552419Sjulian return (0); 20652419Sjulian} 20752419Sjulian 20852419Sjulian/* 20952419Sjulian * Reserve a hook for a pending connection 21052419Sjulian */ 21152419Sjulianstatic int 21252419Sjuliannga_newhook(node_p node, hook_p hook, const char *name) 21352419Sjulian{ 21452419Sjulian const sc_p sc = node->private; 21552419Sjulian hook_p *hookp; 21652419Sjulian 21752419Sjulian if (!strcmp(name, NG_ASYNC_HOOK_ASYNC)) 21852419Sjulian hookp = &sc->async; 21952419Sjulian else if (!strcmp(name, NG_ASYNC_HOOK_SYNC)) 22052419Sjulian hookp = &sc->sync; 22152419Sjulian else 22252419Sjulian return (EINVAL); 22352419Sjulian if (*hookp) 22452419Sjulian return (EISCONN); 22552419Sjulian *hookp = hook; 22652419Sjulian return (0); 22752419Sjulian} 22852419Sjulian 22952419Sjulian/* 23052419Sjulian * Receive incoming data 23152419Sjulian */ 23252419Sjulianstatic int 23359728Sjuliannga_rcvdata(hook_p hook, struct mbuf *m, meta_p meta, 23469922Sjulian struct mbuf **ret_m, meta_p *ret_meta, struct ng_mesg **resp) 23552419Sjulian{ 23652419Sjulian const sc_p sc = hook->node->private; 23752419Sjulian 23852419Sjulian if (hook == sc->sync) 23952419Sjulian return (nga_rcv_sync(sc, m, meta)); 24052976Sarchie if (hook == sc->async) 24152419Sjulian return (nga_rcv_async(sc, m, meta)); 24252419Sjulian panic(__FUNCTION__); 24352419Sjulian} 24452419Sjulian 24552419Sjulian/* 24652419Sjulian * Receive incoming control message 24752419Sjulian */ 24852419Sjulianstatic int 24952419Sjuliannga_rcvmsg(node_p node, struct ng_mesg *msg, 25059728Sjulian const char *rtn, struct ng_mesg **rptr, hook_p lasthook) 25152419Sjulian{ 25252419Sjulian const sc_p sc = (sc_p) node->private; 25352419Sjulian struct ng_mesg *resp = NULL; 25452419Sjulian int error = 0; 25552419Sjulian 25652419Sjulian switch (msg->header.typecookie) { 25752419Sjulian case NGM_ASYNC_COOKIE: 25852419Sjulian switch (msg->header.cmd) { 25952419Sjulian case NGM_ASYNC_CMD_GET_STATS: 26052419Sjulian NG_MKRESPONSE(resp, msg, sizeof(sc->stats), M_NOWAIT); 26152419Sjulian if (resp == NULL) 26252419Sjulian ERROUT(ENOMEM); 26352419Sjulian *((struct ng_async_stat *) resp->data) = sc->stats; 26452419Sjulian break; 26552419Sjulian case NGM_ASYNC_CMD_CLR_STATS: 26652419Sjulian bzero(&sc->stats, sizeof(sc->stats)); 26752419Sjulian break; 26852419Sjulian case NGM_ASYNC_CMD_SET_CONFIG: 26952419Sjulian { 27052419Sjulian struct ng_async_cfg *const cfg = 27152419Sjulian (struct ng_async_cfg *) msg->data; 27252419Sjulian u_char *buf; 27352419Sjulian 27452419Sjulian if (msg->header.arglen != sizeof(*cfg)) 27552419Sjulian ERROUT(EINVAL); 27652419Sjulian if (cfg->amru < NG_ASYNC_MIN_MRU 27752419Sjulian || cfg->amru > NG_ASYNC_MAX_MRU 27852419Sjulian || cfg->smru < NG_ASYNC_MIN_MRU 27952419Sjulian || cfg->smru > NG_ASYNC_MAX_MRU) 28052419Sjulian ERROUT(EINVAL); 28152419Sjulian cfg->enabled = !!cfg->enabled; /* normalize */ 28252419Sjulian if (cfg->smru > sc->cfg.smru) { /* reallocate buffer */ 28352419Sjulian MALLOC(buf, u_char *, ASYNC_BUF_SIZE(cfg->smru), 28452419Sjulian M_NETGRAPH, M_NOWAIT); 28552419Sjulian if (!buf) 28652419Sjulian ERROUT(ENOMEM); 28752419Sjulian FREE(sc->abuf, M_NETGRAPH); 28852419Sjulian sc->abuf = buf; 28952419Sjulian } 29052419Sjulian if (cfg->amru > sc->cfg.amru) { /* reallocate buffer */ 29152419Sjulian MALLOC(buf, u_char *, SYNC_BUF_SIZE(cfg->amru), 29252419Sjulian M_NETGRAPH, M_NOWAIT); 29352419Sjulian if (!buf) 29452419Sjulian ERROUT(ENOMEM); 29552419Sjulian FREE(sc->sbuf, M_NETGRAPH); 29652419Sjulian sc->sbuf = buf; 29752419Sjulian sc->amode = MODE_HUNT; 29852419Sjulian sc->slen = 0; 29952419Sjulian } 30052419Sjulian if (!cfg->enabled) { 30152419Sjulian sc->amode = MODE_HUNT; 30252419Sjulian sc->slen = 0; 30352419Sjulian } 30452419Sjulian sc->cfg = *cfg; 30552419Sjulian break; 30652419Sjulian } 30752419Sjulian case NGM_ASYNC_CMD_GET_CONFIG: 30852419Sjulian NG_MKRESPONSE(resp, msg, sizeof(sc->cfg), M_NOWAIT); 30952419Sjulian if (!resp) 31052419Sjulian ERROUT(ENOMEM); 31152419Sjulian *((struct ng_async_cfg *) resp->data) = sc->cfg; 31252419Sjulian break; 31352419Sjulian default: 31452419Sjulian ERROUT(EINVAL); 31552419Sjulian } 31652419Sjulian break; 31752419Sjulian default: 31852419Sjulian ERROUT(EINVAL); 31952419Sjulian } 32052419Sjulian if (rptr) 32152419Sjulian *rptr = resp; 32252419Sjulian else if (resp) 32352419Sjulian FREE(resp, M_NETGRAPH); 32452419Sjulian 32552419Sjuliandone: 32652419Sjulian FREE(msg, M_NETGRAPH); 32752419Sjulian return (error); 32852419Sjulian} 32952419Sjulian 33052419Sjulian/* 33152419Sjulian * Shutdown this node 33252419Sjulian */ 33352419Sjulianstatic int 33452419Sjuliannga_shutdown(node_p node) 33552419Sjulian{ 33652419Sjulian const sc_p sc = node->private; 33752419Sjulian 33852419Sjulian ng_cutlinks(node); 33952419Sjulian ng_unname(node); 34052419Sjulian FREE(sc->abuf, M_NETGRAPH); 34152419Sjulian FREE(sc->sbuf, M_NETGRAPH); 34252419Sjulian bzero(sc, sizeof(*sc)); 34352419Sjulian FREE(sc, M_NETGRAPH); 34452419Sjulian node->private = NULL; 34552419Sjulian ng_unref(node); 34652419Sjulian return (0); 34752419Sjulian} 34852419Sjulian 34952419Sjulian/* 35052419Sjulian * Lose a hook. When both hooks go away, we disappear. 35152419Sjulian */ 35252419Sjulianstatic int 35352419Sjuliannga_disconnect(hook_p hook) 35452419Sjulian{ 35552419Sjulian const sc_p sc = hook->node->private; 35652419Sjulian hook_p *hookp; 35752419Sjulian 35852419Sjulian if (hook == sc->async) 35952419Sjulian hookp = &sc->async; 36052419Sjulian else if (hook == sc->sync) 36152419Sjulian hookp = &sc->sync; 36252419Sjulian else 36352419Sjulian panic(__FUNCTION__); 36452419Sjulian if (!*hookp) 36552419Sjulian panic(__FUNCTION__ "2"); 36652419Sjulian *hookp = NULL; 36752419Sjulian bzero(&sc->stats, sizeof(sc->stats)); 36852419Sjulian sc->lasttime = 0; 36952419Sjulian if (hook->node->numhooks == 0) 37052419Sjulian ng_rmnode(hook->node); 37152419Sjulian return (0); 37252419Sjulian} 37352419Sjulian 37452419Sjulian/****************************************************************** 37552419Sjulian INTERNAL HELPER STUFF 37652419Sjulian******************************************************************/ 37752419Sjulian 37852419Sjulian/* 37952419Sjulian * Encode a byte into the async buffer 38052419Sjulian */ 38152419Sjulianstatic __inline__ void 38252419Sjuliannga_async_add(const sc_p sc, u_int16_t *fcs, u_int32_t accm, int *len, u_char x) 38352419Sjulian{ 38452419Sjulian *fcs = PPP_FCS(*fcs, x); 38552419Sjulian if ((x < 32 && ((1 << x) & accm)) 38652419Sjulian || (x == PPP_ESCAPE) 38752419Sjulian || (x == PPP_FLAG)) { 38852419Sjulian sc->abuf[(*len)++] = PPP_ESCAPE; 38952419Sjulian x ^= PPP_TRANS; 39052419Sjulian } 39152419Sjulian sc->abuf[(*len)++] = x; 39252419Sjulian} 39352419Sjulian 39452419Sjulian/* 39552976Sarchie * Receive incoming synchronous data. 39652419Sjulian */ 39752419Sjulianstatic int 39852419Sjuliannga_rcv_sync(const sc_p sc, struct mbuf *m, meta_p meta) 39952419Sjulian{ 40052419Sjulian struct ifnet *const rcvif = m->m_pkthdr.rcvif; 40153394Sarchie int alen, error = 0; 40252976Sarchie struct timeval time; 40352419Sjulian u_int16_t fcs, fcs0; 40452976Sarchie u_int32_t accm; 40552419Sjulian 40652976Sarchie#define ADD_BYTE(x) nga_async_add(sc, &fcs, accm, &alen, (x)) 40752419Sjulian 40852976Sarchie /* Check for bypass mode */ 40952419Sjulian if (!sc->cfg.enabled) { 41052419Sjulian NG_SEND_DATA(error, sc->async, m, meta); 41152419Sjulian return (error); 41252419Sjulian } 41352976Sarchie 41453394Sarchie /* Get ACCM; special case LCP frames, which use full ACCM */ 41552976Sarchie accm = sc->cfg.accm; 41653394Sarchie if (m->m_pkthdr.len >= 4) { 41753394Sarchie static const u_char lcphdr[4] = { 41853394Sarchie PPP_ALLSTATIONS, 41953394Sarchie PPP_UI, 42053394Sarchie (u_char)(PPP_LCP >> 8), 42153394Sarchie (u_char)(PPP_LCP & 0xff) 42253394Sarchie }; 42353394Sarchie u_char buf[4]; 42452976Sarchie 42553394Sarchie m_copydata(m, 0, 4, (caddr_t)buf); 42653394Sarchie if (bcmp(buf, &lcphdr, 4) == 0) 42752976Sarchie accm = ~0; 42852976Sarchie } 42952976Sarchie 43052976Sarchie /* Check for overflow */ 43152419Sjulian if (m->m_pkthdr.len > sc->cfg.smru) { 43252419Sjulian sc->stats.syncOverflows++; 43352419Sjulian NG_FREE_DATA(m, meta); 43452419Sjulian return (EMSGSIZE); 43552419Sjulian } 43652976Sarchie 43752976Sarchie /* Update stats */ 43852419Sjulian sc->stats.syncFrames++; 43952419Sjulian sc->stats.syncOctets += m->m_pkthdr.len; 44052419Sjulian 44152419Sjulian /* Initialize async encoded version of input mbuf */ 44252419Sjulian alen = 0; 44352419Sjulian fcs = PPP_INITFCS; 44452419Sjulian 44552419Sjulian /* Add beginning sync flag if it's been long enough to need one */ 44652976Sarchie getmicrotime(&time); 44752976Sarchie if (time.tv_sec >= sc->lasttime + 1) { 44852976Sarchie sc->abuf[alen++] = PPP_FLAG; 44952976Sarchie sc->lasttime = time.tv_sec; 45052419Sjulian } 45152419Sjulian 45253394Sarchie /* Add packet payload */ 45352976Sarchie while (m != NULL) { 45452419Sjulian struct mbuf *n; 45552419Sjulian 45652419Sjulian while (m->m_len > 0) { 45752976Sarchie ADD_BYTE(*mtod(m, u_char *)); 45852419Sjulian m->m_data++; 45952419Sjulian m->m_len--; 46052419Sjulian } 46152419Sjulian MFREE(m, n); 46252419Sjulian m = n; 46352419Sjulian } 46452419Sjulian 46552419Sjulian /* Add checksum and final sync flag */ 46652419Sjulian fcs0 = fcs; 46752419Sjulian ADD_BYTE(~fcs0 & 0xff); 46852419Sjulian ADD_BYTE(~fcs0 >> 8); 46952419Sjulian sc->abuf[alen++] = PPP_FLAG; 47052419Sjulian 47152419Sjulian /* Put frame in an mbuf and ship it off */ 47252976Sarchie if (!(m = m_devget(sc->abuf, alen, 0, rcvif, NULL))) { 47352976Sarchie NG_FREE_META(meta); 47452419Sjulian error = ENOBUFS; 47552976Sarchie } else 47652419Sjulian NG_SEND_DATA(error, sc->async, m, meta); 47752419Sjulian return (error); 47852419Sjulian} 47952419Sjulian 48052419Sjulian/* 48152419Sjulian * Receive incoming asynchronous data 48252976Sarchie * XXX Technically, we should strip out incoming characters 48352976Sarchie * that are in our ACCM. Not sure if this is good or not. 48452419Sjulian */ 48552419Sjulianstatic int 48652419Sjuliannga_rcv_async(const sc_p sc, struct mbuf * m, meta_p meta) 48752419Sjulian{ 48852419Sjulian struct ifnet *const rcvif = m->m_pkthdr.rcvif; 48952419Sjulian int error; 49052419Sjulian 49152419Sjulian if (!sc->cfg.enabled) { 49252419Sjulian NG_SEND_DATA(error, sc->sync, m, meta); 49352419Sjulian return (error); 49452419Sjulian } 49552419Sjulian NG_FREE_META(meta); 49652419Sjulian while (m) { 49752419Sjulian struct mbuf *n; 49852419Sjulian 49952419Sjulian for (; m->m_len > 0; m->m_data++, m->m_len--) { 50052419Sjulian u_char ch = *mtod(m, u_char *); 50152419Sjulian 50252419Sjulian sc->stats.asyncOctets++; 50352419Sjulian if (ch == PPP_FLAG) { /* Flag overrides everything */ 50452419Sjulian int skip = 0; 50552419Sjulian 50652419Sjulian /* Check for runts */ 50752419Sjulian if (sc->slen < 2) { 50852419Sjulian if (sc->slen > 0) 50952419Sjulian sc->stats.asyncRunts++; 51052419Sjulian goto reset; 51152419Sjulian } 51252419Sjulian 51352419Sjulian /* Verify CRC */ 51452419Sjulian if (sc->fcs != PPP_GOODFCS) { 51552419Sjulian sc->stats.asyncBadCheckSums++; 51652419Sjulian goto reset; 51752419Sjulian } 51852419Sjulian sc->slen -= 2; 51952419Sjulian 52052419Sjulian /* Strip address and control fields */ 52152419Sjulian if (sc->slen >= 2 52252419Sjulian && sc->sbuf[0] == PPP_ALLSTATIONS 52352419Sjulian && sc->sbuf[1] == PPP_UI) 52452419Sjulian skip = 2; 52552419Sjulian 52652419Sjulian /* Check for frame too big */ 52752419Sjulian if (sc->slen - skip > sc->cfg.amru) { 52852419Sjulian sc->stats.asyncOverflows++; 52952419Sjulian goto reset; 53052419Sjulian } 53152419Sjulian 53252419Sjulian /* OK, ship it out */ 53352419Sjulian if ((n = m_devget(sc->sbuf + skip, 53452419Sjulian sc->slen - skip, 0, rcvif, NULL))) 53552419Sjulian NG_SEND_DATA(error, sc->sync, n, meta); 53652419Sjulian sc->stats.asyncFrames++; 53752419Sjulianreset: 53852419Sjulian sc->amode = MODE_NORMAL; 53952419Sjulian sc->fcs = PPP_INITFCS; 54052419Sjulian sc->slen = 0; 54152419Sjulian continue; 54252419Sjulian } 54352419Sjulian switch (sc->amode) { 54452419Sjulian case MODE_NORMAL: 54552419Sjulian if (ch == PPP_ESCAPE) { 54652419Sjulian sc->amode = MODE_ESC; 54752419Sjulian continue; 54852419Sjulian } 54952419Sjulian break; 55052419Sjulian case MODE_ESC: 55152419Sjulian ch ^= PPP_TRANS; 55252419Sjulian sc->amode = MODE_NORMAL; 55352419Sjulian break; 55452419Sjulian case MODE_HUNT: 55552419Sjulian default: 55652419Sjulian continue; 55752419Sjulian } 55852419Sjulian 55952419Sjulian /* Add byte to frame */ 56052419Sjulian if (sc->slen >= SYNC_BUF_SIZE(sc->cfg.amru)) { 56152419Sjulian sc->stats.asyncOverflows++; 56252419Sjulian sc->amode = MODE_HUNT; 56352419Sjulian sc->slen = 0; 56452419Sjulian } else { 56552419Sjulian sc->sbuf[sc->slen++] = ch; 56652419Sjulian sc->fcs = PPP_FCS(sc->fcs, ch); 56752419Sjulian } 56852419Sjulian } 56952419Sjulian MFREE(m, n); 57052419Sjulian m = n; 57152419Sjulian } 57252419Sjulian return (0); 57352419Sjulian} 57452419Sjulian 57552419Sjulian/* 57652419Sjulian * CRC table 57752419Sjulian * 57852419Sjulian * Taken from RFC 1171 Appendix B 57952419Sjulian */ 58052419Sjulianstatic const u_int16_t fcstab[256] = { 58152419Sjulian 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, 58252419Sjulian 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, 58352419Sjulian 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, 58452419Sjulian 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, 58552419Sjulian 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, 58652419Sjulian 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, 58752419Sjulian 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, 58852419Sjulian 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, 58952419Sjulian 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, 59052419Sjulian 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, 59152419Sjulian 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, 59252419Sjulian 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, 59352419Sjulian 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, 59452419Sjulian 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, 59552419Sjulian 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, 59652419Sjulian 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, 59752419Sjulian 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, 59852419Sjulian 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, 59952419Sjulian 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, 60052419Sjulian 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, 60152419Sjulian 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, 60252419Sjulian 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, 60352419Sjulian 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, 60452419Sjulian 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, 60552419Sjulian 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, 60652419Sjulian 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, 60752419Sjulian 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, 60852419Sjulian 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, 60952419Sjulian 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, 61052419Sjulian 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, 61152419Sjulian 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, 61252419Sjulian 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 61352419Sjulian}; 614