xref: /freebsd/sys/netgraph/ng_async.c (revision 02e9120893770924227138ba49df1edb3896112a)
1 /*
2  * ng_async.c
3  */
4 
5 /*-
6  * Copyright (c) 1996-1999 Whistle Communications, Inc.
7  * All rights reserved.
8  *
9  * Subject to the following obligations and disclaimer of warranty, use and
10  * redistribution of this software, in source or object code forms, with or
11  * without modifications are expressly permitted by Whistle Communications;
12  * provided, however, that:
13  * 1. Any and all reproductions of the source or object code must include the
14  *    copyright notice above and the following disclaimer of warranties; and
15  * 2. No rights are granted, in any manner or form, to use Whistle
16  *    Communications, Inc. trademarks, including the mark "WHISTLE
17  *    COMMUNICATIONS" on advertising, endorsements, or otherwise except as
18  *    such appears in the above copyright notice or in the software.
19  *
20  * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
21  * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
22  * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
23  * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
24  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
25  * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
26  * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
27  * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
28  * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
29  * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
30  * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
31  * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
32  * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
33  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
35  * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
36  * OF SUCH DAMAGE.
37  *
38  * Author: Archie Cobbs <archie@freebsd.org>
39  * $Whistle: ng_async.c,v 1.17 1999/11/01 09:24:51 julian Exp $
40  */
41 
42 /*
43  * This node type implements a PPP style sync <-> async converter.
44  * See RFC 1661 for details of how asynchronous encoding works.
45  */
46 
47 #include <sys/param.h>
48 #include <sys/systm.h>
49 #include <sys/kernel.h>
50 #include <sys/mbuf.h>
51 #include <sys/malloc.h>
52 #include <sys/errno.h>
53 
54 #include <netgraph/ng_message.h>
55 #include <netgraph/netgraph.h>
56 #include <netgraph/ng_async.h>
57 #include <netgraph/ng_parse.h>
58 
59 #include <net/ppp_defs.h>
60 
61 #ifdef NG_SEPARATE_MALLOC
62 static MALLOC_DEFINE(M_NETGRAPH_ASYNC, "netgraph_async", "netgraph async node");
63 #else
64 #define M_NETGRAPH_ASYNC M_NETGRAPH
65 #endif
66 
67 /* Async decode state */
68 #define MODE_HUNT	0
69 #define MODE_NORMAL	1
70 #define MODE_ESC	2
71 
72 /* Private data structure */
73 struct ng_async_private {
74 	node_p  	node;		/* Our node */
75 	hook_p  	async;		/* Asynchronous side */
76 	hook_p  	sync;		/* Synchronous side */
77 	u_char  	amode;		/* Async hunt/esape mode */
78 	u_int16_t	fcs;		/* Decoded async FCS (so far) */
79 	u_char	       *abuf;		/* Buffer to encode sync into */
80 	u_char	       *sbuf;		/* Buffer to decode async into */
81 	u_int		slen;		/* Length of data in sbuf */
82 	long		lasttime;	/* Time of last async packet sent */
83 	struct		ng_async_cfg	cfg;	/* Configuration */
84 	struct		ng_async_stat	stats;	/* Statistics */
85 };
86 typedef struct ng_async_private *sc_p;
87 
88 /* Useful macros */
89 #define ASYNC_BUF_SIZE(smru)	(2 * (smru) + 10)
90 #define SYNC_BUF_SIZE(amru)	((amru) + 10)
91 #define ERROUT(x)		do { error = (x); goto done; } while (0)
92 
93 /* Netgraph methods */
94 static ng_constructor_t		nga_constructor;
95 static ng_rcvdata_t		nga_rcvdata;
96 static ng_rcvmsg_t		nga_rcvmsg;
97 static ng_shutdown_t		nga_shutdown;
98 static ng_newhook_t		nga_newhook;
99 static ng_disconnect_t		nga_disconnect;
100 
101 /* Helper stuff */
102 static int	nga_rcv_sync(const sc_p sc, item_p item);
103 static int	nga_rcv_async(const sc_p sc, item_p item);
104 
105 /* Parse type for struct ng_async_cfg */
106 static const struct ng_parse_struct_field nga_config_type_fields[]
107 	= NG_ASYNC_CONFIG_TYPE_INFO;
108 static const struct ng_parse_type nga_config_type = {
109 	&ng_parse_struct_type,
110 	&nga_config_type_fields
111 };
112 
113 /* Parse type for struct ng_async_stat */
114 static const struct ng_parse_struct_field nga_stats_type_fields[]
115 	= NG_ASYNC_STATS_TYPE_INFO;
116 static const struct ng_parse_type nga_stats_type = {
117 	&ng_parse_struct_type,
118 	&nga_stats_type_fields
119 };
120 
121 /* List of commands and how to convert arguments to/from ASCII */
122 static const struct ng_cmdlist nga_cmdlist[] = {
123 	{
124 	  NGM_ASYNC_COOKIE,
125 	  NGM_ASYNC_CMD_SET_CONFIG,
126 	  "setconfig",
127 	  &nga_config_type,
128 	  NULL
129 	},
130 	{
131 	  NGM_ASYNC_COOKIE,
132 	  NGM_ASYNC_CMD_GET_CONFIG,
133 	  "getconfig",
134 	  NULL,
135 	  &nga_config_type
136 	},
137 	{
138 	  NGM_ASYNC_COOKIE,
139 	  NGM_ASYNC_CMD_GET_STATS,
140 	  "getstats",
141 	  NULL,
142 	  &nga_stats_type
143 	},
144 	{
145 	  NGM_ASYNC_COOKIE,
146 	  NGM_ASYNC_CMD_CLR_STATS,
147 	  "clrstats",
148 	  &nga_stats_type,
149 	  NULL
150 	},
151 	{ 0 }
152 };
153 
154 /* Define the netgraph node type */
155 static struct ng_type typestruct = {
156 	.version =	NG_ABI_VERSION,
157 	.name =		NG_ASYNC_NODE_TYPE,
158 	.constructor =	nga_constructor,
159 	.rcvmsg =	nga_rcvmsg,
160 	.shutdown = 	nga_shutdown,
161 	.newhook =	nga_newhook,
162 	.rcvdata =	nga_rcvdata,
163 	.disconnect =	nga_disconnect,
164 	.cmdlist =	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 node)
180 {
181 	sc_p sc;
182 
183 	sc = malloc(sizeof(*sc), M_NETGRAPH_ASYNC, M_WAITOK | M_ZERO);
184 	sc->amode = MODE_HUNT;
185 	sc->cfg.accm = ~0;
186 	sc->cfg.amru = NG_ASYNC_DEFAULT_MRU;
187 	sc->cfg.smru = NG_ASYNC_DEFAULT_MRU;
188 	sc->abuf = malloc(ASYNC_BUF_SIZE(sc->cfg.smru),
189 	    M_NETGRAPH_ASYNC, M_WAITOK);
190 	sc->sbuf = malloc(SYNC_BUF_SIZE(sc->cfg.amru),
191 	    M_NETGRAPH_ASYNC, M_WAITOK);
192 	NG_NODE_SET_PRIVATE(node, sc);
193 	sc->node = node;
194 	return (0);
195 }
196 
197 /*
198  * Reserve a hook for a pending connection
199  */
200 static int
201 nga_newhook(node_p node, hook_p hook, const char *name)
202 {
203 	const sc_p sc = NG_NODE_PRIVATE(node);
204 	hook_p *hookp;
205 
206 	if (!strcmp(name, NG_ASYNC_HOOK_ASYNC)) {
207 		/*
208 		 * We use a static buffer here so only one packet
209 		 * at a time can be allowed to travel in this direction.
210 		 * Force Writer semantics.
211 		 */
212 		NG_HOOK_FORCE_WRITER(hook);
213 		hookp = &sc->async;
214 	} else if (!strcmp(name, NG_ASYNC_HOOK_SYNC)) {
215 		/*
216 		 * We use a static state here so only one packet
217 		 * at a time can be allowed to travel in this direction.
218 		 * Force Writer semantics.
219 		 * Since we set this for both directions
220 		 * we might as well set it for the whole node
221 		 * bit I haven;t done that (yet).
222 		 */
223 		NG_HOOK_FORCE_WRITER(hook);
224 		hookp = &sc->sync;
225 	} else {
226 		return (EINVAL);
227 	}
228 	if (*hookp) /* actually can't happen I think [JRE] */
229 		return (EISCONN);
230 	*hookp = hook;
231 	return (0);
232 }
233 
234 /*
235  * Receive incoming data
236  */
237 static int
238 nga_rcvdata(hook_p hook, item_p item)
239 {
240 	const sc_p sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
241 
242 	if (hook == sc->sync)
243 		return (nga_rcv_sync(sc, item));
244 	if (hook == sc->async)
245 		return (nga_rcv_async(sc, item));
246 	panic("%s", __func__);
247 }
248 
249 /*
250  * Receive incoming control message
251  */
252 static int
253 nga_rcvmsg(node_p node, item_p item, hook_p lasthook)
254 {
255 	const sc_p sc = NG_NODE_PRIVATE(node);
256 	struct ng_mesg *resp = NULL;
257 	int error = 0;
258 	struct ng_mesg *msg;
259 
260 	NGI_GET_MSG(item, msg);
261 	switch (msg->header.typecookie) {
262 	case NGM_ASYNC_COOKIE:
263 		switch (msg->header.cmd) {
264 		case NGM_ASYNC_CMD_GET_STATS:
265 			NG_MKRESPONSE(resp, msg, sizeof(sc->stats), M_NOWAIT);
266 			if (resp == NULL)
267 				ERROUT(ENOMEM);
268 			*((struct ng_async_stat *) resp->data) = sc->stats;
269 			break;
270 		case NGM_ASYNC_CMD_CLR_STATS:
271 			bzero(&sc->stats, sizeof(sc->stats));
272 			break;
273 		case NGM_ASYNC_CMD_SET_CONFIG:
274 		    {
275 			struct ng_async_cfg *const cfg =
276 				(struct ng_async_cfg *) msg->data;
277 			u_char *buf;
278 
279 			if (msg->header.arglen != sizeof(*cfg))
280 				ERROUT(EINVAL);
281 			if (cfg->amru < NG_ASYNC_MIN_MRU
282 			    || cfg->amru > NG_ASYNC_MAX_MRU
283 			    || cfg->smru < NG_ASYNC_MIN_MRU
284 			    || cfg->smru > NG_ASYNC_MAX_MRU)
285 				ERROUT(EINVAL);
286 			cfg->enabled = !!cfg->enabled;	/* normalize */
287 			if (cfg->smru > sc->cfg.smru) {	/* reallocate buffer */
288 				buf = malloc(ASYNC_BUF_SIZE(cfg->smru),
289 				    M_NETGRAPH_ASYNC, M_NOWAIT);
290 				if (!buf)
291 					ERROUT(ENOMEM);
292 				free(sc->abuf, M_NETGRAPH_ASYNC);
293 				sc->abuf = buf;
294 			}
295 			if (cfg->amru > sc->cfg.amru) {	/* reallocate buffer */
296 				buf = malloc(SYNC_BUF_SIZE(cfg->amru),
297 				    M_NETGRAPH_ASYNC, M_NOWAIT);
298 				if (!buf)
299 					ERROUT(ENOMEM);
300 				free(sc->sbuf, M_NETGRAPH_ASYNC);
301 				sc->sbuf = buf;
302 				sc->amode = MODE_HUNT;
303 				sc->slen = 0;
304 			}
305 			if (!cfg->enabled) {
306 				sc->amode = MODE_HUNT;
307 				sc->slen = 0;
308 			}
309 			sc->cfg = *cfg;
310 			break;
311 		    }
312 		case NGM_ASYNC_CMD_GET_CONFIG:
313 			NG_MKRESPONSE(resp, msg, sizeof(sc->cfg), M_NOWAIT);
314 			if (!resp)
315 				ERROUT(ENOMEM);
316 			*((struct ng_async_cfg *) resp->data) = sc->cfg;
317 			break;
318 		default:
319 			ERROUT(EINVAL);
320 		}
321 		break;
322 	default:
323 		ERROUT(EINVAL);
324 	}
325 done:
326 	NG_RESPOND_MSG(error, node, item, resp);
327 	NG_FREE_MSG(msg);
328 	return (error);
329 }
330 
331 /*
332  * Shutdown this node
333  */
334 static int
335 nga_shutdown(node_p node)
336 {
337 	const sc_p sc = NG_NODE_PRIVATE(node);
338 
339 	free(sc->abuf, M_NETGRAPH_ASYNC);
340 	free(sc->sbuf, M_NETGRAPH_ASYNC);
341 	bzero(sc, sizeof(*sc));
342 	free(sc, M_NETGRAPH_ASYNC);
343 	NG_NODE_SET_PRIVATE(node, NULL);
344 	NG_NODE_UNREF(node);
345 	return (0);
346 }
347 
348 /*
349  * Lose a hook. When both hooks go away, we disappear.
350  */
351 static int
352 nga_disconnect(hook_p hook)
353 {
354 	const sc_p sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
355 	hook_p *hookp;
356 
357 	if (hook == sc->async)
358 		hookp = &sc->async;
359 	else if (hook == sc->sync)
360 		hookp = &sc->sync;
361 	else
362 		panic("%s", __func__);
363 	if (!*hookp)
364 		panic("%s 2", __func__);
365 	*hookp = NULL;
366 	bzero(&sc->stats, sizeof(sc->stats));
367 	sc->lasttime = 0;
368 	if ((NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0)
369 	&& (NG_NODE_IS_VALID(NG_HOOK_NODE(hook))))
370 		ng_rmnode_self(NG_HOOK_NODE(hook));
371 	return (0);
372 }
373 
374 /******************************************************************
375 		    INTERNAL HELPER STUFF
376 ******************************************************************/
377 
378 /*
379  * Encode a byte into the async buffer
380  */
381 static __inline void
382 nga_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  */
397 static int
398 nga_rcv_sync(const sc_p sc, item_p item)
399 {
400 	struct ifnet *rcvif;
401 	int alen, error = 0;
402 	struct timeval time;
403 	u_int16_t fcs, fcs0;
404 	u_int32_t accm;
405 	struct mbuf *m;
406 
407 #define ADD_BYTE(x)	nga_async_add(sc, &fcs, accm, &alen, (x))
408 
409 	/* Check for bypass mode */
410 	if (!sc->cfg.enabled) {
411 		NG_FWD_ITEM_HOOK(error, item, sc->async );
412 		return (error);
413 	}
414 	NGI_GET_M(item, m);
415 
416 	rcvif = m->m_pkthdr.rcvif;
417 
418 	/* Get ACCM; special case LCP frames, which use full ACCM */
419 	accm = sc->cfg.accm;
420 	if (m->m_pkthdr.len >= 4) {
421 		static const u_char lcphdr[4] = {
422 		    PPP_ALLSTATIONS,
423 		    PPP_UI,
424 		    (u_char)(PPP_LCP >> 8),
425 		    (u_char)(PPP_LCP & 0xff)
426 		};
427 		u_char buf[4];
428 
429 		m_copydata(m, 0, 4, (caddr_t)buf);
430 		if (bcmp(buf, &lcphdr, 4) == 0)
431 			accm = ~0;
432 	}
433 
434 	/* Check for overflow */
435 	if (m->m_pkthdr.len > sc->cfg.smru) {
436 		sc->stats.syncOverflows++;
437 		NG_FREE_M(m);
438 		NG_FREE_ITEM(item);
439 		return (EMSGSIZE);
440 	}
441 
442 	/* Update stats */
443 	sc->stats.syncFrames++;
444 	sc->stats.syncOctets += m->m_pkthdr.len;
445 
446 	/* Initialize async encoded version of input mbuf */
447 	alen = 0;
448 	fcs = PPP_INITFCS;
449 
450 	/* Add beginning sync flag if it's been long enough to need one */
451 	getmicrotime(&time);
452 	if (time.tv_sec >= sc->lasttime + 1) {
453 		sc->abuf[alen++] = PPP_FLAG;
454 		sc->lasttime = time.tv_sec;
455 	}
456 
457 	/* Add packet payload */
458 	while (m != NULL) {
459 		while (m->m_len > 0) {
460 			ADD_BYTE(*mtod(m, u_char *));
461 			m->m_data++;
462 			m->m_len--;
463 		}
464 		m = m_free(m);
465 	}
466 
467 	/* Add checksum and final sync flag */
468 	fcs0 = fcs;
469 	ADD_BYTE(~fcs0 & 0xff);
470 	ADD_BYTE(~fcs0 >> 8);
471 	sc->abuf[alen++] = PPP_FLAG;
472 
473 	/* Put frame in an mbuf and ship it off */
474 	if (!(m = m_devget(sc->abuf, alen, 0, rcvif, NULL))) {
475 		NG_FREE_ITEM(item);
476 		error = ENOBUFS;
477 	} else {
478 		NG_FWD_NEW_DATA(error, item, sc->async, m);
479 	}
480 	return (error);
481 }
482 
483 /*
484  * Receive incoming asynchronous data
485  * XXX Technically, we should strip out incoming characters
486  *     that are in our ACCM. Not sure if this is good or not.
487  */
488 static int
489 nga_rcv_async(const sc_p sc, item_p item)
490 {
491 	struct ifnet *rcvif;
492 	int error;
493 	struct mbuf *m;
494 
495 	if (!sc->cfg.enabled) {
496 		NG_FWD_ITEM_HOOK(error, item,  sc->sync);
497 		return (error);
498 	}
499 	NGI_GET_M(item, m);
500 	rcvif = m->m_pkthdr.rcvif;
501 	while (m) {
502 		struct mbuf *n;
503 
504 		for (; m->m_len > 0; m->m_data++, m->m_len--) {
505 			u_char  ch = *mtod(m, u_char *);
506 
507 			sc->stats.asyncOctets++;
508 			if (ch == PPP_FLAG) {	/* Flag overrides everything */
509 				int     skip = 0;
510 
511 				/* Check for runts */
512 				if (sc->slen < 2) {
513 					if (sc->slen > 0)
514 						sc->stats.asyncRunts++;
515 					goto reset;
516 				}
517 
518 				/* Verify CRC */
519 				if (sc->fcs != PPP_GOODFCS) {
520 					sc->stats.asyncBadCheckSums++;
521 					goto reset;
522 				}
523 				sc->slen -= 2;
524 
525 				/* Strip address and control fields */
526 				if (sc->slen >= 2
527 				    && sc->sbuf[0] == PPP_ALLSTATIONS
528 				    && sc->sbuf[1] == PPP_UI)
529 					skip = 2;
530 
531 				/* Check for frame too big */
532 				if (sc->slen - skip > sc->cfg.amru) {
533 					sc->stats.asyncOverflows++;
534 					goto reset;
535 				}
536 
537 				/* OK, ship it out */
538 				if ((n = m_devget(sc->sbuf + skip,
539 					   sc->slen - skip, 0, rcvif, NULL))) {
540 					if (item) { /* sets NULL -> item */
541 						NG_FWD_NEW_DATA(error, item,
542 							sc->sync, n);
543 					} else {
544 						NG_SEND_DATA_ONLY(error,
545 							sc->sync ,n);
546 					}
547 				}
548 				sc->stats.asyncFrames++;
549 reset:
550 				sc->amode = MODE_NORMAL;
551 				sc->fcs = PPP_INITFCS;
552 				sc->slen = 0;
553 				continue;
554 			}
555 			switch (sc->amode) {
556 			case MODE_NORMAL:
557 				if (ch == PPP_ESCAPE) {
558 					sc->amode = MODE_ESC;
559 					continue;
560 				}
561 				break;
562 			case MODE_ESC:
563 				ch ^= PPP_TRANS;
564 				sc->amode = MODE_NORMAL;
565 				break;
566 			case MODE_HUNT:
567 			default:
568 				continue;
569 			}
570 
571 			/* Add byte to frame */
572 			if (sc->slen >= SYNC_BUF_SIZE(sc->cfg.amru)) {
573 				sc->stats.asyncOverflows++;
574 				sc->amode = MODE_HUNT;
575 				sc->slen = 0;
576 			} else {
577 				sc->sbuf[sc->slen++] = ch;
578 				sc->fcs = PPP_FCS(sc->fcs, ch);
579 			}
580 		}
581 		m = m_free(m);
582 	}
583 	if (item)
584 		NG_FREE_ITEM(item);
585 	return (0);
586 }
587 
588 /*
589  * CRC table
590  *
591  * Taken from RFC 1171 Appendix B
592  */
593 static const u_int16_t fcstab[256] = {
594 	 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
595 	 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
596 	 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
597 	 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
598 	 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
599 	 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
600 	 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
601 	 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
602 	 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
603 	 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
604 	 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
605 	 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
606 	 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
607 	 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
608 	 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
609 	 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
610 	 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
611 	 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
612 	 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
613 	 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
614 	 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
615 	 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
616 	 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
617 	 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
618 	 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
619 	 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
620 	 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
621 	 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
622 	 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
623 	 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
624 	 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
625 	 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
626 };
627