ng_async.c revision 131575
165123Speter 265123Speter/* 365123Speter * ng_async.c 465123Speter * 565123Speter * Copyright (c) 1996-1999 Whistle Communications, Inc. 665123Speter * All rights reserved. 765123Speter * 865123Speter * Subject to the following obligations and disclaimer of warranty, use and 965123Speter * redistribution of this software, in source or object code forms, with or 1065123Speter * without modifications are expressly permitted by Whistle Communications; 1165123Speter * provided, however, that: 1265123Speter * 1. Any and all reproductions of the source or object code must include the 1365123Speter * copyright notice above and the following disclaimer of warranties; and 1465123Speter * 2. No rights are granted, in any manner or form, to use Whistle 1565123Speter * Communications, Inc. trademarks, including the mark "WHISTLE 1665123Speter * COMMUNICATIONS" on advertising, endorsements, or otherwise except as 1765123Speter * such appears in the above copyright notice or in the software. 1865123Speter * 1965123Speter * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND 2065123Speter * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO 2165123Speter * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, 2265123Speter * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF 2365123Speter * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. 2465123Speter * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY 2565123Speter * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS 2665123Speter * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. 2765123Speter * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES 2865123Speter * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING 2965123Speter * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 3065123Speter * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR 3165123Speter * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY 3265123Speter * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3365123Speter * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 3465123Speter * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY 3565123Speter * OF SUCH DAMAGE. 3665123Speter * 3765123Speter * Author: Archie Cobbs <archie@freebsd.org> 3865123Speter * 3965123Speter * $FreeBSD: head/sys/netgraph/ng_async.c 131575 2004-07-04 16:11:03Z stefanf $ 4065123Speter * $Whistle: ng_async.c,v 1.17 1999/11/01 09:24:51 julian Exp $ 4165123Speter */ 4265123Speter 4365123Speter/* 4465123Speter * This node type implements a PPP style sync <-> async converter. 4565123Speter * See RFC 1661 for details of how asynchronous encoding works. 4665123Speter */ 4765123Speter 4865123Speter#include <sys/param.h> 4965123Speter#include <sys/systm.h> 5065123Speter#include <sys/kernel.h> 5165123Speter#include <sys/mbuf.h> 5265123Speter#include <sys/malloc.h> 5365123Speter#include <sys/errno.h> 5465123Speter 5565123Speter#include <netgraph/ng_message.h> 5665123Speter#include <netgraph/netgraph.h> 5765123Speter#include <netgraph/ng_async.h> 5865123Speter#include <netgraph/ng_parse.h> 5965123Speter 6065123Speter#include <net/ppp_defs.h> 6165123Speter 6265123Speter#ifdef NG_SEPARATE_MALLOC 6365123SpeterMALLOC_DEFINE(M_NETGRAPH_ASYNC, "netgraph_async", "netgraph async node "); 6465123Speter#else 6565123Speter#define M_NETGRAPH_ASYNC M_NETGRAPH 6665126Speter#endif 6765123Speter 6865123Speter 6965123Speter/* Async decode state */ 7065123Speter#define MODE_HUNT 0 7165123Speter#define MODE_NORMAL 1 7265123Speter#define MODE_ESC 2 7365123Speter 7465123Speter/* Private data structure */ 7565123Speterstruct ng_async_private { 7665123Speter node_p node; /* Our node */ 7765123Speter hook_p async; /* Asynchronous side */ 7865123Speter hook_p sync; /* Synchronous side */ 7965123Speter u_char amode; /* Async hunt/esape mode */ 8065123Speter u_int16_t fcs; /* Decoded async FCS (so far) */ 8165123Speter u_char *abuf; /* Buffer to encode sync into */ 8265123Speter u_char *sbuf; /* Buffer to decode async into */ 8365123Speter u_int slen; /* Length of data in sbuf */ 8465123Speter long lasttime; /* Time of last async packet sent */ 8565123Speter struct ng_async_cfg cfg; /* Configuration */ 8665123Speter struct ng_async_stat stats; /* Statistics */ 8765123Speter}; 8865123Spetertypedef struct ng_async_private *sc_p; 8965123Speter 9065123Speter/* Useful macros */ 9165123Speter#define ASYNC_BUF_SIZE(smru) (2 * (smru) + 10) 9265123Speter#define SYNC_BUF_SIZE(amru) ((amru) + 10) 9365123Speter#define ERROUT(x) do { error = (x); goto done; } while (0) 9465123Speter 9565123Speter/* Netgraph methods */ 9665123Speterstatic ng_constructor_t nga_constructor; 9765123Speterstatic ng_rcvdata_t nga_rcvdata; 9865123Speterstatic ng_rcvmsg_t nga_rcvmsg; 9965123Speterstatic ng_shutdown_t nga_shutdown; 10065123Speterstatic ng_newhook_t nga_newhook; 10165123Speterstatic ng_disconnect_t nga_disconnect; 10265123Speter 10365127Speter/* Helper stuff */ 10465123Speterstatic int nga_rcv_sync(const sc_p sc, item_p item); 10565123Speterstatic int nga_rcv_async(const sc_p sc, item_p item); 10665123Speter 10765123Speter/* Parse type for struct ng_async_cfg */ 10865123Speterstatic const struct ng_parse_struct_field nga_config_type_fields[] 10965123Speter = NG_ASYNC_CONFIG_TYPE_INFO; 11065123Speterstatic const struct ng_parse_type nga_config_type = { 11165123Speter &ng_parse_struct_type, 11265123Speter &nga_config_type_fields 11365123Speter}; 11465123Speter 11565123Speter/* Parse type for struct ng_async_stat */ 11665123Speterstatic const struct ng_parse_struct_field nga_stats_type_fields[] 11765123Speter = NG_ASYNC_STATS_TYPE_INFO; 11865123Speterstatic const struct ng_parse_type nga_stats_type = { 11965123Speter &ng_parse_struct_type, 12065123Speter &nga_stats_type_fields 12165123Speter}; 12265127Speter 12365123Speter/* List of commands and how to convert arguments to/from ASCII */ 12465123Speterstatic const struct ng_cmdlist nga_cmdlist[] = { 12565123Speter { 12665123Speter NGM_ASYNC_COOKIE, 12765123Speter NGM_ASYNC_CMD_SET_CONFIG, 12865123Speter "setconfig", 12965123Speter &nga_config_type, 13065123Speter NULL 13165123Speter }, 13265123Speter { 13365123Speter NGM_ASYNC_COOKIE, 13465123Speter NGM_ASYNC_CMD_GET_CONFIG, 13565123Speter "getconfig", 13665123Speter NULL, 13765123Speter &nga_config_type 13865123Speter }, 13965123Speter { 14065123Speter NGM_ASYNC_COOKIE, 14165123Speter NGM_ASYNC_CMD_GET_STATS, 14265123Speter "getstats", 14365123Speter NULL, 14465123Speter &nga_stats_type 14565123Speter }, 14665123Speter { 14765123Speter NGM_ASYNC_COOKIE, 14865123Speter NGM_ASYNC_CMD_CLR_STATS, 14965123Speter "clrstats", 15065123Speter &nga_stats_type, 15165123Speter NULL 15265123Speter }, 15365123Speter { 0 } 15465123Speter}; 15565123Speter 15665123Speter/* Define the netgraph node type */ 15765123Speterstatic struct ng_type typestruct = { 15865123Speter .version = NG_ABI_VERSION, 15965123Speter .name = NG_ASYNC_NODE_TYPE, 16065123Speter .constructor = nga_constructor, 16165123Speter .rcvmsg = nga_rcvmsg, 16265123Speter .shutdown = nga_shutdown, 16365123Speter .newhook = nga_newhook, 16465123Speter .rcvdata = nga_rcvdata, 16565123Speter .disconnect = nga_disconnect, 16665123Speter .cmdlist = nga_cmdlist 16765123Speter}; 16865123SpeterNETGRAPH_INIT(async, &typestruct); 16965123Speter 17065123Speter/* CRC table */ 17165123Speterstatic const u_int16_t fcstab[]; 17265123Speter 17365123Speter/****************************************************************** 17465123Speter NETGRAPH NODE METHODS 17565123Speter******************************************************************/ 17665123Speter 17765123Speter/* 17865123Speter * Initialize a new node 17965123Speter */ 18065123Speterstatic int 18165123Speternga_constructor(node_p node) 18265123Speter{ 18365123Speter sc_p sc; 18465123Speter 18565123Speter MALLOC(sc, sc_p, sizeof(*sc), M_NETGRAPH_ASYNC, M_NOWAIT | M_ZERO); 18665123Speter if (sc == NULL) 18765123Speter return (ENOMEM); 18865123Speter sc->amode = MODE_HUNT; 18965123Speter sc->cfg.accm = ~0; 19065123Speter sc->cfg.amru = NG_ASYNC_DEFAULT_MRU; 19165123Speter sc->cfg.smru = NG_ASYNC_DEFAULT_MRU; 19265123Speter MALLOC(sc->abuf, u_char *, 19365123Speter ASYNC_BUF_SIZE(sc->cfg.smru), M_NETGRAPH_ASYNC, M_NOWAIT); 19465123Speter if (sc->abuf == NULL) 19565123Speter goto fail; 19665123Speter MALLOC(sc->sbuf, u_char *, 19765123Speter SYNC_BUF_SIZE(sc->cfg.amru), M_NETGRAPH_ASYNC, M_NOWAIT); 19865123Speter if (sc->sbuf == NULL) { 19965123Speter FREE(sc->abuf, M_NETGRAPH_ASYNC); 20065123Speterfail: 20165123Speter FREE(sc, M_NETGRAPH_ASYNC); 20265123Speter return (ENOMEM); 20365123Speter } 20465123Speter NG_NODE_SET_PRIVATE(node, sc); 20565123Speter sc->node = node; 20665123Speter return (0); 20765123Speter} 20865123Speter 20965123Speter/* 21065123Speter * Reserve a hook for a pending connection 21165123Speter */ 21265123Speterstatic int 21365123Speternga_newhook(node_p node, hook_p hook, const char *name) 21465123Speter{ 21565123Speter const sc_p sc = NG_NODE_PRIVATE(node); 21665123Speter hook_p *hookp; 21765123Speter 21865123Speter if (!strcmp(name, NG_ASYNC_HOOK_ASYNC)) { 21965123Speter /* 22065123Speter * We use a static buffer here so only one packet 22165123Speter * at a time can be allowed to travel in this direction. 22265123Speter * Force Writer semantics. 22365123Speter */ 22465123Speter NG_HOOK_FORCE_WRITER(hook); 22565123Speter hookp = &sc->async; 22665123Speter } else if (!strcmp(name, NG_ASYNC_HOOK_SYNC)) { 22765123Speter /* 22865123Speter * We use a static state here so only one packet 22965123Speter * at a time can be allowed to travel in this direction. 23065123Speter * Force Writer semantics. 23165123Speter * Since we set this for both directions 23265123Speter * we might as well set it for the whole node 23365123Speter * bit I haven;t done that (yet). 23465123Speter */ 23565123Speter NG_HOOK_FORCE_WRITER(hook); 23665123Speter hookp = &sc->sync; 23765123Speter } else { 23865123Speter return (EINVAL); 23965123Speter } 24065123Speter if (*hookp) /* actually can't happen I think [JRE] */ 24165123Speter return (EISCONN); 24265123Speter *hookp = hook; 24365123Speter return (0); 24465123Speter} 24565123Speter 24665123Speter/* 24765123Speter * Receive incoming data 24865123Speter */ 24965123Speterstatic int 25065123Speternga_rcvdata(hook_p hook, item_p item) 25165123Speter{ 25265123Speter const sc_p sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 25365123Speter 25465123Speter if (hook == sc->sync) 25565123Speter return (nga_rcv_sync(sc, item)); 25665123Speter if (hook == sc->async) 25765123Speter return (nga_rcv_async(sc, item)); 25865123Speter panic(__func__); 25965123Speter} 26065123Speter 26165123Speter/* 26265123Speter * Receive incoming control message 26365123Speter */ 26465123Speterstatic int 26565123Speternga_rcvmsg(node_p node, item_p item, hook_p lasthook) 26665123Speter{ 26765123Speter const sc_p sc = NG_NODE_PRIVATE(node); 26865123Speter struct ng_mesg *resp = NULL; 26965123Speter int error = 0; 27065123Speter struct ng_mesg *msg; 27165123Speter 27265123Speter NGI_GET_MSG(item, msg); 27365123Speter switch (msg->header.typecookie) { 27465123Speter case NGM_ASYNC_COOKIE: 27565123Speter switch (msg->header.cmd) { 27665123Speter case NGM_ASYNC_CMD_GET_STATS: 27765123Speter NG_MKRESPONSE(resp, msg, sizeof(sc->stats), M_NOWAIT); 27865123Speter if (resp == NULL) 27965123Speter ERROUT(ENOMEM); 28065123Speter *((struct ng_async_stat *) resp->data) = sc->stats; 28165123Speter break; 28265123Speter case NGM_ASYNC_CMD_CLR_STATS: 28365123Speter bzero(&sc->stats, sizeof(sc->stats)); 28465123Speter break; 28565123Speter case NGM_ASYNC_CMD_SET_CONFIG: 28665123Speter { 28765123Speter struct ng_async_cfg *const cfg = 28865123Speter (struct ng_async_cfg *) msg->data; 28965123Speter u_char *buf; 29065123Speter 29165123Speter if (msg->header.arglen != sizeof(*cfg)) 29265123Speter ERROUT(EINVAL); 29365123Speter if (cfg->amru < NG_ASYNC_MIN_MRU 29465123Speter || cfg->amru > NG_ASYNC_MAX_MRU 29565123Speter || cfg->smru < NG_ASYNC_MIN_MRU 29665123Speter || cfg->smru > NG_ASYNC_MAX_MRU) 29765123Speter ERROUT(EINVAL); 29865123Speter cfg->enabled = !!cfg->enabled; /* normalize */ 29965123Speter if (cfg->smru > sc->cfg.smru) { /* reallocate buffer */ 30065123Speter MALLOC(buf, u_char *, ASYNC_BUF_SIZE(cfg->smru), 30165123Speter M_NETGRAPH_ASYNC, M_NOWAIT); 30265123Speter if (!buf) 30365123Speter ERROUT(ENOMEM); 30465123Speter FREE(sc->abuf, M_NETGRAPH_ASYNC); 30565123Speter sc->abuf = buf; 30665123Speter } 30765123Speter if (cfg->amru > sc->cfg.amru) { /* reallocate buffer */ 30865123Speter MALLOC(buf, u_char *, SYNC_BUF_SIZE(cfg->amru), 30965123Speter M_NETGRAPH_ASYNC, M_NOWAIT); 31065123Speter if (!buf) 31165123Speter ERROUT(ENOMEM); 31265123Speter FREE(sc->sbuf, M_NETGRAPH_ASYNC); 31365123Speter sc->sbuf = buf; 31465123Speter sc->amode = MODE_HUNT; 31565123Speter sc->slen = 0; 31665123Speter } 31765123Speter if (!cfg->enabled) { 31865123Speter sc->amode = MODE_HUNT; 31965123Speter sc->slen = 0; 32065123Speter } 32165123Speter sc->cfg = *cfg; 32265123Speter break; 32365123Speter } 32465123Speter case NGM_ASYNC_CMD_GET_CONFIG: 32565123Speter NG_MKRESPONSE(resp, msg, sizeof(sc->cfg), M_NOWAIT); 32665123Speter if (!resp) 32765123Speter ERROUT(ENOMEM); 32865123Speter *((struct ng_async_cfg *) resp->data) = sc->cfg; 32965123Speter break; 33065123Speter default: 33165123Speter ERROUT(EINVAL); 33265123Speter } 33365123Speter break; 33465123Speter default: 33565123Speter ERROUT(EINVAL); 33665123Speter } 33765123Speterdone: 33865123Speter NG_RESPOND_MSG(error, node, item, resp); 33965123Speter NG_FREE_MSG(msg); 34065123Speter return (error); 34165123Speter} 34265123Speter 34365123Speter/* 34465123Speter * Shutdown this node 34565123Speter */ 34665123Speterstatic int 34765123Speternga_shutdown(node_p node) 34865123Speter{ 34965123Speter const sc_p sc = NG_NODE_PRIVATE(node); 35065123Speter 35165123Speter FREE(sc->abuf, M_NETGRAPH_ASYNC); 35265123Speter FREE(sc->sbuf, M_NETGRAPH_ASYNC); 35365123Speter bzero(sc, sizeof(*sc)); 35465123Speter FREE(sc, M_NETGRAPH_ASYNC); 35565123Speter NG_NODE_SET_PRIVATE(node, NULL); 35665123Speter NG_NODE_UNREF(node); 35765125Speter return (0); 35865123Speter} 35965123Speter 36065123Speter/* 36165123Speter * Lose a hook. When both hooks go away, we disappear. 36265123Speter */ 36365123Speterstatic int 36465123Speternga_disconnect(hook_p hook) 36565123Speter{ 36665123Speter const sc_p sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 36765123Speter hook_p *hookp; 36865123Speter 36965123Speter if (hook == sc->async) 370 hookp = &sc->async; 371 else if (hook == sc->sync) 372 hookp = &sc->sync; 373 else 374 panic(__func__); 375 if (!*hookp) 376 panic("%s 2", __func__); 377 *hookp = NULL; 378 bzero(&sc->stats, sizeof(sc->stats)); 379 sc->lasttime = 0; 380 if ((NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0) 381 && (NG_NODE_IS_VALID(NG_HOOK_NODE(hook)))) 382 ng_rmnode_self(NG_HOOK_NODE(hook)); 383 return (0); 384} 385 386/****************************************************************** 387 INTERNAL HELPER STUFF 388******************************************************************/ 389 390/* 391 * Encode a byte into the async buffer 392 */ 393static __inline void 394nga_async_add(const sc_p sc, u_int16_t *fcs, u_int32_t accm, int *len, u_char x) 395{ 396 *fcs = PPP_FCS(*fcs, x); 397 if ((x < 32 && ((1 << x) & accm)) 398 || (x == PPP_ESCAPE) 399 || (x == PPP_FLAG)) { 400 sc->abuf[(*len)++] = PPP_ESCAPE; 401 x ^= PPP_TRANS; 402 } 403 sc->abuf[(*len)++] = x; 404} 405 406/* 407 * Receive incoming synchronous data. 408 */ 409static int 410nga_rcv_sync(const sc_p sc, item_p item) 411{ 412 struct ifnet *rcvif; 413 int alen, error = 0; 414 struct timeval time; 415 u_int16_t fcs, fcs0; 416 u_int32_t accm; 417 struct mbuf *m; 418 419 420#define ADD_BYTE(x) nga_async_add(sc, &fcs, accm, &alen, (x)) 421 422 /* Check for bypass mode */ 423 if (!sc->cfg.enabled) { 424 NG_FWD_ITEM_HOOK(error, item, sc->async ); 425 return (error); 426 } 427 NGI_GET_M(item, m); 428 429 rcvif = m->m_pkthdr.rcvif; 430 431 /* Get ACCM; special case LCP frames, which use full ACCM */ 432 accm = sc->cfg.accm; 433 if (m->m_pkthdr.len >= 4) { 434 static const u_char lcphdr[4] = { 435 PPP_ALLSTATIONS, 436 PPP_UI, 437 (u_char)(PPP_LCP >> 8), 438 (u_char)(PPP_LCP & 0xff) 439 }; 440 u_char buf[4]; 441 442 m_copydata(m, 0, 4, (caddr_t)buf); 443 if (bcmp(buf, &lcphdr, 4) == 0) 444 accm = ~0; 445 } 446 447 /* Check for overflow */ 448 if (m->m_pkthdr.len > sc->cfg.smru) { 449 sc->stats.syncOverflows++; 450 NG_FREE_M(m); 451 NG_FREE_ITEM(item); 452 return (EMSGSIZE); 453 } 454 455 /* Update stats */ 456 sc->stats.syncFrames++; 457 sc->stats.syncOctets += m->m_pkthdr.len; 458 459 /* Initialize async encoded version of input mbuf */ 460 alen = 0; 461 fcs = PPP_INITFCS; 462 463 /* Add beginning sync flag if it's been long enough to need one */ 464 getmicrotime(&time); 465 if (time.tv_sec >= sc->lasttime + 1) { 466 sc->abuf[alen++] = PPP_FLAG; 467 sc->lasttime = time.tv_sec; 468 } 469 470 /* Add packet payload */ 471 while (m != NULL) { 472 while (m->m_len > 0) { 473 ADD_BYTE(*mtod(m, u_char *)); 474 m->m_data++; 475 m->m_len--; 476 } 477 m = m_free(m); 478 } 479 480 /* Add checksum and final sync flag */ 481 fcs0 = fcs; 482 ADD_BYTE(~fcs0 & 0xff); 483 ADD_BYTE(~fcs0 >> 8); 484 sc->abuf[alen++] = PPP_FLAG; 485 486 /* Put frame in an mbuf and ship it off */ 487 if (!(m = m_devget(sc->abuf, alen, 0, rcvif, NULL))) { 488 NG_FREE_ITEM(item); 489 error = ENOBUFS; 490 } else { 491 NG_FWD_NEW_DATA(error, item, sc->async, m); 492 } 493 return (error); 494} 495 496/* 497 * Receive incoming asynchronous data 498 * XXX Technically, we should strip out incoming characters 499 * that are in our ACCM. Not sure if this is good or not. 500 */ 501static int 502nga_rcv_async(const sc_p sc, item_p item) 503{ 504 struct ifnet *rcvif; 505 int error; 506 struct mbuf *m; 507 508 if (!sc->cfg.enabled) { 509 NG_FWD_ITEM_HOOK(error, item, sc->sync); 510 return (error); 511 } 512 NGI_GET_M(item, m); 513 rcvif = m->m_pkthdr.rcvif; 514 while (m) { 515 struct mbuf *n; 516 517 for (; m->m_len > 0; m->m_data++, m->m_len--) { 518 u_char ch = *mtod(m, u_char *); 519 520 sc->stats.asyncOctets++; 521 if (ch == PPP_FLAG) { /* Flag overrides everything */ 522 int skip = 0; 523 524 /* Check for runts */ 525 if (sc->slen < 2) { 526 if (sc->slen > 0) 527 sc->stats.asyncRunts++; 528 goto reset; 529 } 530 531 /* Verify CRC */ 532 if (sc->fcs != PPP_GOODFCS) { 533 sc->stats.asyncBadCheckSums++; 534 goto reset; 535 } 536 sc->slen -= 2; 537 538 /* Strip address and control fields */ 539 if (sc->slen >= 2 540 && sc->sbuf[0] == PPP_ALLSTATIONS 541 && sc->sbuf[1] == PPP_UI) 542 skip = 2; 543 544 /* Check for frame too big */ 545 if (sc->slen - skip > sc->cfg.amru) { 546 sc->stats.asyncOverflows++; 547 goto reset; 548 } 549 550 /* OK, ship it out */ 551 if ((n = m_devget(sc->sbuf + skip, 552 sc->slen - skip, 0, rcvif, NULL))) { 553 if (item) { /* sets NULL -> item */ 554 NG_FWD_NEW_DATA(error, item, 555 sc->sync, n); 556 } else { 557 NG_SEND_DATA_ONLY(error, 558 sc->sync ,n); 559 } 560 } 561 sc->stats.asyncFrames++; 562reset: 563 sc->amode = MODE_NORMAL; 564 sc->fcs = PPP_INITFCS; 565 sc->slen = 0; 566 continue; 567 } 568 switch (sc->amode) { 569 case MODE_NORMAL: 570 if (ch == PPP_ESCAPE) { 571 sc->amode = MODE_ESC; 572 continue; 573 } 574 break; 575 case MODE_ESC: 576 ch ^= PPP_TRANS; 577 sc->amode = MODE_NORMAL; 578 break; 579 case MODE_HUNT: 580 default: 581 continue; 582 } 583 584 /* Add byte to frame */ 585 if (sc->slen >= SYNC_BUF_SIZE(sc->cfg.amru)) { 586 sc->stats.asyncOverflows++; 587 sc->amode = MODE_HUNT; 588 sc->slen = 0; 589 } else { 590 sc->sbuf[sc->slen++] = ch; 591 sc->fcs = PPP_FCS(sc->fcs, ch); 592 } 593 } 594 m = m_free(m); 595 } 596 if (item) 597 NG_FREE_ITEM(item); 598 return (0); 599} 600 601/* 602 * CRC table 603 * 604 * Taken from RFC 1171 Appendix B 605 */ 606static const u_int16_t fcstab[256] = { 607 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, 608 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, 609 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, 610 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, 611 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, 612 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, 613 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, 614 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, 615 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, 616 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, 617 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, 618 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, 619 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, 620 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, 621 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, 622 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, 623 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, 624 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, 625 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, 626 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, 627 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, 628 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, 629 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, 630 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, 631 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, 632 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, 633 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, 634 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, 635 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, 636 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, 637 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, 638 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 639}; 640