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 */ 101656485a2SArchie Cobbs static const struct ng_parse_struct_info ng_vjc_config_type_info 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, 105656485a2SArchie Cobbs &ng_vjc_config_type_info 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 */ 130656485a2SArchie Cobbs static const struct ng_parse_struct_info ng_vjc_cstate_type_info = { 131656485a2SArchie Cobbs { 132656485a2SArchie Cobbs { "cs_next", NG_VJC_TSTATE_PTR_TYPE }, 133656485a2SArchie Cobbs { "cs_hlen", &ng_parse_uint16_type }, 134656485a2SArchie Cobbs { "cs_id", &ng_parse_uint8_type }, 135656485a2SArchie Cobbs { "cs_filler", &ng_parse_uint8_type }, 136656485a2SArchie Cobbs { "cs_hdr", &ng_vjc_cs_hdr_type }, 137656485a2SArchie Cobbs { NULL }, 138656485a2SArchie Cobbs } 139656485a2SArchie Cobbs }; 140656485a2SArchie Cobbs static const struct ng_parse_type ng_vjc_cstate_type = { 141656485a2SArchie Cobbs &ng_parse_struct_type, 142656485a2SArchie Cobbs &ng_vjc_cstate_type_info 143656485a2SArchie Cobbs }; 144656485a2SArchie Cobbs 145656485a2SArchie Cobbs /* Parse type for an array of MAX_STATES struct cstate's, ie, tstate & rstate */ 146656485a2SArchie Cobbs static const struct ng_parse_fixedarray_info ng_vjc_cstatearray_type_info = { 147656485a2SArchie Cobbs &ng_vjc_cstate_type, 148656485a2SArchie Cobbs MAX_STATES 149656485a2SArchie Cobbs }; 150656485a2SArchie Cobbs static const struct ng_parse_type ng_vjc_cstatearray_type = { 151656485a2SArchie Cobbs &ng_parse_fixedarray_type, 152656485a2SArchie Cobbs &ng_vjc_cstatearray_type_info 153656485a2SArchie Cobbs }; 154656485a2SArchie Cobbs 155656485a2SArchie Cobbs /* Parse type for struct slcompress. Keep this in sync with the 156656485a2SArchie Cobbs definition of struct slcompress defined in <net/slcompress.h> */ 157656485a2SArchie Cobbs static const struct ng_parse_struct_info ng_vjc_slcompress_type_info = { 158656485a2SArchie Cobbs { 159656485a2SArchie Cobbs { "last_cs", NG_VJC_TSTATE_PTR_TYPE }, 160656485a2SArchie Cobbs { "last_recv", &ng_parse_uint8_type }, 161656485a2SArchie Cobbs { "last_xmit", &ng_parse_uint8_type }, 162656485a2SArchie Cobbs { "flags", &ng_parse_hint16_type }, 163656485a2SArchie Cobbs #ifndef SL_NO_STATS 164656485a2SArchie Cobbs { "sls_packets", &ng_parse_uint32_type }, 165656485a2SArchie Cobbs { "sls_compressed", &ng_parse_uint32_type }, 166656485a2SArchie Cobbs { "sls_searches", &ng_parse_uint32_type }, 167656485a2SArchie Cobbs { "sls_misses", &ng_parse_uint32_type }, 168656485a2SArchie Cobbs { "sls_uncompressedin", &ng_parse_uint32_type }, 169656485a2SArchie Cobbs { "sls_compressedin", &ng_parse_uint32_type }, 170656485a2SArchie Cobbs { "sls_errorin", &ng_parse_uint32_type }, 171656485a2SArchie Cobbs { "sls_tossed", &ng_parse_uint32_type }, 172656485a2SArchie Cobbs #endif 173656485a2SArchie Cobbs { "tstate", &ng_vjc_cstatearray_type }, 174656485a2SArchie Cobbs { "rstate", &ng_vjc_cstatearray_type }, 175656485a2SArchie Cobbs { NULL }, 176656485a2SArchie Cobbs } 177656485a2SArchie Cobbs }; 178656485a2SArchie Cobbs static const struct ng_parse_type ng_vjc_slcompress_type = { 179656485a2SArchie Cobbs &ng_parse_struct_type, 180656485a2SArchie Cobbs &ng_vjc_slcompress_type_info 181656485a2SArchie Cobbs }; 182656485a2SArchie Cobbs 183656485a2SArchie Cobbs /* List of commands and how to convert arguments to/from ASCII */ 184656485a2SArchie Cobbs static const struct ng_cmdlist ng_vjc_cmds[] = { 185656485a2SArchie Cobbs { 186656485a2SArchie Cobbs NGM_VJC_COOKIE, 187656485a2SArchie Cobbs NGM_VJC_SET_CONFIG, 188656485a2SArchie Cobbs "setconfig", 189656485a2SArchie Cobbs &ng_vjc_config_type, 190656485a2SArchie Cobbs NULL 191656485a2SArchie Cobbs }, 192656485a2SArchie Cobbs { 193656485a2SArchie Cobbs NGM_VJC_COOKIE, 194656485a2SArchie Cobbs NGM_VJC_GET_CONFIG, 195656485a2SArchie Cobbs "getconfig", 196656485a2SArchie Cobbs NULL, 197656485a2SArchie Cobbs &ng_vjc_config_type, 198656485a2SArchie Cobbs }, 199656485a2SArchie Cobbs { 200656485a2SArchie Cobbs NGM_VJC_COOKIE, 201656485a2SArchie Cobbs NGM_VJC_GET_STATE, 202656485a2SArchie Cobbs "getstate", 203656485a2SArchie Cobbs NULL, 204656485a2SArchie Cobbs &ng_vjc_slcompress_type, 205656485a2SArchie Cobbs }, 206656485a2SArchie Cobbs { 207656485a2SArchie Cobbs NGM_VJC_COOKIE, 208656485a2SArchie Cobbs NGM_VJC_CLR_STATS, 209656485a2SArchie Cobbs "clrstats", 210656485a2SArchie Cobbs NULL, 211656485a2SArchie Cobbs NULL, 212656485a2SArchie Cobbs }, 213656485a2SArchie Cobbs { 214656485a2SArchie Cobbs NGM_VJC_COOKIE, 215656485a2SArchie Cobbs NGM_VJC_RECV_ERROR, 216656485a2SArchie Cobbs "recverror", 217656485a2SArchie Cobbs NULL, 218656485a2SArchie Cobbs NULL, 219656485a2SArchie Cobbs }, 220656485a2SArchie Cobbs { 0 } 221656485a2SArchie Cobbs }; 222656485a2SArchie Cobbs 2234cf49a43SJulian Elischer /* Node type descriptor */ 224656485a2SArchie Cobbs static struct ng_type ng_vjc_typestruct = { 225589f6ed8SJulian Elischer NG_ABI_VERSION, 2264cf49a43SJulian Elischer NG_VJC_NODE_TYPE, 2274cf49a43SJulian Elischer NULL, 2284cf49a43SJulian Elischer ng_vjc_constructor, 2294cf49a43SJulian Elischer ng_vjc_rcvmsg, 230069154d5SJulian Elischer ng_vjc_shutdown, 2314cf49a43SJulian Elischer ng_vjc_newhook, 2324cf49a43SJulian Elischer NULL, 2334cf49a43SJulian Elischer NULL, 2344cf49a43SJulian Elischer ng_vjc_rcvdata, 235f8307e12SArchie Cobbs ng_vjc_disconnect, 236656485a2SArchie Cobbs ng_vjc_cmds 2374cf49a43SJulian Elischer }; 238656485a2SArchie Cobbs NETGRAPH_INIT(vjc, &ng_vjc_typestruct); 2394cf49a43SJulian Elischer 2404cf49a43SJulian Elischer /************************************************************************ 2414cf49a43SJulian Elischer NETGRAPH NODE METHODS 2424cf49a43SJulian Elischer ************************************************************************/ 2434cf49a43SJulian Elischer 2444cf49a43SJulian Elischer /* 2454cf49a43SJulian Elischer * Create a new node 2464cf49a43SJulian Elischer */ 2474cf49a43SJulian Elischer static int 248069154d5SJulian Elischer ng_vjc_constructor(node_p node) 2494cf49a43SJulian Elischer { 2504cf49a43SJulian Elischer priv_p priv; 2514cf49a43SJulian Elischer 2524cf49a43SJulian Elischer /* Allocate private structure */ 25399cdf4ccSDavid Malone MALLOC(priv, priv_p, sizeof(*priv), M_NETGRAPH, M_NOWAIT | M_ZERO); 2544cf49a43SJulian Elischer if (priv == NULL) 2554cf49a43SJulian Elischer return (ENOMEM); 2564cf49a43SJulian Elischer 257069154d5SJulian Elischer node->private = priv; 2584cf49a43SJulian Elischer 2594cf49a43SJulian Elischer /* Done */ 2604cf49a43SJulian Elischer return (0); 2614cf49a43SJulian Elischer } 2624cf49a43SJulian Elischer 2634cf49a43SJulian Elischer /* 2644cf49a43SJulian Elischer * Add a new hook 2654cf49a43SJulian Elischer */ 2664cf49a43SJulian Elischer static int 2674cf49a43SJulian Elischer ng_vjc_newhook(node_p node, hook_p hook, const char *name) 2684cf49a43SJulian Elischer { 2694cf49a43SJulian Elischer const priv_p priv = (priv_p) node->private; 2704cf49a43SJulian Elischer hook_p *hookp; 2714cf49a43SJulian Elischer 2724cf49a43SJulian Elischer /* Get hook */ 2733f47e1e3SArchie Cobbs if (strcmp(name, NG_VJC_HOOK_IP) == 0) 2744cf49a43SJulian Elischer hookp = &priv->ip; 2753f47e1e3SArchie Cobbs else if (strcmp(name, NG_VJC_HOOK_VJCOMP) == 0) 2764cf49a43SJulian Elischer hookp = &priv->vjcomp; 2773f47e1e3SArchie Cobbs else if (strcmp(name, NG_VJC_HOOK_VJUNCOMP) == 0) 2784cf49a43SJulian Elischer hookp = &priv->vjuncomp; 2793f47e1e3SArchie Cobbs else if (strcmp(name, NG_VJC_HOOK_VJIP) == 0) 2804cf49a43SJulian Elischer hookp = &priv->vjip; 2814cf49a43SJulian Elischer else 2824cf49a43SJulian Elischer return (EINVAL); 2834cf49a43SJulian Elischer 2844cf49a43SJulian Elischer /* See if already connected */ 2854cf49a43SJulian Elischer if (*hookp) 2864cf49a43SJulian Elischer return (EISCONN); 2874cf49a43SJulian Elischer 2884cf49a43SJulian Elischer /* OK */ 2894cf49a43SJulian Elischer *hookp = hook; 2904cf49a43SJulian Elischer return (0); 2914cf49a43SJulian Elischer } 2924cf49a43SJulian Elischer 2934cf49a43SJulian Elischer /* 2944cf49a43SJulian Elischer * Receive a control message 2954cf49a43SJulian Elischer */ 2964cf49a43SJulian Elischer static int 297069154d5SJulian Elischer ng_vjc_rcvmsg(node_p node, item_p item, hook_p lasthook) 2984cf49a43SJulian Elischer { 2994cf49a43SJulian Elischer const priv_p priv = (priv_p) node->private; 3004cf49a43SJulian Elischer struct ng_mesg *resp = NULL; 3014cf49a43SJulian Elischer int error = 0; 302069154d5SJulian Elischer struct ng_mesg *msg; 3034cf49a43SJulian Elischer 304069154d5SJulian Elischer NGI_GET_MSG(item, msg); 3054cf49a43SJulian Elischer /* Check type cookie */ 3064cf49a43SJulian Elischer switch (msg->header.typecookie) { 3074cf49a43SJulian Elischer case NGM_VJC_COOKIE: 3084cf49a43SJulian Elischer switch (msg->header.cmd) { 309bef9dae0SJulian Elischer case NGM_VJC_SET_CONFIG: 3104cf49a43SJulian Elischer { 3114cf49a43SJulian Elischer struct ngm_vjc_config *const c = 3124cf49a43SJulian Elischer (struct ngm_vjc_config *) msg->data; 3134cf49a43SJulian Elischer 314bef9dae0SJulian Elischer if (msg->header.arglen != sizeof(*c)) 315bef9dae0SJulian Elischer ERROUT(EINVAL); 316bef9dae0SJulian Elischer if ((priv->conf.enableComp || priv->conf.enableDecomp) 317bef9dae0SJulian Elischer && (c->enableComp || c->enableDecomp)) 318bef9dae0SJulian Elischer ERROUT(EALREADY); 319bef9dae0SJulian Elischer if (c->enableComp) { 3203f47e1e3SArchie Cobbs if (c->maxChannel > NG_VJC_MAX_CHANNELS - 1 3213f47e1e3SArchie Cobbs || c->maxChannel < NG_VJC_MIN_CHANNELS - 1) 3224cf49a43SJulian Elischer ERROUT(EINVAL); 323309c48c6SArchie Cobbs } else 324309c48c6SArchie Cobbs c->maxChannel = NG_VJC_MAX_CHANNELS - 1; 325bef9dae0SJulian Elischer if (c->enableComp != 0 || c->enableDecomp != 0) { 3264cf49a43SJulian Elischer bzero(&priv->slc, sizeof(priv->slc)); 3273f47e1e3SArchie Cobbs sl_compress_init(&priv->slc, c->maxChannel); 3284cf49a43SJulian Elischer } 3294cf49a43SJulian Elischer priv->conf = *c; 3304cf49a43SJulian Elischer break; 3314cf49a43SJulian Elischer } 332656485a2SArchie Cobbs case NGM_VJC_GET_CONFIG: 333656485a2SArchie Cobbs { 334656485a2SArchie Cobbs struct ngm_vjc_config *conf; 335656485a2SArchie Cobbs 336656485a2SArchie Cobbs NG_MKRESPONSE(resp, msg, sizeof(*conf), M_NOWAIT); 3374cf49a43SJulian Elischer if (resp == NULL) 3384cf49a43SJulian Elischer ERROUT(ENOMEM); 339656485a2SArchie Cobbs conf = (struct ngm_vjc_config *)resp->data; 340656485a2SArchie Cobbs *conf = priv->conf; 3414cf49a43SJulian Elischer break; 342656485a2SArchie Cobbs } 343656485a2SArchie Cobbs case NGM_VJC_GET_STATE: 344656485a2SArchie Cobbs { 345656485a2SArchie Cobbs const struct slcompress *const sl0 = &priv->slc; 346656485a2SArchie Cobbs struct slcompress *sl; 347656485a2SArchie Cobbs u_int16_t index; 348656485a2SArchie Cobbs int i; 349656485a2SArchie Cobbs 350656485a2SArchie Cobbs /* Get response structure */ 351656485a2SArchie Cobbs NG_MKRESPONSE(resp, msg, sizeof(*sl), M_NOWAIT); 352656485a2SArchie Cobbs if (resp == NULL) 353656485a2SArchie Cobbs ERROUT(ENOMEM); 354656485a2SArchie Cobbs sl = (struct slcompress *)resp->data; 355656485a2SArchie Cobbs *sl = *sl0; 356656485a2SArchie Cobbs 357656485a2SArchie Cobbs /* Replace pointers with integer indicies */ 358656485a2SArchie Cobbs if (sl->last_cs != NULL) { 359656485a2SArchie Cobbs index = sl0->last_cs - sl0->tstate; 360656485a2SArchie Cobbs bzero(&sl->last_cs, sizeof(sl->last_cs)); 361656485a2SArchie Cobbs *((u_int16_t *)&sl->last_cs) = index; 362656485a2SArchie Cobbs } 363656485a2SArchie Cobbs for (i = 0; i < MAX_STATES; i++) { 364656485a2SArchie Cobbs struct cstate *const cs = &sl->tstate[i]; 365656485a2SArchie Cobbs 366656485a2SArchie Cobbs index = sl0->tstate[i].cs_next - sl0->tstate; 367656485a2SArchie Cobbs bzero(&cs->cs_next, sizeof(cs->cs_next)); 368656485a2SArchie Cobbs *((u_int16_t *)&cs->cs_next) = index; 369656485a2SArchie Cobbs } 370656485a2SArchie Cobbs break; 371656485a2SArchie Cobbs } 3724cf49a43SJulian Elischer case NGM_VJC_CLR_STATS: 3734cf49a43SJulian Elischer priv->slc.sls_packets = 0; 3744cf49a43SJulian Elischer priv->slc.sls_compressed = 0; 3754cf49a43SJulian Elischer priv->slc.sls_searches = 0; 3764cf49a43SJulian Elischer priv->slc.sls_misses = 0; 3774cf49a43SJulian Elischer priv->slc.sls_uncompressedin = 0; 3784cf49a43SJulian Elischer priv->slc.sls_compressedin = 0; 3794cf49a43SJulian Elischer priv->slc.sls_errorin = 0; 3804cf49a43SJulian Elischer priv->slc.sls_tossed = 0; 3814cf49a43SJulian Elischer break; 3824cf49a43SJulian Elischer case NGM_VJC_RECV_ERROR: 3833f47e1e3SArchie Cobbs sl_uncompress_tcp(NULL, 0, TYPE_ERROR, &priv->slc); 3844cf49a43SJulian Elischer break; 3854cf49a43SJulian Elischer default: 3864cf49a43SJulian Elischer error = EINVAL; 3874cf49a43SJulian Elischer break; 3884cf49a43SJulian Elischer } 3894cf49a43SJulian Elischer break; 3904cf49a43SJulian Elischer default: 3914cf49a43SJulian Elischer error = EINVAL; 3924cf49a43SJulian Elischer break; 3934cf49a43SJulian Elischer } 3944cf49a43SJulian Elischer done: 395069154d5SJulian Elischer NG_RESPOND_MSG(error, node, item, resp); 396069154d5SJulian Elischer NG_FREE_MSG(msg); 3974cf49a43SJulian Elischer return (error); 3984cf49a43SJulian Elischer } 3994cf49a43SJulian Elischer 4004cf49a43SJulian Elischer /* 4014cf49a43SJulian Elischer * Receive data 4024cf49a43SJulian Elischer */ 4034cf49a43SJulian Elischer static int 404069154d5SJulian Elischer ng_vjc_rcvdata(hook_p hook, item_p item) 4054cf49a43SJulian Elischer { 4064cf49a43SJulian Elischer const node_p node = hook->node; 4074cf49a43SJulian Elischer const priv_p priv = (priv_p) node->private; 4084cf49a43SJulian Elischer int error = 0; 409069154d5SJulian Elischer struct mbuf *m; 4104cf49a43SJulian Elischer 411069154d5SJulian Elischer NGI_GET_M(item, m); 4124cf49a43SJulian Elischer if (hook == priv->ip) { /* outgoing packet */ 413309c48c6SArchie Cobbs u_int type = TYPE_IP; 4144cf49a43SJulian Elischer 415309c48c6SArchie Cobbs /* Compress packet if enabled and proto is TCP */ 416309c48c6SArchie Cobbs if (priv->conf.enableComp) { 4174cf49a43SJulian Elischer struct ip *ip; 4184cf49a43SJulian Elischer 419309c48c6SArchie Cobbs if ((m = ng_vjc_pulluphdrs(m, 0)) == NULL) { 420069154d5SJulian Elischer NG_FREE_ITEM(item); 421309c48c6SArchie Cobbs return (ENOBUFS); 4224cf49a43SJulian Elischer } 423309c48c6SArchie Cobbs ip = mtod(m, struct ip *); 424309c48c6SArchie Cobbs if (ip->ip_p == IPPROTO_TCP) { 425309c48c6SArchie Cobbs const int origLen = m->m_len; 426309c48c6SArchie Cobbs 427309c48c6SArchie Cobbs type = sl_compress_tcp(m, ip, 428309c48c6SArchie Cobbs &priv->slc, priv->conf.compressCID); 429309c48c6SArchie Cobbs m->m_pkthdr.len += m->m_len - origLen; 430309c48c6SArchie Cobbs } 431309c48c6SArchie Cobbs } 432309c48c6SArchie Cobbs 433309c48c6SArchie Cobbs /* Dispatch to the appropriate outgoing hook */ 4344cf49a43SJulian Elischer switch (type) { 4354cf49a43SJulian Elischer case TYPE_IP: 4364cf49a43SJulian Elischer hook = priv->vjip; 4374cf49a43SJulian Elischer break; 4384cf49a43SJulian Elischer case TYPE_UNCOMPRESSED_TCP: 4394cf49a43SJulian Elischer hook = priv->vjuncomp; 4404cf49a43SJulian Elischer break; 4414cf49a43SJulian Elischer case TYPE_COMPRESSED_TCP: 4424cf49a43SJulian Elischer hook = priv->vjcomp; 4434cf49a43SJulian Elischer break; 4444cf49a43SJulian Elischer default: 4453f47e1e3SArchie Cobbs panic("%s: type=%d", __FUNCTION__, type); 4464cf49a43SJulian Elischer } 4474cf49a43SJulian Elischer } else if (hook == priv->vjcomp) { /* incoming compressed packet */ 448309c48c6SArchie Cobbs int vjlen, need2pullup; 449309c48c6SArchie Cobbs struct mbuf *hm; 4504cf49a43SJulian Elischer u_char *hdr; 451309c48c6SArchie Cobbs u_int hlen; 4524cf49a43SJulian Elischer 453bef9dae0SJulian Elischer /* Are we decompressing? */ 454bef9dae0SJulian Elischer if (!priv->conf.enableDecomp) { 455069154d5SJulian Elischer NG_FREE_M(m); 456069154d5SJulian Elischer NG_FREE_ITEM(item); 457309c48c6SArchie Cobbs return (ENXIO); 458309c48c6SArchie Cobbs } 459309c48c6SArchie Cobbs 460309c48c6SArchie Cobbs /* Pull up the necessary amount from the mbuf */ 461309c48c6SArchie Cobbs need2pullup = MAX_VJHEADER; 462309c48c6SArchie Cobbs if (need2pullup > m->m_pkthdr.len) 463309c48c6SArchie Cobbs need2pullup = m->m_pkthdr.len; 464309c48c6SArchie Cobbs if (m->m_len < need2pullup 465309c48c6SArchie Cobbs && (m = m_pullup(m, need2pullup)) == NULL) { 466309c48c6SArchie Cobbs priv->slc.sls_errorin++; 467069154d5SJulian Elischer NG_FREE_ITEM(item); 468309c48c6SArchie Cobbs return (ENOBUFS); 4694cf49a43SJulian Elischer } 4704cf49a43SJulian Elischer 4714cf49a43SJulian Elischer /* Uncompress packet to reconstruct TCP/IP header */ 4724cf49a43SJulian Elischer vjlen = sl_uncompress_tcp_core(mtod(m, u_char *), 4734cf49a43SJulian Elischer m->m_len, m->m_pkthdr.len, TYPE_COMPRESSED_TCP, 4744cf49a43SJulian Elischer &priv->slc, &hdr, &hlen); 4754cf49a43SJulian Elischer if (vjlen <= 0) { 476069154d5SJulian Elischer NG_FREE_M(m); 477069154d5SJulian Elischer NG_FREE_ITEM(item); 478309c48c6SArchie Cobbs return (EINVAL); 4794cf49a43SJulian Elischer } 4803f47e1e3SArchie Cobbs m_adj(m, vjlen); 4814cf49a43SJulian Elischer 4824cf49a43SJulian Elischer /* Copy the reconstructed TCP/IP headers into a new mbuf */ 483309c48c6SArchie Cobbs MGETHDR(hm, M_DONTWAIT, MT_DATA); 484309c48c6SArchie Cobbs if (hm == NULL) { 485309c48c6SArchie Cobbs priv->slc.sls_errorin++; 486069154d5SJulian Elischer NG_FREE_M(m); 487069154d5SJulian Elischer NG_FREE_ITEM(item); 488309c48c6SArchie Cobbs return (ENOBUFS); 489309c48c6SArchie Cobbs } 490309c48c6SArchie Cobbs hm->m_len = 0; 4914e256e6eSArchie Cobbs hm->m_pkthdr.rcvif = NULL; 492309c48c6SArchie Cobbs if (hlen > MHLEN) { /* unlikely, but can happen */ 493309c48c6SArchie Cobbs MCLGET(hm, M_DONTWAIT); 494309c48c6SArchie Cobbs if ((hm->m_flags & M_EXT) == 0) { 495309c48c6SArchie Cobbs m_freem(hm); 496309c48c6SArchie Cobbs priv->slc.sls_errorin++; 497069154d5SJulian Elischer NG_FREE_M(m); 498069154d5SJulian Elischer NG_FREE_ITEM(item); 499309c48c6SArchie Cobbs return (ENOBUFS); 5004cf49a43SJulian Elischer } 5014cf49a43SJulian Elischer } 502309c48c6SArchie Cobbs bcopy(hdr, mtod(hm, u_char *), hlen); 503309c48c6SArchie Cobbs hm->m_len = hlen; 5044cf49a43SJulian Elischer 505309c48c6SArchie Cobbs /* Glue TCP/IP headers and rest of packet together */ 506309c48c6SArchie Cobbs hm->m_next = m; 507309c48c6SArchie Cobbs hm->m_pkthdr.len = hlen + m->m_pkthdr.len; 508309c48c6SArchie Cobbs m = hm; 5094cf49a43SJulian Elischer hook = priv->ip; 5104cf49a43SJulian Elischer } else if (hook == priv->vjuncomp) { /* incoming uncompressed pkt */ 5114cf49a43SJulian Elischer u_char *hdr; 512bef9dae0SJulian Elischer u_int hlen; 5134cf49a43SJulian Elischer 514bef9dae0SJulian Elischer /* Are we decompressing? */ 515bef9dae0SJulian Elischer if (!priv->conf.enableDecomp) { 516069154d5SJulian Elischer NG_FREE_M(m); 517069154d5SJulian Elischer NG_FREE_ITEM(item); 518309c48c6SArchie Cobbs return (ENXIO); 519309c48c6SArchie Cobbs } 520309c48c6SArchie Cobbs 521309c48c6SArchie Cobbs /* Pull up IP+TCP headers */ 522309c48c6SArchie Cobbs if ((m = ng_vjc_pulluphdrs(m, 1)) == NULL) { 523069154d5SJulian Elischer NG_FREE_ITEM(item); 524309c48c6SArchie Cobbs return (ENOBUFS); 5254cf49a43SJulian Elischer } 5264cf49a43SJulian Elischer 5274cf49a43SJulian Elischer /* Run packet through uncompressor */ 5284cf49a43SJulian Elischer if (sl_uncompress_tcp_core(mtod(m, u_char *), 5294cf49a43SJulian Elischer m->m_len, m->m_pkthdr.len, TYPE_UNCOMPRESSED_TCP, 5304cf49a43SJulian Elischer &priv->slc, &hdr, &hlen) < 0) { 531069154d5SJulian Elischer NG_FREE_M(m); 532069154d5SJulian Elischer NG_FREE_ITEM(item); 533309c48c6SArchie Cobbs return (EINVAL); 5344cf49a43SJulian Elischer } 5354cf49a43SJulian Elischer hook = priv->ip; 5364cf49a43SJulian Elischer } else if (hook == priv->vjip) /* incoming regular packet (bypass) */ 5374cf49a43SJulian Elischer hook = priv->ip; 5384cf49a43SJulian Elischer else 5393f47e1e3SArchie Cobbs panic("%s: unknown hook", __FUNCTION__); 5404cf49a43SJulian Elischer 541309c48c6SArchie Cobbs /* Send result back out */ 542069154d5SJulian Elischer NG_FWD_NEW_DATA(error, item, hook, m); 5434cf49a43SJulian Elischer return (error); 5444cf49a43SJulian Elischer } 5454cf49a43SJulian Elischer 5464cf49a43SJulian Elischer /* 5474cf49a43SJulian Elischer * Shutdown node 5484cf49a43SJulian Elischer */ 5494cf49a43SJulian Elischer static int 550069154d5SJulian Elischer ng_vjc_shutdown(node_p node) 5514cf49a43SJulian Elischer { 5524cf49a43SJulian Elischer const priv_p priv = (priv_p) node->private; 5534cf49a43SJulian Elischer 5544cf49a43SJulian Elischer node->flags |= NG_INVALID; 5554cf49a43SJulian Elischer bzero(priv, sizeof(*priv)); 5564cf49a43SJulian Elischer FREE(priv, M_NETGRAPH); 5574cf49a43SJulian Elischer node->private = NULL; 5584cf49a43SJulian Elischer ng_unref(node); 5594cf49a43SJulian Elischer return (0); 5604cf49a43SJulian Elischer } 5614cf49a43SJulian Elischer 5624cf49a43SJulian Elischer /* 5634cf49a43SJulian Elischer * Hook disconnection 5644cf49a43SJulian Elischer */ 5654cf49a43SJulian Elischer static int 5664cf49a43SJulian Elischer ng_vjc_disconnect(hook_p hook) 5674cf49a43SJulian Elischer { 56862838faeSArchie Cobbs const node_p node = hook->node; 56962838faeSArchie Cobbs const priv_p priv = node->private; 57062838faeSArchie Cobbs 57162838faeSArchie Cobbs /* Zero out hook pointer */ 57262838faeSArchie Cobbs if (hook == priv->ip) 57362838faeSArchie Cobbs priv->ip = NULL; 57462838faeSArchie Cobbs else if (hook == priv->vjcomp) 57562838faeSArchie Cobbs priv->vjcomp = NULL; 57662838faeSArchie Cobbs else if (hook == priv->vjuncomp) 57762838faeSArchie Cobbs priv->vjuncomp = NULL; 57862838faeSArchie Cobbs else if (hook == priv->vjip) 57962838faeSArchie Cobbs priv->vjip = NULL; 58062838faeSArchie Cobbs else 58162838faeSArchie Cobbs panic("%s: unknown hook", __FUNCTION__); 58262838faeSArchie Cobbs 58362838faeSArchie Cobbs /* Go away if no hooks left */ 584069154d5SJulian Elischer if ((node->numhooks == 0) 585069154d5SJulian Elischer && ((node->flags & NG_INVALID) == 0)) 586069154d5SJulian Elischer ng_rmnode_self(node); 5874cf49a43SJulian Elischer return (0); 5884cf49a43SJulian Elischer } 5894cf49a43SJulian Elischer 5904cf49a43SJulian Elischer /************************************************************************ 5914cf49a43SJulian Elischer HELPER STUFF 5924cf49a43SJulian Elischer ************************************************************************/ 5934cf49a43SJulian Elischer 5944cf49a43SJulian Elischer /* 595bef9dae0SJulian Elischer * Pull up the full IP and TCP headers of a packet. If packet is not 5964cf49a43SJulian Elischer * a TCP packet, just pull up the IP header. 5974cf49a43SJulian Elischer */ 5984cf49a43SJulian Elischer static struct mbuf * 599309c48c6SArchie Cobbs ng_vjc_pulluphdrs(struct mbuf *m, int knownTCP) 6004cf49a43SJulian Elischer { 6014cf49a43SJulian Elischer struct ip *ip; 6024cf49a43SJulian Elischer struct tcphdr *tcp; 6034cf49a43SJulian Elischer int ihlen, thlen; 6044cf49a43SJulian Elischer 6053f47e1e3SArchie Cobbs if (m->m_len < sizeof(*ip) && (m = m_pullup(m, sizeof(*ip))) == NULL) 6064cf49a43SJulian Elischer return (NULL); 6074cf49a43SJulian Elischer ip = mtod(m, struct ip *); 608309c48c6SArchie Cobbs if (!knownTCP && ip->ip_p != IPPROTO_TCP) 6094cf49a43SJulian Elischer return (m); 610bef9dae0SJulian Elischer ihlen = ip->ip_hl << 2; 611bef9dae0SJulian Elischer if (m->m_len < ihlen + sizeof(*tcp)) { 6123f47e1e3SArchie Cobbs if ((m = m_pullup(m, ihlen + sizeof(*tcp))) == NULL) 6134cf49a43SJulian Elischer return (NULL); 6144cf49a43SJulian Elischer ip = mtod(m, struct ip *); 6154cf49a43SJulian Elischer } 6164cf49a43SJulian Elischer tcp = (struct tcphdr *)((u_char *)ip + ihlen); 617bef9dae0SJulian Elischer thlen = tcp->th_off << 2; 618bef9dae0SJulian Elischer if (m->m_len < ihlen + thlen) 6194cf49a43SJulian Elischer m = m_pullup(m, ihlen + thlen); 6204cf49a43SJulian Elischer return (m); 6214cf49a43SJulian Elischer } 6224cf49a43SJulian Elischer 623