152419Sjulian 252419Sjulian/* 352419Sjulian * ng_vjc.c 4139823Simp */ 5139823Simp 6139823Simp/*- 752419Sjulian * Copyright (c) 1996-1999 Whistle Communications, Inc. 852419Sjulian * All rights reserved. 952419Sjulian * 1052419Sjulian * Subject to the following obligations and disclaimer of warranty, use and 1152419Sjulian * redistribution of this software, in source or object code forms, with or 1252419Sjulian * without modifications are expressly permitted by Whistle Communications; 1352419Sjulian * provided, however, that: 1452419Sjulian * 1. Any and all reproductions of the source or object code must include the 1552419Sjulian * copyright notice above and the following disclaimer of warranties; and 1652419Sjulian * 2. No rights are granted, in any manner or form, to use Whistle 1752419Sjulian * Communications, Inc. trademarks, including the mark "WHISTLE 1852419Sjulian * COMMUNICATIONS" on advertising, endorsements, or otherwise except as 1952419Sjulian * such appears in the above copyright notice or in the software. 2052419Sjulian * 2152419Sjulian * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND 2252419Sjulian * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO 2352419Sjulian * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, 2452419Sjulian * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF 2552419Sjulian * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. 2652419Sjulian * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY 2752419Sjulian * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS 2852419Sjulian * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. 2952419Sjulian * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES 3052419Sjulian * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING 3152419Sjulian * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 3252419Sjulian * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR 3352419Sjulian * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY 3452419Sjulian * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3552419Sjulian * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 3652419Sjulian * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY 3752419Sjulian * OF SUCH DAMAGE. 3852419Sjulian * 3967506Sjulian * Author: Archie Cobbs <archie@freebsd.org> 4052419Sjulian * 4152419Sjulian * $FreeBSD$ 4252752Sjulian * $Whistle: ng_vjc.c,v 1.17 1999/11/01 09:24:52 julian Exp $ 4352419Sjulian */ 4452419Sjulian 4552419Sjulian/* 4664287Sarchie * This node performs Van Jacobson IP header (de)compression. 4752419Sjulian * You must have included net/slcompress.c in your kernel compilation. 4852419Sjulian */ 4952419Sjulian 5052419Sjulian#include <sys/param.h> 5152419Sjulian#include <sys/systm.h> 5252419Sjulian#include <sys/errno.h> 5352419Sjulian#include <sys/kernel.h> 5452419Sjulian#include <sys/mbuf.h> 5552419Sjulian#include <sys/malloc.h> 5652419Sjulian#include <sys/errno.h> 5752419Sjulian 5852419Sjulian#include <netgraph/ng_message.h> 5952419Sjulian#include <netgraph/netgraph.h> 6064509Sarchie#include <netgraph/ng_parse.h> 6152419Sjulian#include <netgraph/ng_vjc.h> 6252419Sjulian 6352419Sjulian#include <netinet/in.h> 6452419Sjulian#include <netinet/in_systm.h> 6552419Sjulian#include <netinet/ip.h> 6652419Sjulian#include <netinet/tcp.h> 6752419Sjulian 6852419Sjulian#include <net/slcompress.h> 6952419Sjulian 7052419Sjulian/* Check agreement with slcompress.c */ 7152419Sjulian#if MAX_STATES != NG_VJC_MAX_CHANNELS 7252419Sjulian#error NG_VJC_MAX_CHANNELS must be the same as MAX_STATES 7352419Sjulian#endif 7452419Sjulian 7553190Sarchie/* Maximum length of a compressed TCP VJ header */ 7653190Sarchie#define MAX_VJHEADER 19 7752419Sjulian 7852419Sjulian/* Node private data */ 7953406Sarchiestruct ng_vjc_private { 8052419Sjulian struct ngm_vjc_config conf; 8152419Sjulian struct slcompress slc; 8252419Sjulian hook_p ip; 8352419Sjulian hook_p vjcomp; 8452419Sjulian hook_p vjuncomp; 8552419Sjulian hook_p vjip; 8652419Sjulian}; 8753406Sarchietypedef struct ng_vjc_private *priv_p; 8852419Sjulian 8952419Sjulian#define ERROUT(x) do { error = (x); goto done; } while (0) 9052419Sjulian 9152419Sjulian/* Netgraph node methods */ 9252752Sjulianstatic ng_constructor_t ng_vjc_constructor; 9352752Sjulianstatic ng_rcvmsg_t ng_vjc_rcvmsg; 9470700Sjulianstatic ng_shutdown_t ng_vjc_shutdown; 9552752Sjulianstatic ng_newhook_t ng_vjc_newhook; 9652752Sjulianstatic ng_rcvdata_t ng_vjc_rcvdata; 9752752Sjulianstatic ng_disconnect_t ng_vjc_disconnect; 9852419Sjulian 9952419Sjulian/* Helper stuff */ 10053190Sarchiestatic struct mbuf *ng_vjc_pulluphdrs(struct mbuf *m, int knownTCP); 10152419Sjulian 10264509Sarchie/* Parse type for struct ngm_vjc_config */ 10397685Sarchiestatic const struct ng_parse_struct_field ng_vjc_config_type_fields[] 10464509Sarchie = NG_VJC_CONFIG_TYPE_INFO; 10564509Sarchiestatic const struct ng_parse_type ng_vjc_config_type = { 10664509Sarchie &ng_parse_struct_type, 10797685Sarchie &ng_vjc_config_type_fields 10864509Sarchie}; 10964509Sarchie 11064509Sarchie/* Parse type for the 'last_cs' and 'cs_next' fields in struct slcompress, 11164509Sarchie which are pointers converted to integer indices, so parse them that way. */ 112153069Sru#ifndef __LP64__ 11364509Sarchie#define NG_VJC_TSTATE_PTR_TYPE &ng_parse_uint32_type 114153069Sru#else 11564509Sarchie#define NG_VJC_TSTATE_PTR_TYPE &ng_parse_uint64_type 11664509Sarchie#endif 11764509Sarchie 11864509Sarchie/* Parse type for the 'cs_hdr' field in a struct cstate. Ideally we would 11964509Sarchie like to use a 'struct ip' type instead of a simple array of bytes. */ 12064509Sarchiestatic const struct ng_parse_fixedarray_info ng_vjc_cs_hdr_type_info = { 12164509Sarchie &ng_parse_hint8_type, 12264509Sarchie MAX_HDR 12364509Sarchie}; 12464509Sarchiestatic const struct ng_parse_type ng_vjc_cs_hdr_type = { 12564509Sarchie &ng_parse_fixedarray_type, 12664509Sarchie &ng_vjc_cs_hdr_type_info 12764509Sarchie}; 12864509Sarchie 12964509Sarchie/* Parse type for a struct cstate */ 13097685Sarchiestatic const struct ng_parse_struct_field ng_vjc_cstate_type_fields[] = { 13164509Sarchie { "cs_next", NG_VJC_TSTATE_PTR_TYPE }, 13264509Sarchie { "cs_hlen", &ng_parse_uint16_type }, 13364509Sarchie { "cs_id", &ng_parse_uint8_type }, 13464509Sarchie { "cs_filler", &ng_parse_uint8_type }, 13564509Sarchie { "cs_hdr", &ng_vjc_cs_hdr_type }, 13697685Sarchie { NULL } 13764509Sarchie}; 13864509Sarchiestatic const struct ng_parse_type ng_vjc_cstate_type = { 13964509Sarchie &ng_parse_struct_type, 14097685Sarchie &ng_vjc_cstate_type_fields 14164509Sarchie}; 14264509Sarchie 14364509Sarchie/* Parse type for an array of MAX_STATES struct cstate's, ie, tstate & rstate */ 14464509Sarchiestatic const struct ng_parse_fixedarray_info ng_vjc_cstatearray_type_info = { 14564509Sarchie &ng_vjc_cstate_type, 14664509Sarchie MAX_STATES 14764509Sarchie}; 14864509Sarchiestatic const struct ng_parse_type ng_vjc_cstatearray_type = { 14964509Sarchie &ng_parse_fixedarray_type, 15064509Sarchie &ng_vjc_cstatearray_type_info 15164509Sarchie}; 15264509Sarchie 15364509Sarchie/* Parse type for struct slcompress. Keep this in sync with the 15464509Sarchie definition of struct slcompress defined in <net/slcompress.h> */ 15597685Sarchiestatic const struct ng_parse_struct_field ng_vjc_slcompress_type_fields[] = { 15664509Sarchie { "last_cs", NG_VJC_TSTATE_PTR_TYPE }, 15764509Sarchie { "last_recv", &ng_parse_uint8_type }, 15864509Sarchie { "last_xmit", &ng_parse_uint8_type }, 15964509Sarchie { "flags", &ng_parse_hint16_type }, 16064509Sarchie#ifndef SL_NO_STATS 16164509Sarchie { "sls_packets", &ng_parse_uint32_type }, 16264509Sarchie { "sls_compressed", &ng_parse_uint32_type }, 16364509Sarchie { "sls_searches", &ng_parse_uint32_type }, 16464509Sarchie { "sls_misses", &ng_parse_uint32_type }, 16564509Sarchie { "sls_uncompressedin", &ng_parse_uint32_type }, 16664509Sarchie { "sls_compressedin", &ng_parse_uint32_type }, 16764509Sarchie { "sls_errorin", &ng_parse_uint32_type }, 16864509Sarchie { "sls_tossed", &ng_parse_uint32_type }, 16964509Sarchie#endif 17064509Sarchie { "tstate", &ng_vjc_cstatearray_type }, 17164509Sarchie { "rstate", &ng_vjc_cstatearray_type }, 17297685Sarchie { NULL } 17364509Sarchie}; 17464509Sarchiestatic const struct ng_parse_type ng_vjc_slcompress_type = { 17564509Sarchie &ng_parse_struct_type, 17697685Sarchie &ng_vjc_slcompress_type_fields 17764509Sarchie}; 17864509Sarchie 17964509Sarchie/* List of commands and how to convert arguments to/from ASCII */ 18064509Sarchiestatic const struct ng_cmdlist ng_vjc_cmds[] = { 18164509Sarchie { 18264509Sarchie NGM_VJC_COOKIE, 18364509Sarchie NGM_VJC_SET_CONFIG, 18464509Sarchie "setconfig", 18564509Sarchie &ng_vjc_config_type, 18664509Sarchie NULL 18764509Sarchie }, 18864509Sarchie { 18964509Sarchie NGM_VJC_COOKIE, 19064509Sarchie NGM_VJC_GET_CONFIG, 19164509Sarchie "getconfig", 19264509Sarchie NULL, 19364509Sarchie &ng_vjc_config_type, 19464509Sarchie }, 19564509Sarchie { 19664509Sarchie NGM_VJC_COOKIE, 19764509Sarchie NGM_VJC_GET_STATE, 19864509Sarchie "getstate", 19964509Sarchie NULL, 20064509Sarchie &ng_vjc_slcompress_type, 20164509Sarchie }, 20264509Sarchie { 20364509Sarchie NGM_VJC_COOKIE, 20464509Sarchie NGM_VJC_CLR_STATS, 20564509Sarchie "clrstats", 20664509Sarchie NULL, 20764509Sarchie NULL, 20864509Sarchie }, 20964509Sarchie { 21064509Sarchie NGM_VJC_COOKIE, 21164509Sarchie NGM_VJC_RECV_ERROR, 21264509Sarchie "recverror", 21364509Sarchie NULL, 21464509Sarchie NULL, 21564509Sarchie }, 21664509Sarchie { 0 } 21764509Sarchie}; 21864509Sarchie 21952419Sjulian/* Node type descriptor */ 22064509Sarchiestatic struct ng_type ng_vjc_typestruct = { 221129823Sjulian .version = NG_ABI_VERSION, 222129823Sjulian .name = NG_VJC_NODE_TYPE, 223129823Sjulian .constructor = ng_vjc_constructor, 224129823Sjulian .rcvmsg = ng_vjc_rcvmsg, 225129823Sjulian .shutdown = ng_vjc_shutdown, 226129823Sjulian .newhook = ng_vjc_newhook, 227129823Sjulian .rcvdata = ng_vjc_rcvdata, 228129823Sjulian .disconnect = ng_vjc_disconnect, 229129823Sjulian .cmdlist = ng_vjc_cmds, 23052419Sjulian}; 23164509SarchieNETGRAPH_INIT(vjc, &ng_vjc_typestruct); 23252419Sjulian 23352419Sjulian/************************************************************************ 23452419Sjulian NETGRAPH NODE METHODS 23552419Sjulian ************************************************************************/ 23652419Sjulian 23752419Sjulian/* 23852419Sjulian * Create a new node 23952419Sjulian */ 24052419Sjulianstatic int 24170700Sjulianng_vjc_constructor(node_p node) 24252419Sjulian{ 24352419Sjulian priv_p priv; 24452419Sjulian 24552419Sjulian /* Allocate private structure */ 246220768Sglebius priv = malloc(sizeof(*priv), M_NETGRAPH, M_WAITOK | M_ZERO); 24752419Sjulian 24870784Sjulian NG_NODE_SET_PRIVATE(node, priv); 24952419Sjulian 250186907Smav /* slcompress is not thread-safe. Protect it's state here. */ 251186907Smav NG_NODE_FORCE_WRITER(node); 252186907Smav 25352419Sjulian /* Done */ 25452419Sjulian return (0); 25552419Sjulian} 25652419Sjulian 25752419Sjulian/* 25852419Sjulian * Add a new hook 25952419Sjulian */ 26052419Sjulianstatic int 26152419Sjulianng_vjc_newhook(node_p node, hook_p hook, const char *name) 26252419Sjulian{ 26370784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 26452419Sjulian hook_p *hookp; 26552419Sjulian 26652419Sjulian /* Get hook */ 26753076Sarchie if (strcmp(name, NG_VJC_HOOK_IP) == 0) 26852419Sjulian hookp = &priv->ip; 26953076Sarchie else if (strcmp(name, NG_VJC_HOOK_VJCOMP) == 0) 27052419Sjulian hookp = &priv->vjcomp; 27153076Sarchie else if (strcmp(name, NG_VJC_HOOK_VJUNCOMP) == 0) 27252419Sjulian hookp = &priv->vjuncomp; 27353076Sarchie else if (strcmp(name, NG_VJC_HOOK_VJIP) == 0) 27452419Sjulian hookp = &priv->vjip; 27552419Sjulian else 27652419Sjulian return (EINVAL); 27752419Sjulian 27852419Sjulian /* See if already connected */ 27952419Sjulian if (*hookp) 28052419Sjulian return (EISCONN); 28152419Sjulian 28252419Sjulian /* OK */ 28352419Sjulian *hookp = hook; 28452419Sjulian return (0); 28552419Sjulian} 28652419Sjulian 28752419Sjulian/* 28852419Sjulian * Receive a control message 28952419Sjulian */ 29052419Sjulianstatic int 29170700Sjulianng_vjc_rcvmsg(node_p node, item_p item, hook_p lasthook) 29252419Sjulian{ 29370784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 29452419Sjulian struct ng_mesg *resp = NULL; 29552419Sjulian int error = 0; 29670700Sjulian struct ng_mesg *msg; 29752419Sjulian 29870700Sjulian NGI_GET_MSG(item, msg); 29952419Sjulian /* Check type cookie */ 30052419Sjulian switch (msg->header.typecookie) { 30152419Sjulian case NGM_VJC_COOKIE: 30252419Sjulian switch (msg->header.cmd) { 30352539Sjulian case NGM_VJC_SET_CONFIG: 30452419Sjulian { 30552419Sjulian struct ngm_vjc_config *const c = 30652419Sjulian (struct ngm_vjc_config *) msg->data; 30752419Sjulian 30852539Sjulian if (msg->header.arglen != sizeof(*c)) 30952419Sjulian ERROUT(EINVAL); 31052539Sjulian if ((priv->conf.enableComp || priv->conf.enableDecomp) 31152539Sjulian && (c->enableComp || c->enableDecomp)) 31252419Sjulian ERROUT(EALREADY); 31352539Sjulian if (c->enableComp) { 31453076Sarchie if (c->maxChannel > NG_VJC_MAX_CHANNELS - 1 31553076Sarchie || c->maxChannel < NG_VJC_MIN_CHANNELS - 1) 31652539Sjulian ERROUT(EINVAL); 31753190Sarchie } else 31853190Sarchie c->maxChannel = NG_VJC_MAX_CHANNELS - 1; 31952539Sjulian if (c->enableComp != 0 || c->enableDecomp != 0) { 32052419Sjulian bzero(&priv->slc, sizeof(priv->slc)); 32153076Sarchie sl_compress_init(&priv->slc, c->maxChannel); 32252419Sjulian } 32352419Sjulian priv->conf = *c; 32452419Sjulian break; 32552419Sjulian } 32664509Sarchie case NGM_VJC_GET_CONFIG: 32764509Sarchie { 32864509Sarchie struct ngm_vjc_config *conf; 32964509Sarchie 33064509Sarchie NG_MKRESPONSE(resp, msg, sizeof(*conf), M_NOWAIT); 33164509Sarchie if (resp == NULL) 33264509Sarchie ERROUT(ENOMEM); 33364509Sarchie conf = (struct ngm_vjc_config *)resp->data; 33464509Sarchie *conf = priv->conf; 33564509Sarchie break; 33664509Sarchie } 33752419Sjulian case NGM_VJC_GET_STATE: 33864509Sarchie { 33964509Sarchie const struct slcompress *const sl0 = &priv->slc; 34064509Sarchie struct slcompress *sl; 34164509Sarchie u_int16_t index; 34264509Sarchie int i; 34364509Sarchie 34464509Sarchie /* Get response structure */ 34564509Sarchie NG_MKRESPONSE(resp, msg, sizeof(*sl), M_NOWAIT); 34652419Sjulian if (resp == NULL) 34752419Sjulian ERROUT(ENOMEM); 34864509Sarchie sl = (struct slcompress *)resp->data; 34964509Sarchie *sl = *sl0; 35064509Sarchie 35164509Sarchie /* Replace pointers with integer indicies */ 35264509Sarchie if (sl->last_cs != NULL) { 35364509Sarchie index = sl0->last_cs - sl0->tstate; 35464509Sarchie bzero(&sl->last_cs, sizeof(sl->last_cs)); 35564509Sarchie *((u_int16_t *)&sl->last_cs) = index; 35664509Sarchie } 35764509Sarchie for (i = 0; i < MAX_STATES; i++) { 35864509Sarchie struct cstate *const cs = &sl->tstate[i]; 35964509Sarchie 36064509Sarchie index = sl0->tstate[i].cs_next - sl0->tstate; 36164509Sarchie bzero(&cs->cs_next, sizeof(cs->cs_next)); 36264509Sarchie *((u_int16_t *)&cs->cs_next) = index; 36364509Sarchie } 36452419Sjulian break; 36564509Sarchie } 36652419Sjulian case NGM_VJC_CLR_STATS: 36752419Sjulian priv->slc.sls_packets = 0; 36852419Sjulian priv->slc.sls_compressed = 0; 36952419Sjulian priv->slc.sls_searches = 0; 37052419Sjulian priv->slc.sls_misses = 0; 37152419Sjulian priv->slc.sls_uncompressedin = 0; 37252419Sjulian priv->slc.sls_compressedin = 0; 37352419Sjulian priv->slc.sls_errorin = 0; 37452419Sjulian priv->slc.sls_tossed = 0; 37552419Sjulian break; 37652419Sjulian case NGM_VJC_RECV_ERROR: 37753076Sarchie sl_uncompress_tcp(NULL, 0, TYPE_ERROR, &priv->slc); 37852419Sjulian break; 37952419Sjulian default: 38052419Sjulian error = EINVAL; 38152419Sjulian break; 38252419Sjulian } 38352419Sjulian break; 38452419Sjulian default: 38552419Sjulian error = EINVAL; 38652419Sjulian break; 38752419Sjulian } 38852419Sjuliandone: 38970700Sjulian NG_RESPOND_MSG(error, node, item, resp); 39070700Sjulian NG_FREE_MSG(msg); 39152419Sjulian return (error); 39252419Sjulian} 39352419Sjulian 39452419Sjulian/* 39552419Sjulian * Receive data 39652419Sjulian */ 39752419Sjulianstatic int 39870700Sjulianng_vjc_rcvdata(hook_p hook, item_p item) 39952419Sjulian{ 40070784Sjulian const node_p node = NG_HOOK_NODE(hook); 40170784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 40252419Sjulian int error = 0; 40370700Sjulian struct mbuf *m; 40452419Sjulian 40570700Sjulian NGI_GET_M(item, m); 40652419Sjulian if (hook == priv->ip) { /* outgoing packet */ 40753190Sarchie u_int type = TYPE_IP; 40852419Sjulian 40953190Sarchie /* Compress packet if enabled and proto is TCP */ 41053190Sarchie if (priv->conf.enableComp) { 41152419Sjulian struct ip *ip; 41252419Sjulian 41353190Sarchie if ((m = ng_vjc_pulluphdrs(m, 0)) == NULL) { 41470700Sjulian NG_FREE_ITEM(item); 41553190Sarchie return (ENOBUFS); 41653190Sarchie } 41752419Sjulian ip = mtod(m, struct ip *); 41853190Sarchie if (ip->ip_p == IPPROTO_TCP) { 41953190Sarchie const int origLen = m->m_len; 42053190Sarchie 42153190Sarchie type = sl_compress_tcp(m, ip, 42253190Sarchie &priv->slc, priv->conf.compressCID); 42353190Sarchie m->m_pkthdr.len += m->m_len - origLen; 42453190Sarchie } 42552419Sjulian } 42653190Sarchie 42753190Sarchie /* Dispatch to the appropriate outgoing hook */ 42852419Sjulian switch (type) { 42952419Sjulian case TYPE_IP: 43052419Sjulian hook = priv->vjip; 43152419Sjulian break; 43252419Sjulian case TYPE_UNCOMPRESSED_TCP: 43352419Sjulian hook = priv->vjuncomp; 43452419Sjulian break; 43552419Sjulian case TYPE_COMPRESSED_TCP: 43652419Sjulian hook = priv->vjcomp; 43752419Sjulian break; 43852419Sjulian default: 43987599Sobrien panic("%s: type=%d", __func__, type); 44052419Sjulian } 44152419Sjulian } else if (hook == priv->vjcomp) { /* incoming compressed packet */ 44253190Sarchie int vjlen, need2pullup; 44353190Sarchie struct mbuf *hm; 44452419Sjulian u_char *hdr; 44553190Sarchie u_int hlen; 44652419Sjulian 44752539Sjulian /* Are we decompressing? */ 44852539Sjulian if (!priv->conf.enableDecomp) { 44970700Sjulian NG_FREE_M(m); 45070700Sjulian NG_FREE_ITEM(item); 45153190Sarchie return (ENXIO); 45252419Sjulian } 45352419Sjulian 45453190Sarchie /* Pull up the necessary amount from the mbuf */ 45553190Sarchie need2pullup = MAX_VJHEADER; 45653190Sarchie if (need2pullup > m->m_pkthdr.len) 45753190Sarchie need2pullup = m->m_pkthdr.len; 45853190Sarchie if (m->m_len < need2pullup 45953190Sarchie && (m = m_pullup(m, need2pullup)) == NULL) { 46053190Sarchie priv->slc.sls_errorin++; 46170700Sjulian NG_FREE_ITEM(item); 46253190Sarchie return (ENOBUFS); 46353076Sarchie } 46453190Sarchie 46553190Sarchie /* Uncompress packet to reconstruct TCP/IP header */ 46652419Sjulian vjlen = sl_uncompress_tcp_core(mtod(m, u_char *), 46752419Sjulian m->m_len, m->m_pkthdr.len, TYPE_COMPRESSED_TCP, 46852419Sjulian &priv->slc, &hdr, &hlen); 46952419Sjulian if (vjlen <= 0) { 47070700Sjulian NG_FREE_M(m); 47170700Sjulian NG_FREE_ITEM(item); 47253190Sarchie return (EINVAL); 47352419Sjulian } 47453076Sarchie m_adj(m, vjlen); 47552419Sjulian 47652419Sjulian /* Copy the reconstructed TCP/IP headers into a new mbuf */ 477111119Simp MGETHDR(hm, M_DONTWAIT, MT_DATA); 47853190Sarchie if (hm == NULL) { 47953190Sarchie priv->slc.sls_errorin++; 48070700Sjulian NG_FREE_M(m); 48170700Sjulian NG_FREE_ITEM(item); 48253190Sarchie return (ENOBUFS); 48353190Sarchie } 48453190Sarchie hm->m_len = 0; 48553284Sarchie hm->m_pkthdr.rcvif = NULL; 48653190Sarchie if (hlen > MHLEN) { /* unlikely, but can happen */ 487111119Simp MCLGET(hm, M_DONTWAIT); 48853190Sarchie if ((hm->m_flags & M_EXT) == 0) { 48953190Sarchie m_freem(hm); 49053190Sarchie priv->slc.sls_errorin++; 49170700Sjulian NG_FREE_M(m); 49270700Sjulian NG_FREE_ITEM(item); 49353190Sarchie return (ENOBUFS); 49452419Sjulian } 49552419Sjulian } 49653190Sarchie bcopy(hdr, mtod(hm, u_char *), hlen); 49753190Sarchie hm->m_len = hlen; 49852419Sjulian 49953190Sarchie /* Glue TCP/IP headers and rest of packet together */ 50053190Sarchie hm->m_next = m; 50153190Sarchie hm->m_pkthdr.len = hlen + m->m_pkthdr.len; 50253190Sarchie m = hm; 50352419Sjulian hook = priv->ip; 50452419Sjulian } else if (hook == priv->vjuncomp) { /* incoming uncompressed pkt */ 50552419Sjulian u_char *hdr; 50652539Sjulian u_int hlen; 50752419Sjulian 50852539Sjulian /* Are we decompressing? */ 50952539Sjulian if (!priv->conf.enableDecomp) { 51070700Sjulian NG_FREE_M(m); 51170700Sjulian NG_FREE_ITEM(item); 51253190Sarchie return (ENXIO); 51352419Sjulian } 51452419Sjulian 51553190Sarchie /* Pull up IP+TCP headers */ 51653190Sarchie if ((m = ng_vjc_pulluphdrs(m, 1)) == NULL) { 51770700Sjulian NG_FREE_ITEM(item); 51853190Sarchie return (ENOBUFS); 51953190Sarchie } 52053190Sarchie 52152419Sjulian /* Run packet through uncompressor */ 52252419Sjulian if (sl_uncompress_tcp_core(mtod(m, u_char *), 52352419Sjulian m->m_len, m->m_pkthdr.len, TYPE_UNCOMPRESSED_TCP, 52452419Sjulian &priv->slc, &hdr, &hlen) < 0) { 52570700Sjulian NG_FREE_M(m); 52670700Sjulian NG_FREE_ITEM(item); 52753190Sarchie return (EINVAL); 52852419Sjulian } 52952419Sjulian hook = priv->ip; 53052419Sjulian } else if (hook == priv->vjip) /* incoming regular packet (bypass) */ 53152419Sjulian hook = priv->ip; 53252419Sjulian else 53387599Sobrien panic("%s: unknown hook", __func__); 53452419Sjulian 53553190Sarchie /* Send result back out */ 53670700Sjulian NG_FWD_NEW_DATA(error, item, hook, m); 53752419Sjulian return (error); 53852419Sjulian} 53952419Sjulian 54052419Sjulian/* 54152419Sjulian * Shutdown node 54252419Sjulian */ 54352419Sjulianstatic int 54470700Sjulianng_vjc_shutdown(node_p node) 54552419Sjulian{ 54670784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 54752419Sjulian 54852419Sjulian bzero(priv, sizeof(*priv)); 549184205Sdes free(priv, M_NETGRAPH); 55070784Sjulian NG_NODE_SET_PRIVATE(node, NULL); 55170784Sjulian NG_NODE_UNREF(node); 55252419Sjulian return (0); 55352419Sjulian} 55452419Sjulian 55552419Sjulian/* 55652419Sjulian * Hook disconnection 55752419Sjulian */ 55852419Sjulianstatic int 55952419Sjulianng_vjc_disconnect(hook_p hook) 56052419Sjulian{ 56170784Sjulian const node_p node = NG_HOOK_NODE(hook); 56270784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 56353406Sarchie 56453406Sarchie /* Zero out hook pointer */ 56553406Sarchie if (hook == priv->ip) 56653406Sarchie priv->ip = NULL; 56753406Sarchie else if (hook == priv->vjcomp) 56853406Sarchie priv->vjcomp = NULL; 56953406Sarchie else if (hook == priv->vjuncomp) 57053406Sarchie priv->vjuncomp = NULL; 57153406Sarchie else if (hook == priv->vjip) 57253406Sarchie priv->vjip = NULL; 57353406Sarchie else 57487599Sobrien panic("%s: unknown hook", __func__); 57553406Sarchie 57653406Sarchie /* Go away if no hooks left */ 57770784Sjulian if ((NG_NODE_NUMHOOKS(node) == 0) 57870784Sjulian && (NG_NODE_IS_VALID(node))) 57970700Sjulian ng_rmnode_self(node); 58052419Sjulian return (0); 58152419Sjulian} 58252419Sjulian 58352419Sjulian/************************************************************************ 58452419Sjulian HELPER STUFF 58552419Sjulian ************************************************************************/ 58652419Sjulian 58752419Sjulian/* 58852539Sjulian * Pull up the full IP and TCP headers of a packet. If packet is not 58952419Sjulian * a TCP packet, just pull up the IP header. 59052419Sjulian */ 59152419Sjulianstatic struct mbuf * 59253190Sarchieng_vjc_pulluphdrs(struct mbuf *m, int knownTCP) 59352419Sjulian{ 59452419Sjulian struct ip *ip; 59552419Sjulian struct tcphdr *tcp; 59652419Sjulian int ihlen, thlen; 59752419Sjulian 59853076Sarchie if (m->m_len < sizeof(*ip) && (m = m_pullup(m, sizeof(*ip))) == NULL) 59952419Sjulian return (NULL); 60052419Sjulian ip = mtod(m, struct ip *); 60153190Sarchie if (!knownTCP && ip->ip_p != IPPROTO_TCP) 60252419Sjulian return (m); 60352539Sjulian ihlen = ip->ip_hl << 2; 60452539Sjulian if (m->m_len < ihlen + sizeof(*tcp)) { 60553076Sarchie if ((m = m_pullup(m, ihlen + sizeof(*tcp))) == NULL) 60652419Sjulian return (NULL); 60752419Sjulian ip = mtod(m, struct ip *); 60852419Sjulian } 60953190Sarchie tcp = (struct tcphdr *)((u_char *)ip + ihlen); 61052539Sjulian thlen = tcp->th_off << 2; 61152539Sjulian if (m->m_len < ihlen + thlen) 61252419Sjulian m = m_pullup(m, ihlen + thlen); 61352419Sjulian return (m); 61452419Sjulian} 61552419Sjulian 616