Re: New Bridge patch for 2.3.x - Give this a whirl to test it.

From: Bernard Wei (bwei@home.com)
Date: Mon Jan 10 2000 - 00:49:30 EST


"David S. Miller" wrote:
>
> From: Matthew Grant <grantma@anathoth.gen.nz>
> Date: Sun, 09 Jan 2000 20:06:22 GMT
>
> Here is the comapnion patch to the one that went into 2.2.14.
>
> People can't try it with all of this...
>
> =20
> + /* Bridge stuff */
> + int bridge_port_id; =09
> +=09
>
> Please send patches as raw ascii-text or uuencoded if you have
> no other means to avoid these escape sequences.
>

It looks like text attachment on this end. I'm re-attaching this one
for him.

-- 
Bernard Wei                              -o)
bwei@home.com                 o)  o)     /\\
______________________________/\__/\_____>V/__

--- linux/include/linux/netdevice.h.orig Sun Dec 19 21:56:37 1999 +++ linux/include/linux/netdevice.h Sun Dec 19 22:51:06 1999 @@ -293,6 +293,9 @@ /* Called after last user reference disappears. */ void (*destructor)(struct net_device *dev); + /* Bridge stuff */ + int bridge_port_id; + /* Pointers to interface service routines. */ int (*open)(struct net_device *dev); int (*stop)(struct net_device *dev); --- linux/include/net/br.h.orig Sun Dec 19 21:56:37 1999 +++ linux/include/net/br.h Sun Dec 19 22:58:03 1999 @@ -19,7 +19,16 @@ #define Forwarding 3 /* (4 4 4) */ #define Blocking 4 /* (4.4.1) */ -#define No_of_ports 8 + +/* MAG Yich! Easiest way of giving a configurable number of ports + * If you want more than 32, change BR_MAX_PORTS and recompile brcfg! + */ +#define BR_MAX_PORTS (32) +#if CONFIG_BRIDGE_NUM_PORTS > BR_MAX_PORTS +#undef CONFIG_BRIDGE_NUM_PORTS +#define CONFIG_BRIDGE_NUM_PORTS BR_MAX_PORTS +#endif +#define No_of_ports CONFIG_BRIDGE_NUM_PORTS /* arbitrary choice, to allow the code below to compile */ #define All_ports (No_of_ports + 1) @@ -147,6 +156,7 @@ unsigned int top_change; /* (4.5.3.12) */ unsigned short topology_change_time; /* (4.5.3.13) */ unsigned short hold_time; /* (4.5.3.14) */ + unsigned int instance; } Bridge_data; /** Port Parameters (4.5.5) **/ @@ -160,7 +170,9 @@ unsigned short designated_port; /* (4.5.5.7) */ unsigned int top_change_ack; /* (4.5.5.8) */ unsigned int config_pending; /* (4.5.5.9) */ - struct net_device *dev; + bridge_id_t ifmac; + char ifname[IFNAMSIZ]; /* Make life easier for brcfg */ + struct net_device *dev; struct fdb *fdb; /* head of per port fdb chain */ } Port_data; @@ -245,13 +257,14 @@ struct br_stat { unsigned int flags; Bridge_data bridge_data; - Port_data port_data[No_of_ports]; unsigned int policy; unsigned int exempt_protocols; unsigned short protocols[BR_MAX_PROTOCOLS]; unsigned short prot_id[BR_MAX_PROT_STATS]; /* Protocol encountered */ unsigned int prot_counter[BR_MAX_PROT_STATS]; /* How many packets ? */ br_stats_counter packet_cnts; + unsigned int num_ports; + Port_data port_data[BR_MAX_PORTS + 1]; }; /* defined flags for br_stat.flags */ @@ -274,7 +287,7 @@ #define BRCMD_SET_BRIDGE_PRIORITY 5 /* arg1 = priority */ #define BRCMD_SET_PORT_PRIORITY 6 /* arg1 = port, arg2 = priority */ #define BRCMD_SET_PATH_COST 7 /* arg1 = port, arg2 = cost */ -#define BRCMD_DISPLAY_FDB 8 /* arg1 = port */ +#define BRCMD_DISPLAY_FDB 8 #define BRCMD_ENABLE_DEBUG 9 #define BRCMD_DISABLE_DEBUG 10 #define BRCMD_SET_POLICY 11 /* arg1 = default policy (1==bridge all) */ @@ -283,22 +296,34 @@ #define BRCMD_DISABLE_PROT_STATS 14 #define BRCMD_ZERO_PROT_STATS 15 #define BRCMD_TOGGLE_STP 16 +#define BRCMD_IF_ENABLE 17 /* arg1 = if_index */ +#define BRCMD_IF_DISABLE 18 /* arg1 = if_index */ +#define BRCMD_SET_IF_PRIORITY 19 /* arg1 = if_index, arg2 = priority */ +#define BRCMD_SET_IF_PATH_COST 20 /* arg1 = if_index, arg2 = cost */ /* prototypes of exported bridging functions... */ +#ifdef __KERNEL__ void br_init(void); int br_receive_frame(struct sk_buff *skb); /* 3.5 */ int br_tx_frame(struct sk_buff *skb); +int brg_init(void); int br_ioctl(unsigned int cmd, void *arg); -int br_protocol_ok(unsigned short protocol); void requeue_fdb(struct fdb *node, int new_port); struct fdb *br_avl_find_addr(unsigned char addr[6]); struct fdb *br_avl_insert (struct fdb * new_node); void sprintf_avl (char **pbuffer, struct fdb * tree, off_t *pos,int* len, off_t offset, int length); void br_avl_delete_by_port(int port); +int br_call_bridge(struct sk_buff *skb, unsigned short type); +void br_spacedevice_register(void); + /* externs */ extern struct br_stat br_stats; extern Port_data port_info[]; +#endif + + + --- linux/net/Config.in.orig Sun Dec 19 21:56:37 1999 +++ linux/net/Config.in Sun Dec 19 22:27:35 1999 @@ -62,7 +62,10 @@ tristate 'CCITT X.25 Packet Layer (EXPERIMENTAL)' CONFIG_X25 tristate 'LAPB Data Link Driver (EXPERIMENTAL)' CONFIG_LAPB bool 'Bridging (EXPERIMENTAL)' CONFIG_BRIDGE - bool '802.2 LLC (EXPERIMENTAL)' CONFIG_LLC + if [ "$CONFIG_BRIDGE" != "n" ]; then + int ' Maximum number of bridged interfaces' CONFIG_BRIDGE_NUM_PORTS 8 + fi +bool '802.2 LLC (EXPERIMENTAL)' CONFIG_LLC # if [ "$CONFIG_LLC" = "y" ]; then # bool ' Netbeui (EXPERIMENTAL)' CONFIG_NETBEUI # fi --- linux/net/bridge/br.c.orig Sat Nov 20 08:33:29 1999 +++ linux/net/bridge/br.c Sun Dec 19 23:07:00 1999 @@ -40,10 +40,19 @@ * so blame me first if its broken ;) * * Robert Pintarelli: fixed bug in bpdu time values + * + * Matthew Grant: start ports disabled. + * auto-promiscuous mode on port enable/disable + * fleshed out interface event handling, interfaces + * now register with bridge on module load as well as ifup + * port control ioctls with ifindex support + * brg0 logical ethernet interface + * reworked brcfg to take interface arguments + * added support for changing the hardware address + * generally made bridge a lot more usable. * * Todo: - * Don't bring up devices automatically. Start ports disabled - * and use a netlink notifier so a daemon can maintain the bridge + * Use a netlink notifier so a daemon can maintain the bridge * port group (could we also do multiple groups ????). * A nice /proc file interface. * Put the path costs in the port info and devices. @@ -52,6 +61,7 @@ * */ +#include <linux/module.h> #include <linux/errno.h> #include <linux/types.h> #include <linux/socket.h> @@ -60,10 +70,13 @@ #include <linux/kernel.h> #include <linux/sched.h> #include <linux/timer.h> +#include <linux/malloc.h> #include <linux/string.h> #include <linux/net.h> #include <linux/inet.h> #include <linux/netdevice.h> +#include <linux/inetdevice.h> +#include <linux/etherdevice.h> #include <linux/skbuff.h> #include <linux/if_arp.h> #include <linux/ip.h> @@ -71,6 +84,7 @@ #include <linux/init.h> #include <asm/uaccess.h> #include <asm/system.h> +#include <linux/rtnetlink.h> #include <net/br.h> #include <linux/proc_fs.h> @@ -144,11 +158,20 @@ static int br_flood(struct sk_buff *skb, int port); static int br_drop(struct sk_buff *skb); static int br_learn(struct sk_buff *skb, int port); /* 3.8 */ +static int br_protocol_ok(unsigned short protocol); +static int br_find_port(int ifindex); +static void br_get_ifnames(void); +static int brg_rx(struct sk_buff *skb, int port); static unsigned char bridge_ula[ETH_ALEN] = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 }; static Bridge_data bridge_info; /* (4.5.3) */ Port_data port_info[All_ports]; /* (4.5.5) */ +/* MAG: Maximum port registered - used to speed up flooding and to make + * have a large ports array more efficient + */ +static int max_port_used = 0; + /* JRP: fdb cache 1/port save kmalloc/kfree on every frame */ struct fdb *newfdb[All_ports]; int allocated_fdb_cnt = 0; @@ -189,6 +212,30 @@ 0 }; + +/* + * the following data is for the bridge network device + */ +struct brg_if { + struct net_device dev; + char name[IFNAMSIZ]; +}; +static struct brg_if brg_if; + +/* + * Here to save linkage? problems + */ + +static inline int find_port(struct net_device *dev) +{ + int i; + + for (i = One; i <= No_of_ports; i++) + if (port_info[i].dev == dev) + return(i); + return(0); +} + /* * Implementation of Protocol specific bridging * @@ -201,7 +248,7 @@ /* Checks if that protocol type is to be bridged */ -int br_protocol_ok(unsigned short protocol) +static int inline br_protocol_ok(unsigned short protocol) { unsigned x; @@ -830,12 +877,19 @@ return len; } + void __init br_init(void) { /* (4.8.1) */ int port_no; - printk(KERN_INFO "NET4: Ethernet Bridge 005 for NET4.0\n"); + printk(KERN_INFO "NET4: Ethernet Bridge 006 for NET4.0\n"); + /* Set up brg device information */ + bridge_info.instance = 0; + brg_init(); + + max_port_used = 0; + /* * Form initial topology change time. * The topology change timer is only used if this is the root bridge. @@ -865,8 +919,8 @@ stop_topology_change_timer(); memset(newfdb, 0, sizeof(newfdb)); for (port_no = One; port_no <= No_of_ports; port_no++) { /* (4.8.1.4) */ - /* initial state = Enable */ - user_port_state[port_no] = ~Disabled; + /* initial state = Disable */ + user_port_state[port_no] = Disabled; port_priority[port_no] = 128; br_init_port(port_no); disable_port(port_no); @@ -1194,7 +1248,7 @@ memcpy(eth->h_source, dev->dev_addr, ETH_ALEN); if (br_stats.flags & BR_DEBUG) - printk("send_%s_bpdu: port %i src %02x:%02x:%02x:%02x:%02x:%02x\n", + printk(KERN_DEBUG "send_%s_bpdu: port %i src %02x:%02x:%02x:%02x:%02x:%02x\n", pdu_name, port_no, eth->h_source[0], @@ -1295,6 +1349,9 @@ if (dev->flags & IFF_LOOPBACK) return(NOTIFY_DONE); + if (dev == &brg_if.dev) + return(NOTIFY_DONE); /* Don't attach the brg device to a port! */ + switch (event) { case NETDEV_DOWN: @@ -1324,6 +1381,9 @@ { port_info[i].dev = dev; port_info[i].port_id = i; + dev->bridge_port_id = i; + if( i > max_port_used ) + max_port_used = i; /* set bridge addr from 1st device addr */ if (((htonl(bridge_info.bridge_id.BRIDGE_ID[0])&0xffff) == 0) && (bridge_info.bridge_id.BRIDGE_ID[1] == 0)) @@ -1333,7 +1393,10 @@ bridge_info.bridge_id.BRIDGE_PRIORITY = htons(32768); set_bridge_priority(&bridge_info.bridge_id); } + /* Add local MAC address */ br_add_local_mac(dev->dev_addr); + /* Save MAC address for latter change address events */ + memcpy(port_info[i].ifmac.BRIDGE_ID_ULA, dev->dev_addr, 6); if((br_stats.flags & BR_UP) && (user_port_state[i] != Disabled)) { @@ -1351,19 +1414,116 @@ } } break; + case NETDEV_REGISTER: + if (br_stats.flags & BR_DEBUG) + printk(KERN_DEBUG "br_device_event: NETDEV_REGISTER...\n"); + /* printk(KERN_ERR "br_device_event: NETDEV_REGISTER...\n"); */ + /* printk(KERN_ERR "br_device_event: dev->type: 0x%X\n", dev->type); */ + /* Only handle ethernet ports */ + if(dev->type!=ARPHRD_ETHER && dev->type!=ARPHRD_LOOPBACK) + return NOTIFY_DONE; + /* printk(KERN_ERR "br_device_event: Looking for port...\n"); */ + for (i = One; i <= No_of_ports; i++) + { + if (port_info[i].dev == NULL || port_info[i].dev == dev) + { + /* printk(KERN_ERR "br_device_event: Found port %d\n", i); */ + port_info[i].dev = dev; + port_info[i].port_id = i; + dev->bridge_port_id = i; + if( i > max_port_used ) + max_port_used = i; + /* handle local MAC address minuplations */ + br_add_local_mac(dev->dev_addr); + memcpy(port_info[i].ifmac.BRIDGE_ID_ULA, dev->dev_addr, 6); + return NOTIFY_DONE; + break; + } + } + break; case NETDEV_UNREGISTER: if (br_stats.flags & BR_DEBUG) printk(KERN_DEBUG "br_device_event: NETDEV_UNREGISTER...\n"); i = find_port(dev); if (i > 0) { br_avl_delete_by_port(i); + memset(port_info[i].ifmac.BRIDGE_ID_ULA, 0, 6); port_info[i].dev = NULL; } break; + case NETDEV_CHANGEADDR: + if (br_stats.flags & BR_DEBUG) + printk(KERN_DEBUG "br_device_event: NETDEV_CHANGEADDR...\n"); + i = find_port(dev); + if (i <= 0) + break; + if (memcmp(port_info[i].ifmac.BRIDGE_ID_ULA, dev->dev_addr, 6) != 0) + break; /* Don't worry about a change of hardware broadcast address! */ + if (dev->start) { + printk(KERN_CRIT "br_device_event: NETDEV_CHANGEADDR on busy device %s - FIX DRIVER!\n", + dev->name); + /* return NOTIFY_BAD; It SHOULD be this, but I want to be friendly... */ + return NOTIFY_DONE; + } + br_avl_delete_by_port(i); + memset(port_info[i].ifmac.BRIDGE_ID_ULA, 0, 6); + break; } return NOTIFY_DONE; } +/* Routine to loop over device list and register + * interfaces to bridge. Called from last part of net_dev_init just before + * bootp/rarp interface setup + */ +void br_spacedevice_register(void) +{ + struct net_device *dev; + for( dev = dev_base; dev != NULL; dev = dev->next) + { + br_device_event(NULL, NETDEV_REGISTER, dev); + } +} + + +/* This is for SPEED in the kernel in net_bh.c */ + +int br_call_bridge(struct sk_buff *skb, unsigned short type) +{ + int port; + struct net_device *dev; + +#if 0 /* Checked first in handle_bridge to save expense of function call */ + if(!(br_stats.flags & BR_UP)) + return 0; +#endif + + dev = skb->dev; + port = dev->bridge_port_id; + + if(!port) + return 0; + + /* Sanity - make sure we are not leaping off into fairy space! */ + if ( port < 0 || port > max_port_used || port_info[port].dev != dev) { + if (net_ratelimit()) + printk(KERN_CRIT "br_call_bridge: device %s has invalid port ID %d!\n", + dev->name, + dev->bridge_port_id); + return 0; + } + + if(user_port_state[port] == Disabled) + return 0; + + if (!br_protocol_ok(ntohs(type))) + return 0; + + return 1; + +} + + /* * following routine is called when a frame is received * from an interface, it returns 1 when it consumes the @@ -1375,6 +1535,7 @@ int port; Port_data *p; struct ethhdr *eth; + struct net_device *dev; /* sanity */ if (!skb) { @@ -1382,17 +1543,27 @@ return(1); } + dev = skb->dev; + skb->pkt_bridged = IS_BRIDGED; /* check for loopback */ - if (skb->dev->flags & IFF_LOOPBACK) + if (dev->flags & IFF_LOOPBACK) return 0 ; - port = find_port(skb->dev); +#if 0 + port = find_port(dev); +#else + port = dev->bridge_port_id; +#endif if(!port) return 0; + /* Hand off to brg_rx BEFORE we screw up the skb */ + if(brg_rx(skb, port)) + return(1); + skb->nh.raw = skb->mac.raw; eth = skb->mac.ethernet; p = &port_info[port]; @@ -1501,7 +1672,7 @@ eth = skb->mac.ethernet; port = 0; /* an impossible port (locally generated) */ if (br_stats.flags & BR_DEBUG) - printk("br_tx_fr : port %i src %02x:%02x:%02x:%02x:%02x:%02x" + printk(KERN_DEBUG "br_tx_fr : port %i src %02x:%02x:%02x:%02x:%02x:%02x" " dest %02x:%02x:%02x:%02x:%02x:%02x\n", port, eth->h_source[0], @@ -1739,7 +1910,7 @@ /* timer expired, invalidate entry */ f->flags &= ~FDB_ENT_VALID; if (br_stats.flags & BR_DEBUG) - printk("fdb entry expired...\n"); + printk(KERN_DEBUG "fdb entry expired...\n"); /* * Send flood and drop original */ @@ -1781,7 +1952,7 @@ /* timer expired, invalidate entry */ f->flags &= ~FDB_ENT_VALID; if (br_stats.flags & BR_DEBUG) - printk("fdb entry expired...\n"); + printk(KERN_DEBUG "fdb entry expired...\n"); ++br_stats_cnt.drop_same_port_aged; } else ++br_stats_cnt.drop_same_port; @@ -1808,6 +1979,9 @@ { if (i == port) /* don't send back where we got it */ continue; + if (i > max_port_used) + /* Don't go scanning empty port entries */ + break; if (port_info[i].state == Forwarding) { nskb = skb_clone(skb, GFP_ATOMIC); @@ -1820,7 +1994,7 @@ /* To get here we must have done ARP already, or have a received valid MAC header */ -/* printk("Flood to port %d\n",i);*/ +/* printk(KERN_DEBUG "Flood to port %d\n",i);*/ nskb->nh.raw = nskb->data + ETH_HLEN; nskb->priority = 1; dev_queue_xmit(nskb); @@ -1829,16 +2003,6 @@ return(0); } -static int find_port(struct net_device *dev) -{ - int i; - - for (i = One; i <= No_of_ports; i++) - if (port_info[i].dev == dev) - return(i); - return(0); -} - /* * FIXME: This needs to come from the device structs, eg for * 10,100,1Gbit ethernet. @@ -1945,17 +2109,58 @@ return fdbis; } + +/* Fill in interface names in port_info structure + */ +static void br_get_ifnames(void) { + int i; + + for(i=One;i<=No_of_ports; i++) { + /* memset IS needed. Kernel strncpy does NOT NULL terminate strings when limit + reached */ + memset(port_info[i].ifname, 0, IFNAMSIZ); + if( port_info[i].dev == 0 ) + continue; + strncpy(port_info[i].ifname, port_info[i].dev->name, IFNAMSIZ-1); + /* Being paranoid */ + port_info[i].ifname[IFNAMSIZ-1] = '\0'; + } +} + +/* Given an interface index, loop over port array to see if configured. If + so, return port number, otherwise error */ +static int br_find_port(int ifindex) +{ + int i; + + for(i=1; i <= No_of_ports; i++) { + if (port_info[i].dev == 0) + continue; + if (port_info[i].dev->ifindex == ifindex) + return(i); + } + + return -EUNATCH; /* Tell me if this is incorrect error code for this case */ +} + + int br_ioctl(unsigned int cmd, void *arg) { - int err, i; + int err, i, ifflags; struct br_cf bcf; bridge_id_t new_id; - + struct net_device *dev; + switch(cmd) { case SIOCGIFBR: /* get bridging control blocks */ memcpy(&br_stats.bridge_data, &bridge_info, sizeof(Bridge_data)); - memcpy(&br_stats.port_data, &port_info, sizeof(Port_data)*No_of_ports); + + /* Fill in interface names in port_info*/ + br_get_ifnames(); + + br_stats.num_ports = No_of_ports; + memcpy(&br_stats.port_data, &port_info, sizeof(Port_data)*All_ports); err = copy_to_user(arg, &br_stats, sizeof(struct br_stat)); if (err) @@ -2021,16 +2226,28 @@ } br_stats.flags ^= BR_STP_DISABLED; break; + case BRCMD_IF_ENABLE: + bcf.arg1 = br_find_port(bcf.arg1); + if (bcf.arg1 < 0) + return(bcf.arg1); case BRCMD_PORT_ENABLE: if (port_info[bcf.arg1].dev == 0) return(-EINVAL); if (user_port_state[bcf.arg1] != Disabled) return(-EALREADY); printk(KERN_DEBUG "br: enabling port %i\n",bcf.arg1); + dev = port_info[bcf.arg1].dev; + ifflags = (dev->flags&~(IFF_PROMISC|IFF_ALLMULTI)) + |(dev->gflags&(IFF_PROMISC|IFF_ALLMULTI)); + dev_change_flags(dev, ifflags|IFF_PROMISC); user_port_state[bcf.arg1] = ~Disabled; if(br_stats.flags & BR_UP) enable_port(bcf.arg1); break; + case BRCMD_IF_DISABLE: + bcf.arg1 = br_find_port(bcf.arg1); + if (bcf.arg1 < 0) + return(bcf.arg1); case BRCMD_PORT_DISABLE: if (port_info[bcf.arg1].dev == 0) return(-EINVAL); @@ -2040,12 +2257,20 @@ user_port_state[bcf.arg1] = Disabled; if(br_stats.flags & BR_UP) disable_port(bcf.arg1); + dev = port_info[bcf.arg1].dev; + ifflags = (dev->flags&~(IFF_PROMISC|IFF_ALLMULTI)) + |(dev->gflags&(IFF_PROMISC|IFF_ALLMULTI)); + dev_change_flags(port_info[bcf.arg1].dev, ifflags & ~IFF_PROMISC); break; case BRCMD_SET_BRIDGE_PRIORITY: new_id = bridge_info.bridge_id; new_id.BRIDGE_PRIORITY = htons(bcf.arg1); set_bridge_priority(&new_id); break; + case BRCMD_SET_IF_PRIORITY: + bcf.arg1 = br_find_port(bcf.arg1); + if (bcf.arg1 < 0) + return(bcf.arg1); case BRCMD_SET_PORT_PRIORITY: if((port_info[bcf.arg1].dev == 0) || (bcf.arg2 & ~0xff)) @@ -2053,6 +2278,10 @@ port_priority[bcf.arg1] = bcf.arg2; set_port_priority(bcf.arg1); break; + case BRCMD_SET_IF_PATH_COST: + bcf.arg1 = br_find_port(bcf.arg1); + if (bcf.arg1 < 0) + return(bcf.arg1); case BRCMD_SET_PATH_COST: if (port_info[bcf.arg1].dev == 0) return(-EINVAL); @@ -2134,3 +2363,377 @@ } return(0); } + + + + +/* -------------------------------------------------------------------------------- + * + * + * Bridge network device here for future modularization - device structures + * must be 'static' inside bridge instance + * Modelled after sch_teql.c + * + */ + + + +/* + * Index to functions. + */ + +int brg_probe(struct net_device *dev); +static int brg_open(struct net_device *dev); +static int brg_start_xmit(struct sk_buff *skb, struct net_device *dev); +static int brg_close(struct net_device *dev); +static struct net_device_stats *brg_get_stats(struct net_device *dev); +static void brg_set_multicast_list(struct net_device *dev); + +/* + * Board-specific info in dev->priv. + */ + +struct net_local +{ + __u32 groups; + struct net_device_stats stats; +}; + + + + +/* + * To call this a probe is a bit misleading, however for real + * hardware it would have to check what was present. + */ + +int __init brg_probe(struct net_device *dev) +{ + unsigned int bogomips; + struct timeval utime; + + printk(KERN_INFO "%s: network interface for Ethernet Bridge 006/NET4.0\n", dev->name); + + /* + * Initialize the device structure. + */ + + dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL); + if (dev->priv == NULL) + return -ENOMEM; + memset(dev->priv, 0, sizeof(struct net_local)); + + /* Set up MAC address based on BogoMIPs figure for first CPU and time + */ + bogomips = (boot_cpu_data.loops_per_sec+2500)/500000 ; + get_fast_time(&utime); + + /* Ummmm.... YES! */ + dev->dev_addr[0] = '\xFE'; + dev->dev_addr[1] = '\xFD'; + dev->dev_addr[2] = (bridge_info.instance & 0x0F) << 4; + dev->dev_addr[2] |= ((utime.tv_sec & 0x000F0000) >> 16); + dev->dev_addr[3] = bogomips & 0xFF; + dev->dev_addr[4] = (utime.tv_sec & 0x0000FF00) >> 8; + dev->dev_addr[5] = (utime.tv_sec & 0x000000FF); + + printk(KERN_INFO "%s: generated MAC address %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X\n", + dev->name, + dev->dev_addr[0], + dev->dev_addr[1], + dev->dev_addr[2], + dev->dev_addr[3], + dev->dev_addr[4], + dev->dev_addr[5]); + + + printk(KERN_INFO "%s: attached to bridge instance %lu\n", dev->name, dev->base_addr); + + /* + * The brg specific entries in the device structure. + */ + + dev->open = brg_open; + dev->hard_start_xmit = brg_start_xmit; + dev->stop = brg_close; + dev->get_stats = brg_get_stats; + dev->set_multicast_list = brg_set_multicast_list; + + /* + * Setup the generic properties + */ + + ether_setup(dev); + + dev->tx_queue_len = 0; + + return 0; +} + +/* + * Open/initialize the board. + */ + +static int brg_open(struct net_device *dev) +{ + if (br_stats.flags & BR_DEBUG) + printk(KERN_DEBUG "%s: Doing brg_open()...", dev->name); + + if (memcmp(dev->dev_addr, "\x00\x00\x00\x00\x00\x00", ETH_ALEN) == 0) + return -EFAULT; + + dev->start = 1; + dev->tbusy = 0; + return 0; +} + +static unsigned brg_mc_hash(__u8 *dest) +{ + unsigned idx = 0; + idx ^= dest[0]; + idx ^= dest[1]; + idx ^= dest[2]; + idx ^= dest[3]; + idx ^= dest[4]; + idx ^= dest[5]; + return 1U << (idx&0x1F); +} + +static void brg_set_multicast_list(struct net_device *dev) +{ + unsigned groups = ~0; + struct net_local *lp = (struct net_local *)dev->priv; + + if (!(dev->flags&(IFF_PROMISC|IFF_ALLMULTI))) { + struct dev_mc_list *dmi; + + groups = brg_mc_hash(dev->broadcast); + + for (dmi=dev->mc_list; dmi; dmi=dmi->next) { + if (dmi->dmi_addrlen != 6) + continue; + groups |= brg_mc_hash(dmi->dmi_addr); + } + } + lp->groups = groups; +} + +/* + * We transmit by throwing the packet at the bridge. + */ + +static int brg_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct net_local *lp = (struct net_local *)dev->priv; + struct ethhdr *eth = (struct ethhdr*)skb->data; + int port; + + /* Deal with the bridge being disabled */ + if(!(br_stats.flags & BR_UP)) { + /* Either this */ + /* lp->stats.tx_errors++; */ /* this condition is NOT an error */ + /* or this (implied by RFC 2233) */ + lp->stats.tx_dropped++; + dev_kfree_skb(skb); + return 0; + } + + lp->stats.tx_bytes+=skb->len; + lp->stats.tx_packets++; + +#if 0 + ++br_stats_cnt.port_not_disable; +#endif + skb->mac.raw = skb->nh.raw = skb->data; + eth = skb->mac.ethernet; + port = 0; /* an impossible port (locally generated) */ + + if (br_stats.flags & BR_DEBUG) + printk(KERN_DEBUG "%s: brg_start_xmit - src %02x:%02x:%02x:%02x:%02x:%02x" + " dest %02x:%02x:%02x:%02x:%02x:%02x\n", + dev->name, + eth->h_source[0], + eth->h_source[1], + eth->h_source[2], + eth->h_source[3], + eth->h_source[4], + eth->h_source[5], + eth->h_dest[0], + eth->h_dest[1], + eth->h_dest[2], + eth->h_dest[3], + eth->h_dest[4], + eth->h_dest[5]); + + /* Forward the packet ! */ + if(br_forward(skb, port)) + return(0); + + /* Throw packet initially */ + dev_kfree_skb(skb); + return 0; +} + + +/* + * The typical workload of the driver: + * Handle the ether interface interrupts. + * + * (In this case handle the packets posted from the bridge) + */ + +static int brg_rx(struct sk_buff *skb, int port) +{ + struct net_device *dev = &brg_if.dev; + struct net_local *lp = (struct net_local *)dev->priv; + struct ethhdr *eth = (struct ethhdr*)(skb->data); + int len = skb->len; + int clone = 0; + + if (br_stats.flags & BR_DEBUG) + printk(KERN_DEBUG "%s: brg_rx()\n", dev->name); + + /* Get out of here if the bridge interface is not up + */ + if(!(dev->flags & IFF_UP)) + return(0); + + /* Check that the port that this thing came off is in the forwarding state + * We sould only listen to the same address scope we will transmit to. + */ + if(port_info[port].state != Forwarding) + return(0); + + /* Is this for us? - broadcast/mulitcast/promiscuous packets need cloning, + * with uni-cast we eat the packet + */ + clone = 0; + if (dev->flags & IFF_PROMISC) { + clone = 1; + } + else if (eth->h_dest[0]&1) { + if (!(dev->flags&(IFF_ALLMULTI)) + && !(brg_mc_hash(eth->h_dest)&lp->groups)) + return(0); + clone = 1; + } + else if (memcmp(eth->h_dest, dev->dev_addr, ETH_ALEN) != 0) { + return(0); + } + + /* Clone things here - we want to be transparent before we check packet data + * integrity + */ + if(clone) { + struct sk_buff *skb2 = skb; + skb = skb_clone(skb2, GFP_KERNEL); + if (skb == NULL) { + return(0); + } + + } + + /* Check packet length + */ + if (len < 16) { + printk(KERN_DEBUG "%s : rx len = %d\n", dev->name, len); + kfree_skb(skb); + return(!clone); + } + + if (br_stats.flags & BR_DEBUG) + printk(KERN_DEBUG "%s: brg_rx - src %02x:%02x:%02x:%02x:%02x:%02x" + " dest %02x:%02x:%02x:%02x:%02x:%02x\n", + dev->name, + eth->h_source[0], + eth->h_source[1], + eth->h_source[2], + eth->h_source[3], + eth->h_source[4], + eth->h_source[5], + eth->h_dest[0], + eth->h_dest[1], + eth->h_dest[2], + eth->h_dest[3], + eth->h_dest[4], + eth->h_dest[5]); + + /* Do it */ + skb->pkt_type = PACKET_HOST; + skb->dev = dev; + skb->protocol=eth_type_trans(skb,dev); + memset(skb->cb, 0, sizeof(skb->cb)); + lp->stats.rx_packets++; + lp->stats.rx_bytes+=len; + netif_rx(skb); + return(!clone); +} + +static int brg_close(struct net_device *dev) +{ + if (br_stats.flags & BR_DEBUG) + printk(KERN_DEBUG "%s: Shutting down.\n", dev->name); + + dev->tbusy = 1; + dev->start = 0; + + return 0; +} + +static struct net_device_stats *brg_get_stats(struct net_device *dev) +{ + struct net_local *lp = (struct net_local *)dev->priv; + return &lp->stats; +} + +/* + * + */ + +int __init brg_init(void) +{ + int err; + + memset(&brg_if, 0, sizeof(brg_if)); + + rtnl_lock(); + + brg_if.dev.base_addr = bridge_info.instance; + sprintf (brg_if.name, "brg%d", bridge_info.instance); + brg_if.dev.name = (void*)&brg_if.name; + if(dev_get(brg_if.name)) { + printk(KERN_INFO "%s already loaded.\n", brg_if.name); + return -EBUSY; + } + brg_if.dev.init = brg_probe; + + err = register_netdevice(&brg_if.dev); + rtnl_unlock(); + return err; +} + + +#if 0 /* Its here if we ever need it... */ +#ifdef MODULE + +void cleanup_module(void) +{ + + /* + * Unregister the device + */ + rtnl_lock(); + unregister_netdevice(&the_master.dev); + rtnl_unlock(); + + /* + * Free up the private structure. + */ + + kfree(brg_if.dev.priv); + brg_if.dev.priv = NULL; /* gets re-allocated by brg_probe */ +} + +#endif /* MODULE */ + +#endif --- linux/net/bridge/br_tree.c.orig Mon Mar 8 12:25:23 1999 +++ linux/net/bridge/br_tree.c Sun Dec 19 22:22:55 1999 @@ -492,7 +492,8 @@ port_info[port].fdb = NULL; /* remove the local mac too */ - next = br_avl_find_addr(port_info[port].dev->dev_addr); +/* next = br_avl_find_addr(port_info[port].dev->dev_addr); */ + next = br_avl_find_addr(port_info[port].ifmac.BRIDGE_ID_ULA); if (next != NULL) br_avl_remove(next); --- linux/net/core/dev.c.orig Sun Dec 19 21:56:37 1999 +++ linux/net/core/dev.c Sun Dec 19 22:22:55 1999 @@ -860,7 +860,11 @@ #ifdef CONFIG_BRIDGE static inline void handle_bridge(struct sk_buff *skb, unsigned short type) { - if (br_stats.flags & BR_UP && br_protocol_ok(ntohs(type))) + /* + * The br_stats.flags is checked here to save the expense of a + * function call. + */ + if ((br_stats.flags & BR_UP) && br_call_bridge(skb, type)) { /* * We pass the bridge a complete frame. This means @@ -884,7 +888,6 @@ } #endif - /* * When we are called the queue is ready to grab, the interrupts are * on and hardware can interrupt and queue to the receive queue as we @@ -2094,6 +2097,13 @@ dst_init(); dev_mcast_init(); + +#ifdef CONFIG_BRIDGE + /* + * Register any statically linked ethernet devices with the bridge + */ + br_spacedevice_register(); +#endif /* * Initialise network devices

- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.rutgers.edu Please read the FAQ at http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Sun Jan 23 2000 - 21:00:21 EST