Fazal,

I took your bridge-nf-0.0.6-against-2.4.17.diff and applied to kernel-2.4.9.
Seems to work. Thanks for your effort. However, I needed something else.
- Support for bridge filtering with IPv6 was missing, that is, to work with
  ip6tables I hacked:
  - include/linux/netfilter_ipv6.h: sabotage def. addition
  - net/bridge/br_netfilter.c IPv6 support addition
  - net/ipv6/netfilter/ip6_tables.c IPv6 support hooks addition
In the attached patch there are 3 diffs from these files just catenated.
It works in my kernel, so in case you want to patch them in, pse go ahead.
I ignored the NAT support and did not do all the details ready (cf. #if 0s).
The patch is not exactly against your patch but the actual files in linux.

BR,

-Jari
--- linux/include/linux/netfilter_ipv6.h.v4orig Sun Mar 24 01:18:05 2002
+++ linux/include/linux/netfilter_ipv6.h        Sun Mar 24 01:19:27 2002
@@ -59,6 +59,7 @@
        NF_IP6_PRI_CONNTRACK = -200,
        NF_IP6_PRI_MANGLE = -150,
        NF_IP6_PRI_NAT_DST = -100,
+       NF_IP6_PRI_BRIDGE_SABOTAGE = -50,
        NF_IP6_PRI_FILTER = 0,
        NF_IP6_PRI_NAT_SRC = 100,
        NF_IP6_PRI_LAST = INT_MAX,
--- linux/net/bridge/br_netfilter.c.v4orig      Sat Mar 23 00:14:16 2002
+++ linux/net/bridge/br_netfilter.c     Sun Mar 24 01:09:57 2002
@@ -5,6 +5,7 @@
  *     Authors:
  *     Lennert Buytenhek               <[EMAIL PROTECTED]>
  *     Bart De Schuymer                <[EMAIL PROTECTED]>
+ *     Jari T. Malinen (IPv6 support)  <[EMAIL PROTECTED]>
  *
  *     $Id: bridge-nf-0.0.6-against-2.4.18.diff,v 1.2 2002/02/26 04:11:56 buytenh Exp 
$
  *
@@ -17,19 +18,23 @@
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/ip.h>
+#include <linux/ipv6.h>
 #include <linux/netdevice.h>
 #include <linux/skbuff.h>
 #include <linux/if_ether.h>
 #include <linux/netfilter_bridge.h>
 #include <linux/netfilter_ipv4.h>
+#include <linux/netfilter_ipv6.h>
 #include <linux/in_route.h>
+#include <linux/ipv6_route.h>
 #include <net/ip.h>
+#include <net/ipv6.h>
 #include <net/tcp.h>
 #include <asm/uaccess.h>
 #include <asm/checksum.h>
 #include "br_private.h"
 
-
+#define WE_REALLY_INSIST_ON_NOT_HAVING_NAT_SUPPORT
 
 #ifndef WE_REALLY_INSIST_ON_NOT_HAVING_NAT_SUPPORT
 /* As the original source/destination addresses are variables private to this
@@ -46,11 +51,22 @@
 #define store_orig_srcaddr(skb)                (skb_origaddr(skb) = 
(skb)->nh.iph->saddr)
 #define dnat_took_place(skb)           (skb_origaddr(skb) != (skb)->nh.iph->daddr)
 #define snat_took_place(skb)           (skb_origaddr(skb) != (skb)->nh.iph->saddr)
+#define skb_origaddr6(skb)             (*((struct in6_addr*)((skb)->cb + 
+sizeof((skb)->cb)))) /* - 16 XXX doesn't fit */
+#define store_orig_dstaddr6(skb)       (skb_origaddr6(skb) = (skb)->nh.ipv6h->daddr)
+#define store_orig_srcaddr6(skb)       (skb_origaddr6(skb) = (skb)->nh.ipv6h->saddr)
+#define dnat6_took_place(skb)          (skb_origaddr6(skb) != (skb)->nh.ipv6h->daddr)
+#define snat6_took_place(skb)          (skb_origaddr6(skb) != (skb)->nh.ipv6h->saddr)
+
 #else
 #define store_orig_dstaddr(skb)
 #define store_orig_srcaddr(skb)
 #define dnat_took_place(skb)           (0)
 #define snat_took_place(skb)           (0)
+#define store_orig_dstaddr6(skb)
+#define store_orig_srcaddr6(skb)
+#define dnat6_took_place(skb)          (0)
+#define snat6_took_place(skb)          (0)
+
 #endif
 
 
@@ -58,6 +74,7 @@
 #define bridge_parent(device)          (&((device)->br_port->br->dev))
 
 
+/* IPv4 */
 static inline void __maybe_fixup_src_address(struct sk_buff *skb)
 {
        if (snat_took_place(skb) &&
@@ -68,6 +85,19 @@
        }
 }
 
+/* IPv6 XXX no NAT */
+static inline void __maybe_fixup_src6_address(struct sk_buff *skb)
+{
+#if 0
+       if (snat_took_place(skb) &&
+           inet6_addr_type(skb->nh.ipiv6h->saddr) == RTF_LOCAL) { /* XXX */
+               memcpy(skb->mac.ethernet->h_source,
+                       bridge_parent(skb->dev)->dev_addr,
+                       ETH_ALEN);
+       }
+#endif
+}
+
 static struct net_device __fake_net_device = {
        hard_header_len:        ETH_HLEN
 };
@@ -84,7 +114,9 @@
        rt_flags:       0
 };
 
