ng_async.c revision 69922
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 69922 2000-12-12 18:52:14Z 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_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 *nodep)
178{
179	sc_p sc;
180	int error;
181
182	if ((error = ng_make_node_common(&typestruct, nodep)))
183		return (error);
184	MALLOC(sc, sc_p, sizeof(*sc), M_NETGRAPH, M_NOWAIT | M_ZERO);
185	if (sc == NULL)
186		return (ENOMEM);
187	sc->amode = MODE_HUNT;
188	sc->cfg.accm = ~0;
189	sc->cfg.amru = NG_ASYNC_DEFAULT_MRU;
190	sc->cfg.smru = NG_ASYNC_DEFAULT_MRU;
191	MALLOC(sc->abuf, u_char *,
192	    ASYNC_BUF_SIZE(sc->cfg.smru), M_NETGRAPH, M_NOWAIT);
193	if (sc->abuf == NULL)
194		goto fail;
195	MALLOC(sc->sbuf, u_char *,
196	    SYNC_BUF_SIZE(sc->cfg.amru), M_NETGRAPH, M_NOWAIT);
197	if (sc->sbuf == NULL) {
198		FREE(sc->abuf, M_NETGRAPH);
199fail:
200		FREE(sc, M_NETGRAPH);
201		return (ENOMEM);
202	}
203	(*nodep)->private = sc;
204	sc->node = *nodep;
205	return (0);
206}
207
208/*
209 * Reserve a hook for a pending connection
210 */
211static int
212nga_newhook(node_p node, hook_p hook, const char *name)
213{
214	const sc_p sc = node->private;
215	hook_p *hookp;
216
217	if (!strcmp(name, NG_ASYNC_HOOK_ASYNC))
218		hookp = &sc->async;
219	else if (!strcmp(name, NG_ASYNC_HOOK_SYNC))
220		hookp = &sc->sync;
221	else
222		return (EINVAL);
223	if (*hookp)
224		return (EISCONN);
225	*hookp = hook;
226	return (0);
227}
228
229/*
230 * Receive incoming data
231 */
232static int
233nga_rcvdata(hook_p hook, struct mbuf *m, meta_p meta,
234		struct mbuf **ret_m, meta_p *ret_meta, struct ng_mesg **resp)
235{
236	const sc_p sc = hook->node->private;
237
238	if (hook == sc->sync)
239		return (nga_rcv_sync(sc, m, meta));
240	if (hook == sc->async)
241		return (nga_rcv_async(sc, m, meta));
242	panic(__FUNCTION__);
243}
244
245/*
246 * Receive incoming control message
247 */
248static int
249nga_rcvmsg(node_p node, struct ng_mesg *msg,
250	const char *rtn, struct ng_mesg **rptr, hook_p lasthook)
251{
252	const sc_p sc = (sc_p) node->private;
253	struct ng_mesg *resp = NULL;
254	int error = 0;
255
256	switch (msg->header.typecookie) {
257	case NGM_ASYNC_COOKIE:
258		switch (msg->header.cmd) {
259		case NGM_ASYNC_CMD_GET_STATS:
260			NG_MKRESPONSE(resp, msg, sizeof(sc->stats), M_NOWAIT);
261			if (resp == NULL)
262				ERROUT(ENOMEM);
263			*((struct ng_async_stat *) resp->data) = sc->stats;
264			break;
265		case NGM_ASYNC_CMD_CLR_STATS:
266			bzero(&sc->stats, sizeof(sc->stats));
267			break;
268		case NGM_ASYNC_CMD_SET_CONFIG:
269		    {
270			struct ng_async_cfg *const cfg =
271				(struct ng_async_cfg *) msg->data;
272			u_char *buf;
273
274			if (msg->header.arglen != sizeof(*cfg))
275				ERROUT(EINVAL);
276			if (cfg->amru < NG_ASYNC_MIN_MRU
277			    || cfg->amru > NG_ASYNC_MAX_MRU
278			    || cfg->smru < NG_ASYNC_MIN_MRU
279			    || cfg->smru > NG_ASYNC_MAX_MRU)
280				ERROUT(EINVAL);
281			cfg->enabled = !!cfg->enabled;	/* normalize */
282			if (cfg->smru > sc->cfg.smru) {	/* reallocate buffer */
283				MALLOC(buf, u_char *, ASYNC_BUF_SIZE(cfg->smru),
284				    M_NETGRAPH, M_NOWAIT);
285				if (!buf)
286					ERROUT(ENOMEM);
287				FREE(sc->abuf, M_NETGRAPH);
288				sc->abuf = buf;
289			}
290			if (cfg->amru > sc->cfg.amru) {	/* reallocate buffer */
291				MALLOC(buf, u_char *, SYNC_BUF_SIZE(cfg->amru),
292				    M_NETGRAPH, M_NOWAIT);
293				if (!buf)
294					ERROUT(ENOMEM);
295				FREE(sc->sbuf, M_NETGRAPH);
296				sc->sbuf = buf;
297				sc->amode = MODE_HUNT;
298				sc->slen = 0;
299			}
300			if (!cfg->enabled) {
301				sc->amode = MODE_HUNT;
302				sc->slen = 0;
303			}
304			sc->cfg = *cfg;
305			break;
306		    }
307		case NGM_ASYNC_CMD_GET_CONFIG:
308			NG_MKRESPONSE(resp, msg, sizeof(sc->cfg), M_NOWAIT);
309			if (!resp)
310				ERROUT(ENOMEM);
311			*((struct ng_async_cfg *) resp->data) = sc->cfg;
312			break;
313		default:
314			ERROUT(EINVAL);
315		}
316		break;
317	default:
318		ERROUT(EINVAL);
319	}
320	if (rptr)
321		*rptr = resp;
322	else if (resp)
323		FREE(resp, M_NETGRAPH);
324
325done:
326	FREE(msg, M_NETGRAPH);
327	return (error);
328}
329
330/*
331 * Shutdown this node
332 */
333static int
334nga_shutdown(node_p node)
335{
336	const sc_p sc = node->private;
337
338	ng_cutlinks(node);
339	ng_unname(node);
340	FREE(sc->abuf, M_NETGRAPH);
341	FREE(sc->sbuf, M_NETGRAPH);
342	bzero(sc, sizeof(*sc));
343	FREE(sc, M_NETGRAPH);
344	node->private = NULL;
345	ng_unref(node);
346	return (0);
347}
348
349/*
350 * Lose a hook. When both hooks go away, we disappear.
351 */
352static int
353nga_disconnect(hook_p hook)
354{
355	const sc_p sc = hook->node->private;
356	hook_p *hookp;
357
358	if (hook == sc->async)
359		hookp = &sc->async;
360	else if (hook == sc->sync)
361		hookp = &sc->sync;
362	else
363		panic(__FUNCTION__);
364	if (!*hookp)
365		panic(__FUNCTION__ "2");
366	*hookp = NULL;
367	bzero(&sc->stats, sizeof(sc->stats));
368	sc->lasttime = 0;
369	if (hook->node->numhooks == 0)
370		ng_rmnode(hook->node);
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, struct mbuf *m, meta_p meta)
399{
400	struct ifnet *const rcvif = m->m_pkthdr.rcvif;
401	int alen, error = 0;
402	struct timeval time;
403	u_int16_t fcs, fcs0;
404	u_int32_t accm;
405
406#define ADD_BYTE(x)	nga_async_add(sc, &fcs, accm, &alen, (x))
407
408	/* Check for bypass mode */
409	if (!sc->cfg.enabled) {
410		NG_SEND_DATA(error, sc->async, m, meta);
411		return (error);
412	}
413
414	/* Get ACCM; special case LCP frames, which use full ACCM */
415	accm = sc->cfg.accm;
416	if (m->m_pkthdr.len >= 4) {
417		static const u_char lcphdr[4] = {
418		    PPP_ALLSTATIONS,
419		    PPP_UI,
420		    (u_char)(PPP_LCP >> 8),
421		    (u_char)(PPP_LCP & 0xff)
422		};
423		u_char buf[4];
424
425		m_copydata(m, 0, 4, (caddr_t)buf);
426		if (bcmp(buf, &lcphdr, 4) == 0)
427			accm = ~0;
428	}
429
430	/* Check for overflow */
431	if (m->m_pkthdr.len > sc->cfg.smru) {
432		sc->stats.syncOverflows++;
433		NG_FREE_DATA(m, meta);
434		return (EMSGSIZE);
435	}
436
437	/* Update stats */
438	sc->stats.syncFrames++;
439	sc->stats.syncOctets += m->m_pkthdr.len;
440
441	/* Initialize async encoded version of input mbuf */
442	alen = 0;
443	fcs = PPP_INITFCS;
444
445	/* Add beginning sync flag if it's been long enough to need one */
446	getmicrotime(&time);
447	if (time.tv_sec >= sc->lasttime + 1) {
448		sc->abuf[alen++] = PPP_FLAG;
449		sc->lasttime = time.tv_sec;
450	}
451
452	/* Add packet payload */
453	while (m != NULL) {
454		struct mbuf *n;
455
456		while (m->m_len > 0) {
457			ADD_BYTE(*mtod(m, u_char *));
458			m->m_data++;
459			m->m_len--;
460		}
461		MFREE(m, n);
462		m = n;
463	}
464
465	/* Add checksum and final sync flag */
466	fcs0 = fcs;
467	ADD_BYTE(~fcs0 & 0xff);
468	ADD_BYTE(~fcs0 >> 8);
469	sc->abuf[alen++] = PPP_FLAG;
470
471	/* Put frame in an mbuf and ship it off */
472	if (!(m = m_devget(sc->abuf, alen, 0, rcvif, NULL))) {
473		NG_FREE_META(meta);
474		error = ENOBUFS;
475	} else
476		NG_SEND_DATA(error, sc->async, m, meta);
477	return (error);
478}
479
480/*
481 * Receive incoming asynchronous data
482 * XXX Technically, we should strip out incoming characters
483 *     that are in our ACCM. Not sure if this is good or not.
484 */
485static int
486nga_rcv_async(const sc_p sc, struct mbuf * m, meta_p meta)
487{
488	struct ifnet *const rcvif = m->m_pkthdr.rcvif;
489	int error;
490
491	if (!sc->cfg.enabled) {
492		NG_SEND_DATA(error, sc->sync, m, meta);
493		return (error);
494	}
495	NG_FREE_META(meta);
496	while (m) {
497		struct mbuf *n;
498
499		for (; m->m_len > 0; m->m_data++, m->m_len--) {
500			u_char  ch = *mtod(m, u_char *);
501
502			sc->stats.asyncOctets++;
503			if (ch == PPP_FLAG) {	/* Flag overrides everything */
504				int     skip = 0;
505
506				/* Check for runts */
507				if (sc->slen < 2) {
508					if (sc->slen > 0)
509						sc->stats.asyncRunts++;
510					goto reset;
511				}
512
513				/* Verify CRC */
514				if (sc->fcs != PPP_GOODFCS) {
515					sc->stats.asyncBadCheckSums++;
516					goto reset;
517				}
518				sc->slen -= 2;
519
520				/* Strip address and control fields */
521				if (sc->slen >= 2
522				    && sc->sbuf[0] == PPP_ALLSTATIONS
523				    && sc->sbuf[1] == PPP_UI)
524					skip = 2;
525
526				/* Check for frame too big */
527				if (sc->slen - skip > sc->cfg.amru) {
528					sc->stats.asyncOverflows++;
529					goto reset;
530				}
531
532				/* OK, ship it out */
533				if ((n = m_devget(sc->sbuf + skip,
534					   sc->slen - skip, 0, rcvif, NULL)))
535					NG_SEND_DATA(error, sc->sync, n, meta);
536				sc->stats.asyncFrames++;
537reset:
538				sc->amode = MODE_NORMAL;
539				sc->fcs = PPP_INITFCS;
540				sc->slen = 0;
541				continue;
542			}
543			switch (sc->amode) {
544			case MODE_NORMAL:
545				if (ch == PPP_ESCAPE) {
546					sc->amode = MODE_ESC;
547					continue;
548				}
549				break;
550			case MODE_ESC:
551				ch ^= PPP_TRANS;
552				sc->amode = MODE_NORMAL;
553				break;
554			case MODE_HUNT:
555			default:
556				continue;
557			}
558
559			/* Add byte to frame */
560			if (sc->slen >= SYNC_BUF_SIZE(sc->cfg.amru)) {
561				sc->stats.asyncOverflows++;
562				sc->amode = MODE_HUNT;
563				sc->slen = 0;
564			} else {
565				sc->sbuf[sc->slen++] = ch;
566				sc->fcs = PPP_FCS(sc->fcs, ch);
567			}
568		}
569		MFREE(m, n);
570		m = n;
571	}
572	return (0);
573}
574
575/*
576 * CRC table
577 *
578 * Taken from RFC 1171 Appendix B
579 */
580static const u_int16_t fcstab[256] = {
581	 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
582	 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
583	 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
584	 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
585	 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
586	 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
587	 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
588	 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
589	 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
590	 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
591	 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
592	 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
593	 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
594	 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
595	 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
596	 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
597	 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
598	 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
599	 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
600	 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
601	 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
602	 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
603	 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
604	 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
605	 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
606	 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
607	 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
608	 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
609	 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
610	 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
611	 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
612	 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
613};
614