int br_add_if(struct net_bridge *br, struct net_device *dev) { struct net_bridge_port *p; if (dev->br_port != NULL) return -EBUSY; if (dev->flags & IFF_LOOPBACK || dev->type != ARPHRD_ETHER) return -EINVAL; dev_hold(dev); write_lock_bh(&br->lock); if ((p = new_nbp(br, dev)) == NULL) { write_unlock_bh(&br->lock); dev_put(dev); return -EXFULL; } dev_set_promiscuity(dev, 1); br_stp_recalculate_bridge_id(br); br_fdb_insert(br, p, dev->dev_addr, 1); if ((br->dev.flags & IFF_UP) && (dev->flags & IFF_UP)) br_stp_enable_port(p); write_unlock_bh(&br->lock); return 0; }
/* * Handle changes in state of network devices enslaved to a bridge. * * Note: don't care about up/down if bridge itself is down, because * port state is checked when bridge is brought up. */ static int br_device_event(struct notifier_block *unused, unsigned long event, void *ptr) { struct net_device *dev = ptr; struct net_bridge_port *p = dev->br_port; struct net_bridge *br; /* not a port of a bridge */ if (p == NULL) return NOTIFY_DONE; br = p->br; switch (event) { case NETDEV_CHANGEMTU: dev_set_mtu(br->dev, br_min_mtu(br)); break; case NETDEV_CHANGEADDR: spin_lock_bh(&br->lock); br_fdb_changeaddr(p, dev->dev_addr); br_ifinfo_notify(RTM_NEWLINK, p); br_stp_recalculate_bridge_id(br); spin_unlock_bh(&br->lock); break; case NETDEV_CHANGE: br_port_carrier_check(p); break; case NETDEV_FEAT_CHANGE: spin_lock_bh(&br->lock); if (netif_running(br->dev)) br_features_recompute(br); spin_unlock_bh(&br->lock); break; case NETDEV_DOWN: spin_lock_bh(&br->lock); if (br->dev->flags & IFF_UP) br_stp_disable_port(p); spin_unlock_bh(&br->lock); break; case NETDEV_UP: spin_lock_bh(&br->lock); if (netif_carrier_ok(dev) && (br->dev->flags & IFF_UP)) br_stp_enable_port(p); spin_unlock_bh(&br->lock); break; case NETDEV_UNREGISTER: br_del_if(br, dev); break; } return NOTIFY_DONE; }
int br_del_if(struct net_bridge *br, struct net_device *dev) { int retval; write_lock_bh(&br->lock); retval = __br_del_if(br, dev); br_stp_recalculate_bridge_id(br); write_unlock_bh(&br->lock); return retval; }
static int br_device_event(struct notifier_block *unused, unsigned long event, void *ptr) { struct net_device *dev; struct net_bridge_port *p; dev = ptr; p = dev->br_port; if (p == NULL) return NOTIFY_DONE; switch (event) { case NETDEV_CHANGEADDR: read_lock(&p->br->lock); br_fdb_changeaddr(p, dev->dev_addr); br_stp_recalculate_bridge_id(p->br); read_unlock(&p->br->lock); break; case NETDEV_GOING_DOWN: /* extend the protocol to send some kind of notification? */ break; case NETDEV_DOWN: if (p->br->dev.flags & IFF_UP) { read_lock(&p->br->lock); #if 0 #ifdef STP_DISABLE_ETH //Chris: stp+mesh p->disable_by_mesh = 0; #endif #endif br_stp_disable_port(dev->br_port); read_unlock(&p->br->lock); } break; case NETDEV_UP: if (p->br->dev.flags & IFF_UP) { read_lock(&p->br->lock); br_stp_enable_port(dev->br_port); read_unlock(&p->br->lock); } break; case NETDEV_UNREGISTER: br_del_if(dev->br_port->br, dev); break; } return NOTIFY_DONE; }
int br_add_if(struct net_bridge *br, struct net_device *dev) { struct net_bridge_port *p; if (dev->br_port != NULL) return -EBUSY; #if 0 if (dev->flags & IFF_LOOPBACK || dev->type != ARPHRD_ETHER) return -EINVAL; #endif if (dev->hard_start_xmit == br_dev_xmit) return -ELOOP; if (!is_valid_ether_addr(dev->dev_addr)) return -EADDRNOTAVAIL; dev_hold(dev); write_lock_bh(&br->lock); if ((p = new_nbp(br, dev)) == NULL) { write_unlock_bh(&br->lock); dev_put(dev); return -EXFULL; } dev_set_promiscuity(dev, 1); br_stp_recalculate_bridge_id(br); br_fdb_insert(br, p, dev->dev_addr, 1); if ((br->dev.flags & IFF_UP) && (dev->flags & IFF_UP)) br_stp_enable_port(p); write_unlock_bh(&br->lock); return 0; }
static int br_device_event(struct notifier_block *unused, unsigned long event, void *ptr) { struct net_device *dev = ptr; struct net_bridge_port *p = dev->br_port; struct net_bridge *br; int err; /* not a port of a bridge */ if (p == NULL) return NOTIFY_DONE; br = p->br; switch (event) { case NETDEV_CHANGEMTU: dev_set_mtu(br->dev, br_min_mtu(br)); break; case NETDEV_CHANGEADDR: spin_lock_bh(&br->lock); br_fdb_changeaddr(p, dev->dev_addr); br_stp_recalculate_bridge_id(br); spin_unlock_bh(&br->lock); break; case NETDEV_CHANGE: br_port_carrier_check(p); break; case NETDEV_FEAT_CHANGE: spin_lock_bh(&br->lock); if (netif_running(br->dev)) br_features_recompute(br); spin_unlock_bh(&br->lock); break; case NETDEV_DOWN: spin_lock_bh(&br->lock); if (br->dev->flags & IFF_UP) br_stp_disable_port(p); spin_unlock_bh(&br->lock); break; case NETDEV_UP: if (netif_carrier_ok(dev) && (br->dev->flags & IFF_UP)) { spin_lock_bh(&br->lock); br_stp_enable_port(p); spin_unlock_bh(&br->lock); } break; case NETDEV_UNREGISTER: br_del_if(br, dev); break; case NETDEV_CHANGENAME: err = br_sysfs_renameif(p); if (err) return notifier_from_errno(err); break; case NETDEV_PRE_TYPE_CHANGE: /* Forbid underlaying device to change its type. */ return NOTIFY_BAD; } /* Events that may cause spanning tree to refresh */ if (event == NETDEV_CHANGEADDR || event == NETDEV_UP || event == NETDEV_CHANGE || event == NETDEV_DOWN) br_ifinfo_notify(RTM_NEWLINK, p); return NOTIFY_DONE; }
/* * Handle changes in state of network devices enslaved to a bridge. * * Note: don't care about up/down if bridge itself is down, because * port state is checked when bridge is brought up. */ static int br_device_event(struct notifier_block *unused, unsigned long event, void *ptr) { struct net_device *dev = netdev_notifier_info_to_dev(ptr); struct net_bridge_port *p; struct net_bridge *br; bool changed_addr; int err; /* register of bridge completed, add sysfs entries */ if ((dev->priv_flags & IFF_EBRIDGE) && event == NETDEV_REGISTER) { br_sysfs_addbr(dev); return NOTIFY_DONE; } /* not a port of a bridge */ p = br_port_get_rtnl(dev); if (!p) return NOTIFY_DONE; br = p->br; switch (event) { case NETDEV_CHANGEMTU: dev_set_mtu(br->dev, br_min_mtu(br)); break; case NETDEV_CHANGEADDR: spin_lock_bh(&br->lock); br_fdb_changeaddr(p, dev->dev_addr); changed_addr = br_stp_recalculate_bridge_id(br); spin_unlock_bh(&br->lock); if (changed_addr) call_netdevice_notifiers(NETDEV_CHANGEADDR, br->dev); break; case NETDEV_CHANGE: br_port_carrier_check(p); break; case NETDEV_FEAT_CHANGE: netdev_update_features(br->dev); break; case NETDEV_DOWN: spin_lock_bh(&br->lock); if (br->dev->flags & IFF_UP) br_stp_disable_port(p); spin_unlock_bh(&br->lock); break; case NETDEV_UP: if (netif_running(br->dev) && netif_oper_up(dev)) { spin_lock_bh(&br->lock); br_stp_enable_port(p); spin_unlock_bh(&br->lock); } break; case NETDEV_UNREGISTER: br_del_if(br, dev); break; case NETDEV_CHANGENAME: err = br_sysfs_renameif(p); if (err) return notifier_from_errno(err); break; case NETDEV_PRE_TYPE_CHANGE: /* Forbid underlaying device to change its type. */ return NOTIFY_BAD; case NETDEV_RESEND_IGMP: /* Propagate to master device */ call_netdevice_notifiers(event, br->dev); break; } /* Events that may cause spanning tree to refresh */ if (event == NETDEV_CHANGEADDR || event == NETDEV_UP || event == NETDEV_CHANGE || event == NETDEV_DOWN) br_ifinfo_notify(RTM_NEWLINK, p); return NOTIFY_DONE; }
/* * Handle changes in state of network devices enslaved to a bridge. * * Note: don't care about up/down if bridge itself is down, because * port state is checked when bridge is brought up. */ static int br_device_event(struct notifier_block *unused, unsigned long event, void *ptr) { struct net_device *dev = ptr; struct net_bridge_port *p = dev->br_port; struct net_bridge *br; /* not a port of a bridge */ if (p == NULL) return NOTIFY_DONE; br = p->br; spin_lock_bh(&br->lock); switch (event) { case NETDEV_CHANGEMTU: dev_set_mtu(br->dev, br_min_mtu(br)); break; case NETDEV_CHANGEADDR: br_fdb_changeaddr(p, dev->dev_addr); br_stp_recalculate_bridge_id(br); break; case NETDEV_CHANGE: /* device is up but carrier changed */ if (!(br->dev->flags & IFF_UP)) break; if (netif_carrier_ok(dev)) { if (p->state == BR_STATE_DISABLED) br_stp_enable_port(p); } else { if (p->state != BR_STATE_DISABLED) br_stp_disable_port(p); } break; case NETDEV_FEAT_CHANGE: if (br->dev->flags & IFF_UP) br_features_recompute(br); /* could do recursive feature change notification * but who would care?? */ break; case NETDEV_DOWN: if (br->dev->flags & IFF_UP) br_stp_disable_port(p); break; case NETDEV_UP: if (netif_carrier_ok(dev) && (br->dev->flags & IFF_UP)) br_stp_enable_port(p); break; case NETDEV_UNREGISTER: spin_unlock_bh(&br->lock); br_del_if(br, dev); goto done; } spin_unlock_bh(&br->lock); done: return NOTIFY_DONE; }