Deleted Added
sdiff udiff text old ( 69922 ) new ( 70159 )
full compact
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: head/sys/netgraph/ng_async.c 70159 2000-12-18 20:03:32Z julian $
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/* Async decode state */
63#define MODE_HUNT 0
64#define MODE_NORMAL 1
65#define MODE_ESC 2
66
67/* Private data structure */
68struct ng_async_private {
69 node_p node; /* Our node */
70 hook_p async; /* Asynchronous side */
71 hook_p sync; /* Synchronous side */
72 u_char amode; /* Async hunt/esape mode */
73 u_int16_t fcs; /* Decoded async FCS (so far) */
74 u_char *abuf; /* Buffer to encode sync into */
75 u_char *sbuf; /* Buffer to decode async into */
76 u_int slen; /* Length of data in sbuf */
77 long lasttime; /* Time of last async packet sent */
78 struct ng_async_cfg cfg; /* Configuration */
79 struct ng_async_stat stats; /* Statistics */
80};
81typedef struct ng_async_private *sc_p;
82
83/* Useful macros */
84#define ASYNC_BUF_SIZE(smru) (2 * (smru) + 10)
85#define SYNC_BUF_SIZE(amru) ((amru) + 10)
86#define ERROUT(x) do { error = (x); goto done; } while (0)
87
88/* Netgraph methods */
89static ng_constructor_t nga_constructor;
90static ng_rcvdata_t nga_rcvdata;
91static ng_rcvmsg_t nga_rcvmsg;
92static ng_shutdown_t nga_shutdown;
93static ng_newhook_t nga_newhook;
94static ng_disconnect_t nga_disconnect;
95
96/* Helper stuff */
97static int nga_rcv_sync(const sc_p sc, struct mbuf *m, meta_p meta);
98static int nga_rcv_async(const sc_p sc, struct mbuf *m, meta_p meta);
99
100/* Parse type for struct ng_async_cfg */
101static const struct ng_parse_struct_info
102 nga_config_type_info = NG_ASYNC_CONFIG_TYPE_INFO;
103static const struct ng_parse_type nga_config_type = {
104 &ng_parse_struct_type,
105 &nga_config_type_info
106};
107
108/* Parse type for struct ng_async_stat */
109static const struct ng_parse_struct_info
110 nga_stats_type_info = NG_ASYNC_STATS_TYPE_INFO;
111static const struct ng_parse_type nga_stats_type = {
112 &ng_parse_struct_type,
113 &nga_stats_type_info,
114};
115
116/* List of commands and how to convert arguments to/from ASCII */
117static const struct ng_cmdlist nga_cmdlist[] = {
118 {
119 NGM_ASYNC_COOKIE,
120 NGM_ASYNC_CMD_SET_CONFIG,
121 "setconfig",
122 &nga_config_type,
123 NULL
124 },
125 {
126 NGM_ASYNC_COOKIE,
127 NGM_ASYNC_CMD_GET_CONFIG,
128 "getconfig",
129 NULL,
130 &nga_config_type
131 },
132 {
133 NGM_ASYNC_COOKIE,
134 NGM_ASYNC_CMD_GET_STATS,
135 "getstats",
136 NULL,
137 &nga_stats_type
138 },
139 {
140 NGM_ASYNC_COOKIE,
141 NGM_ASYNC_CMD_CLR_STATS,
142 "clrstats",
143 &nga_stats_type,
144 NULL
145 },
146 { 0 }
147};
148
149/* Define the netgraph node type */
150static struct ng_type typestruct = {
151 NG_ABI_VERSION,
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};