1/*
2 * ng_async.c
3 */
4
5/*-
6 * Copyright (c) 1996-1999 Whistle Communications, Inc.
7 * All rights reserved.
8 *
9 * Subject to the following obligations and disclaimer of warranty, use and
10 * redistribution of this software, in source or object code forms, with or
11 * without modifications are expressly permitted by Whistle Communications;
12 * provided, however, that:
13 * 1. Any and all reproductions of the source or object code must include the
14 *    copyright notice above and the following disclaimer of warranties; and
15 * 2. No rights are granted, in any manner or form, to use Whistle
16 *    Communications, Inc. trademarks, including the mark "WHISTLE
17 *    COMMUNICATIONS" on advertising, endorsements, or otherwise except as
18 *    such appears in the above copyright notice or in the software.
19 *
20 * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
21 * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
22 * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
23 * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
24 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
25 * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
26 * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
27 * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
28 * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
29 * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
30 * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
31 * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
32 * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
35 * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
36 * OF SUCH DAMAGE.
37 *
38 * Author: Archie Cobbs <archie@freebsd.org>
39 *
40 * $FreeBSD$
41 * $Whistle: ng_async.c,v 1.17 1999/11/01 09:24:51 julian Exp $
42 */
43
44/*
45 * This node type implements a PPP style sync <-> async converter.
46 * See RFC 1661 for details of how asynchronous encoding works.
47 */
48
49#include <sys/param.h>
50#include <sys/systm.h>
51#include <sys/kernel.h>
52#include <sys/mbuf.h>
53#include <sys/malloc.h>
54#include <sys/errno.h>
55
56#include <netgraph/ng_message.h>
57#include <netgraph/netgraph.h>
58#include <netgraph/ng_async.h>
59#include <netgraph/ng_parse.h>
60
61#include <net/ppp_defs.h>
62
63#ifdef NG_SEPARATE_MALLOC
64static MALLOC_DEFINE(M_NETGRAPH_ASYNC, "netgraph_async", "netgraph async node");
65#else
66#define M_NETGRAPH_ASYNC M_NETGRAPH
67#endif
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	.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};
168NETGRAPH_INIT(async, &typestruct);
169
170/* CRC table */
171static const u_int16_t fcstab[];
172
173/******************************************************************
174		    NETGRAPH NODE METHODS
175******************************************************************/
176
177/*
178 * Initialize a new node
179 */
180static int
181nga_constructor(node_p node)
182{
183	sc_p sc;
184
185	sc = malloc(sizeof(*sc), M_NETGRAPH_ASYNC, M_WAITOK | M_ZERO);
186	sc->amode = MODE_HUNT;
187	sc->cfg.accm = ~0;
188	sc->cfg.amru = NG_ASYNC_DEFAULT_MRU;
189	sc->cfg.smru = NG_ASYNC_DEFAULT_MRU;
190	sc->abuf = malloc(ASYNC_BUF_SIZE(sc->cfg.smru),
191	    M_NETGRAPH_ASYNC, M_WAITOK);
192	sc->sbuf = malloc(SYNC_BUF_SIZE(sc->cfg.amru),
193	    M_NETGRAPH_ASYNC, M_WAITOK);
194	NG_NODE_SET_PRIVATE(node, sc);
195	sc->node = node;
196	return (0);
197}
198
199/*
200 * Reserve a hook for a pending connection
201 */
202static int
203nga_newhook(node_p node, hook_p hook, const char *name)
204{
205	const sc_p sc = NG_NODE_PRIVATE(node);
206	hook_p *hookp;
207
208	if (!strcmp(name, NG_ASYNC_HOOK_ASYNC)) {
209		/*
210		 * We use a static buffer here so only one packet
211		 * at a time can be allowed to travel in this direction.
212		 * Force Writer semantics.
213		 */
214		NG_HOOK_FORCE_WRITER(hook);
215		hookp = &sc->async;
216	} else if (!strcmp(name, NG_ASYNC_HOOK_SYNC)) {
217		/*
218		 * We use a static state here so only one packet
219		 * at a time can be allowed to travel in this direction.
220		 * Force Writer semantics.
221		 * Since we set this for both directions
222		 * we might as well set it for the whole node
223		 * bit I haven;t done that (yet).
224		 */
225		NG_HOOK_FORCE_WRITER(hook);
226		hookp = &sc->sync;
227	} else {
228		return (EINVAL);
229	}
230	if (*hookp) /* actually can't happen I think [JRE] */
231		return (EISCONN);
232	*hookp = hook;
233	return (0);
234}
235
236/*
237 * Receive incoming data
238 */
239static int
240nga_rcvdata(hook_p hook, item_p item)
241{
242	const sc_p sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
243
244	if (hook == sc->sync)
245		return (nga_rcv_sync(sc, item));
246	if (hook == sc->async)
247		return (nga_rcv_async(sc, item));
248	panic("%s", __func__);
249}
250
251/*
252 * Receive incoming control message
253 */
254static int
255nga_rcvmsg(node_p node, item_p item, hook_p lasthook)
256{
257	const sc_p sc = NG_NODE_PRIVATE(node);
258	struct ng_mesg *resp = NULL;
259	int error = 0;
260	struct ng_mesg *msg;
261
262	NGI_GET_MSG(item, msg);
263	switch (msg->header.typecookie) {
264	case NGM_ASYNC_COOKIE:
265		switch (msg->header.cmd) {
266		case NGM_ASYNC_CMD_GET_STATS:
267			NG_MKRESPONSE(resp, msg, sizeof(sc->stats), M_NOWAIT);
268			if (resp == NULL)
269				ERROUT(ENOMEM);
270			*((struct ng_async_stat *) resp->data) = sc->stats;
271			break;
272		case NGM_ASYNC_CMD_CLR_STATS:
273			bzero(&sc->stats, sizeof(sc->stats));
274			break;
275		case NGM_ASYNC_CMD_SET_CONFIG:
276		    {
277			struct ng_async_cfg *const cfg =
278				(struct ng_async_cfg *) msg->data;
279			u_char *buf;
280
281			if (msg->header.arglen != sizeof(*cfg))
282				ERROUT(EINVAL);
283			if (cfg->amru < NG_ASYNC_MIN_MRU
284			    || cfg->amru > NG_ASYNC_MAX_MRU
285			    || cfg->smru < NG_ASYNC_MIN_MRU
286			    || cfg->smru > NG_ASYNC_MAX_MRU)
287				ERROUT(EINVAL);
288			cfg->enabled = !!cfg->enabled;	/* normalize */
289			if (cfg->smru > sc->cfg.smru) {	/* reallocate buffer */
290				buf = malloc(ASYNC_BUF_SIZE(cfg->smru),
291				    M_NETGRAPH_ASYNC, M_NOWAIT);
292				if (!buf)
293					ERROUT(ENOMEM);
294				free(sc->abuf, M_NETGRAPH_ASYNC);
295				sc->abuf = buf;
296			}
297			if (cfg->amru > sc->cfg.amru) {	/* reallocate buffer */
298				buf = malloc(SYNC_BUF_SIZE(cfg->amru),
299				    M_NETGRAPH_ASYNC, M_NOWAIT);
300				if (!buf)
301					ERROUT(ENOMEM);
302				free(sc->sbuf, M_NETGRAPH_ASYNC);
303				sc->sbuf = buf;
304				sc->amode = MODE_HUNT;
305				sc->slen = 0;
306			}
307			if (!cfg->enabled) {
308				sc->amode = MODE_HUNT;
309				sc->slen = 0;
310			}
311			sc->cfg = *cfg;
312			break;
313		    }
314		case NGM_ASYNC_CMD_GET_CONFIG:
315			NG_MKRESPONSE(resp, msg, sizeof(sc->cfg), M_NOWAIT);
316			if (!resp)
317				ERROUT(ENOMEM);
318			*((struct ng_async_cfg *) resp->data) = sc->cfg;
319			break;
320		default:
321			ERROUT(EINVAL);
322		}
323		break;
324	default:
325		ERROUT(EINVAL);
326	}
327done:
328	NG_RESPOND_MSG(error, node, item, resp);
329	NG_FREE_MSG(msg);
330	return (error);
331}
332
333/*
334 * Shutdown this node
335 */
336static int
337nga_shutdown(node_p node)
338{
339	const sc_p sc = NG_NODE_PRIVATE(node);
340
341	free(sc->abuf, M_NETGRAPH_ASYNC);
342	free(sc->sbuf, M_NETGRAPH_ASYNC);
343	bzero(sc, sizeof(*sc));
344	free(sc, M_NETGRAPH_ASYNC);
345	NG_NODE_SET_PRIVATE(node, NULL);
346	NG_NODE_UNREF(node);
347	return (0);
348}
349
350/*
351 * Lose a hook. When both hooks go away, we disappear.
352 */
353static int
354nga_disconnect(hook_p hook)
355{
356	const sc_p sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
357	hook_p *hookp;
358
359	if (hook == sc->async)
360		hookp = &sc->async;
361	else if (hook == sc->sync)
362		hookp = &sc->sync;
363	else
364		panic("%s", __func__);
365	if (!*hookp)
366		panic("%s 2", __func__);
367	*hookp = NULL;
368	bzero(&sc->stats, sizeof(sc->stats));
369	sc->lasttime = 0;
370	if ((NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0)
371	&& (NG_NODE_IS_VALID(NG_HOOK_NODE(hook))))
372		ng_rmnode_self(NG_HOOK_NODE(hook));
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, item_p item)
401{
402	struct ifnet *rcvif;
403	int alen, error = 0;
404	struct timeval time;
405	u_int16_t fcs, fcs0;
406	u_int32_t accm;
407	struct mbuf *m;
408
409#define ADD_BYTE(x)	nga_async_add(sc, &fcs, accm, &alen, (x))
410
411	/* Check for bypass mode */
412	if (!sc->cfg.enabled) {
413		NG_FWD_ITEM_HOOK(error, item, sc->async );
414		return (error);
415	}
416	NGI_GET_M(item, m);
417
418	rcvif = m->m_pkthdr.rcvif;
419
420	/* Get ACCM; special case LCP frames, which use full ACCM */
421	accm = sc->cfg.accm;
422	if (m->m_pkthdr.len >= 4) {
423		static const u_char lcphdr[4] = {
424		    PPP_ALLSTATIONS,
425		    PPP_UI,
426		    (u_char)(PPP_LCP >> 8),
427		    (u_char)(PPP_LCP & 0xff)
428		};
429		u_char buf[4];
430
431		m_copydata(m, 0, 4, (caddr_t)buf);
432		if (bcmp(buf, &lcphdr, 4) == 0)
433			accm = ~0;
434	}
435
436	/* Check for overflow */
437	if (m->m_pkthdr.len > sc->cfg.smru) {
438		sc->stats.syncOverflows++;
439		NG_FREE_M(m);
440		NG_FREE_ITEM(item);
441		return (EMSGSIZE);
442	}
443
444	/* Update stats */
445	sc->stats.syncFrames++;
446	sc->stats.syncOctets += m->m_pkthdr.len;
447
448	/* Initialize async encoded version of input mbuf */
449	alen = 0;
450	fcs = PPP_INITFCS;
451
452	/* Add beginning sync flag if it's been long enough to need one */
453	getmicrotime(&time);
454	if (time.tv_sec >= sc->lasttime + 1) {
455		sc->abuf[alen++] = PPP_FLAG;
456		sc->lasttime = time.tv_sec;
457	}
458
459	/* Add packet payload */
460	while (m != NULL) {
461		while (m->m_len > 0) {
462			ADD_BYTE(*mtod(m, u_char *));
463			m->m_data++;
464			m->m_len--;
465		}
466		m = m_free(m);
467	}
468
469	/* Add checksum and final sync flag */
470	fcs0 = fcs;
471	ADD_BYTE(~fcs0 & 0xff);
472	ADD_BYTE(~fcs0 >> 8);
473	sc->abuf[alen++] = PPP_FLAG;
474
475	/* Put frame in an mbuf and ship it off */
476	if (!(m = m_devget(sc->abuf, alen, 0, rcvif, NULL))) {
477		NG_FREE_ITEM(item);
478		error = ENOBUFS;
479	} else {
480		NG_FWD_NEW_DATA(error, item, sc->async, m);
481	}
482	return (error);
483}
484
485/*
486 * Receive incoming asynchronous data
487 * XXX Technically, we should strip out incoming characters
488 *     that are in our ACCM. Not sure if this is good or not.
489 */
490static int
491nga_rcv_async(const sc_p sc, item_p item)
492{
493	struct ifnet *rcvif;
494	int error;
495	struct mbuf *m;
496
497	if (!sc->cfg.enabled) {
498		NG_FWD_ITEM_HOOK(error, item,  sc->sync);
499		return (error);
500	}
501	NGI_GET_M(item, m);
502	rcvif = m->m_pkthdr.rcvif;
503	while (m) {
504		struct mbuf *n;
505
506		for (; m->m_len > 0; m->m_data++, m->m_len--) {
507			u_char  ch = *mtod(m, u_char *);
508
509			sc->stats.asyncOctets++;
510			if (ch == PPP_FLAG) {	/* Flag overrides everything */
511				int     skip = 0;
512
513				/* Check for runts */
514				if (sc->slen < 2) {
515					if (sc->slen > 0)
516						sc->stats.asyncRunts++;
517					goto reset;
518				}
519
520				/* Verify CRC */
521				if (sc->fcs != PPP_GOODFCS) {
522					sc->stats.asyncBadCheckSums++;
523					goto reset;
524				}
525				sc->slen -= 2;
526
527				/* Strip address and control fields */
528				if (sc->slen >= 2
529				    && sc->sbuf[0] == PPP_ALLSTATIONS
530				    && sc->sbuf[1] == PPP_UI)
531					skip = 2;
532
533				/* Check for frame too big */
534				if (sc->slen - skip > sc->cfg.amru) {
535					sc->stats.asyncOverflows++;
536					goto reset;
537				}
538
539				/* OK, ship it out */
540				if ((n = m_devget(sc->sbuf + skip,
541					   sc->slen - skip, 0, rcvif, NULL))) {
542					if (item) { /* sets NULL -> item */
543						NG_FWD_NEW_DATA(error, item,
544							sc->sync, n);
545					} else {
546						NG_SEND_DATA_ONLY(error,
547							sc->sync ,n);
548					}
549				}
550				sc->stats.asyncFrames++;
551reset:
552				sc->amode = MODE_NORMAL;
553				sc->fcs = PPP_INITFCS;
554				sc->slen = 0;
555				continue;
556			}
557			switch (sc->amode) {
558			case MODE_NORMAL:
559				if (ch == PPP_ESCAPE) {
560					sc->amode = MODE_ESC;
561					continue;
562				}
563				break;
564			case MODE_ESC:
565				ch ^= PPP_TRANS;
566				sc->amode = MODE_NORMAL;
567				break;
568			case MODE_HUNT:
569			default:
570				continue;
571			}
572
573			/* Add byte to frame */
574			if (sc->slen >= SYNC_BUF_SIZE(sc->cfg.amru)) {
575				sc->stats.asyncOverflows++;
576				sc->amode = MODE_HUNT;
577				sc->slen = 0;
578			} else {
579				sc->sbuf[sc->slen++] = ch;
580				sc->fcs = PPP_FCS(sc->fcs, ch);
581			}
582		}
583		m = m_free(m);
584	}
585	if (item)
586		NG_FREE_ITEM(item);
587	return (0);
588}
589
590/*
591 * CRC table
592 *
593 * Taken from RFC 1171 Appendix B
594 */
595static const u_int16_t fcstab[256] = {
596	 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
597	 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
598	 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
599	 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
600	 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
601	 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
602	 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
603	 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
604	 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
605	 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
606	 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
607	 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
608	 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
609	 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
610	 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
611	 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
612	 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
613	 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
614	 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
615	 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
616	 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
617	 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
618	 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
619	 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
620	 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
621	 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
622	 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
623	 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
624	 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
625	 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
626	 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
627	 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
628};
629