Greetings everyone, The following change (against ppclinux 2.4.18pre2 --sorry that's what I'm working on right now) removes the bridge driver's global hook and replaces it with a device-specific function. With this change, any driver which defines net_device.recv_from_slave() and calls netdev_set_master(slave, self) has the opportunity to process the packets received by the slave device. This method seemed more flexible than adding a global hook for my own driver. Please let me know what you think. A simple "this looks good" or "it has the following problems..." would be greatly appreciated. diff -wbBurN linux-GPL.orig/drivers/net/bonding.c linux-GPL/drivers/net/bonding.c --- linux-GPL.orig/drivers/net/bonding.c Fri May 3 13:49:25 2002 +++ linux-GPL/drivers/net/bonding.c Wed Jan 29 13:31:21 2003 @@ -504,7 +504,7 @@ } memset(new_slave, 0, sizeof(slave_t)); - err = netdev_set_master(slave_dev, master_dev); + err = netdev_set_master(slave_dev, master_dev, NULL); if (err) { #ifdef BONDING_DEBUG @@ -833,7 +833,7 @@ /* release the slave from its bond */ - netdev_set_master(slave, NULL); + netdev_set_master(slave, NULL, NULL); /* only restore its RUNNING flag if monitoring set it down */ if (slave->flags & IFF_UP) { diff -wbBurN linux-GPL.orig/include/linux/if_bridge.h linux-GPL/include/linux/if_bridge.h --- linux-GPL.orig/include/linux/if_bridge.h Wed Jan 22 13:47:27 2003 +++ linux-GPL/include/linux/if_bridge.h Thu Jan 30 16:16:03 2003 @@ -102,7 +102,6 @@ struct net_bridge_port; extern int (*br_ioctl_hook)(unsigned long arg); -extern void (*br_handle_frame_hook)(struct sk_buff *skb); #endif diff -wbBurN linux-GPL.orig/include/linux/netdevice.h linux-GPL/include/linux/netdevice.h --- linux-GPL.orig/include/linux/netdevice.h Wed Jan 22 13:46:26 2003 +++ linux-GPL/include/linux/netdevice.h Thu Jan 30 16:12:24 2003 @@ -303,6 +303,7 @@ struct net_device *master; /* Pointer to master device of a group, * which this device is member of. */ + void *master_priv; /* for use by master device */ /* Interface address info. */ unsigned char broadcast[MAX_ADDR_LEN]; /* hw bcast add */ @@ -371,6 +372,7 @@ void *saddr, unsigned len); int (*rebuild_header)(struct sk_buff *skb); + void (*recv_from_slave)(struct sk_buff *skb); #define HAVE_MULTICAST void (*set_multicast_list)(struct net_device *dev); #define HAVE_SET_MAC_ADDR @@ -402,9 +404,6 @@ /* open/release and usage marking */ struct module *owner; - /* bridge stuff */ - struct net_bridge_port *br_port; - #ifdef CONFIG_NET_FASTROUTE #define NETDEV_FASTROUTE_HMASK 0xF /* Semi-private data. Keep it at the end of device struct. */ @@ -709,7 +708,7 @@ extern int netdev_max_backlog; extern unsigned long netdev_fc_xoff; extern atomic_t netdev_dropping; -extern int netdev_set_master(struct net_device *dev, struct net_device *master); +extern int netdev_set_master(struct net_device *dev, struct net_device *master, void *master_priv); extern struct sk_buff * skb_checksum_help(struct sk_buff *skb); #ifdef CONFIG_NET_FASTROUTE extern int netdev_fastroute; diff -wbBurN linux-GPL.orig/net/bridge/br.c linux-GPL/net/bridge/br.c --- linux-GPL.orig/net/bridge/br.c Fri May 3 13:49:45 2002 +++ linux-GPL/net/bridge/br.c Wed Jan 29 09:42:09 2003 @@ -42,7 +42,6 @@ { printk(KERN_INFO "NET4: Ethernet Bridge 008 for NET4.0\n"); - br_handle_frame_hook = br_handle_frame; #ifdef CONFIG_INET br_ioctl_hook = br_ioctl_deviceless_stub; #endif @@ -55,11 +54,6 @@ return 0; } -static void __br_clear_frame_hook(void) -{ - br_handle_frame_hook = NULL; -} - static void __br_clear_ioctl_hook(void) { #ifdef CONFIG_INET @@ -71,7 +65,6 @@ { unregister_netdevice_notifier(&br_device_notifier); br_call_ioctl_atomic(__br_clear_ioctl_hook); - net_call_rx_atomic(__br_clear_frame_hook); #if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE) br_fdb_get_hook = NULL; br_fdb_put_hook = NULL; diff -wbBurN linux-GPL.orig/net/bridge/br_device.c linux-GPL/net/bridge/br_device.c --- linux-GPL.orig/net/bridge/br_device.c Fri May 3 13:49:45 2002 +++ linux-GPL/net/bridge/br_device.c Thu Jan 30 13:56:31 2003 @@ -128,6 +128,7 @@ dev->do_ioctl = br_dev_do_ioctl; dev->get_stats = br_dev_get_stats; dev->hard_start_xmit = br_dev_xmit; + dev->recv_from_slave = br_handle_frame; dev->open = br_dev_open; dev->set_multicast_list = br_dev_set_multicast_list; dev->stop = br_dev_stop; diff -wbBurN linux-GPL.orig/net/bridge/br_if.c linux-GPL/net/bridge/br_if.c --- linux-GPL.orig/net/bridge/br_if.c Fri May 3 13:49:45 2002 +++ linux-GPL/net/bridge/br_if.c Fri Jan 31 09:16:14 2003 @@ -43,13 +43,23 @@ struct net_bridge_port *p; struct net_bridge_port **pptr; - if ((p = dev->br_port) == NULL) + if ((p = dev->master_priv) == NULL) return -EINVAL; br_stp_disable_port(p); dev_set_promiscuity(dev, -1); - dev->br_port = NULL; + +#if 0 + /* This yields "alloc_skb called nonatomically from interrupt". */ + netdev_set_master(dev, NULL, NULL); +#else + /* This is the essence of netdev_set_master() but without the locks and + * rtmsg_ifinfo(RTM_NEWLINK...) call. */ + dev->flags &= ~IFF_SLAVE; + dev->master = NULL; + dev->master_priv = NULL; +#endif pptr = &br->port_list; while (*pptr != NULL) { @@ -150,8 +160,6 @@ p->path_cost = br_initial_port_cost(dev); p->priority = 0x80; - dev->br_port = p; - for (i=1;i<255;i++) if (br_get_port(br, i) == NULL) break; @@ -161,6 +169,17 @@ return NULL; } +#if 0 + /* This yields "alloc_skb called nonatomically from interrupt". */ + netdev_set_master(dev, &br->dev, p); +#else + /* This is the essence of netdev_set_master() but without the locks and + * rtmsg_ifinfo(RTM_NEWLINK...) call. */ + dev->master_priv = p; + dev->master = &br->dev; + dev->flags |= IFF_SLAVE; +#endif + p->port_no = i; br_init_port(p); p->state = BR_STATE_DISABLED; @@ -220,7 +239,7 @@ { struct net_bridge_port *p; - if (dev->br_port != NULL) + if (dev->master_priv != NULL) return -EBUSY; if (dev->flags & IFF_LOOPBACK || dev->type != ARPHRD_ETHER) diff -wbBurN linux-GPL.orig/net/bridge/br_input.c linux-GPL/net/bridge/br_input.c --- linux-GPL.orig/net/bridge/br_input.c Fri May 3 13:49:45 2002 +++ linux-GPL/net/bridge/br_input.c Wed Jan 29 13:28:37 2003 @@ -56,7 +56,7 @@ dest = skb->mac.ethernet->h_dest; - p = skb->dev->br_port; + p = skb->dev->master_priv; br = p->br; passedup = 0; @@ -144,7 +144,7 @@ { struct net_bridge *br; - br = skb->dev->br_port->br; + br = ((struct net_bridge_port*)skb->dev->master_priv)->br; read_lock(&br->lock); __br_handle_frame(skb); read_unlock(&br->lock); diff -wbBurN linux-GPL.orig/net/bridge/br_notify.c linux-GPL/net/bridge/br_notify.c --- linux-GPL.orig/net/bridge/br_notify.c Fri May 3 13:49:45 2002 +++ linux-GPL/net/bridge/br_notify.c Tue Jan 28 15:00:19 2003 @@ -32,7 +32,7 @@ struct net_bridge_port *p; dev = ptr; - p = dev->br_port; + p = dev->master_priv; if (p == NULL) return NOTIFY_DONE; @@ -53,7 +53,7 @@ case NETDEV_DOWN: if (p->br->dev.flags & IFF_UP) { read_lock(&p->br->lock); - br_stp_disable_port(dev->br_port); + br_stp_disable_port(p); read_unlock(&p->br->lock); } break; @@ -61,13 +61,13 @@ case NETDEV_UP: if (p->br->dev.flags & IFF_UP) { read_lock(&p->br->lock); - br_stp_enable_port(dev->br_port); + br_stp_enable_port(p); read_unlock(&p->br->lock); } break; case NETDEV_UNREGISTER: - br_del_if(dev->br_port->br, dev); + br_del_if(p->br, dev); break; } diff -wbBurN linux-GPL.orig/net/bridge/br_stp_bpdu.c linux-GPL/net/bridge/br_stp_bpdu.c --- linux-GPL.orig/net/bridge/br_stp_bpdu.c Fri May 3 13:49:45 2002 +++ linux-GPL/net/bridge/br_stp_bpdu.c Tue Jan 28 15:00:55 2003 @@ -139,7 +139,7 @@ struct net_bridge_port *p; buf = skb->mac.raw + 14; - p = skb->dev->br_port; + p = skb->dev->master_priv; if (!p->br->stp_enabled || memcmp(buf, header, 6)) { kfree_skb(skb); return; diff -wbBurN linux-GPL.orig/net/core/dev.c linux-GPL/net/core/dev.c --- linux-GPL.orig/net/core/dev.c Fri May 3 13:49:45 2002 +++ linux-GPL/net/core/dev.c Fri Jan 31 15:46:21 2003 @@ -1307,15 +1307,15 @@ return ret; } -/* Reparent skb to master device. This function is called - * only from net_rx_action under BR_NETPROTO_LOCK. It is misuse - * of BR_NETPROTO_LOCK, but it is OK for now. +/* If the master device has no recv_from_slave() handler, just reparent skb to + * the master device. This function is called only from net_rx_action under + * BR_NETPROTO_LOCK. It is misuse of BR_NETPROTO_LOCK, but it is OK for now. */ static __inline__ void skb_bond(struct sk_buff *skb) { struct net_device *dev = skb->dev; - if (dev->master) { + if (dev->master && !dev->master->recv_from_slave) { dev_hold(dev->master); skb->dev = dev->master; dev_put(dev); @@ -1383,11 +1383,7 @@ br_write_unlock_bh(BR_NETPROTO_LOCK); } -#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) -void (*br_handle_frame_hook)(struct sk_buff *skb) = NULL; -#endif - -static __inline__ int handle_bridge(struct sk_buff *skb, +static __inline__ int handle_master_recv(struct sk_buff *skb, struct packet_type *pt_prev) { int ret = NET_RX_DROP; @@ -1401,7 +1397,7 @@ } } - br_handle_frame_hook(skb); + skb->dev->master->recv_from_slave(skb); return ret; } @@ -1476,14 +1472,12 @@ #endif /* CONFIG_NET_DIVERT */ -#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) - if (skb->dev->br_port != NULL && - br_handle_frame_hook != NULL) { - handle_bridge(skb, pt_prev); + if (skb->dev->master != NULL + && skb->dev->master->recv_from_slave != NULL) { + handle_master_recv(skb, pt_prev); dev_put(rx_dev); continue; } -#endif for (ptype=ptype_base[ntohs(type)&15];ptype;ptype=ptype->next) { if (ptype->type == type && @@ -1916,6 +1910,7 @@ * netdev_set_master - set up master/slave pair * @slave: slave device * @master: new master device + * @master_priv: private data for master device * * Changes the master device of the slave. Pass %NULL to break the * bonding. The caller must hold the RTNL semaphore. On a failure @@ -1924,7 +1919,8 @@ * function returns zero. */ -int netdev_set_master(struct net_device *slave, struct net_device *master) +int netdev_set_master(struct net_device *slave, + struct net_device *master, void *master_priv) { struct net_device *old = slave->master; @@ -1938,16 +1934,18 @@ br_write_lock_bh(BR_NETPROTO_LOCK); slave->master = master; + if (master) { + slave->master_priv = master_priv; + slave->flags |= IFF_SLAVE; + } else { + slave->master_priv = NULL; + slave->flags &= ~IFF_SLAVE; + } br_write_unlock_bh(BR_NETPROTO_LOCK); if (old) dev_put(old); - if (master) - slave->flags |= IFF_SLAVE; - else - slave->flags &= ~IFF_SLAVE; - rtmsg_ifinfo(RTM_NEWLINK, slave, IFF_SLAVE); return 0; } diff -wbBurN linux-GPL.orig/net/netsyms.c linux-GPL/net/netsyms.c --- linux-GPL.orig/net/netsyms.c Thu Sep 5 08:05:15 2002 +++ linux-GPL/net/netsyms.c Wed Jan 29 09:40:44 2003 @@ -227,7 +227,6 @@ EXPORT_SYMBOL(scm_detach_fds); #if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) -EXPORT_SYMBOL(br_handle_frame_hook); #ifdef CONFIG_INET EXPORT_SYMBOL(br_ioctl_hook); #endif -- Dan Eble <dane@aiinet.com> _____ . | _ |/| Applied Innovation Inc. | |_| | | http://www.aiinet.com/ |__/|_|_| - : send the line "unsubscribe linux-net" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html