xref: /freebsd/sys/netgraph/ng_vjc.c (revision bef9dae05a72866e79d97d9bff3fc5a2538b4421)
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$
404cf49a43SJulian Elischer  * $Whistle: ng_vjc.c,v 1.14 1999/01/28 23:54:54 julian Exp $
414cf49a43SJulian Elischer  */
424cf49a43SJulian Elischer 
434cf49a43SJulian Elischer /*
444cf49a43SJulian Elischer  * This node performs Van Jacobsen 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/conf.h>
554cf49a43SJulian Elischer #include <sys/errno.h>
564cf49a43SJulian Elischer #include <sys/socket.h>
574cf49a43SJulian Elischer #include <sys/syslog.h>
584cf49a43SJulian Elischer 
594cf49a43SJulian Elischer #include <netgraph/ng_message.h>
604cf49a43SJulian Elischer #include <netgraph/netgraph.h>
614cf49a43SJulian Elischer #include <netgraph/ng_vjc.h>
624cf49a43SJulian Elischer 
634cf49a43SJulian Elischer #include <netinet/in.h>
644cf49a43SJulian Elischer #include <netinet/in_systm.h>
654cf49a43SJulian Elischer #include <netinet/ip.h>
664cf49a43SJulian Elischer #include <netinet/tcp.h>
674cf49a43SJulian Elischer 
684cf49a43SJulian Elischer #include <net/slcompress.h>
694cf49a43SJulian Elischer 
704cf49a43SJulian Elischer /* Check agreement with slcompress.c */
714cf49a43SJulian Elischer #if MAX_STATES != NG_VJC_MAX_CHANNELS
724cf49a43SJulian Elischer #error NG_VJC_MAX_CHANNELS must be the same as MAX_STATES
734cf49a43SJulian Elischer #endif
744cf49a43SJulian Elischer 
754cf49a43SJulian Elischer #define MAX_VJHEADER		16
764cf49a43SJulian Elischer 
774cf49a43SJulian Elischer /* Node private data */
784cf49a43SJulian Elischer struct private {
794cf49a43SJulian Elischer 	struct	ngm_vjc_config conf;
804cf49a43SJulian Elischer 	struct	slcompress slc;
814cf49a43SJulian Elischer 	hook_p	ip;
824cf49a43SJulian Elischer 	hook_p	vjcomp;
834cf49a43SJulian Elischer 	hook_p	vjuncomp;
844cf49a43SJulian Elischer 	hook_p	vjip;
854cf49a43SJulian Elischer };
864cf49a43SJulian Elischer typedef struct private *priv_p;
874cf49a43SJulian Elischer 
884cf49a43SJulian Elischer #define ERROUT(x)	do { error = (x); goto done; } while (0)
894cf49a43SJulian Elischer 
904cf49a43SJulian Elischer /* Netgraph node methods */
914cf49a43SJulian Elischer static int	ng_vjc_constructor(node_p *nodep);
924cf49a43SJulian Elischer static int	ng_vjc_rcvmsg(node_p node, struct ng_mesg *msg,
934cf49a43SJulian Elischer 		  const char *retaddr, struct ng_mesg **resp);
944cf49a43SJulian Elischer static int	ng_vjc_rmnode(node_p node);
954cf49a43SJulian Elischer static int	ng_vjc_newhook(node_p node, hook_p hook, const char *name);
964cf49a43SJulian Elischer static int	ng_vjc_rcvdata(hook_p hook, struct mbuf *m, meta_p t);
974cf49a43SJulian Elischer static int	ng_vjc_disconnect(hook_p hook);
984cf49a43SJulian Elischer 
994cf49a43SJulian Elischer /* Helper stuff */
100bef9dae0SJulian Elischer static struct mbuf *ng_vjc_pulluphdrs(struct mbuf *m);
1014cf49a43SJulian Elischer 
1024cf49a43SJulian Elischer /* Node type descriptor */
1034cf49a43SJulian Elischer static struct ng_type typestruct = {
1044cf49a43SJulian Elischer 	NG_VERSION,
1054cf49a43SJulian Elischer 	NG_VJC_NODE_TYPE,
1064cf49a43SJulian Elischer 	NULL,
1074cf49a43SJulian Elischer 	ng_vjc_constructor,
1084cf49a43SJulian Elischer 	ng_vjc_rcvmsg,
1094cf49a43SJulian Elischer 	ng_vjc_rmnode,
1104cf49a43SJulian Elischer 	ng_vjc_newhook,
1114cf49a43SJulian Elischer 	NULL,
1124cf49a43SJulian Elischer 	NULL,
1134cf49a43SJulian Elischer 	ng_vjc_rcvdata,
1144cf49a43SJulian Elischer 	ng_vjc_rcvdata,
1154cf49a43SJulian Elischer 	ng_vjc_disconnect
1164cf49a43SJulian Elischer };
1174cf49a43SJulian Elischer NETGRAPH_INIT(vjc, &typestruct);
1184cf49a43SJulian Elischer 
1194cf49a43SJulian Elischer /************************************************************************
1204cf49a43SJulian Elischer 			NETGRAPH NODE METHODS
1214cf49a43SJulian Elischer  ************************************************************************/
1224cf49a43SJulian Elischer 
1234cf49a43SJulian Elischer /*
1244cf49a43SJulian Elischer  * Create a new node
1254cf49a43SJulian Elischer  */
1264cf49a43SJulian Elischer static int
1274cf49a43SJulian Elischer ng_vjc_constructor(node_p *nodep)
1284cf49a43SJulian Elischer {
1294cf49a43SJulian Elischer 	priv_p priv;
1304cf49a43SJulian Elischer 	int error;
1314cf49a43SJulian Elischer 
1324cf49a43SJulian Elischer 	/* Allocate private structure */
1334cf49a43SJulian Elischer 	MALLOC(priv, priv_p, sizeof(*priv), M_NETGRAPH, M_WAITOK);
1344cf49a43SJulian Elischer 	if (priv == NULL)
1354cf49a43SJulian Elischer 		return (ENOMEM);
1364cf49a43SJulian Elischer 	bzero(priv, sizeof(*priv));
1374cf49a43SJulian Elischer 
1384cf49a43SJulian Elischer 	/* Call generic node constructor */
1394cf49a43SJulian Elischer 	if ((error = ng_make_node_common(&typestruct, nodep))) {
1404cf49a43SJulian Elischer 		FREE(priv, M_NETGRAPH);
1414cf49a43SJulian Elischer 		return (error);
1424cf49a43SJulian Elischer 	}
1434cf49a43SJulian Elischer 	(*nodep)->private = priv;
1444cf49a43SJulian Elischer 
1454cf49a43SJulian Elischer 	/* Done */
1464cf49a43SJulian Elischer 	return (0);
1474cf49a43SJulian Elischer }
1484cf49a43SJulian Elischer 
1494cf49a43SJulian Elischer /*
1504cf49a43SJulian Elischer  * Add a new hook
1514cf49a43SJulian Elischer  */
1524cf49a43SJulian Elischer static int
1534cf49a43SJulian Elischer ng_vjc_newhook(node_p node, hook_p hook, const char *name)
1544cf49a43SJulian Elischer {
1554cf49a43SJulian Elischer 	const priv_p priv = (priv_p) node->private;
1564cf49a43SJulian Elischer 	hook_p *hookp;
1574cf49a43SJulian Elischer 
1584cf49a43SJulian Elischer 	/* Get hook */
1594cf49a43SJulian Elischer 	if (!strcmp(name, NG_VJC_HOOK_IP))
1604cf49a43SJulian Elischer 		hookp = &priv->ip;
1614cf49a43SJulian Elischer 	else if (!strcmp(name, NG_VJC_HOOK_VJCOMP))
1624cf49a43SJulian Elischer 		hookp = &priv->vjcomp;
1634cf49a43SJulian Elischer 	else if (!strcmp(name, NG_VJC_HOOK_VJUNCOMP))
1644cf49a43SJulian Elischer 		hookp = &priv->vjuncomp;
1654cf49a43SJulian Elischer 	else if (!strcmp(name, NG_VJC_HOOK_VJIP))
1664cf49a43SJulian Elischer 		hookp = &priv->vjip;
1674cf49a43SJulian Elischer 	else
1684cf49a43SJulian Elischer 		return (EINVAL);
1694cf49a43SJulian Elischer 
1704cf49a43SJulian Elischer 	/* See if already connected */
1714cf49a43SJulian Elischer 	if (*hookp)
1724cf49a43SJulian Elischer 		return (EISCONN);
1734cf49a43SJulian Elischer 
1744cf49a43SJulian Elischer 	/* OK */
1754cf49a43SJulian Elischer 	*hookp = hook;
1764cf49a43SJulian Elischer 	return (0);
1774cf49a43SJulian Elischer }
1784cf49a43SJulian Elischer 
1794cf49a43SJulian Elischer /*
1804cf49a43SJulian Elischer  * Receive a control message
1814cf49a43SJulian Elischer  */
1824cf49a43SJulian Elischer static int
1834cf49a43SJulian Elischer ng_vjc_rcvmsg(node_p node, struct ng_mesg *msg,
1844cf49a43SJulian Elischer 	      const char *raddr, struct ng_mesg **rptr)
1854cf49a43SJulian Elischer {
1864cf49a43SJulian Elischer 	const priv_p priv = (priv_p) node->private;
1874cf49a43SJulian Elischer 	struct ng_mesg *resp = NULL;
1884cf49a43SJulian Elischer 	int error = 0;
1894cf49a43SJulian Elischer 
1904cf49a43SJulian Elischer 	/* Check type cookie */
1914cf49a43SJulian Elischer 	switch (msg->header.typecookie) {
1924cf49a43SJulian Elischer 	case NGM_VJC_COOKIE:
1934cf49a43SJulian Elischer 		switch (msg->header.cmd) {
194bef9dae0SJulian Elischer 		case NGM_VJC_SET_CONFIG:
1954cf49a43SJulian Elischer 		    {
1964cf49a43SJulian Elischer 			struct ngm_vjc_config *const c =
1974cf49a43SJulian Elischer 				(struct ngm_vjc_config *) msg->data;
1984cf49a43SJulian Elischer 
199bef9dae0SJulian Elischer 			if (msg->header.arglen != sizeof(*c))
200bef9dae0SJulian Elischer 				ERROUT(EINVAL);
201bef9dae0SJulian Elischer 			if ((priv->conf.enableComp || priv->conf.enableDecomp)
202bef9dae0SJulian Elischer 			    && (c->enableComp || c->enableDecomp))
203bef9dae0SJulian Elischer 				ERROUT(EALREADY);
204bef9dae0SJulian Elischer 			if (c->enableComp) {
205bef9dae0SJulian Elischer 				if (c->numChannels > NG_VJC_MAX_CHANNELS
2064cf49a43SJulian Elischer 				    || c->numChannels < NG_VJC_MIN_CHANNELS)
2074cf49a43SJulian Elischer 					ERROUT(EINVAL);
208bef9dae0SJulian Elischer 			} else {
209bef9dae0SJulian Elischer 				c->numChannels = NG_VJC_MAX_CHANNELS;
210bef9dae0SJulian Elischer 			}
211bef9dae0SJulian Elischer 			if (c->enableComp != 0 || c->enableDecomp != 0) {
2124cf49a43SJulian Elischer 				bzero(&priv->slc, sizeof(priv->slc));
2134cf49a43SJulian Elischer 				sl_compress_init(&priv->slc, c->numChannels);
2144cf49a43SJulian Elischer 			}
2154cf49a43SJulian Elischer 			priv->conf = *c;
2164cf49a43SJulian Elischer 			break;
2174cf49a43SJulian Elischer 		    }
2184cf49a43SJulian Elischer 		case NGM_VJC_GET_STATE:
2194cf49a43SJulian Elischer 			NG_MKRESPONSE(resp, msg, sizeof(priv->slc), M_NOWAIT);
2204cf49a43SJulian Elischer 			if (resp == NULL)
2214cf49a43SJulian Elischer 				ERROUT(ENOMEM);
2224cf49a43SJulian Elischer 			*((struct slcompress *) resp->data) = priv->slc;
2234cf49a43SJulian Elischer 			break;
2244cf49a43SJulian Elischer 		case NGM_VJC_CLR_STATS:
2254cf49a43SJulian Elischer 			priv->slc.sls_packets = 0;
2264cf49a43SJulian Elischer 			priv->slc.sls_compressed = 0;
2274cf49a43SJulian Elischer 			priv->slc.sls_searches = 0;
2284cf49a43SJulian Elischer 			priv->slc.sls_misses = 0;
2294cf49a43SJulian Elischer 			priv->slc.sls_uncompressedin = 0;
2304cf49a43SJulian Elischer 			priv->slc.sls_compressedin = 0;
2314cf49a43SJulian Elischer 			priv->slc.sls_errorin = 0;
2324cf49a43SJulian Elischer 			priv->slc.sls_tossed = 0;
2334cf49a43SJulian Elischer 			break;
2344cf49a43SJulian Elischer 		case NGM_VJC_RECV_ERROR:
2354cf49a43SJulian Elischer 			priv->slc.flags |= SLF_TOSS;
2364cf49a43SJulian Elischer 			break;
2374cf49a43SJulian Elischer 		default:
2384cf49a43SJulian Elischer 			error = EINVAL;
2394cf49a43SJulian Elischer 			break;
2404cf49a43SJulian Elischer 		}
2414cf49a43SJulian Elischer 		break;
2424cf49a43SJulian Elischer 	default:
2434cf49a43SJulian Elischer 		error = EINVAL;
2444cf49a43SJulian Elischer 		break;
2454cf49a43SJulian Elischer 	}
2464cf49a43SJulian Elischer 	if (rptr)
2474cf49a43SJulian Elischer 		*rptr = resp;
2484cf49a43SJulian Elischer 	else if (resp)
2494cf49a43SJulian Elischer 		FREE(resp, M_NETGRAPH);
2504cf49a43SJulian Elischer 
2514cf49a43SJulian Elischer done:
2524cf49a43SJulian Elischer 	FREE(msg, M_NETGRAPH);
2534cf49a43SJulian Elischer 	return (error);
2544cf49a43SJulian Elischer }
2554cf49a43SJulian Elischer 
2564cf49a43SJulian Elischer /*
2574cf49a43SJulian Elischer  * Receive data
2584cf49a43SJulian Elischer  */
2594cf49a43SJulian Elischer static int
2604cf49a43SJulian Elischer ng_vjc_rcvdata(hook_p hook, struct mbuf *m, meta_p meta)
2614cf49a43SJulian Elischer {
2624cf49a43SJulian Elischer 	const node_p node = hook->node;
2634cf49a43SJulian Elischer 	const priv_p priv = (priv_p) node->private;
2644cf49a43SJulian Elischer 	int error = 0;
2654cf49a43SJulian Elischer 
2664cf49a43SJulian Elischer 	if (hook == priv->ip) {			/* outgoing packet */
2674cf49a43SJulian Elischer 		u_int   type;
2684cf49a43SJulian Elischer 
269bef9dae0SJulian Elischer 		if (!priv->conf.enableComp)	/* compression not enabled */
2704cf49a43SJulian Elischer 			type = TYPE_IP;
2714cf49a43SJulian Elischer 		else {
2724cf49a43SJulian Elischer 			struct ip *ip;
2734cf49a43SJulian Elischer 
274bef9dae0SJulian Elischer 			if ((m = ng_vjc_pulluphdrs(m)) == NULL)
2754cf49a43SJulian Elischer 				ERROUT(ENOBUFS);
2764cf49a43SJulian Elischer 			ip = mtod(m, struct ip *);
2774cf49a43SJulian Elischer 			type = (ip->ip_p == IPPROTO_TCP) ?
2784cf49a43SJulian Elischer 			    sl_compress_tcp(m, ip,
2794cf49a43SJulian Elischer 				&priv->slc, priv->conf.compressCID) : TYPE_IP;
2804cf49a43SJulian Elischer 		}
2814cf49a43SJulian Elischer 		switch (type) {
2824cf49a43SJulian Elischer 		case TYPE_IP:
2834cf49a43SJulian Elischer 			hook = priv->vjip;
2844cf49a43SJulian Elischer 			break;
2854cf49a43SJulian Elischer 		case TYPE_UNCOMPRESSED_TCP:
2864cf49a43SJulian Elischer 			hook = priv->vjuncomp;
2874cf49a43SJulian Elischer 			break;
2884cf49a43SJulian Elischer 		case TYPE_COMPRESSED_TCP:
2894cf49a43SJulian Elischer 			hook = priv->vjcomp;
2904cf49a43SJulian Elischer 			break;
2914cf49a43SJulian Elischer 		default:
2924cf49a43SJulian Elischer 			panic(__FUNCTION__);
2934cf49a43SJulian Elischer 		}
2944cf49a43SJulian Elischer 	} else if (hook == priv->vjcomp) {	/* incoming compressed packet */
2954cf49a43SJulian Elischer 		int     vjlen;
2964cf49a43SJulian Elischer 		u_int   hlen;
2974cf49a43SJulian Elischer 		u_char *hdr;
2984cf49a43SJulian Elischer 		struct mbuf *mp;
2994cf49a43SJulian Elischer 
300bef9dae0SJulian Elischer 		/* Are we decompressing? */
301bef9dae0SJulian Elischer 		if (!priv->conf.enableDecomp) {
3024cf49a43SJulian Elischer 			m_freem(m);
3034cf49a43SJulian Elischer 			m = NULL;
3044cf49a43SJulian Elischer 			ERROUT(ENETDOWN);
3054cf49a43SJulian Elischer 		}
3064cf49a43SJulian Elischer 
3074cf49a43SJulian Elischer 		/* Uncompress packet to reconstruct TCP/IP header */
308bef9dae0SJulian Elischer 		if (m->m_len < MAX_VJHEADER && !(m = m_pullup(m, MAX_VJHEADER)))
3094cf49a43SJulian Elischer 			ERROUT(ENOBUFS);
3104cf49a43SJulian Elischer 		vjlen = sl_uncompress_tcp_core(mtod(m, u_char *),
3114cf49a43SJulian Elischer 		    m->m_len, m->m_pkthdr.len, TYPE_COMPRESSED_TCP,
3124cf49a43SJulian Elischer 		    &priv->slc, &hdr, &hlen);
3134cf49a43SJulian Elischer 		if (vjlen <= 0) {
3144cf49a43SJulian Elischer 			m_freem(m);
3154cf49a43SJulian Elischer 			m = NULL;
3164cf49a43SJulian Elischer 			ERROUT(EINVAL);
3174cf49a43SJulian Elischer 		}
3184cf49a43SJulian Elischer 
3194cf49a43SJulian Elischer 		/* Copy the reconstructed TCP/IP headers into a new mbuf */
3204cf49a43SJulian Elischer 		MGETHDR(mp, M_DONTWAIT, MT_DATA);
3214cf49a43SJulian Elischer 		if (!mp)
3224cf49a43SJulian Elischer 			goto compfailmem;
3234cf49a43SJulian Elischer 		mp->m_len = 0;
3244cf49a43SJulian Elischer 		mp->m_next = NULL;
3254cf49a43SJulian Elischer 		if (hlen > MHLEN) {
3264cf49a43SJulian Elischer 			MCLGET(mp, M_DONTWAIT);
3274cf49a43SJulian Elischer 			if (M_TRAILINGSPACE(mp) < hlen) {
3284cf49a43SJulian Elischer 				m_freem(mp);	/* can't get a cluster, drop */
3294cf49a43SJulian Elischer compfailmem:
3304cf49a43SJulian Elischer 				m_freem(m);
3314cf49a43SJulian Elischer 				m = NULL;
3324cf49a43SJulian Elischer 				ERROUT(ENOBUFS);
3334cf49a43SJulian Elischer 			}
3344cf49a43SJulian Elischer 		}
3354cf49a43SJulian Elischer 		bcopy(hdr, mtod(mp, u_char *), hlen);
3364cf49a43SJulian Elischer 		mp->m_len = hlen;
3374cf49a43SJulian Elischer 
3384cf49a43SJulian Elischer 		/* Stick header and rest of packet together */
3394cf49a43SJulian Elischer 		m->m_data += vjlen;
3404cf49a43SJulian Elischer 		m->m_len -= vjlen;
3414cf49a43SJulian Elischer 		if (m->m_len <= M_TRAILINGSPACE(mp)) {
3424cf49a43SJulian Elischer 			bcopy(mtod(m, u_char *),
3434cf49a43SJulian Elischer 			    mtod(mp, u_char *) + mp->m_len, m->m_len);
3444cf49a43SJulian Elischer 			mp->m_len += m->m_len;
3454cf49a43SJulian Elischer 			MFREE(m, mp->m_next);
3464cf49a43SJulian Elischer 		} else
3474cf49a43SJulian Elischer 			mp->m_next = m;
3484cf49a43SJulian Elischer 		m = mp;
3494cf49a43SJulian Elischer 		hook = priv->ip;
3504cf49a43SJulian Elischer 	} else if (hook == priv->vjuncomp) {	/* incoming uncompressed pkt */
3514cf49a43SJulian Elischer 		u_char *hdr;
352bef9dae0SJulian Elischer 		u_int hlen;
3534cf49a43SJulian Elischer 
354bef9dae0SJulian Elischer 		/* Are we decompressing? */
355bef9dae0SJulian Elischer 		if (!priv->conf.enableDecomp) {
3564cf49a43SJulian Elischer 			m_freem(m);
3574cf49a43SJulian Elischer 			m = NULL;
3584cf49a43SJulian Elischer 			ERROUT(ENETDOWN);
3594cf49a43SJulian Elischer 		}
3604cf49a43SJulian Elischer 
3614cf49a43SJulian Elischer 		/* Run packet through uncompressor */
362bef9dae0SJulian Elischer 		if ((m = ng_vjc_pulluphdrs(m)) == NULL)
3634cf49a43SJulian Elischer 			ERROUT(ENOBUFS);
3644cf49a43SJulian Elischer 		if (sl_uncompress_tcp_core(mtod(m, u_char *),
3654cf49a43SJulian Elischer 		    m->m_len, m->m_pkthdr.len, TYPE_UNCOMPRESSED_TCP,
3664cf49a43SJulian Elischer 		    &priv->slc, &hdr, &hlen) < 0) {
3674cf49a43SJulian Elischer 			m_freem(m);
3684cf49a43SJulian Elischer 			m = NULL;
3694cf49a43SJulian Elischer 			ERROUT(EINVAL);
3704cf49a43SJulian Elischer 		}
3714cf49a43SJulian Elischer 		hook = priv->ip;
3724cf49a43SJulian Elischer 	} else if (hook == priv->vjip)	/* incoming regular packet (bypass) */
3734cf49a43SJulian Elischer 		hook = priv->ip;
3744cf49a43SJulian Elischer 	else
3754cf49a43SJulian Elischer 		panic(__FUNCTION__);
3764cf49a43SJulian Elischer 
3774cf49a43SJulian Elischer done:
3784cf49a43SJulian Elischer 	if (m)
3794cf49a43SJulian Elischer 		NG_SEND_DATA(error, hook, m, meta);
3804cf49a43SJulian Elischer 	else
3814cf49a43SJulian Elischer 		NG_FREE_META(meta);
3824cf49a43SJulian Elischer 	return (error);
3834cf49a43SJulian Elischer }
3844cf49a43SJulian Elischer 
3854cf49a43SJulian Elischer /*
3864cf49a43SJulian Elischer  * Shutdown node
3874cf49a43SJulian Elischer  */
3884cf49a43SJulian Elischer static int
3894cf49a43SJulian Elischer ng_vjc_rmnode(node_p node)
3904cf49a43SJulian Elischer {
3914cf49a43SJulian Elischer 	const priv_p priv = (priv_p) node->private;
3924cf49a43SJulian Elischer 
3934cf49a43SJulian Elischer 	node->flags |= NG_INVALID;
3944cf49a43SJulian Elischer 	ng_cutlinks(node);
3954cf49a43SJulian Elischer 	ng_unname(node);
3964cf49a43SJulian Elischer 	bzero(priv, sizeof(*priv));
3974cf49a43SJulian Elischer 	FREE(priv, M_NETGRAPH);
3984cf49a43SJulian Elischer 	node->private = NULL;
3994cf49a43SJulian Elischer 	ng_unref(node);
4004cf49a43SJulian Elischer 	return (0);
4014cf49a43SJulian Elischer }
4024cf49a43SJulian Elischer 
4034cf49a43SJulian Elischer /*
4044cf49a43SJulian Elischer  * Hook disconnection
4054cf49a43SJulian Elischer  */
4064cf49a43SJulian Elischer static int
4074cf49a43SJulian Elischer ng_vjc_disconnect(hook_p hook)
4084cf49a43SJulian Elischer {
4094cf49a43SJulian Elischer 	if (hook->node->numhooks == 0)
4104cf49a43SJulian Elischer 		ng_rmnode(hook->node);
4114cf49a43SJulian Elischer 	return (0);
4124cf49a43SJulian Elischer }
4134cf49a43SJulian Elischer 
4144cf49a43SJulian Elischer /************************************************************************
4154cf49a43SJulian Elischer 			HELPER STUFF
4164cf49a43SJulian Elischer  ************************************************************************/
4174cf49a43SJulian Elischer 
4184cf49a43SJulian Elischer /*
419bef9dae0SJulian Elischer  * Pull up the full IP and TCP headers of a packet. If packet is not
4204cf49a43SJulian Elischer  * a TCP packet, just pull up the IP header.
4214cf49a43SJulian Elischer  */
4224cf49a43SJulian Elischer static struct mbuf *
423bef9dae0SJulian Elischer ng_vjc_pulluphdrs(struct mbuf *m)
4244cf49a43SJulian Elischer {
4254cf49a43SJulian Elischer 	struct ip *ip;
4264cf49a43SJulian Elischer 	struct tcphdr *tcp;
4274cf49a43SJulian Elischer 	int ihlen, thlen;
4284cf49a43SJulian Elischer 
429bef9dae0SJulian Elischer 	if (m->m_len < sizeof(*ip) && !(m = m_pullup(m, sizeof(*ip))))
4304cf49a43SJulian Elischer 		return (NULL);
4314cf49a43SJulian Elischer 	ip = mtod(m, struct ip *);
4324cf49a43SJulian Elischer 	if (ip->ip_p != IPPROTO_TCP)
4334cf49a43SJulian Elischer 		return (m);
434bef9dae0SJulian Elischer 	ihlen = ip->ip_hl << 2;
435bef9dae0SJulian Elischer 	if (m->m_len < ihlen + sizeof(*tcp)) {
4364cf49a43SJulian Elischer 		if (!(m = m_pullup(m, ihlen + sizeof(*tcp))))
4374cf49a43SJulian Elischer 			return (NULL);
4384cf49a43SJulian Elischer 		ip = mtod(m, struct ip *);
4394cf49a43SJulian Elischer 	}
4404cf49a43SJulian Elischer 	tcp = (struct tcphdr *) ((u_char *) ip + ihlen);
441bef9dae0SJulian Elischer 	thlen = tcp->th_off << 2;
442bef9dae0SJulian Elischer 	if (m->m_len < ihlen + thlen)
4434cf49a43SJulian Elischer 		m = m_pullup(m, ihlen + thlen);
4444cf49a43SJulian Elischer 	return (m);
4454cf49a43SJulian Elischer }
4464cf49a43SJulian Elischer 
447