Checkign in new iproute2
[iproute2.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 <dlfcn.h>
19 #include <errno.h>
20 #include <sys/socket.h>
21 #include <linux/if.h>
22 #include <linux/if_packet.h>
23 #include <linux/if_ether.h>
24 #include <linux/sockios.h>
25 #include <netinet/in.h>
26 #include <arpa/inet.h>
27 #include <string.h>
28 #include <sys/ioctl.h>
29 #include <linux/sockios.h>
30
31 #include "rt_names.h"
32 #include "utils.h"
33 #include "ip_common.h"
34
35 #define IPLINK_IOCTL_COMPAT     1
36 #ifndef LIBDIR
37 #define LIBDIR "/usr/lib/"
38 #endif
39
40 static void usage(void) __attribute__((noreturn));
41 static int iplink_have_newlink(void);
42
43 void iplink_usage(void)
44 {
45         if (iplink_have_newlink()) {
46                 fprintf(stderr, "Usage: ip link add link DEV [ name ] NAME\n");
47                 fprintf(stderr, "                   [ txqueuelen PACKETS ]\n");
48                 fprintf(stderr, "                   [ address LLADDR ]\n");
49                 fprintf(stderr, "                   [ broadcast LLADDR ]\n");
50                 fprintf(stderr, "                   [ mtu MTU ]\n");
51                 fprintf(stderr, "                   type TYPE [ ARGS ]\n");
52                 fprintf(stderr, "       ip link delete DEV type TYPE [ ARGS ]\n");
53                 fprintf(stderr, "\n");
54                 fprintf(stderr, "       ip link set DEVICE [ { up | down } ]\n");
55         } else
56                 fprintf(stderr, "Usage: ip link set DEVICE [ { up | down } ]\n");
57
58         fprintf(stderr, "                         [ arp { on | off } ]\n");
59         fprintf(stderr, "                         [ dynamic { on | off } ]\n");
60         fprintf(stderr, "                         [ multicast { on | off } ]\n");
61         fprintf(stderr, "                         [ allmulticast { on | off } ]\n");
62         fprintf(stderr, "                         [ promisc { on | off } ]\n");
63         fprintf(stderr, "                         [ trailers { on | off } ]\n");
64         fprintf(stderr, "                         [ txqueuelen PACKETS ]\n");
65         fprintf(stderr, "                         [ name NEWNAME ]\n");
66         fprintf(stderr, "                         [ address LLADDR ]\n");
67         fprintf(stderr, "                         [ broadcast LLADDR ]\n");
68         fprintf(stderr, "                         [ mtu MTU ]\n");
69         fprintf(stderr, "                         [ netns PID ]\n");
70         fprintf(stderr, "       ip link show [ DEVICE ]\n");
71
72         if (iplink_have_newlink()) {
73                 fprintf(stderr, "\n");
74                 fprintf(stderr, "TYPE := { vlan | veth | dummy | ifb | macvlan }\n");
75         }
76         exit(-1);
77 }
78
79 static void usage(void)
80 {
81         iplink_usage();
82 }
83
84 static int on_off(char *msg)
85 {
86         fprintf(stderr, "Error: argument of \"%s\" must be \"on\" or \"off\"\n", msg);
87         return -1;
88 }
89
90 static void *BODY;              /* cached dlopen(NULL) handle */
91 static struct link_util *linkutil_list;
92
93 struct link_util *get_link_kind(const char *id)
94 {
95         void *dlh;
96         char buf[256];
97         struct link_util *l;
98
99         for (l = linkutil_list; l; l = l->next)
100                 if (strcmp(l->id, id) == 0)
101                         return l;
102
103         snprintf(buf, sizeof(buf), LIBDIR "/ip/link_%s.so", id);
104         dlh = dlopen(buf, RTLD_LAZY);
105         if (dlh == NULL) {
106                 /* look in current binary, only open once */
107                 dlh = BODY;
108                 if (dlh == NULL) {
109                         dlh = BODY = dlopen(NULL, RTLD_LAZY);
110                         if (dlh == NULL)
111                                 return NULL;
112                 }
113         }
114
115         snprintf(buf, sizeof(buf), "%s_link_util", id);
116         l = dlsym(dlh, buf);
117         if (l == NULL)
118                 return NULL;
119
120         l->next = linkutil_list;
121         linkutil_list = l;
122         return l;
123 }
124
125 #if IPLINK_IOCTL_COMPAT
126 static int have_rtnl_newlink = -1;
127
128 static int accept_msg(const struct sockaddr_nl *who,
129                       struct nlmsghdr *n, void *arg)
130 {
131         struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(n);
132
133         if (n->nlmsg_type == NLMSG_ERROR &&
134             (err->error == -EOPNOTSUPP || err->error == -EINVAL))
135                 have_rtnl_newlink = 0;
136         else
137                 have_rtnl_newlink = 1;
138         return -1;
139 }
140
141 static int iplink_have_newlink(void)
142 {
143         struct {
144                 struct nlmsghdr         n;
145                 struct ifinfomsg        i;
146                 char                    buf[1024];
147         } req;
148
149         if (have_rtnl_newlink < 0) {
150                 memset(&req, 0, sizeof(req));
151
152                 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
153                 req.n.nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK;
154                 req.n.nlmsg_type = RTM_NEWLINK;
155                 req.i.ifi_family = AF_UNSPEC;
156
157                 rtnl_send(&rth, (char *)&req.n, req.n.nlmsg_len);
158                 rtnl_listen(&rth, accept_msg, NULL);
159         }
160         return have_rtnl_newlink;
161 }
162 #else /* IPLINK_IOCTL_COMPAT */
163 static int iplink_have_newlink(void)
164 {
165         return 1;
166 }
167 #endif /* ! IPLINK_IOCTL_COMPAT */
168
169 struct iplink_req {
170         struct nlmsghdr         n;
171         struct ifinfomsg        i;
172         char                    buf[1024];
173 };
174
175 int iplink_parse(int argc, char **argv, struct iplink_req *req,
176                 char **name, char **type, char **link, char **dev)
177 {
178         int ret, len;
179         char abuf[32];
180         int qlen = -1;
181         int mtu = -1;
182         int netns = -1;
183
184         ret = argc;
185
186         while (argc > 0) {
187                 if (strcmp(*argv, "up") == 0) {
188                         req->i.ifi_change |= IFF_UP;
189                         req->i.ifi_flags |= IFF_UP;
190                 } else if (strcmp(*argv, "down") == 0) {
191                         req->i.ifi_change |= IFF_UP;
192                         req->i.ifi_flags &= ~IFF_UP;
193                 } else if (strcmp(*argv, "name") == 0) {
194                         NEXT_ARG();
195                         *name = *argv;
196                 } else if (matches(*argv, "link") == 0) {
197                         NEXT_ARG();
198                         *link = *argv;
199                 } else if (matches(*argv, "address") == 0) {
200                         NEXT_ARG();
201                         len = ll_addr_a2n(abuf, sizeof(abuf), *argv);
202                         addattr_l(&req->n, sizeof(*req), IFLA_ADDRESS, abuf, len);
203                 } else if (matches(*argv, "broadcast") == 0 ||
204                                 strcmp(*argv, "brd") == 0) {
205                         NEXT_ARG();
206                         len = ll_addr_a2n(abuf, sizeof(abuf), *argv);
207                         addattr_l(&req->n, sizeof(*req), IFLA_BROADCAST, abuf, len);
208                 } else if (matches(*argv, "txqueuelen") == 0 ||
209                                 strcmp(*argv, "qlen") == 0 ||
210                                 matches(*argv, "txqlen") == 0) {
211                         NEXT_ARG();
212                         if (qlen != -1)
213                                 duparg("txqueuelen", *argv);
214                         if (get_integer(&qlen,  *argv, 0))
215                                 invarg("Invalid \"txqueuelen\" value\n", *argv);
216                         addattr_l(&req->n, sizeof(*req), IFLA_TXQLEN, &qlen, 4);
217                 } else if (strcmp(*argv, "mtu") == 0) {
218                         NEXT_ARG();
219                         if (mtu != -1)
220                                 duparg("mtu", *argv);
221                         if (get_integer(&mtu, *argv, 0))
222                                 invarg("Invalid \"mtu\" value\n", *argv);
223                         addattr_l(&req->n, sizeof(*req), IFLA_MTU, &mtu, 4);
224                 } else if (strcmp(*argv, "netns") == 0) {
225                         NEXT_ARG();
226                         if (netns != -1)
227                                 duparg("netns", *argv);
228                         if (get_integer(&netns, *argv, 0))
229                                 invarg("Invalid \"netns\" value\n", *argv);
230                         addattr_l(&req->n, sizeof(*req), IFLA_NET_NS_PID, &netns, 4);
231                 } else if (strcmp(*argv, "multicast") == 0) {
232                         NEXT_ARG();
233                         req->i.ifi_change |= IFF_MULTICAST;
234                         if (strcmp(*argv, "on") == 0) {
235                                 req->i.ifi_flags |= IFF_MULTICAST;
236                         } else if (strcmp(*argv, "off") == 0) {
237                                 req->i.ifi_flags &= ~IFF_MULTICAST;
238                         } else
239                                 return on_off("multicast");
240                 } else if (strcmp(*argv, "allmulticast") == 0) {
241                         NEXT_ARG();
242                         req->i.ifi_change |= IFF_ALLMULTI;
243                         if (strcmp(*argv, "on") == 0) {
244                                 req->i.ifi_flags |= IFF_ALLMULTI;
245                         } else if (strcmp(*argv, "off") == 0) {
246                                 req->i.ifi_flags &= ~IFF_ALLMULTI;
247                         } else
248                                 return on_off("allmulticast");
249                 } else if (strcmp(*argv, "promisc") == 0) {
250                         NEXT_ARG();
251                         req->i.ifi_change |= IFF_PROMISC;
252                         if (strcmp(*argv, "on") == 0) {
253                                 req->i.ifi_flags |= IFF_PROMISC;
254                         } else if (strcmp(*argv, "off") == 0) {
255                                 req->i.ifi_flags &= ~IFF_PROMISC;
256                         } else
257                                 return on_off("promisc");
258                 } else if (strcmp(*argv, "trailers") == 0) {
259                         NEXT_ARG();
260                         req->i.ifi_change |= IFF_NOTRAILERS;
261                         if (strcmp(*argv, "off") == 0) {
262                                 req->i.ifi_flags |= IFF_NOTRAILERS;
263                         } else if (strcmp(*argv, "on") == 0) {
264                                 req->i.ifi_flags &= ~IFF_NOTRAILERS;
265                         } else
266                                 return on_off("trailers");
267                 } else if (strcmp(*argv, "arp") == 0) {
268                         NEXT_ARG();
269                         req->i.ifi_change |= IFF_NOARP;
270                         if (strcmp(*argv, "on") == 0) {
271                                 req->i.ifi_flags &= ~IFF_NOARP;
272                         } else if (strcmp(*argv, "off") == 0) {
273                                 req->i.ifi_flags |= IFF_NOARP;
274                         } else
275                                 return on_off("noarp");
276 #ifdef IFF_DYNAMIC
277                 } else if (matches(*argv, "dynamic") == 0) {
278                         NEXT_ARG();
279                         req->i.ifi_change |= IFF_DYNAMIC;
280                         if (strcmp(*argv, "on") == 0) {
281                                 req->i.ifi_flags |= IFF_DYNAMIC;
282                         } else if (strcmp(*argv, "off") == 0) {
283                                 req->i.ifi_flags &= ~IFF_DYNAMIC;
284                         } else
285                                 return on_off("dynamic");
286 #endif
287                 } else if (matches(*argv, "type") == 0) {
288                         NEXT_ARG();
289                         *type = *argv;
290                         argc--; argv++;
291                         break;
292                 } else {
293                         if (strcmp(*argv, "dev") == 0) {
294                                 NEXT_ARG();
295                         }
296                         if (matches(*argv, "help") == 0)
297                                 usage();
298                         if (*dev)
299                                 duparg2("dev", *argv);
300                         *dev = *argv;
301                 }
302                 argc--; argv++;
303         }
304
305         return ret - argc;
306 }
307
308 static int iplink_modify(int cmd, unsigned int flags, int argc, char **argv)
309 {
310         int len;
311         char *dev = NULL;
312         char *name = NULL;
313         char *link = NULL;
314         char *type = NULL;
315         struct link_util *lu = NULL;
316         struct iplink_req req;
317         int ret;
318
319         memset(&req, 0, sizeof(req));
320
321         req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
322         req.n.nlmsg_flags = NLM_F_REQUEST|flags;
323         req.n.nlmsg_type = cmd;
324         req.i.ifi_family = preferred_family;
325
326         ret = iplink_parse(argc, argv, &req, &name, &type, &link, &dev);
327         if (ret < 0)
328                 return ret;
329
330         argc -= ret;
331         argv += ret;
332         ll_init_map(&rth);
333
334         if (type) {
335                 struct rtattr *linkinfo = NLMSG_TAIL(&req.n);
336                 addattr_l(&req.n, sizeof(req), IFLA_LINKINFO, NULL, 0);
337                 addattr_l(&req.n, sizeof(req), IFLA_INFO_KIND, type,
338                          strlen(type));
339
340                 lu = get_link_kind(type);
341                 if (lu && argc) {
342                         struct rtattr * data = NLMSG_TAIL(&req.n);
343                         addattr_l(&req.n, sizeof(req), IFLA_INFO_DATA, NULL, 0);
344
345                         if (lu->parse_opt &&
346                             lu->parse_opt(lu, argc, argv, &req.n))
347                                 return -1;
348
349                         data->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)data;
350                 } else if (argc) {
351                         if (matches(*argv, "help") == 0)
352                                 usage();
353                         fprintf(stderr, "Garbage instead of arguments \"%s ...\". "
354                                         "Try \"ip link help\".\n", *argv);
355                         return -1;
356                 }
357                 linkinfo->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)linkinfo;
358         } else if (flags & NLM_F_CREATE) {
359                 fprintf(stderr, "Not enough information: \"type\" argument "
360                                 "is required\n");
361                 return -1;
362         }
363
364         if (!(flags & NLM_F_CREATE)) {
365                 if (!dev) {
366                         fprintf(stderr, "Not enough information: \"dev\" "
367                                         "argument is required.\n");
368                         exit(-1);
369                 }
370
371                 req.i.ifi_index = ll_name_to_index(dev);
372                 if (req.i.ifi_index == 0) {
373                         fprintf(stderr, "Cannot find device \"%s\"\n", dev);
374                         return -1;
375                 }
376         } else {
377                 /* Allow "ip link add dev" and "ip link add name" */
378                 if (!name)
379                         name = dev;
380
381                 if (link) {
382                         int ifindex;
383
384                         ifindex = ll_name_to_index(link);
385                         if (ifindex == 0) {
386                                 fprintf(stderr, "Cannot find device \"%s\"\n",
387                                         link);
388                                 return -1;
389                         }
390                         addattr_l(&req.n, sizeof(req), IFLA_LINK, &ifindex, 4);
391                 }
392         }
393
394         if (name) {
395                 len = strlen(name) + 1;
396                 if (len == 1)
397                         invarg("\"\" is not a valid device identifier\n", "name");
398                 if (len > IFNAMSIZ)
399                         invarg("\"name\" too long\n", name);
400                 addattr_l(&req.n, sizeof(req), IFLA_IFNAME, name, len);
401         }
402
403         if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0)
404                 exit(2);
405
406         return 0;
407 }
408
409 #if IPLINK_IOCTL_COMPAT
410 static int get_ctl_fd(void)
411 {
412         int s_errno;
413         int fd;
414
415         fd = socket(PF_INET, SOCK_DGRAM, 0);
416         if (fd >= 0)
417                 return fd;
418         s_errno = errno;
419         fd = socket(PF_PACKET, SOCK_DGRAM, 0);
420         if (fd >= 0)
421                 return fd;
422         fd = socket(PF_INET6, SOCK_DGRAM, 0);
423         if (fd >= 0)
424                 return fd;
425         errno = s_errno;
426         perror("Cannot create control socket");
427         return -1;
428 }
429
430 static int do_chflags(const char *dev, __u32 flags, __u32 mask)
431 {
432         struct ifreq ifr;
433         int fd;
434         int err;
435
436         strncpy(ifr.ifr_name, dev, IFNAMSIZ);
437         fd = get_ctl_fd();
438         if (fd < 0)
439                 return -1;
440         err = ioctl(fd, SIOCGIFFLAGS, &ifr);
441         if (err) {
442                 perror("SIOCGIFFLAGS");
443                 close(fd);
444                 return -1;
445         }
446         if ((ifr.ifr_flags^flags)&mask) {
447                 ifr.ifr_flags &= ~mask;
448                 ifr.ifr_flags |= mask&flags;
449                 err = ioctl(fd, SIOCSIFFLAGS, &ifr);
450                 if (err)
451                         perror("SIOCSIFFLAGS");
452         }
453         close(fd);
454         return err;
455 }
456
457 static int do_changename(const char *dev, const char *newdev)
458 {
459         struct ifreq ifr;
460         int fd;
461         int err;
462
463         strncpy(ifr.ifr_name, dev, IFNAMSIZ);
464         strncpy(ifr.ifr_newname, newdev, IFNAMSIZ);
465         fd = get_ctl_fd();
466         if (fd < 0)
467                 return -1;
468         err = ioctl(fd, SIOCSIFNAME, &ifr);
469         if (err) {
470                 perror("SIOCSIFNAME");
471                 close(fd);
472                 return -1;
473         }
474         close(fd);
475         return err;
476 }
477
478 static int set_qlen(const char *dev, int qlen)
479 {
480         struct ifreq ifr;
481         int s;
482
483         s = get_ctl_fd();
484         if (s < 0)
485                 return -1;
486
487         memset(&ifr, 0, sizeof(ifr));
488         strncpy(ifr.ifr_name, dev, IFNAMSIZ);
489         ifr.ifr_qlen = qlen;
490         if (ioctl(s, SIOCSIFTXQLEN, &ifr) < 0) {
491                 perror("SIOCSIFXQLEN");
492                 close(s);
493                 return -1;
494         }
495         close(s);
496
497         return 0;
498 }
499
500 static int set_mtu(const char *dev, int mtu)
501 {
502         struct ifreq ifr;
503         int s;
504
505         s = get_ctl_fd();
506         if (s < 0)
507                 return -1;
508
509         memset(&ifr, 0, sizeof(ifr));
510         strncpy(ifr.ifr_name, dev, IFNAMSIZ);
511         ifr.ifr_mtu = mtu;
512         if (ioctl(s, SIOCSIFMTU, &ifr) < 0) {
513                 perror("SIOCSIFMTU");
514                 close(s);
515                 return -1;
516         }
517         close(s);
518
519         return 0;
520 }
521
522 static int get_address(const char *dev, int *htype)
523 {
524         struct ifreq ifr;
525         struct sockaddr_ll me;
526         socklen_t alen;
527         int s;
528
529         s = socket(PF_PACKET, SOCK_DGRAM, 0);
530         if (s < 0) {
531                 perror("socket(PF_PACKET)");
532                 return -1;
533         }
534
535         memset(&ifr, 0, sizeof(ifr));
536         strncpy(ifr.ifr_name, dev, IFNAMSIZ);
537         if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) {
538                 perror("SIOCGIFINDEX");
539                 close(s);
540                 return -1;
541         }
542
543         memset(&me, 0, sizeof(me));
544         me.sll_family = AF_PACKET;
545         me.sll_ifindex = ifr.ifr_ifindex;
546         me.sll_protocol = htons(ETH_P_LOOP);
547         if (bind(s, (struct sockaddr*)&me, sizeof(me)) == -1) {
548                 perror("bind");
549                 close(s);
550                 return -1;
551         }
552
553         alen = sizeof(me);
554         if (getsockname(s, (struct sockaddr*)&me, &alen) == -1) {
555                 perror("getsockname");
556                 close(s);
557                 return -1;
558         }
559         close(s);
560         *htype = me.sll_hatype;
561         return me.sll_halen;
562 }
563
564 static int parse_address(const char *dev, int hatype, int halen,
565                 char *lla, struct ifreq *ifr)
566 {
567         int alen;
568
569         memset(ifr, 0, sizeof(*ifr));
570         strncpy(ifr->ifr_name, dev, IFNAMSIZ);
571         ifr->ifr_hwaddr.sa_family = hatype;
572         alen = ll_addr_a2n(ifr->ifr_hwaddr.sa_data, 14, lla);
573         if (alen < 0)
574                 return -1;
575         if (alen != halen) {
576                 fprintf(stderr, "Wrong address (%s) length: expected %d bytes\n", lla, halen);
577                 return -1;
578         }
579         return 0;
580 }
581
582 static int set_address(struct ifreq *ifr, int brd)
583 {
584         int s;
585
586         s = get_ctl_fd();
587         if (s < 0)
588                 return -1;
589         if (ioctl(s, brd?SIOCSIFHWBROADCAST:SIOCSIFHWADDR, ifr) < 0) {
590                 perror(brd?"SIOCSIFHWBROADCAST":"SIOCSIFHWADDR");
591                 close(s);
592                 return -1;
593         }
594         close(s);
595         return 0;
596 }
597
598
599 static int do_set(int argc, char **argv)
600 {
601         char *dev = NULL;
602         __u32 mask = 0;
603         __u32 flags = 0;
604         int qlen = -1;
605         int mtu = -1;
606         char *newaddr = NULL;
607         char *newbrd = NULL;
608         struct ifreq ifr0, ifr1;
609         char *newname = NULL;
610         int htype, halen;
611
612         while (argc > 0) {
613                 if (strcmp(*argv, "up") == 0) {
614                         mask |= IFF_UP;
615                         flags |= IFF_UP;
616                 } else if (strcmp(*argv, "down") == 0) {
617                         mask |= IFF_UP;
618                         flags &= ~IFF_UP;
619                 } else if (strcmp(*argv, "name") == 0) {
620                         NEXT_ARG();
621                         newname = *argv;
622                 } else if (matches(*argv, "address") == 0) {
623                         NEXT_ARG();
624                         newaddr = *argv;
625                 } else if (matches(*argv, "broadcast") == 0 ||
626                            strcmp(*argv, "brd") == 0) {
627                         NEXT_ARG();
628                         newbrd = *argv;
629                 } else if (matches(*argv, "txqueuelen") == 0 ||
630                            strcmp(*argv, "qlen") == 0 ||
631                            matches(*argv, "txqlen") == 0) {
632                         NEXT_ARG();
633                         if (qlen != -1)
634                                 duparg("txqueuelen", *argv);
635                         if (get_integer(&qlen,  *argv, 0))
636                                 invarg("Invalid \"txqueuelen\" value\n", *argv);
637                 } else if (strcmp(*argv, "mtu") == 0) {
638                         NEXT_ARG();
639                         if (mtu != -1)
640                                 duparg("mtu", *argv);
641                         if (get_integer(&mtu, *argv, 0))
642                                 invarg("Invalid \"mtu\" value\n", *argv);
643                 } else if (strcmp(*argv, "multicast") == 0) {
644                         NEXT_ARG();
645                         mask |= IFF_MULTICAST;
646                         if (strcmp(*argv, "on") == 0) {
647                                 flags |= IFF_MULTICAST;
648                         } else if (strcmp(*argv, "off") == 0) {
649                                 flags &= ~IFF_MULTICAST;
650                         } else
651                                 return on_off("multicast");
652                 } else if (strcmp(*argv, "allmulticast") == 0) {
653                         NEXT_ARG();
654                         mask |= IFF_ALLMULTI;
655                         if (strcmp(*argv, "on") == 0) {
656                                 flags |= IFF_ALLMULTI;
657                         } else if (strcmp(*argv, "off") == 0) {
658                                 flags &= ~IFF_ALLMULTI;
659                         } else
660                                 return on_off("allmulticast");
661                 } else if (strcmp(*argv, "promisc") == 0) {
662                         NEXT_ARG();
663                         mask |= IFF_PROMISC;
664                         if (strcmp(*argv, "on") == 0) {
665                                 flags |= IFF_PROMISC;
666                         } else if (strcmp(*argv, "off") == 0) {
667                                 flags &= ~IFF_PROMISC;
668                         } else
669                                 return on_off("promisc");
670                 } else if (strcmp(*argv, "trailers") == 0) {
671                         NEXT_ARG();
672                         mask |= IFF_NOTRAILERS;
673                         if (strcmp(*argv, "off") == 0) {
674                                 flags |= IFF_NOTRAILERS;
675                         } else if (strcmp(*argv, "on") == 0) {
676                                 flags &= ~IFF_NOTRAILERS;
677                         } else
678                                 return on_off("trailers");
679                 } else if (strcmp(*argv, "arp") == 0) {
680                         NEXT_ARG();
681                         mask |= IFF_NOARP;
682                         if (strcmp(*argv, "on") == 0) {
683                                 flags &= ~IFF_NOARP;
684                         } else if (strcmp(*argv, "off") == 0) {
685                                 flags |= IFF_NOARP;
686                         } else
687                                 return on_off("noarp");
688 #ifdef IFF_DYNAMIC
689                 } else if (matches(*argv, "dynamic") == 0) {
690                         NEXT_ARG();
691                         mask |= IFF_DYNAMIC;
692                         if (strcmp(*argv, "on") == 0) {
693                                 flags |= IFF_DYNAMIC;
694                         } else if (strcmp(*argv, "off") == 0) {
695                                 flags &= ~IFF_DYNAMIC;
696                         } else
697                                 return on_off("dynamic");
698 #endif
699                 } else {
700                         if (strcmp(*argv, "dev") == 0) {
701                                 NEXT_ARG();
702                         }
703                         if (matches(*argv, "help") == 0)
704                                 usage();
705                         if (dev)
706                                 duparg2("dev", *argv);
707                         dev = *argv;
708                 }
709                 argc--; argv++;
710         }
711
712         if (!dev) {
713                 fprintf(stderr, "Not enough of information: \"dev\" argument is required.\n");
714                 exit(-1);
715         }
716
717         if (newaddr || newbrd) {
718                 halen = get_address(dev, &htype);
719                 if (halen < 0)
720                         return -1;
721                 if (newaddr) {
722                         if (parse_address(dev, htype, halen, newaddr, &ifr0) < 0)
723                                 return -1;
724                 }
725                 if (newbrd) {
726                         if (parse_address(dev, htype, halen, newbrd, &ifr1) < 0)
727                                 return -1;
728                 }
729         }
730
731         if (newname && strcmp(dev, newname)) {
732                 if (strlen(newname) == 0)
733                         invarg("\"\" is not a valid device identifier\n", "name");
734                 if (do_changename(dev, newname) < 0)
735                         return -1;
736                 dev = newname;
737         }
738         if (qlen != -1) {
739                 if (set_qlen(dev, qlen) < 0)
740                         return -1;
741         }
742         if (mtu != -1) {
743                 if (set_mtu(dev, mtu) < 0)
744                         return -1;
745         }
746         if (newaddr || newbrd) {
747                 if (newbrd) {
748                         if (set_address(&ifr1, 1) < 0)
749                                 return -1;
750                 }
751                 if (newaddr) {
752                         if (set_address(&ifr0, 0) < 0)
753                                 return -1;
754                 }
755         }
756         if (mask)
757                 return do_chflags(dev, flags, mask);
758         return 0;
759 }
760 #endif /* IPLINK_IOCTL_COMPAT */
761
762 int do_iplink(int argc, char **argv)
763 {
764         if (argc > 0) {
765                 if (iplink_have_newlink()) {
766                         if (matches(*argv, "add") == 0)
767                                 return iplink_modify(RTM_NEWLINK,
768                                                      NLM_F_CREATE|NLM_F_EXCL,
769                                                      argc-1, argv+1);
770                         if (matches(*argv, "set") == 0 ||
771                             matches(*argv, "change") == 0)
772                                 return iplink_modify(RTM_NEWLINK, 0,
773                                                      argc-1, argv+1);
774                         if (matches(*argv, "replace") == 0)
775                                 return iplink_modify(RTM_NEWLINK,
776                                                      NLM_F_CREATE|NLM_F_REPLACE,
777                                                      argc-1, argv+1);
778                         if (matches(*argv, "delete") == 0)
779                                 return iplink_modify(RTM_DELLINK, 0,
780                                                      argc-1, argv+1);
781                 } else {
782 #if IPLINK_IOCTL_COMPAT
783                         if (matches(*argv, "set") == 0)
784                                 return do_set(argc-1, argv+1);
785 #endif
786                 }
787                 if (matches(*argv, "show") == 0 ||
788                     matches(*argv, "lst") == 0 ||
789                     matches(*argv, "list") == 0)
790                         return ipaddr_list_link(argc-1, argv+1);
791                 if (matches(*argv, "help") == 0)
792                         usage();
793         } else
794                 return ipaddr_list_link(0, NULL);
795
796         fprintf(stderr, "Command \"%s\" is unknown, try \"ip link help\".\n", *argv);
797         exit(-1);
798 }