X-Git-Url: http://git.onelab.eu/?p=ipfw.git;a=blobdiff_plain;f=dummynet2%2Fipfw2_mod.c;fp=dummynet2%2Fipfw2_mod.c;h=7ce046b48c5181d94c58124cda31b0e30564eea1;hp=1ea6e5718b6511bf184ccf8c27074636152592fa;hb=28a7fe9d930667786b902af6697c01eb87694173;hpb=2a8b6c544cf5ea3c84f763144c7ecfa79daea969 diff --git a/dummynet2/ipfw2_mod.c b/dummynet2/ipfw2_mod.c index 1ea6e57..7ce046b 100644 --- a/dummynet2/ipfw2_mod.c +++ b/dummynet2/ipfw2_mod.c @@ -24,7 +24,7 @@ */ /* - * $Id: ipfw2_mod.c 5797 2010-03-21 16:31:08Z luigi $ + * $Id: ipfw2_mod.c 10302 2012-01-19 21:49:23Z marta $ * * The main interface to build ipfw+dummynet as a linux module. * (and possibly as a windows module as well, though that part @@ -59,7 +59,7 @@ #include /* nf_queue */ #endif -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17) +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14) #define __read_mostly #endif @@ -73,8 +73,9 @@ #ifdef __linux__ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) -#warning --- inet_hashtables not present on 2.4 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,13) +/* XXX was < 2.6.0: inet_hashtables.h is introduced in 2.6.14 */ +// #warning --- inet_hashtables not present on 2.4 #include #include #include @@ -227,13 +228,127 @@ ipfw_ctl_h(struct sockopt *s, int cmd, int dir, int len, void __user *user) return -ret; /* errors are < 0 on linux */ } +/* + * Convert an mbuf into an skbuff + * At the moment this only works for ip packets fully contained + * in a single mbuf. We assume that on entry ip_len and ip_off are + * in host format, and the ip checksum is not computed. + */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) /* check boundary */ +int dst_output(struct skbuff *s) +{ + return 0; +} + +struct sk_buff * +mbuf2skbuff(struct mbuf* m) +{ + return NULL; +} +#else +struct sk_buff * +mbuf2skbuff(struct mbuf* m) +{ + struct sk_buff *skb; + size_t len = m->m_pkthdr.len; + + /* used to lookup the routing table */ + struct rtable *r; + struct flowi fl; + int ret = 0; /* success for ip_route_output_key() */ + + struct ip *ip = mtod(m, struct ip *); + + /* XXX ip_output has ip_len and ip_off in network format, + * linux expects host format */ + ip->ip_len = ntohs(ip->ip_len); + ip->ip_off = ntohs(ip->ip_off); + + ip->ip_sum = 0; + ip->ip_sum = in_cksum(m, ip->ip_hl<<2); + + /* fill flowi struct, we need just the dst addr, see XXX */ + bzero(&fl, sizeof(fl)); + flow_daddr.daddr = ip->ip_dst.s_addr; + + /* + * ip_route_output_key() should increment + * r->u.dst.__use and call a dst_hold(dst) + * XXX verify how we release the resources. + */ +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,38) /* check boundary */ + r = ip_route_output_key(&init_net, &fl.u.ip4); +#elif LINUX_VERSION_CODE > KERNEL_VERSION(2,6,26) /* check boundary */ + ret = ip_route_output_key(&init_net, &r, &fl); +#else + ret = ip_route_output_key(&r, &fl); +#endif + if (ret != 0 || r == NULL ) { + printf("NO ROUTE FOUND\n"); + return NULL; + } + + /* allocate the skbuff and the data */ + skb = alloc_skb(len + sizeof(struct ethhdr), GFP_ATOMIC); + if (skb == NULL) { + printf("%s: can not allocate SKB buffers.\n", __FUNCTION__); + return NULL; + } + + skb->protocol = htons(ETH_P_IP); // XXX 8 or 16 bit ? + /* sk_dst_set XXX take the lock (?) */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36) + skb_dst_set(skb, &r->u.dst); +#else + skb_dst_set(skb, &r->dst); +#endif + skb->dev = skb_dst(skb)->dev; + + /* reserve space for ethernet header */ + skb_reserve(skb, sizeof(struct ethhdr)); + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) + skb_reset_network_header(skb); // skb->network_header = skb->data - skb->head +#else + skb->nh.raw = skb->data; +#endif + /* set skbuff tail pointers and copy content */ + skb_put(skb, len); + memcpy(skb->data, m->m_data, len); + + return skb; +} +#endif /* keepalives not supported on linux 2.4 */ + +/* + * This function is called to reinject packets to the + * kernel stack within the linux netfilter system + * or to send a new created mbuf. + * In the first case we have a valid sk_buff pointer + * encapsulated within the fake mbuf, so we can call + * the reinject function trough netisr_dispatch. + * In the last case we need to build a sk_buff from scratch, + * before sending out the packet. + */ int ip_output(struct mbuf *m, struct mbuf __unused *opt, struct route __unused *ro, int __unused flags, struct ip_moptions __unused *imo, struct inpcb __unused *inp) { - netisr_dispatch(0, m); - return 0; + if ( m->m_skb != NULL ) { /* reinjected packet, just call dispatch */ + netisr_dispatch(0, m); + } else { + /* self-generated packet, wrap as appropriate and send */ +#ifdef __linux__ + struct sk_buff *skb = mbuf2skbuff(m); + + if (skb != NULL) + dst_output(skb); +#else /* Windows */ +#endif + FREE_PKT(m); + } + return 0; } /* @@ -347,7 +462,7 @@ call_ipfw(unsigned int __unused hooknum, return NF_QUEUE; } -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12) /* XXX was 2.6.0 */ #define NF_STOP NF_ACCEPT #endif @@ -360,10 +475,10 @@ call_ipfw(unsigned int __unused hooknum, #define nf_queue_entry nf_info /* for simplicity */ /* also, 2.4 and perhaps something else have different arguments */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) /* unsure on the exact boundary */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14) /* XXX unsure */ /* on 2.4 we use nf_info */ #define QH_ARGS struct sk_buff *skb, struct nf_info *info, void *data -#else /* 2.6.1.. 2.6.24 */ +#else /* 2.6.14. 2.6.24 */ #define QH_ARGS struct sk_buff *skb, struct nf_info *info, unsigned int qnum, void *data #endif @@ -420,7 +535,7 @@ ipfw2_queue_handler(QH_ARGS) m->m_pkthdr.len = skb->len; /* total packet len */ m->m_pkthdr.rcvif = info->indev; m->queue_entry = info; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22) /* XXX was 2.6.0 */ m->m_data = skb->nh.iph; #else m->m_data = skb_network_header(skb); @@ -451,11 +566,11 @@ struct route; struct ip_moptions; struct inpcb; - /* XXX should include prototypes for netisr_dispatch and ip_output */ /* * The reinjection routine after a packet comes out from dummynet. * We must update the skb timestamp so ping reports the right time. + * This routine is also used (with num == -1) as FREE_PKT. XXX */ void netisr_dispatch(int num, struct mbuf *m) @@ -463,9 +578,21 @@ netisr_dispatch(int num, struct mbuf *m) struct nf_queue_entry *info = m->queue_entry; struct sk_buff *skb = m->m_skb; /* always used */ + /* + * This function can be called by the FREE_PKT() + * used when ipfw generate their own mbuf packets + * or by the mbuf2skbuff() function. + */ m_freem(m); - KASSERT((info != NULL), ("%s info null!\n", __FUNCTION__)); + /* XXX check + * info is null in the case of a real mbuf + * (one created by the ipfw code without a + * valid sk_buff pointer + */ + if (info == NULL) + return; + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) // XXX above 2.6.x ? __net_timestamp(skb); /* update timestamp */ #endif @@ -508,7 +635,7 @@ linux_lookup(const int proto, const __be32 saddr, const __be16 sport, const __be32 daddr, const __be16 dport, struct sk_buff *skb, int dir, struct bsd_ucred *u) { -#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,0) +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,13) /* XXX was 2.6.0 */ return -1; #else struct sock *sk; @@ -617,7 +744,15 @@ linux_lookup(const int proto, const __be32 saddr, const __be16 sport, * * the unregister function changed arguments between 2.6.22 and 2.6.24 */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,14) +struct nf_queue_handler ipfw2_queue_handler_desc = { + .outfn = ipfw2_queue_handler, + .name = "ipfw2 dummynet queue", +}; +#define REG_QH_ARG(fn) &(fn ## _desc) +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17) /* XXX was 2.6.0 */ static int nf_register_hooks(struct nf_hook_ops *ops, int n) { @@ -638,17 +773,13 @@ nf_unregister_hooks(struct nf_hook_ops *ops, int n) nf_unregister_hook(ops + i); } } +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14) /* XXX was 2.6.0 */ #define REG_QH_ARG(fn) fn, NULL /* argument for nf_[un]register_queue_handler */ +#endif #define UNREG_QH_ARG(fn) //fn /* argument for nf_[un]register_queue_handler */ #define SET_MOD_OWNER -#else /* linux >= 2.6.0 */ - -struct nf_queue_handler ipfw2_queue_handler_desc = { - .outfn = ipfw2_queue_handler, - .name = "ipfw2 dummynet queue", -}; -#define REG_QH_ARG(fn) &(fn ## _desc) +#else /* linux > 2.6.17 */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24) #define UNREG_QH_ARG(fn) //fn /* argument for nf_[un]register_queue_handler */