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