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