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