--- zzzz-none-000/linux-2.6.32.61/net/bridge/br_sysfs_if.c 2013-06-10 09:43:48.000000000 +0000 +++ ar9-7330-650/linux-2.6.32.61/net/bridge/br_sysfs_if.c 2014-11-18 14:41:37.000000000 +0000 @@ -23,42 +23,54 @@ struct brport_attribute { struct attribute attr; ssize_t (*show)(struct net_bridge_port *, char *); - ssize_t (*store)(struct net_bridge_port *, unsigned long); + int (*store)(struct net_bridge_port *, unsigned long); }; -#define BRPORT_ATTR(_name,_mode,_show,_store) \ -struct brport_attribute brport_attr_##_name = { \ +#define BRPORT_ATTR(_name, _mode, _show, _store) \ +const struct brport_attribute brport_attr_##_name = { \ .attr = {.name = __stringify(_name), \ .mode = _mode }, \ .show = _show, \ .store = _store, \ }; +#define BRPORT_ATTR_FLAG(_name, _mask) \ +static ssize_t show_##_name(struct net_bridge_port *p, char *buf) \ +{ \ + return sprintf(buf, "%d\n", !!(p->flags & _mask)); \ +} \ +static int store_##_name(struct net_bridge_port *p, unsigned long v) \ +{ \ + unsigned long flags = p->flags; \ + if (v) \ + flags |= _mask; \ + else \ + flags &= ~_mask; \ + if (flags != p->flags) { \ + p->flags = flags; \ + br_ifinfo_notify(RTM_NEWLINK, p); \ + } \ + return 0; \ +} \ +static BRPORT_ATTR(_name, S_IRUGO | S_IWUSR, \ + show_##_name, store_##_name) + + static ssize_t show_path_cost(struct net_bridge_port *p, char *buf) { return sprintf(buf, "%d\n", p->path_cost); } -static ssize_t store_path_cost(struct net_bridge_port *p, unsigned long v) -{ - br_stp_set_path_cost(p, v); - return 0; -} + static BRPORT_ATTR(path_cost, S_IRUGO | S_IWUSR, - show_path_cost, store_path_cost); + show_path_cost, br_stp_set_path_cost); static ssize_t show_priority(struct net_bridge_port *p, char *buf) { return sprintf(buf, "%d\n", p->priority); } -static ssize_t store_priority(struct net_bridge_port *p, unsigned long v) -{ - if (v >= (1<<(16-BR_PORT_BITS))) - return -ERANGE; - br_stp_set_port_priority(p, v); - return 0; -} + static BRPORT_ATTR(priority, S_IRUGO | S_IWUSR, - show_priority, store_priority); + show_priority, br_stp_set_port_priority); static ssize_t show_designated_root(struct net_bridge_port *p, char *buf) { @@ -136,30 +148,124 @@ } static BRPORT_ATTR(hold_timer, S_IRUGO, show_hold_timer, NULL); -static ssize_t store_flush(struct net_bridge_port *p, unsigned long v) +static int store_flush(struct net_bridge_port *p, unsigned long v) { br_fdb_delete_by_port(p->br, p, 0); // Don't delete local entry return 0; } static BRPORT_ATTR(flush, S_IWUSR, NULL, store_flush); -static ssize_t show_hairpin_mode(struct net_bridge_port *p, char *buf) +BRPORT_ATTR_FLAG(hairpin_mode, BR_HAIRPIN_MODE); +BRPORT_ATTR_FLAG(bpdu_guard, BR_BPDU_GUARD); +BRPORT_ATTR_FLAG(root_block, BR_ROOT_BLOCK); +BRPORT_ATTR_FLAG(learning, BR_LEARNING); +BRPORT_ATTR_FLAG(unicast_flood, BR_FLOOD); + +#ifdef CONFIG_BRIDGE_IGMP_SNOOPING +static ssize_t show_multicast_router(struct net_bridge_port *p, char *buf) { - int hairpin_mode = (p->flags & BR_HAIRPIN_MODE) ? 1 : 0; - return sprintf(buf, "%d\n", hairpin_mode); + return sprintf(buf, "%d\n", p->multicast_router); } -static ssize_t store_hairpin_mode(struct net_bridge_port *p, unsigned long v) + +static int store_multicast_router(struct net_bridge_port *p, + unsigned long v) { - if (v) - p->flags |= BR_HAIRPIN_MODE; - else - p->flags &= ~BR_HAIRPIN_MODE; + return br_multicast_set_port_router(p, v); +} +static BRPORT_ATTR(multicast_router, S_IRUGO | S_IWUSR, show_multicast_router, + store_multicast_router); + +BRPORT_ATTR_FLAG(multicast_fast_leave, BR_MULTICAST_FAST_LEAVE); + +#ifdef CONFIG_AVM_BRIDGE_MULTICAST_TO_UNICAST + +BRPORT_ATTR_FLAG(avm_multicast_to_unicast, BR_MULTICAST_TO_UNICAST); + +static ssize_t show_multicast_to_unicast_threshold(struct net_bridge_port *p, char *buf) +{ + return sprintf(buf, "%d\n", p->multicast_to_unicast_threshold); +} + +static int store_multicast_to_unicast_threshold(struct net_bridge_port *p, unsigned long v) +{ + p->multicast_to_unicast_threshold = v; return 0; } -static BRPORT_ATTR(hairpin_mode, S_IRUGO | S_IWUSR, - show_hairpin_mode, store_hairpin_mode); +static BRPORT_ATTR(avm_multicast_to_unicast_threshold, S_IRUGO | S_IWUSR, + show_multicast_to_unicast_threshold, + store_multicast_to_unicast_threshold); + +static ssize_t show_recipients(struct net_bridge_port *p, char *buf) +{ + int i; + struct net_bridge *br = p->br; + struct net_bridge_mdb_htable *mdb; + char line[128]; + + if (!netif_running(br->dev) || (p->state == BR_STATE_DISABLED)) + return -EBUSY; + + buf[0] = '\0'; + + spin_lock_irq(&br->multicast_lock); + rcu_read_lock(); + + mdb = rcu_dereference(br->mdb); + if (!mdb) + goto out; + + for (i = 0; i < mdb->max; i++) { + struct net_bridge_mdb_entry *mp; + struct net_bridge_port_group *pg; + struct net_bridge_group_recipient *recp; + struct net_bridge_fdb_entry *fdb; + + hlist_for_each_entry_rcu_v3_15(mp, &mdb->mhash[i], hlist[mdb->ver]) { + + for (pg = mlock_dereference(mp->ports, br); + pg != NULL; + pg = mlock_dereference(pg->next, br)) { + if (pg->port != p) + continue; + + list_for_each_entry_rcu(recp, &pg->recipients, list) { + fdb = rcu_dereference(recp->recipient); + + switch (mp->addr.proto) { + case htons(ETH_P_IP): + snprintf(line, sizeof(line), + "%pI4: %pM\n", &mp->addr.u.ip4, &fdb->addr.addr); + break; +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + case htons(ETH_P_IPV6): + snprintf(line, sizeof(line), + "%pI6: %pM\n", &mp->addr.u.ip6, &fdb->addr.addr); + break; +#endif + default: + /* unreachable */ + continue; + } + if (strlcat(buf, line, PAGE_SIZE) >= PAGE_SIZE) + goto out; + } + } + } + } + +out: + rcu_read_unlock(); + spin_unlock_irq(&br->multicast_lock); + + return strlen(buf); +} + +static BRPORT_ATTR(avm_multicast_recipients, S_IRUGO, show_recipients, NULL); + +#endif +#endif -static struct brport_attribute *brport_attrs[] = { +static const struct brport_attribute *brport_attrs[] = { &brport_attr_path_cost, &brport_attr_priority, &brport_attr_port_id, @@ -176,27 +282,40 @@ &brport_attr_hold_timer, &brport_attr_flush, &brport_attr_hairpin_mode, + &brport_attr_bpdu_guard, + &brport_attr_root_block, + &brport_attr_learning, + &brport_attr_unicast_flood, +#ifdef CONFIG_BRIDGE_IGMP_SNOOPING + &brport_attr_multicast_router, + &brport_attr_multicast_fast_leave, +#ifdef CONFIG_AVM_BRIDGE_MULTICAST_TO_UNICAST + &brport_attr_avm_multicast_to_unicast, + &brport_attr_avm_multicast_to_unicast_threshold, + &brport_attr_avm_multicast_recipients, +#endif +#endif NULL }; #define to_brport_attr(_at) container_of(_at, struct brport_attribute, attr) #define to_brport(obj) container_of(obj, struct net_bridge_port, kobj) -static ssize_t brport_show(struct kobject * kobj, - struct attribute * attr, char * buf) +static ssize_t brport_show(struct kobject *kobj, + struct attribute *attr, char *buf) { - struct brport_attribute * brport_attr = to_brport_attr(attr); - struct net_bridge_port * p = to_brport(kobj); + struct brport_attribute *brport_attr = to_brport_attr(attr); + struct net_bridge_port *p = to_brport(kobj); return brport_attr->show(p, buf); } -static ssize_t brport_store(struct kobject * kobj, - struct attribute * attr, - const char * buf, size_t count) +static ssize_t brport_store(struct kobject *kobj, + struct attribute *attr, + const char *buf, size_t count) { - struct brport_attribute * brport_attr = to_brport_attr(attr); - struct net_bridge_port * p = to_brport(kobj); + struct brport_attribute *brport_attr = to_brport_attr(attr); + struct net_bridge_port *p = to_brport(kobj); ssize_t ret = -EINVAL; char *endp; unsigned long val; @@ -228,26 +347,53 @@ /* * Add sysfs entries to ethernet device added to a bridge. * Creates a brport subdirectory with bridge attributes. - * Puts symlink in bridge's brport subdirectory + * Puts symlink in bridge's brif subdirectory */ int br_sysfs_addif(struct net_bridge_port *p) { struct net_bridge *br = p->br; - struct brport_attribute **a; + const struct brport_attribute **a; int err; err = sysfs_create_link(&p->kobj, &br->dev->dev.kobj, SYSFS_BRIDGE_PORT_LINK); if (err) - goto out2; + return err; for (a = brport_attrs; *a; ++a) { err = sysfs_create_file(&p->kobj, &((*a)->attr)); if (err) - goto out2; + return err; } - err = sysfs_create_link(br->ifobj, &p->kobj, p->dev->name); -out2: + strlcpy(p->sysfs_name, p->dev->name, IFNAMSIZ); + return sysfs_create_link(br->ifobj, &p->kobj, p->sysfs_name); +} + + +#if 0 + /* AVM: revert effect of commit + * e0f43752a942b7be1bc06b9fd74e20ae337c1cca bridge: update sysfs link names if port device names have changed */ +/* Rename bridge's brif symlink */ +int br_sysfs_renameif(struct net_bridge_port *p) +{ + struct net_bridge *br = p->br; + int err; + + /* If a rename fails, the rollback will cause another + * rename call with the existing name. + */ + if (!strncmp(p->sysfs_name, p->dev->name, IFNAMSIZ)) + return 0; + + err = sysfs_rename_link(br->ifobj, &p->kobj, + p->sysfs_name, p->dev->name); + if (err) + netdev_notice(br->dev, "unable to rename link %s to %s", + p->sysfs_name, p->dev->name); + else + strlcpy(p->sysfs_name, p->dev->name, IFNAMSIZ); + return err; } +#endif