]> rtime.felk.cvut.cz Git - lisovros/iproute2_canprio.git/blob - ip/iplink.c
(Logical change 1.3)
[lisovros/iproute2_canprio.git] / ip / 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 <stdio.h>
14 #include <stdlib.h>
15 #include <unistd.h>
16 #include <syslog.h>
17 #include <fcntl.h>
18 #include <errno.h>
19 #include <sys/socket.h>
20 #include <linux/if.h>
21 #include <linux/if_packet.h>
22 #include <linux/if_ether.h>
23 #include <linux/sockios.h>
24 #include <netinet/in.h>
25 #include <arpa/inet.h>
26 #include <string.h>
27 #include <sys/ioctl.h>
28 #include <linux/sockios.h>
29
30 #include "rt_names.h"
31 #include "utils.h"
32 #include "ip_common.h"
33
34
35 static void usage(void) __attribute__((noreturn));
36
37 void iplink_usage(void)
38 {
39         fprintf(stderr, "Usage: ip link set DEVICE { up | down | arp { on | off } |\n");
40         fprintf(stderr, "                            dynamic { on | off } |\n");
41         fprintf(stderr, "                            multicast { on | off } | txqueuelen PACKETS |\n");
42         fprintf(stderr, "                            name NEWNAME |\n");
43         fprintf(stderr, "                            address LLADDR | broadcast LLADDR |\n");
44         fprintf(stderr, "                            mtu MTU }\n");
45         fprintf(stderr, "       ip link show [ DEVICE ]\n");
46         exit(-1);
47 }
48
49 static void usage(void)
50 {
51         iplink_usage();
52 }
53
54 static int on_off(char *msg)
55 {
56         fprintf(stderr, "Error: argument of \"%s\" must be \"on\" or \"off\"\n", msg);
57         return -1;
58 }
59
60 static int get_ctl_fd(void)
61 {
62         int s_errno;
63         int fd;
64
65         fd = socket(PF_INET, SOCK_DGRAM, 0);
66         if (fd >= 0)
67                 return fd;
68         s_errno = errno;
69         fd = socket(PF_PACKET, SOCK_DGRAM, 0);
70         if (fd >= 0)
71                 return fd;
72         fd = socket(PF_INET6, SOCK_DGRAM, 0);
73         if (fd >= 0)
74                 return fd;
75         errno = s_errno;
76         perror("Cannot create control socket");
77         return -1;
78 }
79
80 static int do_chflags(char *dev, __u32 flags, __u32 mask)
81 {
82         struct ifreq ifr;
83         int fd;
84         int err;
85
86         strcpy(ifr.ifr_name, dev);
87         fd = get_ctl_fd();
88         if (fd < 0)
89                 return -1;
90         err = ioctl(fd, SIOCGIFFLAGS, &ifr);
91         if (err) {
92                 perror("SIOCGIFFLAGS");
93                 close(fd);
94                 return -1;
95         }
96         if ((ifr.ifr_flags^flags)&mask) {
97                 ifr.ifr_flags &= ~mask;
98                 ifr.ifr_flags |= mask&flags;
99                 err = ioctl(fd, SIOCSIFFLAGS, &ifr);
100                 if (err)
101                         perror("SIOCSIFFLAGS");
102         }
103         close(fd);
104         return err;
105 }
106
107 static int do_changename(char *dev, char *newdev)
108 {
109         struct ifreq ifr;
110         int fd;
111         int err;
112
113         strcpy(ifr.ifr_name, dev);
114         strcpy(ifr.ifr_newname, newdev);
115         fd = get_ctl_fd();
116         if (fd < 0)
117                 return -1;
118         err = ioctl(fd, SIOCSIFNAME, &ifr);
119         if (err) {
120                 perror("SIOCSIFNAME");
121                 close(fd);
122                 return -1;
123         }
124         close(fd);
125         return err;
126 }
127
128 static int set_qlen(char *dev, int qlen)
129 {
130         struct ifreq ifr;
131         int s;
132
133         s = get_ctl_fd();
134         if (s < 0)
135                 return -1;
136
137         memset(&ifr, 0, sizeof(ifr));
138         strcpy(ifr.ifr_name, dev); 
139         ifr.ifr_qlen = qlen; 
140         if (ioctl(s, SIOCSIFTXQLEN, &ifr) < 0) {
141                 perror("SIOCSIFXQLEN");
142                 close(s);
143                 return -1;
144         }
145         close(s);
146
147         return 0; 
148 }
149
150 static int set_mtu(char *dev, int mtu)
151 {
152         struct ifreq ifr;
153         int s;
154
155         s = get_ctl_fd();
156         if (s < 0)
157                 return -1;
158
159         memset(&ifr, 0, sizeof(ifr));
160         strcpy(ifr.ifr_name, dev); 
161         ifr.ifr_mtu = mtu; 
162         if (ioctl(s, SIOCSIFMTU, &ifr) < 0) {
163                 perror("SIOCSIFMTU");
164                 close(s);
165                 return -1;
166         }
167         close(s);
168
169         return 0; 
170 }
171
172 static int get_address(char *dev, int *htype)
173 {
174         struct ifreq ifr;
175         struct sockaddr_ll me;
176         int alen;
177         int s;
178
179         s = socket(PF_PACKET, SOCK_DGRAM, 0);
180         if (s < 0) { 
181                 perror("socket(PF_PACKET)");
182                 return -1;
183         }
184
185         memset(&ifr, 0, sizeof(ifr));
186         strcpy(ifr.ifr_name, dev);
187         if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) {
188                 perror("SIOCGIFINDEX");
189                 close(s);
190                 return -1;
191         }
192
193         memset(&me, 0, sizeof(me));
194         me.sll_family = AF_PACKET;
195         me.sll_ifindex = ifr.ifr_ifindex;
196         me.sll_protocol = htons(ETH_P_LOOP);
197         if (bind(s, (struct sockaddr*)&me, sizeof(me)) == -1) {
198                 perror("bind");
199                 close(s);
200                 return -1;
201         }
202
203         alen = sizeof(me);
204         if (getsockname(s, (struct sockaddr*)&me, &alen) == -1) {
205                 perror("getsockname");
206                 close(s);
207                 return -1;
208         }
209         close(s);
210         *htype = me.sll_hatype;
211         return me.sll_halen;
212 }
213
214 static int parse_address(char *dev, int hatype, int halen, char *lla, struct ifreq *ifr)
215 {
216         int alen;
217
218         memset(ifr, 0, sizeof(*ifr));
219         strcpy(ifr->ifr_name, dev);
220         ifr->ifr_hwaddr.sa_family = hatype;
221         alen = ll_addr_a2n(ifr->ifr_hwaddr.sa_data, 14, lla);
222         if (alen < 0)
223                 return -1;
224         if (alen != halen) {
225                 fprintf(stderr, "Wrong address (%s) length: expected %d bytes\n", lla, halen);
226                 return -1;
227         }
228         return 0; 
229 }
230
231 static int set_address(struct ifreq *ifr, int brd)
232 {
233         int s;
234
235         s = get_ctl_fd();
236         if (s < 0)
237                 return -1;
238         if (ioctl(s, brd?SIOCSIFHWBROADCAST:SIOCSIFHWADDR, ifr) < 0) {
239                 perror(brd?"SIOCSIFHWBROADCAST":"SIOCSIFHWADDR");
240                 close(s);
241                 return -1;
242         }
243         close(s);
244         return 0; 
245 }
246
247
248 static int do_set(int argc, char **argv)
249 {
250         char *dev = NULL;
251         __u32 mask = 0;
252         __u32 flags = 0;
253         int qlen = -1;
254         int mtu = -1;
255         char *newaddr = NULL;
256         char *newbrd = NULL;
257         struct ifreq ifr0, ifr1;
258         char *newname = NULL;
259         int htype, halen;
260
261         while (argc > 0) {
262                 if (strcmp(*argv, "up") == 0) {
263                         mask |= IFF_UP;
264                         flags |= IFF_UP;
265                 } else if (strcmp(*argv, "down") == 0) {
266                         mask |= IFF_UP;
267                         flags &= ~IFF_UP;
268                 } else if (strcmp(*argv, "name") == 0) {
269                         NEXT_ARG();
270                         newname = *argv;
271                 } else if (matches(*argv, "address") == 0) {
272                         NEXT_ARG();
273                         newaddr = *argv;
274                 } else if (matches(*argv, "broadcast") == 0 ||
275                            strcmp(*argv, "brd") == 0) {
276                         NEXT_ARG();
277                         newbrd = *argv;
278                 } else if (matches(*argv, "txqueuelen") == 0 ||
279                            strcmp(*argv, "qlen") == 0 ||
280                            matches(*argv, "txqlen") == 0) {
281                         NEXT_ARG();
282                         if (qlen != -1)
283                                 duparg("txqueuelen", *argv);
284                         if (get_integer(&qlen,  *argv, 0))
285                                 invarg("Invalid \"txqueuelen\" value\n", *argv);
286                 } else if (strcmp(*argv, "mtu") == 0) {
287                         NEXT_ARG();
288                         if (mtu != -1)
289                                 duparg("mtu", *argv);
290                         if (get_integer(&mtu, *argv, 0))
291                                 invarg("Invalid \"mtu\" value\n", *argv);
292                 } else if (strcmp(*argv, "multicast") == 0) {
293                         NEXT_ARG();
294                         mask |= IFF_MULTICAST;
295                         if (strcmp(*argv, "on") == 0) {
296                                 flags |= IFF_MULTICAST;
297                         } else if (strcmp(*argv, "off") == 0) {
298                                 flags &= ~IFF_MULTICAST;
299                         } else
300                                 return on_off("multicast");
301                 } else if (strcmp(*argv, "arp") == 0) {
302                         NEXT_ARG();
303                         mask |= IFF_NOARP;
304                         if (strcmp(*argv, "on") == 0) {
305                                 flags &= ~IFF_NOARP;
306                         } else if (strcmp(*argv, "off") == 0) {
307                                 flags |= IFF_NOARP;
308                         } else
309                                 return on_off("noarp");
310 #ifdef IFF_DYNAMIC
311                 } else if (matches(*argv, "dynamic") == 0) {
312                         NEXT_ARG();
313                         mask |= IFF_DYNAMIC;
314                         if (strcmp(*argv, "on") == 0) {
315                                 flags |= IFF_DYNAMIC;
316                         } else if (strcmp(*argv, "off") == 0) {
317                                 flags &= ~IFF_DYNAMIC;
318                         } else
319                                 return on_off("dynamic");
320 #endif
321                 } else {
322                         if (strcmp(*argv, "dev") == 0) {
323                                 NEXT_ARG();
324                         }
325                         if (matches(*argv, "help") == 0)
326                                 usage();
327                         if (dev)
328                                 duparg2("dev", *argv);
329                         dev = *argv;
330                 }
331                 argc--; argv++;
332         }
333
334         if (!dev) {
335                 fprintf(stderr, "Not enough of information: \"dev\" argument is required.\n");
336                 exit(-1);
337         }
338
339         if (newaddr || newbrd) {
340                 halen = get_address(dev, &htype);
341                 if (halen < 0)
342                         return -1;
343                 if (newaddr) {
344                         if (parse_address(dev, htype, halen, newaddr, &ifr0) < 0)
345                                 return -1;
346                 }
347                 if (newbrd) {
348                         if (parse_address(dev, htype, halen, newbrd, &ifr1) < 0)
349                                 return -1; 
350                 }
351         }
352
353         if (newname && strcmp(dev, newname)) {
354                 if (do_changename(dev, newname) < 0)
355                         return -1;
356                 dev = newname;
357         }
358         if (qlen != -1) { 
359                 if (set_qlen(dev, qlen) < 0)
360                         return -1; 
361         }
362         if (mtu != -1) { 
363                 if (set_mtu(dev, mtu) < 0)
364                         return -1; 
365         }
366         if (newaddr || newbrd) {
367                 if (newbrd) {
368                         if (set_address(&ifr1, 1) < 0)
369                                 return -1; 
370                 }
371                 if (newaddr) {
372                         if (set_address(&ifr0, 0) < 0)
373                                 return -1;
374                 }
375         }
376         if (mask)
377                 return do_chflags(dev, flags, mask);
378         return 0;
379 }
380
381 int do_iplink(int argc, char **argv)
382 {
383         if (argc > 0) {
384                 if (matches(*argv, "set") == 0)
385                         return do_set(argc-1, argv+1);
386                 if (matches(*argv, "show") == 0 ||
387                     matches(*argv, "lst") == 0 ||
388                     matches(*argv, "list") == 0)
389                         return ipaddr_list_link(argc-1, argv+1);
390                 if (matches(*argv, "help") == 0)
391                         usage();
392         } else
393                 return ipaddr_list_link(0, NULL);
394
395         fprintf(stderr, "Command \"%s\" is unknown, try \"ip link help\".\n", *argv);
396         exit(-1);
397 }