-
+/*
+ * ########## IPv4 ###########>
+ */
 /* PF_BRIDGE/PRE_ROUTING *********************************************/
 static int br_nf_pre_routing_finish(struct sk_buff *skb)
 {
@@ -301,6 +333,231 @@
 }
 
 
+/*
+ * ########## IPv6 ###########>
+ */
+/* PF_BRIDGE/PRE_ROUTING *********************************************/
+static int br_nf6_pre_routing_finish(struct sk_buff *skb)
+{
+#if 0
+/* We dont't care about NAT.. */
+       struct net_device *dev = skb->dev;
+       struct ipv6hdr *iph = skb->nh.ipv6h;
+
+       if (dnat_took_place(skb)) {
+               if (ip6_route_input(skb)) {
+                       struct rtable *rt;
+
+                       if (ip6_route_output(foo,bar)) { /* XXX */
+                               /* This test is racy.  */
+                               if (!ip6_route_output(foo,bar))
+                                       BUG();
+
+                               kfree_skb(skb);
+                               return 0;
+                       }
+
+                       skb->dst = (struct dst_entry *)rt;
+
+                       /* This changes source ethernet address.  */
+                       skb->dst->output(skb);
+                       return 0;
+               } else {
+                       memcpy(skb->mac.ethernet->h_dest, dev->dev_addr, ETH_ALEN);
+               }
+       } else {
+#endif
+               skb->dst = (struct dst_entry *)&__fake_rtable;
+               dst_hold(skb->dst);
+#if 0
+       }
+#endif
+       skb->dev = skb->physindev;
+       NF_HOOK_THRESH(PF_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL,
+                       br_handle_frame_finish, 1);
+
+       return 0;
+}
+
+static unsigned int br_nf6_pre_routing(unsigned int hook, struct sk_buff **pskb, 
+const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff 
+*))
+{
+       struct ipv6hdr *iph;
+       __u32 len;
+       struct sk_buff *skb;
+
+       if ((*pskb)->mac.ethernet->h_proto != __constant_htons(ETH_P_IPV6))
+               return NF_ACCEPT;
+
+       if ((skb = skb_share_check(*pskb, GFP_ATOMIC)) == NULL)
+               goto out;
+
+       if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
+               goto inhdr_error;
+
+       iph = skb->nh.ipv6h;
+       len = skb->len = ntohs(iph->payload_len) + 40;
+
+       if (iph->priority < 0 || iph->version != 6)
+               goto inhdr_error;
+
+       if (!pskb_may_pull(skb, 4*iph->priority))
+               goto inhdr_error;
+
+       iph = skb->nh.ipv6h;
+#if 0
+       if (ipv6_fast_csum((__u8 *)iph, iph->priority) != 0)
+               goto inhdr_error;
+#endif
+       if (skb->len < len || len < 4*iph->priority)
+               goto inhdr_error;
+
+       if (skb->len > len) {
+               __pskb_trim(skb, len);
+               if (skb->ip_summed == CHECKSUM_HW)
+                       skb->ip_summed = CHECKSUM_NONE;
+       }
+
+       skb->physindev = skb->dev;
+       skb->dev = bridge_parent(skb->dev);
+       if (skb->pkt_type == PACKET_OTHERHOST)
+               skb->pkt_type = PACKET_HOST;
+       store_orig_dstaddr(skb);
+       NF_HOOK(PF_INET6, NF_IP6_PRE_ROUTING, skb, skb->dev, NULL,
+               br_nf6_pre_routing_finish);
+
+       return NF_STOLEN;
+
+inhdr_error:
+//     IP_INC_STATS_BH(IpInHdrErrors);
+out:
+       return NF_DROP;
+}
+
+
+/* PF_BRIDGE/LOCAL_IN ************************************************/
+static unsigned int br_nf6_local_in(unsigned int hook, struct sk_buff **pskb, const 
+struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *))
+{
+       struct sk_buff *skb = *pskb;
+
+       if (skb->mac.ethernet->h_proto != __constant_htons(ETH_P_IPV6))
+               return NF_ACCEPT;
+
+       if (skb->dst == (struct dst_entry *)&__fake_rtable) {
+               dst_release(skb->dst);
+               skb->dst = NULL;
+       }
+
+       return NF_ACCEPT;
+}
+
+
+/* PF_BRIDGE/FORWARD *************************************************/
+static int br_nf6_forward_finish(struct sk_buff *skb)
+{
+       NF_HOOK_THRESH(PF_BRIDGE, NF_BR_FORWARD, skb, skb->physindev,
+                       skb->dev, br_forward_finish, 1);
+
+       return 0;
+}
+
+static unsigned int br_nf6_forward(unsigned int hook, struct sk_buff **pskb, const 
+struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *))
+{
+       struct sk_buff *skb = *pskb;
+
+       if (skb->mac.ethernet->h_proto != __constant_htons(ETH_P_IPV6))
+               return NF_ACCEPT;
+
+       skb->physoutdev = skb->dev;
+       NF_HOOK(PF_INET6, NF_IP6_FORWARD, skb, bridge_parent(skb->physindev),
+                       bridge_parent(skb->dev), br_nf6_forward_finish);
+
+       return NF_STOLEN;
+}
+
+
+/* PF_BRIDGE/LOCAL_OUT ***********************************************/
+static int br_nf6_local_out_finish_forward(struct sk_buff *skb)
+{
+       NF_HOOK_THRESH(PF_BRIDGE, NF_BR_FORWARD, skb, skb->physindev,
+                       skb->dev, br_forward_finish, 1);
+
+       return 0;
+}
+
+static int br_nf6_local_out_finish(struct sk_buff *skb)
+{
+       NF_HOOK_THRESH(PF_BRIDGE, NF_BR_LOCAL_OUT, skb, NULL, skb->dev,
+                       br_forward_finish, 1);
+
+       return 0;
+}
+
+static unsigned int br_nf6_local_out(unsigned int hook, struct sk_buff **pskb, const 
+struct net_device *in, const struct net_device *out, int (*_okfn)(struct sk_buff *))
+{
+       int hookno;
+       int (*okfn)(struct sk_buff *);
+       struct net_device *realindev;
+       struct sk_buff *skb = *pskb;
+
+       if (skb->mac.ethernet->h_proto != __constant_htons(ETH_P_IPV6))
+               return NF_ACCEPT;
+
+       /* Sometimes we get packets with NULL ->dst here (for example,
+        * running a dhcp client daemon triggers this).
+        */
+       if (skb->dst == NULL)
+               return NF_ACCEPT;
+
+       skb->physoutdev = skb->dev;
+
+       hookno = NF_IP6_LOCAL_OUT;
+       okfn = br_nf6_local_out_finish;
+       if ((realindev = skb->physindev) != NULL) {
+               hookno = NF_IP6_FORWARD;
+               okfn = br_nf6_local_out_finish_forward;
+               if (has_bridge_parent(realindev))
+                       realindev = bridge_parent(realindev);
+       }
+
+       NF_HOOK_THRESH(PF_INET6, hookno, skb, realindev,
+                       bridge_parent(skb->dev), okfn,
+                       NF_IP6_PRI_BRIDGE_SABOTAGE + 1);
+
+       return NF_STOLEN;
+}
+
+
+/* PF_BRIDGE/POST_ROUTING ********************************************/
+static int br_nf6_post_routing_finish(struct sk_buff *skb)
+{
+       __maybe_fixup_src6_address(skb);
+       NF_HOOK_THRESH(PF_BRIDGE, NF_BR_POST_ROUTING, skb, NULL,
+                       bridge_parent(skb->dev), br_dev_queue_push_xmit, 1);
+
+       return 0;
+}
+
+static unsigned int br_nf6_post_routing(unsigned int hook, struct sk_buff **pskb, 
+const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff 
+*))
+{
+       struct sk_buff *skb = *pskb;
+
+       if (skb->mac.ethernet->h_proto != __constant_htons(ETH_P_IPV6))
+               return NF_ACCEPT;
+
+       /* Sometimes we get packets with NULL ->dst here (for example,
+        * running a dhcp client daemon triggers this).
+        */
+       if (skb->dst == NULL)
+               return NF_ACCEPT;
+
+       store_orig_srcaddr(skb);
+       NF_HOOK(PF_INET6, NF_IP6_POST_ROUTING, skb, NULL,
+               bridge_parent(skb->dev), br_nf6_post_routing_finish);
+
+       return NF_STOLEN;
+}
+
+
 /* IPv4/SABOTAGE *****************************************************/
 static unsigned int ipv4_sabotage_in(unsigned int hook, struct sk_buff **pskb, const 
struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *))
 {
@@ -336,8 +593,44 @@
        return NF_ACCEPT;
 }
 
