10147868eSNuno Antunes
20147868eSNuno Antunes /*
30147868eSNuno Antunes * ng_vjc.c
40147868eSNuno Antunes */
50147868eSNuno Antunes
60147868eSNuno Antunes /*-
70147868eSNuno Antunes * Copyright (c) 1996-1999 Whistle Communications, Inc.
80147868eSNuno Antunes * All rights reserved.
90147868eSNuno Antunes *
100147868eSNuno Antunes * Subject to the following obligations and disclaimer of warranty, use and
110147868eSNuno Antunes * redistribution of this software, in source or object code forms, with or
120147868eSNuno Antunes * without modifications are expressly permitted by Whistle Communications;
130147868eSNuno Antunes * provided, however, that:
140147868eSNuno Antunes * 1. Any and all reproductions of the source or object code must include the
150147868eSNuno Antunes * copyright notice above and the following disclaimer of warranties; and
160147868eSNuno Antunes * 2. No rights are granted, in any manner or form, to use Whistle
170147868eSNuno Antunes * Communications, Inc. trademarks, including the mark "WHISTLE
180147868eSNuno Antunes * COMMUNICATIONS" on advertising, endorsements, or otherwise except as
190147868eSNuno Antunes * such appears in the above copyright notice or in the software.
200147868eSNuno Antunes *
210147868eSNuno Antunes * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
220147868eSNuno Antunes * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
230147868eSNuno Antunes * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
240147868eSNuno Antunes * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
250147868eSNuno Antunes * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
260147868eSNuno Antunes * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
270147868eSNuno Antunes * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
280147868eSNuno Antunes * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
290147868eSNuno Antunes * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
300147868eSNuno Antunes * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
310147868eSNuno Antunes * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
320147868eSNuno Antunes * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
330147868eSNuno Antunes * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
340147868eSNuno Antunes * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
350147868eSNuno Antunes * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
360147868eSNuno Antunes * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
370147868eSNuno Antunes * OF SUCH DAMAGE.
380147868eSNuno Antunes *
390147868eSNuno Antunes * Author: Archie Cobbs <archie@freebsd.org>
400147868eSNuno Antunes *
410147868eSNuno Antunes * $FreeBSD: src/sys/netgraph/ng_vjc.c,v 1.26 2005/12/04 00:25:03 ru Exp $
420147868eSNuno Antunes * $Whistle: ng_vjc.c,v 1.17 1999/11/01 09:24:52 julian Exp $
430147868eSNuno Antunes */
440147868eSNuno Antunes
450147868eSNuno Antunes /*
460147868eSNuno Antunes * This node performs Van Jacobson IP header (de)compression.
470147868eSNuno Antunes * You must have included net/slcompress.c in your kernel compilation.
480147868eSNuno Antunes */
490147868eSNuno Antunes
500147868eSNuno Antunes #include <sys/param.h>
510147868eSNuno Antunes #include <sys/systm.h>
520147868eSNuno Antunes #include <sys/errno.h>
530147868eSNuno Antunes #include <sys/kernel.h>
540147868eSNuno Antunes #include <sys/mbuf.h>
550147868eSNuno Antunes #include <sys/malloc.h>
560147868eSNuno Antunes
570147868eSNuno Antunes #include <netgraph7/ng_message.h>
580147868eSNuno Antunes #include <netgraph7/netgraph.h>
590147868eSNuno Antunes #include <netgraph7/ng_parse.h>
600147868eSNuno Antunes #include "ng_vjc.h"
610147868eSNuno Antunes
620147868eSNuno Antunes #include <netinet/in.h>
630147868eSNuno Antunes #include <netinet/in_systm.h>
640147868eSNuno Antunes #include <netinet/ip.h>
650147868eSNuno Antunes #include <netinet/tcp.h>
660147868eSNuno Antunes
670147868eSNuno Antunes #include <net/slcompress.h>
680147868eSNuno Antunes
690147868eSNuno Antunes /* Check agreement with slcompress.c */
700147868eSNuno Antunes #if MAX_STATES != NG_VJC_MAX_CHANNELS
710147868eSNuno Antunes #error NG_VJC_MAX_CHANNELS must be the same as MAX_STATES
720147868eSNuno Antunes #endif
730147868eSNuno Antunes
740147868eSNuno Antunes /* Maximum length of a compressed TCP VJ header */
750147868eSNuno Antunes #define MAX_VJHEADER 19
760147868eSNuno Antunes
770147868eSNuno Antunes /* Node private data */
780147868eSNuno Antunes struct ng_vjc_private {
790147868eSNuno Antunes struct ngm_vjc_config conf;
800147868eSNuno Antunes struct slcompress slc;
810147868eSNuno Antunes hook_p ip;
820147868eSNuno Antunes hook_p vjcomp;
830147868eSNuno Antunes hook_p vjuncomp;
840147868eSNuno Antunes hook_p vjip;
850147868eSNuno Antunes };
860147868eSNuno Antunes typedef struct ng_vjc_private *priv_p;
870147868eSNuno Antunes
880147868eSNuno Antunes #define ERROUT(x) do { error = (x); goto done; } while (0)
890147868eSNuno Antunes
900147868eSNuno Antunes /* Netgraph node methods */
910147868eSNuno Antunes static ng_constructor_t ng_vjc_constructor;
920147868eSNuno Antunes static ng_rcvmsg_t ng_vjc_rcvmsg;
930147868eSNuno Antunes static ng_shutdown_t ng_vjc_shutdown;
940147868eSNuno Antunes static ng_newhook_t ng_vjc_newhook;
950147868eSNuno Antunes static ng_rcvdata_t ng_vjc_rcvdata;
960147868eSNuno Antunes static ng_disconnect_t ng_vjc_disconnect;
970147868eSNuno Antunes
980147868eSNuno Antunes /* Helper stuff */
990147868eSNuno Antunes static struct mbuf *ng_vjc_pulluphdrs(struct mbuf *m, int knownTCP);
1000147868eSNuno Antunes
1010147868eSNuno Antunes /* Parse type for struct ngm_vjc_config */
1020147868eSNuno Antunes static const struct ng_parse_struct_field ng_vjc_config_type_fields[]
1030147868eSNuno Antunes = NG_VJC_CONFIG_TYPE_INFO;
1040147868eSNuno Antunes static const struct ng_parse_type ng_vjc_config_type = {
1050147868eSNuno Antunes &ng_parse_struct_type,
1060147868eSNuno Antunes &ng_vjc_config_type_fields
1070147868eSNuno Antunes };
1080147868eSNuno Antunes
1090147868eSNuno Antunes /* Parse type for the 'last_cs' and 'cs_next' fields in struct slcompress,
1100147868eSNuno Antunes which are pointers converted to integer indices, so parse them that way. */
1110147868eSNuno Antunes #ifndef __LP64__
1120147868eSNuno Antunes #define NG_VJC_TSTATE_PTR_TYPE &ng_parse_uint32_type
1130147868eSNuno Antunes #else
1140147868eSNuno Antunes #define NG_VJC_TSTATE_PTR_TYPE &ng_parse_uint64_type
1150147868eSNuno Antunes #endif
1160147868eSNuno Antunes
1170147868eSNuno Antunes /* Parse type for the 'cs_hdr' field in a struct cstate. Ideally we would
1180147868eSNuno Antunes like to use a 'struct ip' type instead of a simple array of bytes. */
1190147868eSNuno Antunes static const struct ng_parse_fixedarray_info ng_vjc_cs_hdr_type_info = {
1200147868eSNuno Antunes &ng_parse_hint8_type,
1210147868eSNuno Antunes MAX_HDR
1220147868eSNuno Antunes };
1230147868eSNuno Antunes static const struct ng_parse_type ng_vjc_cs_hdr_type = {
1240147868eSNuno Antunes &ng_parse_fixedarray_type,
1250147868eSNuno Antunes &ng_vjc_cs_hdr_type_info
1260147868eSNuno Antunes };
1270147868eSNuno Antunes
1280147868eSNuno Antunes /* Parse type for a struct cstate */
1290147868eSNuno Antunes static const struct ng_parse_struct_field ng_vjc_cstate_type_fields[] = {
1300147868eSNuno Antunes { "cs_next", NG_VJC_TSTATE_PTR_TYPE },
1310147868eSNuno Antunes { "cs_hlen", &ng_parse_uint16_type },
1320147868eSNuno Antunes { "cs_id", &ng_parse_uint8_type },
1330147868eSNuno Antunes { "cs_filler", &ng_parse_uint8_type },
1340147868eSNuno Antunes { "cs_hdr", &ng_vjc_cs_hdr_type },
1350147868eSNuno Antunes { NULL }
1360147868eSNuno Antunes };
1370147868eSNuno Antunes static const struct ng_parse_type ng_vjc_cstate_type = {
1380147868eSNuno Antunes &ng_parse_struct_type,
1390147868eSNuno Antunes &ng_vjc_cstate_type_fields
1400147868eSNuno Antunes };
1410147868eSNuno Antunes
1420147868eSNuno Antunes /* Parse type for an array of MAX_STATES struct cstate's, ie, tstate & rstate */
1430147868eSNuno Antunes static const struct ng_parse_fixedarray_info ng_vjc_cstatearray_type_info = {
1440147868eSNuno Antunes &ng_vjc_cstate_type,
1450147868eSNuno Antunes MAX_STATES
1460147868eSNuno Antunes };
1470147868eSNuno Antunes static const struct ng_parse_type ng_vjc_cstatearray_type = {
1480147868eSNuno Antunes &ng_parse_fixedarray_type,
1490147868eSNuno Antunes &ng_vjc_cstatearray_type_info
1500147868eSNuno Antunes };
1510147868eSNuno Antunes
1520147868eSNuno Antunes /* Parse type for struct slcompress. Keep this in sync with the
1530147868eSNuno Antunes definition of struct slcompress defined in <net/slcompress.h> */
1540147868eSNuno Antunes static const struct ng_parse_struct_field ng_vjc_slcompress_type_fields[] = {
1550147868eSNuno Antunes { "last_cs", NG_VJC_TSTATE_PTR_TYPE },
1560147868eSNuno Antunes { "last_recv", &ng_parse_uint8_type },
1570147868eSNuno Antunes { "last_xmit", &ng_parse_uint8_type },
1580147868eSNuno Antunes { "flags", &ng_parse_hint16_type },
1590147868eSNuno Antunes #ifndef SL_NO_STATS
1600147868eSNuno Antunes { "sls_packets", &ng_parse_uint32_type },
1610147868eSNuno Antunes { "sls_compressed", &ng_parse_uint32_type },
1620147868eSNuno Antunes { "sls_searches", &ng_parse_uint32_type },
1630147868eSNuno Antunes { "sls_misses", &ng_parse_uint32_type },
1640147868eSNuno Antunes { "sls_uncompressedin", &ng_parse_uint32_type },
1650147868eSNuno Antunes { "sls_compressedin", &ng_parse_uint32_type },
1660147868eSNuno Antunes { "sls_errorin", &ng_parse_uint32_type },
1670147868eSNuno Antunes { "sls_tossed", &ng_parse_uint32_type },
1680147868eSNuno Antunes #endif
1690147868eSNuno Antunes { "tstate", &ng_vjc_cstatearray_type },
1700147868eSNuno Antunes { "rstate", &ng_vjc_cstatearray_type },
1710147868eSNuno Antunes { NULL }
1720147868eSNuno Antunes };
1730147868eSNuno Antunes static const struct ng_parse_type ng_vjc_slcompress_type = {
1740147868eSNuno Antunes &ng_parse_struct_type,
1750147868eSNuno Antunes &ng_vjc_slcompress_type_fields
1760147868eSNuno Antunes };
1770147868eSNuno Antunes
1780147868eSNuno Antunes /* List of commands and how to convert arguments to/from ASCII */
1790147868eSNuno Antunes static const struct ng_cmdlist ng_vjc_cmds[] = {
1800147868eSNuno Antunes {
1810147868eSNuno Antunes NGM_VJC_COOKIE,
1820147868eSNuno Antunes NGM_VJC_SET_CONFIG,
1830147868eSNuno Antunes "setconfig",
1840147868eSNuno Antunes &ng_vjc_config_type,
1850147868eSNuno Antunes NULL
1860147868eSNuno Antunes },
1870147868eSNuno Antunes {
1880147868eSNuno Antunes NGM_VJC_COOKIE,
1890147868eSNuno Antunes NGM_VJC_GET_CONFIG,
1900147868eSNuno Antunes "getconfig",
1910147868eSNuno Antunes NULL,
1920147868eSNuno Antunes &ng_vjc_config_type,
1930147868eSNuno Antunes },
1940147868eSNuno Antunes {
1950147868eSNuno Antunes NGM_VJC_COOKIE,
1960147868eSNuno Antunes NGM_VJC_GET_STATE,
1970147868eSNuno Antunes "getstate",
1980147868eSNuno Antunes NULL,
1990147868eSNuno Antunes &ng_vjc_slcompress_type,
2000147868eSNuno Antunes },
2010147868eSNuno Antunes {
2020147868eSNuno Antunes NGM_VJC_COOKIE,
2030147868eSNuno Antunes NGM_VJC_CLR_STATS,
2040147868eSNuno Antunes "clrstats",
2050147868eSNuno Antunes NULL,
2060147868eSNuno Antunes NULL,
2070147868eSNuno Antunes },
2080147868eSNuno Antunes {
2090147868eSNuno Antunes NGM_VJC_COOKIE,
2100147868eSNuno Antunes NGM_VJC_RECV_ERROR,
2110147868eSNuno Antunes "recverror",
2120147868eSNuno Antunes NULL,
2130147868eSNuno Antunes NULL,
2140147868eSNuno Antunes },
2150147868eSNuno Antunes { 0 }
2160147868eSNuno Antunes };
2170147868eSNuno Antunes
2180147868eSNuno Antunes /* Node type descriptor */
2190147868eSNuno Antunes static struct ng_type ng_vjc_typestruct = {
2200147868eSNuno Antunes .version = NG_ABI_VERSION,
2210147868eSNuno Antunes .name = NG_VJC_NODE_TYPE,
2220147868eSNuno Antunes .constructor = ng_vjc_constructor,
2230147868eSNuno Antunes .rcvmsg = ng_vjc_rcvmsg,
2240147868eSNuno Antunes .shutdown = ng_vjc_shutdown,
2250147868eSNuno Antunes .newhook = ng_vjc_newhook,
2260147868eSNuno Antunes .rcvdata = ng_vjc_rcvdata,
2270147868eSNuno Antunes .disconnect = ng_vjc_disconnect,
2280147868eSNuno Antunes .cmdlist = ng_vjc_cmds,
2290147868eSNuno Antunes };
2300147868eSNuno Antunes NETGRAPH_INIT(vjc, &ng_vjc_typestruct);
2310147868eSNuno Antunes
2320147868eSNuno Antunes /************************************************************************
2330147868eSNuno Antunes NETGRAPH NODE METHODS
2340147868eSNuno Antunes ************************************************************************/
2350147868eSNuno Antunes
2360147868eSNuno Antunes /*
2370147868eSNuno Antunes * Create a new node
2380147868eSNuno Antunes */
2390147868eSNuno Antunes static int
ng_vjc_constructor(node_p node)2400147868eSNuno Antunes ng_vjc_constructor(node_p node)
2410147868eSNuno Antunes {
2420147868eSNuno Antunes priv_p priv;
2430147868eSNuno Antunes
2440147868eSNuno Antunes /* Allocate private structure */
2450147868eSNuno Antunes priv = kmalloc(sizeof(*priv), M_NETGRAPH,
2460147868eSNuno Antunes M_WAITOK | M_NULLOK | M_ZERO);
2470147868eSNuno Antunes if (priv == NULL)
2480147868eSNuno Antunes return (ENOMEM);
2490147868eSNuno Antunes
2500147868eSNuno Antunes NG_NODE_SET_PRIVATE(node, priv);
2510147868eSNuno Antunes
2520147868eSNuno Antunes /* Done */
2530147868eSNuno Antunes return (0);
2540147868eSNuno Antunes }
2550147868eSNuno Antunes
2560147868eSNuno Antunes /*
2570147868eSNuno Antunes * Add a new hook
2580147868eSNuno Antunes */
2590147868eSNuno Antunes static int
ng_vjc_newhook(node_p node,hook_p hook,const char * name)2600147868eSNuno Antunes ng_vjc_newhook(node_p node, hook_p hook, const char *name)
2610147868eSNuno Antunes {
2620147868eSNuno Antunes const priv_p priv = NG_NODE_PRIVATE(node);
2630147868eSNuno Antunes hook_p *hookp;
2640147868eSNuno Antunes
2650147868eSNuno Antunes /* Get hook */
2660147868eSNuno Antunes if (strcmp(name, NG_VJC_HOOK_IP) == 0)
2670147868eSNuno Antunes hookp = &priv->ip;
2680147868eSNuno Antunes else if (strcmp(name, NG_VJC_HOOK_VJCOMP) == 0)
2690147868eSNuno Antunes hookp = &priv->vjcomp;
2700147868eSNuno Antunes else if (strcmp(name, NG_VJC_HOOK_VJUNCOMP) == 0)
2710147868eSNuno Antunes hookp = &priv->vjuncomp;
2720147868eSNuno Antunes else if (strcmp(name, NG_VJC_HOOK_VJIP) == 0)
2730147868eSNuno Antunes hookp = &priv->vjip;
2740147868eSNuno Antunes else
2750147868eSNuno Antunes return (EINVAL);
2760147868eSNuno Antunes
2770147868eSNuno Antunes /* See if already connected */
2780147868eSNuno Antunes if (*hookp)
2790147868eSNuno Antunes return (EISCONN);
2800147868eSNuno Antunes
2810147868eSNuno Antunes /* OK */
2820147868eSNuno Antunes *hookp = hook;
2830147868eSNuno Antunes return (0);
2840147868eSNuno Antunes }
2850147868eSNuno Antunes
2860147868eSNuno Antunes /*
2870147868eSNuno Antunes * Receive a control message
2880147868eSNuno Antunes */
2890147868eSNuno Antunes static int
ng_vjc_rcvmsg(node_p node,item_p item,hook_p lasthook)2900147868eSNuno Antunes ng_vjc_rcvmsg(node_p node, item_p item, hook_p lasthook)
2910147868eSNuno Antunes {
2920147868eSNuno Antunes const priv_p priv = NG_NODE_PRIVATE(node);
2930147868eSNuno Antunes struct ng_mesg *resp = NULL;
2940147868eSNuno Antunes int error = 0;
2950147868eSNuno Antunes struct ng_mesg *msg;
2960147868eSNuno Antunes
2970147868eSNuno Antunes NGI_GET_MSG(item, msg);
2980147868eSNuno Antunes /* Check type cookie */
2990147868eSNuno Antunes switch (msg->header.typecookie) {
3000147868eSNuno Antunes case NGM_VJC_COOKIE:
3010147868eSNuno Antunes switch (msg->header.cmd) {
3020147868eSNuno Antunes case NGM_VJC_SET_CONFIG:
3030147868eSNuno Antunes {
3040147868eSNuno Antunes struct ngm_vjc_config *const c =
3050147868eSNuno Antunes (struct ngm_vjc_config *) msg->data;
3060147868eSNuno Antunes
3070147868eSNuno Antunes if (msg->header.arglen != sizeof(*c))
3080147868eSNuno Antunes ERROUT(EINVAL);
3090147868eSNuno Antunes if ((priv->conf.enableComp || priv->conf.enableDecomp)
3100147868eSNuno Antunes && (c->enableComp || c->enableDecomp))
3110147868eSNuno Antunes ERROUT(EALREADY);
3120147868eSNuno Antunes if (c->enableComp) {
3130147868eSNuno Antunes if (c->maxChannel > NG_VJC_MAX_CHANNELS - 1
3140147868eSNuno Antunes || c->maxChannel < NG_VJC_MIN_CHANNELS - 1)
3150147868eSNuno Antunes ERROUT(EINVAL);
3160147868eSNuno Antunes } else
3170147868eSNuno Antunes c->maxChannel = NG_VJC_MAX_CHANNELS - 1;
3180147868eSNuno Antunes if (c->enableComp != 0 || c->enableDecomp != 0) {
3190147868eSNuno Antunes bzero(&priv->slc, sizeof(priv->slc));
3200147868eSNuno Antunes sl_compress_init(&priv->slc, c->maxChannel);
3210147868eSNuno Antunes }
3220147868eSNuno Antunes priv->conf = *c;
3230147868eSNuno Antunes break;
3240147868eSNuno Antunes }
3250147868eSNuno Antunes case NGM_VJC_GET_CONFIG:
3260147868eSNuno Antunes {
3270147868eSNuno Antunes struct ngm_vjc_config *conf;
3280147868eSNuno Antunes
3290147868eSNuno Antunes NG_MKRESPONSE(resp, msg, sizeof(*conf), M_WAITOK | M_NULLOK);
3300147868eSNuno Antunes if (resp == NULL)
3310147868eSNuno Antunes ERROUT(ENOMEM);
3320147868eSNuno Antunes conf = (struct ngm_vjc_config *)resp->data;
3330147868eSNuno Antunes *conf = priv->conf;
3340147868eSNuno Antunes break;
3350147868eSNuno Antunes }
3360147868eSNuno Antunes case NGM_VJC_GET_STATE:
3370147868eSNuno Antunes {
3380147868eSNuno Antunes const struct slcompress *const sl0 = &priv->slc;
3390147868eSNuno Antunes struct slcompress *sl;
3400147868eSNuno Antunes u_int16_t index;
3410147868eSNuno Antunes int i;
3420147868eSNuno Antunes
3430147868eSNuno Antunes /* Get response structure */
3440147868eSNuno Antunes NG_MKRESPONSE(resp, msg, sizeof(*sl), M_WAITOK | M_NULLOK);
3450147868eSNuno Antunes if (resp == NULL)
3460147868eSNuno Antunes ERROUT(ENOMEM);
3470147868eSNuno Antunes sl = (struct slcompress *)resp->data;
3480147868eSNuno Antunes *sl = *sl0;
3490147868eSNuno Antunes
3500147868eSNuno Antunes /* Replace pointers with integer indicies */
3510147868eSNuno Antunes if (sl->last_cs != NULL) {
3520147868eSNuno Antunes index = sl0->last_cs - sl0->tstate;
3530147868eSNuno Antunes bzero(&sl->last_cs, sizeof(sl->last_cs));
3540147868eSNuno Antunes *((u_int16_t *)&sl->last_cs) = index;
3550147868eSNuno Antunes }
3560147868eSNuno Antunes for (i = 0; i < MAX_STATES; i++) {
3570147868eSNuno Antunes struct cstate *const cs = &sl->tstate[i];
3580147868eSNuno Antunes
3590147868eSNuno Antunes index = sl0->tstate[i].cs_next - sl0->tstate;
3600147868eSNuno Antunes bzero(&cs->cs_next, sizeof(cs->cs_next));
3610147868eSNuno Antunes *((u_int16_t *)&cs->cs_next) = index;
3620147868eSNuno Antunes }
3630147868eSNuno Antunes break;
3640147868eSNuno Antunes }
3650147868eSNuno Antunes case NGM_VJC_CLR_STATS:
3660147868eSNuno Antunes priv->slc.sls_packets = 0;
3670147868eSNuno Antunes priv->slc.sls_compressed = 0;
3680147868eSNuno Antunes priv->slc.sls_searches = 0;
3690147868eSNuno Antunes priv->slc.sls_misses = 0;
3700147868eSNuno Antunes priv->slc.sls_uncompressedin = 0;
3710147868eSNuno Antunes priv->slc.sls_compressedin = 0;
3720147868eSNuno Antunes priv->slc.sls_errorin = 0;
3730147868eSNuno Antunes priv->slc.sls_tossed = 0;
3740147868eSNuno Antunes break;
3750147868eSNuno Antunes case NGM_VJC_RECV_ERROR:
3760147868eSNuno Antunes sl_uncompress_tcp(NULL, 0, TYPE_ERROR, &priv->slc);
3770147868eSNuno Antunes break;
3780147868eSNuno Antunes default:
3790147868eSNuno Antunes error = EINVAL;
3800147868eSNuno Antunes break;
3810147868eSNuno Antunes }
3820147868eSNuno Antunes break;
3830147868eSNuno Antunes default:
3840147868eSNuno Antunes error = EINVAL;
3850147868eSNuno Antunes break;
3860147868eSNuno Antunes }
3870147868eSNuno Antunes done:
3880147868eSNuno Antunes NG_RESPOND_MSG(error, node, item, resp);
3890147868eSNuno Antunes NG_FREE_MSG(msg);
3900147868eSNuno Antunes return (error);
3910147868eSNuno Antunes }
3920147868eSNuno Antunes
3930147868eSNuno Antunes /*
3940147868eSNuno Antunes * Receive data
3950147868eSNuno Antunes */
3960147868eSNuno Antunes static int
ng_vjc_rcvdata(hook_p hook,item_p item)3970147868eSNuno Antunes ng_vjc_rcvdata(hook_p hook, item_p item)
3980147868eSNuno Antunes {
3990147868eSNuno Antunes const node_p node = NG_HOOK_NODE(hook);
4000147868eSNuno Antunes const priv_p priv = NG_NODE_PRIVATE(node);
4010147868eSNuno Antunes int error = 0;
4020147868eSNuno Antunes struct mbuf *m;
4030147868eSNuno Antunes
4040147868eSNuno Antunes NGI_GET_M(item, m);
4050147868eSNuno Antunes if (hook == priv->ip) { /* outgoing packet */
4060147868eSNuno Antunes u_int type = TYPE_IP;
4070147868eSNuno Antunes
4080147868eSNuno Antunes /* Compress packet if enabled and proto is TCP */
4090147868eSNuno Antunes if (priv->conf.enableComp) {
4100147868eSNuno Antunes struct ip *ip;
4110147868eSNuno Antunes
4120147868eSNuno Antunes if ((m = ng_vjc_pulluphdrs(m, 0)) == NULL) {
4130147868eSNuno Antunes NG_FREE_ITEM(item);
4140147868eSNuno Antunes return (ENOBUFS);
4150147868eSNuno Antunes }
4160147868eSNuno Antunes ip = mtod(m, struct ip *);
4170147868eSNuno Antunes if (ip->ip_p == IPPROTO_TCP) {
4180147868eSNuno Antunes const int origLen = m->m_len;
4190147868eSNuno Antunes
4200147868eSNuno Antunes type = sl_compress_tcp(m, ip,
4210147868eSNuno Antunes &priv->slc, priv->conf.compressCID);
4220147868eSNuno Antunes m->m_pkthdr.len += m->m_len - origLen;
4230147868eSNuno Antunes }
4240147868eSNuno Antunes }
4250147868eSNuno Antunes
4260147868eSNuno Antunes /* Dispatch to the appropriate outgoing hook */
4270147868eSNuno Antunes switch (type) {
4280147868eSNuno Antunes case TYPE_IP:
4290147868eSNuno Antunes hook = priv->vjip;
4300147868eSNuno Antunes break;
4310147868eSNuno Antunes case TYPE_UNCOMPRESSED_TCP:
4320147868eSNuno Antunes hook = priv->vjuncomp;
4330147868eSNuno Antunes break;
4340147868eSNuno Antunes case TYPE_COMPRESSED_TCP:
4350147868eSNuno Antunes hook = priv->vjcomp;
4360147868eSNuno Antunes break;
4370147868eSNuno Antunes default:
4380147868eSNuno Antunes panic("%s: type=%d", __func__, type);
4390147868eSNuno Antunes }
4400147868eSNuno Antunes } else if (hook == priv->vjcomp) { /* incoming compressed packet */
4410147868eSNuno Antunes int vjlen, need2pullup;
4420147868eSNuno Antunes struct mbuf *hm;
4430147868eSNuno Antunes u_char *hdr;
4440147868eSNuno Antunes u_int hlen;
4450147868eSNuno Antunes
4460147868eSNuno Antunes /* Are we decompressing? */
4470147868eSNuno Antunes if (!priv->conf.enableDecomp) {
4480147868eSNuno Antunes NG_FREE_M(m);
4490147868eSNuno Antunes NG_FREE_ITEM(item);
4500147868eSNuno Antunes return (ENXIO);
4510147868eSNuno Antunes }
4520147868eSNuno Antunes
4530147868eSNuno Antunes /* Pull up the necessary amount from the mbuf */
4540147868eSNuno Antunes need2pullup = MAX_VJHEADER;
4550147868eSNuno Antunes if (need2pullup > m->m_pkthdr.len)
4560147868eSNuno Antunes need2pullup = m->m_pkthdr.len;
4570147868eSNuno Antunes if (m->m_len < need2pullup
4580147868eSNuno Antunes && (m = m_pullup(m, need2pullup)) == NULL) {
4590147868eSNuno Antunes priv->slc.sls_errorin++;
4600147868eSNuno Antunes NG_FREE_ITEM(item);
4610147868eSNuno Antunes return (ENOBUFS);
4620147868eSNuno Antunes }
4630147868eSNuno Antunes
4640147868eSNuno Antunes /* Uncompress packet to reconstruct TCP/IP header */
4650147868eSNuno Antunes vjlen = sl_uncompress_tcp_core(mtod(m, u_char *),
4660147868eSNuno Antunes m->m_len, m->m_pkthdr.len, TYPE_COMPRESSED_TCP,
4670147868eSNuno Antunes &priv->slc, &hdr, &hlen);
4680147868eSNuno Antunes if (vjlen <= 0) {
4690147868eSNuno Antunes NG_FREE_M(m);
4700147868eSNuno Antunes NG_FREE_ITEM(item);
4710147868eSNuno Antunes return (EINVAL);
4720147868eSNuno Antunes }
4730147868eSNuno Antunes m_adj(m, vjlen);
4740147868eSNuno Antunes
4750147868eSNuno Antunes /* Copy the reconstructed TCP/IP headers into a new mbuf */
476*b5523eacSSascha Wildner MGETHDR(hm, M_NOWAIT, MT_DATA);
4770147868eSNuno Antunes if (hm == NULL) {
4780147868eSNuno Antunes priv->slc.sls_errorin++;
4790147868eSNuno Antunes NG_FREE_M(m);
4800147868eSNuno Antunes NG_FREE_ITEM(item);
4810147868eSNuno Antunes return (ENOBUFS);
4820147868eSNuno Antunes }
4830147868eSNuno Antunes hm->m_len = 0;
4840147868eSNuno Antunes hm->m_pkthdr.rcvif = NULL;
4850147868eSNuno Antunes if (hlen > MHLEN) { /* unlikely, but can happen */
486*b5523eacSSascha Wildner MCLGET(hm, M_NOWAIT);
4870147868eSNuno Antunes if ((hm->m_flags & M_EXT) == 0) {
4880147868eSNuno Antunes m_freem(hm);
4890147868eSNuno Antunes priv->slc.sls_errorin++;
4900147868eSNuno Antunes NG_FREE_M(m);
4910147868eSNuno Antunes NG_FREE_ITEM(item);
4920147868eSNuno Antunes return (ENOBUFS);
4930147868eSNuno Antunes }
4940147868eSNuno Antunes }
4950147868eSNuno Antunes bcopy(hdr, mtod(hm, u_char *), hlen);
4960147868eSNuno Antunes hm->m_len = hlen;
4970147868eSNuno Antunes
4980147868eSNuno Antunes /* Glue TCP/IP headers and rest of packet together */
4990147868eSNuno Antunes hm->m_next = m;
5000147868eSNuno Antunes hm->m_pkthdr.len = hlen + m->m_pkthdr.len;
5010147868eSNuno Antunes m = hm;
5020147868eSNuno Antunes hook = priv->ip;
5030147868eSNuno Antunes } else if (hook == priv->vjuncomp) { /* incoming uncompressed pkt */
5040147868eSNuno Antunes u_char *hdr;
5050147868eSNuno Antunes u_int hlen;
5060147868eSNuno Antunes
5070147868eSNuno Antunes /* Are we decompressing? */
5080147868eSNuno Antunes if (!priv->conf.enableDecomp) {
5090147868eSNuno Antunes NG_FREE_M(m);
5100147868eSNuno Antunes NG_FREE_ITEM(item);
5110147868eSNuno Antunes return (ENXIO);
5120147868eSNuno Antunes }
5130147868eSNuno Antunes
5140147868eSNuno Antunes /* Pull up IP+TCP headers */
5150147868eSNuno Antunes if ((m = ng_vjc_pulluphdrs(m, 1)) == NULL) {
5160147868eSNuno Antunes NG_FREE_ITEM(item);
5170147868eSNuno Antunes return (ENOBUFS);
5180147868eSNuno Antunes }
5190147868eSNuno Antunes
5200147868eSNuno Antunes /* Run packet through uncompressor */
5210147868eSNuno Antunes if (sl_uncompress_tcp_core(mtod(m, u_char *),
5220147868eSNuno Antunes m->m_len, m->m_pkthdr.len, TYPE_UNCOMPRESSED_TCP,
5230147868eSNuno Antunes &priv->slc, &hdr, &hlen) < 0) {
5240147868eSNuno Antunes NG_FREE_M(m);
5250147868eSNuno Antunes NG_FREE_ITEM(item);
5260147868eSNuno Antunes return (EINVAL);
5270147868eSNuno Antunes }
5280147868eSNuno Antunes hook = priv->ip;
5290147868eSNuno Antunes } else if (hook == priv->vjip) /* incoming regular packet (bypass) */
5300147868eSNuno Antunes hook = priv->ip;
5310147868eSNuno Antunes else
5320147868eSNuno Antunes panic("%s: unknown hook", __func__);
5330147868eSNuno Antunes
5340147868eSNuno Antunes /* Send result back out */
5350147868eSNuno Antunes NG_FWD_NEW_DATA(error, item, hook, m);
5360147868eSNuno Antunes return (error);
5370147868eSNuno Antunes }
5380147868eSNuno Antunes
5390147868eSNuno Antunes /*
5400147868eSNuno Antunes * Shutdown node
5410147868eSNuno Antunes */
5420147868eSNuno Antunes static int
ng_vjc_shutdown(node_p node)5430147868eSNuno Antunes ng_vjc_shutdown(node_p node)
5440147868eSNuno Antunes {
5450147868eSNuno Antunes const priv_p priv = NG_NODE_PRIVATE(node);
5460147868eSNuno Antunes
5470147868eSNuno Antunes bzero(priv, sizeof(*priv));
5480147868eSNuno Antunes kfree(priv, M_NETGRAPH);
5490147868eSNuno Antunes NG_NODE_SET_PRIVATE(node, NULL);
5500147868eSNuno Antunes NG_NODE_UNREF(node);
5510147868eSNuno Antunes return (0);
5520147868eSNuno Antunes }
5530147868eSNuno Antunes
5540147868eSNuno Antunes /*
5550147868eSNuno Antunes * Hook disconnection
5560147868eSNuno Antunes */
5570147868eSNuno Antunes static int
ng_vjc_disconnect(hook_p hook)5580147868eSNuno Antunes ng_vjc_disconnect(hook_p hook)
5590147868eSNuno Antunes {
5600147868eSNuno Antunes const node_p node = NG_HOOK_NODE(hook);
5610147868eSNuno Antunes const priv_p priv = NG_NODE_PRIVATE(node);
5620147868eSNuno Antunes
5630147868eSNuno Antunes /* Zero out hook pointer */
5640147868eSNuno Antunes if (hook == priv->ip)
5650147868eSNuno Antunes priv->ip = NULL;
5660147868eSNuno Antunes else if (hook == priv->vjcomp)
5670147868eSNuno Antunes priv->vjcomp = NULL;
5680147868eSNuno Antunes else if (hook == priv->vjuncomp)
5690147868eSNuno Antunes priv->vjuncomp = NULL;
5700147868eSNuno Antunes else if (hook == priv->vjip)
5710147868eSNuno Antunes priv->vjip = NULL;
5720147868eSNuno Antunes else
5730147868eSNuno Antunes panic("%s: unknown hook", __func__);
5740147868eSNuno Antunes
5750147868eSNuno Antunes /* Go away if no hooks left */
5760147868eSNuno Antunes if ((NG_NODE_NUMHOOKS(node) == 0)
5770147868eSNuno Antunes && (NG_NODE_IS_VALID(node)))
5780147868eSNuno Antunes ng_rmnode_self(node);
5790147868eSNuno Antunes return (0);
5800147868eSNuno Antunes }
5810147868eSNuno Antunes
5820147868eSNuno Antunes /************************************************************************
5830147868eSNuno Antunes HELPER STUFF
5840147868eSNuno Antunes ************************************************************************/
5850147868eSNuno Antunes
5860147868eSNuno Antunes /*
5870147868eSNuno Antunes * Pull up the full IP and TCP headers of a packet. If packet is not
5880147868eSNuno Antunes * a TCP packet, just pull up the IP header.
5890147868eSNuno Antunes */
5900147868eSNuno Antunes static struct mbuf *
ng_vjc_pulluphdrs(struct mbuf * m,int knownTCP)5910147868eSNuno Antunes ng_vjc_pulluphdrs(struct mbuf *m, int knownTCP)
5920147868eSNuno Antunes {
5930147868eSNuno Antunes struct ip *ip;
5940147868eSNuno Antunes struct tcphdr *tcp;
5950147868eSNuno Antunes int ihlen, thlen;
5960147868eSNuno Antunes
5970147868eSNuno Antunes if (m->m_len < sizeof(*ip) && (m = m_pullup(m, sizeof(*ip))) == NULL)
5980147868eSNuno Antunes return (NULL);
5990147868eSNuno Antunes ip = mtod(m, struct ip *);
6000147868eSNuno Antunes if (!knownTCP && ip->ip_p != IPPROTO_TCP)
6010147868eSNuno Antunes return (m);
6020147868eSNuno Antunes ihlen = ip->ip_hl << 2;
6030147868eSNuno Antunes if (m->m_len < ihlen + sizeof(*tcp)) {
6040147868eSNuno Antunes if ((m = m_pullup(m, ihlen + sizeof(*tcp))) == NULL)
6050147868eSNuno Antunes return (NULL);
6060147868eSNuno Antunes ip = mtod(m, struct ip *);
6070147868eSNuno Antunes }
6080147868eSNuno Antunes tcp = (struct tcphdr *)((u_char *)ip + ihlen);
6090147868eSNuno Antunes thlen = tcp->th_off << 2;
6100147868eSNuno Antunes if (m->m_len < ihlen + thlen)
6110147868eSNuno Antunes m = m_pullup(m, ihlen + thlen);
6120147868eSNuno Antunes return (m);
6130147868eSNuno Antunes }
6140147868eSNuno Antunes
615