Hi all,

enclosed are two patchs for kernel-2.4.10 and brctl-0.9.3. They are based
on Christian Welzel's patche (can be found under
http://bridge.sourceforge.net/devel/bridge-mac/) which enables MAC based
filtering on the bridge. you don't have to apply Christian's patch first,
it is included in this one.

Christian's patch forwards all packets by default. You can define MAC
addresses, and packets with this source OR destination addresses are not
forwarded anymore.

Our addon makes it possible to filter based on MAC source addresses or MAC
destination addresses or both (like Christian's version). Additionaly it
is possible to define a default behavior. Christian's way is to allow
everything but the specified addresses (default allow), with this addon
patch you can also deny everything by default and allow some specified
addresses (default deny).

However, there is still only one filter database (ftdb) which is a
limitation. Technically it is possible to choose 'default allow' for
source MACs and 'default deny' for destination MACs, but since all MAC
addresses are stored in the same database this would be very obscure setup
(at least in my eyes, perhaps there is use even for this :-)).


So perhaps somebody out there needs exactly something like this because
iptables can't filter ARPs or something like that - it's here, just take
it.

And again: most of this is from Christian Welzel <[EMAIL PROTECTED]>,
only the meantioned changes are from my colleague Wolfram and me.


bye,
Kurt
diff -Naur bridge-utils-0.9.3/brctl/brctl.c bridge-utils-0.9.3-patched/brctl/brctl.c
--- bridge-utils-0.9.3/brctl/brctl.c    Fri Jun 22 21:59:02 2001
+++ bridge-utils-0.9.3-patched/brctl/brctl.c    Tue Sep 25 11:07:22 2001
@@ -26,23 +26,30 @@
 
 char *help_message =
 "commands:\n"
-"\taddbr\t\t<bridge>\t\tadd bridge\n"
-"\taddif\t\t<bridge> <device>\tadd interface to bridge\n"
-"\tdelbr\t\t<bridge>\t\tdelete bridge\n"
-"\tdelif\t\t<bridge> <device>\tdelete interface from bridge\n"
-"\tshow\t\t\t\t\tshow a list of bridges\n"
-"\tshowmacs\t<bridge>\t\tshow a list of mac addrs\n"
-"\tshowstp\t\t<bridge>\t\tshow bridge stp info\n"
+"\taddbr\t\t<bridge>\t\t\tadd bridge\n"
+"\taddif\t\t<bridge> <device>\t\tadd interface to bridge\n"
+"\tdelbr\t\t<bridge>\t\t\tdelete bridge\n"
+"\tdelif\t\t<bridge> <device>\t\tdelete interface from bridge\n"
+"\tshow\t\t\t\t\t\tshow a list of bridges\n"
+"\tshowmacs\t<bridge>\t\t\tshow a list of mac addrs\n"
+"\tshowmac\t\t<bridge>\t\t\tshow a list of mac addrs (no title)\n"
+"\tshowftdb\t<bridge>\t\t\tshow macs in the filter database (ftdb)\n"
+"\tshowstp\t\t<bridge>\t\t\tshow bridge stp info\n"
 "\n"
