14cf49a43SJulian Elischer 24cf49a43SJulian Elischer /* 34cf49a43SJulian Elischer * ng_vjc.c 4c398230bSWarner Losh */ 5c398230bSWarner Losh 6c398230bSWarner Losh /*- 74cf49a43SJulian Elischer * Copyright (c) 1996-1999 Whistle Communications, Inc. 84cf49a43SJulian Elischer * All rights reserved. 94cf49a43SJulian Elischer * 104cf49a43SJulian Elischer * Subject to the following obligations and disclaimer of warranty, use and 114cf49a43SJulian Elischer * redistribution of this software, in source or object code forms, with or 124cf49a43SJulian Elischer * without modifications are expressly permitted by Whistle Communications; 134cf49a43SJulian Elischer * provided, however, that: 144cf49a43SJulian Elischer * 1. Any and all reproductions of the source or object code must include the 154cf49a43SJulian Elischer * copyright notice above and the following disclaimer of warranties; and 164cf49a43SJulian Elischer * 2. No rights are granted, in any manner or form, to use Whistle 174cf49a43SJulian Elischer * Communications, Inc. trademarks, including the mark "WHISTLE 184cf49a43SJulian Elischer * COMMUNICATIONS" on advertising, endorsements, or otherwise except as 194cf49a43SJulian Elischer * such appears in the above copyright notice or in the software. 204cf49a43SJulian Elischer * 214cf49a43SJulian Elischer * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND 224cf49a43SJulian Elischer * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO 234cf49a43SJulian Elischer * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, 244cf49a43SJulian Elischer * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF 254cf49a43SJulian Elischer * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. 264cf49a43SJulian Elischer * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY 274cf49a43SJulian Elischer * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS 284cf49a43SJulian Elischer * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. 294cf49a43SJulian Elischer * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES 304cf49a43SJulian Elischer * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING 314cf49a43SJulian Elischer * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 324cf49a43SJulian Elischer * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR 334cf49a43SJulian Elischer * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY 344cf49a43SJulian Elischer * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 354cf49a43SJulian Elischer * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 364cf49a43SJulian Elischer * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY 374cf49a43SJulian Elischer * OF SUCH DAMAGE. 384cf49a43SJulian Elischer * 39cc3bbd68SJulian Elischer * Author: Archie Cobbs <archie@freebsd.org> 404cf49a43SJulian Elischer * 414cf49a43SJulian Elischer * $FreeBSD$ 4274f5c6aaSJulian Elischer * $Whistle: ng_vjc.c,v 1.17 1999/11/01 09:24:52 julian Exp $ 434cf49a43SJulian Elischer */ 444cf49a43SJulian Elischer 454cf49a43SJulian Elischer /* 469dcab530SArchie Cobbs * This node performs Van Jacobson IP header (de)compression. 474cf49a43SJulian Elischer * You must have included net/slcompress.c in your kernel compilation. 484cf49a43SJulian Elischer */ 494cf49a43SJulian Elischer 504cf49a43SJulian Elischer #include <sys/param.h> 514cf49a43SJulian Elischer #include <sys/systm.h> 524cf49a43SJulian Elischer #include <sys/errno.h> 534cf49a43SJulian Elischer #include <sys/kernel.h> 544cf49a43SJulian Elischer #include <sys/mbuf.h> 554cf49a43SJulian Elischer #include <sys/malloc.h> 564cf49a43SJulian Elischer #include <sys/errno.h> 574cf49a43SJulian Elischer 584cf49a43SJulian Elischer #include <netgraph/ng_message.h> 594cf49a43SJulian Elischer #include <netgraph/netgraph.h> 60656485a2SArchie Cobbs #include <netgraph/ng_parse.h> 614cf49a43SJulian Elischer #include <netgraph/ng_vjc.h> 624cf49a43SJulian Elischer 634cf49a43SJulian Elischer #include <netinet/in.h> 644cf49a43SJulian Elischer #include <netinet/in_systm.h> 654cf49a43SJulian Elischer #include <netinet/ip.h> 664cf49a43SJulian Elischer #include <netinet/tcp.h> 674cf49a43SJulian Elischer 684cf49a43SJulian Elischer #include <net/slcompress.h> 694cf49a43SJulian Elischer 704cf49a43SJulian Elischer /* Check agreement with slcompress.c */ 714cf49a43SJulian Elischer #if MAX_STATES != NG_VJC_MAX_CHANNELS 724cf49a43SJulian Elischer #error NG_VJC_MAX_CHANNELS must be the same as MAX_STATES 734cf49a43SJulian Elischer #endif 744cf49a43SJulian Elischer 75309c48c6SArchie Cobbs /* Maximum length of a compressed TCP VJ header */ 76309c48c6SArchie Cobbs #define MAX_VJHEADER 19 774cf49a43SJulian Elischer 784cf49a43SJulian Elischer /* Node private data */ 7962838faeSArchie Cobbs struct ng_vjc_private { 804cf49a43SJulian Elischer struct ngm_vjc_config conf; 814cf49a43SJulian Elischer struct slcompress slc; 824cf49a43SJulian Elischer hook_p ip; 834cf49a43SJulian Elischer hook_p vjcomp; 844cf49a43SJulian Elischer hook_p vjuncomp; 854cf49a43SJulian Elischer hook_p vjip; 864cf49a43SJulian Elischer }; 8762838faeSArchie Cobbs typedef struct ng_vjc_private *priv_p; 884cf49a43SJulian Elischer 894cf49a43SJulian Elischer #define ERROUT(x) do { error = (x); goto done; } while (0) 904cf49a43SJulian Elischer 914cf49a43SJulian Elischer /* Netgraph node methods */ 9274f5c6aaSJulian Elischer static ng_constructor_t ng_vjc_constructor; 9374f5c6aaSJulian Elischer static ng_rcvmsg_t ng_vjc_rcvmsg; 94069154d5SJulian Elischer static ng_shutdown_t ng_vjc_shutdown; 9574f5c6aaSJulian Elischer static ng_newhook_t ng_vjc_newhook; 9674f5c6aaSJulian Elischer static ng_rcvdata_t ng_vjc_rcvdata; 9774f5c6aaSJulian Elischer static ng_disconnect_t ng_vjc_disconnect; 984cf49a43SJulian Elischer 994cf49a43SJulian Elischer /* Helper stuff */ 100309c48c6SArchie Cobbs static struct mbuf *ng_vjc_pulluphdrs(struct mbuf *m, int knownTCP); 1014cf49a43SJulian Elischer 102656485a2SArchie Cobbs /* Parse type for struct ngm_vjc_config */ 103f0184ff8SArchie Cobbs static const struct ng_parse_struct_field ng_vjc_config_type_fields[] 104656485a2SArchie Cobbs = NG_VJC_CONFIG_TYPE_INFO; 105656485a2SArchie Cobbs static const struct ng_parse_type ng_vjc_config_type = { 106656485a2SArchie Cobbs &ng_parse_struct_type, 107f0184ff8SArchie Cobbs &ng_vjc_config_type_fields 108656485a2SArchie Cobbs }; 109656485a2SArchie Cobbs 110656485a2SArchie Cobbs /* Parse type for the 'last_cs' and 'cs_next' fields in struct slcompress, 111656485a2SArchie Cobbs which are pointers converted to integer indices, so parse them that way. */ 112c7e7950dSRuslan Ermilov #ifndef __LP64__ 113656485a2SArchie Cobbs #define NG_VJC_TSTATE_PTR_TYPE &ng_parse_uint32_type 114656485a2SArchie Cobbs #else 115c7e7950dSRuslan Ermilov #define NG_VJC_TSTATE_PTR_TYPE &ng_parse_uint64_type 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 */ 246674d86bfSGleb Smirnoff priv = malloc(sizeof(*priv), M_NETGRAPH, M_WAITOK | M_ZERO); 2474cf49a43SJulian Elischer 24830400f03SJulian Elischer NG_NODE_SET_PRIVATE(node, priv); 2494cf49a43SJulian Elischer 250b0987442SAlexander Motin /* slcompress is not thread-safe. Protect it's state here. */ 251b0987442SAlexander Motin NG_NODE_FORCE_WRITER(node); 252b0987442SAlexander Motin 2534cf49a43SJulian Elischer /* Done */ 2544cf49a43SJulian Elischer return (0); 2554cf49a43SJulian Elischer } 2564cf49a43SJulian Elischer 2574cf49a43SJulian Elischer /* 2584cf49a43SJulian Elischer * Add a new hook 2594cf49a43SJulian Elischer */ 2604cf49a43SJulian Elischer static int 2614cf49a43SJulian Elischer ng_vjc_newhook(node_p node, hook_p hook, const char *name) 2624cf49a43SJulian Elischer { 26330400f03SJulian Elischer const priv_p priv = NG_NODE_PRIVATE(node); 2644cf49a43SJulian Elischer hook_p *hookp; 2654cf49a43SJulian Elischer 2664cf49a43SJulian Elischer /* Get hook */ 2673f47e1e3SArchie Cobbs if (strcmp(name, NG_VJC_HOOK_IP) == 0) 2684cf49a43SJulian Elischer hookp = &priv->ip; 2693f47e1e3SArchie Cobbs else if (strcmp(name, NG_VJC_HOOK_VJCOMP) == 0) 2704cf49a43SJulian Elischer hookp = &priv->vjcomp; 2713f47e1e3SArchie Cobbs else if (strcmp(name, NG_VJC_HOOK_VJUNCOMP) == 0) 2724cf49a43SJulian Elischer hookp = &priv->vjuncomp; 2733f47e1e3SArchie Cobbs else if (strcmp(name, NG_VJC_HOOK_VJIP) == 0) 2744cf49a43SJulian Elischer hookp = &priv->vjip; 2754cf49a43SJulian Elischer else 2764cf49a43SJulian Elischer return (EINVAL); 2774cf49a43SJulian Elischer 2784cf49a43SJulian Elischer /* See if already connected */ 2794cf49a43SJulian Elischer if (*hookp) 2804cf49a43SJulian Elischer return (EISCONN); 2814cf49a43SJulian Elischer 2824cf49a43SJulian Elischer /* OK */ 2834cf49a43SJulian Elischer *hookp = hook; 2844cf49a43SJulian Elischer return (0); 2854cf49a43SJulian Elischer } 2864cf49a43SJulian Elischer 2874cf49a43SJulian Elischer /* 2884cf49a43SJulian Elischer * Receive a control message 2894cf49a43SJulian Elischer */ 2904cf49a43SJulian Elischer static int 291069154d5SJulian Elischer ng_vjc_rcvmsg(node_p node, item_p item, hook_p lasthook) 2924cf49a43SJulian Elischer { 29330400f03SJulian Elischer const priv_p priv = NG_NODE_PRIVATE(node); 2944cf49a43SJulian Elischer struct ng_mesg *resp = NULL; 2954cf49a43SJulian Elischer int error = 0; 296069154d5SJulian Elischer struct ng_mesg *msg; 2974cf49a43SJulian Elischer 298069154d5SJulian Elischer NGI_GET_MSG(item, msg); 2994cf49a43SJulian Elischer /* Check type cookie */ 3004cf49a43SJulian Elischer switch (msg->header.typecookie) { 3014cf49a43SJulian Elischer case NGM_VJC_COOKIE: 3024cf49a43SJulian Elischer switch (msg->header.cmd) { 303bef9dae0SJulian Elischer case NGM_VJC_SET_CONFIG: 3044cf49a43SJulian Elischer { 3054cf49a43SJulian Elischer struct ngm_vjc_config *const c = 3064cf49a43SJulian Elischer (struct ngm_vjc_config *) msg->data; 3074cf49a43SJulian Elischer 308bef9dae0SJulian Elischer if (msg->header.arglen != sizeof(*c)) 309bef9dae0SJulian Elischer ERROUT(EINVAL); 310bef9dae0SJulian Elischer if ((priv->conf.enableComp || priv->conf.enableDecomp) 311bef9dae0SJulian Elischer && (c->enableComp || c->enableDecomp)) 312bef9dae0SJulian Elischer ERROUT(EALREADY); 313bef9dae0SJulian Elischer if (c->enableComp) { 3143f47e1e3SArchie Cobbs if (c->maxChannel > NG_VJC_MAX_CHANNELS - 1 3153f47e1e3SArchie Cobbs || c->maxChannel < NG_VJC_MIN_CHANNELS - 1) 3164cf49a43SJulian Elischer ERROUT(EINVAL); 317309c48c6SArchie Cobbs } else 318309c48c6SArchie Cobbs c->maxChannel = NG_VJC_MAX_CHANNELS - 1; 319bef9dae0SJulian Elischer if (c->enableComp != 0 || c->enableDecomp != 0) { 3204cf49a43SJulian Elischer bzero(&priv->slc, sizeof(priv->slc)); 3213f47e1e3SArchie Cobbs sl_compress_init(&priv->slc, c->maxChannel); 3224cf49a43SJulian Elischer } 3234cf49a43SJulian Elischer priv->conf = *c; 3244cf49a43SJulian Elischer break; 3254cf49a43SJulian Elischer } 326656485a2SArchie Cobbs case NGM_VJC_GET_CONFIG: 327656485a2SArchie Cobbs { 328656485a2SArchie Cobbs struct ngm_vjc_config *conf; 329656485a2SArchie Cobbs 330656485a2SArchie Cobbs NG_MKRESPONSE(resp, msg, sizeof(*conf), M_NOWAIT); 3314cf49a43SJulian Elischer if (resp == NULL) 3324cf49a43SJulian Elischer ERROUT(ENOMEM); 333656485a2SArchie Cobbs conf = (struct ngm_vjc_config *)resp->data; 334656485a2SArchie Cobbs *conf = priv->conf; 3354cf49a43SJulian Elischer break; 336656485a2SArchie Cobbs } 337656485a2SArchie Cobbs case NGM_VJC_GET_STATE: 338656485a2SArchie Cobbs { 339656485a2SArchie Cobbs const struct slcompress *const sl0 = &priv->slc; 340656485a2SArchie Cobbs struct slcompress *sl; 341656485a2SArchie Cobbs u_int16_t index; 342656485a2SArchie Cobbs int i; 343656485a2SArchie Cobbs 344656485a2SArchie Cobbs /* Get response structure */ 345656485a2SArchie Cobbs NG_MKRESPONSE(resp, msg, sizeof(*sl), M_NOWAIT); 346656485a2SArchie Cobbs if (resp == NULL) 347656485a2SArchie Cobbs ERROUT(ENOMEM); 348656485a2SArchie Cobbs sl = (struct slcompress *)resp->data; 349656485a2SArchie Cobbs *sl = *sl0; 350656485a2SArchie Cobbs 351*053359b7SPedro F. Giffuni /* Replace pointers with integer indices */ 352656485a2SArchie Cobbs if (sl->last_cs != NULL) { 353656485a2SArchie Cobbs index = sl0->last_cs - sl0->tstate; 354656485a2SArchie Cobbs bzero(&sl->last_cs, sizeof(sl->last_cs)); 355656485a2SArchie Cobbs *((u_int16_t *)&sl->last_cs) = index; 356656485a2SArchie Cobbs } 357656485a2SArchie Cobbs for (i = 0; i < MAX_STATES; i++) { 358656485a2SArchie Cobbs struct cstate *const cs = &sl->tstate[i]; 359656485a2SArchie Cobbs 360656485a2SArchie Cobbs index = sl0->tstate[i].cs_next - sl0->tstate; 361656485a2SArchie Cobbs bzero(&cs->cs_next, sizeof(cs->cs_next)); 362656485a2SArchie Cobbs *((u_int16_t *)&cs->cs_next) = index; 363656485a2SArchie Cobbs } 364656485a2SArchie Cobbs break; 365656485a2SArchie Cobbs } 3664cf49a43SJulian Elischer case NGM_VJC_CLR_STATS: 3674cf49a43SJulian Elischer priv->slc.sls_packets = 0; 3684cf49a43SJulian Elischer priv->slc.sls_compressed = 0; 3694cf49a43SJulian Elischer priv->slc.sls_searches = 0; 3704cf49a43SJulian Elischer priv->slc.sls_misses = 0; 3714cf49a43SJulian Elischer priv->slc.sls_uncompressedin = 0; 3724cf49a43SJulian Elischer priv->slc.sls_compressedin = 0; 3734cf49a43SJulian Elischer priv->slc.sls_errorin = 0; 3744cf49a43SJulian Elischer priv->slc.sls_tossed = 0; 3754cf49a43SJulian Elischer break; 3764cf49a43SJulian Elischer case NGM_VJC_RECV_ERROR: 3773f47e1e3SArchie Cobbs sl_uncompress_tcp(NULL, 0, TYPE_ERROR, &priv->slc); 3784cf49a43SJulian Elischer break; 3794cf49a43SJulian Elischer default: 3804cf49a43SJulian Elischer error = EINVAL; 3814cf49a43SJulian Elischer break; 3824cf49a43SJulian Elischer } 3834cf49a43SJulian Elischer break; 3844cf49a43SJulian Elischer default: 3854cf49a43SJulian Elischer error = EINVAL; 3864cf49a43SJulian Elischer break; 3874cf49a43SJulian Elischer } 3884cf49a43SJulian Elischer done: 389069154d5SJulian Elischer NG_RESPOND_MSG(error, node, item, resp); 390069154d5SJulian Elischer NG_FREE_MSG(msg); 3914cf49a43SJulian Elischer return (error); 3924cf49a43SJulian Elischer } 3934cf49a43SJulian Elischer 3944cf49a43SJulian Elischer /* 3954cf49a43SJulian Elischer * Receive data 3964cf49a43SJulian Elischer */ 3974cf49a43SJulian Elischer static int 398069154d5SJulian Elischer ng_vjc_rcvdata(hook_p hook, item_p item) 3994cf49a43SJulian Elischer { 40030400f03SJulian Elischer const node_p node = NG_HOOK_NODE(hook); 40130400f03SJulian Elischer const priv_p priv = NG_NODE_PRIVATE(node); 4024cf49a43SJulian Elischer int error = 0; 403069154d5SJulian Elischer struct mbuf *m; 4044cf49a43SJulian Elischer 405069154d5SJulian Elischer NGI_GET_M(item, m); 4064cf49a43SJulian Elischer if (hook == priv->ip) { /* outgoing packet */ 407309c48c6SArchie Cobbs u_int type = TYPE_IP; 4084cf49a43SJulian Elischer 409309c48c6SArchie Cobbs /* Compress packet if enabled and proto is TCP */ 410309c48c6SArchie Cobbs if (priv->conf.enableComp) { 4114cf49a43SJulian Elischer struct ip *ip; 4124cf49a43SJulian Elischer 413309c48c6SArchie Cobbs if ((m = ng_vjc_pulluphdrs(m, 0)) == NULL) { 414069154d5SJulian Elischer NG_FREE_ITEM(item); 415309c48c6SArchie Cobbs return (ENOBUFS); 4164cf49a43SJulian Elischer } 417309c48c6SArchie Cobbs ip = mtod(m, struct ip *); 418309c48c6SArchie Cobbs if (ip->ip_p == IPPROTO_TCP) { 419309c48c6SArchie Cobbs const int origLen = m->m_len; 420309c48c6SArchie Cobbs 421309c48c6SArchie Cobbs type = sl_compress_tcp(m, ip, 422309c48c6SArchie Cobbs &priv->slc, priv->conf.compressCID); 423309c48c6SArchie Cobbs m->m_pkthdr.len += m->m_len - origLen; 424309c48c6SArchie Cobbs } 425309c48c6SArchie Cobbs } 426309c48c6SArchie Cobbs 427309c48c6SArchie Cobbs /* Dispatch to the appropriate outgoing hook */ 4284cf49a43SJulian Elischer switch (type) { 4294cf49a43SJulian Elischer case TYPE_IP: 4304cf49a43SJulian Elischer hook = priv->vjip; 4314cf49a43SJulian Elischer break; 4324cf49a43SJulian Elischer case TYPE_UNCOMPRESSED_TCP: 4334cf49a43SJulian Elischer hook = priv->vjuncomp; 4344cf49a43SJulian Elischer break; 4354cf49a43SJulian Elischer case TYPE_COMPRESSED_TCP: 4364cf49a43SJulian Elischer hook = priv->vjcomp; 4374cf49a43SJulian Elischer break; 4384cf49a43SJulian Elischer default: 4396e551fb6SDavid E. O'Brien panic("%s: type=%d", __func__, type); 4404cf49a43SJulian Elischer } 4414cf49a43SJulian Elischer } else if (hook == priv->vjcomp) { /* incoming compressed packet */ 442309c48c6SArchie Cobbs int vjlen, need2pullup; 443309c48c6SArchie Cobbs struct mbuf *hm; 4444cf49a43SJulian Elischer u_char *hdr; 445309c48c6SArchie Cobbs u_int hlen; 4464cf49a43SJulian Elischer 447bef9dae0SJulian Elischer /* Are we decompressing? */ 448bef9dae0SJulian Elischer if (!priv->conf.enableDecomp) { 449069154d5SJulian Elischer NG_FREE_M(m); 450069154d5SJulian Elischer NG_FREE_ITEM(item); 451309c48c6SArchie Cobbs return (ENXIO); 452309c48c6SArchie Cobbs } 453309c48c6SArchie Cobbs 454309c48c6SArchie Cobbs /* Pull up the necessary amount from the mbuf */ 455309c48c6SArchie Cobbs need2pullup = MAX_VJHEADER; 456309c48c6SArchie Cobbs if (need2pullup > m->m_pkthdr.len) 457309c48c6SArchie Cobbs need2pullup = m->m_pkthdr.len; 458309c48c6SArchie Cobbs if (m->m_len < need2pullup 459309c48c6SArchie Cobbs && (m = m_pullup(m, need2pullup)) == NULL) { 460309c48c6SArchie Cobbs priv->slc.sls_errorin++; 461069154d5SJulian Elischer NG_FREE_ITEM(item); 462309c48c6SArchie Cobbs return (ENOBUFS); 4634cf49a43SJulian Elischer } 4644cf49a43SJulian Elischer 4654cf49a43SJulian Elischer /* Uncompress packet to reconstruct TCP/IP header */ 4664cf49a43SJulian Elischer vjlen = sl_uncompress_tcp_core(mtod(m, u_char *), 4674cf49a43SJulian Elischer m->m_len, m->m_pkthdr.len, TYPE_COMPRESSED_TCP, 4684cf49a43SJulian Elischer &priv->slc, &hdr, &hlen); 4694cf49a43SJulian Elischer if (vjlen <= 0) { 470069154d5SJulian Elischer NG_FREE_M(m); 471069154d5SJulian Elischer NG_FREE_ITEM(item); 472309c48c6SArchie Cobbs return (EINVAL); 4734cf49a43SJulian Elischer } 4743f47e1e3SArchie Cobbs m_adj(m, vjlen); 4754cf49a43SJulian Elischer 4764cf49a43SJulian Elischer /* Copy the reconstructed TCP/IP headers into a new mbuf */ 477eb1b1807SGleb Smirnoff MGETHDR(hm, M_NOWAIT, MT_DATA); 478309c48c6SArchie Cobbs if (hm == NULL) { 479309c48c6SArchie Cobbs priv->slc.sls_errorin++; 480069154d5SJulian Elischer NG_FREE_M(m); 481069154d5SJulian Elischer NG_FREE_ITEM(item); 482309c48c6SArchie Cobbs return (ENOBUFS); 483309c48c6SArchie Cobbs } 484309c48c6SArchie Cobbs hm->m_len = 0; 4854e256e6eSArchie Cobbs hm->m_pkthdr.rcvif = NULL; 486309c48c6SArchie Cobbs if (hlen > MHLEN) { /* unlikely, but can happen */ 4872a8c860fSRobert Watson if (!(MCLGET(hm, M_NOWAIT))) { 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)); 5481ede983cSDag-Erling Smørgrav 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