ng_deflate.c revision 166019
1165581Sglebius/*- 2165581Sglebius * Copyright (c) 2006 Alexander Motin <mav@alkar.net> 3165581Sglebius * All rights reserved. 4165581Sglebius * 5165581Sglebius * Redistribution and use in source and binary forms, with or without 6165581Sglebius * modification, are permitted provided that the following conditions 7165581Sglebius * are met: 8165581Sglebius * 1. Redistributions of source code must retain the above copyright 9165581Sglebius * notice unmodified, this list of conditions, and the following 10165581Sglebius * disclaimer. 11165581Sglebius * 2. Redistributions in binary form must reproduce the above copyright 12165581Sglebius * notice, this list of conditions and the following disclaimer in the 13165581Sglebius * documentation and/or other materials provided with the distribution. 14165581Sglebius * 15165581Sglebius * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16165581Sglebius * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17165581Sglebius * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18165581Sglebius * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19165581Sglebius * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20165581Sglebius * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21165581Sglebius * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22165581Sglebius * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23165581Sglebius * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24165581Sglebius * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25165581Sglebius * SUCH DAMAGE. 26165581Sglebius * 27165581Sglebius * $FreeBSD: head/sys/netgraph/ng_deflate.c 166019 2007-01-15 05:55:56Z glebius $ 28165581Sglebius */ 29165581Sglebius 30165581Sglebius/* 31165581Sglebius * Deflate PPP compression netgraph node type. 32165581Sglebius */ 33165581Sglebius 34165581Sglebius#include <sys/param.h> 35165581Sglebius#include <sys/systm.h> 36165581Sglebius#include <sys/kernel.h> 37165581Sglebius#include <sys/mbuf.h> 38165581Sglebius#include <sys/malloc.h> 39165581Sglebius#include <sys/errno.h> 40165581Sglebius#include <sys/syslog.h> 41165581Sglebius 42165581Sglebius#include <net/zlib.h> 43165581Sglebius 44165581Sglebius#include <netgraph/ng_message.h> 45165581Sglebius#include <netgraph/netgraph.h> 46165581Sglebius#include <netgraph/ng_parse.h> 47165581Sglebius#include <netgraph/ng_deflate.h> 48165581Sglebius 49165581Sglebius#include "opt_netgraph.h" 50165581Sglebius 51165581SglebiusMALLOC_DEFINE(M_NETGRAPH_DEFLATE, "netgraph_deflate", "netgraph deflate node "); 52165581Sglebius 53165581Sglebius/* DEFLATE header length */ 54165581Sglebius#define DEFLATE_HDRLEN 2 55165581Sglebius 56165581Sglebius#define PROT_COMPD 0x00fd 57165581Sglebius 58165581Sglebius#define DEFLATE_BUF_SIZE 4096 59165581Sglebius 60165581Sglebius/* Node private data */ 61165581Sglebiusstruct ng_deflate_private { 62165581Sglebius struct ng_deflate_config cfg; /* configuration */ 63165581Sglebius u_char inbuf[DEFLATE_BUF_SIZE]; /* input buffer */ 64165581Sglebius u_char outbuf[DEFLATE_BUF_SIZE]; /* output buffer */ 65165581Sglebius z_stream cx; /* compression context */ 66165581Sglebius struct ng_deflate_stats stats; /* statistics */ 67165581Sglebius ng_ID_t ctrlnode; /* path to controlling node */ 68165581Sglebius uint16_t seqnum; /* sequence number */ 69165581Sglebius u_char compress; /* compress/decompress flag */ 70165581Sglebius}; 71165581Sglebiustypedef struct ng_deflate_private *priv_p; 72165581Sglebius 73165581Sglebius/* Netgraph node methods */ 74165581Sglebiusstatic ng_constructor_t ng_deflate_constructor; 75165581Sglebiusstatic ng_rcvmsg_t ng_deflate_rcvmsg; 76165581Sglebiusstatic ng_shutdown_t ng_deflate_shutdown; 77165581Sglebiusstatic ng_newhook_t ng_deflate_newhook; 78165581Sglebiusstatic ng_rcvdata_t ng_deflate_rcvdata; 79165581Sglebiusstatic ng_disconnect_t ng_deflate_disconnect; 80165581Sglebius 81165581Sglebius/* Helper functions */ 82165581Sglebiusstatic void *z_alloc(void *, u_int items, u_int size); 83165581Sglebiusstatic void z_free(void *, void *ptr); 84165581Sglebiusstatic int ng_deflate_compress(node_p node, 85165581Sglebius struct mbuf *m, struct mbuf **resultp); 86165581Sglebiusstatic int ng_deflate_decompress(node_p node, 87165581Sglebius struct mbuf *m, struct mbuf **resultp); 88165581Sglebiusstatic void ng_deflate_reset_req(node_p node); 89165581Sglebius 90165581Sglebius/* Parse type for struct ng_deflate_config. */ 91165581Sglebiusstatic const struct ng_parse_struct_field ng_deflate_config_type_fields[] 92165581Sglebius = NG_DEFLATE_CONFIG_INFO; 93165581Sglebiusstatic const struct ng_parse_type ng_deflate_config_type = { 94165581Sglebius &ng_parse_struct_type, 95165581Sglebius ng_deflate_config_type_fields 96165581Sglebius}; 97165581Sglebius 98165581Sglebius/* Parse type for struct ng_deflate_stat. */ 99165581Sglebiusstatic const struct ng_parse_struct_field ng_deflate_stats_type_fields[] 100165581Sglebius = NG_DEFLATE_STATS_INFO; 101165581Sglebiusstatic const struct ng_parse_type ng_deflate_stat_type = { 102165581Sglebius &ng_parse_struct_type, 103165581Sglebius ng_deflate_stats_type_fields 104165581Sglebius}; 105165581Sglebius 106165581Sglebius/* List of commands and how to convert arguments to/from ASCII. */ 107165581Sglebiusstatic const struct ng_cmdlist ng_deflate_cmds[] = { 108165581Sglebius { 109165581Sglebius NGM_DEFLATE_COOKIE, 110165581Sglebius NGM_DEFLATE_CONFIG, 111165581Sglebius "config", 112165581Sglebius &ng_deflate_config_type, 113165581Sglebius NULL 114165581Sglebius }, 115165581Sglebius { 116165581Sglebius NGM_DEFLATE_COOKIE, 117165581Sglebius NGM_DEFLATE_RESETREQ, 118165581Sglebius "resetreq", 119165581Sglebius NULL, 120165581Sglebius NULL 121165581Sglebius }, 122165581Sglebius { 123165581Sglebius NGM_DEFLATE_COOKIE, 124165581Sglebius NGM_DEFLATE_GET_STATS, 125165581Sglebius "getstats", 126165581Sglebius NULL, 127165581Sglebius &ng_deflate_stat_type 128165581Sglebius }, 129165581Sglebius { 130165581Sglebius NGM_DEFLATE_COOKIE, 131165581Sglebius NGM_DEFLATE_CLR_STATS, 132165581Sglebius "clrstats", 133165581Sglebius NULL, 134165581Sglebius NULL 135165581Sglebius }, 136165581Sglebius { 137165581Sglebius NGM_DEFLATE_COOKIE, 138165581Sglebius NGM_DEFLATE_GETCLR_STATS, 139165581Sglebius "getclrstats", 140165581Sglebius NULL, 141165581Sglebius &ng_deflate_stat_type 142165581Sglebius }, 143165581Sglebius { 0 } 144165581Sglebius}; 145165581Sglebius 146165581Sglebius/* Node type descriptor */ 147165581Sglebiusstatic struct ng_type ng_deflate_typestruct = { 148165581Sglebius .version = NG_ABI_VERSION, 149165581Sglebius .name = NG_DEFLATE_NODE_TYPE, 150165581Sglebius .constructor = ng_deflate_constructor, 151165581Sglebius .rcvmsg = ng_deflate_rcvmsg, 152165581Sglebius .shutdown = ng_deflate_shutdown, 153165581Sglebius .newhook = ng_deflate_newhook, 154165581Sglebius .rcvdata = ng_deflate_rcvdata, 155165581Sglebius .disconnect = ng_deflate_disconnect, 156165581Sglebius .cmdlist = ng_deflate_cmds, 157165581Sglebius}; 158165581SglebiusNETGRAPH_INIT(deflate, &ng_deflate_typestruct); 159165581Sglebius 160165581Sglebius/* Depend on separate zlib module. */ 161165581SglebiusMODULE_DEPEND(ng_deflate, zlib, 1, 1, 1); 162165581Sglebius 163165581Sglebius#define ERROUT(x) do { error = (x); goto done; } while (0) 164165581Sglebius 165165581Sglebius/************************************************************************ 166165581Sglebius NETGRAPH NODE STUFF 167165581Sglebius ************************************************************************/ 168165581Sglebius 169165581Sglebius/* 170165581Sglebius * Node type constructor 171165581Sglebius */ 172165581Sglebiusstatic int 173165581Sglebiusng_deflate_constructor(node_p node) 174165581Sglebius{ 175165581Sglebius priv_p priv; 176165581Sglebius 177165581Sglebius /* Allocate private structure. */ 178165581Sglebius priv = malloc(sizeof(*priv), M_NETGRAPH_DEFLATE, M_WAITOK | M_ZERO); 179165581Sglebius 180165581Sglebius NG_NODE_SET_PRIVATE(node, priv); 181165581Sglebius 182165581Sglebius /* This node is not thread safe. */ 183165581Sglebius NG_NODE_FORCE_WRITER(node); 184165581Sglebius 185165581Sglebius /* Done */ 186165581Sglebius return (0); 187165581Sglebius} 188165581Sglebius 189165581Sglebius/* 190165581Sglebius * Give our OK for a hook to be added. 191165581Sglebius */ 192165581Sglebiusstatic int 193165581Sglebiusng_deflate_newhook(node_p node, hook_p hook, const char *name) 194165581Sglebius{ 195165581Sglebius const priv_p priv = NG_NODE_PRIVATE(node); 196165581Sglebius 197165581Sglebius if (NG_NODE_NUMHOOKS(node) > 0) 198165581Sglebius return (EINVAL); 199165581Sglebius 200165581Sglebius if (strcmp(name, NG_DEFLATE_HOOK_COMP) == 0) 201165581Sglebius priv->compress = 1; 202165581Sglebius else if (strcmp(name, NG_DEFLATE_HOOK_DECOMP) == 0) 203165581Sglebius priv->compress = 0; 204165581Sglebius else 205165581Sglebius return (EINVAL); 206165581Sglebius 207165581Sglebius return (0); 208165581Sglebius} 209165581Sglebius 210165581Sglebius/* 211165581Sglebius * Receive a control message 212165581Sglebius */ 213165581Sglebiusstatic int 214165581Sglebiusng_deflate_rcvmsg(node_p node, item_p item, hook_p lasthook) 215165581Sglebius{ 216165581Sglebius const priv_p priv = NG_NODE_PRIVATE(node); 217165581Sglebius struct ng_mesg *resp = NULL; 218165581Sglebius int error = 0; 219165581Sglebius struct ng_mesg *msg; 220165581Sglebius 221165581Sglebius NGI_GET_MSG(item, msg); 222165581Sglebius 223165581Sglebius if (msg->header.typecookie != NGM_DEFLATE_COOKIE) 224165581Sglebius ERROUT(EINVAL); 225166019Sglebius 226165581Sglebius switch (msg->header.cmd) { 227165581Sglebius case NGM_DEFLATE_CONFIG: 228165581Sglebius { 229165581Sglebius struct ng_deflate_config *const cfg 230165581Sglebius = (struct ng_deflate_config *)msg->data; 231165581Sglebius 232165581Sglebius /* Check configuration. */ 233165581Sglebius if (msg->header.arglen != sizeof(*cfg)) 234165581Sglebius ERROUT(EINVAL); 235165581Sglebius if (cfg->enable) { 236165581Sglebius if (cfg->windowBits < 8 || cfg->windowBits > 15) 237165581Sglebius ERROUT(EINVAL); 238165581Sglebius } else 239165581Sglebius cfg->windowBits = 0; 240165581Sglebius 241165581Sglebius /* Clear previous state. */ 242165581Sglebius if (priv->cfg.enable) { 243165581Sglebius if (priv->compress) 244165581Sglebius deflateEnd(&priv->cx); 245165581Sglebius else 246165581Sglebius inflateEnd(&priv->cx); 247165581Sglebius priv->cfg.enable = 0; 248165581Sglebius } 249166019Sglebius 250165581Sglebius /* Configuration is OK, reset to it. */ 251165581Sglebius priv->cfg = *cfg; 252165581Sglebius 253165581Sglebius if (priv->cfg.enable) { 254165581Sglebius priv->cx.next_in = NULL; 255165581Sglebius priv->cx.zalloc = z_alloc; 256165581Sglebius priv->cx.zfree = z_free; 257165581Sglebius int res; 258165581Sglebius if (priv->compress) { 259165581Sglebius if ((res = deflateInit2(&priv->cx, 260165581Sglebius Z_DEFAULT_COMPRESSION, Z_DEFLATED, 261165581Sglebius -cfg->windowBits, 8, 262165581Sglebius Z_DEFAULT_STRATEGY)) != Z_OK) { 263165581Sglebius log(LOG_NOTICE, 264165581Sglebius "deflateInit2: error %d, %s\n", 265165581Sglebius res, priv->cx.msg); 266165581Sglebius priv->cfg.enable = 0; 267165581Sglebius ERROUT(ENOMEM); 268165581Sglebius } 269165581Sglebius } else { 270165581Sglebius if ((res = inflateInit2(&priv->cx, 271165581Sglebius -cfg->windowBits)) != Z_OK) { 272165581Sglebius log(LOG_NOTICE, 273165581Sglebius "inflateInit2: error %d, %s\n", 274165581Sglebius res, priv->cx.msg); 275165581Sglebius priv->cfg.enable = 0; 276165581Sglebius ERROUT(ENOMEM); 277165581Sglebius } 278165581Sglebius } 279165581Sglebius } 280165581Sglebius 281165581Sglebius /* Initialize other state. */ 282165581Sglebius priv->seqnum = 0; 283165581Sglebius 284165581Sglebius /* Save return address so we can send reset-req's */ 285165581Sglebius priv->ctrlnode = NGI_RETADDR(item); 286165581Sglebius break; 287165581Sglebius } 288165581Sglebius 289165581Sglebius case NGM_DEFLATE_RESETREQ: 290165581Sglebius ng_deflate_reset_req(node); 291165581Sglebius break; 292165581Sglebius 293165581Sglebius case NGM_DEFLATE_GET_STATS: 294165581Sglebius case NGM_DEFLATE_CLR_STATS: 295165581Sglebius case NGM_DEFLATE_GETCLR_STATS: 296165581Sglebius /* Create response if requested. */ 297165581Sglebius if (msg->header.cmd != NGM_DEFLATE_CLR_STATS) { 298165581Sglebius NG_MKRESPONSE(resp, msg, 299165581Sglebius sizeof(struct ng_deflate_stats), M_NOWAIT); 300165581Sglebius if (resp == NULL) 301165581Sglebius ERROUT(ENOMEM); 302165581Sglebius bcopy(&priv->stats, resp->data, 303166019Sglebius sizeof(struct ng_deflate_stats)); 304165581Sglebius } 305165581Sglebius 306165581Sglebius /* Clear stats if requested. */ 307165581Sglebius if (msg->header.cmd != NGM_DEFLATE_GET_STATS) 308165581Sglebius bzero(&priv->stats, 309165581Sglebius sizeof(struct ng_deflate_stats)); 310165581Sglebius break; 311165581Sglebius 312165581Sglebius default: 313165581Sglebius error = EINVAL; 314165581Sglebius break; 315165581Sglebius } 316165581Sglebiusdone: 317165581Sglebius NG_RESPOND_MSG(error, node, item, resp); 318165581Sglebius NG_FREE_MSG(msg); 319165581Sglebius return (error); 320165581Sglebius} 321165581Sglebius 322165581Sglebius/* 323165581Sglebius * Receive incoming data on our hook. 324165581Sglebius */ 325165581Sglebiusstatic int 326165581Sglebiusng_deflate_rcvdata(hook_p hook, item_p item) 327165581Sglebius{ 328165581Sglebius const node_p node = NG_HOOK_NODE(hook); 329165581Sglebius const priv_p priv = NG_NODE_PRIVATE(node); 330165581Sglebius struct mbuf *m, *out; 331165581Sglebius int error; 332165581Sglebius 333165581Sglebius if (!priv->cfg.enable) { 334165581Sglebius NG_FREE_ITEM(item); 335165581Sglebius return (ENXIO); 336165581Sglebius } 337166019Sglebius 338165581Sglebius NGI_GET_M(item, m); 339165581Sglebius /* Compress */ 340165581Sglebius if (priv->compress) { 341165581Sglebius if ((error = ng_deflate_compress(node, m, &out)) != 0) { 342165581Sglebius NG_FREE_ITEM(item); 343165581Sglebius log(LOG_NOTICE, "%s: error: %d\n", __func__, error); 344165581Sglebius return (error); 345165581Sglebius } 346165581Sglebius 347165581Sglebius } else { /* Decompress */ 348165581Sglebius if ((error = ng_deflate_decompress(node, m, &out)) != 0) { 349165581Sglebius NG_FREE_ITEM(item); 350165581Sglebius log(LOG_NOTICE, "%s: error: %d\n", __func__, error); 351165581Sglebius if (priv->ctrlnode != 0) { 352165581Sglebius struct ng_mesg *msg; 353165581Sglebius 354165581Sglebius /* Need to send a reset-request. */ 355165581Sglebius NG_MKMESSAGE(msg, NGM_DEFLATE_COOKIE, 356165581Sglebius NGM_DEFLATE_RESETREQ, 0, M_NOWAIT); 357165581Sglebius if (msg == NULL) 358165581Sglebius return (error); 359165581Sglebius NG_SEND_MSG_ID(error, node, msg, 360165581Sglebius priv->ctrlnode, 0); 361165581Sglebius } 362165581Sglebius return (error); 363165581Sglebius } 364165581Sglebius } 365165581Sglebius 366165581Sglebius NG_FWD_NEW_DATA(error, item, hook, out); 367165581Sglebius return (error); 368165581Sglebius} 369165581Sglebius 370165581Sglebius/* 371165581Sglebius * Destroy node. 372165581Sglebius */ 373165581Sglebiusstatic int 374165581Sglebiusng_deflate_shutdown(node_p node) 375165581Sglebius{ 376165581Sglebius const priv_p priv = NG_NODE_PRIVATE(node); 377165581Sglebius 378165581Sglebius /* Take down netgraph node. */ 379165581Sglebius if (priv->cfg.enable) { 380165581Sglebius if (priv->compress) 381165581Sglebius deflateEnd(&priv->cx); 382165581Sglebius else 383165581Sglebius inflateEnd(&priv->cx); 384165581Sglebius } 385165581Sglebius 386165581Sglebius free(priv, M_NETGRAPH_DEFLATE); 387165581Sglebius NG_NODE_SET_PRIVATE(node, NULL); 388165581Sglebius NG_NODE_UNREF(node); /* let the node escape */ 389165581Sglebius return (0); 390165581Sglebius} 391165581Sglebius 392165581Sglebius/* 393165581Sglebius * Hook disconnection 394165581Sglebius */ 395165581Sglebiusstatic int 396165581Sglebiusng_deflate_disconnect(hook_p hook) 397165581Sglebius{ 398165581Sglebius const node_p node = NG_HOOK_NODE(hook); 399165581Sglebius const priv_p priv = NG_NODE_PRIVATE(node); 400165581Sglebius 401165581Sglebius if (priv->cfg.enable) { 402165581Sglebius if (priv->compress) 403165581Sglebius deflateEnd(&priv->cx); 404165581Sglebius else 405165581Sglebius inflateEnd(&priv->cx); 406165581Sglebius priv->cfg.enable = 0; 407165581Sglebius } 408165581Sglebius 409165581Sglebius /* Go away if no longer connected. */ 410165581Sglebius if ((NG_NODE_NUMHOOKS(node) == 0) && NG_NODE_IS_VALID(node)) 411165581Sglebius ng_rmnode_self(node); 412165581Sglebius return (0); 413165581Sglebius} 414165581Sglebius 415165581Sglebius/************************************************************************ 416165581Sglebius HELPER STUFF 417165581Sglebius ************************************************************************/ 418165581Sglebius 419165581Sglebius/* 420165581Sglebius * Space allocation and freeing routines for use by zlib routines. 421165581Sglebius */ 422165581Sglebius 423165581Sglebiusstatic void * 424165581Sglebiusz_alloc(void *notused, u_int items, u_int size) 425165581Sglebius{ 426165581Sglebius 427165581Sglebius return (malloc(items * size, M_NETGRAPH_DEFLATE, M_NOWAIT)); 428165581Sglebius} 429165581Sglebius 430165581Sglebiusstatic void 431165581Sglebiusz_free(void *notused, void *ptr) 432165581Sglebius{ 433165581Sglebius 434165581Sglebius free(ptr, M_NETGRAPH_DEFLATE); 435165581Sglebius} 436165581Sglebius 437165581Sglebius/* 438165581Sglebius * Compress/encrypt a packet and put the result in a new mbuf at *resultp. 439165581Sglebius * The original mbuf is not free'd. 440165581Sglebius */ 441165581Sglebiusstatic int 442165581Sglebiusng_deflate_compress(node_p node, struct mbuf *m, struct mbuf **resultp) 443165581Sglebius{ 444165581Sglebius const priv_p priv = NG_NODE_PRIVATE(node); 445165581Sglebius int outlen, inlen; 446165581Sglebius int rtn; 447165581Sglebius 448165581Sglebius /* Initialize. */ 449165581Sglebius *resultp = NULL; 450165581Sglebius 451165581Sglebius inlen = m->m_pkthdr.len; 452165581Sglebius 453165581Sglebius priv->stats.FramesPlain++; 454165581Sglebius priv->stats.InOctets+=inlen; 455165581Sglebius 456165581Sglebius if (inlen > DEFLATE_BUF_SIZE) { 457165581Sglebius priv->stats.Errors++; 458165581Sglebius NG_FREE_M(m); 459165581Sglebius return (ENOMEM); 460165581Sglebius } 461166019Sglebius 462165581Sglebius /* Work with contiguous regions of memory. */ 463165581Sglebius m_copydata(m, 0, inlen, (caddr_t)priv->inbuf); 464165581Sglebius outlen = DEFLATE_BUF_SIZE; 465165581Sglebius 466165581Sglebius /* Compress "inbuf" into "outbuf". */ 467165581Sglebius /* Prepare to compress. */ 468165581Sglebius if (priv->inbuf[0] != 0) { 469165581Sglebius priv->cx.next_in = priv->inbuf; 470165581Sglebius priv->cx.avail_in = inlen; 471165581Sglebius } else { 472165581Sglebius priv->cx.next_in = priv->inbuf + 1; /* compress protocol */ 473165581Sglebius priv->cx.avail_in = inlen - 1; 474165581Sglebius } 475165581Sglebius priv->cx.next_out = priv->outbuf + 2 + DEFLATE_HDRLEN; 476165581Sglebius priv->cx.avail_out = outlen - 2 - DEFLATE_HDRLEN; 477165581Sglebius 478165581Sglebius /* Compress. */ 479165581Sglebius rtn = deflate(&priv->cx, Z_PACKET_FLUSH); 480165581Sglebius 481165581Sglebius /* Check return value. */ 482165581Sglebius if (rtn != Z_OK) { 483165581Sglebius priv->stats.Errors++; 484165581Sglebius log(LOG_NOTICE, "ng_deflate: compression error: %d (%s)\n", 485165581Sglebius rtn, priv->cx.msg); 486165581Sglebius NG_FREE_M(m); 487165581Sglebius return (EINVAL); 488165581Sglebius } 489165581Sglebius 490165581Sglebius /* Calculate resulting size. */ 491165581Sglebius outlen -= priv->cx.avail_out; 492165581Sglebius 493165581Sglebius /* If we can't compress this packet, send it as-is. */ 494165581Sglebius if (outlen > inlen) { 495165581Sglebius /* Return original packet uncompressed. */ 496165581Sglebius *resultp = m; 497165581Sglebius priv->stats.FramesUncomp++; 498165581Sglebius priv->stats.OutOctets+=inlen; 499165581Sglebius } else { 500165581Sglebius NG_FREE_M(m); 501165581Sglebius 502165581Sglebius /* Install header. */ 503165581Sglebius ((u_int16_t *)priv->outbuf)[0] = htons(PROT_COMPD); 504165581Sglebius ((u_int16_t *)priv->outbuf)[1] = htons(priv->seqnum); 505165581Sglebius 506165581Sglebius /* Return packet in an mbuf. */ 507165581Sglebius *resultp = m_devget((caddr_t)priv->outbuf, outlen, 0, NULL, 508165581Sglebius NULL); 509165581Sglebius if (*resultp == NULL) { 510165581Sglebius priv->stats.Errors++; 511165581Sglebius return (ENOMEM); 512165581Sglebius }; 513165581Sglebius priv->stats.FramesComp++; 514165581Sglebius priv->stats.OutOctets+=outlen; 515165581Sglebius } 516165581Sglebius 517165581Sglebius /* Update sequence number. */ 518165581Sglebius priv->seqnum++; 519165581Sglebius 520165581Sglebius return (0); 521165581Sglebius} 522165581Sglebius 523165581Sglebius/* 524165581Sglebius * Decompress/decrypt packet and put the result in a new mbuf at *resultp. 525165581Sglebius * The original mbuf is not free'd. 526165581Sglebius */ 527165581Sglebiusstatic int 528165581Sglebiusng_deflate_decompress(node_p node, struct mbuf *m, struct mbuf **resultp) 529165581Sglebius{ 530165581Sglebius const priv_p priv = NG_NODE_PRIVATE(node); 531165581Sglebius int outlen, inlen; 532165581Sglebius int rtn; 533165581Sglebius uint16_t proto; 534165581Sglebius int offset; 535165581Sglebius uint16_t rseqnum; 536165581Sglebius 537165581Sglebius /* Initialize. */ 538165581Sglebius *resultp = NULL; 539165581Sglebius 540165581Sglebius inlen = m->m_pkthdr.len; 541166019Sglebius 542165581Sglebius if (inlen > DEFLATE_BUF_SIZE) { 543165581Sglebius priv->stats.Errors++; 544165581Sglebius NG_FREE_M(m); 545165581Sglebius priv->seqnum = 0; 546165581Sglebius return (ENOMEM); 547165581Sglebius } 548165581Sglebius 549165581Sglebius /* Work with contiguous regions of memory. */ 550165581Sglebius m_copydata(m, 0, inlen, (caddr_t)priv->inbuf); 551165581Sglebius 552165581Sglebius /* Separate proto. */ 553165581Sglebius if ((priv->inbuf[0] & 0x01) != 0) { 554165581Sglebius proto = priv->inbuf[0]; 555165581Sglebius offset = 1; 556165581Sglebius } else { 557165581Sglebius proto = ntohs(((uint16_t *)priv->inbuf)[0]); 558165581Sglebius offset = 2; 559165581Sglebius } 560165581Sglebius 561165925Sglebius priv->stats.InOctets += inlen; 562165925Sglebius 563165581Sglebius /* Packet is compressed, so decompress. */ 564165581Sglebius if (proto == PROT_COMPD) { 565165581Sglebius priv->stats.FramesComp++; 566166019Sglebius 567165581Sglebius /* Check sequence number. */ 568165581Sglebius rseqnum = ntohs(((uint16_t *)(priv->inbuf + offset))[0]); 569165581Sglebius offset += 2; 570165581Sglebius if (rseqnum != priv->seqnum) { 571165581Sglebius priv->stats.Errors++; 572165581Sglebius log(LOG_NOTICE, "ng_deflate: wrong sequence: %u " 573165581Sglebius "instead of %u\n", rseqnum, priv->seqnum); 574165581Sglebius NG_FREE_M(m); 575165581Sglebius priv->seqnum = 0; 576165581Sglebius return (EPIPE); 577165581Sglebius } 578165581Sglebius 579165581Sglebius outlen = DEFLATE_BUF_SIZE; 580165581Sglebius 581165581Sglebius /* Decompress "inbuf" into "outbuf". */ 582165581Sglebius /* Prepare to decompress. */ 583165581Sglebius priv->cx.next_in = priv->inbuf + offset; 584165581Sglebius priv->cx.avail_in = inlen - offset; 585165581Sglebius /* Reserve space for protocol decompression. */ 586165581Sglebius priv->cx.next_out = priv->outbuf + 1; 587165581Sglebius priv->cx.avail_out = outlen - 1; 588165581Sglebius 589165581Sglebius /* Decompress. */ 590165581Sglebius rtn = inflate(&priv->cx, Z_PACKET_FLUSH); 591165581Sglebius 592165581Sglebius /* Check return value. */ 593165581Sglebius if (rtn != Z_OK && rtn != Z_STREAM_END) { 594165581Sglebius priv->stats.Errors++; 595165581Sglebius NG_FREE_M(m); 596165581Sglebius priv->seqnum = 0; 597165581Sglebius log(LOG_NOTICE, "%s: decompression error: %d (%s)\n", 598165581Sglebius __func__, rtn, priv->cx.msg); 599165581Sglebius 600165581Sglebius switch (rtn) { 601165581Sglebius case Z_MEM_ERROR: 602165581Sglebius return (ENOMEM); 603165581Sglebius case Z_DATA_ERROR: 604165581Sglebius return (EIO); 605165581Sglebius default: 606165581Sglebius return (EINVAL); 607165581Sglebius } 608165581Sglebius } 609165581Sglebius 610165581Sglebius /* Calculate resulting size. */ 611165581Sglebius outlen -= priv->cx.avail_out; 612165581Sglebius 613165581Sglebius NG_FREE_M(m); 614165581Sglebius 615165581Sglebius /* Decompress protocol. */ 616165581Sglebius if ((priv->outbuf[1] & 0x01) != 0) { 617165581Sglebius priv->outbuf[0] = 0; 618165581Sglebius /* Return packet in an mbuf. */ 619165581Sglebius *resultp = m_devget((caddr_t)priv->outbuf, outlen, 0, 620165581Sglebius NULL, NULL); 621165581Sglebius } else { 622165581Sglebius outlen--; 623165581Sglebius /* Return packet in an mbuf. */ 624165581Sglebius *resultp = m_devget((caddr_t)(priv->outbuf + 1), 625165581Sglebius outlen, 0, NULL, NULL); 626165581Sglebius } 627165581Sglebius if (*resultp == NULL) { 628165581Sglebius priv->stats.Errors++; 629165581Sglebius priv->seqnum = 0; 630165581Sglebius return (ENOMEM); 631165581Sglebius }; 632165581Sglebius priv->stats.FramesPlain++; 633165581Sglebius priv->stats.OutOctets+=outlen; 634165581Sglebius 635165581Sglebius } else { /* Packet is not compressed, just update dictionary. */ 636165581Sglebius priv->stats.FramesUncomp++; 637165581Sglebius if (priv->inbuf[0] == 0) { 638165581Sglebius priv->cx.next_in = priv->inbuf + 1; /* compress protocol */ 639165581Sglebius priv->cx.avail_in = inlen - 1; 640165581Sglebius } else { 641165581Sglebius priv->cx.next_in = priv->inbuf; 642165581Sglebius priv->cx.avail_in = inlen; 643165581Sglebius } 644165581Sglebius 645165581Sglebius rtn = inflateIncomp(&priv->cx); 646165581Sglebius 647165581Sglebius /* Check return value */ 648165581Sglebius if (rtn != Z_OK) { 649165581Sglebius priv->stats.Errors++; 650165581Sglebius log(LOG_NOTICE, "%s: inflateIncomp error: %d (%s)\n", 651165581Sglebius __func__, rtn, priv->cx.msg); 652165581Sglebius NG_FREE_M(m); 653165581Sglebius priv->seqnum = 0; 654165581Sglebius return (EINVAL); 655165581Sglebius } 656165581Sglebius 657165581Sglebius *resultp = m; 658165581Sglebius priv->stats.FramesPlain++; 659165581Sglebius priv->stats.OutOctets += inlen; 660165581Sglebius } 661165581Sglebius 662165581Sglebius /* Update sequence number. */ 663165581Sglebius priv->seqnum++; 664165581Sglebius 665165581Sglebius return (0); 666165581Sglebius} 667165581Sglebius 668165581Sglebius/* 669165581Sglebius * The peer has sent us a CCP ResetRequest, so reset our transmit state. 670165581Sglebius */ 671165581Sglebiusstatic void 672165581Sglebiusng_deflate_reset_req(node_p node) 673165581Sglebius{ 674165581Sglebius const priv_p priv = NG_NODE_PRIVATE(node); 675165581Sglebius 676165581Sglebius priv->seqnum = 0; 677165581Sglebius if (priv->cfg.enable) { 678165581Sglebius if (priv->compress) 679165581Sglebius deflateReset(&priv->cx); 680165581Sglebius else 681165581Sglebius inflateReset(&priv->cx); 682165581Sglebius } 683165581Sglebius} 684165581Sglebius 685