-"\tsetageing\t<bridge> <time>\t\tset ageing time\n"
-"\tsetbridgeprio\t<bridge> <prio>\t\tset bridge priority\n"
-"\tsetfd\t\t<bridge> <time>\t\tset bridge forward delay\n"
-"\tsetgcint\t<bridge> <time>\t\tset garbage collection interval\n"
-"\tsethello\t<bridge> <time>\t\tset hello time\n"
-"\tsetmaxage\t<bridge> <time>\t\tset max message age\n"
-"\tsetpathcost\t<bridge> <port> <cost>\tset path cost\n"
-"\tsetportprio\t<bridge> <port> <prio>\tset port priority\n"
-"\tstp\t\t<bridge> <state>\tturn stp on/off\n";
+"\tftdbdelmac\t<bridge> <mac>\t\t\tremoves a mac from the ftdb\n"
+"\tftdbaddmac\t<bridge> <mac>\t\t\tadds a mac to the ftdb\n"
+"\tsetfilter\t<bridge> src|dest on|off\tset mac filtering\n"
+"\tsetpolicy\t<bridge> src|dest allow|deny\tset mac filter default policy\n"
+"\n"
+"\tsetageing\t<bridge> <time>\t\t\tset ageing time\n"
+"\tsetbridgeprio\t<bridge> <prio>\t\t\tset bridge priority\n"
+"\tsetfd\t\t<bridge> <time>\t\t\tset bridge forward delay\n"
+"\tsetgcint\t<bridge> <time>\t\t\tset garbage collection interval\n"
+"\tsethello\t<bridge> <time>\t\t\tset hello time\n"
+"\tsetmaxage\t<bridge> <time>\t\t\tset max message age\n"
+"\tsetpathcost\t<bridge> <port> <cost>\t\tset path cost\n"
+"\tsetportprio\t<bridge> <port> <prio>\t\tset port priority\n"
+"\tstp\t\t<bridge> <state>\t\tturn stp on/off\n";
 
 void help()
 {
diff -Naur bridge-utils-0.9.3/brctl/brctl_cmd.c 
bridge-utils-0.9.3-patched/brctl/brctl_cmd.c
--- bridge-utils-0.9.3/brctl/brctl_cmd.c        Fri Jun 22 21:59:02 2001
+++ bridge-utils-0.9.3-patched/brctl/brctl_cmd.c        Tue Sep 25 11:07:22 2001
@@ -230,12 +230,15 @@
 
 void br_cmd_show(struct bridge *br, char *arg0, char *arg1)
 {
-       printf("bridge name\tbridge id\t\tSTP enabled\tinterfaces\n");
+       printf("           \t         \t\t           \tMAC filtering\t          \n" );
+       printf("bridge name\tbridge id\t\tSTP enabled\t src    dest \tinterfaces\n");
        br = bridge_list;
        while (br != NULL) {
                printf("%s\t\t", br->ifname);
                br_dump_bridge_id((unsigned char *)&br->info.bridge_id);
                printf("\t%s\t\t", br->info.stp_enabled?"yes":"no");
+               printf("%5.5s %5.5s\t", br->info.flt_src ? br->info.flt_src_allow ? 
+"allow" : "deny" : "off",
+                                          br->info.flt_dest ? br->info.flt_dest_allow 
+? "allow" : "deny" : "off" );
                br_dump_interface_list(br);
 
                br = br->next;
@@ -294,6 +297,131 @@
        }
 }
 
+void br_cmd_showmac(struct bridge *br, char *arg0, char *arg1)
+{
+       struct fdb_entry fdb[1024];
+       int offset;
+
+       offset = 0;
+       while (1) {
+               int i;
+               int num;
+
+               num = br_read_fdb(br, fdb, offset, 1024);
+               if (!num)
+                       break;
+
+               qsort(fdb, num, sizeof(struct fdb_entry), compare_fdbs);
+
+               for (i=0;i<num;i++)
+                       __dump_fdb_entry(fdb+i);
+
+               offset += num;
+       }
+}
+
+
+static int compare_ftdbs(const void *f0, const void *f1)
+{
+       return memcmp(((struct ftdb_entry*)f0)->mac_addr, ((struct ftdb_entry 
+*)f1)->mac_addr, 6);
+}
+
+void br_cmd_showdismacs(struct bridge *br, char *arg0, char *arg1) 
+{
+       struct ftdb_entry fdb[1024];
+       int offset;
+
+       offset = 0;
+       while (1) {
+               int i;
+               int num;
+
+               num = br_read_ftdb(br, fdb, offset, 1024);
+               if (!num)
+                       break;
+
+               qsort(fdb, num, sizeof(struct ftdb_entry), compare_ftdbs);
+
+               for (i=0;i<num;i++)
+                   printf("%.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",
+                      (fdb+i)->mac_addr[0], (fdb+i)->mac_addr[1], 
+(fdb+i)->mac_addr[2],
+                      (fdb+i)->mac_addr[3], (fdb+i)->mac_addr[4], 
+(fdb+i)->mac_addr[5]);
+
+               offset += num;
+       }
+
+}
+
+int machex2macint(char *arg1, char *arg2)
+{
+  int tmp[6];
+
+  if(sscanf(arg1, "%02x:%02x:%02x:%02x:%02x:%02x", 
+tmp,tmp+1,tmp+2,tmp+3,tmp+4,tmp+5)!=6)
+    return -1;
+
+  arg2[0]=(char) tmp[0];
+  arg2[1]=(char) tmp[1];
+  arg2[2]=(char) tmp[2];
+  arg2[3]=(char) tmp[3];
+  arg2[4]=(char) tmp[4];
+  arg2[5]=(char) tmp[5];
+
+
+  return 1;
+}
+
+void br_cmd_enablemac(struct bridge *br, char *arg0, char *arg1) 
+{
+  char tmp[6];
+
+  if(machex2macint(arg0, tmp))
+  {
+
+    if(br_set_mac_enabled(br, tmp) == 0) 
+    {
+       printf("mac adress %s removed from fdb.\n", arg0);
+       return;
+    }  
+  }
+  printf("removing mac not successful.\n");
+}
+
+void br_cmd_disablemac(struct bridge *br, char *arg0, char *arg1)
+{
+  char tmp[6];
+
+  if(machex2macint(arg0, tmp))
+  {
+    if(br_set_mac_disabled(br, tmp) == 0) 
+    {
+      printf("mac adress %s added to fdb.\n", arg0);
+      return;
+    }
+  }
+  printf("adding mac not successful.\n");
+
+}
+
+void br_cmd_setfilter(struct bridge *br, char *arg0, char *arg1)
+{
+       unsigned char mac = 0xFF, on = 0xFF;
+
+       mac = !strncasecmp( arg0, "src", 3 ) ? 1 : !strncasecmp( arg0, "dest", 4 ) ? 0 
+: 0xFF;
+       on = !strncasecmp( arg1, "off", 3 ) ? 0 : !strncasecmp( arg1, "on", 2 ) ? 1 : 
+0xFF;
+
+       br_set_filter( br, mac, on );
+}
+
+void br_cmd_setpolicy(struct bridge *br, char *arg0, char *arg1)
+{
+       unsigned char mac = 0xFF, allow = 0xFF;
+
+       mac = !strncasecmp( arg0, "src", 3 ) ? 1 : !strncasecmp( arg0, "dest", 4 ) ? 0 
+: 0xFF;
+       allow = !strncasecmp( arg1, "deny", 4 ) ? 0 : !strncasecmp( arg1, "allow", 5 ) 
+? 1 : 0xFF;
+
+       br_set_policy( br, mac, allow );
+}
+
 static struct command commands[] = {
        {0, "addbr", br_cmd_addbr},
        {1, "addif", br_cmd_addif},
@@ -309,8 +437,14 @@
        {1, "setportprio", br_cmd_setportprio},
        {0, "show", br_cmd_show},
        {1, "showmacs", br_cmd_showmacs},
+       {1, "showmac", br_cmd_showmac},
        {1, "showstp", br_cmd_showstp},
        {1, "stp", br_cmd_stp},
+       {1, "showftdb", br_cmd_showdismacs},
+       {1, "ftdbdelmac", br_cmd_enablemac},
+       {1, "ftdbaddmac", br_cmd_disablemac},
+       {1, "setfilter", br_cmd_setfilter},
+       {1, "setpolicy", br_cmd_setpolicy}
 };
 
 struct command *br_command_lookup(char *cmd)
diff -Naur bridge-utils-0.9.3/brctl/brctl_disp.c 
bridge-utils-0.9.3-patched/brctl/brctl_disp.c
--- bridge-utils-0.9.3/brctl/brctl_disp.c       Fri Jun 22 21:59:02 2001
+++ bridge-utils-0.9.3-patched/brctl/brctl_disp.c       Tue Sep 25 11:07:22 2001
@@ -46,7 +46,7 @@
        printf("\n");
 
        while (p != NULL) {
-               printf("\t\t\t\t\t\t\t%s\n", if_indextoname(p->ifindex, ifname));
+               printf("\t\t\t\t\t\t\t\t\t%s\n", if_indextoname(p->ifindex, ifname));
                p = p->next;
        }
 }
