summaryrefslogtreecommitdiffstats
path: root/target/linux/generic-2.6/patches/160-netfilter_route.patch
diff options
context:
space:
mode:
authorImre Kaloz <kaloz@openwrt.org>2007-05-23 19:48:34 +0000
committerImre Kaloz <kaloz@openwrt.org>2007-05-23 19:48:34 +0000
commit615e8af8411e64db4db57d453af00ea9a7ca1fa2 (patch)
treeb4fa16ada763cf659876a3ef907e0e49e4cb73f1 /target/linux/generic-2.6/patches/160-netfilter_route.patch
parente1bb43f263ea0a0c72bac8750fb420697ca7866f (diff)
downloadmaster-31e0f0ae-615e8af8411e64db4db57d453af00ea9a7ca1fa2.tar.gz
master-31e0f0ae-615e8af8411e64db4db57d453af00ea9a7ca1fa2.tar.bz2
master-31e0f0ae-615e8af8411e64db4db57d453af00ea9a7ca1fa2.zip
break trunk temporary - upgrade to 2.6.21.1 and iptables 1.3.7
SVN-Revision: 7315
Diffstat (limited to 'target/linux/generic-2.6/patches/160-netfilter_route.patch')
-rw-r--r--target/linux/generic-2.6/patches/160-netfilter_route.patch1284
1 files changed, 669 insertions, 615 deletions
diff --git a/target/linux/generic-2.6/patches/160-netfilter_route.patch b/target/linux/generic-2.6/patches/160-netfilter_route.patch
index 7e8491c3e3..0d73ba3193 100644
--- a/target/linux/generic-2.6/patches/160-netfilter_route.patch
+++ b/target/linux/generic-2.6/patches/160-netfilter_route.patch
@@ -1,6 +1,6 @@
-diff -urN linux-2.6.19.old/include/linux/netfilter_ipv4/ipt_ROUTE.h linux-2.6.19.dev/include/linux/netfilter_ipv4/ipt_ROUTE.h
---- linux-2.6.19.old/include/linux/netfilter_ipv4/ipt_ROUTE.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.19.dev/include/linux/netfilter_ipv4/ipt_ROUTE.h 2006-12-14 03:13:49.000000000 +0100
+diff -Nur linux-2.6.21.1/include/linux/netfilter_ipv4/ipt_ROUTE.h linux-2.6.21.1-owrt/include/linux/netfilter_ipv4/ipt_ROUTE.h
+--- linux-2.6.21.1/include/linux/netfilter_ipv4/ipt_ROUTE.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.21.1-owrt/include/linux/netfilter_ipv4/ipt_ROUTE.h 2007-05-23 20:32:22.000000000 +0200
@@ -0,0 +1,23 @@
+/* Header file for iptables ipt_ROUTE target
+ *
@@ -14,10 +14,10 @@ diff -urN linux-2.6.19.old/include/linux/netfilter_ipv4/ipt_ROUTE.h linux-2.6.19
+#define IPT_ROUTE_IFNAMSIZ 16
+
+struct ipt_route_target_info {
-+ char oif[IPT_ROUTE_IFNAMSIZ]; /* Output Interface Name */
-+ char iif[IPT_ROUTE_IFNAMSIZ]; /* Input Interface Name */
-+ u_int32_t gw; /* IP address of gateway */
-+ u_int8_t flags;
++ char oif[IPT_ROUTE_IFNAMSIZ]; /* Output Interface Name */
++ char iif[IPT_ROUTE_IFNAMSIZ]; /* Input Interface Name */
++ u_int32_t gw; /* IP address of gateway */
++ u_int8_t flags;
+};
+
+/* Values for "flags" field */
@@ -25,9 +25,9 @@ diff -urN linux-2.6.19.old/include/linux/netfilter_ipv4/ipt_ROUTE.h linux-2.6.19
+#define IPT_ROUTE_TEE 0x02
+
+#endif /*_IPT_ROUTE_H_target*/
-diff -urN linux-2.6.19.old/include/linux/netfilter_ipv6/ip6t_ROUTE.h linux-2.6.19.dev/include/linux/netfilter_ipv6/ip6t_ROUTE.h
---- linux-2.6.19.old/include/linux/netfilter_ipv6/ip6t_ROUTE.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.19.dev/include/linux/netfilter_ipv6/ip6t_ROUTE.h 2006-12-14 03:13:49.000000000 +0100
+diff -Nur linux-2.6.21.1/include/linux/netfilter_ipv6/ip6t_ROUTE.h linux-2.6.21.1-owrt/include/linux/netfilter_ipv6/ip6t_ROUTE.h
+--- linux-2.6.21.1/include/linux/netfilter_ipv6/ip6t_ROUTE.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.21.1-owrt/include/linux/netfilter_ipv6/ip6t_ROUTE.h 2007-05-23 20:32:22.000000000 +0200
@@ -0,0 +1,23 @@
+/* Header file for iptables ip6t_ROUTE target
+ *
@@ -41,10 +41,10 @@ diff -urN linux-2.6.19.old/include/linux/netfilter_ipv6/ip6t_ROUTE.h linux-2.6.1
+#define IP6T_ROUTE_IFNAMSIZ 16
+
+struct ip6t_route_target_info {
-+ char oif[IP6T_ROUTE_IFNAMSIZ]; /* Output Interface Name */
-+ char iif[IP6T_ROUTE_IFNAMSIZ]; /* Input Interface Name */
-+ u_int32_t gw[4]; /* IPv6 address of gateway */
-+ u_int8_t flags;
++ char oif[IP6T_ROUTE_IFNAMSIZ]; /* Output Interface Name */
++ char iif[IP6T_ROUTE_IFNAMSIZ]; /* Input Interface Name */
++ u_int32_t gw[4]; /* IPv6 address of gateway */
++ u_int8_t flags;
+};
+
+/* Values for "flags" field */
@@ -52,10 +52,10 @@ diff -urN linux-2.6.19.old/include/linux/netfilter_ipv6/ip6t_ROUTE.h linux-2.6.1
+#define IP6T_ROUTE_TEE 0x02
+
+#endif /*_IP6T_ROUTE_H_target*/
-diff -urN linux-2.6.19.old/net/ipv4/netfilter/ipt_ROUTE.c linux-2.6.19.dev/net/ipv4/netfilter/ipt_ROUTE.c
---- linux-2.6.19.old/net/ipv4/netfilter/ipt_ROUTE.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.19.dev/net/ipv4/netfilter/ipt_ROUTE.c 2006-12-14 03:13:49.000000000 +0100
-@@ -0,0 +1,455 @@
+diff -Nur linux-2.6.21.1/net/ipv4/netfilter/ipt_ROUTE.c linux-2.6.21.1-owrt/net/ipv4/netfilter/ipt_ROUTE.c
+--- linux-2.6.21.1/net/ipv4/netfilter/ipt_ROUTE.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.21.1-owrt/net/ipv4/netfilter/ipt_ROUTE.c 2007-05-23 20:32:22.000000000 +0200
+@@ -0,0 +1,483 @@
+/*
+ * This implements the ROUTE target, which enables you to setup unusual
+ * routes not supported by the standard kernel routing table.
@@ -75,6 +75,7 @@ diff -urN linux-2.6.19.old/net/ipv4/netfilter/ipt_ROUTE.c linux-2.6.19.dev/net/i
+#include <linux/netfilter_ipv4/ipt_ROUTE.h>
+#include <linux/netdevice.h>
+#include <linux/route.h>
++#include <linux/version.h>
+#include <linux/if_arp.h>
+#include <net/ip.h>
+#include <net/route.h>
@@ -93,73 +94,73 @@ diff -urN linux-2.6.19.old/net/ipv4/netfilter/ipt_ROUTE.c linux-2.6.19.dev/net/i
+
+/* Try to route the packet according to the routing keys specified in
+ * route_info. Keys are :
-+ * - ifindex :
-+ * 0 if no oif preferred,
++ * - ifindex :
++ * 0 if no oif preferred,
+ * otherwise set to the index of the desired oif
+ * - route_info->gw :
+ * 0 if no gateway specified,
+ * otherwise set to the next host to which the pkt must be routed
-+ * If success, skb->dev is the output device to which the packet must
++ * If success, skb->dev is the output device to which the packet must
+ * be sent and skb->dst is not NULL
+ *
+ * RETURN: -1 if an error occured
-+ * 1 if the packet was succesfully routed to the
++ * 1 if the packet was succesfully routed to the
+ * destination desired
+ * 0 if the kernel routing table could not route the packet
+ * according to the keys specified
+ */
+static int route(struct sk_buff *skb,
-+ unsigned int ifindex,
-+ const struct ipt_route_target_info *route_info)
++ unsigned int ifindex,
++ const struct ipt_route_target_info *route_info)
+{
-+ int err;
-+ struct rtable *rt;
-+ struct iphdr *iph = skb->nh.iph;
-+ struct flowi fl = {
-+ .oif = ifindex,
-+ .nl_u = {
-+ .ip4_u = {
-+ .daddr = iph->daddr,
-+ .saddr = 0,
-+ .tos = RT_TOS(iph->tos),
-+ .scope = RT_SCOPE_UNIVERSE,
-+ }
-+ }
-+ };
-+
-+ /* The destination address may be overloaded by the target */
-+ if (route_info->gw)
-+ fl.fl4_dst = route_info->gw;
-+
-+ /* Trying to route the packet using the standard routing table. */
-+ if ((err = ip_route_output_key(&rt, &fl))) {
-+ if (net_ratelimit())
-+ DEBUGP("ipt_ROUTE: couldn't route pkt (err: %i)",err);
-+ return -1;
-+ }
-+
-+ /* Drop old route. */
-+ dst_release(skb->dst);
-+ skb->dst = NULL;
-+
-+ /* Success if no oif specified or if the oif correspond to the
-+ * one desired */
-+ if (!ifindex || rt->u.dst.dev->ifindex == ifindex) {
-+ skb->dst = &rt->u.dst;
-+ skb->dev = skb->dst->dev;
-+ skb->protocol = htons(ETH_P_IP);
-+ return 1;
-+ }
-+
-+ /* The interface selected by the routing table is not the one
-+ * specified by the user. This may happen because the dst address
-+ * is one of our own addresses.
-+ */
-+ if (net_ratelimit())
-+ DEBUGP("ipt_ROUTE: failed to route as desired gw=%u.%u.%u.%u oif=%i (got oif=%i)\n",
-+ NIPQUAD(route_info->gw), ifindex, rt->u.dst.dev->ifindex);
-+
-+ return 0;
++ int err;
++ struct rtable *rt;
++ struct iphdr *iph = skb->nh.iph;
++ struct flowi fl = {
++ .oif = ifindex,
++ .nl_u = {
++ .ip4_u = {
++ .daddr = iph->daddr,
++ .saddr = 0,
++ .tos = RT_TOS(iph->tos),
++ .scope = RT_SCOPE_UNIVERSE,
++ }
++ }
++ };
++
++ /* The destination address may be overloaded by the target */
++ if (route_info->gw)
++ fl.fl4_dst = route_info->gw;
++
++ /* Trying to route the packet using the standard routing table. */
++ if ((err = ip_route_output_key(&rt, &fl))) {
++ if (net_ratelimit())
++ DEBUGP("ipt_ROUTE: couldn't route pkt (err: %i)",err);
++ return -1;
++ }
++
++ /* Drop old route. */
++ dst_release(skb->dst);
++ skb->dst = NULL;
++
++ /* Success if no oif specified or if the oif correspond to the
++ * one desired */
++ if (!ifindex || rt->u.dst.dev->ifindex == ifindex) {
++ skb->dst = &rt->u.dst;
++ skb->dev = skb->dst->dev;
++ skb->protocol = htons(ETH_P_IP);
++ return 1;
++ }
++
++ /* The interface selected by the routing table is not the one
++ * specified by the user. This may happen because the dst address
++ * is one of our own addresses.
++ */
++ if (net_ratelimit())
++ DEBUGP("ipt_ROUTE: failed to route as desired gw=%u.%u.%u.%u oif=%i (got oif=%i)\n",
++ NIPQUAD(route_info->gw), ifindex, rt->u.dst.dev->ifindex);
++
++ return 0;
+}
+
+
@@ -171,158 +172,158 @@ diff -urN linux-2.6.19.old/net/ipv4/netfilter/ipt_ROUTE.c linux-2.6.19.dev/net/i
+ */
+static void ip_direct_send(struct sk_buff *skb)
+{
-+ struct dst_entry *dst = skb->dst;
-+ struct hh_cache *hh = dst->hh;
-+ struct net_device *dev = dst->dev;
-+ int hh_len = LL_RESERVED_SPACE(dev);
-+
-+ /* Be paranoid, rather than too clever. */
-+ if (unlikely(skb_headroom(skb) < hh_len && dev->hard_header)) {
-+ struct sk_buff *skb2;
-+
-+ skb2 = skb_realloc_headroom(skb, LL_RESERVED_SPACE(dev));
-+ if (skb2 == NULL) {
-+ kfree_skb(skb);
-+ return;
-+ }
-+ if (skb->sk)
-+ skb_set_owner_w(skb2, skb->sk);
-+ kfree_skb(skb);
-+ skb = skb2;
-+ }
-+
-+ if (hh) {
-+ int hh_alen;
-+
-+ read_lock_bh(&hh->hh_lock);
-+ hh_alen = HH_DATA_ALIGN(hh->hh_len);
-+ memcpy(skb->data - hh_alen, hh->hh_data, hh_alen);
-+ read_unlock_bh(&hh->hh_lock);
-+ skb_push(skb, hh->hh_len);
-+ hh->hh_output(skb);
-+ } else if (dst->neighbour)
-+ dst->neighbour->output(skb);
-+ else {
-+ if (net_ratelimit())
-+ DEBUGP(KERN_DEBUG "ipt_ROUTE: no hdr & no neighbour cache!\n");
-+ kfree_skb(skb);
-+ }
++ struct dst_entry *dst = skb->dst;
++ struct hh_cache *hh = dst->hh;
++ struct net_device *dev = dst->dev;
++ int hh_len = LL_RESERVED_SPACE(dev);
++
++ /* Be paranoid, rather than too clever. */
++ if (unlikely(skb_headroom(skb) < hh_len && dev->hard_header)) {
++ struct sk_buff *skb2;
++
++ skb2 = skb_realloc_headroom(skb, LL_RESERVED_SPACE(dev));
++ if (skb2 == NULL) {
++ kfree_skb(skb);
++ return;
++ }
++ if (skb->sk)
++ skb_set_owner_w(skb2, skb->sk);
++ kfree_skb(skb);
++ skb = skb2;
++ }
++
++ if (hh) {
++ int hh_alen;
++
++ read_lock_bh(&hh->hh_lock);
++ hh_alen = HH_DATA_ALIGN(hh->hh_len);
++ memcpy(skb->data - hh_alen, hh->hh_data, hh_alen);
++ read_unlock_bh(&hh->hh_lock);
++ skb_push(skb, hh->hh_len);
++ hh->hh_output(skb);
++ } else if (dst->neighbour)
++ dst->neighbour->output(skb);
++ else {
++ if (net_ratelimit())
++ DEBUGP(KERN_DEBUG "ipt_ROUTE: no hdr & no neighbour cache!\n");
++ kfree_skb(skb);
++ }
+}
+
+
+/* PRE : skb->dev is set to the device we are leaving by
-+ * POST: - the packet is directly sent to the skb->dev device, without
++ * POST: - the packet is directly sent to the skb->dev device, without
+ * pushing the link layer header.
+ * - the packet is destroyed
+ */
+static inline int dev_direct_send(struct sk_buff *skb)
+{
-+ return dev_queue_xmit(skb);
++ return dev_queue_xmit(skb);
+}
+
+
+static unsigned int route_oif(const struct ipt_route_target_info *route_info,
-+ struct sk_buff *skb)
++ struct sk_buff *skb)
+{
-+ unsigned int ifindex = 0;
-+ struct net_device *dev_out = NULL;
-+
-+ /* The user set the interface name to use.
-+ * Getting the current interface index.
-+ */
-+ if ((dev_out = dev_get_by_name(route_info->oif))) {
-+ ifindex = dev_out->ifindex;
-+ } else {
-+ /* Unknown interface name : packet dropped */
-+ if (net_ratelimit())
-+ DEBUGP("ipt_ROUTE: oif interface %s not found\n", route_info->oif);
-+ return NF_DROP;
-+ }
-+
-+ /* Trying the standard way of routing packets */
-+ switch (route(skb, ifindex, route_info)) {
-+ case 1:
-+ dev_put(dev_out);
-+ if (route_info->flags & IPT_ROUTE_CONTINUE)
-+ return IPT_CONTINUE;
-+
-+ ip_direct_send(skb);
-+ return NF_STOLEN;
-+
-+ case 0:
-+ /* Failed to send to oif. Trying the hard way */
-+ if (route_info->flags & IPT_ROUTE_CONTINUE)
-+ return NF_DROP;
-+
-+ if (net_ratelimit())
-+ DEBUGP("ipt_ROUTE: forcing the use of %i\n",
-+ ifindex);
-+
-+ /* We have to force the use of an interface.
-+ * This interface must be a tunnel interface since
-+ * otherwise we can't guess the hw address for
-+ * the packet. For a tunnel interface, no hw address
-+ * is needed.
-+ */
-+ if ((dev_out->type != ARPHRD_TUNNEL)
-+ && (dev_out->type != ARPHRD_IPGRE)) {
-+ if (net_ratelimit())
-+ DEBUGP("ipt_ROUTE: can't guess the hw addr !\n");
-+ dev_put(dev_out);
-+ return NF_DROP;
-+ }
-+
-+ /* Send the packet. This will also free skb
-+ * Do not go through the POST_ROUTING hook because
-+ * skb->dst is not set and because it will probably
-+ * get confused by the destination IP address.
-+ */
-+ skb->dev = dev_out;
-+ dev_direct_send(skb);
-+ dev_put(dev_out);
-+ return NF_STOLEN;
-+
-+ default:
-+ /* Unexpected error */
-+ dev_put(dev_out);
-+ return NF_DROP;
-+ }
++ unsigned int ifindex = 0;
++ struct net_device *dev_out = NULL;
++
++ /* The user set the interface name to use.
++ * Getting the current interface index.
++ */
++ if ((dev_out = dev_get_by_name(route_info->oif))) {
++ ifindex = dev_out->ifindex;
++ } else {
++ /* Unknown interface name : packet dropped */
++ if (net_ratelimit())
++ DEBUGP("ipt_ROUTE: oif interface %s not found\n", route_info->oif);
++ return NF_DROP;
++ }
++
++ /* Trying the standard way of routing packets */
++ switch (route(skb, ifindex, route_info)) {
++ case 1:
++ dev_put(dev_out);
++ if (route_info->flags & IPT_ROUTE_CONTINUE)
++ return IPT_CONTINUE;
++
++ ip_direct_send(skb);
++ return NF_STOLEN;
++
++ case 0:
++ /* Failed to send to oif. Trying the hard way */
++ if (route_info->flags & IPT_ROUTE_CONTINUE)
++ return NF_DROP;
++
++ if (net_ratelimit())
++ DEBUGP("ipt_ROUTE: forcing the use of %i\n",
++ ifindex);
++
++ /* We have to force the use of an interface.
++ * This interface must be a tunnel interface since
++ * otherwise we can't guess the hw address for
++ * the packet. For a tunnel interface, no hw address
++ * is needed.
++ */
++ if ((dev_out->type != ARPHRD_TUNNEL)
++ && (dev_out->type != ARPHRD_IPGRE)) {
++ if (net_ratelimit())
++ DEBUGP("ipt_ROUTE: can't guess the hw addr !\n");
++ dev_put(dev_out);
++ return NF_DROP;
++ }
++
++ /* Send the packet. This will also free skb
++ * Do not go through the POST_ROUTING hook because
++ * skb->dst is not set and because it will probably
++ * get confused by the destination IP address.
++ */
++ skb->dev = dev_out;
++ dev_direct_send(skb);
++ dev_put(dev_out);
++ return NF_STOLEN;
++
++ default:
++ /* Unexpected error */
++ dev_put(dev_out);
++ return NF_DROP;
++ }
+}
+
+
+static unsigned int route_iif(const struct ipt_route_target_info *route_info,
-+ struct sk_buff *skb)
++ struct sk_buff *skb)
+{
-+ struct net_device *dev_in = NULL;
-+
-+ /* Getting the current interface index. */
-+ if (!(dev_in = dev_get_by_name(route_info->iif))) {
-+ if (net_ratelimit())
-+ DEBUGP("ipt_ROUTE: iif interface %s not found\n", route_info->iif);
-+ return NF_DROP;
-+ }
-+
-+ skb->dev = dev_in;
-+ dst_release(skb->dst);
-+ skb->dst = NULL;
-+
-+ netif_rx(skb);
-+ dev_put(dev_in);
-+ return NF_STOLEN;
++ struct net_device *dev_in = NULL;
++
++ /* Getting the current interface index. */
++ if (!(dev_in = dev_get_by_name(route_info->iif))) {
++ if (net_ratelimit())
++ DEBUGP("ipt_ROUTE: iif interface %s not found\n", route_info->iif);
++ return NF_DROP;
++ }
++
++ skb->dev = dev_in;
++ dst_release(skb->dst);
++ skb->dst = NULL;
++
++ netif_rx(skb);
++ dev_put(dev_in);
++ return NF_STOLEN;
+}
+
+
+static unsigned int route_gw(const struct ipt_route_target_info *route_info,
-+ struct sk_buff *skb)
++ struct sk_buff *skb)
+{
-+ if (route(skb, 0, route_info)!=1)
-+ return NF_DROP;
++ if (route(skb, 0, route_info)!=1)
++ return NF_DROP;
+
-+ if (route_info->flags & IPT_ROUTE_CONTINUE)
-+ return IPT_CONTINUE;
++ if (route_info->flags & IPT_ROUTE_CONTINUE)
++ return IPT_CONTINUE;
+
-+ ip_direct_send(skb);
-+ return NF_STOLEN;
++ ip_direct_send(skb);
++ return NF_STOLEN;
+}
+
+
@@ -335,224 +336,250 @@ diff -urN linux-2.6.19.old/net/ipv4/netfilter/ipt_ROUTE.c linux-2.6.19.dev/net/i
+static struct ip_conntrack route_tee_track;
+
+static unsigned int ipt_route_target(struct sk_buff **pskb,
-+ const struct net_device *in,
-+ const struct net_device *out,
-+ unsigned int hooknum,
-+ const struct xt_target *target,
-+ const void *targinfo)
++ const struct net_device *in,
++ const struct net_device *out,
++ unsigned int hooknum,
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17)
++ const struct xt_target *target,
++#endif
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
++ const void *targinfo,
++ void *userinfo)
++#else
++ const void *targinfo)
++#endif
+{
-+ const struct ipt_route_target_info *route_info = targinfo;
-+ struct sk_buff *skb = *pskb;
-+ unsigned int res;
-+
-+ if (skb->nfct == &route_tee_track.ct_general) {
-+ /* Loopback - a packet we already routed, is to be
-+ * routed another time. Avoid that, now.
-+ */
-+ if (net_ratelimit())
-+ DEBUGP(KERN_DEBUG "ipt_ROUTE: loopback - DROP!\n");
-+ return NF_DROP;
-+ }
-+
-+ /* If we are at PREROUTING or INPUT hook
-+ * the TTL isn't decreased by the IP stack
-+ */
-+ if (hooknum == NF_IP_PRE_ROUTING ||
-+ hooknum == NF_IP_LOCAL_IN) {
-+
-+ struct iphdr *iph = skb->nh.iph;
-+
-+ if (iph->ttl <= 1) {
-+ struct rtable *rt;
-+ struct flowi fl = {
-+ .oif = 0,
-+ .nl_u = {
-+ .ip4_u = {
-+ .daddr = iph->daddr,
-+ .saddr = iph->saddr,
-+ .tos = RT_TOS(iph->tos),
-+ .scope = ((iph->tos & RTO_ONLINK) ?
-+ RT_SCOPE_LINK :
-+ RT_SCOPE_UNIVERSE)
-+ }
-+ }
-+ };
-+
-+ if (ip_route_output_key(&rt, &fl)) {
-+ return NF_DROP;
-+ }
-+
-+ if (skb->dev == rt->u.dst.dev) {
-+ /* Drop old route. */
-+ dst_release(skb->dst);
-+ skb->dst = &rt->u.dst;
-+
-+ /* this will traverse normal stack, and
-+ * thus call conntrack on the icmp packet */
-+ icmp_send(skb, ICMP_TIME_EXCEEDED,
-+ ICMP_EXC_TTL, 0);
-+ }
-+
-+ return NF_DROP;
-+ }
-+
-+ /*
-+ * If we are at INPUT the checksum must be recalculated since
-+ * the length could change as the result of a defragmentation.
-+ */
-+ if(hooknum == NF_IP_LOCAL_IN) {
-+ iph->ttl = iph->ttl - 1;
-+ iph->check = 0;
-+ iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
-+ } else {
-+ ip_decrease_ttl(iph);
-+ }
-+ }
-+
-+ if ((route_info->flags & IPT_ROUTE_TEE)) {
-+ /*
-+ * Copy the *pskb, and route the copy. Will later return
-+ * IPT_CONTINUE for the original skb, which should continue
-+ * on its way as if nothing happened. The copy should be
-+ * independantly delivered to the ROUTE --gw.
-+ */
-+ skb = skb_copy(*pskb, GFP_ATOMIC);
-+ if (!skb) {
-+ if (net_ratelimit())
-+ DEBUGP(KERN_DEBUG "ipt_ROUTE: copy failed!\n");
-+ return IPT_CONTINUE;
-+ }
-+ }
-+
-+ /* Tell conntrack to forget this packet since it may get confused
-+ * when a packet is leaving with dst address == our address.
-+ * Good idea ? Dunno. Need advice.
-+ *
-+ * NEW: mark the skb with our &route_tee_track, so we avoid looping
-+ * on any already routed packet.
-+ */
-+ if (!(route_info->flags & IPT_ROUTE_CONTINUE)) {
-+ nf_conntrack_put(skb->nfct);
-+ skb->nfct = &route_tee_track.ct_general;
-+ skb->nfctinfo = IP_CT_NEW;
-+ nf_conntrack_get(skb->nfct);
-+ }
-+
-+ if (route_info->oif[0] != '\0') {
-+ res = route_oif(route_info, skb);
-+ } else if (route_info->iif[0] != '\0') {
-+ res = route_iif(route_info, skb);
-+ } else if (route_info->gw) {
-+ res = route_gw(route_info, skb);
-+ } else {
-+ if (net_ratelimit())
-+ DEBUGP(KERN_DEBUG "ipt_ROUTE: no parameter !\n");
-+ res = IPT_CONTINUE;
-+ }
-+
-+ if ((route_info->flags & IPT_ROUTE_TEE))
-+ res = IPT_CONTINUE;
-+
-+ return res;
++ const struct ipt_route_target_info *route_info = targinfo;
++ struct sk_buff *skb = *pskb;
++ unsigned int res;
++
++ if (skb->nfct == &route_tee_track.ct_general) {
++ /* Loopback - a packet we already routed, is to be
++ * routed another time. Avoid that, now.
++ */
++ if (net_ratelimit())
++ DEBUGP(KERN_DEBUG "ipt_ROUTE: loopback - DROP!\n");
++ return NF_DROP;
++ }
++
++ /* If we are at PREROUTING or INPUT hook
++ * the TTL isn't decreased by the IP stack
++ */
++ if (hooknum == NF_IP_PRE_ROUTING ||
++ hooknum == NF_IP_LOCAL_IN) {
++
++ struct iphdr *iph = skb->nh.iph;
++
++ if (iph->ttl <= 1) {
++ struct rtable *rt;
++ struct flowi fl = {
++ .oif = 0,
++ .nl_u = {
++ .ip4_u = {
++ .daddr = iph->daddr,
++ .saddr = iph->saddr,
++ .tos = RT_TOS(iph->tos),
++ .scope = ((iph->tos & RTO_ONLINK) ?
++ RT_SCOPE_LINK :
++ RT_SCOPE_UNIVERSE)
++ }
++ }
++ };
++
++ if (ip_route_output_key(&rt, &fl)) {
++ return NF_DROP;
++ }
++
++ if (skb->dev == rt->u.dst.dev) {
++ /* Drop old route. */
++ dst_release(skb->dst);
++ skb->dst = &rt->u.dst;
++
++ /* this will traverse normal stack, and
++ * thus call conntrack on the icmp packet */
++ icmp_send(skb, ICMP_TIME_EXCEEDED,
++ ICMP_EXC_TTL, 0);
++ }
++
++ return NF_DROP;
++ }
++
++ /*
++ * If we are at INPUT the checksum must be recalculated since
++ * the length could change as the result of a defragmentation.
++ */
++ if(hooknum == NF_IP_LOCAL_IN) {
++ iph->ttl = iph->ttl - 1;
++ iph->check = 0;
++ iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
++ } else {
++ ip_decrease_ttl(iph);
++ }
++ }
++
++ if ((route_info->flags & IPT_ROUTE_TEE)) {
++ /*
++ * Copy the *pskb, and route the copy. Will later return
++ * IPT_CONTINUE for the original skb, which should continue
++ * on its way as if nothing happened. The copy should be
++ * independantly delivered to the ROUTE --gw.
++ */
++ skb = skb_copy(*pskb, GFP_ATOMIC);
++ if (!skb) {
++ if (net_ratelimit())
++ DEBUGP(KERN_DEBUG "ipt_ROUTE: copy failed!\n");
++ return IPT_CONTINUE;
++ }
++ }
++
++ /* Tell conntrack to forget this packet since it may get confused
++ * when a packet is leaving with dst address == our address.
++ * Good idea ? Dunno. Need advice.
++ *
++ * NEW: mark the skb with our &route_tee_track, so we avoid looping
++ * on any already routed packet.
++ */
++ if (!(route_info->flags & IPT_ROUTE_CONTINUE)) {
++ nf_conntrack_put(skb->nfct);
++ skb->nfct = &route_tee_track.ct_general;
++ skb->nfctinfo = IP_CT_NEW;
++ nf_conntrack_get(skb->nfct);
++ }
++
++ if (route_info->oif[0] != '\0') {
++ res = route_oif(route_info, skb);
++ } else if (route_info->iif[0] != '\0') {
++ res = route_iif(route_info, skb);
++ } else if (route_info->gw) {
++ res = route_gw(route_info, skb);
++ } else {
++ if (net_ratelimit())
++ DEBUGP(KERN_DEBUG "ipt_ROUTE: no parameter !\n");
++ res = IPT_CONTINUE;
++ }
++
++ if ((route_info->flags & IPT_ROUTE_TEE))
++ res = IPT_CONTINUE;
++
++ return res;
+}
+
+
+static int ipt_route_checkentry(const char *tablename,
-+ const void *e,
-+ const struct xt_target *target,
-+ void *targinfo,
-+ unsigned int hook_mask)
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
++ const void *e,
++#else
++ const struct ipt_ip *ip,
++#endif
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17)
++ const struct xt_target *target,
++#endif
++ void *targinfo,
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
++ unsigned int targinfosize,
++#endif
++ unsigned int hook_mask)
+{
-+ if (strcmp(tablename, "mangle") != 0) {
-+ printk("ipt_ROUTE: bad table `%s', use the `mangle' table.\n",
-+ tablename);
-+ return 0;
-+ }
-+
-+ if (hook_mask & ~( (1 << NF_IP_PRE_ROUTING)
-+ | (1 << NF_IP_LOCAL_IN)
-+ | (1 << NF_IP_FORWARD)
-+ | (1 << NF_IP_LOCAL_OUT)
-+ | (1 << NF_IP_POST_ROUTING))) {
-+ printk("ipt_ROUTE: bad hook\n");
-+ return 0;
-+ }
-+
-+ return 1;
++ if (strcmp(tablename, "mangle") != 0) {
++ printk("ipt_ROUTE: bad table `%s', use the `mangle' table.\n",
++ tablename);
++ return 0;
++ }
++
++ if (hook_mask & ~( (1 << NF_IP_PRE_ROUTING)
++ | (1 << NF_IP_LOCAL_IN)
++ | (1 << NF_IP_FORWARD)
++ | (1 << NF_IP_LOCAL_OUT)
++ | (1 << NF_IP_POST_ROUTING))) {
++ printk("ipt_ROUTE: bad hook\n");
++ return 0;
++ }
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
++ if (targinfosize != IPT_ALIGN(sizeof(struct ipt_route_target_info))) {
++ printk(KERN_WARNING "ipt_ROUTE: targinfosize %u != %Zu\n",
++ targinfosize,
++ IPT_ALIGN(sizeof(struct ipt_route_target_info)));
++ return 0;
++ }
++#endif
++
++ return 1;
+}
+
+
-+static struct ipt_target ipt_route_reg = {
-+ .name = "ROUTE",
-+ .target = ipt_route_target,
-+ .targetsize = sizeof(struct ipt_route_target_info),
-+ .checkentry = ipt_route_checkentry,
-+ .me = THIS_MODULE,
++static struct ipt_target ipt_route_reg = {
++ .name = "ROUTE",
++ .target = ipt_route_target,
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17)
++ .targetsize = sizeof(struct ipt_route_target_info),
++#endif
++ .checkentry = ipt_route_checkentry,
++ .me = THIS_MODULE,
+};
+
+static int __init init(void)
+{
-+ /* Set up fake conntrack (stolen from raw.patch):
-+ - to never be deleted, not in any hashes */
-+ atomic_set(&route_tee_track.ct_general.use, 1);
-+ /* - and look it like as a confirmed connection */
-+ set_bit(IPS_CONFIRMED_BIT, &route_tee_track.status);
-+ /* Initialize fake conntrack so that NAT will skip it */
-+ route_tee_track.status |= IPS_NAT_DONE_MASK;
-+
-+ return ipt_register_target(&ipt_route_reg);
++ /* Set up fake conntrack (stolen from raw.patch):
++ - to never be deleted, not in any hashes */
++ atomic_set(&route_tee_track.ct_general.use, 1);
++ /* - and look it like as a confirmed connection */
++ set_bit(IPS_CONFIRMED_BIT, &route_tee_track.status);
++ /* Initialize fake conntrack so that NAT will skip it */
++ route_tee_track.status |= IPS_NAT_DONE_MASK;
++
++ return xt_register_target(&ipt_route_reg);
+}
+
+
+static void __exit fini(void)
+{
-+ ipt_unregister_target(&ipt_route_reg);
++ xt_unregister_target(&ipt_route_reg);
+}
+
+module_init(init);
+module_exit(fini);
-diff -urN linux-2.6.19.old/net/ipv4/netfilter/Kconfig linux-2.6.19.dev/net/ipv4/netfilter/Kconfig
---- linux-2.6.19.old/net/ipv4/netfilter/Kconfig 2006-12-14 03:13:49.000000000 +0100
-+++ linux-2.6.19.dev/net/ipv4/netfilter/Kconfig 2006-12-14 03:13:49.000000000 +0100
-@@ -494,6 +494,23 @@
-
- To compile it as a module, choose M here. If unsure, say N.
+diff -Nur linux-2.6.21.1/net/ipv4/netfilter/Kconfig linux-2.6.21.1-owrt/net/ipv4/netfilter/Kconfig
+--- linux-2.6.21.1/net/ipv4/netfilter/Kconfig 2007-04-27 23:49:26.000000000 +0200
++++ linux-2.6.21.1-owrt/net/ipv4/netfilter/Kconfig 2007-05-23 20:32:22.000000000 +0200
+@@ -657,5 +657,22 @@
+ Allows altering the ARP packet payload: source and destination
+ hardware and network addresses.
+config IP_NF_TARGET_ROUTE
-+ tristate 'ROUTE target support'
-+ depends on IP_NF_MANGLE
-+ help
-+ This option adds a `ROUTE' target, which enables you to setup unusual
-+ routes. For example, the ROUTE lets you route a received packet through
-+ an interface or towards a host, even if the regular destination of the
-+ packet is the router itself. The ROUTE target is also able to change the
-+ incoming interface of a packet.
-+
-+ The target can be or not a final target. It has to be used inside the
-+ mangle table.
-+
-+ If you want to compile it as a module, say M here and read
-+ Documentation/modules.txt. The module will be called ipt_ROUTE.o.
-+ If unsure, say `N'.
-+
- config IP_NF_TARGET_NETMAP
- tristate "NETMAP target support"
- depends on IP_NF_NAT
-diff -urN linux-2.6.19.old/net/ipv4/netfilter/Makefile linux-2.6.19.dev/net/ipv4/netfilter/Makefile
---- linux-2.6.19.old/net/ipv4/netfilter/Makefile 2006-12-14 03:13:49.000000000 +0100
-+++ linux-2.6.19.dev/net/ipv4/netfilter/Makefile 2006-12-14 03:13:49.000000000 +0100
-@@ -74,6 +74,7 @@
- obj-$(CONFIG_IP_NF_TARGET_IMQ) += ipt_IMQ.o
++ tristate 'ROUTE target support'
++ depends on IP_NF_MANGLE
++ help
++ This option adds a `ROUTE' target, which enables you to setup unusual
++ routes. For example, the ROUTE lets you route a received packet through
++ an interface or towards a host, even if the regular destination of the
++ packet is the router itself. The ROUTE target is also able to change the
++ incoming interface of a packet.
++
++ The target can be or not a final target. It has to be used inside the
++ mangle table.
++
++ If you want to compile it as a module, say M here and read
++ Documentation/modules.txt. The module will be called ipt_ROUTE.o.
++ If unsure, say `N'.
++
+ endmenu
+
+diff -Nur linux-2.6.21.1/net/ipv4/netfilter/Makefile linux-2.6.21.1-owrt/net/ipv4/netfilter/Makefile
+--- linux-2.6.21.1/net/ipv4/netfilter/Makefile 2007-04-27 23:49:26.000000000 +0200
++++ linux-2.6.21.1-owrt/net/ipv4/netfilter/Makefile 2007-05-23 20:32:22.000000000 +0200
+@@ -98,6 +98,7 @@
+ obj-$(CONFIG_IP_NF_TARGET_ECN) += ipt_ECN.o
obj-$(CONFIG_IP_NF_TARGET_MASQUERADE) += ipt_MASQUERADE.o
obj-$(CONFIG_IP_NF_TARGET_REDIRECT) += ipt_REDIRECT.o
+obj-$(CONFIG_IP_NF_TARGET_ROUTE) += ipt_ROUTE.o
obj-$(CONFIG_IP_NF_TARGET_NETMAP) += ipt_NETMAP.o
obj-$(CONFIG_IP_NF_TARGET_SAME) += ipt_SAME.o
obj-$(CONFIG_IP_NF_NAT_SNMP_BASIC) += ip_nat_snmp_basic.o
-diff -urN linux-2.6.19.old/net/ipv6/ipv6_syms.c linux-2.6.19.dev/net/ipv6/ipv6_syms.c
---- linux-2.6.19.old/net/ipv6/ipv6_syms.c 2006-11-29 22:57:37.000000000 +0100
-+++ linux-2.6.19.dev/net/ipv6/ipv6_syms.c 2006-12-14 03:13:49.000000000 +0100
-@@ -11,6 +11,7 @@
+diff -Nur linux-2.6.21.1/net/ipv6/ipv6_syms.c linux-2.6.21.1-owrt/net/ipv6/ipv6_syms.c
+--- linux-2.6.21.1/net/ipv6/ipv6_syms.c 2007-04-27 23:49:26.000000000 +0200
++++ linux-2.6.21.1-owrt/net/ipv6/ipv6_syms.c 2007-05-23 20:32:22.000000000 +0200
+@@ -10,6 +10,7 @@
EXPORT_SYMBOL(icmpv6_statistics);
EXPORT_SYMBOL(icmpv6_err_convert);
EXPORT_SYMBOL(ndisc_mc_map);
@@ -560,10 +587,10 @@ diff -urN linux-2.6.19.old/net/ipv6/ipv6_syms.c linux-2.6.19.dev/net/ipv6/ipv6_s
EXPORT_SYMBOL(register_inet6addr_notifier);
EXPORT_SYMBOL(unregister_inet6addr_notifier);
EXPORT_SYMBOL(ip6_route_output);
-diff -urN linux-2.6.19.old/net/ipv6/netfilter/ip6t_ROUTE.c linux-2.6.19.dev/net/ipv6/netfilter/ip6t_ROUTE.c
---- linux-2.6.19.old/net/ipv6/netfilter/ip6t_ROUTE.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.19.dev/net/ipv6/netfilter/ip6t_ROUTE.c 2006-12-14 03:13:49.000000000 +0100
-@@ -0,0 +1,302 @@
+diff -Nur linux-2.6.21.1/net/ipv6/netfilter/ip6t_ROUTE.c linux-2.6.21.1-owrt/net/ipv6/netfilter/ip6t_ROUTE.c
+--- linux-2.6.21.1/net/ipv6/netfilter/ip6t_ROUTE.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.21.1-owrt/net/ipv6/netfilter/ip6t_ROUTE.c 2007-05-23 20:32:22.000000000 +0200
+@@ -0,0 +1,330 @@
+/*
+ * This implements the ROUTE v6 target, which enables you to setup unusual
+ * routes not supported by the standard kernel routing table.
@@ -581,6 +608,7 @@ diff -urN linux-2.6.19.old/net/ipv6/netfilter/ip6t_ROUTE.c linux-2.6.19.dev/net/
+#include <linux/netfilter_ipv6/ip6_tables.h>
+#include <linux/netfilter_ipv6/ip6t_ROUTE.h>
+#include <linux/netdevice.h>
++#include <linux/version.h>
+#include <net/ipv6.h>
+#include <net/ndisc.h>
+#include <net/ip6_route.h>
@@ -593,85 +621,85 @@ diff -urN linux-2.6.19.old/net/ipv6/netfilter/ip6t_ROUTE.c linux-2.6.19.dev/net/
+#endif
+
+#define NIP6(addr) \
-+ ntohs((addr).s6_addr16[0]), \
-+ ntohs((addr).s6_addr16[1]), \
-+ ntohs((addr).s6_addr16[2]), \
-+ ntohs((addr).s6_addr16[3]), \
-+ ntohs((addr).s6_addr16[4]), \
-+ ntohs((addr).s6_addr16[5]), \
-+ ntohs((addr).s6_addr16[6]), \
-+ ntohs((addr).s6_addr16[7])
++ ntohs((addr).s6_addr16[0]), \
++ ntohs((addr).s6_addr16[1]), \
++ ntohs((addr).s6_addr16[2]), \
++ ntohs((addr).s6_addr16[3]), \
++ ntohs((addr).s6_addr16[4]), \
++ ntohs((addr).s6_addr16[5]), \
++ ntohs((addr).s6_addr16[6]), \
++ ntohs((addr).s6_addr16[7])
+
+/* Route the packet according to the routing keys specified in
+ * route_info. Keys are :
-+ * - ifindex :
-+ * 0 if no oif preferred,
++ * - ifindex :
++ * 0 if no oif preferred,
+ * otherwise set to the index of the desired oif
+ * - route_info->gw :
+ * 0 if no gateway specified,
+ * otherwise set to the next host to which the pkt must be routed
-+ * If success, skb->dev is the output device to which the packet must
++ * If success, skb->dev is the output device to which the packet must
+ * be sent and skb->dst is not NULL
+ *
-+ * RETURN: 1 if the packet was succesfully routed to the
++ * RETURN: 1 if the packet was succesfully routed to the
+ * destination desired
+ * 0 if the kernel routing table could not route the packet
+ * according to the keys specified
+ */
-+static int
++static int
+route6(struct sk_buff *skb,
+ unsigned int ifindex,
+ const struct ip6t_route_target_info *route_info)
+{
-+ struct rt6_info *rt = NULL;
-+ struct ipv6hdr *ipv6h = skb->nh.ipv6h;
-+ struct in6_addr *gw = (struct in6_addr*)&route_info->gw;
-+
-+ DEBUGP("ip6t_ROUTE: called with: ");
-+ DEBUGP("DST=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", NIP6(ipv6h->daddr));
-+ DEBUGP("GATEWAY=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", NIP6(*gw));
-+ DEBUGP("OUT=%s\n", route_info->oif);
-+
-+ if (ipv6_addr_any(gw))
-+ rt = rt6_lookup(&ipv6h->daddr, &ipv6h->saddr, ifindex, 1);
-+ else
-+ rt = rt6_lookup(gw, &ipv6h->saddr, ifindex, 1);
-+
-+ if (!rt)
-+ goto no_route;
-+
-+ DEBUGP("ip6t_ROUTE: routing gives: ");
-+ DEBUGP("DST=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", NIP6(rt->rt6i_dst.addr));
-+ DEBUGP("GATEWAY=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", NIP6(rt->rt6i_gateway));
-+ DEBUGP("OUT=%s\n", rt->rt6i_dev->name);
-+
-+ if (ifindex && rt->rt6i_dev->ifindex!=ifindex)
-+ goto wrong_route;
-+
-+ if (!rt->rt6i_nexthop) {
-+ DEBUGP("ip6t_ROUTE: discovering neighbour\n");
-+ rt->rt6i_nexthop = ndisc_get_neigh(rt->rt6i_dev, &rt->rt6i_dst.addr);
-+ }
-+
-+ /* Drop old route. */
-+ dst_release(skb->dst);
-+ skb->dst = &rt->u.dst;
-+ skb->dev = rt->rt6i_dev;
-+ return 1;
++ struct rt6_info *rt = NULL;
++ struct ipv6hdr *ipv6h = skb->nh.ipv6h;
++ struct in6_addr *gw = (struct in6_addr*)&route_info->gw;
++
++ DEBUGP("ip6t_ROUTE: called with: ");
++ DEBUGP("DST=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", NIP6(ipv6h->daddr));
++ DEBUGP("GATEWAY=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", NIP6(*gw));
++ DEBUGP("OUT=%s\n", route_info->oif);
++
++ if (ipv6_addr_any(gw))
++ rt = rt6_lookup(&ipv6h->daddr, &ipv6h->saddr, ifindex, 1);
++ else
++ rt = rt6_lookup(gw, &ipv6h->saddr, ifindex, 1);
++
++ if (!rt)
++ goto no_route;
++
++ DEBUGP("ip6t_ROUTE: routing gives: ");
++ DEBUGP("DST=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", NIP6(rt->rt6i_dst.addr));
++ DEBUGP("GATEWAY=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", NIP6(rt->rt6i_gateway));
++ DEBUGP("OUT=%s\n", rt->rt6i_dev->name);
++
++ if (ifindex && rt->rt6i_dev->ifindex!=ifindex)
++ goto wrong_route;
++
++ if (!rt->rt6i_nexthop) {
++ DEBUGP("ip6t_ROUTE: discovering neighbour\n");
++ rt->rt6i_nexthop = ndisc_get_neigh(rt->rt6i_dev, &rt->rt6i_dst.addr);
++ }
++
++ /* Drop old route. */
++ dst_release(skb->dst);
++ skb->dst = &rt->u.dst;
++ skb->dev = rt->rt6i_dev;
++ return 1;
+
+ wrong_route:
-+ dst_release(&rt->u.dst);
++ dst_release(&rt->u.dst);
+ no_route:
-+ if (!net_ratelimit())
-+ return 0;
-+
-+ printk("ip6t_ROUTE: no explicit route found ");
-+ if (ifindex)
-+ printk("via interface %s ", route_info->oif);
-+ if (!ipv6_addr_any(gw))
-+ printk("via gateway %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x", NIP6(*gw));
-+ printk("\n");
-+ return 0;
++ if (!net_ratelimit())
++ return 0;
++
++ printk("ip6t_ROUTE: no explicit route found ");
++ if (ifindex)
++ printk("via interface %s ", route_info->oif);
++ if (!ipv6_addr_any(gw))
++ printk("via gateway %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x", NIP6(*gw));
++ printk("\n");
++ return 0;
+}
+
+
@@ -683,220 +711,246 @@ diff -urN linux-2.6.19.old/net/ipv6/netfilter/ip6t_ROUTE.c linux-2.6.19.dev/net/
+ */
+static void ip_direct_send(struct sk_buff *skb)
+{
-+ struct dst_entry *dst = skb->dst;
-+ struct hh_cache *hh = dst->hh;
-+
-+ if (hh) {
-+ read_lock_bh(&hh->hh_lock);
-+ memcpy(skb->data - 16, hh->hh_data, 16);
-+ read_unlock_bh(&hh->hh_lock);
-+ skb_push(skb, hh->hh_len);
-+ hh->hh_output(skb);
-+ } else if (dst->neighbour)
-+ dst->neighbour->output(skb);
-+ else {
-+ if (net_ratelimit())
-+ DEBUGP(KERN_DEBUG "ip6t_ROUTE: no hdr & no neighbour cache!\n");
-+ kfree_skb(skb);
-+ }
++ struct dst_entry *dst = skb->dst;
++ struct hh_cache *hh = dst->hh;
++
++ if (hh) {
++ read_lock_bh(&hh->hh_lock);
++ memcpy(skb->data - 16, hh->hh_data, 16);
++ read_unlock_bh(&hh->hh_lock);
++ skb_push(skb, hh->hh_len);
++ hh->hh_output(skb);
++ } else if (dst->neighbour)
++ dst->neighbour->output(skb);
++ else {
++ if (net_ratelimit())
++ DEBUGP(KERN_DEBUG "ip6t_ROUTE: no hdr & no neighbour cache!\n");
++ kfree_skb(skb);
++ }
+}
+
+
-+static unsigned int
++static unsigned int
+route6_oif(const struct ip6t_route_target_info *route_info,
-+ struct sk_buff *skb)
++ struct sk_buff *skb)
+{
-+ unsigned int ifindex = 0;
-+ struct net_device *dev_out = NULL;
-+
-+ /* The user set the interface name to use.
-+ * Getting the current interface index.
-+ */
-+ if ((dev_out = dev_get_by_name(route_info->oif))) {
-+ ifindex = dev_out->ifindex;
-+ } else {
-+ /* Unknown interface name : packet dropped */
-+ if (net_ratelimit())
-+ DEBUGP("ip6t_ROUTE: oif interface %s not found\n", route_info->oif);
-+
-+ if (route_info->flags & IP6T_ROUTE_CONTINUE)
-+ return IP6T_CONTINUE;
-+ else
-+ return NF_DROP;
-+ }
-+
-+ /* Trying the standard way of routing packets */
-+ if (route6(skb, ifindex, route_info)) {
-+ dev_put(dev_out);
-+ if (route_info->flags & IP6T_ROUTE_CONTINUE)
-+ return IP6T_CONTINUE;
-+
-+ ip_direct_send(skb);
-+ return NF_STOLEN;
-+ } else
-+ return NF_DROP;
++ unsigned int ifindex = 0;
++ struct net_device *dev_out = NULL;
++
++ /* The user set the interface name to use.
++ * Getting the current interface index.
++ */
++ if ((dev_out = dev_get_by_name(route_info->oif))) {
++ ifindex = dev_out->ifindex;
++ } else {
++ /* Unknown interface name : packet dropped */
++ if (net_ratelimit())
++ DEBUGP("ip6t_ROUTE: oif interface %s not found\n", route_info->oif);
++
++ if (route_info->flags & IP6T_ROUTE_CONTINUE)
++ return IP6T_CONTINUE;
++ else
++ return NF_DROP;
++ }
++
++ /* Trying the standard way of routing packets */
++ if (route6(skb, ifindex, route_info)) {
++ dev_put(dev_out);
++ if (route_info->flags & IP6T_ROUTE_CONTINUE)
++ return IP6T_CONTINUE;
++
++ ip_direct_send(skb);
++ return NF_STOLEN;
++ } else
++ return NF_DROP;
+}
+
+
-+static unsigned int
++static unsigned int
+route6_gw(const struct ip6t_route_target_info *route_info,
-+ struct sk_buff *skb)
++ struct sk_buff *skb)
+{
-+ if (route6(skb, 0, route_info)) {
-+ if (route_info->flags & IP6T_ROUTE_CONTINUE)
-+ return IP6T_CONTINUE;
-+
-+ ip_direct_send(skb);
-+ return NF_STOLEN;
-+ } else
-+ return NF_DROP;
++ if (route6(skb, 0, route_info)) {
++ if (route_info->flags & IP6T_ROUTE_CONTINUE)
++ return IP6T_CONTINUE;
++
++ ip_direct_send(skb);
++ return NF_STOLEN;
++ } else
++ return NF_DROP;
+}
+
+
-+static unsigned int
++static unsigned int
+ip6t_route_target(struct sk_buff **pskb,
-+ const struct net_device *in,
-+ const struct net_device *out,
-+ unsigned int hooknum,
-+ const struct xt_target *target,
-+ const void *targinfo)
++ const struct net_device *in,
++ const struct net_device *out,
++ unsigned int hooknum,
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17)
++ const struct xt_target *target,
++#endif
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
++ const void *targinfo,
++ void *userinfo)
++#else
++ const void *targinfo)
++#endif
+{
-+ const struct ip6t_route_target_info *route_info = targinfo;
-+ struct sk_buff *skb = *pskb;
-+ struct in6_addr *gw = (struct in6_addr*)&route_info->gw;
-+ unsigned int res;
-+
-+ if (route_info->flags & IP6T_ROUTE_CONTINUE)
-+ goto do_it;
-+
-+ /* If we are at PREROUTING or INPUT hook
-+ * the TTL isn't decreased by the IP stack
-+ */
-+ if (hooknum == NF_IP6_PRE_ROUTING ||
-+ hooknum == NF_IP6_LOCAL_IN) {
-+
-+ struct ipv6hdr *ipv6h = skb->nh.ipv6h;
-+
-+ if (ipv6h->hop_limit <= 1) {
-+ /* Force OUTPUT device used as source address */
-+ skb->dev = skb->dst->dev;
-+
-+ icmpv6_send(skb, ICMPV6_TIME_EXCEED,
-+ ICMPV6_EXC_HOPLIMIT, 0, skb->dev);
-+
-+ return NF_DROP;
-+ }
-+
-+ ipv6h->hop_limit--;
-+ }
-+
-+ if ((route_info->flags & IP6T_ROUTE_TEE)) {
-+ /*
-+ * Copy the *pskb, and route the copy. Will later return
-+ * IP6T_CONTINUE for the original skb, which should continue
-+ * on its way as if nothing happened. The copy should be
-+ * independantly delivered to the ROUTE --gw.
-+ */
-+ skb = skb_copy(*pskb, GFP_ATOMIC);
-+ if (!skb) {
-+ if (net_ratelimit())
-+ DEBUGP(KERN_DEBUG "ip6t_ROUTE: copy failed!\n");
-+ return IP6T_CONTINUE;
-+ }
-+ }
++ const struct ip6t_route_target_info *route_info = targinfo;
++ struct sk_buff *skb = *pskb;
++ struct in6_addr *gw = (struct in6_addr*)&route_info->gw;
++ unsigned int res;
++
++ if (route_info->flags & IP6T_ROUTE_CONTINUE)
++ goto do_it;
++
++ /* If we are at PREROUTING or INPUT hook
++ * the TTL isn't decreased by the IP stack
++ */
++ if (hooknum == NF_IP6_PRE_ROUTING ||
++ hooknum == NF_IP6_LOCAL_IN) {
++
++ struct ipv6hdr *ipv6h = skb->nh.ipv6h;
++
++ if (ipv6h->hop_limit <= 1) {
++ /* Force OUTPUT device used as source address */
++ skb->dev = skb->dst->dev;
++
++ icmpv6_send(skb, ICMPV6_TIME_EXCEED,
++ ICMPV6_EXC_HOPLIMIT, 0, skb->dev);
++
++ return NF_DROP;
++ }
++
++ ipv6h->hop_limit--;
++ }
++
++ if ((route_info->flags & IP6T_ROUTE_TEE)) {
++ /*
++ * Copy the *pskb, and route the copy. Will later return
++ * IP6T_CONTINUE for the original skb, which should continue
++ * on its way as if nothing happened. The copy should be
++ * independantly delivered to the ROUTE --gw.
++ */
++ skb = skb_copy(*pskb, GFP_ATOMIC);
++ if (!skb) {
++ if (net_ratelimit())
++ DEBUGP(KERN_DEBUG "ip6t_ROUTE: copy failed!\n");
++ return IP6T_CONTINUE;
++ }
++ }
+
+do_it:
-+ if (route_info->oif[0]) {
-+ res = route6_oif(route_info, skb);
-+ } else if (!ipv6_addr_any(gw)) {
-+ res = route6_gw(route_info, skb);
-+ } else {
-+ if (net_ratelimit())
-+ DEBUGP(KERN_DEBUG "ip6t_ROUTE: no parameter !\n");
-+ res = IP6T_CONTINUE;
-+ }
-+
-+ if ((route_info->flags & IP6T_ROUTE_TEE))
-+ res = IP6T_CONTINUE;
-+
-+ return res;
++ if (route_info->oif[0]) {
++ res = route6_oif(route_info, skb);
++ } else if (!ipv6_addr_any(gw)) {
++ res = route6_gw(route_info, skb);
++ } else {
++ if (net_ratelimit())
++ DEBUGP(KERN_DEBUG "ip6t_ROUTE: no parameter !\n");
++ res = IP6T_CONTINUE;
++ }
++
++ if ((route_info->flags & IP6T_ROUTE_TEE))
++ res = IP6T_CONTINUE;
++
++ return res;
+}
+
+
-+static int
++static int
+ip6t_route_checkentry(const char *tablename,
-+ const void *e,
-+ const struct xt_target *target,
-+ void *targinfo,
-+ unsigned int hook_mask)
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
++ const void *entry,
++#else
++ const struct ip6t_entry *entry
++#endif
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17)
++ const struct xt_target *target,
++#endif
++ void *targinfo,
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
++ unsigned int targinfosize,
++#endif
++ unsigned int hook_mask)
+{
-+ if (strcmp(tablename, "mangle") != 0) {
-+ printk("ip6t_ROUTE: can only be called from \"mangle\" table.\n");
-+ return 0;
-+ }
++ if (strcmp(tablename, "mangle") != 0) {
++ printk("ip6t_ROUTE: can only be called from \"mangle\" table.\n");
++ return 0;
++ }
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
++ if (targinfosize != IP6T_ALIGN(sizeof(struct ip6t_route_target_info))) {
++ printk(KERN_WARNING "ip6t_ROUTE: targinfosize %u != %Zu\n",
++ targinfosize,
++ IP6T_ALIGN(sizeof(struct ip6t_route_target_info)));
++ return 0;
++ }
++#endif
+
-+ return 1;
++ return 1;
+}
+
+
+static struct ip6t_target ip6t_route_reg = {
-+ .name = "ROUTE",
-+ .target = ip6t_route_target,
-+ .targetsize = sizeof(struct ip6t_route_target_info),
-+ .checkentry = ip6t_route_checkentry,
-+ .me = THIS_MODULE
++ .name = "ROUTE",
++ .target = ip6t_route_target,
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17)
++ .targetsize = sizeof(struct ip6t_route_target_info),
++#endif
++ .checkentry = ip6t_route_checkentry,
++ .me = THIS_MODULE
+};
+
+
+static int __init init(void)
+{
-+ printk(KERN_DEBUG "registering ipv6 ROUTE target\n");
-+ if (ip6t_register_target(&ip6t_route_reg))
-+ return -EINVAL;
++ printk(KERN_DEBUG "registering ipv6 ROUTE target\n");
++ if (ip6t_register_target(&ip6t_route_reg))
++ return -EINVAL;
+
-+ return 0;
++ return 0;
+}
+
+
+static void __exit fini(void)
+{
-+ ip6t_unregister_target(&ip6t_route_reg);
++ ip6t_unregister_target(&ip6t_route_reg);
+}
+
+module_init(init);
+module_exit(fini);
+MODULE_LICENSE("GPL");
-diff -urN linux-2.6.19.old/net/ipv6/netfilter/Kconfig linux-2.6.19.dev/net/ipv6/netfilter/Kconfig
---- linux-2.6.19.old/net/ipv6/netfilter/Kconfig 2006-12-14 03:13:49.000000000 +0100
-+++ linux-2.6.19.dev/net/ipv6/netfilter/Kconfig 2006-12-14 03:13:49.000000000 +0100
-@@ -162,6 +162,19 @@
-
- To compile it as a module, choose M here. If unsure, say N.
+diff -Nur linux-2.6.21.1/net/ipv6/netfilter/Kconfig linux-2.6.21.1-owrt/net/ipv6/netfilter/Kconfig
+--- linux-2.6.21.1/net/ipv6/netfilter/Kconfig 2007-04-27 23:49:26.000000000 +0200
++++ linux-2.6.21.1-owrt/net/ipv6/netfilter/Kconfig 2007-05-23 20:32:22.000000000 +0200
+@@ -200,5 +200,18 @@
+ If you want to compile it as a module, say M here and read
+ <file:Documentation/modules.txt>. If unsure, say `N'.
+config IP6_NF_TARGET_ROUTE
-+ tristate "ROUTE target support"
-+ depends on IP6_NF_MANGLE
-+ help
-+ This option adds a `ROUTE' target, which enables you to setup unusual
-+ routes. The ROUTE target is also able to change the incoming interface
-+ of a packet.
-+
-+ The target can be or not a final target. It has to be used inside the
-+ mangle table.
-+
-+ Not working as a module.
-+
- config IP6_NF_MANGLE
- tristate "Packet mangling"
- depends on IP6_NF_IPTABLES
-diff -urN linux-2.6.19.old/net/ipv6/netfilter/Makefile linux-2.6.19.dev/net/ipv6/netfilter/Makefile
---- linux-2.6.19.old/net/ipv6/netfilter/Makefile 2006-12-14 03:13:49.000000000 +0100
-+++ linux-2.6.19.dev/net/ipv6/netfilter/Makefile 2006-12-14 03:13:49.000000000 +0100
-@@ -20,6 +20,7 @@
++ tristate 'ROUTE target support'
++ depends on IP6_NF_MANGLE
++ help
++ This option adds a `ROUTE' target, which enables you to setup unusual
++ routes. The ROUTE target is also able to change the incoming interface
++ of a packet.
++
++ The target can be or not a final target. It has to be used inside the
++ mangle table.
++
++ Not working as a module.
++
+ endmenu
+
+diff -Nur linux-2.6.21.1/net/ipv6/netfilter/Makefile linux-2.6.21.1-owrt/net/ipv6/netfilter/Makefile
+--- linux-2.6.21.1/net/ipv6/netfilter/Makefile 2007-04-27 23:49:26.000000000 +0200
++++ linux-2.6.21.1-owrt/net/ipv6/netfilter/Makefile 2007-05-23 20:32:22.000000000 +0200
+@@ -19,6 +19,7 @@
obj-$(CONFIG_IP6_NF_RAW) += ip6table_raw.o
obj-$(CONFIG_IP6_NF_MATCH_HL) += ip6t_hl.o
obj-$(CONFIG_IP6_NF_TARGET_REJECT) += ip6t_REJECT.o
+obj-$(CONFIG_IP6_NF_TARGET_ROUTE) += ip6t_ROUTE.o
+ obj-$(CONFIG_IP6_NF_MATCH_MH) += ip6t_mh.o
# objects for l3 independent conntrack
- nf_conntrack_ipv6-objs := nf_conntrack_l3proto_ipv6.o nf_conntrack_proto_icmpv6.o nf_conntrack_reasm.o