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