X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=net%2Fbridge%2Fbr_if.c;h=690573bbf012fa935747d998613f1883221567f5;hb=87a596e0b8bc344bd6bfebe83b56d11fb79ee23a;hp=738cb3afa99a859477fac6c11e443e4ad0f3f220;hpb=3b781fa10bcdb148924d1847f68899583e0d66ef;p=safe%2Fjmp%2Flinux-2.6 diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index 738cb3a..690573b 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c @@ -47,7 +47,7 @@ static int port_cost(struct net_device *dev) set_fs(KERNEL_DS); err = dev_ethtool(&ifr); set_fs(old_fs); - + if (!err) { switch(ecmd.speed) { case SPEED_100: @@ -77,22 +77,15 @@ static int port_cost(struct net_device *dev) * Called from work queue to allow for calling functions that * might sleep (such as speed check), and to debounce. */ -static void port_carrier_check(void *arg) +void br_port_carrier_check(struct net_bridge_port *p) { - struct net_device *dev = arg; - struct net_bridge_port *p; - struct net_bridge *br; - - rtnl_lock(); - p = dev->br_port; - if (!p) - goto done; - br = p->br; + struct net_device *dev = p->dev; + struct net_bridge *br = p->br; if (netif_carrier_ok(dev)) p->path_cost = port_cost(dev); - if (br->dev->flags & IFF_UP) { + if (netif_running(br->dev)) { spin_lock_bh(&br->lock); if (netif_carrier_ok(dev)) { if (p->state == BR_STATE_DISABLED) @@ -103,8 +96,6 @@ static void port_carrier_check(void *arg) } spin_unlock_bh(&br->lock); } -done: - rtnl_unlock(); } static void release_nbp(struct kobject *kobj) @@ -157,13 +148,13 @@ static void del_nbp(struct net_bridge_port *p) dev_set_promiscuity(dev, -1); - cancel_delayed_work(&p->carrier_check); - spin_lock_bh(&br->lock); br_stp_disable_port(p); spin_unlock_bh(&br->lock); - br_fdb_delete_by_port(br, p); + br_ifinfo_notify(RTM_DELLINK, p); + + br_fdb_delete_by_port(br, p, 1); list_del_rcu(&p->list); @@ -187,7 +178,7 @@ static void del_br(struct net_bridge *br) del_timer_sync(&br->gc_timer); br_sysfs_delbr(br->dev); - unregister_netdevice(br->dev); + unregister_netdevice(br->dev); } static struct net_device *new_bridge_dev(const char *name) @@ -197,7 +188,7 @@ static struct net_device *new_bridge_dev(const char *name) dev = alloc_netdev(sizeof(struct net_bridge), name, br_dev_setup); - + if (!dev) return NULL; @@ -210,10 +201,11 @@ static struct net_device *new_bridge_dev(const char *name) br->bridge_id.prio[0] = 0x80; br->bridge_id.prio[1] = 0x00; - memset(br->bridge_id.addr, 0, ETH_ALEN); + + memcpy(br->group_addr, br_group_address, ETH_ALEN); br->feature_mask = dev->features; - br->stp_enabled = 0; + br->stp_enabled = BR_NO_STP; br->designated_root = br->bridge_id; br->root_path_cost = 0; br->root_port = 0; @@ -253,36 +245,34 @@ static int find_portno(struct net_bridge *br) } /* called with RTNL but without bridge lock */ -static struct net_bridge_port *new_nbp(struct net_bridge *br, +static struct net_bridge_port *new_nbp(struct net_bridge *br, struct net_device *dev) { int index; struct net_bridge_port *p; - + index = find_portno(br); if (index < 0) return ERR_PTR(index); - p = kmalloc(sizeof(*p), GFP_KERNEL); + p = kzalloc(sizeof(*p), GFP_KERNEL); if (p == NULL) return ERR_PTR(-ENOMEM); - memset(p, 0, sizeof(*p)); p->br = br; dev_hold(dev); p->dev = dev; p->path_cost = port_cost(dev); - p->priority = 0x8000 >> BR_PORT_BITS; + p->priority = 0x8000 >> BR_PORT_BITS; p->port_no = index; br_init_port(p); p->state = BR_STATE_DISABLED; - INIT_WORK(&p->carrier_check, port_carrier_check, dev); br_stp_port_timer_init(p); kobject_init(&p->kobj); kobject_set_name(&p->kobj, SYSFS_BRIDGE_PORT_ATTR); p->kobj.ktype = &brport_ktype; - p->kobj.parent = &(dev->class_dev.kobj); + p->kobj.parent = &(dev->dev.kobj); p->kobj.kset = NULL; return p; @@ -294,40 +284,28 @@ int br_add_bridge(const char *name) int ret; dev = new_bridge_dev(name); - if (!dev) + if (!dev) return -ENOMEM; rtnl_lock(); if (strchr(dev->name, '%')) { ret = dev_alloc_name(dev, dev->name); - if (ret < 0) - goto err1; + if (ret < 0) { + free_netdev(dev); + goto out; + } } ret = register_netdevice(dev); if (ret) - goto err2; - - /* network device kobject is not setup until - * after rtnl_unlock does it's hotplug magic. - * so hold reference to avoid race. - */ - dev_hold(dev); - rtnl_unlock(); + goto out; ret = br_sysfs_addbr(dev); - dev_put(dev); - - if (ret) - unregister_netdev(dev); + if (ret) + unregister_netdevice(dev); out: - return ret; - - err2: - free_netdev(dev); - err1: rtnl_unlock(); - goto out; + return ret; } int br_del_bridge(const char *name) @@ -337,7 +315,7 @@ int br_del_bridge(const char *name) rtnl_lock(); dev = __dev_get_by_name(name); - if (dev == NULL) + if (dev == NULL) ret = -ENXIO; /* Could not find device */ else if (!(dev->priv_flags & IFF_EBRIDGE)) { @@ -348,9 +326,9 @@ int br_del_bridge(const char *name) else if (dev->flags & IFF_UP) { /* Not shutdown yet. */ ret = -EBUSY; - } + } - else + else del_br(netdev_priv(dev)); rtnl_unlock(); @@ -384,17 +362,33 @@ void br_features_recompute(struct net_bridge *br) struct net_bridge_port *p; unsigned long features, checksum; - features = br->feature_mask &~ NETIF_F_IP_CSUM; - checksum = br->feature_mask & NETIF_F_IP_CSUM; + checksum = br->feature_mask & NETIF_F_ALL_CSUM ? NETIF_F_NO_CSUM : 0; + features = br->feature_mask & ~NETIF_F_ALL_CSUM; list_for_each_entry(p, &br->port_list, list) { - if (!(p->dev->features - & (NETIF_F_IP_CSUM|NETIF_F_NO_CSUM|NETIF_F_HW_CSUM))) + unsigned long feature = p->dev->features; + + if (checksum & NETIF_F_NO_CSUM && !(feature & NETIF_F_NO_CSUM)) + checksum ^= NETIF_F_NO_CSUM | NETIF_F_HW_CSUM; + if (checksum & NETIF_F_HW_CSUM && !(feature & NETIF_F_HW_CSUM)) + checksum ^= NETIF_F_HW_CSUM | NETIF_F_IP_CSUM; + if (!(feature & NETIF_F_IP_CSUM)) checksum = 0; - features &= p->dev->features; + + if (feature & NETIF_F_GSO) + feature |= NETIF_F_GSO_SOFTWARE; + feature |= NETIF_F_GSO; + + features &= feature; } - br->dev->features = features | checksum | NETIF_F_LLTX; + if (!(checksum & NETIF_F_ALL_CSUM)) + features &= ~NETIF_F_SG; + if (!(features & NETIF_F_SG)) + features &= ~NETIF_F_GSO_MASK; + + br->dev->features = features | checksum | NETIF_F_LLTX | + NETIF_F_GSO_ROBUST; } /* called with RTNL */ @@ -420,7 +414,7 @@ int br_add_if(struct net_bridge *br, struct net_device *dev) if (err) goto err0; - err = br_fdb_insert(br, p, dev->dev_addr); + err = br_fdb_insert(br, p, dev->dev_addr); if (err) goto err1; @@ -436,15 +430,21 @@ int br_add_if(struct net_bridge *br, struct net_device *dev) spin_lock_bh(&br->lock); br_stp_recalculate_bridge_id(br); br_features_recompute(br); - schedule_delayed_work(&p->carrier_check, BR_PORT_DEBOUNCE); + + if ((dev->flags & IFF_UP) && netif_carrier_ok(dev) && + (br->dev->flags & IFF_UP)) + br_stp_enable_port(p); spin_unlock_bh(&br->lock); + br_ifinfo_notify(RTM_NEWLINK, p); + dev_set_mtu(br->dev, br_min_mtu(br)); + kobject_uevent(&p->kobj, KOBJ_ADD); return 0; err2: - br_fdb_delete_by_port(br, p); + br_fdb_delete_by_port(br, p, 1); err1: kobject_del(&p->kobj); err0: @@ -456,8 +456,8 @@ err0: int br_del_if(struct net_bridge *br, struct net_device *dev) { struct net_bridge_port *p = dev->br_port; - - if (!p || p->br != br) + + if (!p || p->br != br) return -EINVAL; del_nbp(p);