diff -Naur bridge-utils-0.9.3/libbridge/libbridge.h 
bridge-utils-0.9.3-patched/libbridge/libbridge.h
--- bridge-utils-0.9.3/libbridge/libbridge.h    Fri Jun 22 21:59:03 2001
+++ bridge-utils-0.9.3-patched/libbridge/libbridge.h    Tue Sep 25 11:07:22 2001
@@ -55,6 +55,10 @@
        struct timeval tcn_timer_value;
        struct timeval topology_change_timer_value;
        struct timeval gc_timer_value;
+       unsigned char flt_src;
+       unsigned char flt_dest;
+       unsigned char flt_src_allow;
+       unsigned char flt_dest_allow;
 };
 
 struct bridge
@@ -76,6 +80,11 @@
        struct timeval ageing_timer_value;
 };
 
+struct ftdb_entry
+{
+       u_int8_t mac_addr[6];
+};
+
 struct port_info
 {
        struct bridge_id designated_root;
@@ -124,6 +133,12 @@
 int br_set_port_priority(struct port *p, int port_priority);
 int br_set_path_cost(struct port *p, int path_cost);
 int br_read_fdb(struct bridge *br, struct fdb_entry *fdbs, int offset, int num);
+
+int br_read_ftdb(struct bridge *br, struct ftdb_entry *fdbs, int offset, int num);
+int br_set_mac_disabled(struct bridge *br, char *addr);
+int br_set_mac_enabled(struct bridge *br, char *addr);
+int br_set_filter(struct bridge *br, unsigned char mac, unsigned char onoff);
+int br_set_policy(struct bridge *br, unsigned char mac, unsigned char policy);
 
 /* libc5 combatability */
 char *if_indextoname(unsigned int __ifindex, char *__ifname);
diff -Naur bridge-utils-0.9.3/libbridge/libbridge_devif.c 
bridge-utils-0.9.3-patched/libbridge/libbridge_devif.c
--- bridge-utils-0.9.3/libbridge/libbridge_devif.c      Fri Jun 22 21:59:03 2001
+++ bridge-utils-0.9.3-patched/libbridge/libbridge_devif.c      Tue Sep 25 11:07:22 
+2001
@@ -168,3 +168,60 @@
 
        return numread;
 }
