14cf49a43SJulian Elischer 24cf49a43SJulian Elischer /* 34cf49a43SJulian Elischer * ng_vjc.c 44cf49a43SJulian Elischer * 54cf49a43SJulian Elischer * Copyright (c) 1996-1999 Whistle Communications, Inc. 64cf49a43SJulian Elischer * All rights reserved. 74cf49a43SJulian Elischer * 84cf49a43SJulian Elischer * Subject to the following obligations and disclaimer of warranty, use and 94cf49a43SJulian Elischer * redistribution of this software, in source or object code forms, with or 104cf49a43SJulian Elischer * without modifications are expressly permitted by Whistle Communications; 114cf49a43SJulian Elischer * provided, however, that: 124cf49a43SJulian Elischer * 1. Any and all reproductions of the source or object code must include the 134cf49a43SJulian Elischer * copyright notice above and the following disclaimer of warranties; and 144cf49a43SJulian Elischer * 2. No rights are granted, in any manner or form, to use Whistle 154cf49a43SJulian Elischer * Communications, Inc. trademarks, including the mark "WHISTLE 164cf49a43SJulian Elischer * COMMUNICATIONS" on advertising, endorsements, or otherwise except as 174cf49a43SJulian Elischer * such appears in the above copyright notice or in the software. 184cf49a43SJulian Elischer * 194cf49a43SJulian Elischer * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND 204cf49a43SJulian Elischer * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO 214cf49a43SJulian Elischer * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, 224cf49a43SJulian Elischer * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF 234cf49a43SJulian Elischer * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. 244cf49a43SJulian Elischer * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY 254cf49a43SJulian Elischer * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS 264cf49a43SJulian Elischer * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. 274cf49a43SJulian Elischer * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES 284cf49a43SJulian Elischer * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING 294cf49a43SJulian Elischer * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 304cf49a43SJulian Elischer * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR 314cf49a43SJulian Elischer * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY 324cf49a43SJulian Elischer * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 334cf49a43SJulian Elischer * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 344cf49a43SJulian Elischer * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY 354cf49a43SJulian Elischer * OF SUCH DAMAGE. 364cf49a43SJulian Elischer * 37cc3bbd68SJulian Elischer * Author: Archie Cobbs <archie@freebsd.org> 384cf49a43SJulian Elischer * 394cf49a43SJulian Elischer * $FreeBSD$ 4074f5c6aaSJulian Elischer * $Whistle: ng_vjc.c,v 1.17 1999/11/01 09:24:52 julian Exp $ 414cf49a43SJulian Elischer */ 424cf49a43SJulian Elischer 434cf49a43SJulian Elischer /* 449dcab530SArchie Cobbs * This node performs Van Jacobson IP header (de)compression. 454cf49a43SJulian Elischer * You must have included net/slcompress.c in your kernel compilation. 464cf49a43SJulian Elischer */ 474cf49a43SJulian Elischer 484cf49a43SJulian Elischer #include <sys/param.h> 494cf49a43SJulian Elischer #include <sys/systm.h> 504cf49a43SJulian Elischer #include <sys/errno.h> 514cf49a43SJulian Elischer #include <sys/kernel.h> 524cf49a43SJulian Elischer #include <sys/mbuf.h> 534cf49a43SJulian Elischer #include <sys/malloc.h> 544cf49a43SJulian Elischer #include <sys/errno.h> 554cf49a43SJulian Elischer 564cf49a43SJulian Elischer #include <netgraph/ng_message.h> 574cf49a43SJulian Elischer #include <netgraph/netgraph.h> 58656485a2SArchie Cobbs #include <netgraph/ng_parse.h> 594cf49a43SJulian Elischer #include <netgraph/ng_vjc.h> 604cf49a43SJulian Elischer 614cf49a43SJulian Elischer #include <netinet/in.h> 624cf49a43SJulian Elischer #include <netinet/in_systm.h> 634cf49a43SJulian Elischer #include <netinet/ip.h> 644cf49a43SJulian Elischer #include <netinet/tcp.h> 654cf49a43SJulian Elischer 664cf49a43SJulian Elischer #include <net/slcompress.h> 674cf49a43SJulian Elischer 684cf49a43SJulian Elischer /* Check agreement with slcompress.c */ 694cf49a43SJulian Elischer #if MAX_STATES != NG_VJC_MAX_CHANNELS 704cf49a43SJulian Elischer #error NG_VJC_MAX_CHANNELS must be the same as MAX_STATES 714cf49a43SJulian Elischer #endif 724cf49a43SJulian Elischer 73309c48c6SArchie Cobbs /* Maximum length of a compressed TCP VJ header */ 74309c48c6SArchie Cobbs #define MAX_VJHEADER 19 754cf49a43SJulian Elischer 764cf49a43SJulian Elischer /* Node private data */ 7762838faeSArchie Cobbs struct ng_vjc_private { 784cf49a43SJulian Elischer struct ngm_vjc_config conf; 794cf49a43SJulian Elischer struct slcompress slc; 804cf49a43SJulian Elischer hook_p ip; 814cf49a43SJulian Elischer hook_p vjcomp; 824cf49a43SJulian Elischer hook_p vjuncomp; 834cf49a43SJulian Elischer hook_p vjip; 844cf49a43SJulian Elischer }; 8562838faeSArchie Cobbs typedef struct ng_vjc_private *priv_p; 864cf49a43SJulian Elischer 874cf49a43SJulian Elischer #define ERROUT(x) do { error = (x); goto done; } while (0) 884cf49a43SJulian Elischer 894cf49a43SJulian Elischer /* Netgraph node methods */ 9074f5c6aaSJulian Elischer static ng_constructor_t ng_vjc_constructor; 9174f5c6aaSJulian Elischer static ng_rcvmsg_t ng_vjc_rcvmsg; 92069154d5SJulian Elischer static ng_shutdown_t ng_vjc_shutdown; 9374f5c6aaSJulian Elischer static ng_newhook_t ng_vjc_newhook; 9474f5c6aaSJulian Elischer static ng_rcvdata_t ng_vjc_rcvdata; 9574f5c6aaSJulian Elischer static ng_disconnect_t ng_vjc_disconnect; 964cf49a43SJulian Elischer 974cf49a43SJulian Elischer /* Helper stuff */ 98309c48c6SArchie Cobbs static struct mbuf *ng_vjc_pulluphdrs(struct mbuf *m, int knownTCP); 994cf49a43SJulian Elischer 100656485a2SArchie Cobbs /* Parse type for struct ngm_vjc_config */ 101f0184ff8SArchie Cobbs static const struct ng_parse_struct_field ng_vjc_config_type_fields[] 102656485a2SArchie Cobbs = NG_VJC_CONFIG_TYPE_INFO; 103656485a2SArchie Cobbs static const struct ng_parse_type ng_vjc_config_type = { 104656485a2SArchie Cobbs &ng_parse_struct_type, 105f0184ff8SArchie Cobbs &ng_vjc_config_type_fields 106656485a2SArchie Cobbs }; 107656485a2SArchie Cobbs 108656485a2SArchie Cobbs /* Parse type for the 'last_cs' and 'cs_next' fields in struct slcompress, 109656485a2SArchie Cobbs which are pointers converted to integer indices, so parse them that way. */ 110656485a2SArchie Cobbs #if _MACHINE_ARCH == i386 111656485a2SArchie Cobbs #define NG_VJC_TSTATE_PTR_TYPE &ng_parse_uint32_type 112656485a2SArchie Cobbs #elif _MACHINE_ARCH == alpha 113656485a2SArchie Cobbs #define NG_VJC_TSTATE_PTR_TYPE &ng_parse_uint64_type 114656485a2SArchie Cobbs #else 115656485a2SArchie Cobbs #error Unspported _MACHINE_ARCH 116656485a2SArchie Cobbs #endif 117656485a2SArchie Cobbs 118656485a2SArchie Cobbs /* Parse type for the 'cs_hdr' field in a struct cstate. Ideally we would 119656485a2SArchie Cobbs like to use a 'struct ip' type instead of a simple array of bytes. */ 120656485a2SArchie Cobbs static const struct ng_parse_fixedarray_info ng_vjc_cs_hdr_type_info = { 121656485a2SArchie Cobbs &ng_parse_hint8_type, 122656485a2SArchie Cobbs MAX_HDR 123656485a2SArchie Cobbs }; 124656485a2SArchie Cobbs static const struct ng_parse_type ng_vjc_cs_hdr_type = { 125656485a2SArchie Cobbs &ng_parse_fixedarray_type, 126656485a2SArchie Cobbs &ng_vjc_cs_hdr_type_info 127656485a2SArchie Cobbs }; 128656485a2SArchie Cobbs 129656485a2SArchie Cobbs /* Parse type for a struct cstate */ 130f0184ff8SArchie Cobbs static const struct ng_parse_struct_field ng_vjc_cstate_type_fields[] = { 131656485a2SArchie Cobbs { "cs_next", NG_VJC_TSTATE_PTR_TYPE }, 132656485a2SArchie Cobbs { "cs_hlen", &ng_parse_uint16_type }, 133656485a2SArchie Cobbs { "cs_id", &ng_parse_uint8_type }, 134656485a2SArchie Cobbs { "cs_filler", &ng_parse_uint8_type }, 135656485a2SArchie Cobbs { "cs_hdr", &ng_vjc_cs_hdr_type }, 136f0184ff8SArchie Cobbs { NULL } 137656485a2SArchie Cobbs }; 138656485a2SArchie Cobbs static const struct ng_parse_type ng_vjc_cstate_type = { 139656485a2SArchie Cobbs &ng_parse_struct_type, 140f0184ff8SArchie Cobbs &ng_vjc_cstate_type_fields 141656485a2SArchie Cobbs }; 142656485a2SArchie Cobbs 143656485a2SArchie Cobbs /* Parse type for an array of MAX_STATES struct cstate's, ie, tstate & rstate */ 144656485a2SArchie Cobbs static const struct ng_parse_fixedarray_info ng_vjc_cstatearray_type_info = { 145656485a2SArchie Cobbs &ng_vjc_cstate_type, 146656485a2SArchie Cobbs MAX_STATES 147656485a2SArchie Cobbs }; 148656485a2SArchie Cobbs static const struct ng_parse_type ng_vjc_cstatearray_type = { 149656485a2SArchie Cobbs &ng_parse_fixedarray_type, 150656485a2SArchie Cobbs &ng_vjc_cstatearray_type_info 151656485a2SArchie Cobbs }; 152656485a2SArchie Cobbs 153656485a2SArchie Cobbs /* Parse type for struct slcompress. Keep this in sync with the 154656485a2SArchie Cobbs definition of struct slcompress defined in <net/slcompress.h> */ 155f0184ff8SArchie Cobbs static const struct ng_parse_struct_field ng_vjc_slcompress_type_fields[] = { 156656485a2SArchie Cobbs { "last_cs", NG_VJC_TSTATE_PTR_TYPE }, 157656485a2SArchie Cobbs { "last_recv", &ng_parse_uint8_type }, 158656485a2SArchie Cobbs { "last_xmit", &ng_parse_uint8_type }, 159656485a2SArchie Cobbs { "flags", &ng_parse_hint16_type }, 160656485a2SArchie Cobbs #ifndef SL_NO_STATS 161656485a2SArchie Cobbs { "sls_packets", &ng_parse_uint32_type }, 162656485a2SArchie Cobbs { "sls_compressed", &ng_parse_uint32_type }, 163656485a2SArchie Cobbs { "sls_searches", &ng_parse_uint32_type }, 164656485a2SArchie Cobbs { "sls_misses", &ng_parse_uint32_type }, 165656485a2SArchie Cobbs { "sls_uncompressedin", &ng_parse_uint32_type }, 166656485a2SArchie Cobbs { "sls_compressedin", &ng_parse_uint32_type }, 167656485a2SArchie Cobbs { "sls_errorin", &ng_parse_uint32_type }, 168656485a2SArchie Cobbs { "sls_tossed", &ng_parse_uint32_type }, 169656485a2SArchie Cobbs #endif 170656485a2SArchie Cobbs { "tstate", &ng_vjc_cstatearray_type }, 171656485a2SArchie Cobbs { "rstate", &ng_vjc_cstatearray_type }, 172f0184ff8SArchie Cobbs { NULL } 173656485a2SArchie Cobbs }; 174656485a2SArchie Cobbs static const struct ng_parse_type ng_vjc_slcompress_type = { 175656485a2SArchie Cobbs &ng_parse_struct_type, 176f0184ff8SArchie Cobbs &ng_vjc_slcompress_type_fields 177656485a2SArchie Cobbs }; 178656485a2SArchie Cobbs 179656485a2SArchie Cobbs /* List of commands and how to convert arguments to/from ASCII */ 180656485a2SArchie Cobbs static const struct ng_cmdlist ng_vjc_cmds[] = { 181656485a2SArchie Cobbs { 182656485a2SArchie Cobbs NGM_VJC_COOKIE, 183656485a2SArchie Cobbs NGM_VJC_SET_CONFIG, 184656485a2SArchie Cobbs "setconfig", 185656485a2SArchie Cobbs &ng_vjc_config_type, 186656485a2SArchie Cobbs NULL 187656485a2SArchie Cobbs }, 188656485a2SArchie Cobbs { 189656485a2SArchie Cobbs NGM_VJC_COOKIE, 190656485a2SArchie Cobbs NGM_VJC_GET_CONFIG, 191656485a2SArchie Cobbs "getconfig", 192656485a2SArchie Cobbs NULL, 193656485a2SArchie Cobbs &ng_vjc_config_type, 194656485a2SArchie Cobbs }, 195656485a2SArchie Cobbs { 196656485a2SArchie Cobbs NGM_VJC_COOKIE, 197656485a2SArchie Cobbs NGM_VJC_GET_STATE, 198656485a2SArchie Cobbs "getstate", 199656485a2SArchie Cobbs NULL, 200656485a2SArchie Cobbs &ng_vjc_slcompress_type, 201656485a2SArchie Cobbs }, 202656485a2SArchie Cobbs { 203656485a2SArchie Cobbs NGM_VJC_COOKIE, 204656485a2SArchie Cobbs NGM_VJC_CLR_STATS, 205656485a2SArchie Cobbs "clrstats", 206656485a2SArchie Cobbs NULL, 207656485a2SArchie Cobbs NULL, 208656485a2SArchie Cobbs }, 209656485a2SArchie Cobbs { 210656485a2SArchie Cobbs NGM_VJC_COOKIE, 211656485a2SArchie Cobbs NGM_VJC_RECV_ERROR, 212656485a2SArchie Cobbs "recverror", 213656485a2SArchie Cobbs NULL, 214656485a2SArchie Cobbs NULL, 215656485a2SArchie Cobbs }, 216656485a2SArchie Cobbs { 0 } 217656485a2SArchie Cobbs }; 218656485a2SArchie Cobbs 2194cf49a43SJulian Elischer /* Node type descriptor */ 220656485a2SArchie Cobbs static struct ng_type ng_vjc_typestruct = { 221f8aae777SJulian Elischer .version = NG_ABI_VERSION, 222f8aae777SJulian Elischer .name = NG_VJC_NODE_TYPE, 223f8aae777SJulian Elischer .constructor = ng_vjc_constructor, 224f8aae777SJulian Elischer .rcvmsg = ng_vjc_rcvmsg, 225f8aae777SJulian Elischer .shutdown = ng_vjc_shutdown, 226f8aae777SJulian Elischer .newhook = ng_vjc_newhook, 227f8aae777SJulian Elischer .rcvdata = ng_vjc_rcvdata, 228f8aae777SJulian Elischer .disconnect = ng_vjc_disconnect, 229f8aae777SJulian Elischer .cmdlist = ng_vjc_cmds, 2304cf49a43SJulian Elischer }; 231656485a2SArchie Cobbs NETGRAPH_INIT(vjc, &ng_vjc_typestruct); 2324cf49a43SJulian Elischer 2334cf49a43SJulian Elischer /************************************************************************ 2344cf49a43SJulian Elischer NETGRAPH NODE METHODS 2354cf49a43SJulian Elischer ************************************************************************/ 2364cf49a43SJulian Elischer 2374cf49a43SJulian Elischer /* 2384cf49a43SJulian Elischer * Create a new node 2394cf49a43SJulian Elischer */ 2404cf49a43SJulian Elischer static int 241069154d5SJulian Elischer ng_vjc_constructor(node_p node) 2424cf49a43SJulian Elischer { 2434cf49a43SJulian Elischer priv_p priv; 2444cf49a43SJulian Elischer 2454cf49a43SJulian Elischer /* Allocate private structure */ 24699cdf4ccSDavid Malone MALLOC(priv, priv_p, sizeof(*priv), M_NETGRAPH, M_NOWAIT | M_ZERO); 2474cf49a43SJulian Elischer if (priv == NULL) 2484cf49a43SJulian Elischer return (ENOMEM); 2494cf49a43SJulian Elischer 25030400f03SJulian Elischer NG_NODE_SET_PRIVATE(node, priv); 2514cf49a43SJulian Elischer 2524cf49a43SJulian Elischer /* Done */ 2534cf49a43SJulian Elischer return (0); 2544cf49a43SJulian Elischer } 2554cf49a43SJulian Elischer 2564cf49a43SJulian Elischer /* 2574cf49a43SJulian Elischer * Add a new hook 2584cf49a43SJulian Elischer */ 2594cf49a43SJulian Elischer static int 2604cf49a43SJulian Elischer ng_vjc_newhook(node_p node, hook_p hook, const char *name) 2614cf49a43SJulian Elischer { 26230400f03SJulian Elischer const priv_p priv = NG_NODE_PRIVATE(node); 2634cf49a43SJulian Elischer hook_p *hookp; 2644cf49a43SJulian Elischer 2654cf49a43SJulian Elischer /* Get hook */ 2663f47e1e3SArchie Cobbs if (strcmp(name, NG_VJC_HOOK_IP) == 0) 2674cf49a43SJulian Elischer hookp = &priv->ip; 2683f47e1e3SArchie Cobbs else if (strcmp(name, NG_VJC_HOOK_VJCOMP) == 0) 2694cf49a43SJulian Elischer hookp = &priv->vjcomp; 2703f47e1e3SArchie Cobbs else if (strcmp(name, NG_VJC_HOOK_VJUNCOMP) == 0) 2714cf49a43SJulian Elischer hookp = &priv->vjuncomp; 2723f47e1e3SArchie Cobbs else if (strcmp(name, NG_VJC_HOOK_VJIP) == 0) 2734cf49a43SJulian Elischer hookp = &priv->vjip; 2744cf49a43SJulian Elischer else 2754cf49a43SJulian Elischer return (EINVAL); 2764cf49a43SJulian Elischer 2774cf49a43SJulian Elischer /* See if already connected */ 2784cf49a43SJulian Elischer if (*hookp) 2794cf49a43SJulian Elischer return (EISCONN); 2804cf49a43SJulian Elischer 2814cf49a43SJulian Elischer /* OK */ 2824cf49a43SJulian Elischer *hookp = hook; 2834cf49a43SJulian Elischer return (0); 2844cf49a43SJulian Elischer } 2854cf49a43SJulian Elischer 2864cf49a43SJulian Elischer /* 2874cf49a43SJulian Elischer * Receive a control message 2884cf49a43SJulian Elischer */ 2894cf49a43SJulian Elischer static int 290069154d5SJulian Elischer ng_vjc_rcvmsg(node_p node, item_p item, hook_p lasthook) 2914cf49a43SJulian Elischer { 29230400f03SJulian Elischer const priv_p priv = NG_NODE_PRIVATE(node); 2934cf49a43SJulian Elischer struct ng_mesg *resp = NULL; 2944cf49a43SJulian Elischer int error = 0; 295069154d5SJulian Elischer struct ng_mesg *msg; 2964cf49a43SJulian Elischer 297069154d5SJulian Elischer NGI_GET_MSG(item, msg); 2984cf49a43SJulian Elischer /* Check type cookie */ 2994cf49a43SJulian Elischer switch (msg->header.typecookie) { 3004cf49a43SJulian Elischer case NGM_VJC_COOKIE: 3014cf49a43SJulian Elischer switch (msg->header.cmd) { 302bef9dae0SJulian Elischer case NGM_VJC_SET_CONFIG: 3034cf49a43SJulian Elischer { 3044cf49a43SJulian Elischer struct ngm_vjc_config *const c = 3054cf49a43SJulian Elischer (struct ngm_vjc_config *) msg->data; 3064cf49a43SJulian Elischer 307bef9dae0SJulian Elischer if (msg->header.arglen != sizeof(*c)) 308bef9dae0SJulian Elischer ERROUT(EINVAL); 309bef9dae0SJulian Elischer if ((priv->conf.enableComp || priv->conf.enableDecomp) 310bef9dae0SJulian Elischer && (c->enableComp || c->enableDecomp)) 311bef9dae0SJulian Elischer ERROUT(EALREADY); 312bef9dae0SJulian Elischer if (c->enableComp) { 3133f47e1e3SArchie Cobbs if (c->maxChannel > NG_VJC_MAX_CHANNELS - 1 3143f47e1e3SArchie Cobbs || c->maxChannel < NG_VJC_MIN_CHANNELS - 1) 3154cf49a43SJulian Elischer ERROUT(EINVAL); 316309c48c6SArchie Cobbs } else 317309c48c6SArchie Cobbs c->maxChannel = NG_VJC_MAX_CHANNELS - 1; 318bef9dae0SJulian Elischer if (c->enableComp != 0 || c->enableDecomp != 0) { 3194cf49a43SJulian Elischer bzero(&priv->slc, sizeof(priv->slc)); 3203f47e1e3SArchie Cobbs sl_compress_init(&priv->slc, c->maxChannel); 3214cf49a43SJulian Elischer } 3224cf49a43SJulian Elischer priv->conf = *c; 3234cf49a43SJulian Elischer break; 3244cf49a43SJulian Elischer } 325656485a2SArchie Cobbs case NGM_VJC_GET_CONFIG: 326656485a2SArchie Cobbs { 327656485a2SArchie Cobbs struct ngm_vjc_config *conf; 328656485a2SArchie Cobbs 329656485a2SArchie Cobbs NG_MKRESPONSE(resp, msg, sizeof(*conf), M_NOWAIT); 3304cf49a43SJulian Elischer if (resp == NULL) 3314cf49a43SJulian Elischer ERROUT(ENOMEM); 332656485a2SArchie Cobbs conf = (struct ngm_vjc_config *)resp->data; 333656485a2SArchie Cobbs *conf = priv->conf; 3344cf49a43SJulian Elischer break; 335656485a2SArchie Cobbs } 336656485a2SArchie Cobbs case NGM_VJC_GET_STATE: 337656485a2SArchie Cobbs { 338656485a2SArchie Cobbs const struct slcompress *const sl0 = &priv->slc; 339656485a2SArchie Cobbs struct slcompress *sl; 340656485a2SArchie Cobbs u_int16_t index; 341656485a2SArchie Cobbs int i; 342656485a2SArchie Cobbs 343656485a2SArchie Cobbs /* Get response structure */ 344656485a2SArchie Cobbs NG_MKRESPONSE(resp, msg, sizeof(*sl), M_NOWAIT); 345656485a2SArchie Cobbs if (resp == NULL) 346656485a2SArchie Cobbs ERROUT(ENOMEM); 347656485a2SArchie Cobbs sl = (struct slcompress *)resp->data; 348656485a2SArchie Cobbs *sl = *sl0; 349656485a2SArchie Cobbs 350656485a2SArchie Cobbs /* Replace pointers with integer indicies */ 351656485a2SArchie Cobbs if (sl->last_cs != NULL) { 352656485a2SArchie Cobbs index = sl0->last_cs - sl0->tstate; 353656485a2SArchie Cobbs bzero(&sl->last_cs, sizeof(sl->last_cs)); 354656485a2SArchie Cobbs *((u_int16_t *)&sl->last_cs) = index; 355656485a2SArchie Cobbs } 356656485a2SArchie Cobbs for (i = 0; i < MAX_STATES; i++) { 357656485a2SArchie Cobbs struct cstate *const cs = &sl->tstate[i]; 358656485a2SArchie Cobbs 359656485a2SArchie Cobbs index = sl0->tstate[i].cs_next - sl0->tstate; 360656485a2SArchie Cobbs bzero(&cs->cs_next, sizeof(cs->cs_next)); 361656485a2SArchie Cobbs *((u_int16_t *)&cs->cs_next) = index; 362656485a2SArchie Cobbs } 363656485a2SArchie Cobbs break; 364656485a2SArchie Cobbs } 3654cf49a43SJulian Elischer case NGM_VJC_CLR_STATS: 3664cf49a43SJulian Elischer priv->slc.sls_packets = 0; 3674cf49a43SJulian Elischer priv->slc.sls_compressed = 0; 3684cf49a43SJulian Elischer priv->slc.sls_searches = 0; 3694cf49a43SJulian Elischer priv->slc.sls_misses = 0; 3704cf49a43SJulian Elischer priv->slc.sls_uncompressedin = 0; 3714cf49a43SJulian Elischer priv->slc.sls_compressedin = 0; 3724cf49a43SJulian Elischer priv->slc.sls_errorin = 0; 3734cf49a43SJulian Elischer priv->slc.sls_tossed = 0; 3744cf49a43SJulian Elischer break; 3754cf49a43SJulian Elischer case NGM_VJC_RECV_ERROR: 3763f47e1e3SArchie Cobbs sl_uncompress_tcp(NULL, 0, TYPE_ERROR, &priv->slc); 3774cf49a43SJulian Elischer break; 3784cf49a43SJulian Elischer default: 3794cf49a43SJulian Elischer error = EINVAL; 3804cf49a43SJulian Elischer break; 3814cf49a43SJulian Elischer } 3824cf49a43SJulian Elischer break; 3834cf49a43SJulian Elischer default: 3844cf49a43SJulian Elischer error = EINVAL; 3854cf49a43SJulian Elischer break; 3864cf49a43SJulian Elischer } 3874cf49a43SJulian Elischer done: 388069154d5SJulian Elischer NG_RESPOND_MSG(error, node, item, resp); 389069154d5SJulian Elischer NG_FREE_MSG(msg); 3904cf49a43SJulian Elischer return (error); 3914cf49a43SJulian Elischer } 3924cf49a43SJulian Elischer 3934cf49a43SJulian Elischer /* 3944cf49a43SJulian Elischer * Receive data 3954cf49a43SJulian Elischer */ 3964cf49a43SJulian Elischer static int 397069154d5SJulian Elischer ng_vjc_rcvdata(hook_p hook, item_p item) 3984cf49a43SJulian Elischer { 39930400f03SJulian Elischer const node_p node = NG_HOOK_NODE(hook); 40030400f03SJulian Elischer const priv_p priv = NG_NODE_PRIVATE(node); 4014cf49a43SJulian Elischer int error = 0; 402069154d5SJulian Elischer struct mbuf *m; 4034cf49a43SJulian Elischer 404069154d5SJulian Elischer NGI_GET_M(item, m); 4054cf49a43SJulian Elischer if (hook == priv->ip) { /* outgoing packet */ 406309c48c6SArchie Cobbs u_int type = TYPE_IP; 4074cf49a43SJulian Elischer 408309c48c6SArchie Cobbs /* Compress packet if enabled and proto is TCP */ 409309c48c6SArchie Cobbs if (priv->conf.enableComp) { 4104cf49a43SJulian Elischer struct ip *ip; 4114cf49a43SJulian Elischer 412309c48c6SArchie Cobbs if ((m = ng_vjc_pulluphdrs(m, 0)) == NULL) { 413069154d5SJulian Elischer NG_FREE_ITEM(item); 414309c48c6SArchie Cobbs return (ENOBUFS); 4154cf49a43SJulian Elischer } 416309c48c6SArchie Cobbs ip = mtod(m, struct ip *); 417309c48c6SArchie Cobbs if (ip->ip_p == IPPROTO_TCP) { 418309c48c6SArchie Cobbs const int origLen = m->m_len; 419309c48c6SArchie Cobbs 420309c48c6SArchie Cobbs type = sl_compress_tcp(m, ip, 421309c48c6SArchie Cobbs &priv->slc, priv->conf.compressCID); 422309c48c6SArchie Cobbs m->m_pkthdr.len += m->m_len - origLen; 423309c48c6SArchie Cobbs } 424309c48c6SArchie Cobbs } 425309c48c6SArchie Cobbs 426309c48c6SArchie Cobbs /* Dispatch to the appropriate outgoing hook */ 4274cf49a43SJulian Elischer switch (type) { 4284cf49a43SJulian Elischer case TYPE_IP: 4294cf49a43SJulian Elischer hook = priv->vjip; 4304cf49a43SJulian Elischer break; 4314cf49a43SJulian Elischer case TYPE_UNCOMPRESSED_TCP: 4324cf49a43SJulian Elischer hook = priv->vjuncomp; 4334cf49a43SJulian Elischer break; 4344cf49a43SJulian Elischer case TYPE_COMPRESSED_TCP: 4354cf49a43SJulian Elischer hook = priv->vjcomp; 4364cf49a43SJulian Elischer break; 4374cf49a43SJulian Elischer default: 4386e551fb6SDavid E. O'Brien panic("%s: type=%d", __func__, type); 4394cf49a43SJulian Elischer } 4404cf49a43SJulian Elischer } else if (hook == priv->vjcomp) { /* incoming compressed packet */ 441309c48c6SArchie Cobbs int vjlen, need2pullup; 442309c48c6SArchie Cobbs struct mbuf *hm; 4434cf49a43SJulian Elischer u_char *hdr; 444309c48c6SArchie Cobbs u_int hlen; 4454cf49a43SJulian Elischer 446bef9dae0SJulian Elischer /* Are we decompressing? */ 447bef9dae0SJulian Elischer if (!priv->conf.enableDecomp) { 448069154d5SJulian Elischer NG_FREE_M(m); 449069154d5SJulian Elischer NG_FREE_ITEM(item); 450309c48c6SArchie Cobbs return (ENXIO); 451309c48c6SArchie Cobbs } 452309c48c6SArchie Cobbs 453309c48c6SArchie Cobbs /* Pull up the necessary amount from the mbuf */ 454309c48c6SArchie Cobbs need2pullup = MAX_VJHEADER; 455309c48c6SArchie Cobbs if (need2pullup > m->m_pkthdr.len) 456309c48c6SArchie Cobbs need2pullup = m->m_pkthdr.len; 457309c48c6SArchie Cobbs if (m->m_len < need2pullup 458309c48c6SArchie Cobbs && (m = m_pullup(m, need2pullup)) == NULL) { 459309c48c6SArchie Cobbs priv->slc.sls_errorin++; 460069154d5SJulian Elischer NG_FREE_ITEM(item); 461309c48c6SArchie Cobbs return (ENOBUFS); 4624cf49a43SJulian Elischer } 4634cf49a43SJulian Elischer 4644cf49a43SJulian Elischer /* Uncompress packet to reconstruct TCP/IP header */ 4654cf49a43SJulian Elischer vjlen = sl_uncompress_tcp_core(mtod(m, u_char *), 4664cf49a43SJulian Elischer m->m_len, m->m_pkthdr.len, TYPE_COMPRESSED_TCP, 4674cf49a43SJulian Elischer &priv->slc, &hdr, &hlen); 4684cf49a43SJulian Elischer if (vjlen <= 0) { 469069154d5SJulian Elischer NG_FREE_M(m); 470069154d5SJulian Elischer NG_FREE_ITEM(item); 471309c48c6SArchie Cobbs return (EINVAL); 4724cf49a43SJulian Elischer } 4733f47e1e3SArchie Cobbs m_adj(m, vjlen); 4744cf49a43SJulian Elischer 4754cf49a43SJulian Elischer /* Copy the reconstructed TCP/IP headers into a new mbuf */ 476a163d034SWarner Losh MGETHDR(hm, M_DONTWAIT, MT_DATA); 477309c48c6SArchie Cobbs if (hm == NULL) { 478309c48c6SArchie Cobbs priv->slc.sls_errorin++; 479069154d5SJulian Elischer NG_FREE_M(m); 480069154d5SJulian Elischer NG_FREE_ITEM(item); 481309c48c6SArchie Cobbs return (ENOBUFS); 482309c48c6SArchie Cobbs } 483309c48c6SArchie Cobbs hm->m_len = 0; 4844e256e6eSArchie Cobbs hm->m_pkthdr.rcvif = NULL; 485309c48c6SArchie Cobbs if (hlen > MHLEN) { /* unlikely, but can happen */ 486a163d034SWarner Losh MCLGET(hm, M_DONTWAIT); 487309c48c6SArchie Cobbs if ((hm->m_flags & M_EXT) == 0) { 488309c48c6SArchie Cobbs m_freem(hm); 489309c48c6SArchie Cobbs priv->slc.sls_errorin++; 490069154d5SJulian Elischer NG_FREE_M(m); 491069154d5SJulian Elischer NG_FREE_ITEM(item); 492309c48c6SArchie Cobbs return (ENOBUFS); 4934cf49a43SJulian Elischer } 4944cf49a43SJulian Elischer } 495309c48c6SArchie Cobbs bcopy(hdr, mtod(hm, u_char *), hlen); 496309c48c6SArchie Cobbs hm->m_len = hlen; 4974cf49a43SJulian Elischer 498309c48c6SArchie Cobbs /* Glue TCP/IP headers and rest of packet together */ 499309c48c6SArchie Cobbs hm->m_next = m; 500309c48c6SArchie Cobbs hm->m_pkthdr.len = hlen + m->m_pkthdr.len; 501309c48c6SArchie Cobbs m = hm; 5024cf49a43SJulian Elischer hook = priv->ip; 5034cf49a43SJulian Elischer } else if (hook == priv->vjuncomp) { /* incoming uncompressed pkt */ 5044cf49a43SJulian Elischer u_char *hdr; 505bef9dae0SJulian Elischer u_int hlen; 5064cf49a43SJulian Elischer 507bef9dae0SJulian Elischer /* Are we decompressing? */ 508bef9dae0SJulian Elischer if (!priv->conf.enableDecomp) { 509069154d5SJulian Elischer NG_FREE_M(m); 510069154d5SJulian Elischer NG_FREE_ITEM(item); 511309c48c6SArchie Cobbs return (ENXIO); 512309c48c6SArchie Cobbs } 513309c48c6SArchie Cobbs 514309c48c6SArchie Cobbs /* Pull up IP+TCP headers */ 515309c48c6SArchie Cobbs if ((m = ng_vjc_pulluphdrs(m, 1)) == NULL) { 516069154d5SJulian Elischer NG_FREE_ITEM(item); 517309c48c6SArchie Cobbs return (ENOBUFS); 5184cf49a43SJulian Elischer } 5194cf49a43SJulian Elischer 5204cf49a43SJulian Elischer /* Run packet through uncompressor */ 5214cf49a43SJulian Elischer if (sl_uncompress_tcp_core(mtod(m, u_char *), 5224cf49a43SJulian Elischer m->m_len, m->m_pkthdr.len, TYPE_UNCOMPRESSED_TCP, 5234cf49a43SJulian Elischer &priv->slc, &hdr, &hlen) < 0) { 524069154d5SJulian Elischer NG_FREE_M(m); 525069154d5SJulian Elischer NG_FREE_ITEM(item); 526309c48c6SArchie Cobbs return (EINVAL); 5274cf49a43SJulian Elischer } 5284cf49a43SJulian Elischer hook = priv->ip; 5294cf49a43SJulian Elischer } else if (hook == priv->vjip) /* incoming regular packet (bypass) */ 5304cf49a43SJulian Elischer hook = priv->ip; 5314cf49a43SJulian Elischer else 5326e551fb6SDavid E. O'Brien panic("%s: unknown hook", __func__); 5334cf49a43SJulian Elischer 534309c48c6SArchie Cobbs /* Send result back out */ 535069154d5SJulian Elischer NG_FWD_NEW_DATA(error, item, hook, m); 5364cf49a43SJulian Elischer return (error); 5374cf49a43SJulian Elischer } 5384cf49a43SJulian Elischer 5394cf49a43SJulian Elischer /* 5404cf49a43SJulian Elischer * Shutdown node 5414cf49a43SJulian Elischer */ 5424cf49a43SJulian Elischer static int 543069154d5SJulian Elischer ng_vjc_shutdown(node_p node) 5444cf49a43SJulian Elischer { 54530400f03SJulian Elischer const priv_p priv = NG_NODE_PRIVATE(node); 5464cf49a43SJulian Elischer 5474cf49a43SJulian Elischer bzero(priv, sizeof(*priv)); 5484cf49a43SJulian Elischer FREE(priv, M_NETGRAPH); 54930400f03SJulian Elischer NG_NODE_SET_PRIVATE(node, NULL); 55030400f03SJulian Elischer NG_NODE_UNREF(node); 5514cf49a43SJulian Elischer return (0); 5524cf49a43SJulian Elischer } 5534cf49a43SJulian Elischer 5544cf49a43SJulian Elischer /* 5554cf49a43SJulian Elischer * Hook disconnection 5564cf49a43SJulian Elischer */ 5574cf49a43SJulian Elischer static int 5584cf49a43SJulian Elischer ng_vjc_disconnect(hook_p hook) 5594cf49a43SJulian Elischer { 56030400f03SJulian Elischer const node_p node = NG_HOOK_NODE(hook); 56130400f03SJulian Elischer const priv_p priv = NG_NODE_PRIVATE(node); 56262838faeSArchie Cobbs 56362838faeSArchie Cobbs /* Zero out hook pointer */ 56462838faeSArchie Cobbs if (hook == priv->ip) 56562838faeSArchie Cobbs priv->ip = NULL; 56662838faeSArchie Cobbs else if (hook == priv->vjcomp) 56762838faeSArchie Cobbs priv->vjcomp = NULL; 56862838faeSArchie Cobbs else if (hook == priv->vjuncomp) 56962838faeSArchie Cobbs priv->vjuncomp = NULL; 57062838faeSArchie Cobbs else if (hook == priv->vjip) 57162838faeSArchie Cobbs priv->vjip = NULL; 57262838faeSArchie Cobbs else 5736e551fb6SDavid E. O'Brien panic("%s: unknown hook", __func__); 57462838faeSArchie Cobbs 57562838faeSArchie Cobbs /* Go away if no hooks left */ 57630400f03SJulian Elischer if ((NG_NODE_NUMHOOKS(node) == 0) 57730400f03SJulian Elischer && (NG_NODE_IS_VALID(node))) 578069154d5SJulian Elischer ng_rmnode_self(node); 5794cf49a43SJulian Elischer return (0); 5804cf49a43SJulian Elischer } 5814cf49a43SJulian Elischer 5824cf49a43SJulian Elischer /************************************************************************ 5834cf49a43SJulian Elischer HELPER STUFF 5844cf49a43SJulian Elischer ************************************************************************/ 5854cf49a43SJulian Elischer 5864cf49a43SJulian Elischer /* 587bef9dae0SJulian Elischer * Pull up the full IP and TCP headers of a packet. If packet is not 5884cf49a43SJulian Elischer * a TCP packet, just pull up the IP header. 5894cf49a43SJulian Elischer */ 5904cf49a43SJulian Elischer static struct mbuf * 591309c48c6SArchie Cobbs ng_vjc_pulluphdrs(struct mbuf *m, int knownTCP) 5924cf49a43SJulian Elischer { 5934cf49a43SJulian Elischer struct ip *ip; 5944cf49a43SJulian Elischer struct tcphdr *tcp; 5954cf49a43SJulian Elischer int ihlen, thlen; 5964cf49a43SJulian Elischer 5973f47e1e3SArchie Cobbs if (m->m_len < sizeof(*ip) && (m = m_pullup(m, sizeof(*ip))) == NULL) 5984cf49a43SJulian Elischer return (NULL); 5994cf49a43SJulian Elischer ip = mtod(m, struct ip *); 600309c48c6SArchie Cobbs if (!knownTCP && ip->ip_p != IPPROTO_TCP) 6014cf49a43SJulian Elischer return (m); 602bef9dae0SJulian Elischer ihlen = ip->ip_hl << 2; 603bef9dae0SJulian Elischer if (m->m_len < ihlen + sizeof(*tcp)) { 6043f47e1e3SArchie Cobbs if ((m = m_pullup(m, ihlen + sizeof(*tcp))) == NULL) 6054cf49a43SJulian Elischer return (NULL); 6064cf49a43SJulian Elischer ip = mtod(m, struct ip *); 6074cf49a43SJulian Elischer } 6084cf49a43SJulian Elischer tcp = (struct tcphdr *)((u_char *)ip + ihlen); 609bef9dae0SJulian Elischer thlen = tcp->th_off << 2; 610bef9dae0SJulian Elischer if (m->m_len < ihlen + thlen) 6114cf49a43SJulian Elischer m = m_pullup(m, ihlen + thlen); 6124cf49a43SJulian Elischer return (m); 6134cf49a43SJulian Elischer } 6144cf49a43SJulian Elischer 615