summaryrefslogtreecommitdiff
path: root/networking/libiproute/iplink.c
diff options
context:
space:
mode:
Diffstat (limited to 'networking/libiproute/iplink.c')
-rw-r--r--networking/libiproute/iplink.c166
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
28static int on_off(const char *msg) 28static void on_off(const char *msg) ATTRIBUTE_NORETURN;
29static 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 */
34static int get_ctl_fd(void) 35static 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
54static int do_chflags(char *dev, uint32_t flags, uint32_t mask) 51/* Exits on error */
52static 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
81static int do_changename(char *dev, char *newdev) 71/* Exits on error */
72static 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
102static int set_qlen(char *dev, int qlen) 88/* Exits on error */
89static 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
124static int set_mtu(char *dev, int mtu) 104/* Exits on error */
105static 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 */
146static int get_address(char *dev, int *htype) 121static 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
188static int parse_address(char *dev, int hatype, int halen, char *lla, struct ifreq *ifr) 156/* Exits on error */
157static 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
205static int set_address(struct ifreq *ifr, int brd) 172/* Exits on error */
173static 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 */
222static int do_set(int argc, char **argv) 186static 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 */
336int do_iplink(int argc, char **argv) 292int 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}