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_disconnect, 162 nga_cmdlist 163}; 164NETGRAPH_INIT(async, &typestruct); 165 166/* CRC table */ 167static const u_int16_t fcstab[]; 168 169/****************************************************************** 170 NETGRAPH NODE METHODS 171******************************************************************/ 172 173/* 174 * Initialize a new node 175 */ 176static int 177nga_constructor(node_p *nodep) 178{ 179 sc_p sc; 180 int error; 181 182 if ((error = ng_make_node_common(&typestruct, nodep))) 183 return (error); 184 MALLOC(sc, sc_p, sizeof(*sc), M_NETGRAPH, M_NOWAIT | M_ZERO); 185 if (sc == NULL) 186 return (ENOMEM); 187 sc->amode = MODE_HUNT; 188 sc->cfg.accm = ~0; 189 sc->cfg.amru = NG_ASYNC_DEFAULT_MRU; 190 sc->cfg.smru = NG_ASYNC_DEFAULT_MRU; 191 MALLOC(sc->abuf, u_char *, 192 ASYNC_BUF_SIZE(sc->cfg.smru), M_NETGRAPH, M_NOWAIT); 193 if (sc->abuf == NULL) 194 goto fail; 195 MALLOC(sc->sbuf, u_char *, 196 SYNC_BUF_SIZE(sc->cfg.amru), M_NETGRAPH, M_NOWAIT); 197 if (sc->sbuf == NULL) { 198 FREE(sc->abuf, M_NETGRAPH); 199fail: 200 FREE(sc, M_NETGRAPH); 201 return (ENOMEM); 202 } 203 (*nodep)->private = sc; 204 sc->node = *nodep; 205 return (0); 206} 207 208/* 209 * Reserve a hook for a pending connection 210 */ 211static int 212nga_newhook(node_p node, hook_p hook, const char *name) 213{ 214 const sc_p sc = node->private; 215 hook_p *hookp; 216 217 if (!strcmp(name, NG_ASYNC_HOOK_ASYNC)) 218 hookp = &sc->async; 219 else if (!strcmp(name, NG_ASYNC_HOOK_SYNC)) 220 hookp = &sc->sync; 221 else 222 return (EINVAL); 223 if (*hookp) 224 return (EISCONN); 225 *hookp = hook; 226 return (0); 227} 228 229/* 230 * Receive incoming data 231 */ 232static int 233nga_rcvdata(hook_p hook, struct mbuf *m, meta_p meta, 234 struct mbuf **ret_m, meta_p *ret_meta, struct ng_mesg **resp) 235{ 236 const sc_p sc = hook->node->private; 237 238 if (hook == sc->sync) 239 return (nga_rcv_sync(sc, m, meta)); 240 if (hook == sc->async) 241 return (nga_rcv_async(sc, m, meta)); 242 panic(__FUNCTION__); 243} 244 245/* 246 * Receive incoming control message 247 */ 248static int 249nga_rcvmsg(node_p node, struct ng_mesg *msg, 250 const char *rtn, struct ng_mesg **rptr, hook_p lasthook) 251{ 252 const sc_p sc = (sc_p) node->private; 253 struct ng_mesg *resp = NULL; 254 int error = 0; 255 256 switch (msg->header.typecookie) { 257 case NGM_ASYNC_COOKIE: 258 switch (msg->header.cmd) { 259 case NGM_ASYNC_CMD_GET_STATS: 260 NG_MKRESPONSE(resp, msg, sizeof(sc->stats), M_NOWAIT); 261 if (resp == NULL) 262 ERROUT(ENOMEM); 263 *((struct ng_async_stat *) resp->data) = sc->stats; 264 break; 265 case NGM_ASYNC_CMD_CLR_STATS: 266 bzero(&sc->stats, sizeof(sc->stats)); 267 break; 268 case NGM_ASYNC_CMD_SET_CONFIG: 269 { 270 struct ng_async_cfg *const cfg = 271 (struct ng_async_cfg *) msg->data; 272 u_char *buf; 273 274 if (msg->header.arglen != sizeof(*cfg)) 275 ERROUT(EINVAL); 276 if (cfg->amru < NG_ASYNC_MIN_MRU 277 || cfg->amru > NG_ASYNC_MAX_MRU 278 || cfg->smru < NG_ASYNC_MIN_MRU 279 || cfg->smru > NG_ASYNC_MAX_MRU) 280 ERROUT(EINVAL); 281 cfg->enabled = !!cfg->enabled; /* normalize */ 282 if (cfg->smru > sc->cfg.smru) { /* reallocate buffer */ 283 MALLOC(buf, u_char *, ASYNC_BUF_SIZE(cfg->smru), 284 M_NETGRAPH, M_NOWAIT); 285 if (!buf) 286 ERROUT(ENOMEM); 287 FREE(sc->abuf, M_NETGRAPH); 288 sc->abuf = buf; 289 } 290 if (cfg->amru > sc->cfg.amru) { /* reallocate buffer */ 291 MALLOC(buf, u_char *, SYNC_BUF_SIZE(cfg->amru), 292 M_NETGRAPH, M_NOWAIT); 293 if (!buf) 294 ERROUT(ENOMEM); 295 FREE(sc->sbuf, M_NETGRAPH); 296 sc->sbuf = buf; 297 sc->amode = MODE_HUNT; 298 sc->slen = 0; 299 } 300 if (!cfg->enabled) { 301 sc->amode = MODE_HUNT; 302 sc->slen = 0; 303 } 304 sc->cfg = *cfg; 305 break; 306 } 307 case NGM_ASYNC_CMD_GET_CONFIG: 308 NG_MKRESPONSE(resp, msg, sizeof(sc->cfg), M_NOWAIT); 309 if (!resp) 310 ERROUT(ENOMEM); 311 *((struct ng_async_cfg *) resp->data) = sc->cfg; 312 break; 313 default: 314 ERROUT(EINVAL); 315 } 316 break; 317 default: 318 ERROUT(EINVAL); 319 } 320 if (rptr) 321 *rptr = resp; 322 else if (resp) 323 FREE(resp, M_NETGRAPH); 324 325done: 326 FREE(msg, M_NETGRAPH); 327 return (error); 328} 329 330/* 331 * Shutdown this node 332 */ 333static int 334nga_shutdown(node_p node) 335{ 336 const sc_p sc = node->private; 337 338 ng_cutlinks(node); 339 ng_unname(node); 340 FREE(sc->abuf, M_NETGRAPH); 341 FREE(sc->sbuf, M_NETGRAPH); 342 bzero(sc, sizeof(*sc)); 343 FREE(sc, M_NETGRAPH); 344 node->private = NULL; 345 ng_unref(node); 346 return (0); 347} 348 349/* 350 * Lose a hook. When both hooks go away, we disappear. 351 */ 352static int 353nga_disconnect(hook_p hook) 354{ 355 const sc_p sc = hook->node->private; 356 hook_p *hookp; 357 358 if (hook == sc->async) 359 hookp = &sc->async; 360 else if (hook == sc->sync) 361 hookp = &sc->sync; 362 else 363 panic(__FUNCTION__); 364 if (!*hookp) 365 panic(__FUNCTION__ "2"); 366 *hookp = NULL; 367 bzero(&sc->stats, sizeof(sc->stats)); 368 sc->lasttime = 0; 369 if (hook->node->numhooks == 0) 370 ng_rmnode(hook->node); 371 return (0); 372} 373 374/****************************************************************** 375 INTERNAL HELPER STUFF 376******************************************************************/ 377 378/* 379 * Encode a byte into the async buffer 380 */ 381static __inline__ void 382nga_async_add(const sc_p sc, u_int16_t *fcs, u_int32_t accm, int *len, u_char x) 383{ 384 *fcs = PPP_FCS(*fcs, x); 385 if ((x < 32 && ((1 << x) & accm)) 386 || (x == PPP_ESCAPE) 387 || (x == PPP_FLAG)) { 388 sc->abuf[(*len)++] = PPP_ESCAPE; 389 x ^= PPP_TRANS; 390 } 391 sc->abuf[(*len)++] = x; 392} 393 394/* 395 * Receive incoming synchronous data. 396 */ 397static int 398nga_rcv_sync(const sc_p sc, struct mbuf *m, meta_p meta) 399{ 400 struct ifnet *const rcvif = m->m_pkthdr.rcvif; 401 int alen, error = 0; 402 struct timeval time; 403 u_int16_t fcs, fcs0; 404 u_int32_t accm; 405 406#define ADD_BYTE(x) nga_async_add(sc, &fcs, accm, &alen, (x)) 407 408 /* Check for bypass mode */ 409 if (!sc->cfg.enabled) { 410 NG_SEND_DATA(error, sc->async, m, meta); 411 return (error); 412 } 413 414 /* Get ACCM; special case LCP frames, which use full ACCM */ 415 accm = sc->cfg.accm; 416 if (m->m_pkthdr.len >= 4) { 417 static const u_char lcphdr[4] = { 418 PPP_ALLSTATIONS, 419 PPP_UI, 420 (u_char)(PPP_LCP >> 8), 421 (u_char)(PPP_LCP & 0xff) 422 }; 423 u_char buf[4]; 424 425 m_copydata(m, 0, 4, (caddr_t)buf); 426 if (bcmp(buf, &lcphdr, 4) == 0) 427 accm = ~0; 428 } 429 430 /* Check for overflow */ 431 if (m->m_pkthdr.len > sc->cfg.smru) { 432 sc->stats.syncOverflows++; 433 NG_FREE_DATA(m, meta); 434 return (EMSGSIZE); 435 } 436 437 /* Update stats */ 438 sc->stats.syncFrames++; 439 sc->stats.syncOctets += m->m_pkthdr.len; 440 441 /* Initialize async encoded version of input mbuf */ 442 alen = 0; 443 fcs = PPP_INITFCS; 444 445 /* Add beginning sync flag if it's been long enough to need one */ 446 getmicrotime(&time); 447 if (time.tv_sec >= sc->lasttime + 1) { 448 sc->abuf[alen++] = PPP_FLAG; 449 sc->lasttime = time.tv_sec; 450 } 451 452 /* Add packet payload */ 453 while (m != NULL) { 454 struct mbuf *n; 455 456 while (m->m_len > 0) { 457 ADD_BYTE(*mtod(m, u_char *)); 458 m->m_data++; 459 m->m_len--; 460 } 461 MFREE(m, n); 462 m = n; 463 } 464 465 /* Add checksum and final sync flag */ 466 fcs0 = fcs; 467 ADD_BYTE(~fcs0 & 0xff); 468 ADD_BYTE(~fcs0 >> 8); 469 sc->abuf[alen++] = PPP_FLAG; 470 471 /* Put frame in an mbuf and ship it off */ 472 if (!(m = m_devget(sc->abuf, alen, 0, rcvif, NULL))) { 473 NG_FREE_META(meta); 474 error = ENOBUFS; 475 } else 476 NG_SEND_DATA(error, sc->async, m, meta); 477 return (error); 478} 479 480/* 481 * Receive incoming asynchronous data 482 * XXX Technically, we should strip out incoming characters 483 * that are in our ACCM. Not sure if this is good or not. 484 */ 485static int 486nga_rcv_async(const sc_p sc, struct mbuf * m, meta_p meta) 487{ 488 struct ifnet *const rcvif = m->m_pkthdr.rcvif; 489 int error; 490 491 if (!sc->cfg.enabled) { 492 NG_SEND_DATA(error, sc->sync, m, meta); 493 return (error); 494 } 495 NG_FREE_META(meta); 496 while (m) { 497 struct mbuf *n; 498 499 for (; m->m_len > 0; m->m_data++, m->m_len--) { 500 u_char ch = *mtod(m, u_char *); 501 502 sc->stats.asyncOctets++; 503 if (ch == PPP_FLAG) { /* Flag overrides everything */ 504 int skip = 0; 505 506 /* Check for runts */ 507 if (sc->slen < 2) { 508 if (sc->slen > 0) 509 sc->stats.asyncRunts++; 510 goto reset; 511 } 512 513 /* Verify CRC */ 514 if (sc->fcs != PPP_GOODFCS) { 515 sc->stats.asyncBadCheckSums++; 516 goto reset; 517 } 518 sc->slen -= 2; 519 520 /* Strip address and control fields */ 521 if (sc->slen >= 2 522 && sc->sbuf[0] == PPP_ALLSTATIONS 523 && sc->sbuf[1] == PPP_UI) 524 skip = 2; 525 526 /* Check for frame too big */ 527 if (sc->slen - skip > sc->cfg.amru) { 528 sc->stats.asyncOverflows++; 529 goto reset; 530 } 531 532 /* OK, ship it out */ 533 if ((n = m_devget(sc->sbuf + skip, 534 sc->slen - skip, 0, rcvif, NULL))) 535 NG_SEND_DATA(error, sc->sync, n, meta); 536 sc->stats.asyncFrames++; 537reset: 538 sc->amode = MODE_NORMAL; 539 sc->fcs = PPP_INITFCS; 540 sc->slen = 0; 541 continue; 542 } 543 switch (sc->amode) { 544 case MODE_NORMAL: 545 if (ch == PPP_ESCAPE) { 546 sc->amode = MODE_ESC; 547 continue; 548 } 549 break; 550 case MODE_ESC: 551 ch ^= PPP_TRANS; 552 sc->amode = MODE_NORMAL; 553 break; 554 case MODE_HUNT: 555 default: 556 continue; 557 } 558 559 /* Add byte to frame */ 560 if (sc->slen >= SYNC_BUF_SIZE(sc->cfg.amru)) { 561 sc->stats.asyncOverflows++; 562 sc->amode = MODE_HUNT; 563 sc->slen = 0; 564 } else { 565 sc->sbuf[sc->slen++] = ch; 566 sc->fcs = PPP_FCS(sc->fcs, ch); 567 } 568 } 569 MFREE(m, n); 570 m = n; 571 } 572 return (0); 573} 574 575/* 576 * CRC table 577 * 578 * Taken from RFC 1171 Appendix B 579 */ 580static const u_int16_t fcstab[256] = { 581 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, 582 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, 583 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, 584 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, 585 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, 586 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, 587 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, 588 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, 589 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, 590 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, 591 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, 592 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, 593 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, 594 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, 595 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, 596 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, 597 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, 598 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, 599 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, 600 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, 601 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, 602 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, 603 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, 604 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, 605 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, 606 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, 607 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, 608 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, 609 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, 610 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, 611 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, 612 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 613};
|