xref: /dragonfly/sys/netgraph7/vjc/ng_vjc.c (revision b5523eac)
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