diff options
Diffstat (limited to 'net/bridge')
| -rw-r--r-- | net/bridge/br_device.c | 7 | ||||
| -rw-r--r-- | net/bridge/br_fdb.c | 23 | ||||
| -rw-r--r-- | net/bridge/br_if.c | 50 | ||||
| -rw-r--r-- | net/bridge/br_input.c | 34 | ||||
| -rw-r--r-- | net/bridge/br_multicast.c | 27 | ||||
| -rw-r--r-- | net/bridge/br_netlink.c | 1 | ||||
| -rw-r--r-- | net/bridge/br_private.h | 8 | ||||
| -rw-r--r-- | net/bridge/br_stp_if.c | 1 | ||||
| -rw-r--r-- | net/bridge/br_sysfs_br.c | 34 | ||||
| -rw-r--r-- | net/bridge/netfilter/Kconfig | 2 | ||||
| -rw-r--r-- | net/bridge/netfilter/ebt_ulog.c | 7 | ||||
| -rw-r--r-- | net/bridge/netfilter/ebtable_broute.c | 4 |
12 files changed, 140 insertions, 58 deletions
diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c index 32b8f9f7f79e..feb77ea7b58e 100644 --- a/net/bridge/br_device.c +++ b/net/bridge/br_device.c | |||
| @@ -91,7 +91,6 @@ static int br_dev_open(struct net_device *dev) | |||
| 91 | { | 91 | { |
| 92 | struct net_bridge *br = netdev_priv(dev); | 92 | struct net_bridge *br = netdev_priv(dev); |
| 93 | 93 | ||
| 94 | netif_carrier_off(dev); | ||
| 95 | netdev_update_features(dev); | 94 | netdev_update_features(dev); |
| 96 | netif_start_queue(dev); | 95 | netif_start_queue(dev); |
| 97 | br_stp_enable_bridge(br); | 96 | br_stp_enable_bridge(br); |
| @@ -108,8 +107,6 @@ static int br_dev_stop(struct net_device *dev) | |||
| 108 | { | 107 | { |
| 109 | struct net_bridge *br = netdev_priv(dev); | 108 | struct net_bridge *br = netdev_priv(dev); |
| 110 | 109 | ||
| 111 | netif_carrier_off(dev); | ||
| 112 | |||
| 113 | br_stp_disable_bridge(br); | 110 | br_stp_disable_bridge(br); |
| 114 | br_multicast_stop(br); | 111 | br_multicast_stop(br); |
| 115 | 112 | ||
| @@ -304,7 +301,7 @@ static const struct net_device_ops br_netdev_ops = { | |||
| 304 | .ndo_start_xmit = br_dev_xmit, | 301 | .ndo_start_xmit = br_dev_xmit, |
| 305 | .ndo_get_stats64 = br_get_stats64, | 302 | .ndo_get_stats64 = br_get_stats64, |
| 306 | .ndo_set_mac_address = br_set_mac_address, | 303 | .ndo_set_mac_address = br_set_mac_address, |
| 307 | .ndo_set_multicast_list = br_dev_set_multicast_list, | 304 | .ndo_set_rx_mode = br_dev_set_multicast_list, |
| 308 | .ndo_change_mtu = br_change_mtu, | 305 | .ndo_change_mtu = br_change_mtu, |
| 309 | .ndo_do_ioctl = br_dev_ioctl, | 306 | .ndo_do_ioctl = br_dev_ioctl, |
| 310 | #ifdef CONFIG_NET_POLL_CONTROLLER | 307 | #ifdef CONFIG_NET_POLL_CONTROLLER |
| @@ -361,6 +358,8 @@ void br_dev_setup(struct net_device *dev) | |||
| 361 | memcpy(br->group_addr, br_group_address, ETH_ALEN); | 358 | memcpy(br->group_addr, br_group_address, ETH_ALEN); |
| 362 | 359 | ||
| 363 | br->stp_enabled = BR_NO_STP; | 360 | br->stp_enabled = BR_NO_STP; |
| 361 | br->group_fwd_mask = BR_GROUPFWD_DEFAULT; | ||
| 362 | |||
| 364 | br->designated_root = br->bridge_id; | 363 | br->designated_root = br->bridge_id; |
| 365 | br->bridge_max_age = br->max_age = 20 * HZ; | 364 | br->bridge_max_age = br->max_age = 20 * HZ; |
| 366 | br->bridge_hello_time = br->hello_time = 2 * HZ; | 365 | br->bridge_hello_time = br->hello_time = 2 * HZ; |
diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c index 68def3b7fb49..c8e7861b88b0 100644 --- a/net/bridge/br_fdb.c +++ b/net/bridge/br_fdb.c | |||
| @@ -558,19 +558,28 @@ skip: | |||
| 558 | 558 | ||
| 559 | /* Create new static fdb entry */ | 559 | /* Create new static fdb entry */ |
| 560 | static int fdb_add_entry(struct net_bridge_port *source, const __u8 *addr, | 560 | static int fdb_add_entry(struct net_bridge_port *source, const __u8 *addr, |
| 561 | __u16 state) | 561 | __u16 state, __u16 flags) |
| 562 | { | 562 | { |
| 563 | struct net_bridge *br = source->br; | 563 | struct net_bridge *br = source->br; |
| 564 | struct hlist_head *head = &br->hash[br_mac_hash(addr)]; | 564 | struct hlist_head *head = &br->hash[br_mac_hash(addr)]; |
| 565 | struct net_bridge_fdb_entry *fdb; | 565 | struct net_bridge_fdb_entry *fdb; |
| 566 | 566 | ||
| 567 | fdb = fdb_find(head, addr); | 567 | fdb = fdb_find(head, addr); |
| 568 | if (fdb) | 568 | if (fdb == NULL) { |
| 569 | return -EEXIST; | 569 | if (!(flags & NLM_F_CREATE)) |
| 570 | return -ENOENT; | ||
| 570 | 571 | ||
| 571 | fdb = fdb_create(head, source, addr); | 572 | fdb = fdb_create(head, source, addr); |
| 572 | if (!fdb) | 573 | if (!fdb) |
| 573 | return -ENOMEM; | 574 | return -ENOMEM; |
| 575 | } else { | ||
| 576 | if (flags & NLM_F_EXCL) | ||
| 577 | return -EEXIST; | ||
| 578 | |||
| 579 | if (flags & NLM_F_REPLACE) | ||
| 580 | fdb->updated = fdb->used = jiffies; | ||
| 581 | fdb->is_local = fdb->is_static = 0; | ||
| 582 | } | ||
| 574 | 583 | ||
| 575 | if (state & NUD_PERMANENT) | 584 | if (state & NUD_PERMANENT) |
| 576 | fdb->is_local = fdb->is_static = 1; | 585 | fdb->is_local = fdb->is_static = 1; |
| @@ -626,7 +635,7 @@ int br_fdb_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | |||
| 626 | } | 635 | } |
| 627 | 636 | ||
| 628 | spin_lock_bh(&p->br->hash_lock); | 637 | spin_lock_bh(&p->br->hash_lock); |
| 629 | err = fdb_add_entry(p, addr, ndm->ndm_state); | 638 | err = fdb_add_entry(p, addr, ndm->ndm_state, nlh->nlmsg_flags); |
| 630 | spin_unlock_bh(&p->br->hash_lock); | 639 | spin_unlock_bh(&p->br->hash_lock); |
| 631 | 640 | ||
| 632 | return err; | 641 | return err; |
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index e73815456adf..f603e5b0b930 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c | |||
| @@ -13,6 +13,7 @@ | |||
| 13 | 13 | ||
| 14 | #include <linux/kernel.h> | 14 | #include <linux/kernel.h> |
| 15 | #include <linux/netdevice.h> | 15 | #include <linux/netdevice.h> |
| 16 | #include <linux/etherdevice.h> | ||
| 16 | #include <linux/netpoll.h> | 17 | #include <linux/netpoll.h> |
| 17 | #include <linux/ethtool.h> | 18 | #include <linux/ethtool.h> |
| 18 | #include <linux/if_arp.h> | 19 | #include <linux/if_arp.h> |
| @@ -33,20 +34,18 @@ | |||
| 33 | */ | 34 | */ |
| 34 | static int port_cost(struct net_device *dev) | 35 | static int port_cost(struct net_device *dev) |
| 35 | { | 36 | { |
| 36 | if (dev->ethtool_ops && dev->ethtool_ops->get_settings) { | 37 | struct ethtool_cmd ecmd; |
| 37 | struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET, }; | 38 | |
| 38 | 39 | if (!__ethtool_get_settings(dev, &ecmd)) { | |
| 39 | if (!dev_ethtool_get_settings(dev, &ecmd)) { | 40 | switch (ethtool_cmd_speed(&ecmd)) { |
| 40 | switch (ethtool_cmd_speed(&ecmd)) { | 41 | case SPEED_10000: |
| 41 | case SPEED_10000: | 42 | return 2; |
| 42 | return 2; | 43 | case SPEED_1000: |
| 43 | case SPEED_1000: | 44 | return 4; |
| 44 | return 4; | 45 | case SPEED_100: |
| 45 | case SPEED_100: | 46 | return 19; |
| 46 | return 19; | 47 | case SPEED_10: |
| 47 | case SPEED_10: | 48 | return 100; |
| 48 | return 100; | ||
| 49 | } | ||
| 50 | } | 49 | } |
| 51 | } | 50 | } |
| 52 | 51 | ||
| @@ -161,9 +160,10 @@ static void del_nbp(struct net_bridge_port *p) | |||
| 161 | call_rcu(&p->rcu, destroy_nbp_rcu); | 160 | call_rcu(&p->rcu, destroy_nbp_rcu); |
| 162 | } | 161 | } |
| 163 | 162 | ||
| 164 | /* called with RTNL */ | 163 | /* Delete bridge device */ |
| 165 | static void del_br(struct net_bridge *br, struct list_head *head) | 164 | void br_dev_delete(struct net_device *dev, struct list_head *head) |
| 166 | { | 165 | { |
| 166 | struct net_bridge *br = netdev_priv(dev); | ||
| 167 | struct net_bridge_port *p, *n; | 167 | struct net_bridge_port *p, *n; |
| 168 | 168 | ||
| 169 | list_for_each_entry_safe(p, n, &br->port_list, list) { | 169 | list_for_each_entry_safe(p, n, &br->port_list, list) { |
| @@ -268,7 +268,7 @@ int br_del_bridge(struct net *net, const char *name) | |||
| 268 | } | 268 | } |
| 269 | 269 | ||
| 270 | else | 270 | else |
| 271 | del_br(netdev_priv(dev), NULL); | 271 | br_dev_delete(dev, NULL); |
| 272 | 272 | ||
| 273 | rtnl_unlock(); | 273 | rtnl_unlock(); |
| 274 | return ret; | 274 | return ret; |
| @@ -324,7 +324,8 @@ int br_add_if(struct net_bridge *br, struct net_device *dev) | |||
| 324 | 324 | ||
| 325 | /* Don't allow bridging non-ethernet like devices */ | 325 | /* Don't allow bridging non-ethernet like devices */ |
| 326 | if ((dev->flags & IFF_LOOPBACK) || | 326 | if ((dev->flags & IFF_LOOPBACK) || |
| 327 | dev->type != ARPHRD_ETHER || dev->addr_len != ETH_ALEN) | 327 | dev->type != ARPHRD_ETHER || dev->addr_len != ETH_ALEN || |
| 328 | !is_valid_ether_addr(dev->dev_addr)) | ||
| 328 | return -EINVAL; | 329 | return -EINVAL; |
| 329 | 330 | ||
| 330 | /* No bridging of bridges */ | 331 | /* No bridging of bridges */ |
| @@ -352,10 +353,6 @@ int br_add_if(struct net_bridge *br, struct net_device *dev) | |||
| 352 | err = kobject_init_and_add(&p->kobj, &brport_ktype, &(dev->dev.kobj), | 353 | err = kobject_init_and_add(&p->kobj, &brport_ktype, &(dev->dev.kobj), |
| 353 | SYSFS_BRIDGE_PORT_ATTR); | 354 | SYSFS_BRIDGE_PORT_ATTR); |
| 354 | if (err) | 355 | if (err) |
| 355 | goto err0; | ||
| 356 | |||
| 357 | err = br_fdb_insert(br, p, dev->dev_addr); | ||
| 358 | if (err) | ||
| 359 | goto err1; | 356 | goto err1; |
| 360 | 357 | ||
| 361 | err = br_sysfs_addif(p); | 358 | err = br_sysfs_addif(p); |
| @@ -396,6 +393,9 @@ int br_add_if(struct net_bridge *br, struct net_device *dev) | |||
| 396 | 393 | ||
| 397 | dev_set_mtu(br->dev, br_min_mtu(br)); | 394 | dev_set_mtu(br->dev, br_min_mtu(br)); |
| 398 | 395 | ||
| 396 | if (br_fdb_insert(br, p, dev->dev_addr)) | ||
| 397 | netdev_err(dev, "failed insert local address bridge forwarding table\n"); | ||
| 398 | |||
| 399 | kobject_uevent(&p->kobj, KOBJ_ADD); | 399 | kobject_uevent(&p->kobj, KOBJ_ADD); |
| 400 | 400 | ||
| 401 | return 0; | 401 | return 0; |
| @@ -405,11 +405,9 @@ err4: | |||
| 405 | err3: | 405 | err3: |
| 406 | sysfs_remove_link(br->ifobj, p->dev->name); | 406 | sysfs_remove_link(br->ifobj, p->dev->name); |
| 407 | err2: | 407 | err2: |
| 408 | br_fdb_delete_by_port(br, p, 1); | ||
| 409 | err1: | ||
| 410 | kobject_put(&p->kobj); | 408 | kobject_put(&p->kobj); |
| 411 | p = NULL; /* kobject_put frees */ | 409 | p = NULL; /* kobject_put frees */ |
| 412 | err0: | 410 | err1: |
| 413 | dev_set_promiscuity(dev, -1); | 411 | dev_set_promiscuity(dev, -1); |
| 414 | put_back: | 412 | put_back: |
| 415 | dev_put(dev); | 413 | dev_put(dev); |
| @@ -449,7 +447,7 @@ void __net_exit br_net_exit(struct net *net) | |||
| 449 | rtnl_lock(); | 447 | rtnl_lock(); |
| 450 | for_each_netdev(net, dev) | 448 | for_each_netdev(net, dev) |
| 451 | if (dev->priv_flags & IFF_EBRIDGE) | 449 | if (dev->priv_flags & IFF_EBRIDGE) |
| 452 | del_br(netdev_priv(dev), &list); | 450 | br_dev_delete(dev, &list); |
| 453 | 451 | ||
| 454 | unregister_netdevice_many(&list); | 452 | unregister_netdevice_many(&list); |
| 455 | rtnl_unlock(); | 453 | rtnl_unlock(); |
diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c index f06ee39c73fd..5a31731be4d0 100644 --- a/net/bridge/br_input.c +++ b/net/bridge/br_input.c | |||
| @@ -16,6 +16,7 @@ | |||
| 16 | #include <linux/netdevice.h> | 16 | #include <linux/netdevice.h> |
| 17 | #include <linux/etherdevice.h> | 17 | #include <linux/etherdevice.h> |
| 18 | #include <linux/netfilter_bridge.h> | 18 | #include <linux/netfilter_bridge.h> |
| 19 | #include <linux/export.h> | ||
| 19 | #include "br_private.h" | 20 | #include "br_private.h" |
| 20 | 21 | ||
| 21 | /* Bridge group multicast address 802.1d (pg 51). */ | 22 | /* Bridge group multicast address 802.1d (pg 51). */ |
| @@ -162,14 +163,37 @@ rx_handler_result_t br_handle_frame(struct sk_buff **pskb) | |||
| 162 | p = br_port_get_rcu(skb->dev); | 163 | p = br_port_get_rcu(skb->dev); |
| 163 | 164 | ||
| 164 | if (unlikely(is_link_local(dest))) { | 165 | if (unlikely(is_link_local(dest))) { |
| 165 | /* Pause frames shouldn't be passed up by driver anyway */ | 166 | /* |
| 166 | if (skb->protocol == htons(ETH_P_PAUSE)) | 167 | * See IEEE 802.1D Table 7-10 Reserved addresses |
| 168 | * | ||
| 169 | * Assignment Value | ||
| 170 | * Bridge Group Address 01-80-C2-00-00-00 | ||
| 171 | * (MAC Control) 802.3 01-80-C2-00-00-01 | ||
| 172 | * (Link Aggregation) 802.3 01-80-C2-00-00-02 | ||
| 173 | * 802.1X PAE address 01-80-C2-00-00-03 | ||
| 174 | * | ||
| 175 | * 802.1AB LLDP 01-80-C2-00-00-0E | ||
| 176 | * | ||
| 177 | * Others reserved for future standardization | ||
| 178 | */ | ||
| 179 | switch (dest[5]) { | ||
| 180 | case 0x00: /* Bridge Group Address */ | ||
| 181 | /* If STP is turned off, | ||
| 182 | then must forward to keep loop detection */ | ||
| 183 | if (p->br->stp_enabled == BR_NO_STP) | ||
| 184 | goto forward; | ||
| 185 | break; | ||
| 186 | |||
| 187 | case 0x01: /* IEEE MAC (Pause) */ | ||
| 167 | goto drop; | 188 | goto drop; |
| 168 | 189 | ||
| 169 | /* If STP is turned off, then forward */ | 190 | default: |
| 170 | if (p->br->stp_enabled == BR_NO_STP && dest[5] == 0) | 191 | /* Allow selective forwarding for most other protocols */ |
| 171 | goto forward; | 192 | if (p->br->group_fwd_mask & (1u << dest[5])) |
| 193 | goto forward; | ||
| 194 | } | ||
| 172 | 195 | ||
| 196 | /* Deliver packet to local host only */ | ||
| 173 | if (NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_IN, skb, skb->dev, | 197 | if (NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_IN, skb, skb->dev, |
| 174 | NULL, br_handle_local_finish)) { | 198 | NULL, br_handle_local_finish)) { |
| 175 | return RX_HANDLER_CONSUMED; /* consumed by filter */ | 199 | return RX_HANDLER_CONSUMED; /* consumed by filter */ |
diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c index 2d85ca7111d3..a5f4e5769809 100644 --- a/net/bridge/br_multicast.c +++ b/net/bridge/br_multicast.c | |||
| @@ -1456,7 +1456,7 @@ static int br_multicast_ipv6_rcv(struct net_bridge *br, | |||
| 1456 | { | 1456 | { |
| 1457 | struct sk_buff *skb2; | 1457 | struct sk_buff *skb2; |
| 1458 | const struct ipv6hdr *ip6h; | 1458 | const struct ipv6hdr *ip6h; |
| 1459 | struct icmp6hdr *icmp6h; | 1459 | u8 icmp6_type; |
| 1460 | u8 nexthdr; | 1460 | u8 nexthdr; |
| 1461 | unsigned len; | 1461 | unsigned len; |
| 1462 | int offset; | 1462 | int offset; |
| @@ -1501,10 +1501,12 @@ static int br_multicast_ipv6_rcv(struct net_bridge *br, | |||
| 1501 | 1501 | ||
| 1502 | __skb_pull(skb2, offset); | 1502 | __skb_pull(skb2, offset); |
| 1503 | skb_reset_transport_header(skb2); | 1503 | skb_reset_transport_header(skb2); |
| 1504 | skb_postpull_rcsum(skb2, skb_network_header(skb2), | ||
| 1505 | skb_network_header_len(skb2)); | ||
| 1504 | 1506 | ||
| 1505 | icmp6h = icmp6_hdr(skb2); | 1507 | icmp6_type = icmp6_hdr(skb2)->icmp6_type; |
| 1506 | 1508 | ||
| 1507 | switch (icmp6h->icmp6_type) { | 1509 | switch (icmp6_type) { |
| 1508 | case ICMPV6_MGM_QUERY: | 1510 | case ICMPV6_MGM_QUERY: |
| 1509 | case ICMPV6_MGM_REPORT: | 1511 | case ICMPV6_MGM_REPORT: |
| 1510 | case ICMPV6_MGM_REDUCTION: | 1512 | case ICMPV6_MGM_REDUCTION: |
| @@ -1520,16 +1522,23 @@ static int br_multicast_ipv6_rcv(struct net_bridge *br, | |||
| 1520 | err = pskb_trim_rcsum(skb2, len); | 1522 | err = pskb_trim_rcsum(skb2, len); |
| 1521 | if (err) | 1523 | if (err) |
| 1522 | goto out; | 1524 | goto out; |
| 1525 | err = -EINVAL; | ||
| 1523 | } | 1526 | } |
| 1524 | 1527 | ||
| 1528 | ip6h = ipv6_hdr(skb2); | ||
| 1529 | |||
| 1525 | switch (skb2->ip_summed) { | 1530 | switch (skb2->ip_summed) { |
| 1526 | case CHECKSUM_COMPLETE: | 1531 | case CHECKSUM_COMPLETE: |
| 1527 | if (!csum_fold(skb2->csum)) | 1532 | if (!csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr, skb2->len, |
| 1533 | IPPROTO_ICMPV6, skb2->csum)) | ||
| 1528 | break; | 1534 | break; |
| 1529 | /*FALLTHROUGH*/ | 1535 | /*FALLTHROUGH*/ |
| 1530 | case CHECKSUM_NONE: | 1536 | case CHECKSUM_NONE: |
| 1531 | skb2->csum = 0; | 1537 | skb2->csum = ~csum_unfold(csum_ipv6_magic(&ip6h->saddr, |
| 1532 | if (skb_checksum_complete(skb2)) | 1538 | &ip6h->daddr, |
| 1539 | skb2->len, | ||
| 1540 | IPPROTO_ICMPV6, 0)); | ||
| 1541 | if (__skb_checksum_complete(skb2)) | ||
| 1533 | goto out; | 1542 | goto out; |
| 1534 | } | 1543 | } |
| 1535 | 1544 | ||
| @@ -1537,7 +1546,7 @@ static int br_multicast_ipv6_rcv(struct net_bridge *br, | |||
| 1537 | 1546 | ||
| 1538 | BR_INPUT_SKB_CB(skb)->igmp = 1; | 1547 | BR_INPUT_SKB_CB(skb)->igmp = 1; |
| 1539 | 1548 | ||
| 1540 | switch (icmp6h->icmp6_type) { | 1549 | switch (icmp6_type) { |
| 1541 | case ICMPV6_MGM_REPORT: | 1550 | case ICMPV6_MGM_REPORT: |
| 1542 | { | 1551 | { |
| 1543 | struct mld_msg *mld; | 1552 | struct mld_msg *mld; |
| @@ -1763,7 +1772,7 @@ int br_multicast_toggle(struct net_bridge *br, unsigned long val) | |||
| 1763 | int err = 0; | 1772 | int err = 0; |
| 1764 | struct net_bridge_mdb_htable *mdb; | 1773 | struct net_bridge_mdb_htable *mdb; |
| 1765 | 1774 | ||
| 1766 | spin_lock(&br->multicast_lock); | 1775 | spin_lock_bh(&br->multicast_lock); |
| 1767 | if (br->multicast_disabled == !val) | 1776 | if (br->multicast_disabled == !val) |
| 1768 | goto unlock; | 1777 | goto unlock; |
| 1769 | 1778 | ||
| @@ -1799,7 +1808,7 @@ rollback: | |||
| 1799 | } | 1808 | } |
| 1800 | 1809 | ||
| 1801 | unlock: | 1810 | unlock: |
| 1802 | spin_unlock(&br->multicast_lock); | 1811 | spin_unlock_bh(&br->multicast_lock); |
| 1803 | 1812 | ||
| 1804 | return err; | 1813 | return err; |
| 1805 | } | 1814 | } |
diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c index 5b1ed1ba9aa7..e5f9ece3c9a0 100644 --- a/net/bridge/br_netlink.c +++ b/net/bridge/br_netlink.c | |||
| @@ -210,6 +210,7 @@ static struct rtnl_link_ops br_link_ops __read_mostly = { | |||
| 210 | .priv_size = sizeof(struct net_bridge), | 210 | .priv_size = sizeof(struct net_bridge), |
| 211 | .setup = br_dev_setup, | 211 | .setup = br_dev_setup, |
| 212 | .validate = br_validate, | 212 | .validate = br_validate, |
| 213 | .dellink = br_dev_delete, | ||
| 213 | }; | 214 | }; |
| 214 | 215 | ||
| 215 | int __init br_netlink_init(void) | 216 | int __init br_netlink_init(void) |
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index 78cc364997d9..d7d6fb05411f 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h | |||
| @@ -29,6 +29,11 @@ | |||
| 29 | 29 | ||
| 30 | #define BR_VERSION "2.3" | 30 | #define BR_VERSION "2.3" |
| 31 | 31 | ||
| 32 | /* Control of forwarding link local multicast */ | ||
| 33 | #define BR_GROUPFWD_DEFAULT 0 | ||
| 34 | /* Don't allow forwarding control protocols like STP and LLDP */ | ||
| 35 | #define BR_GROUPFWD_RESTRICTED 0x4007u | ||
| 36 | |||
| 32 | /* Path to usermode spanning tree program */ | 37 | /* Path to usermode spanning tree program */ |
| 33 | #define BR_STP_PROG "/sbin/bridge-stp" | 38 | #define BR_STP_PROG "/sbin/bridge-stp" |
| 34 | 39 | ||
| @@ -193,6 +198,8 @@ struct net_bridge | |||
| 193 | unsigned long flags; | 198 | unsigned long flags; |
| 194 | #define BR_SET_MAC_ADDR 0x00000001 | 199 | #define BR_SET_MAC_ADDR 0x00000001 |
| 195 | 200 | ||
| 201 | u16 group_fwd_mask; | ||
| 202 | |||
| 196 | /* STP */ | 203 | /* STP */ |
| 197 | bridge_id designated_root; | 204 | bridge_id designated_root; |
| 198 | bridge_id bridge_id; | 205 | bridge_id bridge_id; |
| @@ -294,6 +301,7 @@ static inline int br_is_root_bridge(const struct net_bridge *br) | |||
| 294 | 301 | ||
| 295 | /* br_device.c */ | 302 | /* br_device.c */ |
| 296 | extern void br_dev_setup(struct net_device *dev); | 303 | extern void br_dev_setup(struct net_device *dev); |
| 304 | extern void br_dev_delete(struct net_device *dev, struct list_head *list); | ||
| 297 | extern netdev_tx_t br_dev_xmit(struct sk_buff *skb, | 305 | extern netdev_tx_t br_dev_xmit(struct sk_buff *skb, |
| 298 | struct net_device *dev); | 306 | struct net_device *dev); |
| 299 | #ifdef CONFIG_NET_POLL_CONTROLLER | 307 | #ifdef CONFIG_NET_POLL_CONTROLLER |
diff --git a/net/bridge/br_stp_if.c b/net/bridge/br_stp_if.c index 10eda3cd1d71..19308e305d85 100644 --- a/net/bridge/br_stp_if.c +++ b/net/bridge/br_stp_if.c | |||
| @@ -12,6 +12,7 @@ | |||
| 12 | */ | 12 | */ |
| 13 | 13 | ||
| 14 | #include <linux/kernel.h> | 14 | #include <linux/kernel.h> |
| 15 | #include <linux/kmod.h> | ||
| 15 | #include <linux/etherdevice.h> | 16 | #include <linux/etherdevice.h> |
| 16 | #include <linux/rtnetlink.h> | 17 | #include <linux/rtnetlink.h> |
| 17 | 18 | ||
diff --git a/net/bridge/br_sysfs_br.c b/net/bridge/br_sysfs_br.c index 68b893ea8c3a..c236c0e43984 100644 --- a/net/bridge/br_sysfs_br.c +++ b/net/bridge/br_sysfs_br.c | |||
| @@ -149,6 +149,39 @@ static ssize_t store_stp_state(struct device *d, | |||
| 149 | static DEVICE_ATTR(stp_state, S_IRUGO | S_IWUSR, show_stp_state, | 149 | static DEVICE_ATTR(stp_state, S_IRUGO | S_IWUSR, show_stp_state, |
| 150 | store_stp_state); | 150 | store_stp_state); |
| 151 | 151 | ||
| 152 | static ssize_t show_group_fwd_mask(struct device *d, | ||
| 153 | struct device_attribute *attr, char *buf) | ||
| 154 | { | ||
| 155 | struct net_bridge *br = to_bridge(d); | ||
| 156 | return sprintf(buf, "%#x\n", br->group_fwd_mask); | ||
| 157 | } | ||
| 158 | |||
| 159 | |||
| 160 | static ssize_t store_group_fwd_mask(struct device *d, | ||
| 161 | struct device_attribute *attr, const char *buf, | ||
| 162 | size_t len) | ||
| 163 | { | ||
| 164 | struct net_bridge *br = to_bridge(d); | ||
| 165 | char *endp; | ||
| 166 | unsigned long val; | ||
| 167 | |||
| 168 | if (!capable(CAP_NET_ADMIN)) | ||
| 169 | return -EPERM; | ||
| 170 | |||
| 171 | val = simple_strtoul(buf, &endp, 0); | ||
| 172 | if (endp == buf) | ||
| 173 | return -EINVAL; | ||
| 174 | |||
| 175 | if (val & BR_GROUPFWD_RESTRICTED) | ||
| 176 | return -EINVAL; | ||
| 177 | |||
| 178 | br->group_fwd_mask = val; | ||
| 179 | |||
| 180 | return len; | ||
| 181 | } | ||
| 182 | static DEVICE_ATTR(group_fwd_mask, S_IRUGO | S_IWUSR, show_group_fwd_mask, | ||
| 183 | store_group_fwd_mask); | ||
| 184 | |||
| 152 | static ssize_t show_priority(struct device *d, struct device_attribute *attr, | 185 | static ssize_t show_priority(struct device *d, struct device_attribute *attr, |
| 153 | char *buf) | 186 | char *buf) |
| 154 | { | 187 | { |
| @@ -652,6 +685,7 @@ static struct attribute *bridge_attrs[] = { | |||
| 652 | &dev_attr_max_age.attr, | 685 | &dev_attr_max_age.attr, |
| 653 | &dev_attr_ageing_time.attr, | 686 | &dev_attr_ageing_time.attr, |
| 654 | &dev_attr_stp_state.attr, | 687 | &dev_attr_stp_state.attr, |
| 688 | &dev_attr_group_fwd_mask.attr, | ||
| 655 | &dev_attr_priority.attr, | 689 | &dev_attr_priority.attr, |
| 656 | &dev_attr_bridge_id.attr, | 690 | &dev_attr_bridge_id.attr, |
| 657 | &dev_attr_root_id.attr, | 691 | &dev_attr_root_id.attr, |
diff --git a/net/bridge/netfilter/Kconfig b/net/bridge/netfilter/Kconfig index ba6f73eb06c6..a9aff9c7d027 100644 --- a/net/bridge/netfilter/Kconfig +++ b/net/bridge/netfilter/Kconfig | |||
| @@ -4,7 +4,7 @@ | |||
| 4 | 4 | ||
| 5 | menuconfig BRIDGE_NF_EBTABLES | 5 | menuconfig BRIDGE_NF_EBTABLES |
| 6 | tristate "Ethernet Bridge tables (ebtables) support" | 6 | tristate "Ethernet Bridge tables (ebtables) support" |
| 7 | depends on BRIDGE && BRIDGE_NETFILTER | 7 | depends on BRIDGE && NETFILTER |
| 8 | select NETFILTER_XTABLES | 8 | select NETFILTER_XTABLES |
| 9 | help | 9 | help |
| 10 | ebtables is a general, extensible frame/packet identification | 10 | ebtables is a general, extensible frame/packet identification |
diff --git a/net/bridge/netfilter/ebt_ulog.c b/net/bridge/netfilter/ebt_ulog.c index bf2a333ca7c7..5449294bdd5e 100644 --- a/net/bridge/netfilter/ebt_ulog.c +++ b/net/bridge/netfilter/ebt_ulog.c | |||
| @@ -102,16 +102,15 @@ static struct sk_buff *ulog_alloc_skb(unsigned int size) | |||
| 102 | unsigned int n; | 102 | unsigned int n; |
| 103 | 103 | ||
| 104 | n = max(size, nlbufsiz); | 104 | n = max(size, nlbufsiz); |
| 105 | skb = alloc_skb(n, GFP_ATOMIC); | 105 | skb = alloc_skb(n, GFP_ATOMIC | __GFP_NOWARN); |
| 106 | if (!skb) { | 106 | if (!skb) { |
| 107 | pr_debug("cannot alloc whole buffer of size %ub!\n", n); | ||
| 108 | if (n > size) { | 107 | if (n > size) { |
| 109 | /* try to allocate only as much as we need for | 108 | /* try to allocate only as much as we need for |
| 110 | * current packet */ | 109 | * current packet */ |
| 111 | skb = alloc_skb(size, GFP_ATOMIC); | 110 | skb = alloc_skb(size, GFP_ATOMIC); |
| 112 | if (!skb) | 111 | if (!skb) |
| 113 | pr_debug("cannot even allocate " | 112 | pr_debug("cannot even allocate buffer of size %ub\n", |
| 114 | "buffer of size %ub\n", size); | 113 | size); |
| 115 | } | 114 | } |
| 116 | } | 115 | } |
| 117 | 116 | ||
diff --git a/net/bridge/netfilter/ebtable_broute.c b/net/bridge/netfilter/ebtable_broute.c index 1bcaf36ad612..40d8258bf74f 100644 --- a/net/bridge/netfilter/ebtable_broute.c +++ b/net/bridge/netfilter/ebtable_broute.c | |||
| @@ -87,14 +87,14 @@ static int __init ebtable_broute_init(void) | |||
| 87 | if (ret < 0) | 87 | if (ret < 0) |
| 88 | return ret; | 88 | return ret; |
| 89 | /* see br_input.c */ | 89 | /* see br_input.c */ |
| 90 | rcu_assign_pointer(br_should_route_hook, | 90 | RCU_INIT_POINTER(br_should_route_hook, |
| 91 | (br_should_route_hook_t *)ebt_broute); | 91 | (br_should_route_hook_t *)ebt_broute); |
| 92 | return 0; | 92 | return 0; |
| 93 | } | 93 | } |
| 94 | 94 | ||
| 95 | static void __exit ebtable_broute_fini(void) | 95 | static void __exit ebtable_broute_fini(void) |
| 96 | { | 96 | { |
| 97 | rcu_assign_pointer(br_should_route_hook, NULL); | 97 | RCU_INIT_POINTER(br_should_route_hook, NULL); |
| 98 | synchronize_net(); | 98 | synchronize_net(); |
| 99 | unregister_pernet_subsys(&broute_net_ops); | 99 | unregister_pernet_subsys(&broute_net_ops); |
| 100 | } | 100 | } |
