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