+
+void __copy_ftdb(struct ftdb_entry *ent, struct __ftdb_entry *f)
+{
+       memcpy(ent->mac_addr, f->mac_addr, 6);
+}
+
+int br_read_ftdb(struct bridge *br, struct ftdb_entry *fdbs, int offset, int num)
+{
+       struct __ftdb_entry f[num];
+       int i;
+       int numread;
+
+       if ((numread = br_device_ioctl(br, BRCTL_GET_DISABLED_MACS,
+                                      (unsigned long)f, num, offset)) < 0)
+               return errno;
+
+       for (i=0;i<numread;i++)
+               __copy_ftdb(fdbs+i, f+i);
+
+       return numread;
+}
+
+
+int br_set_mac_disabled(struct bridge *br, char *addr)
+{
+       if (br_device_ioctl(br, BRCTL_SET_MAC_DISABLED, (ulong) addr,
+                           0, 0) < 0)
+               return errno;
+
+  return 0;
+}
+
+int br_set_mac_enabled(struct bridge *br, char *addr)
+{
+       if (br_device_ioctl(br, BRCTL_SET_MAC_ENABLED, (ulong) addr,
+                           0, 0) < 0)
+               return errno;
+
+  return 0;
+}
+
+int br_set_filter(struct bridge *br, unsigned char mac, unsigned char onoff)
+{
+       if (br_device_ioctl(br, BRCTL_SET_MAC_FILTER, mac, onoff, 0) < 0)
+               return errno;
+
+       return 0;
+}
+
+int br_set_policy(struct bridge *br, unsigned char mac, unsigned char policy)
+{
+       if (br_device_ioctl(br, BRCTL_SET_MAC_FLT_POLICY, mac, policy, 0) < 0)
+               return errno;
+
+       return 0;
+}
+
diff -Naur bridge-utils-0.9.3/libbridge/libbridge_init.c 
bridge-utils-0.9.3-patched/libbridge/libbridge_init.c
--- bridge-utils-0.9.3/libbridge/libbridge_init.c       Fri Jun 22 21:59:03 2001
+++ bridge-utils-0.9.3-patched/libbridge/libbridge_init.c       Tue Sep 25 11:07:22 
+2001
@@ -51,6 +51,10 @@
        __jiffies_to_tv(&info->topology_change_timer_value,
                        i->topology_change_timer_value);
        __jiffies_to_tv(&info->gc_timer_value, i->gc_timer_value);
