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