ng_async.c revision 70870
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: head/sys/netgraph/ng_async.c 70870 2001-01-10 07:13:58Z julian $
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
63MALLOC_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 */
75struct 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};
88typedef 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 */
96static ng_constructor_t		nga_constructor;
97static ng_rcvdata_t		nga_rcvdata;
98static ng_rcvmsg_t		nga_rcvmsg;
99static ng_shutdown_t		nga_shutdown;
100static ng_newhook_t		nga_newhook;
101static ng_disconnect_t		nga_disconnect;
102
103/* Helper stuff */
104static int	nga_rcv_sync(const sc_p sc, item_p item);
105static int	nga_rcv_async(const sc_p sc, item_p item);
106
107/* Parse type for struct ng_async_cfg */
108static const struct ng_parse_struct_info
109	nga_config_type_info = NG_ASYNC_CONFIG_TYPE_INFO;
110static 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 */
116static const struct ng_parse_struct_info
117	nga_stats_type_info = NG_ASYNC_STATS_TYPE_INFO;
118static 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 */
124static 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 */
157static 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};
171NETGRAPH_INIT(async, &typestruct);
172
173/* CRC table */
174static const u_int16_t fcstab[];
175
176/******************************************************************
177		    NETGRAPH NODE METHODS
178******************************************************************/
179
180/*
181 * Initialize a new node
182 */
183static int
184nga_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);
203fail:
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 */
215static int
216nga_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 */
252static int
253nga_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 */
267static int
268nga_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	}
340done:
341	NG_RESPOND_MSG(error, node, item, resp);
342	NG_FREE_MSG(msg);
343	return (error);
344}
345
346/*
347 * Shutdown this node
348 */
349static int
350nga_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 */
366static int
367nga_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 */
396static __inline__ void
397nga_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 */
412static int
413nga_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 */
507static int
508nga_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++;
568reset:
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 */
613static 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