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