break trunk temporary - upgrade to 2.6.21.1 and iptables 1.3.7
[openwrt/staging/chunkeey.git] / target / linux / generic-2.6 / patches / 160-netfilter_route.patch
index 7e8491c3e3b2673e5c6f910d53e0b9c11f65e594..0d73ba3193a7a6906a5a92450fa9e6748c4a1392 100644 (file)
@@ -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