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