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 * 374cf49a43SJulian Elischer * Author: Archie Cobbs <archie@whistle.com> 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; 9274f5c6aaSJulian Elischer static ng_shutdown_t ng_vjc_rmnode; 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 = { 2254cf49a43SJulian Elischer NG_VERSION, 2264cf49a43SJulian Elischer NG_VJC_NODE_TYPE, 2274cf49a43SJulian Elischer NULL, 2284cf49a43SJulian Elischer ng_vjc_constructor, 2294cf49a43SJulian Elischer ng_vjc_rcvmsg, 2304cf49a43SJulian Elischer ng_vjc_rmnode, 2314cf49a43SJulian Elischer ng_vjc_newhook, 2324cf49a43SJulian Elischer NULL, 2334cf49a43SJulian Elischer NULL, 2344cf49a43SJulian Elischer ng_vjc_rcvdata, 2354cf49a43SJulian Elischer ng_vjc_rcvdata, 236f8307e12SArchie Cobbs ng_vjc_disconnect, 237656485a2SArchie Cobbs ng_vjc_cmds 2384cf49a43SJulian Elischer }; 239656485a2SArchie Cobbs NETGRAPH_INIT(vjc, &ng_vjc_typestruct); 2404cf49a43SJulian Elischer 2414cf49a43SJulian Elischer /************************************************************************ 2424cf49a43SJulian Elischer NETGRAPH NODE METHODS 2434cf49a43SJulian Elischer ************************************************************************/ 2444cf49a43SJulian Elischer 2454cf49a43SJulian Elischer /* 2464cf49a43SJulian Elischer * Create a new node 2474cf49a43SJulian Elischer */ 2484cf49a43SJulian Elischer static int 2494cf49a43SJulian Elischer ng_vjc_constructor(node_p *nodep) 2504cf49a43SJulian Elischer { 2514cf49a43SJulian Elischer priv_p priv; 2524cf49a43SJulian Elischer int error; 2534cf49a43SJulian Elischer 2544cf49a43SJulian Elischer /* Allocate private structure */ 2554cf49a43SJulian Elischer MALLOC(priv, priv_p, sizeof(*priv), M_NETGRAPH, M_WAITOK); 2564cf49a43SJulian Elischer if (priv == NULL) 2574cf49a43SJulian Elischer return (ENOMEM); 2584cf49a43SJulian Elischer bzero(priv, sizeof(*priv)); 2594cf49a43SJulian Elischer 2604cf49a43SJulian Elischer /* Call generic node constructor */ 261656485a2SArchie Cobbs if ((error = ng_make_node_common(&ng_vjc_typestruct, nodep))) { 2624cf49a43SJulian Elischer FREE(priv, M_NETGRAPH); 2634cf49a43SJulian Elischer return (error); 2644cf49a43SJulian Elischer } 2654cf49a43SJulian Elischer (*nodep)->private = priv; 2664cf49a43SJulian Elischer 2674cf49a43SJulian Elischer /* Done */ 2684cf49a43SJulian Elischer return (0); 2694cf49a43SJulian Elischer } 2704cf49a43SJulian Elischer 2714cf49a43SJulian Elischer /* 2724cf49a43SJulian Elischer * Add a new hook 2734cf49a43SJulian Elischer */ 2744cf49a43SJulian Elischer static int 2754cf49a43SJulian Elischer ng_vjc_newhook(node_p node, hook_p hook, const char *name) 2764cf49a43SJulian Elischer { 2774cf49a43SJulian Elischer const priv_p priv = (priv_p) node->private; 2784cf49a43SJulian Elischer hook_p *hookp; 2794cf49a43SJulian Elischer 2804cf49a43SJulian Elischer /* Get hook */ 2813f47e1e3SArchie Cobbs if (strcmp(name, NG_VJC_HOOK_IP) == 0) 2824cf49a43SJulian Elischer hookp = &priv->ip; 2833f47e1e3SArchie Cobbs else if (strcmp(name, NG_VJC_HOOK_VJCOMP) == 0) 2844cf49a43SJulian Elischer hookp = &priv->vjcomp; 2853f47e1e3SArchie Cobbs else if (strcmp(name, NG_VJC_HOOK_VJUNCOMP) == 0) 2864cf49a43SJulian Elischer hookp = &priv->vjuncomp; 2873f47e1e3SArchie Cobbs else if (strcmp(name, NG_VJC_HOOK_VJIP) == 0) 2884cf49a43SJulian Elischer hookp = &priv->vjip; 2894cf49a43SJulian Elischer else 2904cf49a43SJulian Elischer return (EINVAL); 2914cf49a43SJulian Elischer 2924cf49a43SJulian Elischer /* See if already connected */ 2934cf49a43SJulian Elischer if (*hookp) 2944cf49a43SJulian Elischer return (EISCONN); 2954cf49a43SJulian Elischer 2964cf49a43SJulian Elischer /* OK */ 2974cf49a43SJulian Elischer *hookp = hook; 2984cf49a43SJulian Elischer return (0); 2994cf49a43SJulian Elischer } 3004cf49a43SJulian Elischer 3014cf49a43SJulian Elischer /* 3024cf49a43SJulian Elischer * Receive a control message 3034cf49a43SJulian Elischer */ 3044cf49a43SJulian Elischer static int 3054cf49a43SJulian Elischer ng_vjc_rcvmsg(node_p node, struct ng_mesg *msg, 306a4ec03cfSJulian Elischer const char *raddr, struct ng_mesg **rptr, hook_p lasthook) 3074cf49a43SJulian Elischer { 3084cf49a43SJulian Elischer const priv_p priv = (priv_p) node->private; 3094cf49a43SJulian Elischer struct ng_mesg *resp = NULL; 3104cf49a43SJulian Elischer int error = 0; 3114cf49a43SJulian Elischer 3124cf49a43SJulian Elischer /* Check type cookie */ 3134cf49a43SJulian Elischer switch (msg->header.typecookie) { 3144cf49a43SJulian Elischer case NGM_VJC_COOKIE: 3154cf49a43SJulian Elischer switch (msg->header.cmd) { 316bef9dae0SJulian Elischer case NGM_VJC_SET_CONFIG: 3174cf49a43SJulian Elischer { 3184cf49a43SJulian Elischer struct ngm_vjc_config *const c = 3194cf49a43SJulian Elischer (struct ngm_vjc_config *) msg->data; 3204cf49a43SJulian Elischer 321bef9dae0SJulian Elischer if (msg->header.arglen != sizeof(*c)) 322bef9dae0SJulian Elischer ERROUT(EINVAL); 323bef9dae0SJulian Elischer if ((priv->conf.enableComp || priv->conf.enableDecomp) 324bef9dae0SJulian Elischer && (c->enableComp || c->enableDecomp)) 325bef9dae0SJulian Elischer ERROUT(EALREADY); 326bef9dae0SJulian Elischer if (c->enableComp) { 3273f47e1e3SArchie Cobbs if (c->maxChannel > NG_VJC_MAX_CHANNELS - 1 3283f47e1e3SArchie Cobbs || c->maxChannel < NG_VJC_MIN_CHANNELS - 1) 3294cf49a43SJulian Elischer ERROUT(EINVAL); 330309c48c6SArchie Cobbs } else 331309c48c6SArchie Cobbs c->maxChannel = NG_VJC_MAX_CHANNELS - 1; 332bef9dae0SJulian Elischer if (c->enableComp != 0 || c->enableDecomp != 0) { 3334cf49a43SJulian Elischer bzero(&priv->slc, sizeof(priv->slc)); 3343f47e1e3SArchie Cobbs sl_compress_init(&priv->slc, c->maxChannel); 3354cf49a43SJulian Elischer } 3364cf49a43SJulian Elischer priv->conf = *c; 3374cf49a43SJulian Elischer break; 3384cf49a43SJulian Elischer } 339656485a2SArchie Cobbs case NGM_VJC_GET_CONFIG: 340656485a2SArchie Cobbs { 341656485a2SArchie Cobbs struct ngm_vjc_config *conf; 342656485a2SArchie Cobbs 343656485a2SArchie Cobbs NG_MKRESPONSE(resp, msg, sizeof(*conf), M_NOWAIT); 3444cf49a43SJulian Elischer if (resp == NULL) 3454cf49a43SJulian Elischer ERROUT(ENOMEM); 346656485a2SArchie Cobbs conf = (struct ngm_vjc_config *)resp->data; 347656485a2SArchie Cobbs *conf = priv->conf; 3484cf49a43SJulian Elischer break; 349656485a2SArchie Cobbs } 350656485a2SArchie Cobbs case NGM_VJC_GET_STATE: 351656485a2SArchie Cobbs { 352656485a2SArchie Cobbs const struct slcompress *const sl0 = &priv->slc; 353656485a2SArchie Cobbs struct slcompress *sl; 354656485a2SArchie Cobbs u_int16_t index; 355656485a2SArchie Cobbs int i; 356656485a2SArchie Cobbs 357656485a2SArchie Cobbs /* Get response structure */ 358656485a2SArchie Cobbs NG_MKRESPONSE(resp, msg, sizeof(*sl), M_NOWAIT); 359656485a2SArchie Cobbs if (resp == NULL) 360656485a2SArchie Cobbs ERROUT(ENOMEM); 361656485a2SArchie Cobbs sl = (struct slcompress *)resp->data; 362656485a2SArchie Cobbs *sl = *sl0; 363656485a2SArchie Cobbs 364656485a2SArchie Cobbs /* Replace pointers with integer indicies */ 365656485a2SArchie Cobbs if (sl->last_cs != NULL) { 366656485a2SArchie Cobbs index = sl0->last_cs - sl0->tstate; 367656485a2SArchie Cobbs bzero(&sl->last_cs, sizeof(sl->last_cs)); 368656485a2SArchie Cobbs *((u_int16_t *)&sl->last_cs) = index; 369656485a2SArchie Cobbs } 370656485a2SArchie Cobbs for (i = 0; i < MAX_STATES; i++) { 371656485a2SArchie Cobbs struct cstate *const cs = &sl->tstate[i]; 372656485a2SArchie Cobbs 373656485a2SArchie Cobbs index = sl0->tstate[i].cs_next - sl0->tstate; 374656485a2SArchie Cobbs bzero(&cs->cs_next, sizeof(cs->cs_next)); 375656485a2SArchie Cobbs *((u_int16_t *)&cs->cs_next) = index; 376656485a2SArchie Cobbs } 377656485a2SArchie Cobbs break; 378656485a2SArchie Cobbs } 3794cf49a43SJulian Elischer case NGM_VJC_CLR_STATS: 3804cf49a43SJulian Elischer priv->slc.sls_packets = 0; 3814cf49a43SJulian Elischer priv->slc.sls_compressed = 0; 3824cf49a43SJulian Elischer priv->slc.sls_searches = 0; 3834cf49a43SJulian Elischer priv->slc.sls_misses = 0; 3844cf49a43SJulian Elischer priv->slc.sls_uncompressedin = 0; 3854cf49a43SJulian Elischer priv->slc.sls_compressedin = 0; 3864cf49a43SJulian Elischer priv->slc.sls_errorin = 0; 3874cf49a43SJulian Elischer priv->slc.sls_tossed = 0; 3884cf49a43SJulian Elischer break; 3894cf49a43SJulian Elischer case NGM_VJC_RECV_ERROR: 3903f47e1e3SArchie Cobbs sl_uncompress_tcp(NULL, 0, TYPE_ERROR, &priv->slc); 3914cf49a43SJulian Elischer break; 3924cf49a43SJulian Elischer default: 3934cf49a43SJulian Elischer error = EINVAL; 3944cf49a43SJulian Elischer break; 3954cf49a43SJulian Elischer } 3964cf49a43SJulian Elischer break; 3974cf49a43SJulian Elischer default: 3984cf49a43SJulian Elischer error = EINVAL; 3994cf49a43SJulian Elischer break; 4004cf49a43SJulian Elischer } 4014cf49a43SJulian Elischer if (rptr) 4024cf49a43SJulian Elischer *rptr = resp; 4034cf49a43SJulian Elischer else if (resp) 4044cf49a43SJulian Elischer FREE(resp, M_NETGRAPH); 4054cf49a43SJulian Elischer 4064cf49a43SJulian Elischer done: 4074cf49a43SJulian Elischer FREE(msg, M_NETGRAPH); 4084cf49a43SJulian Elischer return (error); 4094cf49a43SJulian Elischer } 4104cf49a43SJulian Elischer 4114cf49a43SJulian Elischer /* 4124cf49a43SJulian Elischer * Receive data 4134cf49a43SJulian Elischer */ 4144cf49a43SJulian Elischer static int 415a4ec03cfSJulian Elischer ng_vjc_rcvdata(hook_p hook, struct mbuf *m, meta_p meta, 416a4ec03cfSJulian Elischer struct mbuf **ret_m, meta_p *ret_meta) 4174cf49a43SJulian Elischer { 4184cf49a43SJulian Elischer const node_p node = hook->node; 4194cf49a43SJulian Elischer const priv_p priv = (priv_p) node->private; 4204cf49a43SJulian Elischer int error = 0; 4214cf49a43SJulian Elischer 4224cf49a43SJulian Elischer if (hook == priv->ip) { /* outgoing packet */ 423309c48c6SArchie Cobbs u_int type = TYPE_IP; 4244cf49a43SJulian Elischer 425309c48c6SArchie Cobbs /* Compress packet if enabled and proto is TCP */ 426309c48c6SArchie Cobbs if (priv->conf.enableComp) { 4274cf49a43SJulian Elischer struct ip *ip; 4284cf49a43SJulian Elischer 429309c48c6SArchie Cobbs if ((m = ng_vjc_pulluphdrs(m, 0)) == NULL) { 430309c48c6SArchie Cobbs NG_FREE_META(meta); 431309c48c6SArchie Cobbs return (ENOBUFS); 4324cf49a43SJulian Elischer } 433309c48c6SArchie Cobbs ip = mtod(m, struct ip *); 434309c48c6SArchie Cobbs if (ip->ip_p == IPPROTO_TCP) { 435309c48c6SArchie Cobbs const int origLen = m->m_len; 436309c48c6SArchie Cobbs 437309c48c6SArchie Cobbs type = sl_compress_tcp(m, ip, 438309c48c6SArchie Cobbs &priv->slc, priv->conf.compressCID); 439309c48c6SArchie Cobbs m->m_pkthdr.len += m->m_len - origLen; 440309c48c6SArchie Cobbs } 441309c48c6SArchie Cobbs } 442309c48c6SArchie Cobbs 443309c48c6SArchie Cobbs /* Dispatch to the appropriate outgoing hook */ 4444cf49a43SJulian Elischer switch (type) { 4454cf49a43SJulian Elischer case TYPE_IP: 4464cf49a43SJulian Elischer hook = priv->vjip; 4474cf49a43SJulian Elischer break; 4484cf49a43SJulian Elischer case TYPE_UNCOMPRESSED_TCP: 4494cf49a43SJulian Elischer hook = priv->vjuncomp; 4504cf49a43SJulian Elischer break; 4514cf49a43SJulian Elischer case TYPE_COMPRESSED_TCP: 4524cf49a43SJulian Elischer hook = priv->vjcomp; 4534cf49a43SJulian Elischer break; 4544cf49a43SJulian Elischer default: 4553f47e1e3SArchie Cobbs panic("%s: type=%d", __FUNCTION__, type); 4564cf49a43SJulian Elischer } 4574cf49a43SJulian Elischer } else if (hook == priv->vjcomp) { /* incoming compressed packet */ 458309c48c6SArchie Cobbs int vjlen, need2pullup; 459309c48c6SArchie Cobbs struct mbuf *hm; 4604cf49a43SJulian Elischer u_char *hdr; 461309c48c6SArchie Cobbs u_int hlen; 4624cf49a43SJulian Elischer 463bef9dae0SJulian Elischer /* Are we decompressing? */ 464bef9dae0SJulian Elischer if (!priv->conf.enableDecomp) { 4653f47e1e3SArchie Cobbs NG_FREE_DATA(m, meta); 466309c48c6SArchie Cobbs return (ENXIO); 467309c48c6SArchie Cobbs } 468309c48c6SArchie Cobbs 469309c48c6SArchie Cobbs /* Pull up the necessary amount from the mbuf */ 470309c48c6SArchie Cobbs need2pullup = MAX_VJHEADER; 471309c48c6SArchie Cobbs if (need2pullup > m->m_pkthdr.len) 472309c48c6SArchie Cobbs need2pullup = m->m_pkthdr.len; 473309c48c6SArchie Cobbs if (m->m_len < need2pullup 474309c48c6SArchie Cobbs && (m = m_pullup(m, need2pullup)) == NULL) { 475309c48c6SArchie Cobbs priv->slc.sls_errorin++; 476309c48c6SArchie Cobbs NG_FREE_META(meta); 477309c48c6SArchie Cobbs return (ENOBUFS); 4784cf49a43SJulian Elischer } 4794cf49a43SJulian Elischer 4804cf49a43SJulian Elischer /* Uncompress packet to reconstruct TCP/IP header */ 4814cf49a43SJulian Elischer vjlen = sl_uncompress_tcp_core(mtod(m, u_char *), 4824cf49a43SJulian Elischer m->m_len, m->m_pkthdr.len, TYPE_COMPRESSED_TCP, 4834cf49a43SJulian Elischer &priv->slc, &hdr, &hlen); 4844cf49a43SJulian Elischer if (vjlen <= 0) { 4853f47e1e3SArchie Cobbs NG_FREE_DATA(m, meta); 486309c48c6SArchie Cobbs return (EINVAL); 4874cf49a43SJulian Elischer } 4883f47e1e3SArchie Cobbs m_adj(m, vjlen); 4894cf49a43SJulian Elischer 4904cf49a43SJulian Elischer /* Copy the reconstructed TCP/IP headers into a new mbuf */ 491309c48c6SArchie Cobbs MGETHDR(hm, M_DONTWAIT, MT_DATA); 492309c48c6SArchie Cobbs if (hm == NULL) { 493309c48c6SArchie Cobbs priv->slc.sls_errorin++; 4943f47e1e3SArchie Cobbs NG_FREE_DATA(m, meta); 495309c48c6SArchie Cobbs return (ENOBUFS); 496309c48c6SArchie Cobbs } 497309c48c6SArchie Cobbs hm->m_len = 0; 4984e256e6eSArchie Cobbs hm->m_pkthdr.rcvif = NULL; 499309c48c6SArchie Cobbs if (hlen > MHLEN) { /* unlikely, but can happen */ 500309c48c6SArchie Cobbs MCLGET(hm, M_DONTWAIT); 501309c48c6SArchie Cobbs if ((hm->m_flags & M_EXT) == 0) { 502309c48c6SArchie Cobbs m_freem(hm); 503309c48c6SArchie Cobbs priv->slc.sls_errorin++; 504309c48c6SArchie Cobbs NG_FREE_DATA(m, meta); 505309c48c6SArchie Cobbs return (ENOBUFS); 5064cf49a43SJulian Elischer } 5074cf49a43SJulian Elischer } 508309c48c6SArchie Cobbs bcopy(hdr, mtod(hm, u_char *), hlen); 509309c48c6SArchie Cobbs hm->m_len = hlen; 5104cf49a43SJulian Elischer 511309c48c6SArchie Cobbs /* Glue TCP/IP headers and rest of packet together */ 512309c48c6SArchie Cobbs hm->m_next = m; 513309c48c6SArchie Cobbs hm->m_pkthdr.len = hlen + m->m_pkthdr.len; 514309c48c6SArchie Cobbs m = hm; 5154cf49a43SJulian Elischer hook = priv->ip; 5164cf49a43SJulian Elischer } else if (hook == priv->vjuncomp) { /* incoming uncompressed pkt */ 5174cf49a43SJulian Elischer u_char *hdr; 518bef9dae0SJulian Elischer u_int hlen; 5194cf49a43SJulian Elischer 520bef9dae0SJulian Elischer /* Are we decompressing? */ 521bef9dae0SJulian Elischer if (!priv->conf.enableDecomp) { 5223f47e1e3SArchie Cobbs NG_FREE_DATA(m, meta); 523309c48c6SArchie Cobbs return (ENXIO); 524309c48c6SArchie Cobbs } 525309c48c6SArchie Cobbs 526309c48c6SArchie Cobbs /* Pull up IP+TCP headers */ 527309c48c6SArchie Cobbs if ((m = ng_vjc_pulluphdrs(m, 1)) == NULL) { 528309c48c6SArchie Cobbs NG_FREE_META(meta); 529309c48c6SArchie Cobbs return (ENOBUFS); 5304cf49a43SJulian Elischer } 5314cf49a43SJulian Elischer 5324cf49a43SJulian Elischer /* Run packet through uncompressor */ 5334cf49a43SJulian Elischer if (sl_uncompress_tcp_core(mtod(m, u_char *), 5344cf49a43SJulian Elischer m->m_len, m->m_pkthdr.len, TYPE_UNCOMPRESSED_TCP, 5354cf49a43SJulian Elischer &priv->slc, &hdr, &hlen) < 0) { 5363f47e1e3SArchie Cobbs NG_FREE_DATA(m, meta); 537309c48c6SArchie Cobbs return (EINVAL); 5384cf49a43SJulian Elischer } 5394cf49a43SJulian Elischer hook = priv->ip; 5404cf49a43SJulian Elischer } else if (hook == priv->vjip) /* incoming regular packet (bypass) */ 5414cf49a43SJulian Elischer hook = priv->ip; 5424cf49a43SJulian Elischer else 5433f47e1e3SArchie Cobbs panic("%s: unknown hook", __FUNCTION__); 5444cf49a43SJulian Elischer 545309c48c6SArchie Cobbs /* Send result back out */ 5464cf49a43SJulian Elischer NG_SEND_DATA(error, hook, m, meta); 5474cf49a43SJulian Elischer return (error); 5484cf49a43SJulian Elischer } 5494cf49a43SJulian Elischer 5504cf49a43SJulian Elischer /* 5514cf49a43SJulian Elischer * Shutdown node 5524cf49a43SJulian Elischer */ 5534cf49a43SJulian Elischer static int 5544cf49a43SJulian Elischer ng_vjc_rmnode(node_p node) 5554cf49a43SJulian Elischer { 5564cf49a43SJulian Elischer const priv_p priv = (priv_p) node->private; 5574cf49a43SJulian Elischer 5584cf49a43SJulian Elischer node->flags |= NG_INVALID; 5594cf49a43SJulian Elischer ng_cutlinks(node); 5604cf49a43SJulian Elischer ng_unname(node); 5614cf49a43SJulian Elischer bzero(priv, sizeof(*priv)); 5624cf49a43SJulian Elischer FREE(priv, M_NETGRAPH); 5634cf49a43SJulian Elischer node->private = NULL; 5644cf49a43SJulian Elischer ng_unref(node); 5654cf49a43SJulian Elischer return (0); 5664cf49a43SJulian Elischer } 5674cf49a43SJulian Elischer 5684cf49a43SJulian Elischer /* 5694cf49a43SJulian Elischer * Hook disconnection 5704cf49a43SJulian Elischer */ 5714cf49a43SJulian Elischer static int 5724cf49a43SJulian Elischer ng_vjc_disconnect(hook_p hook) 5734cf49a43SJulian Elischer { 57462838faeSArchie Cobbs const node_p node = hook->node; 57562838faeSArchie Cobbs const priv_p priv = node->private; 57662838faeSArchie Cobbs 57762838faeSArchie Cobbs /* Zero out hook pointer */ 57862838faeSArchie Cobbs if (hook == priv->ip) 57962838faeSArchie Cobbs priv->ip = NULL; 58062838faeSArchie Cobbs else if (hook == priv->vjcomp) 58162838faeSArchie Cobbs priv->vjcomp = NULL; 58262838faeSArchie Cobbs else if (hook == priv->vjuncomp) 58362838faeSArchie Cobbs priv->vjuncomp = NULL; 58462838faeSArchie Cobbs else if (hook == priv->vjip) 58562838faeSArchie Cobbs priv->vjip = NULL; 58662838faeSArchie Cobbs else 58762838faeSArchie Cobbs panic("%s: unknown hook", __FUNCTION__); 58862838faeSArchie Cobbs 58962838faeSArchie Cobbs /* Go away if no hooks left */ 59062838faeSArchie Cobbs if (node->numhooks == 0) 59162838faeSArchie Cobbs ng_rmnode(node); 5924cf49a43SJulian Elischer return (0); 5934cf49a43SJulian Elischer } 5944cf49a43SJulian Elischer 5954cf49a43SJulian Elischer /************************************************************************ 5964cf49a43SJulian Elischer HELPER STUFF 5974cf49a43SJulian Elischer ************************************************************************/ 5984cf49a43SJulian Elischer 5994cf49a43SJulian Elischer /* 600bef9dae0SJulian Elischer * Pull up the full IP and TCP headers of a packet. If packet is not 6014cf49a43SJulian Elischer * a TCP packet, just pull up the IP header. 6024cf49a43SJulian Elischer */ 6034cf49a43SJulian Elischer static struct mbuf * 604309c48c6SArchie Cobbs ng_vjc_pulluphdrs(struct mbuf *m, int knownTCP) 6054cf49a43SJulian Elischer { 6064cf49a43SJulian Elischer struct ip *ip; 6074cf49a43SJulian Elischer struct tcphdr *tcp; 6084cf49a43SJulian Elischer int ihlen, thlen; 6094cf49a43SJulian Elischer 6103f47e1e3SArchie Cobbs if (m->m_len < sizeof(*ip) && (m = m_pullup(m, sizeof(*ip))) == NULL) 6114cf49a43SJulian Elischer return (NULL); 6124cf49a43SJulian Elischer ip = mtod(m, struct ip *); 613309c48c6SArchie Cobbs if (!knownTCP && ip->ip_p != IPPROTO_TCP) 6144cf49a43SJulian Elischer return (m); 615bef9dae0SJulian Elischer ihlen = ip->ip_hl << 2; 616bef9dae0SJulian Elischer if (m->m_len < ihlen + sizeof(*tcp)) { 6173f47e1e3SArchie Cobbs if ((m = m_pullup(m, ihlen + sizeof(*tcp))) == NULL) 6184cf49a43SJulian Elischer return (NULL); 6194cf49a43SJulian Elischer ip = mtod(m, struct ip *); 6204cf49a43SJulian Elischer } 6214cf49a43SJulian Elischer tcp = (struct tcphdr *)((u_char *)ip + ihlen); 622bef9dae0SJulian Elischer thlen = tcp->th_off << 2; 623bef9dae0SJulian Elischer if (m->m_len < ihlen + thlen) 6244cf49a43SJulian Elischer m = m_pullup(m, ihlen + thlen); 6254cf49a43SJulian Elischer return (m); 6264cf49a43SJulian Elischer } 6274cf49a43SJulian Elischer 628