Bernhard Reutner-Fischer | d27d925 | 2008-01-13 15:23:27 +0000 | [diff] [blame] | 1 | /* vi: set sw=4 ts=4: */ |
| 2 | /* |
| 3 | * Small implementation of brctl for busybox. |
| 4 | * |
Bernhard Reutner-Fischer | 6c4dade | 2008-09-25 12:13:34 +0000 | [diff] [blame] | 5 | * Copyright (C) 2008 by Bernhard Reutner-Fischer |
Bernhard Reutner-Fischer | d27d925 | 2008-01-13 15:23:27 +0000 | [diff] [blame] | 6 | * |
Bernhard Reutner-Fischer | 2b11fb4 | 2008-01-14 16:10:11 +0000 | [diff] [blame] | 7 | * Some helper functions from bridge-utils are |
| 8 | * Copyright (C) 2000 Lennert Buytenhek |
| 9 | * |
Denys Vlasenko | 0ef64bd | 2010-08-16 20:14:46 +0200 | [diff] [blame] | 10 | * Licensed under GPLv2 or later, see file LICENSE in this source tree. |
Bernhard Reutner-Fischer | d27d925 | 2008-01-13 15:23:27 +0000 | [diff] [blame] | 11 | */ |
Denys Vlasenko | 47367e1 | 2016-11-23 09:05:14 +0100 | [diff] [blame] | 12 | //config:config BRCTL |
Denys Vlasenko | 4eed2c6 | 2017-07-18 22:01:24 +0200 | [diff] [blame] | 13 | //config: bool "brctl (4.7 kb)" |
Denys Vlasenko | 47367e1 | 2016-11-23 09:05:14 +0100 | [diff] [blame] | 14 | //config: default y |
| 15 | //config: select PLATFORM_LINUX |
| 16 | //config: help |
Denys Vlasenko | 72089cf | 2017-07-21 09:50:55 +0200 | [diff] [blame] | 17 | //config: Manage ethernet bridges. |
| 18 | //config: Supports addbr/delbr and addif/delif. |
Denys Vlasenko | 47367e1 | 2016-11-23 09:05:14 +0100 | [diff] [blame] | 19 | //config: |
| 20 | //config:config FEATURE_BRCTL_FANCY |
| 21 | //config: bool "Fancy options" |
| 22 | //config: default y |
| 23 | //config: depends on BRCTL |
| 24 | //config: help |
Denys Vlasenko | 72089cf | 2017-07-21 09:50:55 +0200 | [diff] [blame] | 25 | //config: Add support for extended option like: |
| 26 | //config: setageing, setfd, sethello, setmaxage, |
| 27 | //config: setpathcost, setportprio, setbridgeprio, |
| 28 | //config: stp |
| 29 | //config: This adds about 600 bytes. |
Denys Vlasenko | 47367e1 | 2016-11-23 09:05:14 +0100 | [diff] [blame] | 30 | //config: |
| 31 | //config:config FEATURE_BRCTL_SHOW |
| 32 | //config: bool "Support show" |
| 33 | //config: default y |
| 34 | //config: depends on BRCTL && FEATURE_BRCTL_FANCY |
| 35 | //config: help |
Denys Vlasenko | 72089cf | 2017-07-21 09:50:55 +0200 | [diff] [blame] | 36 | //config: Add support for option which prints the current config: |
| 37 | //config: show |
Denys Vlasenko | 47367e1 | 2016-11-23 09:05:14 +0100 | [diff] [blame] | 38 | |
Denys Vlasenko | 86e07f6 | 2017-08-06 20:14:02 +0200 | [diff] [blame] | 39 | //applet:IF_BRCTL(APPLET_NOEXEC(brctl, brctl, BB_DIR_USR_SBIN, BB_SUID_DROP, brctl)) |
Denys Vlasenko | 47367e1 | 2016-11-23 09:05:14 +0100 | [diff] [blame] | 40 | |
| 41 | //kbuild:lib-$(CONFIG_BRCTL) += brctl.o |
Pere Orga | 5bc8c00 | 2011-04-11 03:29:49 +0200 | [diff] [blame] | 42 | |
| 43 | //usage:#define brctl_trivial_usage |
Denys Vlasenko | dc1b2d4 | 2019-04-13 13:58:06 +0200 | [diff] [blame] | 44 | //usage: "COMMAND [BRIDGE [ARGS]]" |
Pere Orga | 5bc8c00 | 2011-04-11 03:29:49 +0200 | [diff] [blame] | 45 | //usage:#define brctl_full_usage "\n\n" |
Denys Vlasenko | 2945822 | 2019-04-13 15:48:31 +0200 | [diff] [blame] | 46 | //usage: "Manage ethernet bridges" |
Pere Orga | 5bc8c00 | 2011-04-11 03:29:49 +0200 | [diff] [blame] | 47 | //usage: "\nCommands:" |
| 48 | //usage: IF_FEATURE_BRCTL_SHOW( |
Denys Vlasenko | dc1b2d4 | 2019-04-13 13:58:06 +0200 | [diff] [blame] | 49 | //usage: "\n show [BRIDGE]... Show bridges" |
Pere Orga | 5bc8c00 | 2011-04-11 03:29:49 +0200 | [diff] [blame] | 50 | //usage: ) |
| 51 | //usage: "\n addbr BRIDGE Create BRIDGE" |
| 52 | //usage: "\n delbr BRIDGE Delete BRIDGE" |
| 53 | //usage: "\n addif BRIDGE IFACE Add IFACE to BRIDGE" |
| 54 | //usage: "\n delif BRIDGE IFACE Delete IFACE from BRIDGE" |
| 55 | //usage: IF_FEATURE_BRCTL_FANCY( |
Denys Vlasenko | eb13951 | 2019-10-12 19:51:46 +0200 | [diff] [blame] | 56 | //usage: "\n showmacs BRIDGE List MAC addresses" |
Denys Vlasenko | 3398753 | 2019-10-12 19:24:38 +0200 | [diff] [blame] | 57 | //usage: "\n showstp BRIDGE Show STP info" |
Denys Vlasenko | eb13951 | 2019-10-12 19:51:46 +0200 | [diff] [blame] | 58 | //usage: "\n stp BRIDGE 1/yes/on|0/no/off Set STP on/off" |
Denys Vlasenko | dc1b2d4 | 2019-04-13 13:58:06 +0200 | [diff] [blame] | 59 | //usage: "\n setageing BRIDGE SECONDS Set ageing time" |
| 60 | //usage: "\n setfd BRIDGE SECONDS Set bridge forward delay" |
| 61 | //usage: "\n sethello BRIDGE SECONDS Set hello time" |
| 62 | //usage: "\n setmaxage BRIDGE SECONDS Set max message age" |
Pere Orga | 5bc8c00 | 2011-04-11 03:29:49 +0200 | [diff] [blame] | 63 | //usage: "\n setbridgeprio BRIDGE PRIO Set bridge priority" |
Denys Vlasenko | dc1b2d4 | 2019-04-13 13:58:06 +0200 | [diff] [blame] | 64 | //usage: "\n setportprio BRIDGE IFACE PRIO Set port priority" |
| 65 | //usage: "\n setpathcost BRIDGE IFACE COST Set path cost" |
Pere Orga | 5bc8c00 | 2011-04-11 03:29:49 +0200 | [diff] [blame] | 66 | //usage: ) |
Denys Vlasenko | dc1b2d4 | 2019-04-13 13:58:06 +0200 | [diff] [blame] | 67 | // Not yet implemented: |
Denys Vlasenko | eb13951 | 2019-10-12 19:51:46 +0200 | [diff] [blame] | 68 | // hairpin BRIDGE IFACE on|off Set hairpin on/off |
Martin Lewis | 6dcf563 | 2019-10-10 16:00:19 -0500 | [diff] [blame] | 69 | |
Bernhard Reutner-Fischer | d27d925 | 2008-01-13 15:23:27 +0000 | [diff] [blame] | 70 | #include "libbb.h" |
Denys Vlasenko | c5150e9 | 2019-04-12 18:52:31 +0200 | [diff] [blame] | 71 | #include "common_bufsiz.h" |
Bernhard Reutner-Fischer | d27d925 | 2008-01-13 15:23:27 +0000 | [diff] [blame] | 72 | #include <linux/sockios.h> |
| 73 | #include <net/if.h> |
| 74 | |
Denis Vlasenko | 802cab1 | 2009-01-31 20:08:21 +0000 | [diff] [blame] | 75 | #ifndef SIOCBRADDBR |
| 76 | # define SIOCBRADDBR BRCTL_ADD_BRIDGE |
| 77 | #endif |
| 78 | #ifndef SIOCBRDELBR |
| 79 | # define SIOCBRDELBR BRCTL_DEL_BRIDGE |
| 80 | #endif |
| 81 | #ifndef SIOCBRADDIF |
| 82 | # define SIOCBRADDIF BRCTL_ADD_IF |
| 83 | #endif |
| 84 | #ifndef SIOCBRDELIF |
| 85 | # define SIOCBRDELIF BRCTL_DEL_IF |
| 86 | #endif |
| 87 | |
Bernhard Reutner-Fischer | 1aac3ab | 2008-01-13 18:43:50 +0000 | [diff] [blame] | 88 | #if ENABLE_FEATURE_BRCTL_FANCY |
Denys Vlasenko | 9435608 | 2019-04-13 14:17:55 +0200 | [diff] [blame] | 89 | static unsigned str_to_jiffies(const char *time_str) |
Bernhard Reutner-Fischer | 1aac3ab | 2008-01-13 18:43:50 +0000 | [diff] [blame] | 90 | { |
Denys Vlasenko | 9435608 | 2019-04-13 14:17:55 +0200 | [diff] [blame] | 91 | double dd; |
Maciek Borzecki | 46abfc0 | 2010-03-16 12:41:29 +0100 | [diff] [blame] | 92 | char *endptr; |
Denys Vlasenko | 9435608 | 2019-04-13 14:17:55 +0200 | [diff] [blame] | 93 | dd = /*bb_*/strtod(time_str, &endptr); |
| 94 | if (endptr == time_str || dd < 0) |
Denys Vlasenko | 0f296a3 | 2015-10-14 13:21:01 +0200 | [diff] [blame] | 95 | bb_error_msg_and_die(bb_msg_invalid_arg_to, time_str, "timespec"); |
Bernhard Reutner-Fischer | 1aac3ab | 2008-01-13 18:43:50 +0000 | [diff] [blame] | 96 | |
Denys Vlasenko | 9435608 | 2019-04-13 14:17:55 +0200 | [diff] [blame] | 97 | dd *= 100; |
| 98 | /* For purposes of brctl, |
| 99 | * capping SECONDS by ~20 million seconds is quite enough: |
| 100 | */ |
| 101 | if (dd > INT_MAX) |
| 102 | dd = INT_MAX; |
Bernhard Reutner-Fischer | 1aac3ab | 2008-01-13 18:43:50 +0000 | [diff] [blame] | 103 | |
Denys Vlasenko | 9435608 | 2019-04-13 14:17:55 +0200 | [diff] [blame] | 104 | return dd; |
Bernhard Reutner-Fischer | 1aac3ab | 2008-01-13 18:43:50 +0000 | [diff] [blame] | 105 | } |
Bernhard Reutner-Fischer | d27d925 | 2008-01-13 15:23:27 +0000 | [diff] [blame] | 106 | #endif |
| 107 | |
Denys Vlasenko | c5150e9 | 2019-04-12 18:52:31 +0200 | [diff] [blame] | 108 | #define filedata bb_common_bufsiz1 |
Denys Vlasenko | dc1b2d4 | 2019-04-13 13:58:06 +0200 | [diff] [blame] | 109 | |
Denys Vlasenko | 04a0b7f | 2019-06-08 12:58:16 +0200 | [diff] [blame] | 110 | #if ENABLE_FEATURE_BRCTL_SHOW |
Denys Vlasenko | c5150e9 | 2019-04-12 18:52:31 +0200 | [diff] [blame] | 111 | static int read_file(const char *name) |
| 112 | { |
| 113 | int n = open_read_close(name, filedata, COMMON_BUFSIZE - 1); |
| 114 | if (n < 0) { |
| 115 | filedata[0] = '\0'; |
| 116 | } else { |
| 117 | filedata[n] = '\0'; |
| 118 | if (n != 0 && filedata[n - 1] == '\n') |
| 119 | filedata[--n] = '\0'; |
| 120 | } |
| 121 | return n; |
| 122 | } |
| 123 | |
| 124 | /* NB: we are in /sys/class/net |
| 125 | */ |
| 126 | static int show_bridge(const char *name, int need_hdr) |
| 127 | { |
Denys Vlasenko | dc1b2d4 | 2019-04-13 13:58:06 +0200 | [diff] [blame] | 128 | /* Output: |
| 129 | *bridge name bridge id STP enabled interfaces |
| 130 | *br0 8000.000000000000 no eth0 |
| 131 | */ |
Denys Vlasenko | 3398753 | 2019-10-12 19:24:38 +0200 | [diff] [blame] | 132 | char pathbuf[IFNAMSIZ + sizeof("/bridge/bridge_id") + 8]; |
Denys Vlasenko | c5150e9 | 2019-04-12 18:52:31 +0200 | [diff] [blame] | 133 | int tabs; |
| 134 | DIR *ifaces; |
| 135 | struct dirent *ent; |
| 136 | char *sfx; |
| 137 | |
Denys Vlasenko | dc1b2d4 | 2019-04-13 13:58:06 +0200 | [diff] [blame] | 138 | #if IFNAMSIZ == 16 |
| 139 | sfx = pathbuf + sprintf(pathbuf, "%.16s/bridge/", name); |
| 140 | #else |
| 141 | sfx = pathbuf + sprintf(pathbuf, "%.*s/bridge/", (int)IFNAMSIZ, name); |
| 142 | #endif |
Denys Vlasenko | c5150e9 | 2019-04-12 18:52:31 +0200 | [diff] [blame] | 143 | strcpy(sfx, "bridge_id"); |
| 144 | if (read_file(pathbuf) < 0) |
| 145 | return -1; /* this iface is not a bridge */ |
| 146 | |
| 147 | if (need_hdr) |
| 148 | puts("bridge name\tbridge id\t\tSTP enabled\tinterfaces"); |
Martin Lewis | 6dcf563 | 2019-10-10 16:00:19 -0500 | [diff] [blame] | 149 | printf("%s\t\t%s\t", name, filedata); |
Denys Vlasenko | c5150e9 | 2019-04-12 18:52:31 +0200 | [diff] [blame] | 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"); |
Denys Vlasenko | dc1b2d4 | 2019-04-13 13:58:06 +0200 | [diff] [blame] | 158 | fputs(filedata, stdout); |
Denys Vlasenko | c5150e9 | 2019-04-12 18:52:31 +0200 | [diff] [blame] | 159 | |
Denys Vlasenko | 37a9008 | 2019-10-15 12:31:54 +0200 | [diff] [blame^] | 160 | /* sfx points past "BR/bridge/", turn it into "BR/brif": */ |
| 161 | sfx[-4] = 'f'; sfx[-3] = '\0'; |
Denys Vlasenko | c5150e9 | 2019-04-12 18:52:31 +0200 | [diff] [blame] | 162 | tabs = 0; |
| 163 | ifaces = opendir(pathbuf); |
| 164 | if (ifaces) { |
| 165 | while ((ent = readdir(ifaces)) != NULL) { |
Denys Vlasenko | dc1b2d4 | 2019-04-13 13:58:06 +0200 | [diff] [blame] | 166 | if (DOT_OR_DOTDOT(ent->d_name)) |
| 167 | continue; /* . or .. */ |
Denys Vlasenko | c5150e9 | 2019-04-12 18:52:31 +0200 | [diff] [blame] | 168 | if (tabs) |
| 169 | printf("\t\t\t\t\t"); |
| 170 | else |
| 171 | tabs = 1; |
| 172 | printf("\t\t%s\n", ent->d_name); |
| 173 | } |
| 174 | closedir(ifaces); |
| 175 | } |
| 176 | if (!tabs) /* bridge has no interfaces */ |
| 177 | bb_putchar('\n'); |
| 178 | return 0; |
| 179 | } |
Denys Vlasenko | 3e463e1 | 2019-06-08 12:35:06 +0200 | [diff] [blame] | 180 | #endif |
Bernhard Reutner-Fischer | 1aac3ab | 2008-01-13 18:43:50 +0000 | [diff] [blame] | 181 | |
Denys Vlasenko | 3e463e1 | 2019-06-08 12:35:06 +0200 | [diff] [blame] | 182 | #if ENABLE_FEATURE_BRCTL_FANCY |
Denys Vlasenko | 9435608 | 2019-04-13 14:17:55 +0200 | [diff] [blame] | 183 | static void write_uint(const char *name, const char *leaf, unsigned val) |
Denys Vlasenko | dc1b2d4 | 2019-04-13 13:58:06 +0200 | [diff] [blame] | 184 | { |
| 185 | char pathbuf[IFNAMSIZ + sizeof("/bridge/bridge_id") + 32]; |
| 186 | int fd, n; |
| 187 | |
| 188 | #if IFNAMSIZ == 16 |
| 189 | sprintf(pathbuf, "%.16s/%s", name, leaf); |
| 190 | #else |
| 191 | sprintf(pathbuf, "%.*s/%s", (int)IFNAMSIZ, name, leaf); |
| 192 | #endif |
| 193 | fd = xopen(pathbuf, O_WRONLY); |
Denys Vlasenko | 9435608 | 2019-04-13 14:17:55 +0200 | [diff] [blame] | 194 | n = sprintf(filedata, "%u\n", val); |
Denys Vlasenko | dc1b2d4 | 2019-04-13 13:58:06 +0200 | [diff] [blame] | 195 | if (write(fd, filedata, n) < 0) |
| 196 | bb_simple_perror_msg_and_die(name); |
Denys Vlasenko | 3398753 | 2019-10-12 19:24:38 +0200 | [diff] [blame] | 197 | /* So far all callers exit very soon after calling us. |
| 198 | * Do not bother closing fd (unless debugging): |
| 199 | */ |
| 200 | if (ENABLE_FEATURE_CLEAN_UP) |
| 201 | close(fd); |
Denys Vlasenko | dc1b2d4 | 2019-04-13 13:58:06 +0200 | [diff] [blame] | 202 | } |
Martin Lewis | 6c1af28 | 2019-09-15 18:04:49 +0200 | [diff] [blame] | 203 | |
| 204 | struct fdb_entry { |
| 205 | uint8_t mac_addr[6]; |
| 206 | uint8_t port_no; |
| 207 | uint8_t is_local; |
| 208 | uint32_t ageing_timer_value; |
| 209 | uint8_t port_hi; |
| 210 | uint8_t pad0; |
| 211 | uint16_t unused; |
| 212 | }; |
| 213 | |
| 214 | static int compare_fdbs(const void *_f0, const void *_f1) |
| 215 | { |
| 216 | const struct fdb_entry *f0 = _f0; |
| 217 | const struct fdb_entry *f1 = _f1; |
| 218 | |
| 219 | return memcmp(f0->mac_addr, f1->mac_addr, 6); |
| 220 | } |
| 221 | |
| 222 | static size_t read_bridge_forward_db(const char *name, struct fdb_entry **_fdb) |
| 223 | { |
Denys Vlasenko | 3398753 | 2019-10-12 19:24:38 +0200 | [diff] [blame] | 224 | char pathbuf[IFNAMSIZ + sizeof("/brforward") + 8]; |
Martin Lewis | 6c1af28 | 2019-09-15 18:04:49 +0200 | [diff] [blame] | 225 | struct fdb_entry *fdb; |
| 226 | size_t nentries; |
Martin Lewis | 6c1af28 | 2019-09-15 18:04:49 +0200 | [diff] [blame] | 227 | int fd; |
| 228 | ssize_t cc; |
| 229 | |
Denys Vlasenko | 3398753 | 2019-10-12 19:24:38 +0200 | [diff] [blame] | 230 | #if IFNAMSIZ == 16 |
| 231 | sprintf(pathbuf, "%.16s/brforward", name); |
| 232 | #else |
| 233 | sprintf(pathbuf, "%.*s/brforward", (int)IFNAMSIZ, name); |
| 234 | #endif |
| 235 | fd = open(pathbuf, O_RDONLY); |
Martin Lewis | 6c1af28 | 2019-09-15 18:04:49 +0200 | [diff] [blame] | 236 | if (fd < 0) |
| 237 | bb_error_msg_and_die("bridge %s does not exist", name); |
| 238 | |
| 239 | fdb = NULL; |
| 240 | nentries = 0; |
| 241 | for (;;) { |
| 242 | fdb = xrealloc_vector(fdb, 4, nentries); |
| 243 | cc = full_read(fd, &fdb[nentries], sizeof(*fdb)); |
| 244 | if (cc == 0) { |
| 245 | break; |
| 246 | } |
| 247 | if (cc != sizeof(*fdb)) { |
| 248 | bb_perror_msg_and_die("can't read bridge %s forward db", name); |
| 249 | } |
| 250 | ++nentries; |
| 251 | } |
| 252 | |
Denys Vlasenko | 3398753 | 2019-10-12 19:24:38 +0200 | [diff] [blame] | 253 | if (ENABLE_FEATURE_CLEAN_UP) |
| 254 | close(fd); |
Martin Lewis | 6c1af28 | 2019-09-15 18:04:49 +0200 | [diff] [blame] | 255 | |
| 256 | qsort(fdb, nentries, sizeof(*fdb), compare_fdbs); |
| 257 | |
| 258 | *_fdb = fdb; |
| 259 | return nentries; |
| 260 | } |
| 261 | |
| 262 | static void show_bridge_macs(const char *name) |
| 263 | { |
| 264 | struct fdb_entry *fdb; |
| 265 | size_t nentries; |
| 266 | size_t i; |
| 267 | |
| 268 | nentries = read_bridge_forward_db(name, &fdb); |
| 269 | |
| 270 | printf("port no\tmac addr\t\tis local?\tageing timer\n"); |
| 271 | for (i = 0; i < nentries; ++i) { |
| 272 | const struct fdb_entry *f = &fdb[i]; |
Denys Vlasenko | 3398753 | 2019-10-12 19:24:38 +0200 | [diff] [blame] | 273 | unsigned tv_sec = f->ageing_timer_value / 100; |
| 274 | unsigned tv_csec = f->ageing_timer_value % 100; |
Martin Lewis | 6c1af28 | 2019-09-15 18:04:49 +0200 | [diff] [blame] | 275 | printf("%3u\t" |
| 276 | "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x\t" |
| 277 | "%s\t\t" |
| 278 | "%4u.%.2u\n", |
| 279 | f->port_no, |
| 280 | f->mac_addr[0], f->mac_addr[1], f->mac_addr[2], |
| 281 | f->mac_addr[3], f->mac_addr[4], f->mac_addr[5], |
| 282 | (f->is_local ? "yes" : "no"), |
Denys Vlasenko | 3398753 | 2019-10-12 19:24:38 +0200 | [diff] [blame] | 283 | tv_sec, tv_csec |
Martin Lewis | 6c1af28 | 2019-09-15 18:04:49 +0200 | [diff] [blame] | 284 | ); |
| 285 | } |
| 286 | |
Denys Vlasenko | 3398753 | 2019-10-12 19:24:38 +0200 | [diff] [blame] | 287 | if (ENABLE_FEATURE_CLEAN_UP) |
| 288 | free(fdb); |
Martin Lewis | 6c1af28 | 2019-09-15 18:04:49 +0200 | [diff] [blame] | 289 | } |
Martin Lewis | 6dcf563 | 2019-10-10 16:00:19 -0500 | [diff] [blame] | 290 | |
| 291 | static void show_bridge_timer(const char *msg) |
| 292 | { |
Denys Vlasenko | 3398753 | 2019-10-12 19:24:38 +0200 | [diff] [blame] | 293 | unsigned long long centisec = xstrtoull(filedata, 0); |
| 294 | unsigned tv_sec = centisec / 100; |
| 295 | unsigned tv_csec = centisec % 100; |
| 296 | printf("%s%4u.%.2u", msg, tv_sec, tv_csec); |
Martin Lewis | 6dcf563 | 2019-10-10 16:00:19 -0500 | [diff] [blame] | 297 | } |
| 298 | |
| 299 | static const char *show_bridge_state(unsigned state) |
| 300 | { |
| 301 | /* See linux/if_bridge.h, BR_STATE_ constants */ |
Denys Vlasenko | 3398753 | 2019-10-12 19:24:38 +0200 | [diff] [blame] | 302 | static const char state_names[] ALIGN1 = |
Martin Lewis | 6dcf563 | 2019-10-10 16:00:19 -0500 | [diff] [blame] | 303 | "disabled\0" //BR_STATE_DISABLED 0 |
| 304 | "listening\0" //BR_STATE_LISTENING 1 |
| 305 | "learning\0" //BR_STATE_LEARNING 2 |
| 306 | "forwarding\0" //BR_STATE_FORWARDING 3 |
| 307 | "blocking" //BR_STATE_BLOCKING 4 |
| 308 | ; |
| 309 | if (state < 5) |
| 310 | return nth_string(state_names, state); |
| 311 | return utoa(state); |
| 312 | } |
| 313 | |
| 314 | static void printf_xstrtou(const char *fmt) |
| 315 | { |
| 316 | printf(fmt, xstrtou(filedata, 0)); |
| 317 | } |
| 318 | |
| 319 | static void show_bridge_port(const char *name) |
| 320 | { |
Denys Vlasenko | 3398753 | 2019-10-12 19:24:38 +0200 | [diff] [blame] | 321 | char pathbuf[IFNAMSIZ + sizeof("/brport/forward_delay_timer") + 8]; |
Martin Lewis | 6dcf563 | 2019-10-10 16:00:19 -0500 | [diff] [blame] | 322 | char *sfx; |
| 323 | |
| 324 | #if IFNAMSIZ == 16 |
| 325 | sfx = pathbuf + sprintf(pathbuf, "%.16s/brport/", name); |
| 326 | #else |
| 327 | sfx = pathbuf + sprintf(pathbuf, "%.*s/brport/", (int)IFNAMSIZ, name); |
| 328 | #endif |
| 329 | |
| 330 | strcpy(sfx, "port_no"); |
| 331 | read_file(pathbuf); |
| 332 | printf("%s (%u)\n", name, xstrtou(filedata, 0)); |
| 333 | |
| 334 | strcpy(sfx + 5, "id"); // "port_id" |
| 335 | read_file(pathbuf); |
| 336 | printf_xstrtou(" port id\t\t%.4x"); |
| 337 | |
| 338 | strcpy(sfx, "state"); |
| 339 | read_file(pathbuf); |
| 340 | printf("\t\t\tstate\t\t%15s\n", show_bridge_state(xstrtou(filedata, 0))); |
| 341 | |
| 342 | strcpy(sfx, "designated_root"); |
| 343 | read_file(pathbuf); |
| 344 | printf(" designated root\t%s", filedata); |
| 345 | |
| 346 | strcpy(sfx, "path_cost"); |
| 347 | read_file(pathbuf); |
| 348 | printf_xstrtou("\tpath cost\t\t%4u\n"); |
| 349 | |
| 350 | strcpy(sfx, "designated_bridge"); |
| 351 | read_file(pathbuf); |
| 352 | printf(" designated bridge\t%s", filedata); |
| 353 | |
| 354 | strcpy(sfx, "message_age_timer"); |
| 355 | read_file(pathbuf); |
| 356 | show_bridge_timer("\tmessage age timer\t"); |
| 357 | |
| 358 | strcpy(sfx, "designated_port"); |
| 359 | read_file(pathbuf); |
| 360 | printf_xstrtou("\n designated port\t%.4x"); |
| 361 | |
| 362 | strcpy(sfx, "forward_delay_timer"); |
| 363 | read_file(pathbuf); |
| 364 | show_bridge_timer("\t\t\tforward delay timer\t"); |
| 365 | |
| 366 | strcpy(sfx, "designated_cost"); |
| 367 | read_file(pathbuf); |
| 368 | printf_xstrtou("\n designated cost\t%4u"); |
| 369 | |
| 370 | strcpy(sfx, "hold_timer"); |
| 371 | read_file(pathbuf); |
| 372 | show_bridge_timer("\t\t\thold timer\t\t"); |
| 373 | |
| 374 | printf("\n flags\t\t\t"); |
| 375 | |
| 376 | strcpy(sfx, "config_pending"); |
| 377 | read_file(pathbuf); |
| 378 | if (!LONE_CHAR(filedata, '0')) |
| 379 | printf("CONFIG_PENDING "); |
| 380 | |
| 381 | strcpy(sfx, "change_ack"); |
| 382 | read_file(pathbuf); |
| 383 | if (!LONE_CHAR(filedata, '0')) |
| 384 | printf("TOPOLOGY_CHANGE_ACK "); |
| 385 | |
| 386 | strcpy(sfx, "hairpin_mode"); |
| 387 | read_file(pathbuf); |
| 388 | if (!LONE_CHAR(filedata, '0')) |
| 389 | printf_xstrtou("\n hairpin mode\t\t%4u"); |
| 390 | |
| 391 | printf("\n\n"); |
| 392 | } |
| 393 | |
Martin Lewis | 6dcf563 | 2019-10-10 16:00:19 -0500 | [diff] [blame] | 394 | static void show_bridge_stp(const char *name) |
| 395 | { |
Denys Vlasenko | 3398753 | 2019-10-12 19:24:38 +0200 | [diff] [blame] | 396 | char pathbuf[IFNAMSIZ + sizeof("/bridge/topology_change_timer") + 8]; |
Martin Lewis | 6dcf563 | 2019-10-10 16:00:19 -0500 | [diff] [blame] | 397 | char *sfx; |
| 398 | |
| 399 | #if IFNAMSIZ == 16 |
| 400 | sfx = pathbuf + sprintf(pathbuf, "%.16s/bridge/", name); |
| 401 | #else |
| 402 | sfx = pathbuf + sprintf(pathbuf, "%.*s/bridge/", (int)IFNAMSIZ, name); |
| 403 | #endif |
| 404 | |
| 405 | strcpy(sfx, "bridge_id"); |
| 406 | if (read_file(pathbuf) < 0) |
| 407 | bb_error_msg_and_die("bridge %s does not exist", name); |
| 408 | |
| 409 | printf("%s\n" |
| 410 | " bridge id\t\t%s", name, filedata); |
| 411 | |
| 412 | strcpy(sfx, "root_id"); |
| 413 | read_file(pathbuf); |
| 414 | printf("\n designated root\t%s", filedata); |
| 415 | |
| 416 | strcpy(sfx + 5, "port"); // "root_port" |
| 417 | read_file(pathbuf); |
| 418 | printf_xstrtou("\n root port\t\t%4u\t\t\t"); |
| 419 | |
| 420 | strcpy(sfx + 6, "ath_cost"); // "root_path_cost" |
| 421 | read_file(pathbuf); |
| 422 | printf_xstrtou("path cost\t\t%4u\n"); |
| 423 | |
| 424 | strcpy(sfx, "max_age"); |
| 425 | read_file(pathbuf); |
| 426 | show_bridge_timer(" max age\t\t"); |
| 427 | show_bridge_timer("\t\t\tbridge max age\t\t"); |
| 428 | |
| 429 | strcpy(sfx, "hello_time"); |
| 430 | read_file(pathbuf); |
| 431 | show_bridge_timer("\n hello time\t\t"); |
| 432 | show_bridge_timer("\t\t\tbridge hello time\t"); |
| 433 | |
| 434 | strcpy(sfx, "forward_delay"); |
| 435 | read_file(pathbuf); |
| 436 | show_bridge_timer("\n forward delay\t\t"); |
| 437 | show_bridge_timer("\t\t\tbridge forward delay\t"); |
| 438 | |
| 439 | strcpy(sfx, "ageing_time"); |
| 440 | read_file(pathbuf); |
| 441 | show_bridge_timer("\n ageing time\t\t"); |
| 442 | |
| 443 | strcpy(sfx, "hello_timer"); |
| 444 | read_file(pathbuf); |
| 445 | show_bridge_timer("\n hello timer\t\t"); |
| 446 | |
| 447 | strcpy(sfx, "tcn_timer"); |
| 448 | read_file(pathbuf); |
| 449 | show_bridge_timer("\t\t\ttcn timer\t\t"); |
| 450 | |
| 451 | strcpy(sfx, "topology_change_timer"); |
| 452 | read_file(pathbuf); |
| 453 | show_bridge_timer("\n topology change timer\t"); |
| 454 | |
| 455 | strcpy(sfx, "gc_timer"); |
| 456 | read_file(pathbuf); |
| 457 | show_bridge_timer("\t\t\tgc timer\t\t"); |
| 458 | |
| 459 | printf("\n flags\t\t\t"); |
| 460 | |
| 461 | strcpy(sfx, "topology_change"); |
| 462 | read_file(pathbuf); |
| 463 | if (!LONE_CHAR(filedata, '0')) |
| 464 | printf("TOPOLOGY_CHANGE "); |
| 465 | |
| 466 | strcpy(sfx, "topology_change_detected"); |
| 467 | read_file(pathbuf); |
| 468 | if (!LONE_CHAR(filedata, '0')) |
| 469 | printf("TOPOLOGY_CHANGE_DETECTED "); |
| 470 | printf("\n\n\n"); |
| 471 | |
Denys Vlasenko | b4fa16d | 2019-10-12 19:42:37 +0200 | [diff] [blame] | 472 | /* Show bridge ports */ |
| 473 | { |
| 474 | DIR *ifaces; |
| 475 | |
Denys Vlasenko | 37a9008 | 2019-10-15 12:31:54 +0200 | [diff] [blame^] | 476 | /* sfx points past "BR/bridge/", turn it into "BR/brif": */ |
| 477 | sfx[-4] = 'f'; sfx[-3] = '\0'; |
Denys Vlasenko | b4fa16d | 2019-10-12 19:42:37 +0200 | [diff] [blame] | 478 | ifaces = opendir(pathbuf); |
| 479 | if (ifaces) { |
| 480 | struct dirent *ent; |
| 481 | while ((ent = readdir(ifaces)) != NULL) { |
| 482 | if (DOT_OR_DOTDOT(ent->d_name)) |
| 483 | continue; /* . or .. */ |
| 484 | show_bridge_port(ent->d_name); |
| 485 | } |
| 486 | if (ENABLE_FEATURE_CLEAN_UP) |
| 487 | closedir(ifaces); |
| 488 | } |
| 489 | } |
Martin Lewis | 6dcf563 | 2019-10-10 16:00:19 -0500 | [diff] [blame] | 490 | } |
Denys Vlasenko | 3e463e1 | 2019-06-08 12:35:06 +0200 | [diff] [blame] | 491 | #endif |
Denys Vlasenko | dc1b2d4 | 2019-04-13 13:58:06 +0200 | [diff] [blame] | 492 | |
Denis Vlasenko | d0a071a | 2008-03-17 09:33:45 +0000 | [diff] [blame] | 493 | int brctl_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
Denis Vlasenko | a60f84e | 2008-07-05 09:18:54 +0000 | [diff] [blame] | 494 | int brctl_main(int argc UNUSED_PARAM, char **argv) |
Bernhard Reutner-Fischer | d27d925 | 2008-01-13 15:23:27 +0000 | [diff] [blame] | 495 | { |
Bernhard Reutner-Fischer | d27d925 | 2008-01-13 15:23:27 +0000 | [diff] [blame] | 496 | static const char keywords[] ALIGN1 = |
| 497 | "addbr\0" "delbr\0" "addif\0" "delif\0" |
Denis Vlasenko | 5e34ff2 | 2009-04-21 11:09:40 +0000 | [diff] [blame] | 498 | IF_FEATURE_BRCTL_FANCY( |
Bernhard Reutner-Fischer | 2b11fb4 | 2008-01-14 16:10:11 +0000 | [diff] [blame] | 499 | "stp\0" |
Martin Lewis | 6dcf563 | 2019-10-10 16:00:19 -0500 | [diff] [blame] | 500 | "showstp\0" |
Bernhard Reutner-Fischer | 1aac3ab | 2008-01-13 18:43:50 +0000 | [diff] [blame] | 501 | "setageing\0" "setfd\0" "sethello\0" "setmaxage\0" |
Denys Vlasenko | dc1b2d4 | 2019-04-13 13:58:06 +0200 | [diff] [blame] | 502 | "setpathcost\0" "setportprio\0" |
| 503 | "setbridgeprio\0" |
Martin Lewis | 6c1af28 | 2019-09-15 18:04:49 +0200 | [diff] [blame] | 504 | "showmacs\0" |
Bernhard Reutner-Fischer | 1aac3ab | 2008-01-13 18:43:50 +0000 | [diff] [blame] | 505 | ) |
Nicolas Thill | f47ce07 | 2012-09-25 14:06:01 +0200 | [diff] [blame] | 506 | IF_FEATURE_BRCTL_SHOW("show\0"); |
Bernhard Reutner-Fischer | 1aac3ab | 2008-01-13 18:43:50 +0000 | [diff] [blame] | 507 | enum { ARG_addbr = 0, ARG_delbr, ARG_addif, ARG_delif |
Denis Vlasenko | 5e34ff2 | 2009-04-21 11:09:40 +0000 | [diff] [blame] | 508 | IF_FEATURE_BRCTL_FANCY(, |
Denys Vlasenko | 60cb48c | 2013-01-14 15:57:44 +0100 | [diff] [blame] | 509 | ARG_stp, |
Martin Lewis | 6dcf563 | 2019-10-10 16:00:19 -0500 | [diff] [blame] | 510 | ARG_showstp, |
Denys Vlasenko | 60cb48c | 2013-01-14 15:57:44 +0100 | [diff] [blame] | 511 | ARG_setageing, ARG_setfd, ARG_sethello, ARG_setmaxage, |
Denys Vlasenko | dc1b2d4 | 2019-04-13 13:58:06 +0200 | [diff] [blame] | 512 | ARG_setpathcost, ARG_setportprio, |
Martin Lewis | 6c1af28 | 2019-09-15 18:04:49 +0200 | [diff] [blame] | 513 | ARG_setbridgeprio, |
| 514 | ARG_showmacs |
Bernhard Reutner-Fischer | 1aac3ab | 2008-01-13 18:43:50 +0000 | [diff] [blame] | 515 | ) |
Nicolas Thill | f47ce07 | 2012-09-25 14:06:01 +0200 | [diff] [blame] | 516 | IF_FEATURE_BRCTL_SHOW(, ARG_show) |
Denis Vlasenko | d0a071a | 2008-03-17 09:33:45 +0000 | [diff] [blame] | 517 | }; |
Denys Vlasenko | b4fa16d | 2019-10-12 19:42:37 +0200 | [diff] [blame] | 518 | int key; |
| 519 | char *br; |
Denis Vlasenko | d0a071a | 2008-03-17 09:33:45 +0000 | [diff] [blame] | 520 | |
Bernhard Reutner-Fischer | d27d925 | 2008-01-13 15:23:27 +0000 | [diff] [blame] | 521 | argv++; |
Denys Vlasenko | c5150e9 | 2019-04-12 18:52:31 +0200 | [diff] [blame] | 522 | if (!*argv) { |
| 523 | /* bare "brctl" shows --help */ |
| 524 | bb_show_usage(); |
| 525 | } |
| 526 | |
| 527 | xchdir("/sys/class/net"); |
| 528 | |
Denys Vlasenko | b4fa16d | 2019-10-12 19:42:37 +0200 | [diff] [blame] | 529 | key = index_in_strings(keywords, *argv); |
| 530 | if (key == -1) /* no match found in keywords array, bail out. */ |
| 531 | bb_error_msg_and_die(bb_msg_invalid_arg_to, *argv, applet_name); |
| 532 | argv++; |
Denis Vlasenko | 278a1c2 | 2008-04-06 07:17:02 +0000 | [diff] [blame] | 533 | |
Bernhard Reutner-Fischer | d27d925 | 2008-01-13 15:23:27 +0000 | [diff] [blame] | 534 | #if ENABLE_FEATURE_BRCTL_SHOW |
Denys Vlasenko | b4fa16d | 2019-10-12 19:42:37 +0200 | [diff] [blame] | 535 | if (key == ARG_show) { /* show [BR]... */ |
| 536 | DIR *net; |
| 537 | struct dirent *ent; |
| 538 | int need_hdr = 1; |
| 539 | int exitcode = EXIT_SUCCESS; |
Denis Vlasenko | 278a1c2 | 2008-04-06 07:17:02 +0000 | [diff] [blame] | 540 | |
Denys Vlasenko | b4fa16d | 2019-10-12 19:42:37 +0200 | [diff] [blame] | 541 | if (*argv) { |
| 542 | /* "show BR1 BR2 BR3" */ |
| 543 | do { |
| 544 | if (show_bridge(*argv, need_hdr) >= 0) { |
| 545 | need_hdr = 0; |
| 546 | } else { |
| 547 | bb_error_msg("bridge %s does not exist", *argv); |
Denys Vlasenko | dc1b2d4 | 2019-04-13 13:58:06 +0200 | [diff] [blame] | 548 | //TODO: if device exists, but is not a BR, brctl from bridge-utils 1.6 |
| 549 | //says this instead: "device eth0 is not a bridge" |
Denys Vlasenko | b4fa16d | 2019-10-12 19:42:37 +0200 | [diff] [blame] | 550 | exitcode = EXIT_FAILURE; |
| 551 | } |
| 552 | } while (*++argv != NULL); |
Denys Vlasenko | c5150e9 | 2019-04-12 18:52:31 +0200 | [diff] [blame] | 553 | return exitcode; |
Bernhard Reutner-Fischer | d27d925 | 2008-01-13 15:23:27 +0000 | [diff] [blame] | 554 | } |
Denys Vlasenko | b4fa16d | 2019-10-12 19:42:37 +0200 | [diff] [blame] | 555 | |
| 556 | /* "show" (if no ifaces, shows nothing, not even header) */ |
| 557 | net = xopendir("."); |
| 558 | while ((ent = readdir(net)) != NULL) { |
| 559 | if (DOT_OR_DOTDOT(ent->d_name)) |
| 560 | continue; /* . or .. */ |
| 561 | if (show_bridge(ent->d_name, need_hdr) >= 0) |
| 562 | need_hdr = 0; |
| 563 | } |
| 564 | if (ENABLE_FEATURE_CLEAN_UP) |
| 565 | closedir(net); |
| 566 | return exitcode; |
| 567 | } |
Bernhard Reutner-Fischer | d27d925 | 2008-01-13 15:23:27 +0000 | [diff] [blame] | 568 | #endif |
Denis Vlasenko | 278a1c2 | 2008-04-06 07:17:02 +0000 | [diff] [blame] | 569 | |
Denys Vlasenko | eb13951 | 2019-10-12 19:51:46 +0200 | [diff] [blame] | 570 | if (!*argv) /* All of the below need at least one argument */ |
Denys Vlasenko | b4fa16d | 2019-10-12 19:42:37 +0200 | [diff] [blame] | 571 | bb_show_usage(); |
Denis Vlasenko | 278a1c2 | 2008-04-06 07:17:02 +0000 | [diff] [blame] | 572 | |
Denys Vlasenko | b4fa16d | 2019-10-12 19:42:37 +0200 | [diff] [blame] | 573 | br = *argv++; |
Bernhard Reutner-Fischer | d27d925 | 2008-01-13 15:23:27 +0000 | [diff] [blame] | 574 | |
Denys Vlasenko | b4fa16d | 2019-10-12 19:42:37 +0200 | [diff] [blame] | 575 | if (key == ARG_addbr || key == ARG_delbr) { |
| 576 | /* brctl from bridge-utils 1.6 still uses ioctl |
| 577 | * for SIOCBRADDBR / SIOCBRDELBR, not /sys accesses |
| 578 | */ |
| 579 | int fd = xsocket(AF_INET, SOCK_STREAM, 0); |
| 580 | ioctl_or_perror_and_die(fd, |
| 581 | key == ARG_addbr ? SIOCBRADDBR : SIOCBRDELBR, |
| 582 | br, "bridge %s", br |
| 583 | ); |
| 584 | //close(fd); |
| 585 | //goto done; |
| 586 | /* bridge-utils 1.6 simply ignores trailing args: |
| 587 | * "brctl addbr BR1 ARGS" ignores ARGS |
| 588 | */ |
| 589 | if (ENABLE_FEATURE_CLEAN_UP) |
| 590 | close(fd); |
| 591 | return EXIT_SUCCESS; |
| 592 | } |
Denis Vlasenko | 278a1c2 | 2008-04-06 07:17:02 +0000 | [diff] [blame] | 593 | |
Denys Vlasenko | b4fa16d | 2019-10-12 19:42:37 +0200 | [diff] [blame] | 594 | if (key == ARG_showmacs) { |
| 595 | show_bridge_macs(br); |
| 596 | return EXIT_SUCCESS; |
| 597 | } |
| 598 | if (key == ARG_showstp) { |
| 599 | show_bridge_stp(br); |
| 600 | return EXIT_SUCCESS; |
| 601 | } |
Martin Lewis | 6c1af28 | 2019-09-15 18:04:49 +0200 | [diff] [blame] | 602 | |
Denys Vlasenko | eb13951 | 2019-10-12 19:51:46 +0200 | [diff] [blame] | 603 | if (!*argv) /* All of the below need at least two arguments */ |
Denys Vlasenko | b4fa16d | 2019-10-12 19:42:37 +0200 | [diff] [blame] | 604 | bb_show_usage(); |
Denis Vlasenko | 278a1c2 | 2008-04-06 07:17:02 +0000 | [diff] [blame] | 605 | |
Bernhard Reutner-Fischer | 1aac3ab | 2008-01-13 18:43:50 +0000 | [diff] [blame] | 606 | #if ENABLE_FEATURE_BRCTL_FANCY |
Denys Vlasenko | b4fa16d | 2019-10-12 19:42:37 +0200 | [diff] [blame] | 607 | if (key == ARG_stp) { |
| 608 | static const char no_yes[] ALIGN1 = |
| 609 | "0\0" "off\0" "n\0" "no\0" /* 0 .. 3 */ |
| 610 | "1\0" "on\0" "y\0" "yes\0"; /* 4 .. 7 */ |
| 611 | int onoff = index_in_strings(no_yes, *argv); |
| 612 | if (onoff < 0) |
| 613 | bb_error_msg_and_die(bb_msg_invalid_arg_to, *argv, applet_name); |
| 614 | onoff = (unsigned)onoff / 4; |
| 615 | write_uint(br, "bridge/stp_state", onoff); |
| 616 | return EXIT_SUCCESS; |
| 617 | } |
Denys Vlasenko | dc1b2d4 | 2019-04-13 13:58:06 +0200 | [diff] [blame] | 618 | |
Denys Vlasenko | b4fa16d | 2019-10-12 19:42:37 +0200 | [diff] [blame] | 619 | if ((unsigned)(key - ARG_setageing) < 4) { /* time related ops */ |
| 620 | /* setageing BR N: "N*100\n" to /sys/class/net/BR/bridge/ageing_time |
| 621 | * setfd BR N: "N*100\n" to /sys/class/net/BR/bridge/forward_delay |
| 622 | * sethello BR N: "N*100\n" to /sys/class/net/BR/bridge/hello_time |
| 623 | * setmaxage BR N: "N*100\n" to /sys/class/net/BR/bridge/max_age |
| 624 | */ |
| 625 | write_uint(br, |
| 626 | nth_string( |
| 627 | "bridge/ageing_time" "\0" /* ARG_setageing */ |
| 628 | "bridge/forward_delay""\0" /* ARG_setfd */ |
| 629 | "bridge/hello_time" "\0" /* ARG_sethello */ |
| 630 | "bridge/max_age", /* ARG_setmaxage */ |
| 631 | key - ARG_setageing |
| 632 | ), |
| 633 | str_to_jiffies(*argv) |
| 634 | ); |
| 635 | return EXIT_SUCCESS; |
| 636 | } |
Denys Vlasenko | dc1b2d4 | 2019-04-13 13:58:06 +0200 | [diff] [blame] | 637 | |
Denys Vlasenko | b4fa16d | 2019-10-12 19:42:37 +0200 | [diff] [blame] | 638 | if (key == ARG_setbridgeprio) { |
| 639 | write_uint(br, "bridge/priority", xatoi_positive(*argv)); |
| 640 | return EXIT_SUCCESS; |
| 641 | } |
Denys Vlasenko | dc1b2d4 | 2019-04-13 13:58:06 +0200 | [diff] [blame] | 642 | |
Denys Vlasenko | b4fa16d | 2019-10-12 19:42:37 +0200 | [diff] [blame] | 643 | if (key == ARG_setpathcost |
| 644 | || key == ARG_setportprio |
| 645 | ) { |
| 646 | if (!argv[1]) |
| 647 | bb_show_usage(); |
| 648 | /* BR is not used (and ignored!) for these commands: |
| 649 | * "setpathcost BR PORT N" writes "N\n" to |
| 650 | * /sys/class/net/PORT/brport/path_cost |
| 651 | * "setportprio BR PORT N" writes "N\n" to |
| 652 | * /sys/class/net/PORT/brport/priority |
| 653 | */ |
| 654 | write_uint(argv[0], |
| 655 | nth_string( |
| 656 | "brport/path_cost" "\0" /* ARG_setpathcost */ |
| 657 | "brport/priority", /* ARG_setportprio */ |
| 658 | key - ARG_setpathcost |
| 659 | ), |
| 660 | xatoi_positive(argv[1]) |
| 661 | ); |
| 662 | return EXIT_SUCCESS; |
| 663 | } |
Bernhard Reutner-Fischer | 1aac3ab | 2008-01-13 18:43:50 +0000 | [diff] [blame] | 664 | #endif |
Denys Vlasenko | b4fa16d | 2019-10-12 19:42:37 +0200 | [diff] [blame] | 665 | /* always true: if (key == ARG_addif || key == ARG_delif) */ { |
| 666 | struct ifreq ifr; |
| 667 | int fd = xsocket(AF_INET, SOCK_STREAM, 0); |
Denys Vlasenko | dc1b2d4 | 2019-04-13 13:58:06 +0200 | [diff] [blame] | 668 | |
Denys Vlasenko | b4fa16d | 2019-10-12 19:42:37 +0200 | [diff] [blame] | 669 | strncpy_IFNAMSIZ(ifr.ifr_name, br); |
| 670 | ifr.ifr_ifindex = if_nametoindex(*argv); |
| 671 | if (ifr.ifr_ifindex == 0) { |
| 672 | bb_perror_msg_and_die("iface %s", *argv); |
Denys Vlasenko | dc1b2d4 | 2019-04-13 13:58:06 +0200 | [diff] [blame] | 673 | } |
Denys Vlasenko | b4fa16d | 2019-10-12 19:42:37 +0200 | [diff] [blame] | 674 | ioctl_or_perror_and_die(fd, |
| 675 | key == ARG_addif ? SIOCBRADDIF : SIOCBRDELIF, |
| 676 | &ifr, "bridge %s", br |
| 677 | ); |
| 678 | if (ENABLE_FEATURE_CLEAN_UP) |
| 679 | close(fd); |
Bernhard Reutner-Fischer | d27d925 | 2008-01-13 15:23:27 +0000 | [diff] [blame] | 680 | } |
Denis Vlasenko | 278a1c2 | 2008-04-06 07:17:02 +0000 | [diff] [blame] | 681 | |
Bernhard Reutner-Fischer | d27d925 | 2008-01-13 15:23:27 +0000 | [diff] [blame] | 682 | return EXIT_SUCCESS; |
| 683 | } |