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