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$ 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 <netgraph/ng_async.h> 58 #include <netgraph/ng_parse.h> 59 60 #include <net/ppp_defs.h> 61 62 #ifdef NG_SEPARATE_MALLOC 63 MALLOC_DEFINE(M_NETGRAPH_ASYNC, "netgraph_async", "netgraph async node "); 64 #else 65 #define M_NETGRAPH_ASYNC M_NETGRAPH 66 #endif 67 68 69 /* Async decode state */ 70 #define MODE_HUNT 0 71 #define MODE_NORMAL 1 72 #define MODE_ESC 2 73 74 /* Private data structure */ 75 struct ng_async_private { 76 node_p node; /* Our node */ 77 hook_p async; /* Asynchronous side */ 78 hook_p sync; /* Synchronous side */ 79 u_char amode; /* Async hunt/esape mode */ 80 u_int16_t fcs; /* Decoded async FCS (so far) */ 81 u_char *abuf; /* Buffer to encode sync into */ 82 u_char *sbuf; /* Buffer to decode async into */ 83 u_int slen; /* Length of data in sbuf */ 84 long lasttime; /* Time of last async packet sent */ 85 struct ng_async_cfg cfg; /* Configuration */ 86 struct ng_async_stat stats; /* Statistics */ 87 }; 88 typedef struct ng_async_private *sc_p; 89 90 /* Useful macros */ 91 #define ASYNC_BUF_SIZE(smru) (2 * (smru) + 10) 92 #define SYNC_BUF_SIZE(amru) ((amru) + 10) 93 #define ERROUT(x) do { error = (x); goto done; } while (0) 94 95 /* Netgraph methods */ 96 static ng_constructor_t nga_constructor; 97 static ng_rcvdata_t nga_rcvdata; 98 static ng_rcvmsg_t nga_rcvmsg; 99 static ng_shutdown_t nga_shutdown; 100 static ng_newhook_t nga_newhook; 101 static ng_disconnect_t nga_disconnect; 102 103 /* Helper stuff */ 104 static int nga_rcv_sync(const sc_p sc, item_p item); 105 static int nga_rcv_async(const sc_p sc, item_p item); 106 107 /* Parse type for struct ng_async_cfg */ 108 static const struct ng_parse_struct_field nga_config_type_fields[] 109 = NG_ASYNC_CONFIG_TYPE_INFO; 110 static const struct ng_parse_type nga_config_type = { 111 &ng_parse_struct_type, 112 &nga_config_type_fields 113 }; 114 115 /* Parse type for struct ng_async_stat */ 116 static const struct ng_parse_struct_field nga_stats_type_fields[] 117 = NG_ASYNC_STATS_TYPE_INFO; 118 static const struct ng_parse_type nga_stats_type = { 119 &ng_parse_struct_type, 120 &nga_stats_type_fields 121 }; 122 123 /* List of commands and how to convert arguments to/from ASCII */ 124 static const struct ng_cmdlist nga_cmdlist[] = { 125 { 126 NGM_ASYNC_COOKIE, 127 NGM_ASYNC_CMD_SET_CONFIG, 128 "setconfig", 129 &nga_config_type, 130 NULL 131 }, 132 { 133 NGM_ASYNC_COOKIE, 134 NGM_ASYNC_CMD_GET_CONFIG, 135 "getconfig", 136 NULL, 137 &nga_config_type 138 }, 139 { 140 NGM_ASYNC_COOKIE, 141 NGM_ASYNC_CMD_GET_STATS, 142 "getstats", 143 NULL, 144 &nga_stats_type 145 }, 146 { 147 NGM_ASYNC_COOKIE, 148 NGM_ASYNC_CMD_CLR_STATS, 149 "clrstats", 150 &nga_stats_type, 151 NULL 152 }, 153 { 0 } 154 }; 155 156 /* Define the netgraph node type */ 157 static struct ng_type typestruct = { 158 .version = NG_ABI_VERSION, 159 .name = NG_ASYNC_NODE_TYPE, 160 .constructor = nga_constructor, 161 .rcvmsg = nga_rcvmsg, 162 .shutdown = nga_shutdown, 163 .newhook = nga_newhook, 164 .rcvdata = nga_rcvdata, 165 .disconnect = nga_disconnect, 166 .cmdlist = nga_cmdlist 167 }; 168 NETGRAPH_INIT(async, &typestruct); 169 170 /* CRC table */ 171 static const u_int16_t fcstab[]; 172 173 /****************************************************************** 174 NETGRAPH NODE METHODS 175 ******************************************************************/ 176 177 /* 178 * Initialize a new node 179 */ 180 static int 181 nga_constructor(node_p node) 182 { 183 sc_p sc; 184 185 MALLOC(sc, sc_p, sizeof(*sc), M_NETGRAPH_ASYNC, M_NOWAIT | M_ZERO); 186 if (sc == NULL) 187 return (ENOMEM); 188 sc->amode = MODE_HUNT; 189 sc->cfg.accm = ~0; 190 sc->cfg.amru = NG_ASYNC_DEFAULT_MRU; 191 sc->cfg.smru = NG_ASYNC_DEFAULT_MRU; 192 MALLOC(sc->abuf, u_char *, 193 ASYNC_BUF_SIZE(sc->cfg.smru), M_NETGRAPH_ASYNC, M_NOWAIT); 194 if (sc->abuf == NULL) 195 goto fail; 196 MALLOC(sc->sbuf, u_char *, 197 SYNC_BUF_SIZE(sc->cfg.amru), M_NETGRAPH_ASYNC, M_NOWAIT); 198 if (sc->sbuf == NULL) { 199 FREE(sc->abuf, M_NETGRAPH_ASYNC); 200 fail: 201 FREE(sc, M_NETGRAPH_ASYNC); 202 return (ENOMEM); 203 } 204 NG_NODE_SET_PRIVATE(node, sc); 205 sc->node = node; 206 return (0); 207 } 208 209 /* 210 * Reserve a hook for a pending connection 211 */ 212 static int 213 nga_newhook(node_p node, hook_p hook, const char *name) 214 { 215 const sc_p sc = NG_NODE_PRIVATE(node); 216 hook_p *hookp; 217 218 if (!strcmp(name, NG_ASYNC_HOOK_ASYNC)) { 219 /* 220 * We use a static buffer here so only one packet 221 * at a time can be allowed to travel in this direction. 222 * Force Writer semantics. 223 */ 224 NG_HOOK_FORCE_WRITER(hook); 225 hookp = &sc->async; 226 } else if (!strcmp(name, NG_ASYNC_HOOK_SYNC)) { 227 /* 228 * We use a static state here so only one packet 229 * at a time can be allowed to travel in this direction. 230 * Force Writer semantics. 231 * Since we set this for both directions 232 * we might as well set it for the whole node 233 * bit I haven;t done that (yet). 234 */ 235 NG_HOOK_FORCE_WRITER(hook); 236 hookp = &sc->sync; 237 } else { 238 return (EINVAL); 239 } 240 if (*hookp) /* actually can't happen I think [JRE] */ 241 return (EISCONN); 242 *hookp = hook; 243 return (0); 244 } 245 246 /* 247 * Receive incoming data 248 */ 249 static int 250 nga_rcvdata(hook_p hook, item_p item) 251 { 252 const sc_p sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 253 254 if (hook == sc->sync) 255 return (nga_rcv_sync(sc, item)); 256 if (hook == sc->async) 257 return (nga_rcv_async(sc, item)); 258 panic(__func__); 259 } 260 261 /* 262 * Receive incoming control message 263 */ 264 static int 265 nga_rcvmsg(node_p node, item_p item, hook_p lasthook) 266 { 267 const sc_p sc = NG_NODE_PRIVATE(node); 268 struct ng_mesg *resp = NULL; 269 int error = 0; 270 struct ng_mesg *msg; 271 272 NGI_GET_MSG(item, msg); 273 switch (msg->header.typecookie) { 274 case NGM_ASYNC_COOKIE: 275 switch (msg->header.cmd) { 276 case NGM_ASYNC_CMD_GET_STATS: 277 NG_MKRESPONSE(resp, msg, sizeof(sc->stats), M_NOWAIT); 278 if (resp == NULL) 279 ERROUT(ENOMEM); 280 *((struct ng_async_stat *) resp->data) = sc->stats; 281 break; 282 case NGM_ASYNC_CMD_CLR_STATS: 283 bzero(&sc->stats, sizeof(sc->stats)); 284 break; 285 case NGM_ASYNC_CMD_SET_CONFIG: 286 { 287 struct ng_async_cfg *const cfg = 288 (struct ng_async_cfg *) msg->data; 289 u_char *buf; 290 291 if (msg->header.arglen != sizeof(*cfg)) 292 ERROUT(EINVAL); 293 if (cfg->amru < NG_ASYNC_MIN_MRU 294 || cfg->amru > NG_ASYNC_MAX_MRU 295 || cfg->smru < NG_ASYNC_MIN_MRU 296 || cfg->smru > NG_ASYNC_MAX_MRU) 297 ERROUT(EINVAL); 298 cfg->enabled = !!cfg->enabled; /* normalize */ 299 if (cfg->smru > sc->cfg.smru) { /* reallocate buffer */ 300 MALLOC(buf, u_char *, ASYNC_BUF_SIZE(cfg->smru), 301 M_NETGRAPH_ASYNC, M_NOWAIT); 302 if (!buf) 303 ERROUT(ENOMEM); 304 FREE(sc->abuf, M_NETGRAPH_ASYNC); 305 sc->abuf = buf; 306 } 307 if (cfg->amru > sc->cfg.amru) { /* reallocate buffer */ 308 MALLOC(buf, u_char *, SYNC_BUF_SIZE(cfg->amru), 309 M_NETGRAPH_ASYNC, M_NOWAIT); 310 if (!buf) 311 ERROUT(ENOMEM); 312 FREE(sc->sbuf, M_NETGRAPH_ASYNC); 313 sc->sbuf = buf; 314 sc->amode = MODE_HUNT; 315 sc->slen = 0; 316 } 317 if (!cfg->enabled) { 318 sc->amode = MODE_HUNT; 319 sc->slen = 0; 320 } 321 sc->cfg = *cfg; 322 break; 323 } 324 case NGM_ASYNC_CMD_GET_CONFIG: 325 NG_MKRESPONSE(resp, msg, sizeof(sc->cfg), M_NOWAIT); 326 if (!resp) 327 ERROUT(ENOMEM); 328 *((struct ng_async_cfg *) resp->data) = sc->cfg; 329 break; 330 default: 331 ERROUT(EINVAL); 332 } 333 break; 334 default: 335 ERROUT(EINVAL); 336 } 337 done: 338 NG_RESPOND_MSG(error, node, item, resp); 339 NG_FREE_MSG(msg); 340 return (error); 341 } 342 343 /* 344 * Shutdown this node 345 */ 346 static int 347 nga_shutdown(node_p node) 348 { 349 const sc_p sc = NG_NODE_PRIVATE(node); 350 351 FREE(sc->abuf, M_NETGRAPH_ASYNC); 352 FREE(sc->sbuf, M_NETGRAPH_ASYNC); 353 bzero(sc, sizeof(*sc)); 354 FREE(sc, M_NETGRAPH_ASYNC); 355 NG_NODE_SET_PRIVATE(node, NULL); 356 NG_NODE_UNREF(node); 357 return (0); 358 } 359 360 /* 361 * Lose a hook. When both hooks go away, we disappear. 362 */ 363 static int 364 nga_disconnect(hook_p hook) 365 { 366 const sc_p sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 367 hook_p *hookp; 368 369 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 */ 393 static __inline__ void 394 nga_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 */ 409 static int 410 nga_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 */ 501 static int 502 nga_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++; 562 reset: 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 */ 606 static 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