ng_async.c revision 227293
1218885Sdim/* 2218885Sdim * ng_async.c 3218885Sdim */ 4218885Sdim 5218885Sdim/*- 6218885Sdim * Copyright (c) 1996-1999 Whistle Communications, Inc. 7218885Sdim * All rights reserved. 8218885Sdim * 9218885Sdim * Subject to the following obligations and disclaimer of warranty, use and 10218885Sdim * redistribution of this software, in source or object code forms, with or 11218885Sdim * without modifications are expressly permitted by Whistle Communications; 12218885Sdim * provided, however, that: 13218885Sdim * 1. Any and all reproductions of the source or object code must include the 14218885Sdim * copyright notice above and the following disclaimer of warranties; and 15218885Sdim * 2. No rights are granted, in any manner or form, to use Whistle 16218885Sdim * Communications, Inc. trademarks, including the mark "WHISTLE 17218885Sdim * COMMUNICATIONS" on advertising, endorsements, or otherwise except as 18218885Sdim * such appears in the above copyright notice or in the software. 19218885Sdim * 20218885Sdim * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND 21249423Sdim * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO 22218885Sdim * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, 23218885Sdim * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF 24218885Sdim * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. 25218885Sdim * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY 26218885Sdim * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS 27218885Sdim * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. 28218885Sdim * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES 29218885Sdim * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING 30263508Sdim * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 31218885Sdim * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR 32218885Sdim * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY 33218885Sdim * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34218885Sdim * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 35218885Sdim * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY 36218885Sdim * OF SUCH DAMAGE. 37218885Sdim * 38218885Sdim * Author: Archie Cobbs <archie@freebsd.org> 39218885Sdim * 40218885Sdim * $FreeBSD: head/sys/netgraph/ng_async.c 227293 2011-11-07 06:44:47Z ed $ 41218885Sdim * $Whistle: ng_async.c,v 1.17 1999/11/01 09:24:51 julian Exp $ 42263508Sdim */ 43263508Sdim 44218885Sdim/* 45218885Sdim * This node type implements a PPP style sync <-> async converter. 46218885Sdim * See RFC 1661 for details of how asynchronous encoding works. 47218885Sdim */ 48218885Sdim 49218885Sdim#include <sys/param.h> 50263508Sdim#include <sys/systm.h> 51263508Sdim#include <sys/kernel.h> 52218885Sdim#include <sys/mbuf.h> 53218885Sdim#include <sys/malloc.h> 54218885Sdim#include <sys/errno.h> 55218885Sdim 56218885Sdim#include <netgraph/ng_message.h> 57218885Sdim#include <netgraph/netgraph.h> 58218885Sdim#include <netgraph/ng_async.h> 59218885Sdim#include <netgraph/ng_parse.h> 60218885Sdim 61218885Sdim#include <net/ppp_defs.h> 62218885Sdim 63263508Sdim#ifdef NG_SEPARATE_MALLOC 64263508Sdimstatic MALLOC_DEFINE(M_NETGRAPH_ASYNC, "netgraph_async", "netgraph async node"); 65263508Sdim#else 66218885Sdim#define M_NETGRAPH_ASYNC M_NETGRAPH 67263508Sdim#endif 68263508Sdim 69218885Sdim 70218885Sdim/* Async decode state */ 71218885Sdim#define MODE_HUNT 0 72218885Sdim#define MODE_NORMAL 1 73218885Sdim#define MODE_ESC 2 74218885Sdim 75218885Sdim/* Private data structure */ 76218885Sdimstruct ng_async_private { 77218885Sdim node_p node; /* Our node */ 78218885Sdim hook_p async; /* Asynchronous side */ 79218885Sdim hook_p sync; /* Synchronous side */ 80263508Sdim u_char amode; /* Async hunt/esape mode */ 81218885Sdim u_int16_t fcs; /* Decoded async FCS (so far) */ 82218885Sdim u_char *abuf; /* Buffer to encode sync into */ 83263508Sdim u_char *sbuf; /* Buffer to decode async into */ 84218885Sdim u_int slen; /* Length of data in sbuf */ 85218885Sdim long lasttime; /* Time of last async packet sent */ 86218885Sdim struct ng_async_cfg cfg; /* Configuration */ 87218885Sdim struct ng_async_stat stats; /* Statistics */ 88218885Sdim}; 89218885Sdimtypedef struct ng_async_private *sc_p; 90218885Sdim 91218885Sdim/* Useful macros */ 92218885Sdim#define ASYNC_BUF_SIZE(smru) (2 * (smru) + 10) 93218885Sdim#define SYNC_BUF_SIZE(amru) ((amru) + 10) 94218885Sdim#define ERROUT(x) do { error = (x); goto done; } while (0) 95218885Sdim 96218885Sdim/* Netgraph methods */ 97218885Sdimstatic ng_constructor_t nga_constructor; 98218885Sdimstatic ng_rcvdata_t nga_rcvdata; 99218885Sdimstatic ng_rcvmsg_t nga_rcvmsg; 100218885Sdimstatic ng_shutdown_t nga_shutdown; 101218885Sdimstatic ng_newhook_t nga_newhook; 102218885Sdimstatic ng_disconnect_t nga_disconnect; 103218885Sdim 104218885Sdim/* Helper stuff */ 105218885Sdimstatic int nga_rcv_sync(const sc_p sc, item_p item); 106218885Sdimstatic int nga_rcv_async(const sc_p sc, item_p item); 107218885Sdim 108218885Sdim/* Parse type for struct ng_async_cfg */ 109218885Sdimstatic const struct ng_parse_struct_field nga_config_type_fields[] 110218885Sdim = NG_ASYNC_CONFIG_TYPE_INFO; 111218885Sdimstatic const struct ng_parse_type nga_config_type = { 112218885Sdim &ng_parse_struct_type, 113218885Sdim &nga_config_type_fields 114218885Sdim}; 115218885Sdim 116218885Sdim/* Parse type for struct ng_async_stat */ 117263508Sdimstatic const struct ng_parse_struct_field nga_stats_type_fields[] 118218885Sdim = NG_ASYNC_STATS_TYPE_INFO; 119218885Sdimstatic const struct ng_parse_type nga_stats_type = { 120218885Sdim &ng_parse_struct_type, 121218885Sdim &nga_stats_type_fields 122218885Sdim}; 123218885Sdim 124218885Sdim/* List of commands and how to convert arguments to/from ASCII */ 125218885Sdimstatic const struct ng_cmdlist nga_cmdlist[] = { 126263508Sdim { 127263508Sdim NGM_ASYNC_COOKIE, 128218885Sdim NGM_ASYNC_CMD_SET_CONFIG, 129218885Sdim "setconfig", 130218885Sdim &nga_config_type, 131218885Sdim NULL 132218885Sdim }, 133218885Sdim { 134218885Sdim NGM_ASYNC_COOKIE, 135263508Sdim NGM_ASYNC_CMD_GET_CONFIG, 136263508Sdim "getconfig", 137263508Sdim NULL, 138263508Sdim &nga_config_type 139218885Sdim }, 140218885Sdim { 141263508Sdim NGM_ASYNC_COOKIE, 142218885Sdim NGM_ASYNC_CMD_GET_STATS, 143263508Sdim "getstats", 144218885Sdim NULL, 145218885Sdim &nga_stats_type 146218885Sdim }, 147218885Sdim { 148218885Sdim NGM_ASYNC_COOKIE, 149218885Sdim NGM_ASYNC_CMD_CLR_STATS, 150218885Sdim "clrstats", 151218885Sdim &nga_stats_type, 152218885Sdim NULL 153218885Sdim }, 154218885Sdim { 0 } 155218885Sdim}; 156218885Sdim 157218885Sdim/* Define the netgraph node type */ 158218885Sdimstatic struct ng_type typestruct = { 159218885Sdim .version = NG_ABI_VERSION, 160218885Sdim .name = NG_ASYNC_NODE_TYPE, 161218885Sdim .constructor = nga_constructor, 162263508Sdim .rcvmsg = nga_rcvmsg, 163218885Sdim .shutdown = nga_shutdown, 164263508Sdim .newhook = nga_newhook, 165263508Sdim .rcvdata = nga_rcvdata, 166218885Sdim .disconnect = nga_disconnect, 167218885Sdim .cmdlist = nga_cmdlist 168218885Sdim}; 169218885SdimNETGRAPH_INIT(async, &typestruct); 170218885Sdim 171263508Sdim/* CRC table */ 172218885Sdimstatic const u_int16_t fcstab[]; 173263508Sdim 174263508Sdim/****************************************************************** 175218885Sdim NETGRAPH NODE METHODS 176218885Sdim******************************************************************/ 177218885Sdim 178218885Sdim/* 179218885Sdim * Initialize a new node 180218885Sdim */ 181218885Sdimstatic int 182263508Sdimnga_constructor(node_p node) 183263508Sdim{ 184218885Sdim sc_p sc; 185263508Sdim 186263508Sdim sc = malloc(sizeof(*sc), M_NETGRAPH_ASYNC, M_WAITOK | M_ZERO); 187263508Sdim sc->amode = MODE_HUNT; 188263508Sdim sc->cfg.accm = ~0; 189218885Sdim sc->cfg.amru = NG_ASYNC_DEFAULT_MRU; 190218885Sdim sc->cfg.smru = NG_ASYNC_DEFAULT_MRU; 191263508Sdim sc->abuf = malloc(ASYNC_BUF_SIZE(sc->cfg.smru), 192218885Sdim M_NETGRAPH_ASYNC, M_WAITOK); 193263508Sdim sc->sbuf = malloc(SYNC_BUF_SIZE(sc->cfg.amru), 194218885Sdim M_NETGRAPH_ASYNC, M_WAITOK); 195263508Sdim NG_NODE_SET_PRIVATE(node, sc); 196218885Sdim sc->node = node; 197218885Sdim return (0); 198218885Sdim} 199218885Sdim 200263508Sdim/* 201263508Sdim * Reserve a hook for a pending connection 202218885Sdim */ 203218885Sdimstatic int 204263508Sdimnga_newhook(node_p node, hook_p hook, const char *name) 205218885Sdim{ 206218885Sdim const sc_p sc = NG_NODE_PRIVATE(node); 207218885Sdim hook_p *hookp; 208263508Sdim 209218885Sdim if (!strcmp(name, NG_ASYNC_HOOK_ASYNC)) { 210218885Sdim /* 211218885Sdim * We use a static buffer here so only one packet 212218885Sdim * at a time can be allowed to travel in this direction. 213263508Sdim * Force Writer semantics. 214218885Sdim */ 215263508Sdim NG_HOOK_FORCE_WRITER(hook); 216263508Sdim hookp = &sc->async; 217263508Sdim } else if (!strcmp(name, NG_ASYNC_HOOK_SYNC)) { 218263508Sdim /* 219218885Sdim * We use a static state here so only one packet 220218885Sdim * at a time can be allowed to travel in this direction. 221218885Sdim * Force Writer semantics. 222218885Sdim * Since we set this for both directions 223218885Sdim * we might as well set it for the whole node 224218885Sdim * bit I haven;t done that (yet). 225218885Sdim */ 226263508Sdim NG_HOOK_FORCE_WRITER(hook); 227218885Sdim hookp = &sc->sync; 228218885Sdim } else { 229218885Sdim return (EINVAL); 230218885Sdim } 231263508Sdim if (*hookp) /* actually can't happen I think [JRE] */ 232263508Sdim return (EISCONN); 233218885Sdim *hookp = hook; 234218885Sdim return (0); 235218885Sdim} 236263508Sdim 237218885Sdim/* 238218885Sdim * Receive incoming data 239218885Sdim */ 240218885Sdimstatic int 241218885Sdimnga_rcvdata(hook_p hook, item_p item) 242218885Sdim{ 243263508Sdim const sc_p sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 244263508Sdim 245218885Sdim if (hook == sc->sync) 246218885Sdim return (nga_rcv_sync(sc, item)); 247218885Sdim if (hook == sc->async) 248263508Sdim return (nga_rcv_async(sc, item)); 249218885Sdim panic("%s", __func__); 250218885Sdim} 251218885Sdim 252218885Sdim/* 253218885Sdim * Receive incoming control message 254263508Sdim */ 255263508Sdimstatic int 256218885Sdimnga_rcvmsg(node_p node, item_p item, hook_p lasthook) 257218885Sdim{ 258218885Sdim const sc_p sc = NG_NODE_PRIVATE(node); 259263508Sdim struct ng_mesg *resp = NULL; 260263508Sdim int error = 0; 261218885Sdim struct ng_mesg *msg; 262218885Sdim 263218885Sdim NGI_GET_MSG(item, msg); 264218885Sdim switch (msg->header.typecookie) { 265218885Sdim case NGM_ASYNC_COOKIE: 266218885Sdim switch (msg->header.cmd) { 267263508Sdim case NGM_ASYNC_CMD_GET_STATS: 268218885Sdim NG_MKRESPONSE(resp, msg, sizeof(sc->stats), M_NOWAIT); 269218885Sdim if (resp == NULL) 270218885Sdim ERROUT(ENOMEM); 271218885Sdim *((struct ng_async_stat *) resp->data) = sc->stats; 272218885Sdim break; 273263508Sdim case NGM_ASYNC_CMD_CLR_STATS: 274263508Sdim bzero(&sc->stats, sizeof(sc->stats)); 275218885Sdim break; 276218885Sdim case NGM_ASYNC_CMD_SET_CONFIG: 277263508Sdim { 278218885Sdim struct ng_async_cfg *const cfg = 279263508Sdim (struct ng_async_cfg *) msg->data; 280218885Sdim u_char *buf; 281218885Sdim 282218885Sdim if (msg->header.arglen != sizeof(*cfg)) 283218885Sdim ERROUT(EINVAL); 284218885Sdim if (cfg->amru < NG_ASYNC_MIN_MRU 285218885Sdim || cfg->amru > NG_ASYNC_MAX_MRU 286218885Sdim || cfg->smru < NG_ASYNC_MIN_MRU 287218885Sdim || cfg->smru > NG_ASYNC_MAX_MRU) 288218885Sdim ERROUT(EINVAL); 289218885Sdim cfg->enabled = !!cfg->enabled; /* normalize */ 290263508Sdim if (cfg->smru > sc->cfg.smru) { /* reallocate buffer */ 291218885Sdim buf = malloc(ASYNC_BUF_SIZE(cfg->smru), 292218885Sdim M_NETGRAPH_ASYNC, M_NOWAIT); 293218885Sdim if (!buf) 294218885Sdim ERROUT(ENOMEM); 295218885Sdim free(sc->abuf, M_NETGRAPH_ASYNC); 296218885Sdim sc->abuf = buf; 297263508Sdim } 298263508Sdim if (cfg->amru > sc->cfg.amru) { /* reallocate buffer */ 299218885Sdim buf = malloc(SYNC_BUF_SIZE(cfg->amru), 300218885Sdim M_NETGRAPH_ASYNC, M_NOWAIT); 301263508Sdim if (!buf) 302263508Sdim ERROUT(ENOMEM); 303218885Sdim free(sc->sbuf, M_NETGRAPH_ASYNC); 304218885Sdim sc->sbuf = buf; 305218885Sdim sc->amode = MODE_HUNT; 306218885Sdim sc->slen = 0; 307263508Sdim } 308263508Sdim if (!cfg->enabled) { 309218885Sdim sc->amode = MODE_HUNT; 310218885Sdim sc->slen = 0; 311218885Sdim } 312218885Sdim sc->cfg = *cfg; 313263508Sdim break; 314218885Sdim } 315218885Sdim case NGM_ASYNC_CMD_GET_CONFIG: 316218885Sdim NG_MKRESPONSE(resp, msg, sizeof(sc->cfg), M_NOWAIT); 317218885Sdim if (!resp) 318218885Sdim ERROUT(ENOMEM); 319263508Sdim *((struct ng_async_cfg *) resp->data) = sc->cfg; 320218885Sdim break; 321218885Sdim default: 322218885Sdim ERROUT(EINVAL); 323218885Sdim } 324218885Sdim break; 325218885Sdim default: 326218885Sdim ERROUT(EINVAL); 327218885Sdim } 328218885Sdimdone: 329218885Sdim NG_RESPOND_MSG(error, node, item, resp); 330218885Sdim NG_FREE_MSG(msg); 331218885Sdim return (error); 332218885Sdim} 333218885Sdim 334218885Sdim/* 335218885Sdim * Shutdown this node 336218885Sdim */ 337218885Sdimstatic int 338218885Sdimnga_shutdown(node_p node) 339218885Sdim{ 340218885Sdim const sc_p sc = NG_NODE_PRIVATE(node); 341218885Sdim 342218885Sdim free(sc->abuf, M_NETGRAPH_ASYNC); 343218885Sdim free(sc->sbuf, M_NETGRAPH_ASYNC); 344218885Sdim bzero(sc, sizeof(*sc)); 345218885Sdim free(sc, M_NETGRAPH_ASYNC); 346218885Sdim NG_NODE_SET_PRIVATE(node, NULL); 347218885Sdim NG_NODE_UNREF(node); 348218885Sdim return (0); 349218885Sdim} 350218885Sdim 351263508Sdim/* 352218885Sdim * Lose a hook. When both hooks go away, we disappear. 353218885Sdim */ 354218885Sdimstatic int 355263508Sdimnga_disconnect(hook_p hook) 356263508Sdim{ 357218885Sdim const sc_p sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 358218885Sdim hook_p *hookp; 359218885Sdim 360263508Sdim if (hook == sc->async) 361263508Sdim hookp = &sc->async; 362263508Sdim else if (hook == sc->sync) 363263508Sdim hookp = &sc->sync; 364218885Sdim else 365218885Sdim panic("%s", __func__); 366218885Sdim if (!*hookp) 367218885Sdim panic("%s 2", __func__); 368218885Sdim *hookp = NULL; 369218885Sdim bzero(&sc->stats, sizeof(sc->stats)); 370218885Sdim sc->lasttime = 0; 371218885Sdim if ((NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0) 372218885Sdim && (NG_NODE_IS_VALID(NG_HOOK_NODE(hook)))) 373218885Sdim ng_rmnode_self(NG_HOOK_NODE(hook)); 374218885Sdim return (0); 375218885Sdim} 376218885Sdim 377218885Sdim/****************************************************************** 378263508Sdim INTERNAL HELPER STUFF 379218885Sdim******************************************************************/ 380218885Sdim 381218885Sdim/* 382263508Sdim * Encode a byte into the async buffer 383263508Sdim */ 384218885Sdimstatic __inline void 385218885Sdimnga_async_add(const sc_p sc, u_int16_t *fcs, u_int32_t accm, int *len, u_char x) 386218885Sdim{ 387263508Sdim *fcs = PPP_FCS(*fcs, x); 388263508Sdim if ((x < 32 && ((1 << x) & accm)) 389263508Sdim || (x == PPP_ESCAPE) 390263508Sdim || (x == PPP_FLAG)) { 391218885Sdim sc->abuf[(*len)++] = PPP_ESCAPE; 392218885Sdim x ^= PPP_TRANS; 393218885Sdim } 394218885Sdim sc->abuf[(*len)++] = x; 395218885Sdim} 396263508Sdim 397218885Sdim/* 398218885Sdim * Receive incoming synchronous data. 399218885Sdim */ 400218885Sdimstatic int 401218885Sdimnga_rcv_sync(const sc_p sc, item_p item) 402218885Sdim{ 403218885Sdim struct ifnet *rcvif; 404218885Sdim int alen, error = 0; 405263508Sdim struct timeval time; 406263508Sdim u_int16_t fcs, fcs0; 407263508Sdim u_int32_t accm; 408218885Sdim struct mbuf *m; 409218885Sdim 410218885Sdim 411263508Sdim#define ADD_BYTE(x) nga_async_add(sc, &fcs, accm, &alen, (x)) 412263508Sdim 413218885Sdim /* Check for bypass mode */ 414218885Sdim if (!sc->cfg.enabled) { 415218885Sdim NG_FWD_ITEM_HOOK(error, item, sc->async ); 416218885Sdim return (error); 417263508Sdim } 418218885Sdim NGI_GET_M(item, m); 419218885Sdim 420263508Sdim rcvif = m->m_pkthdr.rcvif; 421234353Sdim 422234353Sdim /* Get ACCM; special case LCP frames, which use full ACCM */ 423234353Sdim accm = sc->cfg.accm; 424234353Sdim if (m->m_pkthdr.len >= 4) { 425234353Sdim static const u_char lcphdr[4] = { 426218885Sdim PPP_ALLSTATIONS, 427218885Sdim PPP_UI, 428218885Sdim (u_char)(PPP_LCP >> 8), 429218885Sdim (u_char)(PPP_LCP & 0xff) 430218885Sdim }; 431263508Sdim u_char buf[4]; 432263508Sdim 433218885Sdim m_copydata(m, 0, 4, (caddr_t)buf); 434263508Sdim if (bcmp(buf, &lcphdr, 4) == 0) 435263508Sdim accm = ~0; 436263508Sdim } 437263508Sdim 438218885Sdim /* Check for overflow */ 439218885Sdim if (m->m_pkthdr.len > sc->cfg.smru) { 440263508Sdim sc->stats.syncOverflows++; 441218885Sdim NG_FREE_M(m); 442218885Sdim NG_FREE_ITEM(item); 443218885Sdim return (EMSGSIZE); 444263508Sdim } 445218885Sdim 446263508Sdim /* Update stats */ 447263508Sdim sc->stats.syncFrames++; 448263508Sdim sc->stats.syncOctets += m->m_pkthdr.len; 449218885Sdim 450263508Sdim /* Initialize async encoded version of input mbuf */ 451263508Sdim alen = 0; 452218885Sdim fcs = PPP_INITFCS; 453218885Sdim 454218885Sdim /* Add beginning sync flag if it's been long enough to need one */ 455218885Sdim getmicrotime(&time); 456218885Sdim if (time.tv_sec >= sc->lasttime + 1) { 457218885Sdim sc->abuf[alen++] = PPP_FLAG; 458218885Sdim sc->lasttime = time.tv_sec; 459218885Sdim } 460218885Sdim 461218885Sdim /* Add packet payload */ 462218885Sdim while (m != NULL) { 463218885Sdim while (m->m_len > 0) { 464218885Sdim ADD_BYTE(*mtod(m, u_char *)); 465218885Sdim m->m_data++; 466218885Sdim m->m_len--; 467218885Sdim } 468218885Sdim m = m_free(m); 469 } 470 471 /* Add checksum and final sync flag */ 472 fcs0 = fcs; 473 ADD_BYTE(~fcs0 & 0xff); 474 ADD_BYTE(~fcs0 >> 8); 475 sc->abuf[alen++] = PPP_FLAG; 476 477 /* Put frame in an mbuf and ship it off */ 478 if (!(m = m_devget(sc->abuf, alen, 0, rcvif, NULL))) { 479 NG_FREE_ITEM(item); 480 error = ENOBUFS; 481 } else { 482 NG_FWD_NEW_DATA(error, item, sc->async, m); 483 } 484 return (error); 485} 486 487/* 488 * Receive incoming asynchronous data 489 * XXX Technically, we should strip out incoming characters 490 * that are in our ACCM. Not sure if this is good or not. 491 */ 492static int 493nga_rcv_async(const sc_p sc, item_p item) 494{ 495 struct ifnet *rcvif; 496 int error; 497 struct mbuf *m; 498 499 if (!sc->cfg.enabled) { 500 NG_FWD_ITEM_HOOK(error, item, sc->sync); 501 return (error); 502 } 503 NGI_GET_M(item, m); 504 rcvif = m->m_pkthdr.rcvif; 505 while (m) { 506 struct mbuf *n; 507 508 for (; m->m_len > 0; m->m_data++, m->m_len--) { 509 u_char ch = *mtod(m, u_char *); 510 511 sc->stats.asyncOctets++; 512 if (ch == PPP_FLAG) { /* Flag overrides everything */ 513 int skip = 0; 514 515 /* Check for runts */ 516 if (sc->slen < 2) { 517 if (sc->slen > 0) 518 sc->stats.asyncRunts++; 519 goto reset; 520 } 521 522 /* Verify CRC */ 523 if (sc->fcs != PPP_GOODFCS) { 524 sc->stats.asyncBadCheckSums++; 525 goto reset; 526 } 527 sc->slen -= 2; 528 529 /* Strip address and control fields */ 530 if (sc->slen >= 2 531 && sc->sbuf[0] == PPP_ALLSTATIONS 532 && sc->sbuf[1] == PPP_UI) 533 skip = 2; 534 535 /* Check for frame too big */ 536 if (sc->slen - skip > sc->cfg.amru) { 537 sc->stats.asyncOverflows++; 538 goto reset; 539 } 540 541 /* OK, ship it out */ 542 if ((n = m_devget(sc->sbuf + skip, 543 sc->slen - skip, 0, rcvif, NULL))) { 544 if (item) { /* sets NULL -> item */ 545 NG_FWD_NEW_DATA(error, item, 546 sc->sync, n); 547 } else { 548 NG_SEND_DATA_ONLY(error, 549 sc->sync ,n); 550 } 551 } 552 sc->stats.asyncFrames++; 553reset: 554 sc->amode = MODE_NORMAL; 555 sc->fcs = PPP_INITFCS; 556 sc->slen = 0; 557 continue; 558 } 559 switch (sc->amode) { 560 case MODE_NORMAL: 561 if (ch == PPP_ESCAPE) { 562 sc->amode = MODE_ESC; 563 continue; 564 } 565 break; 566 case MODE_ESC: 567 ch ^= PPP_TRANS; 568 sc->amode = MODE_NORMAL; 569 break; 570 case MODE_HUNT: 571 default: 572 continue; 573 } 574 575 /* Add byte to frame */ 576 if (sc->slen >= SYNC_BUF_SIZE(sc->cfg.amru)) { 577 sc->stats.asyncOverflows++; 578 sc->amode = MODE_HUNT; 579 sc->slen = 0; 580 } else { 581 sc->sbuf[sc->slen++] = ch; 582 sc->fcs = PPP_FCS(sc->fcs, ch); 583 } 584 } 585 m = m_free(m); 586 } 587 if (item) 588 NG_FREE_ITEM(item); 589 return (0); 590} 591 592/* 593 * CRC table 594 * 595 * Taken from RFC 1171 Appendix B 596 */ 597static const u_int16_t fcstab[256] = { 598 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, 599 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, 600 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, 601 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, 602 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, 603 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, 604 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, 605 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, 606 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, 607 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, 608 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, 609 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, 610 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, 611 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, 612 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, 613 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, 614 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, 615 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, 616 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, 617 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, 618 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, 619 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, 620 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, 621 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, 622 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, 623 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, 624 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, 625 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, 626 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, 627 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, 628 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, 629 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 630}; 631