ng_async.c revision 129823
1228753Smm 2228753Smm/* 3248616Smm * ng_async.c 4228753Smm * 5228753Smm * Copyright (c) 1996-1999 Whistle Communications, Inc. 6228753Smm * All rights reserved. 7228753Smm * 8228753Smm * Subject to the following obligations and disclaimer of warranty, use and 9228753Smm * redistribution of this software, in source or object code forms, with or 10228753Smm * without modifications are expressly permitted by Whistle Communications; 11228753Smm * provided, however, that: 12228753Smm * 1. Any and all reproductions of the source or object code must include the 13228753Smm * copyright notice above and the following disclaimer of warranties; and 14228753Smm * 2. No rights are granted, in any manner or form, to use Whistle 15228753Smm * Communications, Inc. trademarks, including the mark "WHISTLE 16228753Smm * COMMUNICATIONS" on advertising, endorsements, or otherwise except as 17228753Smm * such appears in the above copyright notice or in the software. 18228753Smm * 19228753Smm * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND 20228753Smm * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO 21228753Smm * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, 22228753Smm * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF 23228753Smm * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. 24228753Smm * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY 25228753Smm * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS 26228753Smm * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. 27228763Smm * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES 28228753Smm * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING 29228753Smm * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 30228753Smm * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR 31228753Smm * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY 32228753Smm * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 33228753Smm * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 34228753Smm * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY 35228753Smm * OF SUCH DAMAGE. 36228753Smm * 37232153Smm * Author: Archie Cobbs <archie@freebsd.org> 38232153Smm * 39232153Smm * $FreeBSD: head/sys/netgraph/ng_async.c 129823 2004-05-29 00:51:19Z julian $ 40232153Smm * $Whistle: ng_async.c,v 1.17 1999/11/01 09:24:51 julian Exp $ 41248616Smm */ 42248616Smm 43228753Smm/* 44228753Smm * This node type implements a PPP style sync <-> async converter. 45228753Smm * See RFC 1661 for details of how asynchronous encoding works. 46228753Smm */ 47228753Smm 48228753Smm#include <sys/param.h> 49228753Smm#include <sys/systm.h> 50228753Smm#include <sys/kernel.h> 51228753Smm#include <sys/mbuf.h> 52228753Smm#include <sys/malloc.h> 53228753Smm#include <sys/errno.h> 54228753Smm 55228753Smm#include <netgraph/ng_message.h> 56228753Smm#include <netgraph/netgraph.h> 57232153Smm#include <netgraph/ng_async.h> 58228753Smm#include <netgraph/ng_parse.h> 59228753Smm 60248616Smm#include <net/ppp_defs.h> 61248616Smm 62228753Smm#ifdef NG_SEPARATE_MALLOC 63228753SmmMALLOC_DEFINE(M_NETGRAPH_ASYNC, "netgraph_async", "netgraph async node "); 64228753Smm#else 65228753Smm#define M_NETGRAPH_ASYNC M_NETGRAPH 66228753Smm#endif 67228753Smm 68228753Smm 69228753Smm/* Async decode state */ 70228753Smm#define MODE_HUNT 0 71228753Smm#define MODE_NORMAL 1 72228753Smm#define MODE_ESC 2 73228753Smm 74228753Smm/* Private data structure */ 75228753Smmstruct ng_async_private { 76228753Smm node_p node; /* Our node */ 77228753Smm hook_p async; /* Asynchronous side */ 78228753Smm hook_p sync; /* Synchronous side */ 79228753Smm u_char amode; /* Async hunt/esape mode */ 80228753Smm u_int16_t fcs; /* Decoded async FCS (so far) */ 81228753Smm u_char *abuf; /* Buffer to encode sync into */ 82228753Smm u_char *sbuf; /* Buffer to decode async into */ 83228753Smm u_int slen; /* Length of data in sbuf */ 84228753Smm long lasttime; /* Time of last async packet sent */ 85228753Smm struct ng_async_cfg cfg; /* Configuration */ 86228753Smm struct ng_async_stat stats; /* Statistics */ 87228753Smm}; 88228753Smmtypedef struct ng_async_private *sc_p; 89228753Smm 90228753Smm/* Useful macros */ 91228753Smm#define ASYNC_BUF_SIZE(smru) (2 * (smru) + 10) 92228753Smm#define SYNC_BUF_SIZE(amru) ((amru) + 10) 93228753Smm#define ERROUT(x) do { error = (x); goto done; } while (0) 94228753Smm 95228753Smm/* Netgraph methods */ 96228753Smmstatic ng_constructor_t nga_constructor; 97228753Smmstatic ng_rcvdata_t nga_rcvdata; 98228753Smmstatic ng_rcvmsg_t nga_rcvmsg; 99228753Smmstatic ng_shutdown_t nga_shutdown; 100228753Smmstatic ng_newhook_t nga_newhook; 101228753Smmstatic ng_disconnect_t nga_disconnect; 102228753Smm 103228753Smm/* Helper stuff */ 104228753Smmstatic int nga_rcv_sync(const sc_p sc, item_p item); 105228753Smmstatic int nga_rcv_async(const sc_p sc, item_p item); 106228753Smm 107228753Smm/* Parse type for struct ng_async_cfg */ 108228753Smmstatic const struct ng_parse_struct_field nga_config_type_fields[] 109228753Smm = NG_ASYNC_CONFIG_TYPE_INFO; 110228753Smmstatic const struct ng_parse_type nga_config_type = { 111228753Smm &ng_parse_struct_type, 112228753Smm &nga_config_type_fields 113228753Smm}; 114228753Smm 115232153Smm/* Parse type for struct ng_async_stat */ 116232153Smmstatic const struct ng_parse_struct_field nga_stats_type_fields[] 117232153Smm = NG_ASYNC_STATS_TYPE_INFO; 118232153Smmstatic const struct ng_parse_type nga_stats_type = { 119232153Smm &ng_parse_struct_type, 120232153Smm &nga_stats_type_fields 121232153Smm}; 122232153Smm 123232153Smm/* List of commands and how to convert arguments to/from ASCII */ 124232153Smmstatic const struct ng_cmdlist nga_cmdlist[] = { 125232153Smm { 126232153Smm NGM_ASYNC_COOKIE, 127232153Smm NGM_ASYNC_CMD_SET_CONFIG, 128232153Smm "setconfig", 129232153Smm &nga_config_type, 130232153Smm NULL 131232153Smm }, 132232153Smm { 133232153Smm NGM_ASYNC_COOKIE, 134232153Smm NGM_ASYNC_CMD_GET_CONFIG, 135232153Smm "getconfig", 136232153Smm NULL, 137232153Smm &nga_config_type 138232153Smm }, 139232153Smm { 140232153Smm NGM_ASYNC_COOKIE, 141232153Smm NGM_ASYNC_CMD_GET_STATS, 142232153Smm "getstats", 143232153Smm NULL, 144232153Smm &nga_stats_type 145232153Smm }, 146232153Smm { 147232153Smm NGM_ASYNC_COOKIE, 148232153Smm NGM_ASYNC_CMD_CLR_STATS, 149232153Smm "clrstats", 150232153Smm &nga_stats_type, 151232153Smm NULL 152232153Smm }, 153228753Smm { 0 } 154232153Smm}; 155228753Smm 156232153Smm/* Define the netgraph node type */ 157228753Smmstatic struct ng_type typestruct = { 158228753Smm .version = NG_ABI_VERSION, 159228753Smm .name = NG_ASYNC_NODE_TYPE, 160228753Smm .constructor = nga_constructor, 161228753Smm .rcvmsg = nga_rcvmsg, 162228753Smm .shutdown = nga_shutdown, 163228753Smm .newhook = nga_newhook, 164228753Smm .rcvdata = nga_rcvdata, 165228753Smm .disconnect = nga_disconnect, 166228753Smm .cmdlist = nga_cmdlist 167228753Smm}; 168228753SmmNETGRAPH_INIT(async, &typestruct); 169228753Smm 170232153Smm/* CRC table */ 171228753Smmstatic const u_int16_t fcstab[]; 172228753Smm 173228753Smm/****************************************************************** 174228753Smm NETGRAPH NODE METHODS 175228753Smm******************************************************************/ 176228753Smm 177228753Smm/* 178228753Smm * Initialize a new node 179228753Smm */ 180232153Smmstatic int 181228753Smmnga_constructor(node_p node) 182232153Smm{ 183228753Smm sc_p sc; 184228753Smm 185228753Smm MALLOC(sc, sc_p, sizeof(*sc), M_NETGRAPH_ASYNC, M_NOWAIT | M_ZERO); 186228753Smm if (sc == NULL) 187228753Smm return (ENOMEM); 188228753Smm sc->amode = MODE_HUNT; 189228753Smm sc->cfg.accm = ~0; 190228753Smm sc->cfg.amru = NG_ASYNC_DEFAULT_MRU; 191228753Smm sc->cfg.smru = NG_ASYNC_DEFAULT_MRU; 192228753Smm MALLOC(sc->abuf, u_char *, 193228753Smm ASYNC_BUF_SIZE(sc->cfg.smru), M_NETGRAPH_ASYNC, M_NOWAIT); 194228753Smm if (sc->abuf == NULL) 195228753Smm goto fail; 196228753Smm MALLOC(sc->sbuf, u_char *, 197228753Smm SYNC_BUF_SIZE(sc->cfg.amru), M_NETGRAPH_ASYNC, M_NOWAIT); 198228753Smm if (sc->sbuf == NULL) { 199228753Smm FREE(sc->abuf, M_NETGRAPH_ASYNC); 200228753Smmfail: 201228753Smm FREE(sc, M_NETGRAPH_ASYNC); 202228753Smm return (ENOMEM); 203228753Smm } 204228753Smm NG_NODE_SET_PRIVATE(node, sc); 205232153Smm sc->node = node; 206228753Smm return (0); 207228753Smm} 208228753Smm 209228753Smm/* 210228753Smm * Reserve a hook for a pending connection 211228753Smm */ 212228753Smmstatic int 213228753Smmnga_newhook(node_p node, hook_p hook, const char *name) 214228753Smm{ 215228753Smm const sc_p sc = NG_NODE_PRIVATE(node); 216228753Smm hook_p *hookp; 217228753Smm 218228753Smm if (!strcmp(name, NG_ASYNC_HOOK_ASYNC)) { 219228753Smm /* 220228753Smm * We use a static buffer here so only one packet 221232153Smm * at a time can be allowed to travel in this direction. 222228753Smm * Force Writer semantics. 223232153Smm */ 224228753Smm NG_HOOK_FORCE_WRITER(hook); 225228753Smm hookp = &sc->async; 226228753Smm } else if (!strcmp(name, NG_ASYNC_HOOK_SYNC)) { 227228753Smm /* 228248616Smm * We use a static state here so only one packet 229248616Smm * at a time can be allowed to travel in this direction. 230248616Smm * Force Writer semantics. 231248616Smm * Since we set this for both directions 232248616Smm * we might as well set it for the whole node 233248616Smm * bit I haven;t done that (yet). 234228753Smm */ 235248616Smm NG_HOOK_FORCE_WRITER(hook); 236232153Smm hookp = &sc->sync; 237248616Smm } else { 238248616Smm return (EINVAL); 239248616Smm } 240248616Smm if (*hookp) /* actually can't happen I think [JRE] */ 241248616Smm return (EISCONN); 242248616Smm *hookp = hook; 243248616Smm return (0); 244248616Smm} 245248616Smm 246248616Smm/* 247248616Smm * Receive incoming data 248248616Smm */ 249248616Smmstatic int 250248616Smmnga_rcvdata(hook_p hook, item_p item) 251248616Smm{ 252248616Smm const sc_p sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 253248616Smm 254248616Smm if (hook == sc->sync) 255248616Smm return (nga_rcv_sync(sc, item)); 256248616Smm if (hook == sc->async) 257248616Smm return (nga_rcv_async(sc, item)); 258248616Smm panic(__func__); 259248616Smm} 260248616Smm 261248616Smm/* 262248616Smm * Receive incoming control message 263248616Smm */ 264248616Smmstatic int 265248616Smmnga_rcvmsg(node_p node, item_p item, hook_p lasthook) 266248616Smm{ 267248616Smm const sc_p sc = NG_NODE_PRIVATE(node); 268248616Smm struct ng_mesg *resp = NULL; 269248616Smm int error = 0; 270248616Smm struct ng_mesg *msg; 271248616Smm 272248616Smm NGI_GET_MSG(item, msg); 273248616Smm switch (msg->header.typecookie) { 274248616Smm case NGM_ASYNC_COOKIE: 275248616Smm switch (msg->header.cmd) { 276248616Smm case NGM_ASYNC_CMD_GET_STATS: 277248616Smm NG_MKRESPONSE(resp, msg, sizeof(sc->stats), M_NOWAIT); 278248616Smm if (resp == NULL) 279248616Smm ERROUT(ENOMEM); 280248616Smm *((struct ng_async_stat *) resp->data) = sc->stats; 281248616Smm break; 282248616Smm case NGM_ASYNC_CMD_CLR_STATS: 283248616Smm bzero(&sc->stats, sizeof(sc->stats)); 284248616Smm break; 285248616Smm case NGM_ASYNC_CMD_SET_CONFIG: 286248616Smm { 287248616Smm struct ng_async_cfg *const cfg = 288248616Smm (struct ng_async_cfg *) msg->data; 289248616Smm u_char *buf; 290248616Smm 291248616Smm if (msg->header.arglen != sizeof(*cfg)) 292248616Smm ERROUT(EINVAL); 293248616Smm if (cfg->amru < NG_ASYNC_MIN_MRU 294248616Smm || cfg->amru > NG_ASYNC_MAX_MRU 295248616Smm || cfg->smru < NG_ASYNC_MIN_MRU 296248616Smm || cfg->smru > NG_ASYNC_MAX_MRU) 297248616Smm ERROUT(EINVAL); 298248616Smm cfg->enabled = !!cfg->enabled; /* normalize */ 299248616Smm if (cfg->smru > sc->cfg.smru) { /* reallocate buffer */ 300248616Smm MALLOC(buf, u_char *, ASYNC_BUF_SIZE(cfg->smru), 301248616Smm M_NETGRAPH_ASYNC, M_NOWAIT); 302248616Smm if (!buf) 303248616Smm ERROUT(ENOMEM); 304248616Smm FREE(sc->abuf, M_NETGRAPH_ASYNC); 305248616Smm sc->abuf = buf; 306248616Smm } 307248616Smm if (cfg->amru > sc->cfg.amru) { /* reallocate buffer */ 308248616Smm MALLOC(buf, u_char *, SYNC_BUF_SIZE(cfg->amru), 309248616Smm M_NETGRAPH_ASYNC, M_NOWAIT); 310248616Smm if (!buf) 311248616Smm ERROUT(ENOMEM); 312248616Smm FREE(sc->sbuf, M_NETGRAPH_ASYNC); 313248616Smm sc->sbuf = buf; 314248616Smm sc->amode = MODE_HUNT; 315248616Smm sc->slen = 0; 316248616Smm } 317248616Smm if (!cfg->enabled) { 318248616Smm sc->amode = MODE_HUNT; 319248616Smm sc->slen = 0; 320248616Smm } 321248616Smm sc->cfg = *cfg; 322248616Smm break; 323248616Smm } 324248616Smm case NGM_ASYNC_CMD_GET_CONFIG: 325248616Smm NG_MKRESPONSE(resp, msg, sizeof(sc->cfg), M_NOWAIT); 326248616Smm if (!resp) 327248616Smm ERROUT(ENOMEM); 328248616Smm *((struct ng_async_cfg *) resp->data) = sc->cfg; 329248616Smm break; 330248616Smm default: 331248616Smm ERROUT(EINVAL); 332248616Smm } 333248616Smm break; 334248616Smm default: 335248616Smm ERROUT(EINVAL); 336248616Smm } 337248616Smmdone: 338248616Smm NG_RESPOND_MSG(error, node, item, resp); 339248616Smm NG_FREE_MSG(msg); 340248616Smm return (error); 341248616Smm} 342248616Smm 343248616Smm/* 344248616Smm * Shutdown this node 345248616Smm */ 346248616Smmstatic int 347248616Smmnga_shutdown(node_p node) 348248616Smm{ 349248616Smm const sc_p sc = NG_NODE_PRIVATE(node); 350248616Smm 351248616Smm FREE(sc->abuf, M_NETGRAPH_ASYNC); 352248616Smm FREE(sc->sbuf, M_NETGRAPH_ASYNC); 353248616Smm bzero(sc, sizeof(*sc)); 354248616Smm FREE(sc, M_NETGRAPH_ASYNC); 355248616Smm NG_NODE_SET_PRIVATE(node, NULL); 356248616Smm NG_NODE_UNREF(node); 357248616Smm return (0); 358248616Smm} 359248616Smm 360248616Smm/* 361248616Smm * Lose a hook. When both hooks go away, we disappear. 362248616Smm */ 363248616Smmstatic int 364248616Smmnga_disconnect(hook_p hook) 365248616Smm{ 366248616Smm const sc_p sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 367248616Smm hook_p *hookp; 368248616Smm 369248616Smm if (hook == sc->async) 370232153Smm hookp = &sc->async; 371232153Smm else if (hook == sc->sync) 372232153Smm hookp = &sc->sync; 373232153Smm else 374232153Smm panic(__func__); 375228753Smm if (!*hookp) 376232153Smm panic("%s 2", __func__); 377232153Smm *hookp = NULL; 378232153Smm bzero(&sc->stats, sizeof(sc->stats)); 379232153Smm sc->lasttime = 0; 380232153Smm if ((NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0) 381232153Smm && (NG_NODE_IS_VALID(NG_HOOK_NODE(hook)))) 382232153Smm ng_rmnode_self(NG_HOOK_NODE(hook)); 383248616Smm return (0); 384248616Smm} 385232153Smm 386232153Smm/****************************************************************** 387232153Smm INTERNAL HELPER STUFF 388232153Smm******************************************************************/ 389232153Smm 390232153Smm/* 391232153Smm * Encode a byte into the async buffer 392232153Smm */ 393232153Smmstatic __inline__ void 394232153Smmnga_async_add(const sc_p sc, u_int16_t *fcs, u_int32_t accm, int *len, u_char x) 395232153Smm{ 396232153Smm *fcs = PPP_FCS(*fcs, x); 397232153Smm if ((x < 32 && ((1 << x) & accm)) 398232153Smm || (x == PPP_ESCAPE) 399232153Smm || (x == PPP_FLAG)) { 400232153Smm sc->abuf[(*len)++] = PPP_ESCAPE; 401232153Smm x ^= PPP_TRANS; 402232153Smm } 403232153Smm sc->abuf[(*len)++] = x; 404232153Smm} 405232153Smm 406232153Smm/* 407232153Smm * Receive incoming synchronous data. 408232153Smm */ 409232153Smmstatic int 410232153Smmnga_rcv_sync(const sc_p sc, item_p item) 411232153Smm{ 412232153Smm struct ifnet *rcvif; 413232153Smm int alen, error = 0; 414232153Smm struct timeval time; 415232153Smm u_int16_t fcs, fcs0; 416232153Smm u_int32_t accm; 417232153Smm struct mbuf *m; 418232153Smm 419232153Smm 420232153Smm#define ADD_BYTE(x) nga_async_add(sc, &fcs, accm, &alen, (x)) 421232153Smm 422232153Smm /* Check for bypass mode */ 423232153Smm if (!sc->cfg.enabled) { 424232153Smm NG_FWD_ITEM_HOOK(error, item, sc->async ); 425232153Smm return (error); 426232153Smm } 427232153Smm NGI_GET_M(item, m); 428232153Smm 429232153Smm rcvif = m->m_pkthdr.rcvif; 430232153Smm 431232153Smm /* Get ACCM; special case LCP frames, which use full ACCM */ 432232153Smm accm = sc->cfg.accm; 433232153Smm if (m->m_pkthdr.len >= 4) { 434232153Smm static const u_char lcphdr[4] = { 435232153Smm PPP_ALLSTATIONS, 436232153Smm PPP_UI, 437232153Smm (u_char)(PPP_LCP >> 8), 438232153Smm (u_char)(PPP_LCP & 0xff) 439232153Smm }; 440232153Smm u_char buf[4]; 441232153Smm 442248616Smm m_copydata(m, 0, 4, (caddr_t)buf); 443232153Smm if (bcmp(buf, &lcphdr, 4) == 0) 444248616Smm accm = ~0; 445248616Smm } 446248616Smm 447248616Smm /* Check for overflow */ 448248616Smm if (m->m_pkthdr.len > sc->cfg.smru) { 449248616Smm sc->stats.syncOverflows++; 450248616Smm NG_FREE_M(m); 451248616Smm NG_FREE_ITEM(item); 452248616Smm return (EMSGSIZE); 453248616Smm } 454248616Smm 455248616Smm /* Update stats */ 456248616Smm sc->stats.syncFrames++; 457248616Smm sc->stats.syncOctets += m->m_pkthdr.len; 458248616Smm 459248616Smm /* Initialize async encoded version of input mbuf */ 460248616Smm alen = 0; 461248616Smm fcs = PPP_INITFCS; 462248616Smm 463248616Smm /* Add beginning sync flag if it's been long enough to need one */ 464248616Smm getmicrotime(&time); 465248616Smm if (time.tv_sec >= sc->lasttime + 1) { 466248616Smm sc->abuf[alen++] = PPP_FLAG; 467248616Smm sc->lasttime = time.tv_sec; 468248616Smm } 469248616Smm 470248616Smm /* Add packet payload */ 471248616Smm while (m != NULL) { 472248616Smm while (m->m_len > 0) { 473248616Smm ADD_BYTE(*mtod(m, u_char *)); 474248616Smm m->m_data++; 475248616Smm m->m_len--; 476248616Smm } 477248616Smm m = m_free(m); 478248616Smm } 479248616Smm 480248616Smm /* Add checksum and final sync flag */ 481248616Smm fcs0 = fcs; 482248616Smm ADD_BYTE(~fcs0 & 0xff); 483248616Smm ADD_BYTE(~fcs0 >> 8); 484248616Smm sc->abuf[alen++] = PPP_FLAG; 485248616Smm 486248616Smm /* Put frame in an mbuf and ship it off */ 487248616Smm if (!(m = m_devget(sc->abuf, alen, 0, rcvif, NULL))) { 488248616Smm NG_FREE_ITEM(item); 489248616Smm error = ENOBUFS; 490248616Smm } else { 491248616Smm NG_FWD_NEW_DATA(error, item, sc->async, m); 492248616Smm } 493248616Smm return (error); 494248616Smm} 495248616Smm 496248616Smm/* 497248616Smm * Receive incoming asynchronous data 498248616Smm * XXX Technically, we should strip out incoming characters 499248616Smm * that are in our ACCM. Not sure if this is good or not. 500248616Smm */ 501248616Smmstatic int 502248616Smmnga_rcv_async(const sc_p sc, item_p item) 503248616Smm{ 504248616Smm struct ifnet *rcvif; 505248616Smm int error; 506248616Smm struct mbuf *m; 507232153Smm 508232153Smm if (!sc->cfg.enabled) { 509232153Smm NG_FWD_ITEM_HOOK(error, item, sc->sync); 510248616Smm return (error); 511248616Smm } 512248616Smm NGI_GET_M(item, m); 513248616Smm rcvif = m->m_pkthdr.rcvif; 514248616Smm while (m) { 515248616Smm struct mbuf *n; 516248616Smm 517248616Smm for (; m->m_len > 0; m->m_data++, m->m_len--) { 518248616Smm u_char ch = *mtod(m, u_char *); 519248616Smm 520248616Smm sc->stats.asyncOctets++; 521248616Smm if (ch == PPP_FLAG) { /* Flag overrides everything */ 522248616Smm int skip = 0; 523248616Smm 524248616Smm /* Check for runts */ 525248616Smm if (sc->slen < 2) { 526248616Smm if (sc->slen > 0) 527248616Smm sc->stats.asyncRunts++; 528248616Smm goto reset; 529248616Smm } 530248616Smm 531248616Smm /* Verify CRC */ 532248616Smm if (sc->fcs != PPP_GOODFCS) { 533248616Smm sc->stats.asyncBadCheckSums++; 534248616Smm goto reset; 535248616Smm } 536248616Smm sc->slen -= 2; 537248616Smm 538248616Smm /* Strip address and control fields */ 539248616Smm if (sc->slen >= 2 540248616Smm && sc->sbuf[0] == PPP_ALLSTATIONS 541248616Smm && sc->sbuf[1] == PPP_UI) 542248616Smm skip = 2; 543248616Smm 544248616Smm /* Check for frame too big */ 545248616Smm if (sc->slen - skip > sc->cfg.amru) { 546248616Smm sc->stats.asyncOverflows++; 547248616Smm goto reset; 548248616Smm } 549248616Smm 550248616Smm /* OK, ship it out */ 551248616Smm if ((n = m_devget(sc->sbuf + skip, 552248616Smm sc->slen - skip, 0, rcvif, NULL))) { 553248616Smm if (item) { /* sets NULL -> item */ 554248616Smm NG_FWD_NEW_DATA(error, item, 555248616Smm sc->sync, n); 556248616Smm } else { 557248616Smm NG_SEND_DATA_ONLY(error, 558248616Smm sc->sync ,n); 559248616Smm } 560248616Smm } 561248616Smm sc->stats.asyncFrames++; 562248616Smmreset: 563248616Smm sc->amode = MODE_NORMAL; 564248616Smm sc->fcs = PPP_INITFCS; 565248616Smm sc->slen = 0; 566248616Smm continue; 567248616Smm } 568248616Smm switch (sc->amode) { 569248616Smm case MODE_NORMAL: 570248616Smm if (ch == PPP_ESCAPE) { 571248616Smm sc->amode = MODE_ESC; 572248616Smm continue; 573248616Smm } 574248616Smm break; 575232153Smm case MODE_ESC: 576232153Smm ch ^= PPP_TRANS; 577248616Smm sc->amode = MODE_NORMAL; 578232153Smm break; 579232153Smm case MODE_HUNT: 580232153Smm default: 581232153Smm continue; 582232153Smm } 583232153Smm 584232153Smm /* Add byte to frame */ 585232153Smm if (sc->slen >= SYNC_BUF_SIZE(sc->cfg.amru)) { 586232153Smm sc->stats.asyncOverflows++; 587232153Smm sc->amode = MODE_HUNT; 588232153Smm sc->slen = 0; 589232153Smm } else { 590232153Smm sc->sbuf[sc->slen++] = ch; 591232153Smm sc->fcs = PPP_FCS(sc->fcs, ch); 592232153Smm } 593232153Smm } 594232153Smm m = m_free(m); 595232153Smm } 596232153Smm if (item) 597232153Smm NG_FREE_ITEM(item); 598232153Smm return (0); 599232153Smm} 600232153Smm 601232153Smm/* 602232153Smm * 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