xref: /freebsd/sys/netgraph/ng_async.c (revision 74f5c6aa25752d28460c90aefa625ec0f75e3505)
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 /* 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 ng_constructor_t	nga_constructor;
101 static ng_rcvdata_t		nga_rcvdata;
102 static ng_rcvmsg_t		nga_rcvmsg;
103 static ng_shutdown_t		nga_shutdown;
104 static ng_newhook_t		nga_newhook;
105 static ng_disconnect_t		nga_disconnect;
106 
107 /* Helper stuff */
108 static int	nga_rcv_sync(const sc_p sc, struct mbuf *m, meta_p meta);
109 static int	nga_rcv_async(const sc_p sc, struct mbuf *m, meta_p meta);
110 
111 /* Define the netgraph node type */
112 static struct ng_type typestruct = {
113 	NG_VERSION,
114 	NG_ASYNC_NODE_TYPE,
115 	NULL,
116 	nga_constructor,
117 	nga_rcvmsg,
118 	nga_shutdown,
119 	nga_newhook,
120 	NULL,
121 	NULL,
122 	nga_rcvdata,
123 	nga_rcvdata,
124 	nga_disconnect
125 };
126 NETGRAPH_INIT(async, &typestruct);
127 
128 /* CRC table */
129 static const u_int16_t fcstab[];
130 
131 /******************************************************************
132 		    NETGRAPH NODE METHODS
133 ******************************************************************/
134 
135 /*
136  * Initialize a new node
137  */
138 static int
139 nga_constructor(node_p *nodep)
140 {
141 	sc_p sc;
142 	int error;
143 
144 	if ((error = ng_make_node_common(&typestruct, nodep)))
145 		return (error);
146 	MALLOC(sc, sc_p, sizeof(*sc), M_NETGRAPH, M_WAITOK);
147 	if (sc == NULL)
148 		return (ENOMEM);
149 	bzero(sc, sizeof(*sc));
150 	sc->amode = MODE_HUNT;
151 	sc->cfg.accm = ~0;
152 	sc->cfg.amru = NG_ASYNC_DEFAULT_MRU;
153 	sc->cfg.smru = NG_ASYNC_DEFAULT_MRU;
154 	MALLOC(sc->abuf, u_char *,
155 	    ASYNC_BUF_SIZE(sc->cfg.smru), M_NETGRAPH, M_WAITOK);
156 	if (sc->abuf == NULL)
157 		goto fail;
158 	MALLOC(sc->sbuf, u_char *,
159 	    SYNC_BUF_SIZE(sc->cfg.amru), M_NETGRAPH, M_WAITOK);
160 	if (sc->sbuf == NULL) {
161 		FREE(sc->abuf, M_NETGRAPH);
162 fail:
163 		FREE(sc, M_NETGRAPH);
164 		return (ENOMEM);
165 	}
166 	(*nodep)->private = sc;
167 	sc->node = *nodep;
168 	return (0);
169 }
170 
171 /*
172  * Reserve a hook for a pending connection
173  */
174 static int
175 nga_newhook(node_p node, hook_p hook, const char *name)
176 {
177 	const sc_p sc = node->private;
178 	hook_p *hookp;
179 
180 	if (!strcmp(name, NG_ASYNC_HOOK_ASYNC))
181 		hookp = &sc->async;
182 	else if (!strcmp(name, NG_ASYNC_HOOK_SYNC))
183 		hookp = &sc->sync;
184 	else if (!strcmp(name, NG_ASYNC_HOOK_SYNC2))
185 		hookp = &sc->sync2;
186 	else
187 		return (EINVAL);
188 	if (*hookp)
189 		return (EISCONN);
190 	*hookp = hook;
191 	return (0);
192 }
193 
194 /*
195  * Receive incoming data
196  */
197 static int
198 nga_rcvdata(hook_p hook, struct mbuf *m, meta_p meta)
199 {
200 	const sc_p sc = hook->node->private;
201 
202 	if (hook == sc->sync)
203 		return (nga_rcv_sync(sc, m, meta));
204 	else if (hook == sc->sync2) {
205 		const u_char acfcompSave = sc->cfg.acfcomp;
206 		const u_int32_t accmSave = sc->cfg.accm;
207 		int     rtn;
208 
209 		sc->cfg.acfcomp = 0;
210 		sc->cfg.accm = ~0;
211 		rtn = nga_rcv_sync(sc, m, meta);
212 		sc->cfg.acfcomp = acfcompSave;
213 		sc->cfg.accm = accmSave;
214 		return (rtn);
215 	} else if (hook == sc->async)
216 		return (nga_rcv_async(sc, m, meta));
217 	panic(__FUNCTION__);
218 }
219 
220 /*
221  * Receive incoming control message
222  */
223 static int
224 nga_rcvmsg(node_p node, struct ng_mesg *msg,
225 	const char *rtn, struct ng_mesg **rptr)
226 {
227 	const sc_p sc = (sc_p) node->private;
228 	struct ng_mesg *resp = NULL;
229 	int error = 0;
230 
231 	switch (msg->header.typecookie) {
232 	case NGM_ASYNC_COOKIE:
233 		switch (msg->header.cmd) {
234 		case NGM_ASYNC_CMD_GET_STATS:
235 			NG_MKRESPONSE(resp, msg, sizeof(sc->stats), M_NOWAIT);
236 			if (resp == NULL)
237 				ERROUT(ENOMEM);
238 			*((struct ng_async_stat *) resp->data) = sc->stats;
239 			break;
240 		case NGM_ASYNC_CMD_CLR_STATS:
241 			bzero(&sc->stats, sizeof(sc->stats));
242 			break;
243 		case NGM_ASYNC_CMD_SET_CONFIG:
244 		    {
245 			struct ng_async_cfg *const cfg =
246 				(struct ng_async_cfg *) msg->data;
247 			u_char *buf;
248 
249 			if (msg->header.arglen != sizeof(*cfg))
250 				ERROUT(EINVAL);
251 			if (cfg->amru < NG_ASYNC_MIN_MRU
252 			    || cfg->amru > NG_ASYNC_MAX_MRU
253 			    || cfg->smru < NG_ASYNC_MIN_MRU
254 			    || cfg->smru > NG_ASYNC_MAX_MRU)
255 				ERROUT(EINVAL);
256 			cfg->enabled = !!cfg->enabled;	/* normalize */
257 			cfg->acfcomp = !!cfg->acfcomp;	/* normalize */
258 			if (cfg->smru > sc->cfg.smru) {	/* reallocate buffer */
259 				MALLOC(buf, u_char *, ASYNC_BUF_SIZE(cfg->smru),
260 				    M_NETGRAPH, M_NOWAIT);
261 				if (!buf)
262 					ERROUT(ENOMEM);
263 				FREE(sc->abuf, M_NETGRAPH);
264 				sc->abuf = buf;
265 			}
266 			if (cfg->amru > sc->cfg.amru) {	/* reallocate buffer */
267 				MALLOC(buf, u_char *, SYNC_BUF_SIZE(cfg->amru),
268 				    M_NETGRAPH, M_NOWAIT);
269 				if (!buf)
270 					ERROUT(ENOMEM);
271 				FREE(sc->sbuf, M_NETGRAPH);
272 				sc->sbuf = buf;
273 				sc->amode = MODE_HUNT;
274 				sc->slen = 0;
275 			}
276 			if (!cfg->enabled) {
277 				sc->amode = MODE_HUNT;
278 				sc->slen = 0;
279 			}
280 			sc->cfg = *cfg;
281 			break;
282 		    }
283 		case NGM_ASYNC_CMD_GET_CONFIG:
284 			NG_MKRESPONSE(resp, msg, sizeof(sc->cfg), M_NOWAIT);
285 			if (!resp)
286 				ERROUT(ENOMEM);
287 			*((struct ng_async_cfg *) resp->data) = sc->cfg;
288 			break;
289 		default:
290 			ERROUT(EINVAL);
291 		}
292 		break;
293 	default:
294 		ERROUT(EINVAL);
295 	}
296 	if (rptr)
297 		*rptr = resp;
298 	else if (resp)
299 		FREE(resp, M_NETGRAPH);
300 
301 done:
302 	FREE(msg, M_NETGRAPH);
303 	return (error);
304 }
305 
306 /*
307  * Shutdown this node
308  */
309 static int
310 nga_shutdown(node_p node)
311 {
312 	const sc_p sc = node->private;
313 
314 	ng_cutlinks(node);
315 	ng_unname(node);
316 	FREE(sc->abuf, M_NETGRAPH);
317 	FREE(sc->sbuf, M_NETGRAPH);
318 	bzero(sc, sizeof(*sc));
319 	FREE(sc, M_NETGRAPH);
320 	node->private = NULL;
321 	ng_unref(node);
322 	return (0);
323 }
324 
325 /*
326  * Lose a hook. When both hooks go away, we disappear.
327  */
328 static int
329 nga_disconnect(hook_p hook)
330 {
331 	const sc_p sc = hook->node->private;
332 	hook_p *hookp;
333 
334 	if (hook == sc->async)
335 		hookp = &sc->async;
336 	else if (hook == sc->sync)
337 		hookp = &sc->sync;
338 	else if (hook == sc->sync2)
339 		hookp = &sc->sync2;
340 	else
341 		panic(__FUNCTION__);
342 	if (!*hookp)
343 		panic(__FUNCTION__ "2");
344 	*hookp = NULL;
345 	bzero(&sc->stats, sizeof(sc->stats));
346 #if SYNC_OPT_TIME
347 	sc->lasttime = 0;
348 #endif
349 	if (hook->node->numhooks == 0)
350 		ng_rmnode(hook->node);
351 	return (0);
352 }
353 
354 /******************************************************************
355 		    INTERNAL HELPER STUFF
356 ******************************************************************/
357 
358 /*
359  * Encode a byte into the async buffer
360  */
361 static __inline__ void
362 nga_async_add(const sc_p sc, u_int16_t *fcs, u_int32_t accm, int *len, u_char x)
363 {
364 	*fcs = PPP_FCS(*fcs, x);
365 	if ((x < 32 && ((1 << x) & accm))
366 	    || (x == PPP_ESCAPE)
367 	    || (x == PPP_FLAG)) {
368 		sc->abuf[(*len)++] = PPP_ESCAPE;
369 		x ^= PPP_TRANS;
370 	}
371 	sc->abuf[(*len)++] = x;
372 }
373 
374 /*
375  * Receive incoming synchronous data. Any "meta" information means
376  * for us to apply full ACCM to this frame.
377  */
378 static int
379 nga_rcv_sync(const sc_p sc, struct mbuf *m, meta_p meta)
380 {
381 	struct ifnet *const rcvif = m->m_pkthdr.rcvif;
382 	u_int16_t fcs, fcs0;
383 	int alen, error = 0;
384 
385 #define ADD_BYTE(x)	\
386   nga_async_add(sc, &fcs, meta ? ~0 : sc->cfg.accm, &alen, (x))
387 
388 	if (!sc->cfg.enabled) {
389 		NG_SEND_DATA(error, sc->async, m, meta);
390 		return (error);
391 	}
392 	if (m->m_pkthdr.len > sc->cfg.smru) {
393 		sc->stats.syncOverflows++;
394 		NG_FREE_DATA(m, meta);
395 		return (EMSGSIZE);
396 	}
397 	sc->stats.syncFrames++;
398 	sc->stats.syncOctets += m->m_pkthdr.len;
399 
400 	/* Initialize async encoded version of input mbuf */
401 	alen = 0;
402 	fcs = PPP_INITFCS;
403 
404 	/* Add beginning sync flag if it's been long enough to need one */
405 #if SYNC_OPT_TIME
406 	{
407 		struct timeval time;
408 
409 		getmicrotime(&time);
410 		if (time.tv_sec >= sc->lasttime + SYNC_OPT_TIME) {
411 			sc->abuf[alen++] = PPP_FLAG;
412 			sc->lasttime = time.tv_sec;
413 		}
414 	}
415 #else
416 	sc->abuf[alen++] = PPP_FLAG;
417 #endif
418 
419 	/* Add option address and control fields, then packet payload */
420 	if (!sc->cfg.acfcomp || meta) {
421 		ADD_BYTE(PPP_ALLSTATIONS);
422 		ADD_BYTE(PPP_UI);
423 	}
424 	while (m) {
425 		struct mbuf *n;
426 
427 		while (m->m_len > 0) {
428 			u_char const ch = *mtod(m, u_char *);
429 
430 			ADD_BYTE(ch);
431 			m->m_data++;
432 			m->m_len--;
433 		}
434 		MFREE(m, n);
435 		m = n;
436 	}
437 
438 	/* Add checksum and final sync flag */
439 	fcs0 = fcs;
440 	ADD_BYTE(~fcs0 & 0xff);
441 	ADD_BYTE(~fcs0 >> 8);
442 	sc->abuf[alen++] = PPP_FLAG;
443 
444 	/* Put frame in an mbuf and ship it off */
445 	NG_FREE_META(meta);
446 	if (!(m = m_devget(sc->abuf, alen, 0, rcvif, NULL)))
447 		error = ENOBUFS;
448 	else
449 		NG_SEND_DATA(error, sc->async, m, meta);
450 	return (error);
451 }
452 
453 /*
454  * Receive incoming asynchronous data
455  * XXX technically, we should strip out supposedly escaped characters
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