+/*
+ * 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.
+ */