+/* IPv6/SABOTAGE *****************************************************/
+static unsigned int ipv6_sabotage_in(unsigned int hook, struct sk_buff **pskb, const 
+struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *))
+{
+       /* Don't hand locally destined packets to PF_INET6/PRE_ROUTING for
+        * the second time.  */
+       if (in->hard_start_xmit == br_dev_xmit &&
+           okfn != br_nf6_pre_routing_finish) {
+               okfn(*pskb);
+               return NF_STOLEN;
+       }
+
+       return NF_ACCEPT;
+}
+
+static unsigned int ipv6_sabotage_out(unsigned int hook, struct sk_buff **pskb, const 
+struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *))
+{
+       /* Postpone execution of PF_INET6/FORWARD, PF_INET6/LOCAL_OUT and
+        * PF_INET6/POST_ROUTING until we have done the forwarding decision in
+        * the bridge code and have determined skb->physoutdev.  */
+       if (out->hard_start_xmit == br_dev_xmit &&
+           okfn != br_nf6_forward_finish &&
+           okfn != br_nf6_local_out_finish &&
+           okfn != br_nf6_local_out_finish_forward &&
+           okfn != br_nf6_post_routing_finish) {
+               struct sk_buff *skb = *pskb;
+
+               if (hook == NF_IP6_FORWARD && skb->physindev == NULL)
+                       skb->physindev = (struct net_device *)in;
+               okfn(skb);
+               return NF_STOLEN;
+       }
+
+       return NF_ACCEPT;
+}
+
 
 static struct nf_hook_ops br_nf_ops[] = {
+       /* IPv4 */
        { { NULL, NULL }, br_nf_pre_routing, PF_BRIDGE, NF_BR_PRE_ROUTING, 0 },
        { { NULL, NULL }, br_nf_local_in, PF_BRIDGE, NF_BR_LOCAL_IN, 0 },
        { { NULL, NULL }, br_nf_forward, PF_BRIDGE, NF_BR_FORWARD, 0 },
@@ -349,6 +642,17 @@
        { { NULL, NULL }, ipv4_sabotage_out, PF_INET, NF_IP_FORWARD, 
NF_IP_PRI_BRIDGE_SABOTAGE },
        { { NULL, NULL }, ipv4_sabotage_out, PF_INET, NF_IP_LOCAL_OUT, 
NF_IP_PRI_BRIDGE_SABOTAGE },
        { { NULL, NULL }, ipv4_sabotage_out, PF_INET, NF_IP_POST_ROUTING, 
NF_IP_PRI_FIRST },
+       /* IPv6 */
+       { { NULL, NULL }, br_nf6_pre_routing, PF_BRIDGE, NF_BR_PRE_ROUTING, 0 },
+       { { NULL, NULL }, br_nf6_local_in, PF_BRIDGE, NF_BR_LOCAL_IN, 0 },
+       { { NULL, NULL }, br_nf6_forward, PF_BRIDGE, NF_BR_FORWARD, 0 },
+       { { NULL, NULL }, br_nf6_local_out, PF_BRIDGE, NF_BR_LOCAL_OUT, 0 },
+       { { NULL, NULL }, br_nf6_post_routing, PF_BRIDGE, NF_BR_POST_ROUTING, 0 },
+
+       { { NULL, NULL }, ipv6_sabotage_in, PF_INET6, NF_IP6_PRE_ROUTING, 
+NF_IP6_PRI_FIRST },
+       { { NULL, NULL }, ipv6_sabotage_out, PF_INET6, NF_IP6_FORWARD, 
+NF_IP6_PRI_BRIDGE_SABOTAGE },
+       { { NULL, NULL }, ipv6_sabotage_out, PF_INET6, NF_IP6_LOCAL_OUT, 
+NF_IP6_PRI_BRIDGE_SABOTAGE },
+        { { NULL, NULL }, ipv6_sabotage_out, PF_INET6, NF_IP6_POST_ROUTING, 
+NF_IP6_PRI_FIRST },
 };
 
 #define NUMHOOKS (sizeof(br_nf_ops)/sizeof(br_nf_ops[0]))
