Only included headers that are used.
[platform/upstream/busybox.git] / networking / libiproute / iplink.c
1 /*
2  * iplink.c             "ip link".
3  *
4  *              This program is free software; you can redistribute it and/or
5  *              modify it under the terms of the GNU General Public License
6  *              as published by the Free Software Foundation; either version
7  *              2 of the License, or (at your option) any later version.
8  *
9  * Authors:     Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
10  *
11  */
12
13 #include <sys/ioctl.h>
14 #include <sys/socket.h>
15
16 #include <errno.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <unistd.h>
20
21 #include <linux/if.h>
22 #include <linux/if_packet.h>
23 #include <linux/if_ether.h>
24 #include <linux/sockios.h>
25
26 #include "rt_names.h"
27 #include "utils.h"
28 #include "ip_common.h"
29
30 #include "libbb.h"
31
32 static int do_link;
33
34 static int on_off(char *msg)
35 {
36         error_msg("Error: argument of \"%s\" must be \"on\" or \"off\"", msg);
37         return -1;
38 }
39
40 static int get_ctl_fd(void)
41 {
42         int s_errno;
43         int fd;
44
45         fd = socket(PF_INET, SOCK_DGRAM, 0);
46         if (fd >= 0)
47                 return fd;
48         s_errno = errno;
49         fd = socket(PF_PACKET, SOCK_DGRAM, 0);
50         if (fd >= 0)
51                 return fd;
52         fd = socket(PF_INET6, SOCK_DGRAM, 0);
53         if (fd >= 0)
54                 return fd;
55         errno = s_errno;
56         perror("Cannot create control socket");
57         return -1;
58 }
59
60 static int do_chflags(char *dev, __u32 flags, __u32 mask)
61 {
62         struct ifreq ifr;
63         int fd;
64         int err;
65
66         strcpy(ifr.ifr_name, dev);
67         fd = get_ctl_fd();
68         if (fd < 0)
69                 return -1;
70         err = ioctl(fd, SIOCGIFFLAGS, &ifr);
71         if (err) {
72                 perror("SIOCGIFFLAGS");
73                 close(fd);
74                 return -1;
75         }
76         if ((ifr.ifr_flags^flags)&mask) {
77                 ifr.ifr_flags &= ~mask;
78                 ifr.ifr_flags |= mask&flags;
79                 err = ioctl(fd, SIOCSIFFLAGS, &ifr);
80                 if (err)
81                         perror("SIOCSIFFLAGS");
82         }
83         close(fd);
84         return err;
85 }
86
87 static int do_changename(char *dev, char *newdev)
88 {
89         struct ifreq ifr;
90         int fd;
91         int err;
92
93         strcpy(ifr.ifr_name, dev);
94         strcpy(ifr.ifr_newname, newdev);
95         fd = get_ctl_fd();
96         if (fd < 0)
97                 return -1;
98         err = ioctl(fd, SIOCSIFNAME, &ifr);
99         if (err) {
100                 perror("SIOCSIFNAME");
101                 close(fd);
102                 return -1;
103         }
104         close(fd);
105         return err;
106 }
107
108 static int set_qlen(char *dev, int qlen)
109 {
110         struct ifreq ifr;
111         int s;
112
113         s = get_ctl_fd();
114         if (s < 0)
115                 return -1;
116
117         memset(&ifr, 0, sizeof(ifr));
118         strcpy(ifr.ifr_name, dev); 
119         ifr.ifr_qlen = qlen; 
120         if (ioctl(s, SIOCSIFTXQLEN, &ifr) < 0) {
121                 perror("SIOCSIFXQLEN");
122                 close(s);
123                 return -1;
124         }
125         close(s);
126
127         return 0; 
128 }
129
130 static int set_mtu(char *dev, int mtu)
131 {
132         struct ifreq ifr;
133         int s;
134
135         s = get_ctl_fd();
136         if (s < 0)
137                 return -1;
138
139         memset(&ifr, 0, sizeof(ifr));
140         strcpy(ifr.ifr_name, dev); 
141         ifr.ifr_mtu = mtu; 
142         if (ioctl(s, SIOCSIFMTU, &ifr) < 0) {
143                 perror("SIOCSIFMTU");
144                 close(s);
145                 return -1;
146         }
147         close(s);
148
149         return 0; 
150 }
151
152 static int get_address(char *dev, int *htype)
153 {
154         struct ifreq ifr;
155         struct sockaddr_ll me;
156         int alen;
157         int s;
158
159         s = socket(PF_PACKET, SOCK_DGRAM, 0);
160         if (s < 0) { 
161                 perror("socket(PF_PACKET)");
162                 return -1;
163         }
164
165         memset(&ifr, 0, sizeof(ifr));
166         strcpy(ifr.ifr_name, dev);
167         if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) {
168                 perror("SIOCGIFINDEX");
169                 close(s);
170                 return -1;
171         }
172
173         memset(&me, 0, sizeof(me));
174         me.sll_family = AF_PACKET;
175         me.sll_ifindex = ifr.ifr_ifindex;
176         me.sll_protocol = htons(ETH_P_LOOP);
177         if (bind(s, (struct sockaddr*)&me, sizeof(me)) == -1) {
178                 perror("bind");
179                 close(s);
180                 return -1;
181         }
182
183         alen = sizeof(me);
184         if (getsockname(s, (struct sockaddr*)&me, &alen) == -1) {
185                 perror("getsockname");
186                 close(s);
187                 return -1;
188         }
189         close(s);
190         *htype = me.sll_hatype;
191         return me.sll_halen;
192 }
193
194 static int parse_address(char *dev, int hatype, int halen, char *lla, struct ifreq *ifr)
195 {
196         int alen;
197
198         memset(ifr, 0, sizeof(*ifr));
199         strcpy(ifr->ifr_name, dev);
200         ifr->ifr_hwaddr.sa_family = hatype;
201         alen = ll_addr_a2n(ifr->ifr_hwaddr.sa_data, 14, lla);
202         if (alen < 0)
203                 return -1;
204         if (alen != halen) {
205                 error_msg("Wrong address (%s) length: expected %d bytes", lla, halen);
206                 return -1;
207         }
208         return 0; 
209 }
210
211 static int set_address(struct ifreq *ifr, int brd)
212 {
213         int s;
214
215         s = get_ctl_fd();
216         if (s < 0)
217                 return -1;
218         if (ioctl(s, brd?SIOCSIFHWBROADCAST:SIOCSIFHWADDR, ifr) < 0) {
219                 perror(brd?"SIOCSIFHWBROADCAST":"SIOCSIFHWADDR");
220                 close(s);
221                 return -1;
222         }
223         close(s);
224         return 0; 
225 }
226
227
228 static int do_set(int argc, char **argv)
229 {
230         char *dev = NULL;
231         __u32 mask = 0;
232         __u32 flags = 0;
233         int qlen = -1;
234         int mtu = -1;
235         char *newaddr = NULL;
236         char *newbrd = NULL;
237         struct ifreq ifr0, ifr1;
238         char *newname = NULL;
239         int htype, halen;
240
241         while (argc > 0) {
242                 if (strcmp(*argv, "up") == 0) {
243                         mask |= IFF_UP;
244                         flags |= IFF_UP;
245                 } else if (strcmp(*argv, "down") == 0) {
246                         mask |= IFF_UP;
247                         flags &= ~IFF_UP;
248                 } else if (strcmp(*argv, "name") == 0) {
249                         NEXT_ARG();
250                         newname = *argv;
251                 } else if (strcmp(*argv, "mtu") == 0) {
252                         NEXT_ARG();
253                         if (mtu != -1)
254                                 duparg("mtu", *argv);
255                         if (get_integer(&mtu, *argv, 0))
256                                 invarg("Invalid \"mtu\" value\n", *argv);
257                 } else if (strcmp(*argv, "multicast") == 0) {
258                         NEXT_ARG();
259                         mask |= IFF_MULTICAST;
260                         if (strcmp(*argv, "on") == 0) {
261                                 flags |= IFF_MULTICAST;
262                         } else if (strcmp(*argv, "off") == 0) {
263                                 flags &= ~IFF_MULTICAST;
264                         } else
265                                 return on_off("multicast");
266                 } else if (strcmp(*argv, "arp") == 0) {
267                         NEXT_ARG();
268                         mask |= IFF_NOARP;
269                         if (strcmp(*argv, "on") == 0) {
270                                 flags &= ~IFF_NOARP;
271                         } else if (strcmp(*argv, "off") == 0) {
272                                 flags |= IFF_NOARP;
273                         } else
274                                 return on_off("noarp");
275                 } else {
276                         if (strcmp(*argv, "dev") == 0) {
277                                 NEXT_ARG();
278                         }
279                         if (dev)
280                                 duparg2("dev", *argv);
281                         dev = *argv;
282                 }
283                 argc--; argv++;
284         }
285
286         if (!dev) {
287                 error_msg("Not enough of information: \"dev\" argument is required.");
288                 exit(-1);
289         }
290
291         if (newaddr || newbrd) {
292                 halen = get_address(dev, &htype);
293                 if (halen < 0)
294                         return -1;
295                 if (newaddr) {
296                         if (parse_address(dev, htype, halen, newaddr, &ifr0) < 0)
297                                 return -1;
298                 }
299                 if (newbrd) {
300                         if (parse_address(dev, htype, halen, newbrd, &ifr1) < 0)
301                                 return -1; 
302                 }
303         }
304
305         if (newname && strcmp(dev, newname)) {
306                 if (do_changename(dev, newname) < 0)
307                         return -1;
308                 dev = newname;
309         }
310         if (qlen != -1) { 
311                 if (set_qlen(dev, qlen) < 0)
312                         return -1; 
313         }
314         if (mtu != -1) { 
315                 if (set_mtu(dev, mtu) < 0)
316                         return -1; 
317         }
318         if (newaddr || newbrd) {
319                 if (newbrd) {
320                         if (set_address(&ifr1, 1) < 0)
321                                 return -1; 
322                 }
323                 if (newaddr) {
324                         if (set_address(&ifr0, 0) < 0)
325                                 return -1;
326                 }
327         }
328         if (mask)
329                 return do_chflags(dev, flags, mask);
330         return 0;
331 }
332
333 static int ipaddr_list_link(int argc, char **argv)
334 {
335         preferred_family = AF_PACKET;
336         do_link = 1;
337         return ipaddr_list(argc, argv);
338 }
339
340 int do_iplink(int argc, char **argv)
341 {
342         if (argc > 0) {
343                 if (matches(*argv, "set") == 0)
344                         return do_set(argc-1, argv+1);
345                 if (matches(*argv, "show") == 0 ||
346                     matches(*argv, "lst") == 0 ||
347                     matches(*argv, "list") == 0)
348                         return ipaddr_list_link(argc-1, argv+1);
349         } else
350                 return ipaddr_list_link(0, NULL);
351
352         error_msg("Command \"%s\" is unknown, try \"ip link help\".", *argv);
353         exit(-1);
354 }