diff options
-rw-r--r-- | net/bridge/br_device.c | 2 | ||||
-rw-r--r-- | net/bridge/br_input.c | 33 | ||||
-rw-r--r-- | net/bridge/br_private.h | 7 | ||||
-rw-r--r-- | net/bridge/br_sysfs_br.c | 34 |
4 files changed, 71 insertions, 5 deletions
diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c index ee68eee79e52..28325d15773b 100644 --- a/net/bridge/br_device.c +++ b/net/bridge/br_device.c | |||
@@ -361,6 +361,8 @@ void br_dev_setup(struct net_device *dev) | |||
361 | memcpy(br->group_addr, br_group_address, ETH_ALEN); | 361 | memcpy(br->group_addr, br_group_address, ETH_ALEN); |
362 | 362 | ||
363 | br->stp_enabled = BR_NO_STP; | 363 | br->stp_enabled = BR_NO_STP; |
364 | br->group_fwd_mask = BR_GROUPFWD_DEFAULT; | ||
365 | |||
364 | br->designated_root = br->bridge_id; | 366 | br->designated_root = br->bridge_id; |
365 | br->bridge_max_age = br->max_age = 20 * HZ; | 367 | br->bridge_max_age = br->max_age = 20 * HZ; |
366 | br->bridge_hello_time = br->hello_time = 2 * HZ; | 368 | br->bridge_hello_time = br->hello_time = 2 * HZ; |
diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c index f06ee39c73fd..6f9f8c014725 100644 --- a/net/bridge/br_input.c +++ b/net/bridge/br_input.c | |||
@@ -162,14 +162,37 @@ rx_handler_result_t br_handle_frame(struct sk_buff **pskb) | |||
162 | p = br_port_get_rcu(skb->dev); | 162 | p = br_port_get_rcu(skb->dev); |
163 | 163 | ||
164 | if (unlikely(is_link_local(dest))) { | 164 | if (unlikely(is_link_local(dest))) { |
165 | /* Pause frames shouldn't be passed up by driver anyway */ | 165 | /* |
166 | if (skb->protocol == htons(ETH_P_PAUSE)) | 166 | * See IEEE 802.1D Table 7-10 Reserved addresses |
167 | * | ||
168 | * Assignment Value | ||
169 | * Bridge Group Address 01-80-C2-00-00-00 | ||
170 | * (MAC Control) 802.3 01-80-C2-00-00-01 | ||
171 | * (Link Aggregation) 802.3 01-80-C2-00-00-02 | ||
172 | * 802.1X PAE address 01-80-C2-00-00-03 | ||
173 | * | ||
174 | * 802.1AB LLDP 01-80-C2-00-00-0E | ||
175 | * | ||
176 | * Others reserved for future standardization | ||
177 | */ | ||
178 | switch (dest[5]) { | ||
179 | case 0x00: /* Bridge Group Address */ | ||
180 | /* If STP is turned off, | ||
181 | then must forward to keep loop detection */ | ||
182 | if (p->br->stp_enabled == BR_NO_STP) | ||
183 | goto forward; | ||
184 | break; | ||
185 | |||
186 | case 0x01: /* IEEE MAC (Pause) */ | ||
167 | goto drop; | 187 | goto drop; |
168 | 188 | ||
169 | /* If STP is turned off, then forward */ | 189 | default: |
170 | if (p->br->stp_enabled == BR_NO_STP && dest[5] == 0) | 190 | /* Allow selective forwarding for most other protocols */ |
171 | goto forward; | 191 | if (p->br->group_fwd_mask & (1u << dest[5])) |
192 | goto forward; | ||
193 | } | ||
172 | 194 | ||
195 | /* Deliver packet to local host only */ | ||
173 | if (NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_IN, skb, skb->dev, | 196 | if (NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_IN, skb, skb->dev, |
174 | NULL, br_handle_local_finish)) { | 197 | NULL, br_handle_local_finish)) { |
175 | return RX_HANDLER_CONSUMED; /* consumed by filter */ | 198 | return RX_HANDLER_CONSUMED; /* consumed by filter */ |
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index 78cc364997d9..a248fe65b29a 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; |
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, |