1700218c7SGleb Smirnoff /*-
2*4d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
3fe267a55SPedro F. Giffuni *
4700218c7SGleb Smirnoff * Copyright (c) 2006 Alexander Motin <mav@alkar.net>
5700218c7SGleb Smirnoff * All rights reserved.
6700218c7SGleb Smirnoff *
7700218c7SGleb Smirnoff * Redistribution and use in source and binary forms, with or without
8700218c7SGleb Smirnoff * modification, are permitted provided that the following conditions
9700218c7SGleb Smirnoff * are met:
10700218c7SGleb Smirnoff * 1. Redistributions of source code must retain the above copyright
11700218c7SGleb Smirnoff * notice unmodified, this list of conditions, and the following
12700218c7SGleb Smirnoff * disclaimer.
13700218c7SGleb Smirnoff * 2. Redistributions in binary form must reproduce the above copyright
14700218c7SGleb Smirnoff * notice, this list of conditions and the following disclaimer in the
15700218c7SGleb Smirnoff * documentation and/or other materials provided with the distribution.
16700218c7SGleb Smirnoff *
17700218c7SGleb Smirnoff * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18700218c7SGleb Smirnoff * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19700218c7SGleb Smirnoff * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20700218c7SGleb Smirnoff * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21700218c7SGleb Smirnoff * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22700218c7SGleb Smirnoff * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23700218c7SGleb Smirnoff * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24700218c7SGleb Smirnoff * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25700218c7SGleb Smirnoff * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26700218c7SGleb Smirnoff * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27700218c7SGleb Smirnoff * SUCH DAMAGE.
28700218c7SGleb Smirnoff */
29700218c7SGleb Smirnoff
30700218c7SGleb Smirnoff /*
31700218c7SGleb Smirnoff * Predictor-1 PPP compression netgraph node type.
32700218c7SGleb Smirnoff */
33700218c7SGleb Smirnoff
34700218c7SGleb Smirnoff #include <sys/param.h>
35700218c7SGleb Smirnoff #include <sys/systm.h>
36700218c7SGleb Smirnoff #include <sys/kernel.h>
37700218c7SGleb Smirnoff #include <sys/mbuf.h>
38700218c7SGleb Smirnoff #include <sys/malloc.h>
39700218c7SGleb Smirnoff #include <sys/errno.h>
40700218c7SGleb Smirnoff #include <sys/syslog.h>
41700218c7SGleb Smirnoff
42700218c7SGleb Smirnoff #include <netgraph/ng_message.h>
43700218c7SGleb Smirnoff #include <netgraph/netgraph.h>
44700218c7SGleb Smirnoff #include <netgraph/ng_parse.h>
45700218c7SGleb Smirnoff #include <netgraph/ng_pred1.h>
46700218c7SGleb Smirnoff
47700218c7SGleb Smirnoff #include "opt_netgraph.h"
48700218c7SGleb Smirnoff
49d745c852SEd Schouten static MALLOC_DEFINE(M_NETGRAPH_PRED1, "netgraph_pred1", "netgraph pred1 node");
50700218c7SGleb Smirnoff
51700218c7SGleb Smirnoff /* PRED1 header length */
52700218c7SGleb Smirnoff #define PRED1_HDRLEN 2
53700218c7SGleb Smirnoff
54700218c7SGleb Smirnoff #define PRED1_TABLE_SIZE 0x10000
55700218c7SGleb Smirnoff #define PRED1_BUF_SIZE 4096
56700218c7SGleb Smirnoff #define PPP_INITFCS 0xffff /* Initial FCS value */
57700218c7SGleb Smirnoff #define PPP_GOODFCS 0xf0b8 /* Good final FCS value */
58700218c7SGleb Smirnoff
59700218c7SGleb Smirnoff /*
60700218c7SGleb Smirnoff * The following hash code is the heart of the algorithm:
61700218c7SGleb Smirnoff * it builds a sliding hash sum of the previous 3-and-a-bit
62700218c7SGleb Smirnoff * characters which will be used to index the guess table.
63700218c7SGleb Smirnoff * A better hash function would result in additional compression,
64700218c7SGleb Smirnoff * at the expense of time.
65700218c7SGleb Smirnoff */
66700218c7SGleb Smirnoff
67700218c7SGleb Smirnoff #define HASH(x) priv->Hash = (priv->Hash << 4) ^ (x)
68700218c7SGleb Smirnoff
69700218c7SGleb Smirnoff /* Node private data */
70700218c7SGleb Smirnoff struct ng_pred1_private {
71700218c7SGleb Smirnoff struct ng_pred1_config cfg; /* configuration */
72700218c7SGleb Smirnoff u_char GuessTable[PRED1_TABLE_SIZE]; /* dictionary */
73700218c7SGleb Smirnoff u_char inbuf[PRED1_BUF_SIZE]; /* input buffer */
74700218c7SGleb Smirnoff u_char outbuf[PRED1_BUF_SIZE]; /* output buffer */
75700218c7SGleb Smirnoff struct ng_pred1_stats stats; /* statistics */
76700218c7SGleb Smirnoff uint16_t Hash;
77700218c7SGleb Smirnoff ng_ID_t ctrlnode; /* path to controlling node */
78700218c7SGleb Smirnoff uint16_t seqnum; /* sequence number */
79700218c7SGleb Smirnoff u_char compress; /* compress/decompress flag */
80700218c7SGleb Smirnoff };
81700218c7SGleb Smirnoff typedef struct ng_pred1_private *priv_p;
82700218c7SGleb Smirnoff
83700218c7SGleb Smirnoff /* Netgraph node methods */
84700218c7SGleb Smirnoff static ng_constructor_t ng_pred1_constructor;
85700218c7SGleb Smirnoff static ng_rcvmsg_t ng_pred1_rcvmsg;
86700218c7SGleb Smirnoff static ng_shutdown_t ng_pred1_shutdown;
87700218c7SGleb Smirnoff static ng_newhook_t ng_pred1_newhook;
88700218c7SGleb Smirnoff static ng_rcvdata_t ng_pred1_rcvdata;
89700218c7SGleb Smirnoff static ng_disconnect_t ng_pred1_disconnect;
90700218c7SGleb Smirnoff
91700218c7SGleb Smirnoff /* Helper functions */
92700218c7SGleb Smirnoff static int ng_pred1_compress(node_p node, struct mbuf *m,
93700218c7SGleb Smirnoff struct mbuf **resultp);
94700218c7SGleb Smirnoff static int ng_pred1_decompress(node_p node, struct mbuf *m,
95700218c7SGleb Smirnoff struct mbuf **resultp);
96700218c7SGleb Smirnoff static void Pred1Init(node_p node);
97700218c7SGleb Smirnoff static int Pred1Compress(node_p node, u_char *source, u_char *dest,
98700218c7SGleb Smirnoff int len);
99700218c7SGleb Smirnoff static int Pred1Decompress(node_p node, u_char *source, u_char *dest,
100700218c7SGleb Smirnoff int slen, int dlen);
101700218c7SGleb Smirnoff static void Pred1SyncTable(node_p node, u_char *source, int len);
102700218c7SGleb Smirnoff static uint16_t Crc16(uint16_t fcs, u_char *cp, int len);
103700218c7SGleb Smirnoff
104700218c7SGleb Smirnoff static const uint16_t Crc16Table[];
105700218c7SGleb Smirnoff
106700218c7SGleb Smirnoff /* Parse type for struct ng_pred1_config. */
107700218c7SGleb Smirnoff static const struct ng_parse_struct_field ng_pred1_config_type_fields[]
108700218c7SGleb Smirnoff = NG_PRED1_CONFIG_INFO;
109700218c7SGleb Smirnoff static const struct ng_parse_type ng_pred1_config_type = {
110700218c7SGleb Smirnoff &ng_parse_struct_type,
111700218c7SGleb Smirnoff ng_pred1_config_type_fields
112700218c7SGleb Smirnoff };
113700218c7SGleb Smirnoff
114700218c7SGleb Smirnoff /* Parse type for struct ng_pred1_stat. */
115700218c7SGleb Smirnoff static const struct ng_parse_struct_field ng_pred1_stats_type_fields[]
116700218c7SGleb Smirnoff = NG_PRED1_STATS_INFO;
117700218c7SGleb Smirnoff static const struct ng_parse_type ng_pred1_stat_type = {
118700218c7SGleb Smirnoff &ng_parse_struct_type,
119700218c7SGleb Smirnoff ng_pred1_stats_type_fields
120700218c7SGleb Smirnoff };
121700218c7SGleb Smirnoff
122700218c7SGleb Smirnoff /* List of commands and how to convert arguments to/from ASCII. */
123700218c7SGleb Smirnoff static const struct ng_cmdlist ng_pred1_cmds[] = {
124700218c7SGleb Smirnoff {
125700218c7SGleb Smirnoff NGM_PRED1_COOKIE,
126700218c7SGleb Smirnoff NGM_PRED1_CONFIG,
127700218c7SGleb Smirnoff "config",
128700218c7SGleb Smirnoff &ng_pred1_config_type,
129700218c7SGleb Smirnoff NULL
130700218c7SGleb Smirnoff },
131700218c7SGleb Smirnoff {
132700218c7SGleb Smirnoff NGM_PRED1_COOKIE,
133700218c7SGleb Smirnoff NGM_PRED1_RESETREQ,
134700218c7SGleb Smirnoff "resetreq",
135700218c7SGleb Smirnoff NULL,
136700218c7SGleb Smirnoff NULL
137700218c7SGleb Smirnoff },
138700218c7SGleb Smirnoff {
139700218c7SGleb Smirnoff NGM_PRED1_COOKIE,
140700218c7SGleb Smirnoff NGM_PRED1_GET_STATS,
141700218c7SGleb Smirnoff "getstats",
142700218c7SGleb Smirnoff NULL,
143700218c7SGleb Smirnoff &ng_pred1_stat_type
144700218c7SGleb Smirnoff },
145700218c7SGleb Smirnoff {
146700218c7SGleb Smirnoff NGM_PRED1_COOKIE,
147700218c7SGleb Smirnoff NGM_PRED1_CLR_STATS,
148700218c7SGleb Smirnoff "clrstats",
149700218c7SGleb Smirnoff NULL,
150700218c7SGleb Smirnoff NULL
151700218c7SGleb Smirnoff },
152700218c7SGleb Smirnoff {
153700218c7SGleb Smirnoff NGM_PRED1_COOKIE,
154700218c7SGleb Smirnoff NGM_PRED1_GETCLR_STATS,
155700218c7SGleb Smirnoff "getclrstats",
156700218c7SGleb Smirnoff NULL,
157700218c7SGleb Smirnoff &ng_pred1_stat_type
158700218c7SGleb Smirnoff },
159700218c7SGleb Smirnoff { 0 }
160700218c7SGleb Smirnoff };
161700218c7SGleb Smirnoff
162700218c7SGleb Smirnoff /* Node type descriptor */
163700218c7SGleb Smirnoff static struct ng_type ng_pred1_typestruct = {
164700218c7SGleb Smirnoff .version = NG_ABI_VERSION,
165700218c7SGleb Smirnoff .name = NG_PRED1_NODE_TYPE,
166700218c7SGleb Smirnoff .constructor = ng_pred1_constructor,
167700218c7SGleb Smirnoff .rcvmsg = ng_pred1_rcvmsg,
168700218c7SGleb Smirnoff .shutdown = ng_pred1_shutdown,
169700218c7SGleb Smirnoff .newhook = ng_pred1_newhook,
170700218c7SGleb Smirnoff .rcvdata = ng_pred1_rcvdata,
171700218c7SGleb Smirnoff .disconnect = ng_pred1_disconnect,
172700218c7SGleb Smirnoff .cmdlist = ng_pred1_cmds,
173700218c7SGleb Smirnoff };
174700218c7SGleb Smirnoff NETGRAPH_INIT(pred1, &ng_pred1_typestruct);
175700218c7SGleb Smirnoff
176700218c7SGleb Smirnoff #define ERROUT(x) do { error = (x); goto done; } while (0)
177700218c7SGleb Smirnoff
178700218c7SGleb Smirnoff /************************************************************************
179700218c7SGleb Smirnoff NETGRAPH NODE STUFF
180700218c7SGleb Smirnoff ************************************************************************/
181700218c7SGleb Smirnoff
182700218c7SGleb Smirnoff /*
183700218c7SGleb Smirnoff * Node type constructor
184700218c7SGleb Smirnoff */
185700218c7SGleb Smirnoff static int
ng_pred1_constructor(node_p node)186700218c7SGleb Smirnoff ng_pred1_constructor(node_p node)
187700218c7SGleb Smirnoff {
188700218c7SGleb Smirnoff priv_p priv;
189700218c7SGleb Smirnoff
190700218c7SGleb Smirnoff /* Allocate private structure. */
191700218c7SGleb Smirnoff priv = malloc(sizeof(*priv), M_NETGRAPH_PRED1, M_WAITOK | M_ZERO);
192700218c7SGleb Smirnoff
193700218c7SGleb Smirnoff NG_NODE_SET_PRIVATE(node, priv);
194700218c7SGleb Smirnoff
195700218c7SGleb Smirnoff /* This node is not thread safe. */
196700218c7SGleb Smirnoff NG_NODE_FORCE_WRITER(node);
197700218c7SGleb Smirnoff
198700218c7SGleb Smirnoff /* Done */
199700218c7SGleb Smirnoff return (0);
200700218c7SGleb Smirnoff }
201700218c7SGleb Smirnoff
202700218c7SGleb Smirnoff /*
203700218c7SGleb Smirnoff * Give our OK for a hook to be added.
204700218c7SGleb Smirnoff */
205700218c7SGleb Smirnoff static int
ng_pred1_newhook(node_p node,hook_p hook,const char * name)206700218c7SGleb Smirnoff ng_pred1_newhook(node_p node, hook_p hook, const char *name)
207700218c7SGleb Smirnoff {
208700218c7SGleb Smirnoff const priv_p priv = NG_NODE_PRIVATE(node);
209700218c7SGleb Smirnoff
210700218c7SGleb Smirnoff if (NG_NODE_NUMHOOKS(node) > 0)
211700218c7SGleb Smirnoff return (EINVAL);
212700218c7SGleb Smirnoff
213700218c7SGleb Smirnoff if (strcmp(name, NG_PRED1_HOOK_COMP) == 0)
214700218c7SGleb Smirnoff priv->compress = 1;
215700218c7SGleb Smirnoff else if (strcmp(name, NG_PRED1_HOOK_DECOMP) == 0)
216700218c7SGleb Smirnoff priv->compress = 0;
217700218c7SGleb Smirnoff else
218700218c7SGleb Smirnoff return (EINVAL);
219700218c7SGleb Smirnoff
220700218c7SGleb Smirnoff return (0);
221700218c7SGleb Smirnoff }
222700218c7SGleb Smirnoff
223700218c7SGleb Smirnoff /*
224700218c7SGleb Smirnoff * Receive a control message.
225700218c7SGleb Smirnoff */
226700218c7SGleb Smirnoff static int
ng_pred1_rcvmsg(node_p node,item_p item,hook_p lasthook)227700218c7SGleb Smirnoff ng_pred1_rcvmsg(node_p node, item_p item, hook_p lasthook)
228700218c7SGleb Smirnoff {
229700218c7SGleb Smirnoff const priv_p priv = NG_NODE_PRIVATE(node);
230700218c7SGleb Smirnoff struct ng_mesg *resp = NULL;
231700218c7SGleb Smirnoff int error = 0;
232700218c7SGleb Smirnoff struct ng_mesg *msg;
233700218c7SGleb Smirnoff
234700218c7SGleb Smirnoff NGI_GET_MSG(item, msg);
235700218c7SGleb Smirnoff
236700218c7SGleb Smirnoff if (msg->header.typecookie != NGM_PRED1_COOKIE)
237700218c7SGleb Smirnoff ERROUT(EINVAL);
238700218c7SGleb Smirnoff
239700218c7SGleb Smirnoff switch (msg->header.cmd) {
240700218c7SGleb Smirnoff case NGM_PRED1_CONFIG:
241700218c7SGleb Smirnoff {
242700218c7SGleb Smirnoff struct ng_pred1_config *const cfg =
243700218c7SGleb Smirnoff (struct ng_pred1_config *)msg->data;
244700218c7SGleb Smirnoff
245700218c7SGleb Smirnoff /* Check configuration. */
246700218c7SGleb Smirnoff if (msg->header.arglen != sizeof(*cfg))
247700218c7SGleb Smirnoff ERROUT(EINVAL);
248700218c7SGleb Smirnoff
249700218c7SGleb Smirnoff /* Configuration is OK, reset to it. */
250700218c7SGleb Smirnoff priv->cfg = *cfg;
251700218c7SGleb Smirnoff
252700218c7SGleb Smirnoff /* Save return address so we can send reset-req's. */
253700218c7SGleb Smirnoff priv->ctrlnode = NGI_RETADDR(item);
254700218c7SGleb Smirnoff
255700218c7SGleb Smirnoff /* Clear our state. */
256700218c7SGleb Smirnoff Pred1Init(node);
257700218c7SGleb Smirnoff
258700218c7SGleb Smirnoff break;
259700218c7SGleb Smirnoff }
260700218c7SGleb Smirnoff case NGM_PRED1_RESETREQ:
261700218c7SGleb Smirnoff Pred1Init(node);
262700218c7SGleb Smirnoff break;
263700218c7SGleb Smirnoff
264700218c7SGleb Smirnoff case NGM_PRED1_GET_STATS:
265700218c7SGleb Smirnoff case NGM_PRED1_CLR_STATS:
266700218c7SGleb Smirnoff case NGM_PRED1_GETCLR_STATS:
267700218c7SGleb Smirnoff {
268700218c7SGleb Smirnoff /* Create response. */
269700218c7SGleb Smirnoff if (msg->header.cmd != NGM_PRED1_CLR_STATS) {
270700218c7SGleb Smirnoff NG_MKRESPONSE(resp, msg,
271700218c7SGleb Smirnoff sizeof(struct ng_pred1_stats), M_NOWAIT);
272700218c7SGleb Smirnoff if (resp == NULL)
273700218c7SGleb Smirnoff ERROUT(ENOMEM);
274700218c7SGleb Smirnoff bcopy(&priv->stats, resp->data,
275700218c7SGleb Smirnoff sizeof(struct ng_pred1_stats));
276700218c7SGleb Smirnoff }
277700218c7SGleb Smirnoff
278700218c7SGleb Smirnoff if (msg->header.cmd != NGM_PRED1_GET_STATS)
279700218c7SGleb Smirnoff bzero(&priv->stats, sizeof(struct ng_pred1_stats));
280700218c7SGleb Smirnoff break;
281700218c7SGleb Smirnoff }
282700218c7SGleb Smirnoff
283700218c7SGleb Smirnoff default:
284700218c7SGleb Smirnoff error = EINVAL;
285700218c7SGleb Smirnoff break;
286700218c7SGleb Smirnoff }
287700218c7SGleb Smirnoff done:
288700218c7SGleb Smirnoff NG_RESPOND_MSG(error, node, item, resp);
289700218c7SGleb Smirnoff NG_FREE_MSG(msg);
290700218c7SGleb Smirnoff return (error);
291700218c7SGleb Smirnoff }
292700218c7SGleb Smirnoff
293700218c7SGleb Smirnoff /*
294700218c7SGleb Smirnoff * Receive incoming data on our hook.
295700218c7SGleb Smirnoff */
296700218c7SGleb Smirnoff static int
ng_pred1_rcvdata(hook_p hook,item_p item)297700218c7SGleb Smirnoff ng_pred1_rcvdata(hook_p hook, item_p item)
298700218c7SGleb Smirnoff {
299700218c7SGleb Smirnoff const node_p node = NG_HOOK_NODE(hook);
300700218c7SGleb Smirnoff const priv_p priv = NG_NODE_PRIVATE(node);
301700218c7SGleb Smirnoff struct mbuf *m, *out;
302700218c7SGleb Smirnoff int error;
303700218c7SGleb Smirnoff
304700218c7SGleb Smirnoff if (!priv->cfg.enable) {
305700218c7SGleb Smirnoff NG_FREE_ITEM(item);
306700218c7SGleb Smirnoff return (ENXIO);
307700218c7SGleb Smirnoff }
308700218c7SGleb Smirnoff
309700218c7SGleb Smirnoff NGI_GET_M(item, m);
310700218c7SGleb Smirnoff /* Compress. */
311700218c7SGleb Smirnoff if (priv->compress) {
312700218c7SGleb Smirnoff if ((error = ng_pred1_compress(node, m, &out)) != 0) {
313700218c7SGleb Smirnoff NG_FREE_ITEM(item);
314700218c7SGleb Smirnoff log(LOG_NOTICE, "%s: error: %d\n", __func__, error);
315700218c7SGleb Smirnoff return (error);
316700218c7SGleb Smirnoff }
317700218c7SGleb Smirnoff
318700218c7SGleb Smirnoff } else { /* Decompress. */
319700218c7SGleb Smirnoff if ((error = ng_pred1_decompress(node, m, &out)) != 0) {
320700218c7SGleb Smirnoff NG_FREE_ITEM(item);
321700218c7SGleb Smirnoff log(LOG_NOTICE, "%s: error: %d\n", __func__, error);
322700218c7SGleb Smirnoff if (priv->ctrlnode != 0) {
323700218c7SGleb Smirnoff struct ng_mesg *msg;
324700218c7SGleb Smirnoff
325700218c7SGleb Smirnoff /* Need to send a reset-request. */
326700218c7SGleb Smirnoff NG_MKMESSAGE(msg, NGM_PRED1_COOKIE,
327700218c7SGleb Smirnoff NGM_PRED1_RESETREQ, 0, M_NOWAIT);
328700218c7SGleb Smirnoff if (msg == NULL)
329700218c7SGleb Smirnoff return (error);
330700218c7SGleb Smirnoff NG_SEND_MSG_ID(error, node, msg,
331700218c7SGleb Smirnoff priv->ctrlnode, 0);
332700218c7SGleb Smirnoff }
333700218c7SGleb Smirnoff return (error);
334700218c7SGleb Smirnoff }
335700218c7SGleb Smirnoff }
336700218c7SGleb Smirnoff
337700218c7SGleb Smirnoff NG_FWD_NEW_DATA(error, item, hook, out);
338700218c7SGleb Smirnoff return (error);
339700218c7SGleb Smirnoff }
340700218c7SGleb Smirnoff
341700218c7SGleb Smirnoff /*
342700218c7SGleb Smirnoff * Destroy node.
343700218c7SGleb Smirnoff */
344700218c7SGleb Smirnoff static int
ng_pred1_shutdown(node_p node)345700218c7SGleb Smirnoff ng_pred1_shutdown(node_p node)
346700218c7SGleb Smirnoff {
347700218c7SGleb Smirnoff const priv_p priv = NG_NODE_PRIVATE(node);
348700218c7SGleb Smirnoff
349700218c7SGleb Smirnoff free(priv, M_NETGRAPH_PRED1);
350700218c7SGleb Smirnoff NG_NODE_SET_PRIVATE(node, NULL);
351700218c7SGleb Smirnoff NG_NODE_UNREF(node); /* Let the node escape. */
352700218c7SGleb Smirnoff return (0);
353700218c7SGleb Smirnoff }
354700218c7SGleb Smirnoff
355700218c7SGleb Smirnoff /*
356700218c7SGleb Smirnoff * Hook disconnection
357700218c7SGleb Smirnoff */
358700218c7SGleb Smirnoff static int
ng_pred1_disconnect(hook_p hook)359700218c7SGleb Smirnoff ng_pred1_disconnect(hook_p hook)
360700218c7SGleb Smirnoff {
361700218c7SGleb Smirnoff const node_p node = NG_HOOK_NODE(hook);
362700218c7SGleb Smirnoff
363700218c7SGleb Smirnoff Pred1Init(node);
364700218c7SGleb Smirnoff
365700218c7SGleb Smirnoff /* Go away if no longer connected. */
366700218c7SGleb Smirnoff if ((NG_NODE_NUMHOOKS(node) == 0) && NG_NODE_IS_VALID(node))
367700218c7SGleb Smirnoff ng_rmnode_self(node);
368700218c7SGleb Smirnoff return (0);
369700218c7SGleb Smirnoff }
370700218c7SGleb Smirnoff
371700218c7SGleb Smirnoff /************************************************************************
372700218c7SGleb Smirnoff HELPER STUFF
373700218c7SGleb Smirnoff ************************************************************************/
374700218c7SGleb Smirnoff
375700218c7SGleb Smirnoff /*
376700218c7SGleb Smirnoff * Compress/encrypt a packet and put the result in a new mbuf at *resultp.
377700218c7SGleb Smirnoff * The original mbuf is not free'd.
378700218c7SGleb Smirnoff */
379700218c7SGleb Smirnoff static int
ng_pred1_compress(node_p node,struct mbuf * m,struct mbuf ** resultp)380700218c7SGleb Smirnoff ng_pred1_compress(node_p node, struct mbuf *m, struct mbuf **resultp)
381700218c7SGleb Smirnoff {
382700218c7SGleb Smirnoff const priv_p priv = NG_NODE_PRIVATE(node);
383700218c7SGleb Smirnoff int outlen, inlen;
384700218c7SGleb Smirnoff u_char *out;
385700218c7SGleb Smirnoff uint16_t fcs, lenn;
386700218c7SGleb Smirnoff int len;
387700218c7SGleb Smirnoff
388700218c7SGleb Smirnoff /* Initialize. */
389700218c7SGleb Smirnoff *resultp = NULL;
390700218c7SGleb Smirnoff
391700218c7SGleb Smirnoff inlen = m->m_pkthdr.len;
392700218c7SGleb Smirnoff
393700218c7SGleb Smirnoff priv->stats.FramesPlain++;
394700218c7SGleb Smirnoff priv->stats.InOctets += inlen;
395700218c7SGleb Smirnoff
396700218c7SGleb Smirnoff /* Reserve space for expansion. */
397700218c7SGleb Smirnoff if (inlen > (PRED1_BUF_SIZE*8/9 + 1 + 4)) {
398700218c7SGleb Smirnoff priv->stats.Errors++;
399700218c7SGleb Smirnoff NG_FREE_M(m);
400700218c7SGleb Smirnoff return (ENOMEM);
401700218c7SGleb Smirnoff }
402700218c7SGleb Smirnoff
403e4651e05SAlexander Motin /* We must own the mbuf chain exclusively to modify it. */
404eb1b1807SGleb Smirnoff m = m_unshare(m, M_NOWAIT);
405e4651e05SAlexander Motin if (m == NULL) {
406e4651e05SAlexander Motin priv->stats.Errors++;
407e4651e05SAlexander Motin return (ENOMEM);
408e4651e05SAlexander Motin }
409e4651e05SAlexander Motin
410700218c7SGleb Smirnoff /* Work with contiguous regions of memory. */
411700218c7SGleb Smirnoff m_copydata(m, 0, inlen, (caddr_t)(priv->inbuf + 2));
412700218c7SGleb Smirnoff
413700218c7SGleb Smirnoff lenn = htons(inlen & 0x7FFF);
414700218c7SGleb Smirnoff
415700218c7SGleb Smirnoff /* Compute FCS. */
416700218c7SGleb Smirnoff fcs = Crc16(PPP_INITFCS, (u_char *)&lenn, 2);
417700218c7SGleb Smirnoff fcs = Crc16(fcs, priv->inbuf + 2, inlen);
418700218c7SGleb Smirnoff fcs = ~fcs;
419700218c7SGleb Smirnoff
420700218c7SGleb Smirnoff /* Compress data. */
421700218c7SGleb Smirnoff len = Pred1Compress(node, priv->inbuf + 2, priv->outbuf + 2, inlen);
422700218c7SGleb Smirnoff
423700218c7SGleb Smirnoff /* What happened? */
424700218c7SGleb Smirnoff if (len < inlen) {
425700218c7SGleb Smirnoff out = priv->outbuf;
426700218c7SGleb Smirnoff outlen = 2 + len;
427700218c7SGleb Smirnoff *(uint16_t *)out = lenn;
428700218c7SGleb Smirnoff *out |= 0x80;
429700218c7SGleb Smirnoff priv->stats.FramesComp++;
430700218c7SGleb Smirnoff } else {
431700218c7SGleb Smirnoff out = priv->inbuf;
432700218c7SGleb Smirnoff outlen = 2 + inlen;
433700218c7SGleb Smirnoff *(uint16_t *)out = lenn;
434700218c7SGleb Smirnoff priv->stats.FramesUncomp++;
435700218c7SGleb Smirnoff }
436700218c7SGleb Smirnoff
437700218c7SGleb Smirnoff /* Add FCS. */
438700218c7SGleb Smirnoff (out + outlen)[0] = fcs & 0xFF;
439700218c7SGleb Smirnoff (out + outlen)[1] = fcs >> 8;
440700218c7SGleb Smirnoff
441700218c7SGleb Smirnoff /* Calculate resulting size. */
442700218c7SGleb Smirnoff outlen += 2;
443700218c7SGleb Smirnoff
444700218c7SGleb Smirnoff /* Return packet in an mbuf. */
445e4651e05SAlexander Motin m_copyback(m, 0, outlen, (caddr_t)out);
446e4651e05SAlexander Motin if (m->m_pkthdr.len < outlen) {
447e4651e05SAlexander Motin m_freem(m);
448700218c7SGleb Smirnoff priv->stats.Errors++;
449700218c7SGleb Smirnoff return (ENOMEM);
450e4651e05SAlexander Motin } else if (outlen < m->m_pkthdr.len)
451e4651e05SAlexander Motin m_adj(m, outlen - m->m_pkthdr.len);
452e4651e05SAlexander Motin *resultp = m;
453700218c7SGleb Smirnoff priv->stats.OutOctets += outlen;
454700218c7SGleb Smirnoff
455700218c7SGleb Smirnoff return (0);
456700218c7SGleb Smirnoff }
457700218c7SGleb Smirnoff
458700218c7SGleb Smirnoff /*
459700218c7SGleb Smirnoff * Decompress/decrypt packet and put the result in a new mbuf at *resultp.
460700218c7SGleb Smirnoff * The original mbuf is not free'd.
461700218c7SGleb Smirnoff */
462700218c7SGleb Smirnoff static int
ng_pred1_decompress(node_p node,struct mbuf * m,struct mbuf ** resultp)463700218c7SGleb Smirnoff ng_pred1_decompress(node_p node, struct mbuf *m, struct mbuf **resultp)
464700218c7SGleb Smirnoff {
465700218c7SGleb Smirnoff const priv_p priv = NG_NODE_PRIVATE(node);
466700218c7SGleb Smirnoff int inlen;
467700218c7SGleb Smirnoff uint16_t len, len1, cf, lenn;
468700218c7SGleb Smirnoff uint16_t fcs;
469700218c7SGleb Smirnoff
470700218c7SGleb Smirnoff /* Initialize. */
471700218c7SGleb Smirnoff *resultp = NULL;
472700218c7SGleb Smirnoff
473700218c7SGleb Smirnoff inlen = m->m_pkthdr.len;
474700218c7SGleb Smirnoff
475700218c7SGleb Smirnoff if (inlen > PRED1_BUF_SIZE) {
476700218c7SGleb Smirnoff priv->stats.Errors++;
477700218c7SGleb Smirnoff NG_FREE_M(m);
478700218c7SGleb Smirnoff return (ENOMEM);
479700218c7SGleb Smirnoff }
480700218c7SGleb Smirnoff
481e4651e05SAlexander Motin /* We must own the mbuf chain exclusively to modify it. */
482eb1b1807SGleb Smirnoff m = m_unshare(m, M_NOWAIT);
483e4651e05SAlexander Motin if (m == NULL) {
484e4651e05SAlexander Motin priv->stats.Errors++;
485e4651e05SAlexander Motin return (ENOMEM);
486e4651e05SAlexander Motin }
487e4651e05SAlexander Motin
488700218c7SGleb Smirnoff /* Work with contiguous regions of memory. */
489700218c7SGleb Smirnoff m_copydata(m, 0, inlen, (caddr_t)priv->inbuf);
490700218c7SGleb Smirnoff
491700218c7SGleb Smirnoff priv->stats.InOctets += inlen;
492700218c7SGleb Smirnoff
493700218c7SGleb Smirnoff /* Get initial length value. */
494700218c7SGleb Smirnoff len = priv->inbuf[0] << 8;
495700218c7SGleb Smirnoff len += priv->inbuf[1];
496700218c7SGleb Smirnoff
497700218c7SGleb Smirnoff cf = (len & 0x8000);
498700218c7SGleb Smirnoff len &= 0x7fff;
499700218c7SGleb Smirnoff
500700218c7SGleb Smirnoff /* Is data compressed or not really? */
501700218c7SGleb Smirnoff if (cf) {
502700218c7SGleb Smirnoff priv->stats.FramesComp++;
503700218c7SGleb Smirnoff len1 = Pred1Decompress(node, priv->inbuf + 2, priv->outbuf,
504700218c7SGleb Smirnoff inlen - 4, PRED1_BUF_SIZE);
505700218c7SGleb Smirnoff if (len != len1) {
506700218c7SGleb Smirnoff /* Error is detected. Send reset request */
507e4651e05SAlexander Motin m_freem(m);
508700218c7SGleb Smirnoff priv->stats.Errors++;
509700218c7SGleb Smirnoff log(LOG_NOTICE, "ng_pred1: Comp length error (%d) "
510700218c7SGleb Smirnoff "--> len (%d)\n", len, len1);
511700218c7SGleb Smirnoff return (EIO);
512700218c7SGleb Smirnoff }
513700218c7SGleb Smirnoff
514700218c7SGleb Smirnoff /*
515700218c7SGleb Smirnoff * CRC check on receive is defined in RFC. It is surely required
516700218c7SGleb Smirnoff * for compressed frames to signal dictionary corruption,
517700218c7SGleb Smirnoff * but it is actually useless for uncompressed frames because
518700218c7SGleb Smirnoff * the same check has already done by HDLC and/or other layer.
519700218c7SGleb Smirnoff */
520700218c7SGleb Smirnoff lenn = htons(len);
521700218c7SGleb Smirnoff fcs = Crc16(PPP_INITFCS, (u_char *)&lenn, 2);
522700218c7SGleb Smirnoff fcs = Crc16(fcs, priv->outbuf, len);
523700218c7SGleb Smirnoff fcs = Crc16(fcs, priv->inbuf + inlen - 2, 2);
524700218c7SGleb Smirnoff
525700218c7SGleb Smirnoff if (fcs != PPP_GOODFCS) {
526e4651e05SAlexander Motin m_freem(m);
527700218c7SGleb Smirnoff priv->stats.Errors++;
528700218c7SGleb Smirnoff log(LOG_NOTICE, "ng_pred1: Pred1: Bad CRC-16\n");
529700218c7SGleb Smirnoff return (EIO);
530700218c7SGleb Smirnoff }
531700218c7SGleb Smirnoff
532700218c7SGleb Smirnoff /* Return packet in an mbuf. */
533e4651e05SAlexander Motin m_copyback(m, 0, len, (caddr_t)priv->outbuf);
534e4651e05SAlexander Motin if (m->m_pkthdr.len < len) {
535e4651e05SAlexander Motin m_freem(m);
536700218c7SGleb Smirnoff priv->stats.Errors++;
537700218c7SGleb Smirnoff return (ENOMEM);
538e4651e05SAlexander Motin } else if (len < m->m_pkthdr.len)
539e4651e05SAlexander Motin m_adj(m, len - m->m_pkthdr.len);
540e4651e05SAlexander Motin *resultp = m;
541700218c7SGleb Smirnoff
542700218c7SGleb Smirnoff } else {
543700218c7SGleb Smirnoff priv->stats.FramesUncomp++;
544700218c7SGleb Smirnoff if (len != (inlen - 4)) {
545700218c7SGleb Smirnoff /* Wrong length. Send reset request */
546700218c7SGleb Smirnoff priv->stats.Errors++;
547700218c7SGleb Smirnoff log(LOG_NOTICE, "ng_pred1: Uncomp length error (%d) "
548700218c7SGleb Smirnoff "--> len (%d)\n", len, inlen - 4);
549700218c7SGleb Smirnoff NG_FREE_M(m);
550700218c7SGleb Smirnoff return (EIO);
551700218c7SGleb Smirnoff }
552700218c7SGleb Smirnoff Pred1SyncTable(node, priv->inbuf + 2, len);
553700218c7SGleb Smirnoff m_adj(m, 2); /* Strip length. */
554700218c7SGleb Smirnoff m_adj(m, -2); /* Strip fcs. */
555700218c7SGleb Smirnoff *resultp = m;
556700218c7SGleb Smirnoff }
557700218c7SGleb Smirnoff
558700218c7SGleb Smirnoff priv->stats.FramesPlain++;
559700218c7SGleb Smirnoff priv->stats.OutOctets += len;
560700218c7SGleb Smirnoff
561700218c7SGleb Smirnoff return (0);
562700218c7SGleb Smirnoff }
563700218c7SGleb Smirnoff
564700218c7SGleb Smirnoff /*
565700218c7SGleb Smirnoff * Pred1Init()
566700218c7SGleb Smirnoff */
567700218c7SGleb Smirnoff
568700218c7SGleb Smirnoff static void
Pred1Init(node_p node)569700218c7SGleb Smirnoff Pred1Init(node_p node)
570700218c7SGleb Smirnoff {
571700218c7SGleb Smirnoff const priv_p priv = NG_NODE_PRIVATE(node);
572700218c7SGleb Smirnoff
573700218c7SGleb Smirnoff priv->Hash = 0;
574700218c7SGleb Smirnoff memset(priv->GuessTable, 0, PRED1_TABLE_SIZE);
575700218c7SGleb Smirnoff }
576700218c7SGleb Smirnoff
577700218c7SGleb Smirnoff /*
578700218c7SGleb Smirnoff * Pred1Compress()
579700218c7SGleb Smirnoff */
580700218c7SGleb Smirnoff
581700218c7SGleb Smirnoff static int
Pred1Compress(node_p node,u_char * source,u_char * dest,int len)582700218c7SGleb Smirnoff Pred1Compress(node_p node, u_char *source, u_char *dest, int len)
583700218c7SGleb Smirnoff {
584700218c7SGleb Smirnoff const priv_p priv = NG_NODE_PRIVATE(node);
585f8e5127dSAlexander Motin int i;
586700218c7SGleb Smirnoff u_char flags;
587700218c7SGleb Smirnoff u_char *flagdest, *orgdest;
588700218c7SGleb Smirnoff
589700218c7SGleb Smirnoff orgdest = dest;
590700218c7SGleb Smirnoff while (len) {
591700218c7SGleb Smirnoff flagdest = dest++;
592700218c7SGleb Smirnoff flags = 0; /* All guesses are wrong initially. */
593f8e5127dSAlexander Motin for (i = 0; i < 8 && len; i++) {
594700218c7SGleb Smirnoff if (priv->GuessTable[priv->Hash] == *source)
595700218c7SGleb Smirnoff /* Guess was right - don't output. */
596f8e5127dSAlexander Motin flags |= (1 << i);
597700218c7SGleb Smirnoff else {
598700218c7SGleb Smirnoff /* Guess wrong, output char. */
599700218c7SGleb Smirnoff priv->GuessTable[priv->Hash] = *source;
600700218c7SGleb Smirnoff *dest++ = *source;
601700218c7SGleb Smirnoff }
602700218c7SGleb Smirnoff HASH(*source++);
603700218c7SGleb Smirnoff len--;
604700218c7SGleb Smirnoff }
605700218c7SGleb Smirnoff *flagdest = flags;
606700218c7SGleb Smirnoff }
607700218c7SGleb Smirnoff return (dest - orgdest);
608700218c7SGleb Smirnoff }
609700218c7SGleb Smirnoff
610700218c7SGleb Smirnoff /*
611700218c7SGleb Smirnoff * Pred1Decompress()
612700218c7SGleb Smirnoff *
613700218c7SGleb Smirnoff * Returns decompressed size, or -1 if we ran out of space.
614700218c7SGleb Smirnoff */
615700218c7SGleb Smirnoff
616700218c7SGleb Smirnoff static int
Pred1Decompress(node_p node,u_char * source,u_char * dest,int slen,int dlen)617700218c7SGleb Smirnoff Pred1Decompress(node_p node, u_char *source, u_char *dest, int slen, int dlen)
618700218c7SGleb Smirnoff {
619700218c7SGleb Smirnoff const priv_p priv = NG_NODE_PRIVATE(node);
620f8e5127dSAlexander Motin int i;
621700218c7SGleb Smirnoff u_char flags, *orgdest;
622700218c7SGleb Smirnoff
623700218c7SGleb Smirnoff orgdest = dest;
624700218c7SGleb Smirnoff while (slen) {
625700218c7SGleb Smirnoff flags = *source++;
626700218c7SGleb Smirnoff slen--;
627f8e5127dSAlexander Motin for (i = 0; i < 8; i++, flags >>= 1) {
628700218c7SGleb Smirnoff if (dlen <= 0)
629700218c7SGleb Smirnoff return(-1);
630f8e5127dSAlexander Motin if (flags & 0x01)
631700218c7SGleb Smirnoff /* Guess correct */
632700218c7SGleb Smirnoff *dest = priv->GuessTable[priv->Hash];
633700218c7SGleb Smirnoff else {
634700218c7SGleb Smirnoff if (!slen)
635700218c7SGleb Smirnoff /* We seem to be really done -- cabo. */
636700218c7SGleb Smirnoff break;
637700218c7SGleb Smirnoff
638700218c7SGleb Smirnoff /* Guess wrong. */
639700218c7SGleb Smirnoff priv->GuessTable[priv->Hash] = *source;
640700218c7SGleb Smirnoff /* Read from source. */
641700218c7SGleb Smirnoff *dest = *source++;
642700218c7SGleb Smirnoff slen--;
643700218c7SGleb Smirnoff }
644700218c7SGleb Smirnoff HASH(*dest++);
645700218c7SGleb Smirnoff dlen--;
646700218c7SGleb Smirnoff }
647700218c7SGleb Smirnoff }
648700218c7SGleb Smirnoff return (dest - orgdest);
649700218c7SGleb Smirnoff }
650700218c7SGleb Smirnoff
651700218c7SGleb Smirnoff /*
652700218c7SGleb Smirnoff * Pred1SyncTable()
653700218c7SGleb Smirnoff */
654700218c7SGleb Smirnoff
655700218c7SGleb Smirnoff static void
Pred1SyncTable(node_p node,u_char * source,int len)656700218c7SGleb Smirnoff Pred1SyncTable(node_p node, u_char *source, int len)
657700218c7SGleb Smirnoff {
658700218c7SGleb Smirnoff const priv_p priv = NG_NODE_PRIVATE(node);
659700218c7SGleb Smirnoff
660700218c7SGleb Smirnoff while (len--) {
661700218c7SGleb Smirnoff priv->GuessTable[priv->Hash] = *source;
662700218c7SGleb Smirnoff HASH(*source++);
663700218c7SGleb Smirnoff }
664700218c7SGleb Smirnoff }
665700218c7SGleb Smirnoff
666700218c7SGleb Smirnoff /*
667700218c7SGleb Smirnoff * Crc16()
668700218c7SGleb Smirnoff *
669700218c7SGleb Smirnoff * Compute the 16 bit frame check value, per RFC 1171 Appendix B,
670700218c7SGleb Smirnoff * on an array of bytes.
671700218c7SGleb Smirnoff */
672700218c7SGleb Smirnoff
673700218c7SGleb Smirnoff static uint16_t
Crc16(uint16_t crc,u_char * cp,int len)674700218c7SGleb Smirnoff Crc16(uint16_t crc, u_char *cp, int len)
675700218c7SGleb Smirnoff {
676700218c7SGleb Smirnoff while (len--)
677700218c7SGleb Smirnoff crc = (crc >> 8) ^ Crc16Table[(crc ^ *cp++) & 0xff];
678700218c7SGleb Smirnoff return (crc);
679700218c7SGleb Smirnoff }
680700218c7SGleb Smirnoff
681700218c7SGleb Smirnoff static const uint16_t Crc16Table[256] = {
682700218c7SGleb Smirnoff /* 00 */ 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
683700218c7SGleb Smirnoff /* 08 */ 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
684700218c7SGleb Smirnoff /* 10 */ 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
685700218c7SGleb Smirnoff /* 18 */ 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
686700218c7SGleb Smirnoff /* 20 */ 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
687700218c7SGleb Smirnoff /* 28 */ 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
688700218c7SGleb Smirnoff /* 30 */ 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
689700218c7SGleb Smirnoff /* 38 */ 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
690700218c7SGleb Smirnoff /* 40 */ 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
691700218c7SGleb Smirnoff /* 48 */ 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
692700218c7SGleb Smirnoff /* 50 */ 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
693700218c7SGleb Smirnoff /* 58 */ 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
694700218c7SGleb Smirnoff /* 60 */ 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
695700218c7SGleb Smirnoff /* 68 */ 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
696700218c7SGleb Smirnoff /* 70 */ 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
697700218c7SGleb Smirnoff /* 78 */ 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
698700218c7SGleb Smirnoff /* 80 */ 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
699700218c7SGleb Smirnoff /* 88 */ 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
700700218c7SGleb Smirnoff /* 90 */ 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
701700218c7SGleb Smirnoff /* 98 */ 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
702700218c7SGleb Smirnoff /* a0 */ 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
703700218c7SGleb Smirnoff /* a8 */ 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
704700218c7SGleb Smirnoff /* b0 */ 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
705700218c7SGleb Smirnoff /* b8 */ 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
706700218c7SGleb Smirnoff /* c0 */ 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
707700218c7SGleb Smirnoff /* c8 */ 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
708700218c7SGleb Smirnoff /* d0 */ 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
709700218c7SGleb Smirnoff /* d8 */ 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
710700218c7SGleb Smirnoff /* e0 */ 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
711700218c7SGleb Smirnoff /* e8 */ 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
712700218c7SGleb Smirnoff /* f0 */ 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
713700218c7SGleb Smirnoff /* f8 */ 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
714700218c7SGleb Smirnoff };
715