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