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