diff options
| -rw-r--r-- | net/bridge/br_device.c | 15 | ||||
| -rw-r--r-- | net/bridge/br_input.c | 18 |
2 files changed, 29 insertions, 4 deletions
diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c index 91dffe7574d6..eb7062d2e9e5 100644 --- a/net/bridge/br_device.c +++ b/net/bridge/br_device.c | |||
| @@ -25,6 +25,7 @@ netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev) | |||
| 25 | struct net_bridge *br = netdev_priv(dev); | 25 | struct net_bridge *br = netdev_priv(dev); |
| 26 | const unsigned char *dest = skb->data; | 26 | const unsigned char *dest = skb->data; |
| 27 | struct net_bridge_fdb_entry *dst; | 27 | struct net_bridge_fdb_entry *dst; |
| 28 | struct net_bridge_mdb_entry *mdst; | ||
| 28 | 29 | ||
| 29 | BR_INPUT_SKB_CB(skb)->brdev = dev; | 30 | BR_INPUT_SKB_CB(skb)->brdev = dev; |
| 30 | 31 | ||
| @@ -34,13 +35,21 @@ netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev) | |||
| 34 | skb_reset_mac_header(skb); | 35 | skb_reset_mac_header(skb); |
| 35 | skb_pull(skb, ETH_HLEN); | 36 | skb_pull(skb, ETH_HLEN); |
| 36 | 37 | ||
| 37 | if (dest[0] & 1) | 38 | if (dest[0] & 1) { |
| 38 | br_flood_deliver(br, skb); | 39 | if (br_multicast_rcv(br, NULL, skb)) |
| 39 | else if ((dst = __br_fdb_get(br, dest)) != NULL) | 40 | goto out; |
| 41 | |||
| 42 | mdst = br_mdb_get(br, skb); | ||
| 43 | if (mdst || BR_INPUT_SKB_CB(skb)->mrouters_only) | ||
| 44 | br_multicast_deliver(mdst, skb); | ||
| 45 | else | ||
| 46 | br_flood_deliver(br, skb); | ||
| 47 | } else if ((dst = __br_fdb_get(br, dest)) != NULL) | ||
| 40 | br_deliver(dst->dst, skb); | 48 | br_deliver(dst->dst, skb); |
| 41 | else | 49 | else |
| 42 | br_flood_deliver(br, skb); | 50 | br_flood_deliver(br, skb); |
| 43 | 51 | ||
| 52 | out: | ||
| 44 | return NETDEV_TX_OK; | 53 | return NETDEV_TX_OK; |
| 45 | } | 54 | } |
| 46 | 55 | ||
diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c index edfdaef44296..53b39851d87d 100644 --- a/net/bridge/br_input.c +++ b/net/bridge/br_input.c | |||
| @@ -41,6 +41,7 @@ int br_handle_frame_finish(struct sk_buff *skb) | |||
| 41 | struct net_bridge_port *p = rcu_dereference(skb->dev->br_port); | 41 | struct net_bridge_port *p = rcu_dereference(skb->dev->br_port); |
| 42 | struct net_bridge *br; | 42 | struct net_bridge *br; |
| 43 | struct net_bridge_fdb_entry *dst; | 43 | struct net_bridge_fdb_entry *dst; |
| 44 | struct net_bridge_mdb_entry *mdst; | ||
| 44 | struct sk_buff *skb2; | 45 | struct sk_buff *skb2; |
| 45 | 46 | ||
| 46 | if (!p || p->state == BR_STATE_DISABLED) | 47 | if (!p || p->state == BR_STATE_DISABLED) |
| @@ -50,6 +51,10 @@ int br_handle_frame_finish(struct sk_buff *skb) | |||
| 50 | br = p->br; | 51 | br = p->br; |
| 51 | br_fdb_update(br, p, eth_hdr(skb)->h_source); | 52 | br_fdb_update(br, p, eth_hdr(skb)->h_source); |
| 52 | 53 | ||
| 54 | if (is_multicast_ether_addr(dest) && | ||
| 55 | br_multicast_rcv(br, p, skb)) | ||
| 56 | goto drop; | ||
| 57 | |||
| 53 | if (p->state == BR_STATE_LEARNING) | 58 | if (p->state == BR_STATE_LEARNING) |
| 54 | goto drop; | 59 | goto drop; |
| 55 | 60 | ||
| @@ -64,8 +69,19 @@ int br_handle_frame_finish(struct sk_buff *skb) | |||
| 64 | dst = NULL; | 69 | dst = NULL; |
| 65 | 70 | ||
| 66 | if (is_multicast_ether_addr(dest)) { | 71 | if (is_multicast_ether_addr(dest)) { |
| 72 | mdst = br_mdb_get(br, skb); | ||
| 73 | if (mdst || BR_INPUT_SKB_CB(skb)->mrouters_only) { | ||
| 74 | if ((mdst && !hlist_unhashed(&mdst->mglist)) || | ||
| 75 | br_multicast_is_router(br)) | ||
| 76 | skb2 = skb; | ||
| 77 | br_multicast_forward(mdst, skb, skb2); | ||
| 78 | skb = NULL; | ||
| 79 | if (!skb2) | ||
| 80 | goto out; | ||
| 81 | } else | ||
| 82 | skb2 = skb; | ||
| 83 | |||
| 67 | br->dev->stats.multicast++; | 84 | br->dev->stats.multicast++; |
| 68 | skb2 = skb; | ||
| 69 | } else if ((dst = __br_fdb_get(br, dest)) && dst->is_local) { | 85 | } else if ((dst = __br_fdb_get(br, dest)) && dst->is_local) { |
| 70 | skb2 = skb; | 86 | skb2 = skb; |
| 71 | /* Do not forward the packet since it's local. */ | 87 | /* Do not forward the packet since it's local. */ |
