ng_async.c revision 70700
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 70700 2001-01-06 00:46:47Z 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, item_p item);
98static int	nga_rcv_async(const sc_p sc, item_p item);
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_ABI_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_disconnect,
162	nga_cmdlist
163};
164NETGRAPH_INIT(async, &typestruct);
165
166/* CRC table */
167static const u_int16_t fcstab[];
168
169/******************************************************************
170		    NETGRAPH NODE METHODS
171******************************************************************/
172
173/*
174 * Initialize a new node
175 */
176static int
177nga_constructor(node_p node)
178{
179	sc_p sc;
180
181	MALLOC(sc, sc_p, sizeof(*sc), M_NETGRAPH, M_NOWAIT | M_ZERO);
182	if (sc == NULL)
183		return (ENOMEM);
184	sc->amode = MODE_HUNT;
185	sc->cfg.accm = ~0;
186	sc->cfg.amru = NG_ASYNC_DEFAULT_MRU;
187	sc->cfg.smru = NG_ASYNC_DEFAULT_MRU;
188	MALLOC(sc->abuf, u_char *,
189	    ASYNC_BUF_SIZE(sc->cfg.smru), M_NETGRAPH, M_NOWAIT);
190	if (sc->abuf == NULL)
191		goto fail;
192	MALLOC(sc->sbuf, u_char *,
193	    SYNC_BUF_SIZE(sc->cfg.amru), M_NETGRAPH, M_NOWAIT);
194	if (sc->sbuf == NULL) {
195		FREE(sc->abuf, M_NETGRAPH);
196fail:
197		FREE(sc, M_NETGRAPH);
198		return (ENOMEM);
199	}
200	node->private = sc;
201	sc->node = node;
202	return (0);
203}
204
205/*
206 * Reserve a hook for a pending connection
207 */
208static int
209nga_newhook(node_p node, hook_p hook, const char *name)
210{
211	const sc_p sc = node->private;
212	hook_p *hookp;
213
214	if (!strcmp(name, NG_ASYNC_HOOK_ASYNC)) {
215		/*
216		 * We use a static buffer here so only one packet
217		 * at a time can be allowed to travel in this direction.
218		 * Force Writer semantics.
219		 */
220		hook->flags |= HK_FORCE_WRITER;
221		hookp = &sc->async;
222	} else if (!strcmp(name, NG_ASYNC_HOOK_SYNC)) {
223		/*
224		 * We use a static state here so only one packet
225		 * at a time can be allowed to travel in this direction.
226		 * Force Writer semantics.
227		 * Since we set this for both directions
228		 * we might as well set it for the whole node
229		 * bit I haven;t done that (yet).
230		 */
231		hook->flags |= HK_FORCE_WRITER;
232		hookp = &sc->async;
233		hookp = &sc->sync;
234	} else {
235		return (EINVAL);
236	}
237	if (*hookp) /* actually can't happen I think [JRE] */
238		return (EISCONN);
239	*hookp = hook;
240	return (0);
241}
242
243/*
244 * Receive incoming data
245 */
246static int
247nga_rcvdata(hook_p hook, item_p item)
248{
249	const sc_p sc = hook->node->private;
250#ifdef	ITEM_DEBUG
251	meta_p meta = NGI_META(item);
252#endif
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(__FUNCTION__);
259}
260
261/*
262 * Receive incoming control message
263 */
264static int
265nga_rcvmsg(node_p node, item_p item, hook_p lasthook)
266{
267	const sc_p sc = (sc_p) node->private;
268	struct ng_mesg *resp = NULL;
269	int error = 0;
270	struct ng_mesg *msg;
271
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, M_NOWAIT);
303				if (!buf)
304					ERROUT(ENOMEM);
305				FREE(sc->abuf, M_NETGRAPH);
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, M_NOWAIT);
311				if (!buf)
312					ERROUT(ENOMEM);
313				FREE(sc->sbuf, M_NETGRAPH);
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	}
338done:
339	NG_RESPOND_MSG(error, node, item, resp);
340	NG_FREE_MSG(msg);
341	return (error);
342}
343
344/*
345 * Shutdown this node
346 */
347static int
348nga_shutdown(node_p node)
349{
350	const sc_p sc = node->private;
351
352	FREE(sc->abuf, M_NETGRAPH);
353	FREE(sc->sbuf, M_NETGRAPH);
354	bzero(sc, sizeof(*sc));
355	FREE(sc, M_NETGRAPH);
356	node->private = NULL;
357	ng_unref(node);
358	return (0);
359}
360
361/*
362 * Lose a hook. When both hooks go away, we disappear.
363 */
364static int
365nga_disconnect(hook_p hook)
366{
367	const sc_p sc = hook->node->private;
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(__FUNCTION__);
376	if (!*hookp)
377		panic(__FUNCTION__ "2");
378	*hookp = NULL;
379	bzero(&sc->stats, sizeof(sc->stats));
380	sc->lasttime = 0;
381	if ((hook->node->numhooks == 0)
382	&& ((hook->node->flags & NG_INVALID) == 0))
383		ng_rmnode_self(hook->node);
384	return (0);
385}
386
387/******************************************************************
388		    INTERNAL HELPER STUFF
389******************************************************************/
390
391/*
392 * Encode a byte into the async buffer
393 */
394static __inline__ void
395nga_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 */
410static int
411nga_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_DATA(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		struct mbuf *n;
474
475		while (m->m_len > 0) {
476			ADD_BYTE(*mtod(m, u_char *));
477			m->m_data++;
478			m->m_len--;
479		}
480		MFREE(m, n);
481		m = n;
482	}
483
484	/* Add checksum and final sync flag */
485	fcs0 = fcs;
486	ADD_BYTE(~fcs0 & 0xff);
487	ADD_BYTE(~fcs0 >> 8);
488	sc->abuf[alen++] = PPP_FLAG;
489
490	/* Put frame in an mbuf and ship it off */
491	if (!(m = m_devget(sc->abuf, alen, 0, rcvif, NULL))) {
492		NG_FREE_ITEM(item);
493		error = ENOBUFS;
494	} else {
495		NG_FWD_NEW_DATA(error, item, sc->async, m);
496	}
497	return (error);
498}
499
500/*
501 * Receive incoming asynchronous data
502 * XXX Technically, we should strip out incoming characters
503 *     that are in our ACCM. Not sure if this is good or not.
504 */
505static int
506nga_rcv_async(const sc_p sc, item_p item)
507{
508	struct ifnet *rcvif;
509	int error;
510	struct mbuf *m;
511
512	if (!sc->cfg.enabled) {
513		NG_FWD_DATA(error, item,  sc->sync);
514		return (error);
515	}
516	NGI_GET_M(item, m);
517	rcvif = m->m_pkthdr.rcvif;
518	while (m) {
519		struct mbuf *n;
520
521		for (; m->m_len > 0; m->m_data++, m->m_len--) {
522			u_char  ch = *mtod(m, u_char *);
523
524			sc->stats.asyncOctets++;
525			if (ch == PPP_FLAG) {	/* Flag overrides everything */
526				int     skip = 0;
527
528				/* Check for runts */
529				if (sc->slen < 2) {
530					if (sc->slen > 0)
531						sc->stats.asyncRunts++;
532					goto reset;
533				}
534
535				/* Verify CRC */
536				if (sc->fcs != PPP_GOODFCS) {
537					sc->stats.asyncBadCheckSums++;
538					goto reset;
539				}
540				sc->slen -= 2;
541
542				/* Strip address and control fields */
543				if (sc->slen >= 2
544				    && sc->sbuf[0] == PPP_ALLSTATIONS
545				    && sc->sbuf[1] == PPP_UI)
546					skip = 2;
547
548				/* Check for frame too big */
549				if (sc->slen - skip > sc->cfg.amru) {
550					sc->stats.asyncOverflows++;
551					goto reset;
552				}
553
554				/* OK, ship it out */
555				if ((n = m_devget(sc->sbuf + skip,
556					   sc->slen - skip, 0, rcvif, NULL))) {
557					if (item) { /* sets NULL -> item */
558						NG_FWD_NEW_DATA(error, item,
559							sc->sync, n);
560					} else {
561						NG_SEND_DATA_ONLY(error,
562							sc->sync ,n);
563					}
564				}
565				sc->stats.asyncFrames++;
566reset:
567				sc->amode = MODE_NORMAL;
568				sc->fcs = PPP_INITFCS;
569				sc->slen = 0;
570				continue;
571			}
572			switch (sc->amode) {
573			case MODE_NORMAL:
574				if (ch == PPP_ESCAPE) {
575					sc->amode = MODE_ESC;
576					continue;
577				}
578				break;
579			case MODE_ESC:
580				ch ^= PPP_TRANS;
581				sc->amode = MODE_NORMAL;
582				break;
583			case MODE_HUNT:
584			default:
585				continue;
586			}
587
588			/* Add byte to frame */
589			if (sc->slen >= SYNC_BUF_SIZE(sc->cfg.amru)) {
590				sc->stats.asyncOverflows++;
591				sc->amode = MODE_HUNT;
592				sc->slen = 0;
593			} else {
594				sc->sbuf[sc->slen++] = ch;
595				sc->fcs = PPP_FCS(sc->fcs, ch);
596			}
597		}
598		MFREE(m, n);
599		m = n;
600	}
601	if (item)
602		NG_FREE_ITEM(item);
603	return (0);
604}
605
606/*
607 * CRC table
608 *
609 * Taken from RFC 1171 Appendix B
610 */
611static const u_int16_t fcstab[256] = {
612	 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
613	 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
614	 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
615	 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
616	 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
617	 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
618	 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
619	 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
620	 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
621	 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
622	 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
623	 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
624	 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
625	 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
626	 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
627	 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
628	 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
629	 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
630	 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
631	 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
632	 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
633	 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
634	 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
635	 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
636	 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
637	 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
638	 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
639	 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
640	 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
641	 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
642	 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
643	 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
644};
645