--- linux/net/ipv6/netfilter/ip6_tables.c.v4orig        Thu Oct 11 00:10:34 2001
+++ linux/net/ipv6/netfilter/ip6_tables.c       Sun Mar 24 01:00:23 2002
@@ -2,6 +2,7 @@
  * Packet matching code.
  *
  * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
+ *                   bridge hooks: Jari T. Malinen
  */
 #include <linux/config.h>
 #include <linux/skbuff.h>
@@ -164,12 +165,15 @@
 static inline int
 ip6_packet_match(const struct ipv6hdr *ipv6,
                 const char *indev,
+                const char *physindev,
                 const char *outdev,
+                const char *physoutdev,
                 const struct ip6t_ip6 *ip6info,
                 int isfrag)
 {
        size_t i;
        unsigned long ret;
+       unsigned long ret2;
 
 #define FWINV(bool,invflg) ((bool) ^ !!(ip6info->invflags & invflg))
 
@@ -195,7 +199,13 @@
                        & ((const unsigned long *)ip6info->iniface_mask)[i];
        }
 
-       if (FWINV(ret != 0, IP6T_INV_VIA_IN)) {
+        for (i = 0, ret2 = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) {
+                ret2 |= (((const unsigned long *)physindev)[i]
+                        ^ ((const unsigned long *)ip6info->iniface)[i])
+                        & ((const unsigned long *)ip6info->iniface_mask)[i];
+        }
+
+       if (FWINV(ret != 0 && ret2 != 0, IP6T_INV_VIA_IN)) {
                dprintf("VIA in mismatch (%s vs %s).%s\n",
                        indev, ip6info->iniface,
                        ip6info->invflags&IP6T_INV_VIA_IN ?" (INV)":"");
@@ -208,7 +218,13 @@
                        & ((const unsigned long *)ip6info->outiface_mask)[i];
        }
 
-       if (FWINV(ret != 0, IP6T_INV_VIA_OUT)) {
+        for (i = 0, ret2 = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) {
+                ret2 |= (((const unsigned long *)physoutdev)[i]
+                        ^ ((const unsigned long *)ip6info->outiface)[i])
+                        & ((const unsigned long *)ip6info->outiface_mask)[i];
+        }
+
+       if (FWINV(ret != 0 && ret2 != 0, IP6T_INV_VIA_OUT)) {
                dprintf("VIA out mismatch (%s vs %s).%s\n",
                        outdev, ip6info->outiface,
                        ip6info->invflags&IP6T_INV_VIA_OUT ?" (INV)":"");
@@ -309,6 +325,7 @@
        /* Initializing verdict to NF_DROP keeps gcc happy. */
        unsigned int verdict = NF_DROP;
        const char *indev, *outdev;
+       const char *physindev, *physoutdev;
        void *table_base;
        struct ip6t_entry *e, *back;
 
@@ -318,6 +335,7 @@
        datalen = (*pskb)->len - IPV6_HDR_LEN;
        indev = in ? in->name : nulldevname;
        outdev = out ? out->name : nulldevname;
+        physindev = (*pskb)->physindev ? (*pskb)->physindev->name : nulldevname;      
+  physoutdev = (*pskb)->physoutdev ? (*pskb)->physoutdev->name : nulldevname;
 
        /* We handle fragments by dealing with the first fragment as
         * if it was a normal packet.  All other fragments are treated
@@ -352,7 +370,7 @@
                IP_NF_ASSERT(e);
                IP_NF_ASSERT(back);
                (*pskb)->nfcache |= e->nfcache;
-               if (ip6_packet_match(ipv6, indev, outdev, &e->ipv6, offset)) {
+               if (ip6_packet_match(ipv6, indev, physindev, outdev, physoutdev, 
+&e->ipv6, offset)) {
                        struct ip6t_entry_target *t;
 
                        if (IP6T_MATCH_ITERATE(e, do_match,

Reply via email to