diff options
Diffstat (limited to 'networking/libiproute/iplink.c')
-rw-r--r-- | networking/libiproute/iplink.c | 166 |
1 files changed, 61 insertions, 105 deletions
diff --git a/networking/libiproute/iplink.c b/networking/libiproute/iplink.c index cb6ee962b..0943726e1 100644 --- a/networking/libiproute/iplink.c +++ b/networking/libiproute/iplink.c | |||
@@ -22,63 +22,54 @@ | |||
22 | #include "utils.h" | 22 | #include "utils.h" |
23 | #include "ip_common.h" | 23 | #include "ip_common.h" |
24 | 24 | ||
25 | /* take from linux/sockios.h */ | 25 | /* taken from linux/sockios.h */ |
26 | #define SIOCSIFNAME 0x8923 /* set interface name */ | 26 | #define SIOCSIFNAME 0x8923 /* set interface name */ |
27 | 27 | ||
28 | static int on_off(const char *msg) | 28 | static void on_off(const char *msg) ATTRIBUTE_NORETURN; |
29 | static void on_off(const char *msg) | ||
29 | { | 30 | { |
30 | bb_error_msg("error: argument of \"%s\" must be \"on\" or \"off\"", msg); | 31 | bb_error_msg_and_die("error: argument of \"%s\" must be \"on\" or \"off\"", msg); |
31 | return -1; | ||
32 | } | 32 | } |
33 | 33 | ||
34 | /* Exits on error */ | ||
34 | static int get_ctl_fd(void) | 35 | static int get_ctl_fd(void) |
35 | { | 36 | { |
36 | int s_errno; | ||
37 | int fd; | 37 | int fd; |
38 | 38 | ||
39 | fd = socket(PF_INET, SOCK_DGRAM, 0); | 39 | fd = socket(PF_INET, SOCK_DGRAM, 0); |
40 | if (fd >= 0) | 40 | if (fd >= 0) |
41 | return fd; | 41 | return fd; |
42 | s_errno = errno; | ||
43 | fd = socket(PF_PACKET, SOCK_DGRAM, 0); | 42 | fd = socket(PF_PACKET, SOCK_DGRAM, 0); |
44 | if (fd >= 0) | 43 | if (fd >= 0) |
45 | return fd; | 44 | return fd; |
46 | fd = socket(PF_INET6, SOCK_DGRAM, 0); | 45 | fd = socket(PF_INET6, SOCK_DGRAM, 0); |
47 | if (fd >= 0) | 46 | if (fd >= 0) |
48 | return fd; | 47 | return fd; |
49 | errno = s_errno; | 48 | bb_perror_msg_and_die("cannot create control socket"); |
50 | bb_perror_msg("cannot create control socket"); | ||
51 | return -1; | ||
52 | } | 49 | } |
53 | 50 | ||
54 | static int do_chflags(char *dev, uint32_t flags, uint32_t mask) | 51 | /* Exits on error */ |
52 | static void do_chflags(char *dev, uint32_t flags, uint32_t mask) | ||
55 | { | 53 | { |
56 | struct ifreq ifr; | 54 | struct ifreq ifr; |
57 | int fd; | 55 | int fd; |
58 | int err; | ||
59 | 56 | ||
60 | strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name)); | 57 | strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name)); |
61 | fd = get_ctl_fd(); | 58 | fd = get_ctl_fd(); |
62 | if (fd < 0) | 59 | if (ioctl(fd, SIOCGIFFLAGS, &ifr)) { |
63 | return -1; | 60 | bb_perror_msg_and_die("SIOCGIFFLAGS"); |
64 | err = ioctl(fd, SIOCGIFFLAGS, &ifr); | ||
65 | if (err) { | ||
66 | bb_perror_msg("SIOCGIFFLAGS"); | ||
67 | close(fd); | ||
68 | return -1; | ||
69 | } | 61 | } |
70 | if ((ifr.ifr_flags^flags)&mask) { | 62 | if ((ifr.ifr_flags ^ flags) & mask) { |
71 | ifr.ifr_flags &= ~mask; | 63 | ifr.ifr_flags &= ~mask; |
72 | ifr.ifr_flags |= mask&flags; | 64 | ifr.ifr_flags |= mask & flags; |
73 | err = ioctl(fd, SIOCSIFFLAGS, &ifr); | 65 | if (ioctl(fd, SIOCSIFFLAGS, &ifr)) |
74 | if (err) | 66 | bb_perror_msg_and_die("SIOCSIFFLAGS"); |
75 | bb_perror_msg("SIOCSIFFLAGS"); | ||
76 | } | 67 | } |
77 | close(fd); | 68 | close(fd); |
78 | return err; | ||
79 | } | 69 | } |
80 | 70 | ||
81 | static int do_changename(char *dev, char *newdev) | 71 | /* Exits on error */ |
72 | static void do_changename(char *dev, char *newdev) | ||
82 | { | 73 | { |
83 | struct ifreq ifr; | 74 | struct ifreq ifr; |
84 | int fd; | 75 | int fd; |
@@ -87,62 +78,46 @@ static int do_changename(char *dev, char *newdev) | |||
87 | strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name)); | 78 | strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name)); |
88 | strncpy(ifr.ifr_newname, newdev, sizeof(ifr.ifr_newname)); | 79 | strncpy(ifr.ifr_newname, newdev, sizeof(ifr.ifr_newname)); |
89 | fd = get_ctl_fd(); | 80 | fd = get_ctl_fd(); |
90 | if (fd < 0) | ||
91 | return -1; | ||
92 | err = ioctl(fd, SIOCSIFNAME, &ifr); | 81 | err = ioctl(fd, SIOCSIFNAME, &ifr); |
93 | if (err) { | 82 | if (err) { |
94 | bb_perror_msg("SIOCSIFNAME"); | 83 | bb_perror_msg_and_die("SIOCSIFNAME"); |
95 | close(fd); | ||
96 | return -1; | ||
97 | } | 84 | } |
98 | close(fd); | 85 | close(fd); |
99 | return err; | ||
100 | } | 86 | } |
101 | 87 | ||
102 | static int set_qlen(char *dev, int qlen) | 88 | /* Exits on error */ |
89 | static void set_qlen(char *dev, int qlen) | ||
103 | { | 90 | { |
104 | struct ifreq ifr; | 91 | struct ifreq ifr; |
105 | int s; | 92 | int s; |
106 | 93 | ||
107 | s = get_ctl_fd(); | 94 | s = get_ctl_fd(); |
108 | if (s < 0) | ||
109 | return -1; | ||
110 | |||
111 | memset(&ifr, 0, sizeof(ifr)); | 95 | memset(&ifr, 0, sizeof(ifr)); |
112 | strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name)); | 96 | strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name)); |
113 | ifr.ifr_qlen = qlen; | 97 | ifr.ifr_qlen = qlen; |
114 | if (ioctl(s, SIOCSIFTXQLEN, &ifr) < 0) { | 98 | if (ioctl(s, SIOCSIFTXQLEN, &ifr) < 0) { |
115 | bb_perror_msg("SIOCSIFXQLEN"); | 99 | bb_perror_msg_and_die("SIOCSIFXQLEN"); |
116 | close(s); | ||
117 | return -1; | ||
118 | } | 100 | } |
119 | close(s); | 101 | close(s); |
120 | |||
121 | return 0; | ||
122 | } | 102 | } |
123 | 103 | ||
124 | static int set_mtu(char *dev, int mtu) | 104 | /* Exits on error */ |
105 | static void set_mtu(char *dev, int mtu) | ||
125 | { | 106 | { |
126 | struct ifreq ifr; | 107 | struct ifreq ifr; |
127 | int s; | 108 | int s; |
128 | 109 | ||
129 | s = get_ctl_fd(); | 110 | s = get_ctl_fd(); |
130 | if (s < 0) | ||
131 | return -1; | ||
132 | |||
133 | memset(&ifr, 0, sizeof(ifr)); | 111 | memset(&ifr, 0, sizeof(ifr)); |
134 | strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name)); | 112 | strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name)); |
135 | ifr.ifr_mtu = mtu; | 113 | ifr.ifr_mtu = mtu; |
136 | if (ioctl(s, SIOCSIFMTU, &ifr) < 0) { | 114 | if (ioctl(s, SIOCSIFMTU, &ifr) < 0) { |
137 | bb_perror_msg("SIOCSIFMTU"); | 115 | bb_perror_msg_and_die("SIOCSIFMTU"); |
138 | close(s); | ||
139 | return -1; | ||
140 | } | 116 | } |
141 | close(s); | 117 | close(s); |
142 | |||
143 | return 0; | ||
144 | } | 118 | } |
145 | 119 | ||
120 | /* Exits on error */ | ||
146 | static int get_address(char *dev, int *htype) | 121 | static int get_address(char *dev, int *htype) |
147 | { | 122 | { |
148 | struct ifreq ifr; | 123 | struct ifreq ifr; |
@@ -152,16 +127,13 @@ static int get_address(char *dev, int *htype) | |||
152 | 127 | ||
153 | s = socket(PF_PACKET, SOCK_DGRAM, 0); | 128 | s = socket(PF_PACKET, SOCK_DGRAM, 0); |
154 | if (s < 0) { | 129 | if (s < 0) { |
155 | bb_perror_msg("socket(PF_PACKET)"); | 130 | bb_perror_msg_and_die("socket(PF_PACKET)"); |
156 | return -1; | ||
157 | } | 131 | } |
158 | 132 | ||
159 | memset(&ifr, 0, sizeof(ifr)); | 133 | memset(&ifr, 0, sizeof(ifr)); |
160 | strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name)); | 134 | strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name)); |
161 | if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) { | 135 | if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) { |
162 | bb_perror_msg("SIOCGIFINDEX"); | 136 | bb_perror_msg_and_die("SIOCGIFINDEX"); |
163 | close(s); | ||
164 | return -1; | ||
165 | } | 137 | } |
166 | 138 | ||
167 | memset(&me, 0, sizeof(me)); | 139 | memset(&me, 0, sizeof(me)); |
@@ -169,23 +141,20 @@ static int get_address(char *dev, int *htype) | |||
169 | me.sll_ifindex = ifr.ifr_ifindex; | 141 | me.sll_ifindex = ifr.ifr_ifindex; |
170 | me.sll_protocol = htons(ETH_P_LOOP); | 142 | me.sll_protocol = htons(ETH_P_LOOP); |
171 | if (bind(s, (struct sockaddr*)&me, sizeof(me)) == -1) { | 143 | if (bind(s, (struct sockaddr*)&me, sizeof(me)) == -1) { |
172 | bb_perror_msg("bind"); | 144 | bb_perror_msg_and_die("bind"); |
173 | close(s); | ||
174 | return -1; | ||
175 | } | 145 | } |
176 | 146 | ||
177 | alen = sizeof(me); | 147 | alen = sizeof(me); |
178 | if (getsockname(s, (struct sockaddr*)&me, &alen) == -1) { | 148 | if (getsockname(s, (struct sockaddr*)&me, &alen) == -1) { |
179 | bb_perror_msg("getsockname"); | 149 | bb_perror_msg_and_die("getsockname"); |
180 | close(s); | ||
181 | return -1; | ||
182 | } | 150 | } |
183 | close(s); | 151 | close(s); |
184 | *htype = me.sll_hatype; | 152 | *htype = me.sll_hatype; |
185 | return me.sll_halen; | 153 | return me.sll_halen; |
186 | } | 154 | } |
187 | 155 | ||
188 | static int parse_address(char *dev, int hatype, int halen, char *lla, struct ifreq *ifr) | 156 | /* Exits on error */ |
157 | static void parse_address(char *dev, int hatype, int halen, char *lla, struct ifreq *ifr) | ||
189 | { | 158 | { |
190 | int alen; | 159 | int alen; |
191 | 160 | ||
@@ -194,31 +163,26 @@ static int parse_address(char *dev, int hatype, int halen, char *lla, struct ifr | |||
194 | ifr->ifr_hwaddr.sa_family = hatype; | 163 | ifr->ifr_hwaddr.sa_family = hatype; |
195 | alen = ll_addr_a2n((unsigned char *)(ifr->ifr_hwaddr.sa_data), 14, lla); | 164 | alen = ll_addr_a2n((unsigned char *)(ifr->ifr_hwaddr.sa_data), 14, lla); |
196 | if (alen < 0) | 165 | if (alen < 0) |
197 | return -1; | 166 | exit(1); |
198 | if (alen != halen) { | 167 | if (alen != halen) { |
199 | bb_error_msg("wrong address (%s) length: expected %d bytes", lla, halen); | 168 | bb_error_msg_and_die("wrong address (%s) length: expected %d bytes", lla, halen); |
200 | return -1; | ||
201 | } | 169 | } |
202 | return 0; | ||
203 | } | 170 | } |
204 | 171 | ||
205 | static int set_address(struct ifreq *ifr, int brd) | 172 | /* Exits on error */ |
173 | static void set_address(struct ifreq *ifr, int brd) | ||
206 | { | 174 | { |
207 | int s; | 175 | int s; |
208 | 176 | ||
209 | s = get_ctl_fd(); | 177 | s = get_ctl_fd(); |
210 | if (s < 0) | 178 | if (ioctl(s, brd ? SIOCSIFHWBROADCAST :SIOCSIFHWADDR, ifr) < 0) { |
211 | return -1; | 179 | bb_perror_msg_and_die(brd ? "SIOCSIFHWBROADCAST" : "SIOCSIFHWADDR"); |
212 | if (ioctl(s, brd?SIOCSIFHWBROADCAST:SIOCSIFHWADDR, ifr) < 0) { | ||
213 | bb_perror_msg(brd ? "SIOCSIFHWBROADCAST" : "SIOCSIFHWADDR"); | ||
214 | close(s); | ||
215 | return -1; | ||
216 | } | 180 | } |
217 | close(s); | 181 | close(s); |
218 | return 0; | ||
219 | } | 182 | } |
220 | 183 | ||
221 | 184 | ||
185 | /* Return value becomes exitcode. It's okay to not return at all */ | ||
222 | static int do_set(int argc, char **argv) | 186 | static int do_set(int argc, char **argv) |
223 | { | 187 | { |
224 | char *dev = NULL; | 188 | char *dev = NULL; |
@@ -256,7 +220,7 @@ static int do_set(int argc, char **argv) | |||
256 | } else if (strcmp(*argv, "off") == 0) { | 220 | } else if (strcmp(*argv, "off") == 0) { |
257 | flags &= ~IFF_MULTICAST; | 221 | flags &= ~IFF_MULTICAST; |
258 | } else | 222 | } else |
259 | return on_off("multicast"); | 223 | on_off("multicast"); |
260 | } else if (strcmp(*argv, "arp") == 0) { | 224 | } else if (strcmp(*argv, "arp") == 0) { |
261 | NEXT_ARG(); | 225 | NEXT_ARG(); |
262 | mask |= IFF_NOARP; | 226 | mask |= IFF_NOARP; |
@@ -265,7 +229,7 @@ static int do_set(int argc, char **argv) | |||
265 | } else if (strcmp(*argv, "off") == 0) { | 229 | } else if (strcmp(*argv, "off") == 0) { |
266 | flags |= IFF_NOARP; | 230 | flags |= IFF_NOARP; |
267 | } else | 231 | } else |
268 | return on_off("noarp"); | 232 | on_off("noarp"); |
269 | } else if (strcmp(*argv, "addr") == 0) { | 233 | } else if (strcmp(*argv, "addr") == 0) { |
270 | NEXT_ARG(); | 234 | NEXT_ARG(); |
271 | newaddr = *argv; | 235 | newaddr = *argv; |
@@ -277,53 +241,44 @@ static int do_set(int argc, char **argv) | |||
277 | duparg2("dev", *argv); | 241 | duparg2("dev", *argv); |
278 | dev = *argv; | 242 | dev = *argv; |
279 | } | 243 | } |
280 | argc--; argv++; | 244 | argc--; |
245 | argv++; | ||
281 | } | 246 | } |
282 | 247 | ||
283 | if (!dev) { | 248 | if (!dev) { |
284 | bb_error_msg(bb_msg_requires_arg, "\"dev\""); | 249 | bb_error_msg_and_die(bb_msg_requires_arg, "\"dev\""); |
285 | exit(-1); | ||
286 | } | 250 | } |
287 | 251 | ||
288 | if (newaddr || newbrd) { | 252 | if (newaddr || newbrd) { |
289 | halen = get_address(dev, &htype); | 253 | halen = get_address(dev, &htype); |
290 | if (halen < 0) | ||
291 | return -1; | ||
292 | if (newaddr) { | 254 | if (newaddr) { |
293 | if (parse_address(dev, htype, halen, newaddr, &ifr0) < 0) | 255 | parse_address(dev, htype, halen, newaddr, &ifr0); |
294 | return -1; | ||
295 | } | 256 | } |
296 | if (newbrd) { | 257 | if (newbrd) { |
297 | if (parse_address(dev, htype, halen, newbrd, &ifr1) < 0) | 258 | parse_address(dev, htype, halen, newbrd, &ifr1); |
298 | return -1; | ||
299 | } | 259 | } |
300 | } | 260 | } |
301 | 261 | ||
302 | if (newname && strcmp(dev, newname)) { | 262 | if (newname && strcmp(dev, newname)) { |
303 | if (do_changename(dev, newname) < 0) | 263 | do_changename(dev, newname); |
304 | return -1; | ||
305 | dev = newname; | 264 | dev = newname; |
306 | } | 265 | } |
307 | if (qlen != -1) { | 266 | if (qlen != -1) { |
308 | if (set_qlen(dev, qlen) < 0) | 267 | set_qlen(dev, qlen); |
309 | return -1; | ||
310 | } | 268 | } |
311 | if (mtu != -1) { | 269 | if (mtu != -1) { |
312 | if (set_mtu(dev, mtu) < 0) | 270 | set_mtu(dev, mtu); |
313 | return -1; | ||
314 | } | 271 | } |
315 | if (newaddr || newbrd) { | 272 | if (newaddr || newbrd) { |
316 | if (newbrd) { | 273 | if (newbrd) { |
317 | if (set_address(&ifr1, 1) < 0) | 274 | set_address(&ifr1, 1); |
318 | return -1; | ||
319 | } | 275 | } |
320 | if (newaddr) { | 276 | if (newaddr) { |
321 | if (set_address(&ifr0, 0) < 0) | 277 | set_address(&ifr0, 0); |
322 | return -1; | ||
323 | } | 278 | } |
324 | } | 279 | } |
325 | if (mask) | 280 | if (mask) |
326 | return do_chflags(dev, flags, mask); | 281 | do_chflags(dev, flags, mask); |
327 | return 0; | 282 | return 0; |
328 | } | 283 | } |
329 | 284 | ||
@@ -333,18 +288,19 @@ static int ipaddr_list_link(int argc, char **argv) | |||
333 | return ipaddr_list_or_flush(argc, argv, 0); | 288 | return ipaddr_list_or_flush(argc, argv, 0); |
334 | } | 289 | } |
335 | 290 | ||
291 | /* Return value becomes exitcode. It's okay to not return at all */ | ||
336 | int do_iplink(int argc, char **argv) | 292 | int do_iplink(int argc, char **argv) |
337 | { | 293 | { |
338 | if (argc > 0) { | 294 | if (argc <= 0) |
339 | if (matches(*argv, "set") == 0) | ||
340 | return do_set(argc-1, argv+1); | ||
341 | if (matches(*argv, "show") == 0 || | ||
342 | matches(*argv, "lst") == 0 || | ||
343 | matches(*argv, "list") == 0) | ||
344 | return ipaddr_list_link(argc-1, argv+1); | ||
345 | } else | ||
346 | return ipaddr_list_link(0, NULL); | 295 | return ipaddr_list_link(0, NULL); |
347 | 296 | ||
348 | bb_error_msg("command \"%s\" is unknown", *argv); | 297 | if (matches(*argv, "set") == 0) |
349 | exit(-1); | 298 | return do_set(argc-1, argv+1); |
299 | |||
300 | if (matches(*argv, "show") == 0 || | ||
301 | matches(*argv, "lst") == 0 || | ||
302 | matches(*argv, "list") == 0) | ||
303 | return ipaddr_list_link(argc-1, argv+1); | ||
304 | |||
305 | bb_error_msg_and_die("command \"%s\" is unknown", *argv); | ||
350 | } | 306 | } |