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