xref: /freebsd/sys/netgraph/ng_async.c (revision 5521ff5a4d1929056e7ffc982fac3341ca54df7c)
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(__FUNCTION__);
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(__FUNCTION__);
378 	if (!*hookp)
379 		panic(__FUNCTION__ "2");
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 		struct mbuf *n;
476 
477 		while (m->m_len > 0) {
478 			ADD_BYTE(*mtod(m, u_char *));
479 			m->m_data++;
480 			m->m_len--;
481 		}
482 		MFREE(m, n);
483 		m = n;
484 	}
485 
486 	/* Add checksum and final sync flag */
487 	fcs0 = fcs;
488 	ADD_BYTE(~fcs0 & 0xff);
489 	ADD_BYTE(~fcs0 >> 8);
490 	sc->abuf[alen++] = PPP_FLAG;
491 
492 	/* Put frame in an mbuf and ship it off */
493 	if (!(m = m_devget(sc->abuf, alen, 0, rcvif, NULL))) {
494 		NG_FREE_ITEM(item);
495 		error = ENOBUFS;
496 	} else {
497 		NG_FWD_NEW_DATA(error, item, sc->async, m);
498 	}
499 	return (error);
500 }
501 
502 /*
503  * Receive incoming asynchronous data
504  * XXX Technically, we should strip out incoming characters
505  *     that are in our ACCM. Not sure if this is good or not.
506  */
507 static int
508 nga_rcv_async(const sc_p sc, item_p item)
509 {
510 	struct ifnet *rcvif;
511 	int error;
512 	struct mbuf *m;
513 
514 	if (!sc->cfg.enabled) {
515 		NG_FWD_ITEM_HOOK(error, item,  sc->sync);
516 		return (error);
517 	}
518 	NGI_GET_M(item, m);
519 	rcvif = m->m_pkthdr.rcvif;
520 	while (m) {
521 		struct mbuf *n;
522 
523 		for (; m->m_len > 0; m->m_data++, m->m_len--) {
524 			u_char  ch = *mtod(m, u_char *);
525 
526 			sc->stats.asyncOctets++;
527 			if (ch == PPP_FLAG) {	/* Flag overrides everything */
528 				int     skip = 0;
529 
530 				/* Check for runts */
531 				if (sc->slen < 2) {
532 					if (sc->slen > 0)
533 						sc->stats.asyncRunts++;
534 					goto reset;
535 				}
536 
537 				/* Verify CRC */
538 				if (sc->fcs != PPP_GOODFCS) {
539 					sc->stats.asyncBadCheckSums++;
540 					goto reset;
541 				}
542 				sc->slen -= 2;
543 
544 				/* Strip address and control fields */
545 				if (sc->slen >= 2
546 				    && sc->sbuf[0] == PPP_ALLSTATIONS
547 				    && sc->sbuf[1] == PPP_UI)
548 					skip = 2;
549 
550 				/* Check for frame too big */
551 				if (sc->slen - skip > sc->cfg.amru) {
552 					sc->stats.asyncOverflows++;
553 					goto reset;
554 				}
555 
556 				/* OK, ship it out */
557 				if ((n = m_devget(sc->sbuf + skip,
558 					   sc->slen - skip, 0, rcvif, NULL))) {
559 					if (item) { /* sets NULL -> item */
560 						NG_FWD_NEW_DATA(error, item,
561 							sc->sync, n);
562 					} else {
563 						NG_SEND_DATA_ONLY(error,
564 							sc->sync ,n);
565 					}
566 				}
567 				sc->stats.asyncFrames++;
568 reset:
569 				sc->amode = MODE_NORMAL;
570 				sc->fcs = PPP_INITFCS;
571 				sc->slen = 0;
572 				continue;
573 			}
574 			switch (sc->amode) {
575 			case MODE_NORMAL:
576 				if (ch == PPP_ESCAPE) {
577 					sc->amode = MODE_ESC;
578 					continue;
579 				}
580 				break;
581 			case MODE_ESC:
582 				ch ^= PPP_TRANS;
583 				sc->amode = MODE_NORMAL;
584 				break;
585 			case MODE_HUNT:
586 			default:
587 				continue;
588 			}
589 
590 			/* Add byte to frame */
591 			if (sc->slen >= SYNC_BUF_SIZE(sc->cfg.amru)) {
592 				sc->stats.asyncOverflows++;
593 				sc->amode = MODE_HUNT;
594 				sc->slen = 0;
595 			} else {
596 				sc->sbuf[sc->slen++] = ch;
597 				sc->fcs = PPP_FCS(sc->fcs, ch);
598 			}
599 		}
600 		MFREE(m, n);
601 		m = n;
602 	}
603 	if (item)
604 		NG_FREE_ITEM(item);
605 	return (0);
606 }
607 
608 /*
609  * CRC table
610  *
611  * Taken from RFC 1171 Appendix B
612  */
613 static const u_int16_t fcstab[256] = {
614 	 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
615 	 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
616 	 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
617 	 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
618 	 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
619 	 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
620 	 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
621 	 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
622 	 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
623 	 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
624 	 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
625 	 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
626 	 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
627 	 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
628 	 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
629 	 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
630 	 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
631 	 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
632 	 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
633 	 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
634 	 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
635 	 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
636 	 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
637 	 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
638 	 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
639 	 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
640 	 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
641 	 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
642 	 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
643 	 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
644 	 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
645 	 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
646 };
647