+       info->flt_src = i->flt_src;
+       info->flt_dest = i->flt_dest;
+       info->flt_src_allow = i->flt_src_allow;
+       info->flt_dest_allow = i->flt_dest_allow;
 }
 
 static void __port_info_copy(struct port_info *info, struct __port_info *i)
diff -Naur linux-2.4.10/include/linux/if_bridge.h 
linux-2.4.10-bridge/include/linux/if_bridge.h
--- linux-2.4.10/include/linux/if_bridge.h      Sun Sep 23 19:31:33 2001
+++ linux-2.4.10-bridge/include/linux/if_bridge.h       Mon Sep 24 14:29:02 2001
@@ -39,6 +39,14 @@
 #define BRCTL_SET_PATH_COST 17
 #define BRCTL_GET_FDB_ENTRIES 18
 
+#define BRCTL_SET_MAC_DISABLED 19
+#define BRCTL_SET_MAC_ENABLED 20
+#define BRCTL_GET_DISABLED_MACS 21
+#define BRCTL_SET_MAC_FILTER 22
+#define BRCTL_GET_MAC_FILTER 23
+#define BRCTL_SET_MAC_FLT_POLICY 24
+#define BRCTL_GET_MAC_FLT_POLICY 25
+
 #define BR_STATE_DISABLED 0
 #define BR_STATE_LISTENING 1
 #define BR_STATE_LEARNING 2
@@ -66,6 +74,10 @@
        __u32 tcn_timer_value;
        __u32 topology_change_timer_value;
        __u32 gc_timer_value;
+       __u8 flt_src;
+       __u8 flt_dest;
+       __u8 flt_src_allow;
+       __u8 flt_dest_allow;
 };
 
 struct __port_info
@@ -92,6 +104,11 @@
        __u8 is_local;
        __u32 ageing_timer_value;
        __u32 unused;
+};
+
+struct __ftdb_entry
+{
+       __u8 mac_addr[6];
 };
 
 #ifdef __KERNEL__
diff -Naur linux-2.4.10/net/bridge/Makefile linux-2.4.10-bridge/net/bridge/Makefile
--- linux-2.4.10/net/bridge/Makefile    Fri Dec 29 23:07:24 2000
+++ linux-2.4.10-bridge/net/bridge/Makefile     Mon Sep 24 14:11:19 2001
@@ -8,7 +8,7 @@
 # Note 2! The CFLAGS definition is now in the main makefile...
 
 O_TARGET       := bridge.o
-obj-y          := br.o br_device.o br_fdb.o br_forward.o br_if.o br_input.o \
+obj-y          := br.o br_device.o br_fdb.o br_filter.o br_forward.o br_if.o 
+br_input.o \
                        br_ioctl.o br_notify.o br_stp.o br_stp_bpdu.o \
                        br_stp_if.o br_stp_timer.o
 obj-m          := $(O_TARGET)
