1700218c7SGleb Smirnoff /*- 2700218c7SGleb Smirnoff * Copyright (c) 2006 Alexander Motin <mav@alkar.net> 3700218c7SGleb Smirnoff * All rights reserved. 4700218c7SGleb Smirnoff * 5700218c7SGleb Smirnoff * Redistribution and use in source and binary forms, with or without 6700218c7SGleb Smirnoff * modification, are permitted provided that the following conditions 7700218c7SGleb Smirnoff * are met: 8700218c7SGleb Smirnoff * 1. Redistributions of source code must retain the above copyright 9700218c7SGleb Smirnoff * notice unmodified, this list of conditions, and the following 10700218c7SGleb Smirnoff * disclaimer. 11700218c7SGleb Smirnoff * 2. Redistributions in binary form must reproduce the above copyright 12700218c7SGleb Smirnoff * notice, this list of conditions and the following disclaimer in the 13700218c7SGleb Smirnoff * documentation and/or other materials provided with the distribution. 14700218c7SGleb Smirnoff * 15700218c7SGleb Smirnoff * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16700218c7SGleb Smirnoff * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17700218c7SGleb Smirnoff * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18700218c7SGleb Smirnoff * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19700218c7SGleb Smirnoff * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20700218c7SGleb Smirnoff * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21700218c7SGleb Smirnoff * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22700218c7SGleb Smirnoff * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23700218c7SGleb Smirnoff * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24700218c7SGleb Smirnoff * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25700218c7SGleb Smirnoff * SUCH DAMAGE. 26700218c7SGleb Smirnoff * 27700218c7SGleb Smirnoff * $FreeBSD$ 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 49700218c7SGleb Smirnoff 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 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 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 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 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 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 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 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. */ 404e4651e05SAlexander Motin m = m_unshare(m, M_DONTWAIT); 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 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. */ 482e4651e05SAlexander Motin m = m_unshare(m, M_DONTWAIT); 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 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 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 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 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 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 }; 715700218c7SGleb Smirnoff 716