Root/
1 | /* |
2 | * Sysfs attributes of bridge ports |
3 | * Linux ethernet bridge |
4 | * |
5 | * Authors: |
6 | * Stephen Hemminger <shemminger@osdl.org> |
7 | * |
8 | * This program is free software; you can redistribute it and/or |
9 | * modify it under the terms of the GNU General Public License |
10 | * as published by the Free Software Foundation; either version |
11 | * 2 of the License, or (at your option) any later version. |
12 | */ |
13 | |
14 | #include <linux/capability.h> |
15 | #include <linux/kernel.h> |
16 | #include <linux/netdevice.h> |
17 | #include <linux/etherdevice.h> |
18 | #include <linux/if_bridge.h> |
19 | #include <linux/rtnetlink.h> |
20 | #include <linux/spinlock.h> |
21 | #include <linux/times.h> |
22 | |
23 | #include "br_private.h" |
24 | |
25 | #define to_dev(obj) container_of(obj, struct device, kobj) |
26 | #define to_bridge(cd) ((struct net_bridge *)netdev_priv(to_net_dev(cd))) |
27 | |
28 | /* |
29 | * Common code for storing bridge parameters. |
30 | */ |
31 | static ssize_t store_bridge_parm(struct device *d, |
32 | const char *buf, size_t len, |
33 | int (*set)(struct net_bridge *, unsigned long)) |
34 | { |
35 | struct net_bridge *br = to_bridge(d); |
36 | char *endp; |
37 | unsigned long val; |
38 | int err; |
39 | |
40 | if (!ns_capable(dev_net(br->dev)->user_ns, CAP_NET_ADMIN)) |
41 | return -EPERM; |
42 | |
43 | val = simple_strtoul(buf, &endp, 0); |
44 | if (endp == buf) |
45 | return -EINVAL; |
46 | |
47 | err = (*set)(br, val); |
48 | return err ? err : len; |
49 | } |
50 | |
51 | |
52 | static ssize_t show_forward_delay(struct device *d, |
53 | struct device_attribute *attr, char *buf) |
54 | { |
55 | struct net_bridge *br = to_bridge(d); |
56 | return sprintf(buf, "%lu\n", jiffies_to_clock_t(br->forward_delay)); |
57 | } |
58 | |
59 | static ssize_t store_forward_delay(struct device *d, |
60 | struct device_attribute *attr, |
61 | const char *buf, size_t len) |
62 | { |
63 | return store_bridge_parm(d, buf, len, br_set_forward_delay); |
64 | } |
65 | static DEVICE_ATTR(forward_delay, S_IRUGO | S_IWUSR, |
66 | show_forward_delay, store_forward_delay); |
67 | |
68 | static ssize_t show_hello_time(struct device *d, struct device_attribute *attr, |
69 | char *buf) |
70 | { |
71 | return sprintf(buf, "%lu\n", |
72 | jiffies_to_clock_t(to_bridge(d)->hello_time)); |
73 | } |
74 | |
75 | static ssize_t store_hello_time(struct device *d, |
76 | struct device_attribute *attr, const char *buf, |
77 | size_t len) |
78 | { |
79 | return store_bridge_parm(d, buf, len, br_set_hello_time); |
80 | } |
81 | static DEVICE_ATTR(hello_time, S_IRUGO | S_IWUSR, show_hello_time, |
82 | store_hello_time); |
83 | |
84 | static ssize_t show_max_age(struct device *d, struct device_attribute *attr, |
85 | char *buf) |
86 | { |
87 | return sprintf(buf, "%lu\n", |
88 | jiffies_to_clock_t(to_bridge(d)->max_age)); |
89 | } |
90 | |
91 | static ssize_t store_max_age(struct device *d, struct device_attribute *attr, |
92 | const char *buf, size_t len) |
93 | { |
94 | return store_bridge_parm(d, buf, len, br_set_max_age); |
95 | } |
96 | static DEVICE_ATTR(max_age, S_IRUGO | S_IWUSR, show_max_age, store_max_age); |
97 | |
98 | static ssize_t show_ageing_time(struct device *d, |
99 | struct device_attribute *attr, char *buf) |
100 | { |
101 | struct net_bridge *br = to_bridge(d); |
102 | return sprintf(buf, "%lu\n", jiffies_to_clock_t(br->ageing_time)); |
103 | } |
104 | |
105 | static int set_ageing_time(struct net_bridge *br, unsigned long val) |
106 | { |
107 | br->ageing_time = clock_t_to_jiffies(val); |
108 | return 0; |
109 | } |
110 | |
111 | static ssize_t store_ageing_time(struct device *d, |
112 | struct device_attribute *attr, |
113 | const char *buf, size_t len) |
114 | { |
115 | return store_bridge_parm(d, buf, len, set_ageing_time); |
116 | } |
117 | static DEVICE_ATTR(ageing_time, S_IRUGO | S_IWUSR, show_ageing_time, |
118 | store_ageing_time); |
119 | |
120 | static ssize_t show_stp_state(struct device *d, |
121 | struct device_attribute *attr, char *buf) |
122 | { |
123 | struct net_bridge *br = to_bridge(d); |
124 | return sprintf(buf, "%d\n", br->stp_enabled); |
125 | } |
126 | |
127 | |
128 | static ssize_t store_stp_state(struct device *d, |
129 | struct device_attribute *attr, const char *buf, |
130 | size_t len) |
131 | { |
132 | struct net_bridge *br = to_bridge(d); |
133 | char *endp; |
134 | unsigned long val; |
135 | |
136 | if (!ns_capable(dev_net(br->dev)->user_ns, CAP_NET_ADMIN)) |
137 | return -EPERM; |
138 | |
139 | val = simple_strtoul(buf, &endp, 0); |
140 | if (endp == buf) |
141 | return -EINVAL; |
142 | |
143 | if (!rtnl_trylock()) |
144 | return restart_syscall(); |
145 | br_stp_set_enabled(br, val); |
146 | rtnl_unlock(); |
147 | |
148 | return len; |
149 | } |
150 | static DEVICE_ATTR(stp_state, S_IRUGO | S_IWUSR, show_stp_state, |
151 | store_stp_state); |
152 | |
153 | static ssize_t show_group_fwd_mask(struct device *d, |
154 | struct device_attribute *attr, char *buf) |
155 | { |
156 | struct net_bridge *br = to_bridge(d); |
157 | return sprintf(buf, "%#x\n", br->group_fwd_mask); |
158 | } |
159 | |
160 | |
161 | static ssize_t store_group_fwd_mask(struct device *d, |
162 | struct device_attribute *attr, const char *buf, |
163 | size_t len) |
164 | { |
165 | struct net_bridge *br = to_bridge(d); |
166 | char *endp; |
167 | unsigned long val; |
168 | |
169 | if (!ns_capable(dev_net(br->dev)->user_ns, CAP_NET_ADMIN)) |
170 | return -EPERM; |
171 | |
172 | val = simple_strtoul(buf, &endp, 0); |
173 | if (endp == buf) |
174 | return -EINVAL; |
175 | |
176 | if (val & BR_GROUPFWD_RESTRICTED) |
177 | return -EINVAL; |
178 | |
179 | br->group_fwd_mask = val; |
180 | |
181 | return len; |
182 | } |
183 | static DEVICE_ATTR(group_fwd_mask, S_IRUGO | S_IWUSR, show_group_fwd_mask, |
184 | store_group_fwd_mask); |
185 | |
186 | static ssize_t show_priority(struct device *d, struct device_attribute *attr, |
187 | char *buf) |
188 | { |
189 | struct net_bridge *br = to_bridge(d); |
190 | return sprintf(buf, "%d\n", |
191 | (br->bridge_id.prio[0] << 8) | br->bridge_id.prio[1]); |
192 | } |
193 | |
194 | static int set_priority(struct net_bridge *br, unsigned long val) |
195 | { |
196 | br_stp_set_bridge_priority(br, (u16) val); |
197 | return 0; |
198 | } |
199 | |
200 | static ssize_t store_priority(struct device *d, struct device_attribute *attr, |
201 | const char *buf, size_t len) |
202 | { |
203 | return store_bridge_parm(d, buf, len, set_priority); |
204 | } |
205 | static DEVICE_ATTR(priority, S_IRUGO | S_IWUSR, show_priority, store_priority); |
206 | |
207 | static ssize_t show_root_id(struct device *d, struct device_attribute *attr, |
208 | char *buf) |
209 | { |
210 | return br_show_bridge_id(buf, &to_bridge(d)->designated_root); |
211 | } |
212 | static DEVICE_ATTR(root_id, S_IRUGO, show_root_id, NULL); |
213 | |
214 | static ssize_t show_bridge_id(struct device *d, struct device_attribute *attr, |
215 | char *buf) |
216 | { |
217 | return br_show_bridge_id(buf, &to_bridge(d)->bridge_id); |
218 | } |
219 | static DEVICE_ATTR(bridge_id, S_IRUGO, show_bridge_id, NULL); |
220 | |
221 | static ssize_t show_root_port(struct device *d, struct device_attribute *attr, |
222 | char *buf) |
223 | { |
224 | return sprintf(buf, "%d\n", to_bridge(d)->root_port); |
225 | } |
226 | static DEVICE_ATTR(root_port, S_IRUGO, show_root_port, NULL); |
227 | |
228 | static ssize_t show_root_path_cost(struct device *d, |
229 | struct device_attribute *attr, char *buf) |
230 | { |
231 | return sprintf(buf, "%d\n", to_bridge(d)->root_path_cost); |
232 | } |
233 | static DEVICE_ATTR(root_path_cost, S_IRUGO, show_root_path_cost, NULL); |
234 | |
235 | static ssize_t show_topology_change(struct device *d, |
236 | struct device_attribute *attr, char *buf) |
237 | { |
238 | return sprintf(buf, "%d\n", to_bridge(d)->topology_change); |
239 | } |
240 | static DEVICE_ATTR(topology_change, S_IRUGO, show_topology_change, NULL); |
241 | |
242 | static ssize_t show_topology_change_detected(struct device *d, |
243 | struct device_attribute *attr, |
244 | char *buf) |
245 | { |
246 | struct net_bridge *br = to_bridge(d); |
247 | return sprintf(buf, "%d\n", br->topology_change_detected); |
248 | } |
249 | static DEVICE_ATTR(topology_change_detected, S_IRUGO, |
250 | show_topology_change_detected, NULL); |
251 | |
252 | static ssize_t show_hello_timer(struct device *d, |
253 | struct device_attribute *attr, char *buf) |
254 | { |
255 | struct net_bridge *br = to_bridge(d); |
256 | return sprintf(buf, "%ld\n", br_timer_value(&br->hello_timer)); |
257 | } |
258 | static DEVICE_ATTR(hello_timer, S_IRUGO, show_hello_timer, NULL); |
259 | |
260 | static ssize_t show_tcn_timer(struct device *d, struct device_attribute *attr, |
261 | char *buf) |
262 | { |
263 | struct net_bridge *br = to_bridge(d); |
264 | return sprintf(buf, "%ld\n", br_timer_value(&br->tcn_timer)); |
265 | } |
266 | static DEVICE_ATTR(tcn_timer, S_IRUGO, show_tcn_timer, NULL); |
267 | |
268 | static ssize_t show_topology_change_timer(struct device *d, |
269 | struct device_attribute *attr, |
270 | char *buf) |
271 | { |
272 | struct net_bridge *br = to_bridge(d); |
273 | return sprintf(buf, "%ld\n", br_timer_value(&br->topology_change_timer)); |
274 | } |
275 | static DEVICE_ATTR(topology_change_timer, S_IRUGO, show_topology_change_timer, |
276 | NULL); |
277 | |
278 | static ssize_t show_gc_timer(struct device *d, struct device_attribute *attr, |
279 | char *buf) |
280 | { |
281 | struct net_bridge *br = to_bridge(d); |
282 | return sprintf(buf, "%ld\n", br_timer_value(&br->gc_timer)); |
283 | } |
284 | static DEVICE_ATTR(gc_timer, S_IRUGO, show_gc_timer, NULL); |
285 | |
286 | static ssize_t show_group_addr(struct device *d, |
287 | struct device_attribute *attr, char *buf) |
288 | { |
289 | struct net_bridge *br = to_bridge(d); |
290 | return sprintf(buf, "%x:%x:%x:%x:%x:%x\n", |
291 | br->group_addr[0], br->group_addr[1], |
292 | br->group_addr[2], br->group_addr[3], |
293 | br->group_addr[4], br->group_addr[5]); |
294 | } |
295 | |
296 | static ssize_t store_group_addr(struct device *d, |
297 | struct device_attribute *attr, |
298 | const char *buf, size_t len) |
299 | { |
300 | struct net_bridge *br = to_bridge(d); |
301 | u8 new_addr[6]; |
302 | int i; |
303 | |
304 | if (!ns_capable(dev_net(br->dev)->user_ns, CAP_NET_ADMIN)) |
305 | return -EPERM; |
306 | |
307 | if (sscanf(buf, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", |
308 | &new_addr[0], &new_addr[1], &new_addr[2], |
309 | &new_addr[3], &new_addr[4], &new_addr[5]) != 6) |
310 | return -EINVAL; |
311 | |
312 | if (!is_link_local_ether_addr(new_addr)) |
313 | return -EINVAL; |
314 | |
315 | if (new_addr[5] == 1 || /* 802.3x Pause address */ |
316 | new_addr[5] == 2 || /* 802.3ad Slow protocols */ |
317 | new_addr[5] == 3) /* 802.1X PAE address */ |
318 | return -EINVAL; |
319 | |
320 | spin_lock_bh(&br->lock); |
321 | for (i = 0; i < 6; i++) |
322 | br->group_addr[i] = new_addr[i]; |
323 | spin_unlock_bh(&br->lock); |
324 | return len; |
325 | } |
326 | |
327 | static DEVICE_ATTR(group_addr, S_IRUGO | S_IWUSR, |
328 | show_group_addr, store_group_addr); |
329 | |
330 | static ssize_t store_flush(struct device *d, |
331 | struct device_attribute *attr, |
332 | const char *buf, size_t len) |
333 | { |
334 | struct net_bridge *br = to_bridge(d); |
335 | |
336 | if (!ns_capable(dev_net(br->dev)->user_ns, CAP_NET_ADMIN)) |
337 | return -EPERM; |
338 | |
339 | br_fdb_flush(br); |
340 | return len; |
341 | } |
342 | static DEVICE_ATTR(flush, S_IWUSR, NULL, store_flush); |
343 | |
344 | #ifdef CONFIG_BRIDGE_IGMP_SNOOPING |
345 | static ssize_t show_multicast_router(struct device *d, |
346 | struct device_attribute *attr, char *buf) |
347 | { |
348 | struct net_bridge *br = to_bridge(d); |
349 | return sprintf(buf, "%d\n", br->multicast_router); |
350 | } |
351 | |
352 | static ssize_t store_multicast_router(struct device *d, |
353 | struct device_attribute *attr, |
354 | const char *buf, size_t len) |
355 | { |
356 | return store_bridge_parm(d, buf, len, br_multicast_set_router); |
357 | } |
358 | static DEVICE_ATTR(multicast_router, S_IRUGO | S_IWUSR, show_multicast_router, |
359 | store_multicast_router); |
360 | |
361 | static ssize_t show_multicast_snooping(struct device *d, |
362 | struct device_attribute *attr, |
363 | char *buf) |
364 | { |
365 | struct net_bridge *br = to_bridge(d); |
366 | return sprintf(buf, "%d\n", !br->multicast_disabled); |
367 | } |
368 | |
369 | static ssize_t store_multicast_snooping(struct device *d, |
370 | struct device_attribute *attr, |
371 | const char *buf, size_t len) |
372 | { |
373 | return store_bridge_parm(d, buf, len, br_multicast_toggle); |
374 | } |
375 | static DEVICE_ATTR(multicast_snooping, S_IRUGO | S_IWUSR, |
376 | show_multicast_snooping, store_multicast_snooping); |
377 | |
378 | static ssize_t show_multicast_querier(struct device *d, |
379 | struct device_attribute *attr, |
380 | char *buf) |
381 | { |
382 | struct net_bridge *br = to_bridge(d); |
383 | return sprintf(buf, "%d\n", br->multicast_querier); |
384 | } |
385 | |
386 | static ssize_t store_multicast_querier(struct device *d, |
387 | struct device_attribute *attr, |
388 | const char *buf, size_t len) |
389 | { |
390 | return store_bridge_parm(d, buf, len, br_multicast_set_querier); |
391 | } |
392 | static DEVICE_ATTR(multicast_querier, S_IRUGO | S_IWUSR, |
393 | show_multicast_querier, store_multicast_querier); |
394 | |
395 | static ssize_t show_hash_elasticity(struct device *d, |
396 | struct device_attribute *attr, char *buf) |
397 | { |
398 | struct net_bridge *br = to_bridge(d); |
399 | return sprintf(buf, "%u\n", br->hash_elasticity); |
400 | } |
401 | |
402 | static int set_elasticity(struct net_bridge *br, unsigned long val) |
403 | { |
404 | br->hash_elasticity = val; |
405 | return 0; |
406 | } |
407 | |
408 | static ssize_t store_hash_elasticity(struct device *d, |
409 | struct device_attribute *attr, |
410 | const char *buf, size_t len) |
411 | { |
412 | return store_bridge_parm(d, buf, len, set_elasticity); |
413 | } |
414 | static DEVICE_ATTR(hash_elasticity, S_IRUGO | S_IWUSR, show_hash_elasticity, |
415 | store_hash_elasticity); |
416 | |
417 | static ssize_t show_hash_max(struct device *d, struct device_attribute *attr, |
418 | char *buf) |
419 | { |
420 | struct net_bridge *br = to_bridge(d); |
421 | return sprintf(buf, "%u\n", br->hash_max); |
422 | } |
423 | |
424 | static ssize_t store_hash_max(struct device *d, struct device_attribute *attr, |
425 | const char *buf, size_t len) |
426 | { |
427 | return store_bridge_parm(d, buf, len, br_multicast_set_hash_max); |
428 | } |
429 | static DEVICE_ATTR(hash_max, S_IRUGO | S_IWUSR, show_hash_max, |
430 | store_hash_max); |
431 | |
432 | static ssize_t show_multicast_last_member_count(struct device *d, |
433 | struct device_attribute *attr, |
434 | char *buf) |
435 | { |
436 | struct net_bridge *br = to_bridge(d); |
437 | return sprintf(buf, "%u\n", br->multicast_last_member_count); |
438 | } |
439 | |
440 | static int set_last_member_count(struct net_bridge *br, unsigned long val) |
441 | { |
442 | br->multicast_last_member_count = val; |
443 | return 0; |
444 | } |
445 | |
446 | static ssize_t store_multicast_last_member_count(struct device *d, |
447 | struct device_attribute *attr, |
448 | const char *buf, size_t len) |
449 | { |
450 | return store_bridge_parm(d, buf, len, set_last_member_count); |
451 | } |
452 | static DEVICE_ATTR(multicast_last_member_count, S_IRUGO | S_IWUSR, |
453 | show_multicast_last_member_count, |
454 | store_multicast_last_member_count); |
455 | |
456 | static ssize_t show_multicast_startup_query_count( |
457 | struct device *d, struct device_attribute *attr, char *buf) |
458 | { |
459 | struct net_bridge *br = to_bridge(d); |
460 | return sprintf(buf, "%u\n", br->multicast_startup_query_count); |
461 | } |
462 | |
463 | static int set_startup_query_count(struct net_bridge *br, unsigned long val) |
464 | { |
465 | br->multicast_startup_query_count = val; |
466 | return 0; |
467 | } |
468 | |
469 | static ssize_t store_multicast_startup_query_count( |
470 | struct device *d, struct device_attribute *attr, const char *buf, |
471 | size_t len) |
472 | { |
473 | return store_bridge_parm(d, buf, len, set_startup_query_count); |
474 | } |
475 | static DEVICE_ATTR(multicast_startup_query_count, S_IRUGO | S_IWUSR, |
476 | show_multicast_startup_query_count, |
477 | store_multicast_startup_query_count); |
478 | |
479 | static ssize_t show_multicast_last_member_interval( |
480 | struct device *d, struct device_attribute *attr, char *buf) |
481 | { |
482 | struct net_bridge *br = to_bridge(d); |
483 | return sprintf(buf, "%lu\n", |
484 | jiffies_to_clock_t(br->multicast_last_member_interval)); |
485 | } |
486 | |
487 | static int set_last_member_interval(struct net_bridge *br, unsigned long val) |
488 | { |
489 | br->multicast_last_member_interval = clock_t_to_jiffies(val); |
490 | return 0; |
491 | } |
492 | |
493 | static ssize_t store_multicast_last_member_interval( |
494 | struct device *d, struct device_attribute *attr, const char *buf, |
495 | size_t len) |
496 | { |
497 | return store_bridge_parm(d, buf, len, set_last_member_interval); |
498 | } |
499 | static DEVICE_ATTR(multicast_last_member_interval, S_IRUGO | S_IWUSR, |
500 | show_multicast_last_member_interval, |
501 | store_multicast_last_member_interval); |
502 | |
503 | static ssize_t show_multicast_membership_interval( |
504 | struct device *d, struct device_attribute *attr, char *buf) |
505 | { |
506 | struct net_bridge *br = to_bridge(d); |
507 | return sprintf(buf, "%lu\n", |
508 | jiffies_to_clock_t(br->multicast_membership_interval)); |
509 | } |
510 | |
511 | static int set_membership_interval(struct net_bridge *br, unsigned long val) |
512 | { |
513 | br->multicast_membership_interval = clock_t_to_jiffies(val); |
514 | return 0; |
515 | } |
516 | |
517 | static ssize_t store_multicast_membership_interval( |
518 | struct device *d, struct device_attribute *attr, const char *buf, |
519 | size_t len) |
520 | { |
521 | return store_bridge_parm(d, buf, len, set_membership_interval); |
522 | } |
523 | static DEVICE_ATTR(multicast_membership_interval, S_IRUGO | S_IWUSR, |
524 | show_multicast_membership_interval, |
525 | store_multicast_membership_interval); |
526 | |
527 | static ssize_t show_multicast_querier_interval(struct device *d, |
528 | struct device_attribute *attr, |
529 | char *buf) |
530 | { |
531 | struct net_bridge *br = to_bridge(d); |
532 | return sprintf(buf, "%lu\n", |
533 | jiffies_to_clock_t(br->multicast_querier_interval)); |
534 | } |
535 | |
536 | static int set_querier_interval(struct net_bridge *br, unsigned long val) |
537 | { |
538 | br->multicast_querier_interval = clock_t_to_jiffies(val); |
539 | return 0; |
540 | } |
541 | |
542 | static ssize_t store_multicast_querier_interval(struct device *d, |
543 | struct device_attribute *attr, |
544 | const char *buf, size_t len) |
545 | { |
546 | return store_bridge_parm(d, buf, len, set_querier_interval); |
547 | } |
548 | static DEVICE_ATTR(multicast_querier_interval, S_IRUGO | S_IWUSR, |
549 | show_multicast_querier_interval, |
550 | store_multicast_querier_interval); |
551 | |
552 | static ssize_t show_multicast_query_interval(struct device *d, |
553 | struct device_attribute *attr, |
554 | char *buf) |
555 | { |
556 | struct net_bridge *br = to_bridge(d); |
557 | return sprintf(buf, "%lu\n", |
558 | jiffies_to_clock_t(br->multicast_query_interval)); |
559 | } |
560 | |
561 | static int set_query_interval(struct net_bridge *br, unsigned long val) |
562 | { |
563 | br->multicast_query_interval = clock_t_to_jiffies(val); |
564 | return 0; |
565 | } |
566 | |
567 | static ssize_t store_multicast_query_interval(struct device *d, |
568 | struct device_attribute *attr, |
569 | const char *buf, size_t len) |
570 | { |
571 | return store_bridge_parm(d, buf, len, set_query_interval); |
572 | } |
573 | static DEVICE_ATTR(multicast_query_interval, S_IRUGO | S_IWUSR, |
574 | show_multicast_query_interval, |
575 | store_multicast_query_interval); |
576 | |
577 | static ssize_t show_multicast_query_response_interval( |
578 | struct device *d, struct device_attribute *attr, char *buf) |
579 | { |
580 | struct net_bridge *br = to_bridge(d); |
581 | return sprintf( |
582 | buf, "%lu\n", |
583 | jiffies_to_clock_t(br->multicast_query_response_interval)); |
584 | } |
585 | |
586 | static int set_query_response_interval(struct net_bridge *br, unsigned long val) |
587 | { |
588 | br->multicast_query_response_interval = clock_t_to_jiffies(val); |
589 | return 0; |
590 | } |
591 | |
592 | static ssize_t store_multicast_query_response_interval( |
593 | struct device *d, struct device_attribute *attr, const char *buf, |
594 | size_t len) |
595 | { |
596 | return store_bridge_parm(d, buf, len, set_query_response_interval); |
597 | } |
598 | static DEVICE_ATTR(multicast_query_response_interval, S_IRUGO | S_IWUSR, |
599 | show_multicast_query_response_interval, |
600 | store_multicast_query_response_interval); |
601 | |
602 | static ssize_t show_multicast_startup_query_interval( |
603 | struct device *d, struct device_attribute *attr, char *buf) |
604 | { |
605 | struct net_bridge *br = to_bridge(d); |
606 | return sprintf( |
607 | buf, "%lu\n", |
608 | jiffies_to_clock_t(br->multicast_startup_query_interval)); |
609 | } |
610 | |
611 | static int set_startup_query_interval(struct net_bridge *br, unsigned long val) |
612 | { |
613 | br->multicast_startup_query_interval = clock_t_to_jiffies(val); |
614 | return 0; |
615 | } |
616 | |
617 | static ssize_t store_multicast_startup_query_interval( |
618 | struct device *d, struct device_attribute *attr, const char *buf, |
619 | size_t len) |
620 | { |
621 | return store_bridge_parm(d, buf, len, set_startup_query_interval); |
622 | } |
623 | static DEVICE_ATTR(multicast_startup_query_interval, S_IRUGO | S_IWUSR, |
624 | show_multicast_startup_query_interval, |
625 | store_multicast_startup_query_interval); |
626 | #endif |
627 | #ifdef CONFIG_BRIDGE_NETFILTER |
628 | static ssize_t show_nf_call_iptables( |
629 | struct device *d, struct device_attribute *attr, char *buf) |
630 | { |
631 | struct net_bridge *br = to_bridge(d); |
632 | return sprintf(buf, "%u\n", br->nf_call_iptables); |
633 | } |
634 | |
635 | static int set_nf_call_iptables(struct net_bridge *br, unsigned long val) |
636 | { |
637 | br->nf_call_iptables = val ? true : false; |
638 | return 0; |
639 | } |
640 | |
641 | static ssize_t store_nf_call_iptables( |
642 | struct device *d, struct device_attribute *attr, const char *buf, |
643 | size_t len) |
644 | { |
645 | return store_bridge_parm(d, buf, len, set_nf_call_iptables); |
646 | } |
647 | static DEVICE_ATTR(nf_call_iptables, S_IRUGO | S_IWUSR, |
648 | show_nf_call_iptables, store_nf_call_iptables); |
649 | |
650 | static ssize_t show_nf_call_ip6tables( |
651 | struct device *d, struct device_attribute *attr, char *buf) |
652 | { |
653 | struct net_bridge *br = to_bridge(d); |
654 | return sprintf(buf, "%u\n", br->nf_call_ip6tables); |
655 | } |
656 | |
657 | static int set_nf_call_ip6tables(struct net_bridge *br, unsigned long val) |
658 | { |
659 | br->nf_call_ip6tables = val ? true : false; |
660 | return 0; |
661 | } |
662 | |
663 | static ssize_t store_nf_call_ip6tables( |
664 | struct device *d, struct device_attribute *attr, const char *buf, |
665 | size_t len) |
666 | { |
667 | return store_bridge_parm(d, buf, len, set_nf_call_ip6tables); |
668 | } |
669 | static DEVICE_ATTR(nf_call_ip6tables, S_IRUGO | S_IWUSR, |
670 | show_nf_call_ip6tables, store_nf_call_ip6tables); |
671 | |
672 | static ssize_t show_nf_call_arptables( |
673 | struct device *d, struct device_attribute *attr, char *buf) |
674 | { |
675 | struct net_bridge *br = to_bridge(d); |
676 | return sprintf(buf, "%u\n", br->nf_call_arptables); |
677 | } |
678 | |
679 | static int set_nf_call_arptables(struct net_bridge *br, unsigned long val) |
680 | { |
681 | br->nf_call_arptables = val ? true : false; |
682 | return 0; |
683 | } |
684 | |
685 | static ssize_t store_nf_call_arptables( |
686 | struct device *d, struct device_attribute *attr, const char *buf, |
687 | size_t len) |
688 | { |
689 | return store_bridge_parm(d, buf, len, set_nf_call_arptables); |
690 | } |
691 | static DEVICE_ATTR(nf_call_arptables, S_IRUGO | S_IWUSR, |
692 | show_nf_call_arptables, store_nf_call_arptables); |
693 | #endif |
694 | #ifdef CONFIG_BRIDGE_VLAN_FILTERING |
695 | static ssize_t show_vlan_filtering(struct device *d, |
696 | struct device_attribute *attr, |
697 | char *buf) |
698 | { |
699 | struct net_bridge *br = to_bridge(d); |
700 | return sprintf(buf, "%d\n", br->vlan_enabled); |
701 | } |
702 | |
703 | static ssize_t store_vlan_filtering(struct device *d, |
704 | struct device_attribute *attr, |
705 | const char *buf, size_t len) |
706 | { |
707 | return store_bridge_parm(d, buf, len, br_vlan_filter_toggle); |
708 | } |
709 | static DEVICE_ATTR(vlan_filtering, S_IRUGO | S_IWUSR, |
710 | show_vlan_filtering, store_vlan_filtering); |
711 | #endif |
712 | |
713 | static struct attribute *bridge_attrs[] = { |
714 | &dev_attr_forward_delay.attr, |
715 | &dev_attr_hello_time.attr, |
716 | &dev_attr_max_age.attr, |
717 | &dev_attr_ageing_time.attr, |
718 | &dev_attr_stp_state.attr, |
719 | &dev_attr_group_fwd_mask.attr, |
720 | &dev_attr_priority.attr, |
721 | &dev_attr_bridge_id.attr, |
722 | &dev_attr_root_id.attr, |
723 | &dev_attr_root_path_cost.attr, |
724 | &dev_attr_root_port.attr, |
725 | &dev_attr_topology_change.attr, |
726 | &dev_attr_topology_change_detected.attr, |
727 | &dev_attr_hello_timer.attr, |
728 | &dev_attr_tcn_timer.attr, |
729 | &dev_attr_topology_change_timer.attr, |
730 | &dev_attr_gc_timer.attr, |
731 | &dev_attr_group_addr.attr, |
732 | &dev_attr_flush.attr, |
733 | #ifdef CONFIG_BRIDGE_IGMP_SNOOPING |
734 | &dev_attr_multicast_router.attr, |
735 | &dev_attr_multicast_snooping.attr, |
736 | &dev_attr_multicast_querier.attr, |
737 | &dev_attr_hash_elasticity.attr, |
738 | &dev_attr_hash_max.attr, |
739 | &dev_attr_multicast_last_member_count.attr, |
740 | &dev_attr_multicast_startup_query_count.attr, |
741 | &dev_attr_multicast_last_member_interval.attr, |
742 | &dev_attr_multicast_membership_interval.attr, |
743 | &dev_attr_multicast_querier_interval.attr, |
744 | &dev_attr_multicast_query_interval.attr, |
745 | &dev_attr_multicast_query_response_interval.attr, |
746 | &dev_attr_multicast_startup_query_interval.attr, |
747 | #endif |
748 | #ifdef CONFIG_BRIDGE_NETFILTER |
749 | &dev_attr_nf_call_iptables.attr, |
750 | &dev_attr_nf_call_ip6tables.attr, |
751 | &dev_attr_nf_call_arptables.attr, |
752 | #endif |
753 | #ifdef CONFIG_BRIDGE_VLAN_FILTERING |
754 | &dev_attr_vlan_filtering.attr, |
755 | #endif |
756 | NULL |
757 | }; |
758 | |
759 | static struct attribute_group bridge_group = { |
760 | .name = SYSFS_BRIDGE_ATTR, |
761 | .attrs = bridge_attrs, |
762 | }; |
763 | |
764 | /* |
765 | * Export the forwarding information table as a binary file |
766 | * The records are struct __fdb_entry. |
767 | * |
768 | * Returns the number of bytes read. |
769 | */ |
770 | static ssize_t brforward_read(struct file *filp, struct kobject *kobj, |
771 | struct bin_attribute *bin_attr, |
772 | char *buf, loff_t off, size_t count) |
773 | { |
774 | struct device *dev = to_dev(kobj); |
775 | struct net_bridge *br = to_bridge(dev); |
776 | int n; |
777 | |
778 | /* must read whole records */ |
779 | if (off % sizeof(struct __fdb_entry) != 0) |
780 | return -EINVAL; |
781 | |
782 | n = br_fdb_fillbuf(br, buf, |
783 | count / sizeof(struct __fdb_entry), |
784 | off / sizeof(struct __fdb_entry)); |
785 | |
786 | if (n > 0) |
787 | n *= sizeof(struct __fdb_entry); |
788 | |
789 | return n; |
790 | } |
791 | |
792 | static struct bin_attribute bridge_forward = { |
793 | .attr = { .name = SYSFS_BRIDGE_FDB, |
794 | .mode = S_IRUGO, }, |
795 | .read = brforward_read, |
796 | }; |
797 | |
798 | /* |
799 | * Add entries in sysfs onto the existing network class device |
800 | * for the bridge. |
801 | * Adds a attribute group "bridge" containing tuning parameters. |
802 | * Binary attribute containing the forward table |
803 | * Sub directory to hold links to interfaces. |
804 | * |
805 | * Note: the ifobj exists only to be a subdirectory |
806 | * to hold links. The ifobj exists in same data structure |
807 | * as it's parent the bridge so reference counting works. |
808 | */ |
809 | int br_sysfs_addbr(struct net_device *dev) |
810 | { |
811 | struct kobject *brobj = &dev->dev.kobj; |
812 | struct net_bridge *br = netdev_priv(dev); |
813 | int err; |
814 | |
815 | err = sysfs_create_group(brobj, &bridge_group); |
816 | if (err) { |
817 | pr_info("%s: can't create group %s/%s\n", |
818 | __func__, dev->name, bridge_group.name); |
819 | goto out1; |
820 | } |
821 | |
822 | err = sysfs_create_bin_file(brobj, &bridge_forward); |
823 | if (err) { |
824 | pr_info("%s: can't create attribute file %s/%s\n", |
825 | __func__, dev->name, bridge_forward.attr.name); |
826 | goto out2; |
827 | } |
828 | |
829 | br->ifobj = kobject_create_and_add(SYSFS_BRIDGE_PORT_SUBDIR, brobj); |
830 | if (!br->ifobj) { |
831 | pr_info("%s: can't add kobject (directory) %s/%s\n", |
832 | __func__, dev->name, SYSFS_BRIDGE_PORT_SUBDIR); |
833 | goto out3; |
834 | } |
835 | return 0; |
836 | out3: |
837 | sysfs_remove_bin_file(&dev->dev.kobj, &bridge_forward); |
838 | out2: |
839 | sysfs_remove_group(&dev->dev.kobj, &bridge_group); |
840 | out1: |
841 | return err; |
842 | |
843 | } |
844 | |
845 | void br_sysfs_delbr(struct net_device *dev) |
846 | { |
847 | struct kobject *kobj = &dev->dev.kobj; |
848 | struct net_bridge *br = netdev_priv(dev); |
849 | |
850 | kobject_put(br->ifobj); |
851 | sysfs_remove_bin_file(kobj, &bridge_forward); |
852 | sysfs_remove_group(kobj, &bridge_group); |
853 | } |
854 |
Branches:
ben-wpan
ben-wpan-stefan
javiroman/ks7010
jz-2.6.34
jz-2.6.34-rc5
jz-2.6.34-rc6
jz-2.6.34-rc7
jz-2.6.35
jz-2.6.36
jz-2.6.37
jz-2.6.38
jz-2.6.39
jz-3.0
jz-3.1
jz-3.11
jz-3.12
jz-3.13
jz-3.15
jz-3.16
jz-3.18-dt
jz-3.2
jz-3.3
jz-3.4
jz-3.5
jz-3.6
jz-3.6-rc2-pwm
jz-3.9
jz-3.9-clk
jz-3.9-rc8
jz47xx
jz47xx-2.6.38
master
Tags:
od-2011-09-04
od-2011-09-18
v2.6.34-rc5
v2.6.34-rc6
v2.6.34-rc7
v3.9