1 2 /* 3 * ng_async.c 4 * 5 * Copyright (c) 1996-1999 Whistle Communications, Inc. 6 * All rights reserved. 7 * 8 * Subject to the following obligations and disclaimer of warranty, use and 9 * redistribution of this software, in source or object code forms, with or 10 * without modifications are expressly permitted by Whistle Communications; 11 * provided, however, that: 12 * 1. Any and all reproductions of the source or object code must include the 13 * copyright notice above and the following disclaimer of warranties; and 14 * 2. No rights are granted, in any manner or form, to use Whistle 15 * Communications, Inc. trademarks, including the mark "WHISTLE 16 * COMMUNICATIONS" on advertising, endorsements, or otherwise except as 17 * such appears in the above copyright notice or in the software. 18 * 19 * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND 20 * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO 21 * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, 22 * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF 23 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. 24 * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY 25 * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS 26 * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. 27 * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES 28 * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING 29 * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 30 * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR 31 * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY 32 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 33 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 34 * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY 35 * OF SUCH DAMAGE. 36 * 37 * Author: Archie Cobbs <archie@freebsd.org> 38 * 39 * $FreeBSD: src/sys/netgraph/ng_async.c,v 1.6.2.5 2002/07/02 23:44:02 archie Exp $ 40 * $Whistle: ng_async.c,v 1.17 1999/11/01 09:24:51 julian Exp $ 41 */ 42 43 /* 44 * This node type implements a PPP style sync <-> async converter. 45 * See RFC 1661 for details of how asynchronous encoding works. 46 */ 47 48 #include <sys/param.h> 49 #include <sys/systm.h> 50 #include <sys/kernel.h> 51 #include <sys/mbuf.h> 52 #include <sys/malloc.h> 53 #include <sys/errno.h> 54 55 #include <netgraph/ng_message.h> 56 #include <netgraph/netgraph.h> 57 #include "ng_async.h" 58 #include <netgraph/ng_parse.h> 59 60 #include <net/ppp_layer/ppp_defs.h> 61 62 /* Async decode state */ 63 #define MODE_HUNT 0 64 #define MODE_NORMAL 1 65 #define MODE_ESC 2 66 67 /* Private data structure */ 68 struct ng_async_private { 69 node_p node; /* Our node */ 70 hook_p async; /* Asynchronous side */ 71 hook_p sync; /* Synchronous side */ 72 u_char amode; /* Async hunt/esape mode */ 73 u_int16_t fcs; /* Decoded async FCS (so far) */ 74 u_char *abuf; /* Buffer to encode sync into */ 75 u_char *sbuf; /* Buffer to decode async into */ 76 u_int slen; /* Length of data in sbuf */ 77 long lasttime; /* Time of last async packet sent */ 78 struct ng_async_cfg cfg; /* Configuration */ 79 struct ng_async_stat stats; /* Statistics */ 80 }; 81 typedef struct ng_async_private *sc_p; 82 83 /* Useful macros */ 84 #define ASYNC_BUF_SIZE(smru) (2 * (smru) + 10) 85 #define SYNC_BUF_SIZE(amru) ((amru) + 10) 86 #define ERROUT(x) do { error = (x); goto done; } while (0) 87 88 /* Netgraph methods */ 89 static ng_constructor_t nga_constructor; 90 static ng_rcvdata_t nga_rcvdata; 91 static ng_rcvmsg_t nga_rcvmsg; 92 static ng_shutdown_t nga_shutdown; 93 static ng_newhook_t nga_newhook; 94 static ng_disconnect_t nga_disconnect; 95 96 /* Helper stuff */ 97 static int nga_rcv_sync(const sc_p sc, struct mbuf *m, meta_p meta); 98 static int nga_rcv_async(const sc_p sc, struct mbuf *m, meta_p meta); 99 100 /* Parse type for struct ng_async_cfg */ 101 static const struct ng_parse_struct_field nga_config_type_fields[] 102 = NG_ASYNC_CONFIG_TYPE_INFO; 103 static const struct ng_parse_type nga_config_type = { 104 &ng_parse_struct_type, 105 &nga_config_type_fields 106 }; 107 108 /* Parse type for struct ng_async_stat */ 109 static const struct ng_parse_struct_field nga_stats_type_fields[] 110 = NG_ASYNC_STATS_TYPE_INFO; 111 static const struct ng_parse_type nga_stats_type = { 112 &ng_parse_struct_type, 113 &nga_stats_type_fields 114 }; 115 116 /* List of commands and how to convert arguments to/from ASCII */ 117 static const struct ng_cmdlist nga_cmdlist[] = { 118 { 119 NGM_ASYNC_COOKIE, 120 NGM_ASYNC_CMD_SET_CONFIG, 121 "setconfig", 122 &nga_config_type, 123 NULL 124 }, 125 { 126 NGM_ASYNC_COOKIE, 127 NGM_ASYNC_CMD_GET_CONFIG, 128 "getconfig", 129 NULL, 130 &nga_config_type 131 }, 132 { 133 NGM_ASYNC_COOKIE, 134 NGM_ASYNC_CMD_GET_STATS, 135 "getstats", 136 NULL, 137 &nga_stats_type 138 }, 139 { 140 NGM_ASYNC_COOKIE, 141 NGM_ASYNC_CMD_CLR_STATS, 142 "clrstats", 143 &nga_stats_type, 144 NULL 145 }, 146 { 0 } 147 }; 148 149 /* Define the netgraph node type */ 150 static struct ng_type typestruct = { 151 NG_VERSION, 152 NG_ASYNC_NODE_TYPE, 153 NULL, 154 nga_constructor, 155 nga_rcvmsg, 156 nga_shutdown, 157 nga_newhook, 158 NULL, 159 NULL, 160 nga_rcvdata, 161 nga_rcvdata, 162 nga_disconnect, 163 nga_cmdlist 164 }; 165 NETGRAPH_INIT(async, &typestruct); 166 167 /* 168 * CRC table 169 * 170 * Taken from RFC 1171 Appendix B 171 */ 172 static const u_int16_t fcstab[256] = { 173 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, 174 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, 175 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, 176 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, 177 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, 178 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, 179 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, 180 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, 181 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, 182 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, 183 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, 184 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, 185 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, 186 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, 187 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, 188 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, 189 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, 190 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, 191 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, 192 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, 193 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, 194 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, 195 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, 196 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, 197 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, 198 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, 199 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, 200 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, 201 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, 202 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, 203 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, 204 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 205 }; 206 207 /****************************************************************** 208 NETGRAPH NODE METHODS 209 ******************************************************************/ 210 211 /* 212 * Initialize a new node 213 */ 214 static int 215 nga_constructor(node_p *nodep) 216 { 217 sc_p sc; 218 int error; 219 220 if ((error = ng_make_node_common(&typestruct, nodep))) 221 return (error); 222 sc = kmalloc(sizeof(*sc), M_NETGRAPH, M_NOWAIT | M_ZERO); 223 if (sc == NULL) 224 return (ENOMEM); 225 sc->amode = MODE_HUNT; 226 sc->cfg.accm = ~0; 227 sc->cfg.amru = NG_ASYNC_DEFAULT_MRU; 228 sc->cfg.smru = NG_ASYNC_DEFAULT_MRU; 229 sc->abuf = kmalloc(ASYNC_BUF_SIZE(sc->cfg.smru), M_NETGRAPH, M_NOWAIT); 230 if (sc->abuf == NULL) 231 goto fail; 232 sc->sbuf = kmalloc(SYNC_BUF_SIZE(sc->cfg.amru), M_NETGRAPH, M_NOWAIT); 233 if (sc->sbuf == NULL) { 234 kfree(sc->abuf, M_NETGRAPH); 235 fail: 236 kfree(sc, M_NETGRAPH); 237 return (ENOMEM); 238 } 239 (*nodep)->private = sc; 240 sc->node = *nodep; 241 return (0); 242 } 243 244 /* 245 * Reserve a hook for a pending connection 246 */ 247 static int 248 nga_newhook(node_p node, hook_p hook, const char *name) 249 { 250 const sc_p sc = node->private; 251 hook_p *hookp; 252 253 if (!strcmp(name, NG_ASYNC_HOOK_ASYNC)) 254 hookp = &sc->async; 255 else if (!strcmp(name, NG_ASYNC_HOOK_SYNC)) 256 hookp = &sc->sync; 257 else 258 return (EINVAL); 259 if (*hookp) 260 return (EISCONN); 261 *hookp = hook; 262 return (0); 263 } 264 265 /* 266 * Receive incoming data 267 */ 268 static int 269 nga_rcvdata(hook_p hook, struct mbuf *m, meta_p meta) 270 { 271 const sc_p sc = hook->node->private; 272 273 if (hook == sc->sync) 274 return (nga_rcv_sync(sc, m, meta)); 275 if (hook == sc->async) 276 return (nga_rcv_async(sc, m, meta)); 277 panic(__func__); 278 } 279 280 /* 281 * Receive incoming control message 282 */ 283 static int 284 nga_rcvmsg(node_p node, struct ng_mesg *msg, 285 const char *rtn, struct ng_mesg **rptr) 286 { 287 const sc_p sc = (sc_p) node->private; 288 struct ng_mesg *resp = NULL; 289 int error = 0; 290 291 switch (msg->header.typecookie) { 292 case NGM_ASYNC_COOKIE: 293 switch (msg->header.cmd) { 294 case NGM_ASYNC_CMD_GET_STATS: 295 NG_MKRESPONSE(resp, msg, sizeof(sc->stats), M_NOWAIT); 296 if (resp == NULL) 297 ERROUT(ENOMEM); 298 *((struct ng_async_stat *) resp->data) = sc->stats; 299 break; 300 case NGM_ASYNC_CMD_CLR_STATS: 301 bzero(&sc->stats, sizeof(sc->stats)); 302 break; 303 case NGM_ASYNC_CMD_SET_CONFIG: 304 { 305 struct ng_async_cfg *const cfg = 306 (struct ng_async_cfg *) msg->data; 307 u_char *buf; 308 309 if (msg->header.arglen != sizeof(*cfg)) 310 ERROUT(EINVAL); 311 if (cfg->amru < NG_ASYNC_MIN_MRU 312 || cfg->amru > NG_ASYNC_MAX_MRU 313 || cfg->smru < NG_ASYNC_MIN_MRU 314 || cfg->smru > NG_ASYNC_MAX_MRU) 315 ERROUT(EINVAL); 316 cfg->enabled = !!cfg->enabled; /* normalize */ 317 if (cfg->smru > sc->cfg.smru) { /* reallocate buffer */ 318 buf = kmalloc(ASYNC_BUF_SIZE(cfg->smru), 319 M_NETGRAPH, M_NOWAIT); 320 if (!buf) 321 ERROUT(ENOMEM); 322 kfree(sc->abuf, M_NETGRAPH); 323 sc->abuf = buf; 324 } 325 if (cfg->amru > sc->cfg.amru) { /* reallocate buffer */ 326 buf = kmalloc(SYNC_BUF_SIZE(cfg->amru), 327 M_NETGRAPH, M_NOWAIT); 328 if (!buf) 329 ERROUT(ENOMEM); 330 kfree(sc->sbuf, M_NETGRAPH); 331 sc->sbuf = buf; 332 sc->amode = MODE_HUNT; 333 sc->slen = 0; 334 } 335 if (!cfg->enabled) { 336 sc->amode = MODE_HUNT; 337 sc->slen = 0; 338 } 339 sc->cfg = *cfg; 340 break; 341 } 342 case NGM_ASYNC_CMD_GET_CONFIG: 343 NG_MKRESPONSE(resp, msg, sizeof(sc->cfg), M_NOWAIT); 344 if (!resp) 345 ERROUT(ENOMEM); 346 *((struct ng_async_cfg *) resp->data) = sc->cfg; 347 break; 348 default: 349 ERROUT(EINVAL); 350 } 351 break; 352 default: 353 ERROUT(EINVAL); 354 } 355 if (rptr) 356 *rptr = resp; 357 else if (resp) 358 kfree(resp, M_NETGRAPH); 359 360 done: 361 kfree(msg, M_NETGRAPH); 362 return (error); 363 } 364 365 /* 366 * Shutdown this node 367 */ 368 static int 369 nga_shutdown(node_p node) 370 { 371 const sc_p sc = node->private; 372 373 ng_cutlinks(node); 374 ng_unname(node); 375 kfree(sc->abuf, M_NETGRAPH); 376 kfree(sc->sbuf, M_NETGRAPH); 377 bzero(sc, sizeof(*sc)); 378 kfree(sc, M_NETGRAPH); 379 node->private = NULL; 380 ng_unref(node); 381 return (0); 382 } 383 384 /* 385 * Lose a hook. When both hooks go away, we disappear. 386 */ 387 static int 388 nga_disconnect(hook_p hook) 389 { 390 const sc_p sc = hook->node->private; 391 hook_p *hookp; 392 393 if (hook == sc->async) 394 hookp = &sc->async; 395 else if (hook == sc->sync) 396 hookp = &sc->sync; 397 else 398 panic(__func__); 399 if (!*hookp) 400 panic("%s2", __func__); 401 *hookp = NULL; 402 bzero(&sc->stats, sizeof(sc->stats)); 403 sc->lasttime = 0; 404 if (hook->node->numhooks == 0) 405 ng_rmnode(hook->node); 406 return (0); 407 } 408 409 /****************************************************************** 410 INTERNAL HELPER STUFF 411 ******************************************************************/ 412 413 /* 414 * Encode a byte into the async buffer 415 */ 416 static __inline__ void 417 nga_async_add(const sc_p sc, u_int16_t *fcs, u_int32_t accm, int *len, u_char x) 418 { 419 *fcs = PPP_FCS(*fcs, x); 420 if ((x < 32 && ((1 << x) & accm)) 421 || (x == PPP_ESCAPE) 422 || (x == PPP_FLAG)) { 423 sc->abuf[(*len)++] = PPP_ESCAPE; 424 x ^= PPP_TRANS; 425 } 426 sc->abuf[(*len)++] = x; 427 } 428 429 /* 430 * Receive incoming synchronous data. 431 */ 432 static int 433 nga_rcv_sync(const sc_p sc, struct mbuf *m, meta_p meta) 434 { 435 struct ifnet *const rcvif = m->m_pkthdr.rcvif; 436 int alen, error = 0; 437 struct timeval time; 438 u_int16_t fcs, fcs0; 439 u_int32_t accm; 440 441 #define ADD_BYTE(x) nga_async_add(sc, &fcs, accm, &alen, (x)) 442 443 /* Check for bypass mode */ 444 if (!sc->cfg.enabled) { 445 NG_SEND_DATA(error, sc->async, m, meta); 446 return (error); 447 } 448 449 /* Get ACCM; special case LCP frames, which use full ACCM */ 450 accm = sc->cfg.accm; 451 if (m->m_pkthdr.len >= 4) { 452 static const u_char lcphdr[4] = { 453 PPP_ALLSTATIONS, 454 PPP_UI, 455 (u_char)(PPP_LCP >> 8), 456 (u_char)(PPP_LCP & 0xff) 457 }; 458 u_char buf[4]; 459 460 m_copydata(m, 0, 4, (caddr_t)buf); 461 if (bcmp(buf, &lcphdr, 4) == 0) 462 accm = ~0; 463 } 464 465 /* Check for overflow */ 466 if (m->m_pkthdr.len > sc->cfg.smru) { 467 sc->stats.syncOverflows++; 468 NG_FREE_DATA(m, meta); 469 return (EMSGSIZE); 470 } 471 472 /* Update stats */ 473 sc->stats.syncFrames++; 474 sc->stats.syncOctets += m->m_pkthdr.len; 475 476 /* Initialize async encoded version of input mbuf */ 477 alen = 0; 478 fcs = PPP_INITFCS; 479 480 /* Add beginning sync flag if it's been long enough to need one */ 481 getmicrotime(&time); 482 if (time.tv_sec >= sc->lasttime + 1) { 483 sc->abuf[alen++] = PPP_FLAG; 484 sc->lasttime = time.tv_sec; 485 } 486 487 /* Add packet payload */ 488 while (m != NULL) { 489 while (m->m_len > 0) { 490 ADD_BYTE(*mtod(m, u_char *)); 491 m->m_data++; 492 m->m_len--; 493 } 494 m = m_free(m); 495 } 496 497 /* Add checksum and final sync flag */ 498 fcs0 = fcs; 499 ADD_BYTE(~fcs0 & 0xff); 500 ADD_BYTE(~fcs0 >> 8); 501 sc->abuf[alen++] = PPP_FLAG; 502 503 /* Put frame in an mbuf and ship it off */ 504 if (!(m = m_devget(sc->abuf, alen, 0, rcvif, NULL))) { 505 NG_FREE_META(meta); 506 error = ENOBUFS; 507 } else 508 NG_SEND_DATA(error, sc->async, m, meta); 509 return (error); 510 } 511 512 /* 513 * Receive incoming asynchronous data 514 * XXX Technically, we should strip out incoming characters 515 * that are in our ACCM. Not sure if this is good or not. 516 */ 517 static int 518 nga_rcv_async(const sc_p sc, struct mbuf * m, meta_p meta) 519 { 520 struct ifnet *const rcvif = m->m_pkthdr.rcvif; 521 int error; 522 523 if (!sc->cfg.enabled) { 524 NG_SEND_DATA(error, sc->sync, m, meta); 525 return (error); 526 } 527 NG_FREE_META(meta); 528 while (m) { 529 struct mbuf *n; 530 531 for (; m->m_len > 0; m->m_data++, m->m_len--) { 532 u_char ch = *mtod(m, u_char *); 533 534 sc->stats.asyncOctets++; 535 if (ch == PPP_FLAG) { /* Flag overrides everything */ 536 int skip = 0; 537 538 /* Check for runts */ 539 if (sc->slen < 2) { 540 if (sc->slen > 0) 541 sc->stats.asyncRunts++; 542 goto reset; 543 } 544 545 /* Verify CRC */ 546 if (sc->fcs != PPP_GOODFCS) { 547 sc->stats.asyncBadCheckSums++; 548 goto reset; 549 } 550 sc->slen -= 2; 551 552 /* Strip address and control fields */ 553 if (sc->slen >= 2 554 && sc->sbuf[0] == PPP_ALLSTATIONS 555 && sc->sbuf[1] == PPP_UI) 556 skip = 2; 557 558 /* Check for frame too big */ 559 if (sc->slen - skip > sc->cfg.amru) { 560 sc->stats.asyncOverflows++; 561 goto reset; 562 } 563 564 /* OK, ship it out */ 565 if ((n = m_devget(sc->sbuf + skip, 566 sc->slen - skip, 0, rcvif, NULL))) 567 NG_SEND_DATA(error, sc->sync, n, meta); 568 sc->stats.asyncFrames++; 569 reset: 570 sc->amode = MODE_NORMAL; 571 sc->fcs = PPP_INITFCS; 572 sc->slen = 0; 573 continue; 574 } 575 switch (sc->amode) { 576 case MODE_NORMAL: 577 if (ch == PPP_ESCAPE) { 578 sc->amode = MODE_ESC; 579 continue; 580 } 581 break; 582 case MODE_ESC: 583 ch ^= PPP_TRANS; 584 sc->amode = MODE_NORMAL; 585 break; 586 case MODE_HUNT: 587 default: 588 continue; 589 } 590 591 /* Add byte to frame */ 592 if (sc->slen >= SYNC_BUF_SIZE(sc->cfg.amru)) { 593 sc->stats.asyncOverflows++; 594 sc->amode = MODE_HUNT; 595 sc->slen = 0; 596 } else { 597 sc->sbuf[sc->slen++] = ch; 598 sc->fcs = PPP_FCS(sc->fcs, ch); 599 } 600 } 601 m = m_free(m); 602 } 603 return (0); 604 } 605