1 /* vi: set sw=4 ts=4: */
3 * Small implementation of brctl for busybox.
5 * Copyright (C) 2008 by Bernhard Reutner-Fischer
7 * Some helper functions from bridge-utils are
8 * Copyright (C) 2000 Lennert Buytenhek
10 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
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.
16 #include <linux/sockios.h>
20 # define SIOCBRADDBR BRCTL_ADD_BRIDGE
23 # define SIOCBRDELBR BRCTL_DEL_BRIDGE
26 # define SIOCBRADDIF BRCTL_ADD_IF
29 # define SIOCBRDELIF BRCTL_DEL_IF
33 /* Maximum number of ports supported per bridge interface. */
38 /* Use internal number parsing and not the "exact" conversion. */
39 /* #define BRCTL_USE_INTERNAL 0 */ /* use exact conversion */
40 #define BRCTL_USE_INTERNAL 1
42 #if ENABLE_FEATURE_BRCTL_FANCY
43 #include <linux/if_bridge.h>
45 /* FIXME: These 4 funcs are not really clean and could be improved */
46 static ALWAYS_INLINE
void strtotimeval(struct timeval
*tv
,
50 #if BRCTL_USE_INTERNAL
51 secs
= /*bb_*/strtod(time_str
, NULL
);
54 if (sscanf(time_str
, "%lf", &secs
) != 1)
56 bb_error_msg_and_die (bb_msg_invalid_arg
, time_str
, "timespec");
58 tv
->tv_usec
= 1000000 * (secs
- tv
->tv_sec
);
61 static ALWAYS_INLINE
unsigned long __tv_to_jiffies(const struct timeval
*tv
)
63 unsigned long long jif
;
65 jif
= 1000000ULL * tv
->tv_sec
+ tv
->tv_usec
;
70 static void __jiffies_to_tv(struct timeval
*tv
, unsigned long jiffies
)
72 unsigned long long tvusec
;
74 tvusec
= 10000ULL*jiffies
;
75 tv
->tv_sec
= tvusec
/1000000;
76 tv
->tv_usec
= tvusec
- 1000000 * tv
->tv_sec
;
79 static unsigned long str_to_jiffies(const char *time_str
)
82 strtotimeval(&tv
, time_str
);
83 return __tv_to_jiffies(&tv
);
86 static void arm_ioctl(unsigned long *args
,
87 unsigned long arg0
, unsigned long arg1
, unsigned long arg2
)
97 int brctl_main(int argc
, char **argv
) MAIN_EXTERNALLY_VISIBLE
;
98 int brctl_main(int argc UNUSED_PARAM
, char **argv
)
100 static const char keywords
[] ALIGN1
=
101 "addbr\0" "delbr\0" "addif\0" "delif\0"
102 USE_FEATURE_BRCTL_FANCY(
104 "setageing\0" "setfd\0" "sethello\0" "setmaxage\0"
105 "setpathcost\0" "setportprio\0" "setbridgeprio\0"
107 USE_FEATURE_BRCTL_SHOW("showmacs\0" "show\0");
109 enum { ARG_addbr
= 0, ARG_delbr
, ARG_addif
, ARG_delif
110 USE_FEATURE_BRCTL_FANCY(,
112 ARG_setageing
, ARG_setfd
, ARG_sethello
, ARG_setmaxage
,
113 ARG_setpathcost
, ARG_setportprio
, ARG_setbridgeprio
115 USE_FEATURE_BRCTL_SHOW(, ARG_showmacs
, ARG_show
)
125 #if ENABLE_FEATURE_BRCTL_FANCY
126 int ifidx
[MAX_PORTS
];
127 unsigned long args
[4];
128 ifr
.ifr_data
= (char *) &args
;
131 key
= index_in_strings(keywords
, *argv
);
132 if (key
== -1) /* no match found in keywords array, bail out. */
133 bb_error_msg_and_die(bb_msg_invalid_arg
, *argv
, applet_name
);
135 fd
= xsocket(AF_INET
, SOCK_STREAM
, 0);
137 #if ENABLE_FEATURE_BRCTL_SHOW
138 if (key
== ARG_show
) { /* show */
139 char brname
[IFNAMSIZ
];
140 int bridx
[MAX_PORTS
];
142 arm_ioctl(args
, BRCTL_GET_BRIDGES
,
143 (unsigned long) bridx
, MAX_PORTS
);
144 num
= xioctl(fd
, SIOCGIFBR
, args
);
145 printf("bridge name\tbridge id\t\tSTP enabled\tinterfaces\n");
146 for (i
= 0; i
< num
; i
++) {
147 char ifname
[IFNAMSIZ
];
149 struct __bridge_info bi
;
152 if (!if_indextoname(bridx
[i
], brname
))
153 bb_perror_msg_and_die("can't get bridge name for index %d", i
);
154 strncpy_IFNAMSIZ(ifr
.ifr_name
, brname
);
156 arm_ioctl(args
, BRCTL_GET_BRIDGE_INFO
,
157 (unsigned long) &bi
, 0);
158 xioctl(fd
, SIOCDEVPRIVATE
, &ifr
);
159 printf("%s\t\t", brname
);
161 /* print bridge id */
162 x
= (unsigned char *) &bi
.bridge_id
;
163 for (j
= 0; j
< 8; j
++) {
164 printf("%.2x", x
[j
]);
168 printf(bi
.stp_enabled
? "\tyes" : "\tno");
170 /* print interface list */
171 arm_ioctl(args
, BRCTL_GET_PORT_LIST
,
172 (unsigned long) ifidx
, MAX_PORTS
);
173 xioctl(fd
, SIOCDEVPRIVATE
, &ifr
);
175 for (j
= 0; j
< MAX_PORTS
; j
++) {
178 if (!if_indextoname(ifidx
[j
], ifname
))
179 bb_perror_msg_and_die("can't get interface name for index %d", j
);
181 printf("\t\t\t\t\t");
184 printf("\t\t%s\n", ifname
);
186 if (!tabs
) /* bridge has no interfaces */
193 if (!*argv
) /* all but 'show' need at least one argument */
198 if (key
== ARG_addbr
|| key
== ARG_delbr
) { /* addbr or delbr */
199 ioctl_or_perror_and_die(fd
,
200 key
== ARG_addbr
? SIOCBRADDBR
: SIOCBRDELBR
,
201 br
, "bridge %s", br
);
205 if (!*argv
) /* all but 'addif/delif' need at least two arguments */
208 strncpy_IFNAMSIZ(ifr
.ifr_name
, br
);
209 if (key
== ARG_addif
|| key
== ARG_delif
) { /* addif or delif */
211 ifr
.ifr_ifindex
= if_nametoindex(brif
);
212 if (!ifr
.ifr_ifindex
) {
213 bb_perror_msg_and_die("iface %s", brif
);
215 ioctl_or_perror_and_die(fd
,
216 key
== ARG_addif
? SIOCBRADDIF
: SIOCBRDELIF
,
217 &ifr
, "bridge %s", br
);
220 #if ENABLE_FEATURE_BRCTL_FANCY
221 if (key
== ARG_stp
) { /* stp */
222 /* FIXME: parsing yes/y/on/1 versus no/n/off/0 is too involved */
223 arm_ioctl(args
, BRCTL_SET_BRIDGE_STP_STATE
,
224 (unsigned)(**argv
- '0'), 0);
227 if ((unsigned)(key
- ARG_setageing
) < 4) { /* time related ops */
228 static const uint8_t ops
[] ALIGN1
= {
229 BRCTL_SET_AGEING_TIME
, /* ARG_setageing */
230 BRCTL_SET_BRIDGE_FORWARD_DELAY
, /* ARG_setfd */
231 BRCTL_SET_BRIDGE_HELLO_TIME
, /* ARG_sethello */
232 BRCTL_SET_BRIDGE_MAX_AGE
/* ARG_setmaxage */
234 arm_ioctl(args
, ops
[key
- ARG_setageing
], str_to_jiffies(*argv
), 0);
237 if (key
== ARG_setpathcost
238 || key
== ARG_setportprio
239 || key
== ARG_setbridgeprio
241 static const uint8_t ops
[] ALIGN1
= {
242 BRCTL_SET_PATH_COST
, /* ARG_setpathcost */
243 BRCTL_SET_PORT_PRIORITY
, /* ARG_setportprio */
244 BRCTL_SET_BRIDGE_PRIORITY
/* ARG_setbridgeprio */
249 if (key
!= ARG_setbridgeprio
) {
253 port
= if_nametoindex(*argv
++);
255 bb_error_msg_and_die(bb_msg_invalid_arg
, *argv
, "port");
256 memset(ifidx
, 0, sizeof ifidx
);
257 arm_ioctl(args
, BRCTL_GET_PORT_LIST
, (unsigned long)ifidx
,
259 xioctl(fd
, SIOCDEVPRIVATE
, &ifr
);
260 for (i
= 0; i
< MAX_PORTS
; i
++) {
261 if (ifidx
[i
] == port
) {
268 arg2
= xatoi_u(*argv
);
269 if (key
== ARG_setbridgeprio
) {
273 arm_ioctl(args
, ops
[key
- ARG_setpathcost
], arg1
, arg2
);
276 /* Execute the previously set command */
277 xioctl(fd
, SIOCDEVPRIVATE
, &ifr
);