aboutsummaryrefslogtreecommitdiff
path: root/networking/brctl.c
diff options
context:
space:
mode:
Diffstat (limited to 'networking/brctl.c')
-rw-r--r--networking/brctl.c506
1 files changed, 260 insertions, 246 deletions
diff --git a/networking/brctl.c b/networking/brctl.c
index ba4a714f8..f44ad9c8d 100644
--- a/networking/brctl.c
+++ b/networking/brctl.c
@@ -9,9 +9,6 @@
9 * 9 *
10 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 10 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
11 */ 11 */
12/* This applet currently uses only the ioctl interface and no sysfs at all.
13 * At the time of this writing this was considered a feature.
14 */
15//config:config BRCTL 12//config:config BRCTL
16//config: bool "brctl (4.7 kb)" 13//config: bool "brctl (4.7 kb)"
17//config: default y 14//config: default y
@@ -44,29 +41,34 @@
44//kbuild:lib-$(CONFIG_BRCTL) += brctl.o 41//kbuild:lib-$(CONFIG_BRCTL) += brctl.o
45 42
46//usage:#define brctl_trivial_usage 43//usage:#define brctl_trivial_usage
47//usage: "COMMAND [BRIDGE [INTERFACE]]" 44//usage: "COMMAND [BRIDGE [ARGS]]"
48//usage:#define brctl_full_usage "\n\n" 45//usage:#define brctl_full_usage "\n\n"
49//usage: "Manage ethernet bridges\n" 46//usage: "Manage ethernet bridges"
50//usage: "\nCommands:" 47//usage: "\nCommands:"
51//usage: IF_FEATURE_BRCTL_SHOW( 48//usage: IF_FEATURE_BRCTL_SHOW(
52//usage: "\n show Show a list of bridges" 49//usage: "\n show [BRIDGE]... Show bridges"
53//usage: ) 50//usage: )
54//usage: "\n addbr BRIDGE Create BRIDGE" 51//usage: "\n addbr BRIDGE Create BRIDGE"
55//usage: "\n delbr BRIDGE Delete BRIDGE" 52//usage: "\n delbr BRIDGE Delete BRIDGE"
56//usage: "\n addif BRIDGE IFACE Add IFACE to BRIDGE" 53//usage: "\n addif BRIDGE IFACE Add IFACE to BRIDGE"
57//usage: "\n delif BRIDGE IFACE Delete IFACE from BRIDGE" 54//usage: "\n delif BRIDGE IFACE Delete IFACE from BRIDGE"
58//usage: IF_FEATURE_BRCTL_FANCY( 55//usage: IF_FEATURE_BRCTL_FANCY(
59//usage: "\n setageing BRIDGE TIME Set ageing time" 56//usage: "\n stp BRIDGE 1/yes/on|0/no/off STP on/off"
60//usage: "\n setfd BRIDGE TIME Set bridge forward delay" 57//usage: "\n setageing BRIDGE SECONDS Set ageing time"
61//usage: "\n sethello BRIDGE TIME Set hello time" 58//usage: "\n setfd BRIDGE SECONDS Set bridge forward delay"
62//usage: "\n setmaxage BRIDGE TIME Set max message age" 59//usage: "\n sethello BRIDGE SECONDS Set hello time"
63//usage: "\n setpathcost BRIDGE COST Set path cost" 60//usage: "\n setmaxage BRIDGE SECONDS Set max message age"
64//usage: "\n setportprio BRIDGE PRIO Set port priority"
65//usage: "\n setbridgeprio BRIDGE PRIO Set bridge priority" 61//usage: "\n setbridgeprio BRIDGE PRIO Set bridge priority"
66//usage: "\n stp BRIDGE [1/yes/on|0/no/off] STP on/off" 62//usage: "\n setportprio BRIDGE IFACE PRIO Set port priority"
63//usage: "\n setpathcost BRIDGE IFACE COST Set path cost"
67//usage: ) 64//usage: )
65// Not yet implemented:
66// hairpin BRIDGE IFACE on|off Hairpin on/off
67// showmacs BRIDGE List mac addrs
68// showstp BRIDGE Show stp info
68 69
69#include "libbb.h" 70#include "libbb.h"
71#include "common_bufsiz.h"
70#include <linux/sockios.h> 72#include <linux/sockios.h>
71#include <net/if.h> 73#include <net/if.h>
72 74
@@ -83,121 +85,114 @@
83# define SIOCBRDELIF BRCTL_DEL_IF 85# define SIOCBRDELIF BRCTL_DEL_IF
84#endif 86#endif
85 87
86
87/* Maximum number of ports supported per bridge interface. */
88#ifndef MAX_PORTS
89# define MAX_PORTS 32
90#endif
91
92/* Use internal number parsing and not the "exact" conversion. */
93/* #define BRCTL_USE_INTERNAL 0 */ /* use exact conversion */
94#define BRCTL_USE_INTERNAL 1
95
96#if ENABLE_FEATURE_BRCTL_FANCY 88#if ENABLE_FEATURE_BRCTL_FANCY
97/* #include <linux/if_bridge.h> 89static unsigned str_to_jiffies(const char *time_str)
98 * breaks on musl: we already included netinet/in.h in libbb.h,
99 * if we include <linux/if_bridge.h> here, we get this:
100 * In file included from /usr/include/linux/if_bridge.h:18,
101 * from networking/brctl.c:67:
102 * /usr/include/linux/in6.h:32: error: redefinition of 'struct in6_addr'
103 * /usr/include/linux/in6.h:49: error: redefinition of 'struct sockaddr_in6'
104 * /usr/include/linux/in6.h:59: error: redefinition of 'struct ipv6_mreq'
105 */
106/* From <linux/if_bridge.h> */
107#define BRCTL_GET_VERSION 0
108#define BRCTL_GET_BRIDGES 1
109#define BRCTL_ADD_BRIDGE 2
110#define BRCTL_DEL_BRIDGE 3
111#define BRCTL_ADD_IF 4
112#define BRCTL_DEL_IF 5
113#define BRCTL_GET_BRIDGE_INFO 6
114#define BRCTL_GET_PORT_LIST 7
115#define BRCTL_SET_BRIDGE_FORWARD_DELAY 8
116#define BRCTL_SET_BRIDGE_HELLO_TIME 9
117#define BRCTL_SET_BRIDGE_MAX_AGE 10
118#define BRCTL_SET_AGEING_TIME 11
119#define BRCTL_SET_GC_INTERVAL 12
120#define BRCTL_GET_PORT_INFO 13
121#define BRCTL_SET_BRIDGE_STP_STATE 14
122#define BRCTL_SET_BRIDGE_PRIORITY 15
123#define BRCTL_SET_PORT_PRIORITY 16
124#define BRCTL_SET_PATH_COST 17
125#define BRCTL_GET_FDB_ENTRIES 18
126struct __bridge_info {
127 uint64_t designated_root;
128 uint64_t bridge_id;
129 uint32_t root_path_cost;
130 uint32_t max_age;
131 uint32_t hello_time;
132 uint32_t forward_delay;
133 uint32_t bridge_max_age;
134 uint32_t bridge_hello_time;
135 uint32_t bridge_forward_delay;
136 uint8_t topology_change;
137 uint8_t topology_change_detected;
138 uint8_t root_port;
139 uint8_t stp_enabled;
140 uint32_t ageing_time;
141 uint32_t gc_interval;
142 uint32_t hello_timer_value;
143 uint32_t tcn_timer_value;
144 uint32_t topology_change_timer_value;
145 uint32_t gc_timer_value;
146};
147/* end <linux/if_bridge.h> */
148
149/* FIXME: These 4 funcs are not really clean and could be improved */
150static ALWAYS_INLINE void bb_strtotimeval(struct timeval *tv,
151 const char *time_str)
152{ 90{
153 double secs; 91 double dd;
154# if BRCTL_USE_INTERNAL
155 char *endptr; 92 char *endptr;
156 secs = /*bb_*/strtod(time_str, &endptr); 93 dd = /*bb_*/strtod(time_str, &endptr);
157 if (endptr == time_str) 94 if (endptr == time_str || dd < 0)
158# else
159 if (sscanf(time_str, "%lf", &secs) != 1)
160# endif
161 bb_error_msg_and_die(bb_msg_invalid_arg_to, time_str, "timespec"); 95 bb_error_msg_and_die(bb_msg_invalid_arg_to, time_str, "timespec");
162 tv->tv_sec = secs;
163 tv->tv_usec = 1000000 * (secs - tv->tv_sec);
164}
165 96
166static ALWAYS_INLINE unsigned long tv_to_jiffies(const struct timeval *tv) 97 dd *= 100;
167{ 98 /* For purposes of brctl,
168 unsigned long long jif; 99 * capping SECONDS by ~20 million seconds is quite enough:
169 100 */
170 jif = 1000000ULL * tv->tv_sec + tv->tv_usec; 101 if (dd > INT_MAX)
102 dd = INT_MAX;
171 103
172 return jif/10000; 104 return dd;
173} 105}
174# if 0 106#endif
175static void jiffies_to_tv(struct timeval *tv, unsigned long jiffies)
176{
177 unsigned long long tvusec;
178 107
179 tvusec = 10000ULL*jiffies; 108#define filedata bb_common_bufsiz1
180 tv->tv_sec = tvusec/1000000; 109
181 tv->tv_usec = tvusec - 1000000 * tv->tv_sec; 110static int read_file(const char *name)
182}
183# endif
184static unsigned long str_to_jiffies(const char *time_str)
185{ 111{
186 struct timeval tv; 112 int n = open_read_close(name, filedata, COMMON_BUFSIZE - 1);
187 bb_strtotimeval(&tv, time_str); 113 if (n < 0) {
188 return tv_to_jiffies(&tv); 114 filedata[0] = '\0';
115 } else {
116 filedata[n] = '\0';
117 if (n != 0 && filedata[n - 1] == '\n')
118 filedata[--n] = '\0';
119 }
120 return n;
189} 121}
190 122
191static void arm_ioctl(unsigned long *args, 123/* NB: we are in /sys/class/net
192 unsigned long arg0, unsigned long arg1, unsigned long arg2) 124 */
125static int show_bridge(const char *name, int need_hdr)
193{ 126{
194 args[0] = arg0; 127/* Output:
195 args[1] = arg1; 128 *bridge name bridge id STP enabled interfaces
196 args[2] = arg2; 129 *br0 8000.000000000000 no eth0
197 args[3] = 0; 130 */
198} 131 char pathbuf[IFNAMSIZ + sizeof("/bridge/bridge_id") + 32];
132 int tabs;
133 DIR *ifaces;
134 struct dirent *ent;
135 char *sfx;
136
137#if IFNAMSIZ == 16
138 sfx = pathbuf + sprintf(pathbuf, "%.16s/bridge/", name);
139#else
140 sfx = pathbuf + sprintf(pathbuf, "%.*s/bridge/", (int)IFNAMSIZ, name);
199#endif 141#endif
142 strcpy(sfx, "bridge_id");
143 if (read_file(pathbuf) < 0)
144 return -1; /* this iface is not a bridge */
145
146 if (need_hdr)
147 puts("bridge name\tbridge id\t\tSTP enabled\tinterfaces");
148 printf("%s\t\t", name);
149 printf("%s\t", filedata);
150
151 strcpy(sfx, "stp_state");
152 read_file(pathbuf);
153 if (LONE_CHAR(filedata, '0'))
154 strcpy(filedata, "no");
155 else
156 if (LONE_CHAR(filedata, '1'))
157 strcpy(filedata, "yes");
158 fputs(filedata, stdout);
159
160 strcpy(sfx - (sizeof("bridge/")-1), "brif");
161 tabs = 0;
162 ifaces = opendir(pathbuf);
163 if (ifaces) {
164 while ((ent = readdir(ifaces)) != NULL) {
165 if (DOT_OR_DOTDOT(ent->d_name))
166 continue; /* . or .. */
167 if (tabs)
168 printf("\t\t\t\t\t");
169 else
170 tabs = 1;
171 printf("\t\t%s\n", ent->d_name);
172 }
173 closedir(ifaces);
174 }
175 if (!tabs) /* bridge has no interfaces */
176 bb_putchar('\n');
177 return 0;
178}
200 179
180static void write_uint(const char *name, const char *leaf, unsigned val)
181{
182 char pathbuf[IFNAMSIZ + sizeof("/bridge/bridge_id") + 32];
183 int fd, n;
184
185#if IFNAMSIZ == 16
186 sprintf(pathbuf, "%.16s/%s", name, leaf);
187#else
188 sprintf(pathbuf, "%.*s/%s", (int)IFNAMSIZ, name, leaf);
189#endif
190 fd = xopen(pathbuf, O_WRONLY);
191 n = sprintf(filedata, "%u\n", val);
192 if (write(fd, filedata, n) < 0)
193 bb_simple_perror_msg_and_die(name);
194 close(fd);
195}
201 196
202int brctl_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 197int brctl_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
203int brctl_main(int argc UNUSED_PARAM, char **argv) 198int brctl_main(int argc UNUSED_PARAM, char **argv)
@@ -207,90 +202,71 @@ int brctl_main(int argc UNUSED_PARAM, char **argv)
207 IF_FEATURE_BRCTL_FANCY( 202 IF_FEATURE_BRCTL_FANCY(
208 "stp\0" 203 "stp\0"
209 "setageing\0" "setfd\0" "sethello\0" "setmaxage\0" 204 "setageing\0" "setfd\0" "sethello\0" "setmaxage\0"
210 "setpathcost\0" "setportprio\0" "setbridgeprio\0" 205 "setpathcost\0" "setportprio\0"
206 "setbridgeprio\0"
211 ) 207 )
212 IF_FEATURE_BRCTL_SHOW("show\0"); 208 IF_FEATURE_BRCTL_SHOW("show\0");
213
214 enum { ARG_addbr = 0, ARG_delbr, ARG_addif, ARG_delif 209 enum { ARG_addbr = 0, ARG_delbr, ARG_addif, ARG_delif
215 IF_FEATURE_BRCTL_FANCY(, 210 IF_FEATURE_BRCTL_FANCY(,
216 ARG_stp, 211 ARG_stp,
217 ARG_setageing, ARG_setfd, ARG_sethello, ARG_setmaxage, 212 ARG_setageing, ARG_setfd, ARG_sethello, ARG_setmaxage,
218 ARG_setpathcost, ARG_setportprio, ARG_setbridgeprio 213 ARG_setpathcost, ARG_setportprio,
214 ARG_setbridgeprio
219 ) 215 )
220 IF_FEATURE_BRCTL_SHOW(, ARG_show) 216 IF_FEATURE_BRCTL_SHOW(, ARG_show)
221 }; 217 };
222 218
223 int fd;
224 smallint key;
225 struct ifreq ifr;
226 char *br, *brif;
227
228 argv++; 219 argv++;
229 while (*argv) { 220 if (!*argv) {
230#if ENABLE_FEATURE_BRCTL_FANCY 221 /* bare "brctl" shows --help */
231 int ifidx[MAX_PORTS]; 222 bb_show_usage();
232 unsigned long args[4]; 223 }
233 ifr.ifr_data = (char *) &args; 224
234#endif 225 xchdir("/sys/class/net");
226
227// while (*argv)
228 {
229 smallint key;
230 char *br;
235 231
236 key = index_in_strings(keywords, *argv); 232 key = index_in_strings(keywords, *argv);
237 if (key == -1) /* no match found in keywords array, bail out. */ 233 if (key == -1) /* no match found in keywords array, bail out. */
238 bb_error_msg_and_die(bb_msg_invalid_arg_to, *argv, applet_name); 234 bb_error_msg_and_die(bb_msg_invalid_arg_to, *argv, applet_name);
239 argv++; 235 argv++;
240 fd = xsocket(AF_INET, SOCK_STREAM, 0);
241 236
242#if ENABLE_FEATURE_BRCTL_SHOW 237#if ENABLE_FEATURE_BRCTL_SHOW
243 if (key == ARG_show) { /* show */ 238 if (key == ARG_show) { /* show [BR]... */
244 char buf[IFNAMSIZ]; 239 DIR *net;
245 int bridx[MAX_PORTS]; 240 struct dirent *ent;
246 int i, num; 241 int need_hdr = 1;
247 arm_ioctl(args, BRCTL_GET_BRIDGES, 242 int exitcode = EXIT_SUCCESS;
248 (unsigned long) bridx, MAX_PORTS); 243
249 num = xioctl(fd, SIOCGIFBR, args); 244 if (*argv) {
250 puts("bridge name\tbridge id\t\tSTP enabled\tinterfaces"); 245 /* "show BR1 BR2 BR3" */
251 for (i = 0; i < num; i++) { 246 do {
252 int j, tabs; 247 if (show_bridge(*argv, need_hdr) >= 0) {
253 struct __bridge_info bi; 248 need_hdr = 0;
254 unsigned char *x; 249 } else {
255 250 bb_error_msg("bridge %s does not exist", *argv);
256 if (!if_indextoname(bridx[i], buf)) 251//TODO: if device exists, but is not a BR, brctl from bridge-utils 1.6
257 bb_perror_msg_and_die("can't get bridge name for index %d", i); 252//says this instead: "device eth0 is not a bridge"
258 strncpy_IFNAMSIZ(ifr.ifr_name, buf); 253 exitcode = EXIT_FAILURE;
259 254 }
260 arm_ioctl(args, BRCTL_GET_BRIDGE_INFO, 255 } while (*++argv != NULL);
261 (unsigned long) &bi, 0); 256 return exitcode;
262 xioctl(fd, SIOCDEVPRIVATE, &ifr);
263 printf("%s\t\t", buf);
264
265 /* print bridge id */
266 x = (unsigned char *) &bi.bridge_id;
267 for (j = 0; j < 8; j++) {
268 printf("%02x", x[j]);
269 if (j == 1)
270 bb_putchar('.');
271 }
272 printf(bi.stp_enabled ? "\tyes" : "\tno");
273
274 /* print interface list */
275 arm_ioctl(args, BRCTL_GET_PORT_LIST,
276 (unsigned long) ifidx, MAX_PORTS);
277 xioctl(fd, SIOCDEVPRIVATE, &ifr);
278 tabs = 0;
279 for (j = 0; j < MAX_PORTS; j++) {
280 if (!ifidx[j])
281 continue;
282 if (!if_indextoname(ifidx[j], buf))
283 bb_perror_msg_and_die("can't get interface name for index %d", j);
284 if (tabs)
285 printf("\t\t\t\t\t");
286 else
287 tabs = 1;
288 printf("\t\t%s\n", buf);
289 }
290 if (!tabs) /* bridge has no interfaces */
291 bb_putchar('\n');
292 } 257 }
293 goto done; 258
259 /* "show" (if no ifaces, shows nothing, not even header) */
260 net = xopendir(".");
261 while ((ent = readdir(net)) != NULL) {
262 if (DOT_OR_DOTDOT(ent->d_name))
263 continue; /* . or .. */
264 if (show_bridge(ent->d_name, need_hdr) >= 0)
265 need_hdr = 0;
266 }
267 if (ENABLE_FEATURE_CLEAN_UP)
268 closedir(net);
269 return exitcode;
294 } 270 }
295#endif 271#endif
296 272
@@ -299,28 +275,29 @@ int brctl_main(int argc UNUSED_PARAM, char **argv)
299 275
300 br = *argv++; 276 br = *argv++;
301 277
302 if (key == ARG_addbr || key == ARG_delbr) { /* addbr or delbr */ 278 if (key == ARG_addbr || key == ARG_delbr) {
279 /* addbr or delbr */
280 /* brctl from bridge-utils 1.6 still uses ioctl
281 * for SIOCBRADDBR / SIOCBRDELBR, not /sys accesses
282 */
283 int fd = xsocket(AF_INET, SOCK_STREAM, 0);
303 ioctl_or_perror_and_die(fd, 284 ioctl_or_perror_and_die(fd,
304 key == ARG_addbr ? SIOCBRADDBR : SIOCBRDELBR, 285 key == ARG_addbr ? SIOCBRADDBR : SIOCBRDELBR,
305 br, "bridge %s", br); 286 br, "bridge %s", br
306 goto done; 287 );
288 //close(fd);
289 //goto done;
290 /* bridge-utils 1.6 simply ignores trailing args:
291 * "brctl addbr BR1 ARGS" ignores ARGS
292 */
293 if (ENABLE_FEATURE_CLEAN_UP)
294 close(fd);
295 return EXIT_SUCCESS;
307 } 296 }
308 297
309 if (!*argv) /* all but 'addbr/delbr' need at least two arguments */ 298 if (!*argv) /* all but 'addbr/delbr' need at least two arguments */
310 bb_show_usage(); 299 bb_show_usage();
311 300
312 strncpy_IFNAMSIZ(ifr.ifr_name, br);
313 if (key == ARG_addif || key == ARG_delif) { /* addif or delif */
314 brif = *argv;
315 ifr.ifr_ifindex = if_nametoindex(brif);
316 if (!ifr.ifr_ifindex) {
317 bb_perror_msg_and_die("iface %s", brif);
318 }
319 ioctl_or_perror_and_die(fd,
320 key == ARG_addif ? SIOCBRADDIF : SIOCBRDELIF,
321 &ifr, "bridge %s", br);
322 goto done_next_argv;
323 }
324#if ENABLE_FEATURE_BRCTL_FANCY 301#if ENABLE_FEATURE_BRCTL_FANCY
325 if (key == ARG_stp) { /* stp */ 302 if (key == ARG_stp) { /* stp */
326 static const char no_yes[] ALIGN1 = 303 static const char no_yes[] ALIGN1 =
@@ -330,65 +307,102 @@ int brctl_main(int argc UNUSED_PARAM, char **argv)
330 if (onoff < 0) 307 if (onoff < 0)
331 bb_error_msg_and_die(bb_msg_invalid_arg_to, *argv, applet_name); 308 bb_error_msg_and_die(bb_msg_invalid_arg_to, *argv, applet_name);
332 onoff = (unsigned)onoff / 4; 309 onoff = (unsigned)onoff / 4;
333 arm_ioctl(args, BRCTL_SET_BRIDGE_STP_STATE, onoff, 0); 310 write_uint(br, "bridge/stp_state", onoff);
334 goto fire; 311 //goto done_next_argv;
312 return EXIT_SUCCESS;
335 } 313 }
314
336 if ((unsigned)(key - ARG_setageing) < 4) { /* time related ops */ 315 if ((unsigned)(key - ARG_setageing) < 4) { /* time related ops */
337 static const uint8_t ops[] ALIGN1 = { 316 /* setageing BR N: "N*100\n" to /sys/class/net/BR/bridge/ageing_time
338 BRCTL_SET_AGEING_TIME, /* ARG_setageing */ 317 * setfd BR N: "N*100\n" to /sys/class/net/BR/bridge/forward_delay
339 BRCTL_SET_BRIDGE_FORWARD_DELAY, /* ARG_setfd */ 318 * sethello BR N: "N*100\n" to /sys/class/net/BR/bridge/hello_time
340 BRCTL_SET_BRIDGE_HELLO_TIME, /* ARG_sethello */ 319 * setmaxage BR N: "N*100\n" to /sys/class/net/BR/bridge/max_age
341 BRCTL_SET_BRIDGE_MAX_AGE /* ARG_setmaxage */ 320 */
342 }; 321 write_uint(br,
343 arm_ioctl(args, ops[key - ARG_setageing], str_to_jiffies(*argv), 0); 322 nth_string(
344 goto fire; 323 "bridge/ageing_time" "\0" /* ARG_setageing */
324 "bridge/forward_delay""\0" /* ARG_setfd */
325 "bridge/hello_time" "\0" /* ARG_sethello */
326 "bridge/max_age", /* ARG_setmaxage */
327 key - ARG_setageing
328 ),
329 str_to_jiffies(*argv)
330 );
331 //goto done_next_argv;
332 return EXIT_SUCCESS;
345 } 333 }
334
335 if (key == ARG_setbridgeprio) {
336 write_uint(br, "bridge/priority", xatoi_positive(*argv));
337 //goto done_next_argv;
338 return EXIT_SUCCESS;
339 }
340
346 if (key == ARG_setpathcost 341 if (key == ARG_setpathcost
347 || key == ARG_setportprio 342 || key == ARG_setportprio
348 || key == ARG_setbridgeprio
349 ) { 343 ) {
350 static const uint8_t ops[] ALIGN1 = { 344 if (!argv[1])
351 BRCTL_SET_PATH_COST, /* ARG_setpathcost */ 345 bb_show_usage();
352 BRCTL_SET_PORT_PRIORITY, /* ARG_setportprio */ 346 /* BR is not used (and ignored!) for these commands:
353 BRCTL_SET_BRIDGE_PRIORITY /* ARG_setbridgeprio */ 347 * "setpathcost BR PORT N" writes "N\n" to
354 }; 348 * /sys/class/net/PORT/brport/path_cost
355 int port = -1; 349 * "setportprio BR PORT N" writes "N\n" to
356 unsigned arg1, arg2; 350 * /sys/class/net/PORT/brport/priority
357 351 */
358 if (key != ARG_setbridgeprio) { 352 write_uint(argv[0],
359 /* get portnum */ 353 nth_string(
360 unsigned i; 354 "brport/path_cost" "\0" /* ARG_setpathcost */
361 355 "brport/priority", /* ARG_setportprio */
362 port = if_nametoindex(*argv++); 356 key - ARG_setpathcost
363 if (!port) 357 ),
364 bb_error_msg_and_die(bb_msg_invalid_arg_to, *argv, "port"); 358 xatoi_positive(argv[1])
365 memset(ifidx, 0, sizeof ifidx); 359 );
366 arm_ioctl(args, BRCTL_GET_PORT_LIST, (unsigned long)ifidx, 360 //argv++;
367 MAX_PORTS); 361 //goto done_next_argv;
368 xioctl(fd, SIOCDEVPRIVATE, &ifr); 362 return EXIT_SUCCESS;
369 for (i = 0; i < MAX_PORTS; i++) {
370 if (ifidx[i] == port) {
371 port = i;
372 break;
373 }
374 }
375 }
376 arg1 = port;
377 arg2 = xatoi_positive(*argv);
378 if (key == ARG_setbridgeprio) {
379 arg1 = arg2;
380 arg2 = 0;
381 }
382 arm_ioctl(args, ops[key - ARG_setpathcost], arg1, arg2);
383 } 363 }
384 fire: 364
385 /* Execute the previously set command */ 365/* TODO: "showmacs BR"
386 xioctl(fd, SIOCDEVPRIVATE, &ifr); 366 * port no\tmac addr\t\tis local?\tageing timer
367 * <sp><sp>1\txx:xx:xx:xx:xx:xx\tno\t\t<sp><sp><sp>1.31
368 * port no mac addr is local? ageing timer
369 * 1 xx:xx:xx:xx:xx:xx no 1.31
370 * Read fixed-sized records from /sys/class/net/BR/brforward:
371 * struct __fdb_entry {
372 * uint8_t mac_addr[ETH_ALEN];
373 * uint8_t port_no; //lsb
374 * uint8_t is_local;
375 * uint32_t ageing_timer_value;
376 * uint8_t port_hi;
377 * uint8_t pad0;
378 * uint16_t unused;
379 * };
380 */
387#endif 381#endif
388 done_next_argv: 382 /* always true: if (key == ARG_addif || key == ARG_delif) */ {
389 argv++; 383 /* addif or delif */
390 done: 384 struct ifreq ifr;
391 close(fd); 385 int fd = xsocket(AF_INET, SOCK_STREAM, 0);
386
387 strncpy_IFNAMSIZ(ifr.ifr_name, br);
388 ifr.ifr_ifindex = if_nametoindex(*argv);
389 if (ifr.ifr_ifindex == 0) {
390 bb_perror_msg_and_die("iface %s", *argv);
391 }
392 ioctl_or_perror_and_die(fd,
393 key == ARG_addif ? SIOCBRADDIF : SIOCBRDELIF,
394 &ifr, "bridge %s", br
395 );
396 //close(fd);
397 //goto done_next_argv;
398 if (ENABLE_FEATURE_CLEAN_UP)
399 close(fd);
400 return EXIT_SUCCESS;
401 }
402
403// done_next_argv:
404// argv++;
405// done:
392 } 406 }
393 407
394 return EXIT_SUCCESS; 408 return EXIT_SUCCESS;