diff options
Diffstat (limited to 'net/bridge/br_sysfs_br.c')
-rw-r--r-- | net/bridge/br_sysfs_br.c | 49 |
1 files changed, 49 insertions, 0 deletions
diff --git a/net/bridge/br_sysfs_br.c b/net/bridge/br_sysfs_br.c index 6f577f16c4c0..96bcb2ff59ab 100644 --- a/net/bridge/br_sysfs_br.c +++ b/net/bridge/br_sysfs_br.c | |||
@@ -242,6 +242,54 @@ static ssize_t show_gc_timer(struct class_device *cd, char *buf) | |||
242 | } | 242 | } |
243 | static CLASS_DEVICE_ATTR(gc_timer, S_IRUGO, show_gc_timer, NULL); | 243 | static CLASS_DEVICE_ATTR(gc_timer, S_IRUGO, show_gc_timer, NULL); |
244 | 244 | ||
245 | static ssize_t show_group_addr(struct class_device *cd, char *buf) | ||
246 | { | ||
247 | struct net_bridge *br = to_bridge(cd); | ||
248 | return sprintf(buf, "%x:%x:%x:%x:%x:%x\n", | ||
249 | br->group_addr[0], br->group_addr[1], | ||
250 | br->group_addr[2], br->group_addr[3], | ||
251 | br->group_addr[4], br->group_addr[5]); | ||
252 | } | ||
253 | |||
254 | static ssize_t store_group_addr(struct class_device *cd, const char *buf, | ||
255 | size_t len) | ||
256 | { | ||
257 | struct net_bridge *br = to_bridge(cd); | ||
258 | unsigned new_addr[6]; | ||
259 | int i; | ||
260 | |||
261 | if (!capable(CAP_NET_ADMIN)) | ||
262 | return -EPERM; | ||
263 | |||
264 | if (sscanf(buf, "%x:%x:%x:%x:%x:%x", | ||
265 | &new_addr[0], &new_addr[1], &new_addr[2], | ||
266 | &new_addr[3], &new_addr[4], &new_addr[5]) != 6) | ||
267 | return -EINVAL; | ||
268 | |||
269 | /* Must be 01:80:c2:00:00:0X */ | ||
270 | for (i = 0; i < 5; i++) | ||
271 | if (new_addr[i] != br_group_address[i]) | ||
272 | return -EINVAL; | ||
273 | |||
274 | if (new_addr[5] & ~0xf) | ||
275 | return -EINVAL; | ||
276 | |||
277 | if (new_addr[5] == 1 /* 802.3x Pause address */ | ||
278 | || new_addr[5] == 2 /* 802.3ad Slow protocols */ | ||
279 | || new_addr[5] == 3) /* 802.1X PAE address */ | ||
280 | return -EINVAL; | ||
281 | |||
282 | spin_lock_bh(&br->lock); | ||
283 | for (i = 0; i < 6; i++) | ||
284 | br->group_addr[i] = new_addr[i]; | ||
285 | spin_unlock_bh(&br->lock); | ||
286 | return len; | ||
287 | } | ||
288 | |||
289 | static CLASS_DEVICE_ATTR(group_addr, S_IRUGO | S_IWUSR, | ||
290 | show_group_addr, store_group_addr); | ||
291 | |||
292 | |||
245 | static struct attribute *bridge_attrs[] = { | 293 | static struct attribute *bridge_attrs[] = { |
246 | &class_device_attr_forward_delay.attr, | 294 | &class_device_attr_forward_delay.attr, |
247 | &class_device_attr_hello_time.attr, | 295 | &class_device_attr_hello_time.attr, |
@@ -259,6 +307,7 @@ static struct attribute *bridge_attrs[] = { | |||
259 | &class_device_attr_tcn_timer.attr, | 307 | &class_device_attr_tcn_timer.attr, |
260 | &class_device_attr_topology_change_timer.attr, | 308 | &class_device_attr_topology_change_timer.attr, |
261 | &class_device_attr_gc_timer.attr, | 309 | &class_device_attr_gc_timer.attr, |
310 | &class_device_attr_group_addr.attr, | ||
262 | NULL | 311 | NULL |
263 | }; | 312 | }; |
264 | 313 | ||