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