diff -Naur linux-2.4.10/net/bridge/br_filter.c 
linux-2.4.10-bridge/net/bridge/br_filter.c
--- linux-2.4.10/net/bridge/br_filter.c Thu Jan  1 01:00:00 1970
+++ linux-2.4.10-bridge/net/bridge/br_filter.c  Mon Sep 24 14:41:15 2001
@@ -0,0 +1,217 @@
+/*
+ *     Mac filtering database
+ *     Linux ethernet bridge
+ *
+ *     Authors:
+ *     Christian Welzel                <[EMAIL PROTECTED]>
+ *
+ *     $Id: dismacs-against-kernel2.4.3.diff,v 1.1.1.1 2001/08/30 11:11:13 kwagner 
+Exp $
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License
+ *     as published by the Free Software Foundation; either version
+ *     2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/if_bridge.h>
+#include <asm/atomic.h>
+#include <asm/uaccess.h>
+#include "br_private.h"
+
+// calculates the hash for a mac
+// fertig
+static __inline__ int br_mac_hash(unsigned char *mac)
+{
+       unsigned long x;
+
+       x = mac[0];
+       x = (x << 2) ^ mac[1];
+       x = (x << 2) ^ mac[2];
+       x = (x << 2) ^ mac[3];
+       x = (x << 2) ^ mac[4];
+       x = (x << 2) ^ mac[5];
+
+       x ^= x >> 8;
+
+       return x & (BR_HASH_SIZE - 1);
+}
+
+
+// links diabled macs into hash
+// fertig
+static __inline__ void __disabled_macs_link(struct net_bridge *br,
+                                  struct net_bridge_ftdb_entry *ent,
+                                  int hash)
+{
+       ent->next_hash = br->disabled_macs[hash];
+       if (ent->next_hash != NULL)
+               ent->next_hash->pprev_hash = &ent->next_hash;
+       br->disabled_macs[hash] = ent;
+       ent->pprev_hash = &br->disabled_macs[hash];
+}
+
+// unlinks disabled macs from hash (no further disabled)
+// fertig
+static __inline__ void __disabled_macs_unlink(struct net_bridge_ftdb_entry *ent)
+{
+       *(ent->pprev_hash) = ent->next_hash;
+       if (ent->next_hash != NULL)
+               ent->next_hash->pprev_hash = ent->pprev_hash;
+       ent->next_hash = NULL;
+       ent->pprev_hash = NULL;
+}
+
+// tests if mac is unused -> delete it
+// fertig
+void br_ftdb_delete(struct net_bridge_ftdb_entry *ent)
+{
+       if (atomic_dec_and_test(&ent->use_count))
+               kfree(ent);
+}
+
+// removes a mac from hash (no further disabled)
+// fertig
+void br_ftdb_remove(struct net_bridge *br, unsigned char *addr)
+{
+       struct net_bridge_ftdb_entry *f;
+
+       write_lock_bh(&br->disabled_macs_lock);
+       f = br->disabled_macs[br_mac_hash(addr)];
+
+       while (f != NULL) {
+               if (!memcmp(f->addr.addr, addr, ETH_ALEN)) {
+                       __disabled_macs_unlink(f);
+                       br_ftdb_delete(f);
+               }
+               f = f->next_hash;
+       }
+       write_unlock_bh(&br->disabled_macs_lock);
+}
+
+// returns pointer==1 if mac is disabled
+// fertig
+int br_ftdb_get(struct net_bridge *br, unsigned char *addr)
+{
+       struct net_bridge_ftdb_entry *ftdb;
+
+       read_lock_bh(&br->disabled_macs_lock);
+       ftdb = br->disabled_macs[br_mac_hash(addr)];
+       while (ftdb != NULL) {
+               if (!memcmp(ftdb->addr.addr, addr, ETH_ALEN)) {
+                       read_unlock_bh(&br->disabled_macs_lock);
+                       return 1;
+               }
+
+               ftdb = ftdb->next_hash;
+       }
+
+       read_unlock_bh(&br->disabled_macs_lock);
+       return 0;
+}
+
+
+// returns all macs in hash
+// fertig
+int br_ftdb_get_entries(struct net_bridge *br,
+                      unsigned char *_buf,
+                      int maxnum,
+                      int offset)
+{
+       int i;
+       int num;
+       struct __ftdb_entry *walk;
+
+       num = 0;
+       walk = (struct __ftdb_entry *)_buf;
+
+       read_lock_bh(&br->disabled_macs_lock);
+       for (i=0;i<BR_HASH_SIZE;i++) {
+               struct net_bridge_ftdb_entry *f;
+
+               f = br->disabled_macs[i];
+               while (f != NULL && num < maxnum) {
+                       struct __ftdb_entry ent;
+                       int err;
+                       struct net_bridge_ftdb_entry *g;
+                       struct net_bridge_ftdb_entry **pp; 
+
+                       if (offset) {
+                               offset--;
+                               f = f->next_hash;
+                               continue;
+                       }
+
+                       memset(&ent, 0, sizeof(struct __ftdb_entry));
+                       memcpy(ent.mac_addr, f->addr.addr, ETH_ALEN);
+
+                       atomic_inc(&f->use_count);
+                       read_unlock_bh(&br->disabled_macs_lock);
+                       err = copy_to_user(walk, &ent, sizeof(struct __ftdb_entry));
+                       read_lock_bh(&br->disabled_macs_lock);
+
+                       g = f->next_hash;
+                       pp = f->pprev_hash;
+                       br_ftdb_delete(f);
+
+                       if (err)
+                               goto out_fault;
+
+                       if (g == NULL && pp == NULL)
+                               goto out_disappeared;
+
+                       num++;
+                       walk++;
+
+                       f = g;
+               }
+       }
+
+ out:
+       read_unlock_bh(&br->disabled_macs_lock);
+       return num;
+
+ out_disappeared:
+       num = -EAGAIN;
+       goto out;
+
+ out_fault:
+       num = -EFAULT;
+       goto out;
+}
+
+// inserts a mac into hash
+// fertig
+void br_ftdb_insert(struct net_bridge *br,
+                   unsigned char *addr)
+{
+       struct net_bridge_ftdb_entry *ftdb;
+       int hash;
+
+       hash = br_mac_hash(addr);
+
+       write_lock_bh(&br->disabled_macs_lock);
+       ftdb = br->disabled_macs[hash];
+       while (ftdb != NULL) {
+               if (!memcmp(ftdb->addr.addr, addr, ETH_ALEN)) {
+                       write_unlock_bh(&br->disabled_macs_lock);
+                       return;
+               }
+
+               ftdb = ftdb->next_hash;
+       }
+
+       ftdb = kmalloc(sizeof(*ftdb), GFP_ATOMIC);
+       if (ftdb == NULL) {
+               write_unlock_bh(&br->disabled_macs_lock);
+               return;
+       }
+
+       memcpy(ftdb->addr.addr, addr, ETH_ALEN);
+       atomic_set(&ftdb->use_count, 1);
+
+       __disabled_macs_link(br, ftdb, hash);
+
+       write_unlock_bh(&br->disabled_macs_lock);
+}
diff -Naur linux-2.4.10/net/bridge/br_if.c linux-2.4.10-bridge/net/bridge/br_if.c
--- linux-2.4.10/net/bridge/br_if.c     Fri Nov 10 00:57:53 2000
+++ linux-2.4.10-bridge/net/bridge/br_if.c      Mon Sep 24 14:13:11 2001
@@ -131,6 +131,11 @@
        br->ageing_time = 300 * HZ;
        br->gc_interval = 4 * HZ;
 
+       br->flt_src = 1;
+       br->flt_dest = 1;
+       br->flt_src_allow = 1;
+       br->flt_dest_allow = 1;
+
        return br;
 }
 
diff -Naur linux-2.4.10/net/bridge/br_input.c 
linux-2.4.10-bridge/net/bridge/br_input.c
--- linux-2.4.10/net/bridge/br_input.c  Wed Aug 15 10:54:39 2001
+++ linux-2.4.10-bridge/net/bridge/br_input.c   Mon Sep 24 14:21:40 2001
@@ -4,6 +4,7 @@
  *
  *     Authors:
  *     Lennert Buytenhek               <[EMAIL PROTECTED]>
+ *      Arne Fitzenreiter (MAC Filter)  <[EMAIL PROTECTED]>
  *
  *     $Id: br_input.c,v 1.9 2001/08/14 22:05:57 davem Exp $
  *
@@ -50,11 +51,14 @@
 {
        struct net_bridge *br;
        unsigned char *dest;
+       unsigned char *src;
+       
        struct net_bridge_fdb_entry *dst;
        struct net_bridge_port *p;
        int passedup;
 
        dest = skb->mac.ethernet->h_dest;
+       src = skb->mac.ethernet->h_source;
 
        p = skb->dev->br_port;
        br = p->br;
@@ -63,6 +67,22 @@
        if (!(br->dev.flags & IFF_UP) ||
            p->state == BR_STATE_DISABLED)
                goto freeandout;
+
+       if (br->flt_dest) {
+               if (br->flt_dest_allow) {
+                       if (br_ftdb_get(br,dest)) goto freeandout;
+               } else {
+                       if (! br_ftdb_get(br,dest)) goto freeandout;
+               }
+       }
+
+       if (br->flt_src) {
+               if (br->flt_src_allow) {
+                       if (br_ftdb_get(br,src)) goto freeandout;
+               } else {
+                       if (! br_ftdb_get(br,src)) goto freeandout;
+               }
+       }
 
        if (br->dev.flags & IFF_PROMISC) {
                struct sk_buff *skb2;
diff -Naur linux-2.4.10/net/bridge/br_ioctl.c 
linux-2.4.10-bridge/net/bridge/br_ioctl.c
--- linux-2.4.10/net/bridge/br_ioctl.c  Fri Nov 10 00:57:53 2000
+++ linux-2.4.10-bridge/net/bridge/br_ioctl.c   Tue Sep 25 10:07:48 2001
@@ -73,6 +73,10 @@
                b.tcn_timer_value = br_timer_get_residue(&br->tcn_timer);
                b.topology_change_timer_value = 
br_timer_get_residue(&br->topology_change_timer);
                b.gc_timer_value = br_timer_get_residue(&br->gc_timer);
+               b.flt_src = br->flt_src;
+               b.flt_dest = br->flt_dest;
+               b.flt_src_allow = br->flt_src_allow;
+               b.flt_dest_allow = br->flt_dest_allow;
 
                if (copy_to_user((void *)arg0, &b, sizeof(b)))
                        return -EFAULT;
@@ -179,6 +183,34 @@
 
        case BRCTL_GET_FDB_ENTRIES:
                return br_fdb_get_entries(br, (void *)arg0, arg1, arg2);
+
+       case BRCTL_SET_MAC_DISABLED:
+       {
+               br_ftdb_insert(br, (char *)arg0);
+               return 0;
+       }
+               
+       case BRCTL_SET_MAC_ENABLED:
+       {
+               br_ftdb_remove(br, (char *)arg0);
+               return 0;
+       }
+       
+       case BRCTL_GET_DISABLED_MACS:
+               return br_ftdb_get_entries(br, (void *)arg0, arg1, arg2);
+
+       case BRCTL_SET_MAC_FILTER:
+       {
+               arg0 ? br->flt_src : br->flt_dest = (unsigned char)arg1;
+               return 0;
+       }
+
+       case BRCTL_SET_MAC_FLT_POLICY:
+       {
+               arg0 ? br->flt_src_allow : br->flt_dest_allow = (unsigned char)arg1;
+               return 0;
+       }
+
        }
 
        return -EOPNOTSUPP;
diff -Naur linux-2.4.10/net/bridge/br_private.h 
linux-2.4.10-bridge/net/bridge/br_private.h
--- linux-2.4.10/net/bridge/br_private.h        Tue Jun 12 04:15:27 2001
+++ linux-2.4.10-bridge/net/bridge/br_private.h Mon Sep 24 14:39:03 2001
@@ -53,6 +53,14 @@
        unsigned                        is_static:1;
 };
 
+struct net_bridge_ftdb_entry
+{
+       struct net_bridge_ftdb_entry    *next_hash;
+       struct net_bridge_ftdb_entry    **pprev_hash;
+       atomic_t                        use_count;
+       mac_addr                        addr;
+};
+
 struct net_bridge_port
 {
        struct net_bridge_port          *next;
@@ -86,6 +94,14 @@
        struct net_device_stats         statistics;
        rwlock_t                        hash_lock;
        struct net_bridge_fdb_entry     *hash[BR_HASH_SIZE];
+       rwlock_t                        disabled_macs_lock;
+       struct net_bridge_ftdb_entry    *disabled_macs[BR_HASH_SIZE];
+
+       unsigned char                   flt_src;
+       unsigned char                   flt_dest;
+       unsigned char                   flt_src_allow;
+       unsigned char                   flt_dest_allow;
+
        struct timer_list               tick;
 
        /* STP */
@@ -200,4 +216,16 @@
 /* br_stp_bpdu.c */
 extern void br_stp_handle_bpdu(struct sk_buff *skb);
 
+/* br_filter.c */
+void br_ftdb_remove(struct net_bridge *br, unsigned char *addr);
+int br_ftdb_get(struct net_bridge *br, unsigned char *addr);
+int br_ftdb_get_entries(struct net_bridge *br,
+                      unsigned char *_buf,
+                      int maxnum,
+                      int offset);
+void br_ftdb_insert(struct net_bridge *br,
+                   unsigned char *addr);
+
+
 #endif
+

Reply via email to