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