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