aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/bridge/br_device.c2
-rw-r--r--net/bridge/br_input.c33
-rw-r--r--net/bridge/br_private.h7
-rw-r--r--net/bridge/br_sysfs_br.c34
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,
149static DEVICE_ATTR(stp_state, S_IRUGO | S_IWUSR, show_stp_state, 149static DEVICE_ATTR(stp_state, S_IRUGO | S_IWUSR, show_stp_state,
150 store_stp_state); 150 store_stp_state);
151 151
152static 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
160static 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}
182static DEVICE_ATTR(group_fwd_mask, S_IRUGO | S_IWUSR, show_group_fwd_mask,
183 store_group_fwd_mask);
184
152static ssize_t show_priority(struct device *d, struct device_attribute *attr, 185static 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,