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