1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2006 Alexander Motin <mav@alkar.net> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice unmodified, this list of conditions, and the following 12 * disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 * 29 * $FreeBSD$ 30 */ 31 32 /* 33 * Predictor-1 PPP compression netgraph node type. 34 */ 35 36 #include <sys/param.h> 37 #include <sys/systm.h> 38 #include <sys/kernel.h> 39 #include <sys/mbuf.h> 40 #include <sys/malloc.h> 41 #include <sys/errno.h> 42 #include <sys/syslog.h> 43 44 #include <netgraph/ng_message.h> 45 #include <netgraph/netgraph.h> 46 #include <netgraph/ng_parse.h> 47 #include <netgraph/ng_pred1.h> 48 49 #include "opt_netgraph.h" 50 51 static MALLOC_DEFINE(M_NETGRAPH_PRED1, "netgraph_pred1", "netgraph pred1 node"); 52 53 /* PRED1 header length */ 54 #define PRED1_HDRLEN 2 55 56 #define PRED1_TABLE_SIZE 0x10000 57 #define PRED1_BUF_SIZE 4096 58 #define PPP_INITFCS 0xffff /* Initial FCS value */ 59 #define PPP_GOODFCS 0xf0b8 /* Good final FCS value */ 60 61 /* 62 * The following hash code is the heart of the algorithm: 63 * it builds a sliding hash sum of the previous 3-and-a-bit 64 * characters which will be used to index the guess table. 65 * A better hash function would result in additional compression, 66 * at the expense of time. 67 */ 68 69 #define HASH(x) priv->Hash = (priv->Hash << 4) ^ (x) 70 71 /* Node private data */ 72 struct ng_pred1_private { 73 struct ng_pred1_config cfg; /* configuration */ 74 u_char GuessTable[PRED1_TABLE_SIZE]; /* dictionary */ 75 u_char inbuf[PRED1_BUF_SIZE]; /* input buffer */ 76 u_char outbuf[PRED1_BUF_SIZE]; /* output buffer */ 77 struct ng_pred1_stats stats; /* statistics */ 78 uint16_t Hash; 79 ng_ID_t ctrlnode; /* path to controlling node */ 80 uint16_t seqnum; /* sequence number */ 81 u_char compress; /* compress/decompress flag */ 82 }; 83 typedef struct ng_pred1_private *priv_p; 84 85 /* Netgraph node methods */ 86 static ng_constructor_t ng_pred1_constructor; 87 static ng_rcvmsg_t ng_pred1_rcvmsg; 88 static ng_shutdown_t ng_pred1_shutdown; 89 static ng_newhook_t ng_pred1_newhook; 90 static ng_rcvdata_t ng_pred1_rcvdata; 91 static ng_disconnect_t ng_pred1_disconnect; 92 93 /* Helper functions */ 94 static int ng_pred1_compress(node_p node, struct mbuf *m, 95 struct mbuf **resultp); 96 static int ng_pred1_decompress(node_p node, struct mbuf *m, 97 struct mbuf **resultp); 98 static void Pred1Init(node_p node); 99 static int Pred1Compress(node_p node, u_char *source, u_char *dest, 100 int len); 101 static int Pred1Decompress(node_p node, u_char *source, u_char *dest, 102 int slen, int dlen); 103 static void Pred1SyncTable(node_p node, u_char *source, int len); 104 static uint16_t Crc16(uint16_t fcs, u_char *cp, int len); 105 106 static const uint16_t Crc16Table[]; 107 108 /* Parse type for struct ng_pred1_config. */ 109 static const struct ng_parse_struct_field ng_pred1_config_type_fields[] 110 = NG_PRED1_CONFIG_INFO; 111 static const struct ng_parse_type ng_pred1_config_type = { 112 &ng_parse_struct_type, 113 ng_pred1_config_type_fields 114 }; 115 116 /* Parse type for struct ng_pred1_stat. */ 117 static const struct ng_parse_struct_field ng_pred1_stats_type_fields[] 118 = NG_PRED1_STATS_INFO; 119 static const struct ng_parse_type ng_pred1_stat_type = { 120 &ng_parse_struct_type, 121 ng_pred1_stats_type_fields 122 }; 123 124 /* List of commands and how to convert arguments to/from ASCII. */ 125 static const struct ng_cmdlist ng_pred1_cmds[] = { 126 { 127 NGM_PRED1_COOKIE, 128 NGM_PRED1_CONFIG, 129 "config", 130 &ng_pred1_config_type, 131 NULL 132 }, 133 { 134 NGM_PRED1_COOKIE, 135 NGM_PRED1_RESETREQ, 136 "resetreq", 137 NULL, 138 NULL 139 }, 140 { 141 NGM_PRED1_COOKIE, 142 NGM_PRED1_GET_STATS, 143 "getstats", 144 NULL, 145 &ng_pred1_stat_type 146 }, 147 { 148 NGM_PRED1_COOKIE, 149 NGM_PRED1_CLR_STATS, 150 "clrstats", 151 NULL, 152 NULL 153 }, 154 { 155 NGM_PRED1_COOKIE, 156 NGM_PRED1_GETCLR_STATS, 157 "getclrstats", 158 NULL, 159 &ng_pred1_stat_type 160 }, 161 { 0 } 162 }; 163 164 /* Node type descriptor */ 165 static struct ng_type ng_pred1_typestruct = { 166 .version = NG_ABI_VERSION, 167 .name = NG_PRED1_NODE_TYPE, 168 .constructor = ng_pred1_constructor, 169 .rcvmsg = ng_pred1_rcvmsg, 170 .shutdown = ng_pred1_shutdown, 171 .newhook = ng_pred1_newhook, 172 .rcvdata = ng_pred1_rcvdata, 173 .disconnect = ng_pred1_disconnect, 174 .cmdlist = ng_pred1_cmds, 175 }; 176 NETGRAPH_INIT(pred1, &ng_pred1_typestruct); 177 178 #define ERROUT(x) do { error = (x); goto done; } while (0) 179 180 /************************************************************************ 181 NETGRAPH NODE STUFF 182 ************************************************************************/ 183 184 /* 185 * Node type constructor 186 */ 187 static int 188 ng_pred1_constructor(node_p node) 189 { 190 priv_p priv; 191 192 /* Allocate private structure. */ 193 priv = malloc(sizeof(*priv), M_NETGRAPH_PRED1, M_WAITOK | M_ZERO); 194 195 NG_NODE_SET_PRIVATE(node, priv); 196 197 /* This node is not thread safe. */ 198 NG_NODE_FORCE_WRITER(node); 199 200 /* Done */ 201 return (0); 202 } 203 204 /* 205 * Give our OK for a hook to be added. 206 */ 207 static int 208 ng_pred1_newhook(node_p node, hook_p hook, const char *name) 209 { 210 const priv_p priv = NG_NODE_PRIVATE(node); 211 212 if (NG_NODE_NUMHOOKS(node) > 0) 213 return (EINVAL); 214 215 if (strcmp(name, NG_PRED1_HOOK_COMP) == 0) 216 priv->compress = 1; 217 else if (strcmp(name, NG_PRED1_HOOK_DECOMP) == 0) 218 priv->compress = 0; 219 else 220 return (EINVAL); 221 222 return (0); 223 } 224 225 /* 226 * Receive a control message. 227 */ 228 static int 229 ng_pred1_rcvmsg(node_p node, item_p item, hook_p lasthook) 230 { 231 const priv_p priv = NG_NODE_PRIVATE(node); 232 struct ng_mesg *resp = NULL; 233 int error = 0; 234 struct ng_mesg *msg; 235 236 NGI_GET_MSG(item, msg); 237 238 if (msg->header.typecookie != NGM_PRED1_COOKIE) 239 ERROUT(EINVAL); 240 241 switch (msg->header.cmd) { 242 case NGM_PRED1_CONFIG: 243 { 244 struct ng_pred1_config *const cfg = 245 (struct ng_pred1_config *)msg->data; 246 247 /* Check configuration. */ 248 if (msg->header.arglen != sizeof(*cfg)) 249 ERROUT(EINVAL); 250 251 /* Configuration is OK, reset to it. */ 252 priv->cfg = *cfg; 253 254 /* Save return address so we can send reset-req's. */ 255 priv->ctrlnode = NGI_RETADDR(item); 256 257 /* Clear our state. */ 258 Pred1Init(node); 259 260 break; 261 } 262 case NGM_PRED1_RESETREQ: 263 Pred1Init(node); 264 break; 265 266 case NGM_PRED1_GET_STATS: 267 case NGM_PRED1_CLR_STATS: 268 case NGM_PRED1_GETCLR_STATS: 269 { 270 /* Create response. */ 271 if (msg->header.cmd != NGM_PRED1_CLR_STATS) { 272 NG_MKRESPONSE(resp, msg, 273 sizeof(struct ng_pred1_stats), M_NOWAIT); 274 if (resp == NULL) 275 ERROUT(ENOMEM); 276 bcopy(&priv->stats, resp->data, 277 sizeof(struct ng_pred1_stats)); 278 } 279 280 if (msg->header.cmd != NGM_PRED1_GET_STATS) 281 bzero(&priv->stats, sizeof(struct ng_pred1_stats)); 282 break; 283 } 284 285 default: 286 error = EINVAL; 287 break; 288 } 289 done: 290 NG_RESPOND_MSG(error, node, item, resp); 291 NG_FREE_MSG(msg); 292 return (error); 293 } 294 295 /* 296 * Receive incoming data on our hook. 297 */ 298 static int 299 ng_pred1_rcvdata(hook_p hook, item_p item) 300 { 301 const node_p node = NG_HOOK_NODE(hook); 302 const priv_p priv = NG_NODE_PRIVATE(node); 303 struct mbuf *m, *out; 304 int error; 305 306 if (!priv->cfg.enable) { 307 NG_FREE_ITEM(item); 308 return (ENXIO); 309 } 310 311 NGI_GET_M(item, m); 312 /* Compress. */ 313 if (priv->compress) { 314 if ((error = ng_pred1_compress(node, m, &out)) != 0) { 315 NG_FREE_ITEM(item); 316 log(LOG_NOTICE, "%s: error: %d\n", __func__, error); 317 return (error); 318 } 319 320 } else { /* Decompress. */ 321 if ((error = ng_pred1_decompress(node, m, &out)) != 0) { 322 NG_FREE_ITEM(item); 323 log(LOG_NOTICE, "%s: error: %d\n", __func__, error); 324 if (priv->ctrlnode != 0) { 325 struct ng_mesg *msg; 326 327 /* Need to send a reset-request. */ 328 NG_MKMESSAGE(msg, NGM_PRED1_COOKIE, 329 NGM_PRED1_RESETREQ, 0, M_NOWAIT); 330 if (msg == NULL) 331 return (error); 332 NG_SEND_MSG_ID(error, node, msg, 333 priv->ctrlnode, 0); 334 } 335 return (error); 336 } 337 } 338 339 NG_FWD_NEW_DATA(error, item, hook, out); 340 return (error); 341 } 342 343 /* 344 * Destroy node. 345 */ 346 static int 347 ng_pred1_shutdown(node_p node) 348 { 349 const priv_p priv = NG_NODE_PRIVATE(node); 350 351 free(priv, M_NETGRAPH_PRED1); 352 NG_NODE_SET_PRIVATE(node, NULL); 353 NG_NODE_UNREF(node); /* Let the node escape. */ 354 return (0); 355 } 356 357 /* 358 * Hook disconnection 359 */ 360 static int 361 ng_pred1_disconnect(hook_p hook) 362 { 363 const node_p node = NG_HOOK_NODE(hook); 364 365 Pred1Init(node); 366 367 /* Go away if no longer connected. */ 368 if ((NG_NODE_NUMHOOKS(node) == 0) && NG_NODE_IS_VALID(node)) 369 ng_rmnode_self(node); 370 return (0); 371 } 372 373 /************************************************************************ 374 HELPER STUFF 375 ************************************************************************/ 376 377 /* 378 * Compress/encrypt a packet and put the result in a new mbuf at *resultp. 379 * The original mbuf is not free'd. 380 */ 381 static int 382 ng_pred1_compress(node_p node, struct mbuf *m, struct mbuf **resultp) 383 { 384 const priv_p priv = NG_NODE_PRIVATE(node); 385 int outlen, inlen; 386 u_char *out; 387 uint16_t fcs, lenn; 388 int len; 389 390 /* Initialize. */ 391 *resultp = NULL; 392 393 inlen = m->m_pkthdr.len; 394 395 priv->stats.FramesPlain++; 396 priv->stats.InOctets += inlen; 397 398 /* Reserve space for expansion. */ 399 if (inlen > (PRED1_BUF_SIZE*8/9 + 1 + 4)) { 400 priv->stats.Errors++; 401 NG_FREE_M(m); 402 return (ENOMEM); 403 } 404 405 /* We must own the mbuf chain exclusively to modify it. */ 406 m = m_unshare(m, M_NOWAIT); 407 if (m == NULL) { 408 priv->stats.Errors++; 409 return (ENOMEM); 410 } 411 412 /* Work with contiguous regions of memory. */ 413 m_copydata(m, 0, inlen, (caddr_t)(priv->inbuf + 2)); 414 415 lenn = htons(inlen & 0x7FFF); 416 417 /* Compute FCS. */ 418 fcs = Crc16(PPP_INITFCS, (u_char *)&lenn, 2); 419 fcs = Crc16(fcs, priv->inbuf + 2, inlen); 420 fcs = ~fcs; 421 422 /* Compress data. */ 423 len = Pred1Compress(node, priv->inbuf + 2, priv->outbuf + 2, inlen); 424 425 /* What happened? */ 426 if (len < inlen) { 427 out = priv->outbuf; 428 outlen = 2 + len; 429 *(uint16_t *)out = lenn; 430 *out |= 0x80; 431 priv->stats.FramesComp++; 432 } else { 433 out = priv->inbuf; 434 outlen = 2 + inlen; 435 *(uint16_t *)out = lenn; 436 priv->stats.FramesUncomp++; 437 } 438 439 /* Add FCS. */ 440 (out + outlen)[0] = fcs & 0xFF; 441 (out + outlen)[1] = fcs >> 8; 442 443 /* Calculate resulting size. */ 444 outlen += 2; 445 446 /* Return packet in an mbuf. */ 447 m_copyback(m, 0, outlen, (caddr_t)out); 448 if (m->m_pkthdr.len < outlen) { 449 m_freem(m); 450 priv->stats.Errors++; 451 return (ENOMEM); 452 } else if (outlen < m->m_pkthdr.len) 453 m_adj(m, outlen - m->m_pkthdr.len); 454 *resultp = m; 455 priv->stats.OutOctets += outlen; 456 457 return (0); 458 } 459 460 /* 461 * Decompress/decrypt packet and put the result in a new mbuf at *resultp. 462 * The original mbuf is not free'd. 463 */ 464 static int 465 ng_pred1_decompress(node_p node, struct mbuf *m, struct mbuf **resultp) 466 { 467 const priv_p priv = NG_NODE_PRIVATE(node); 468 int inlen; 469 uint16_t len, len1, cf, lenn; 470 uint16_t fcs; 471 472 /* Initialize. */ 473 *resultp = NULL; 474 475 inlen = m->m_pkthdr.len; 476 477 if (inlen > PRED1_BUF_SIZE) { 478 priv->stats.Errors++; 479 NG_FREE_M(m); 480 return (ENOMEM); 481 } 482 483 /* We must own the mbuf chain exclusively to modify it. */ 484 m = m_unshare(m, M_NOWAIT); 485 if (m == NULL) { 486 priv->stats.Errors++; 487 return (ENOMEM); 488 } 489 490 /* Work with contiguous regions of memory. */ 491 m_copydata(m, 0, inlen, (caddr_t)priv->inbuf); 492 493 priv->stats.InOctets += inlen; 494 495 /* Get initial length value. */ 496 len = priv->inbuf[0] << 8; 497 len += priv->inbuf[1]; 498 499 cf = (len & 0x8000); 500 len &= 0x7fff; 501 502 /* Is data compressed or not really? */ 503 if (cf) { 504 priv->stats.FramesComp++; 505 len1 = Pred1Decompress(node, priv->inbuf + 2, priv->outbuf, 506 inlen - 4, PRED1_BUF_SIZE); 507 if (len != len1) { 508 /* Error is detected. Send reset request */ 509 m_freem(m); 510 priv->stats.Errors++; 511 log(LOG_NOTICE, "ng_pred1: Comp length error (%d) " 512 "--> len (%d)\n", len, len1); 513 return (EIO); 514 } 515 516 /* 517 * CRC check on receive is defined in RFC. It is surely required 518 * for compressed frames to signal dictionary corruption, 519 * but it is actually useless for uncompressed frames because 520 * the same check has already done by HDLC and/or other layer. 521 */ 522 lenn = htons(len); 523 fcs = Crc16(PPP_INITFCS, (u_char *)&lenn, 2); 524 fcs = Crc16(fcs, priv->outbuf, len); 525 fcs = Crc16(fcs, priv->inbuf + inlen - 2, 2); 526 527 if (fcs != PPP_GOODFCS) { 528 m_freem(m); 529 priv->stats.Errors++; 530 log(LOG_NOTICE, "ng_pred1: Pred1: Bad CRC-16\n"); 531 return (EIO); 532 } 533 534 /* Return packet in an mbuf. */ 535 m_copyback(m, 0, len, (caddr_t)priv->outbuf); 536 if (m->m_pkthdr.len < len) { 537 m_freem(m); 538 priv->stats.Errors++; 539 return (ENOMEM); 540 } else if (len < m->m_pkthdr.len) 541 m_adj(m, len - m->m_pkthdr.len); 542 *resultp = m; 543 544 } else { 545 priv->stats.FramesUncomp++; 546 if (len != (inlen - 4)) { 547 /* Wrong length. Send reset request */ 548 priv->stats.Errors++; 549 log(LOG_NOTICE, "ng_pred1: Uncomp length error (%d) " 550 "--> len (%d)\n", len, inlen - 4); 551 NG_FREE_M(m); 552 return (EIO); 553 } 554 Pred1SyncTable(node, priv->inbuf + 2, len); 555 m_adj(m, 2); /* Strip length. */ 556 m_adj(m, -2); /* Strip fcs. */ 557 *resultp = m; 558 } 559 560 priv->stats.FramesPlain++; 561 priv->stats.OutOctets += len; 562 563 return (0); 564 } 565 566 /* 567 * Pred1Init() 568 */ 569 570 static void 571 Pred1Init(node_p node) 572 { 573 const priv_p priv = NG_NODE_PRIVATE(node); 574 575 priv->Hash = 0; 576 memset(priv->GuessTable, 0, PRED1_TABLE_SIZE); 577 } 578 579 /* 580 * Pred1Compress() 581 */ 582 583 static int 584 Pred1Compress(node_p node, u_char *source, u_char *dest, int len) 585 { 586 const priv_p priv = NG_NODE_PRIVATE(node); 587 int i; 588 u_char flags; 589 u_char *flagdest, *orgdest; 590 591 orgdest = dest; 592 while (len) { 593 flagdest = dest++; 594 flags = 0; /* All guesses are wrong initially. */ 595 for (i = 0; i < 8 && len; i++) { 596 if (priv->GuessTable[priv->Hash] == *source) 597 /* Guess was right - don't output. */ 598 flags |= (1 << i); 599 else { 600 /* Guess wrong, output char. */ 601 priv->GuessTable[priv->Hash] = *source; 602 *dest++ = *source; 603 } 604 HASH(*source++); 605 len--; 606 } 607 *flagdest = flags; 608 } 609 return (dest - orgdest); 610 } 611 612 /* 613 * Pred1Decompress() 614 * 615 * Returns decompressed size, or -1 if we ran out of space. 616 */ 617 618 static int 619 Pred1Decompress(node_p node, u_char *source, u_char *dest, int slen, int dlen) 620 { 621 const priv_p priv = NG_NODE_PRIVATE(node); 622 int i; 623 u_char flags, *orgdest; 624 625 orgdest = dest; 626 while (slen) { 627 flags = *source++; 628 slen--; 629 for (i = 0; i < 8; i++, flags >>= 1) { 630 if (dlen <= 0) 631 return(-1); 632 if (flags & 0x01) 633 /* Guess correct */ 634 *dest = priv->GuessTable[priv->Hash]; 635 else { 636 if (!slen) 637 /* We seem to be really done -- cabo. */ 638 break; 639 640 /* Guess wrong. */ 641 priv->GuessTable[priv->Hash] = *source; 642 /* Read from source. */ 643 *dest = *source++; 644 slen--; 645 } 646 HASH(*dest++); 647 dlen--; 648 } 649 } 650 return (dest - orgdest); 651 } 652 653 /* 654 * Pred1SyncTable() 655 */ 656 657 static void 658 Pred1SyncTable(node_p node, u_char *source, int len) 659 { 660 const priv_p priv = NG_NODE_PRIVATE(node); 661 662 while (len--) { 663 priv->GuessTable[priv->Hash] = *source; 664 HASH(*source++); 665 } 666 } 667 668 /* 669 * Crc16() 670 * 671 * Compute the 16 bit frame check value, per RFC 1171 Appendix B, 672 * on an array of bytes. 673 */ 674 675 static uint16_t 676 Crc16(uint16_t crc, u_char *cp, int len) 677 { 678 while (len--) 679 crc = (crc >> 8) ^ Crc16Table[(crc ^ *cp++) & 0xff]; 680 return (crc); 681 } 682 683 static const uint16_t Crc16Table[256] = { 684 /* 00 */ 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, 685 /* 08 */ 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, 686 /* 10 */ 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, 687 /* 18 */ 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, 688 /* 20 */ 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, 689 /* 28 */ 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, 690 /* 30 */ 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, 691 /* 38 */ 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, 692 /* 40 */ 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, 693 /* 48 */ 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, 694 /* 50 */ 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, 695 /* 58 */ 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, 696 /* 60 */ 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, 697 /* 68 */ 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, 698 /* 70 */ 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, 699 /* 78 */ 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, 700 /* 80 */ 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, 701 /* 88 */ 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, 702 /* 90 */ 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, 703 /* 98 */ 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, 704 /* a0 */ 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, 705 /* a8 */ 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, 706 /* b0 */ 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, 707 /* b8 */ 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, 708 /* c0 */ 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, 709 /* c8 */ 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, 710 /* d0 */ 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, 711 /* d8 */ 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, 712 /* e0 */ 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, 713 /* e8 */ 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, 714 /* f0 */ 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, 715 /* f8 */ 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 716 }; 717