]> rtime.felk.cvut.cz Git - lisovros/iproute2_canprio.git/blob - ip/iplink.c
ca1aaebeeb427e72560c13b5a58b4bfc402a88dc
[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 <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 { dev DEVICE | group DEVGROUP } [ { 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, "                         [ netns NAME ]\n");
71         fprintf(stderr, "                         [ alias NAME ]\n");
72         fprintf(stderr, "                         [ vf NUM [ mac LLADDR ]\n");
73         fprintf(stderr, "                                  [ vlan VLANID [ qos VLAN-QOS ] ]\n");
74
75         fprintf(stderr, "                                  [ rate TXRATE ] ] \n");
76
77         fprintf(stderr, "                                  [ spoofchk { on | off} ] ] \n");
78         fprintf(stderr, "                         [ master DEVICE ]\n");
79         fprintf(stderr, "                         [ nomaster ]\n");
80         fprintf(stderr, "       ip link show [ DEVICE | group GROUP ]\n");
81
82         if (iplink_have_newlink()) {
83                 fprintf(stderr, "\n");
84                 fprintf(stderr, "TYPE := { vlan | veth | vcan | dummy | ifb | macvlan | can | bridge }\n");
85         }
86         exit(-1);
87 }
88
89 static void usage(void)
90 {
91         iplink_usage();
92 }
93
94 static int on_off(char *msg)
95 {
96         fprintf(stderr, "Error: argument of \"%s\" must be \"on\" or \"off\"\n", msg);
97         return -1;
98 }
99
100 static void *BODY;              /* cached dlopen(NULL) handle */
101 static struct link_util *linkutil_list;
102
103 struct link_util *get_link_kind(const char *id)
104 {
105         void *dlh;
106         char buf[256];
107         struct link_util *l;
108
109         for (l = linkutil_list; l; l = l->next)
110                 if (strcmp(l->id, id) == 0)
111                         return l;
112
113         snprintf(buf, sizeof(buf), LIBDIR "/ip/link_%s.so", id);
114         dlh = dlopen(buf, RTLD_LAZY);
115         if (dlh == NULL) {
116                 /* look in current binary, only open once */
117                 dlh = BODY;
118                 if (dlh == NULL) {
119                         dlh = BODY = dlopen(NULL, RTLD_LAZY);
120                         if (dlh == NULL)
121                                 return NULL;
122                 }
123         }
124
125         snprintf(buf, sizeof(buf), "%s_link_util", id);
126         l = dlsym(dlh, buf);
127         if (l == NULL)
128                 return NULL;
129
130         l->next = linkutil_list;
131         linkutil_list = l;
132         return l;
133 }
134
135 #if IPLINK_IOCTL_COMPAT
136 static int have_rtnl_newlink = -1;
137
138 static int accept_msg(const struct sockaddr_nl *who,
139                       struct nlmsghdr *n, void *arg)
140 {
141         struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(n);
142
143         if (n->nlmsg_type == NLMSG_ERROR &&
144             (err->error == -EOPNOTSUPP || err->error == -EINVAL))
145                 have_rtnl_newlink = 0;
146         else
147                 have_rtnl_newlink = 1;
148         return -1;
149 }
150
151 static int iplink_have_newlink(void)
152 {
153         struct {
154                 struct nlmsghdr         n;
155                 struct ifinfomsg        i;
156                 char                    buf[1024];
157         } req;
158
159         if (have_rtnl_newlink < 0) {
160                 memset(&req, 0, sizeof(req));
161
162                 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
163                 req.n.nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK;
164                 req.n.nlmsg_type = RTM_NEWLINK;
165                 req.i.ifi_family = AF_UNSPEC;
166
167                 rtnl_send(&rth, (char *)&req.n, req.n.nlmsg_len);
168                 rtnl_listen(&rth, accept_msg, NULL);
169         }
170         return have_rtnl_newlink;
171 }
172 #else /* IPLINK_IOCTL_COMPAT */
173 static int iplink_have_newlink(void)
174 {
175         return 1;
176 }
177 #endif /* ! IPLINK_IOCTL_COMPAT */
178
179 struct iplink_req {
180         struct nlmsghdr         n;
181         struct ifinfomsg        i;
182         char                    buf[1024];
183 };
184
185 int iplink_parse_vf(int vf, int *argcp, char ***argvp,
186                            struct iplink_req *req)
187 {
188         int len, argc = *argcp;
189         char **argv = *argvp;
190         struct rtattr *vfinfo;
191
192         vfinfo = addattr_nest(&req->n, sizeof(*req), IFLA_VF_INFO);
193
194         while (NEXT_ARG_OK()) {
195                 NEXT_ARG();
196                 if (matches(*argv, "mac") == 0) {
197                         struct ifla_vf_mac ivm;
198                         NEXT_ARG();
199                         ivm.vf = vf;
200                         len = ll_addr_a2n((char *)ivm.mac, 32, *argv);
201                         if (len < 0)
202                                 return -1;
203                         addattr_l(&req->n, sizeof(*req), IFLA_VF_MAC, &ivm, sizeof(ivm));
204                 } else if (matches(*argv, "vlan") == 0) {
205                         struct ifla_vf_vlan ivv;
206                         NEXT_ARG();
207                         if (get_unsigned(&ivv.vlan, *argv, 0)) {
208                                 invarg("Invalid \"vlan\" value\n", *argv);
209                         }
210                         ivv.vf = vf;
211                         ivv.qos = 0;
212                         if (NEXT_ARG_OK()) {
213                                 NEXT_ARG();
214                                 if (matches(*argv, "qos") == 0) {
215                                         NEXT_ARG();
216                                         if (get_unsigned(&ivv.qos, *argv, 0)) {
217                                                 invarg("Invalid \"qos\" value\n", *argv);
218                                         }
219                                 } else {
220                                         /* rewind arg */
221                                         PREV_ARG();
222                                 }
223                         }
224                         addattr_l(&req->n, sizeof(*req), IFLA_VF_VLAN, &ivv, sizeof(ivv));
225                 } else if (matches(*argv, "rate") == 0) {
226                         struct ifla_vf_tx_rate ivt;
227                         NEXT_ARG();
228                         if (get_unsigned(&ivt.rate, *argv, 0)) {
229                                 invarg("Invalid \"rate\" value\n", *argv);
230                         }
231                         ivt.vf = vf;
232                         addattr_l(&req->n, sizeof(*req), IFLA_VF_TX_RATE, &ivt, sizeof(ivt));
233                 
234                 } else if (matches(*argv, "spoofchk") == 0) {
235                         struct ifla_vf_spoofchk ivs;
236                         NEXT_ARG();
237                         if (matches(*argv, "on") == 0)
238                                 ivs.setting = 1;
239                         else if (matches(*argv, "off") == 0)
240                                 ivs.setting = 0;
241                         else
242                                 invarg("Invalid \"spoofchk\" value\n", *argv);
243                         ivs.vf = vf;
244                         addattr_l(&req->n, sizeof(*req), IFLA_VF_SPOOFCHK, &ivs, sizeof(ivs));
245
246                 } else {
247                         /* rewind arg */
248                         PREV_ARG();
249                         break;
250                 }
251         }
252
253         if (argc == *argcp)
254                 incomplete_command();
255
256         addattr_nest_end(&req->n, vfinfo);
257
258         *argcp = argc;
259         *argvp = argv;
260         return 0;
261 }
262
263
264 int iplink_parse(int argc, char **argv, struct iplink_req *req,
265                 char **name, char **type, char **link, char **dev, int *group)
266 {
267         int ret, len;
268         char abuf[32];
269         int qlen = -1;
270         int mtu = -1;
271         int netns = -1;
272         int vf = -1;
273
274         *group = -1;
275         ret = argc;
276
277         while (argc > 0) {
278                 if (strcmp(*argv, "up") == 0) {
279                         req->i.ifi_change |= IFF_UP;
280                         req->i.ifi_flags |= IFF_UP;
281                 } else if (strcmp(*argv, "down") == 0) {
282                         req->i.ifi_change |= IFF_UP;
283                         req->i.ifi_flags &= ~IFF_UP;
284                 } else if (strcmp(*argv, "name") == 0) {
285                         NEXT_ARG();
286                         *name = *argv;
287                 } else if (matches(*argv, "link") == 0) {
288                         NEXT_ARG();
289                         *link = *argv;
290                 } else if (matches(*argv, "address") == 0) {
291                         NEXT_ARG();
292                         len = ll_addr_a2n(abuf, sizeof(abuf), *argv);
293                         if (len < 0)
294                                 return -1;
295                         addattr_l(&req->n, sizeof(*req), IFLA_ADDRESS, abuf, len);
296                 } else if (matches(*argv, "broadcast") == 0 ||
297                                 strcmp(*argv, "brd") == 0) {
298                         NEXT_ARG();
299                         len = ll_addr_a2n(abuf, sizeof(abuf), *argv);
300                         if (len < 0)
301                                 return -1;
302                         addattr_l(&req->n, sizeof(*req), IFLA_BROADCAST, abuf, len);
303                 } else if (matches(*argv, "txqueuelen") == 0 ||
304                                 strcmp(*argv, "qlen") == 0 ||
305                                 matches(*argv, "txqlen") == 0) {
306                         NEXT_ARG();
307                         if (qlen != -1)
308                                 duparg("txqueuelen", *argv);
309                         if (get_integer(&qlen,  *argv, 0))
310                                 invarg("Invalid \"txqueuelen\" value\n", *argv);
311                         addattr_l(&req->n, sizeof(*req), IFLA_TXQLEN, &qlen, 4);
312                 } else if (strcmp(*argv, "mtu") == 0) {
313                         NEXT_ARG();
314                         if (mtu != -1)
315                                 duparg("mtu", *argv);
316                         if (get_integer(&mtu, *argv, 0))
317                                 invarg("Invalid \"mtu\" value\n", *argv);
318                         addattr_l(&req->n, sizeof(*req), IFLA_MTU, &mtu, 4);
319                 } else if (strcmp(*argv, "netns") == 0) {
320                         NEXT_ARG();
321                         if (netns != -1)
322                                 duparg("netns", *argv);
323                         if ((netns = get_netns_fd(*argv)) >= 0)
324                                 addattr_l(&req->n, sizeof(*req), IFLA_NET_NS_FD, &netns, 4);
325                         else if (get_integer(&netns, *argv, 0) == 0)
326                                 addattr_l(&req->n, sizeof(*req), IFLA_NET_NS_PID, &netns, 4);
327                         else
328                                 invarg("Invalid \"netns\" value\n", *argv);
329                 } else if (strcmp(*argv, "multicast") == 0) {
330                         NEXT_ARG();
331                         req->i.ifi_change |= IFF_MULTICAST;
332                         if (strcmp(*argv, "on") == 0) {
333                                 req->i.ifi_flags |= IFF_MULTICAST;
334                         } else if (strcmp(*argv, "off") == 0) {
335                                 req->i.ifi_flags &= ~IFF_MULTICAST;
336                         } else
337                                 return on_off("multicast");
338                 } else if (strcmp(*argv, "allmulticast") == 0) {
339                         NEXT_ARG();
340                         req->i.ifi_change |= IFF_ALLMULTI;
341                         if (strcmp(*argv, "on") == 0) {
342                                 req->i.ifi_flags |= IFF_ALLMULTI;
343                         } else if (strcmp(*argv, "off") == 0) {
344                                 req->i.ifi_flags &= ~IFF_ALLMULTI;
345                         } else
346                                 return on_off("allmulticast");
347                 } else if (strcmp(*argv, "promisc") == 0) {
348                         NEXT_ARG();
349                         req->i.ifi_change |= IFF_PROMISC;
350                         if (strcmp(*argv, "on") == 0) {
351                                 req->i.ifi_flags |= IFF_PROMISC;
352                         } else if (strcmp(*argv, "off") == 0) {
353                                 req->i.ifi_flags &= ~IFF_PROMISC;
354                         } else
355                                 return on_off("promisc");
356                 } else if (strcmp(*argv, "trailers") == 0) {
357                         NEXT_ARG();
358                         req->i.ifi_change |= IFF_NOTRAILERS;
359                         if (strcmp(*argv, "off") == 0) {
360                                 req->i.ifi_flags |= IFF_NOTRAILERS;
361                         } else if (strcmp(*argv, "on") == 0) {
362                                 req->i.ifi_flags &= ~IFF_NOTRAILERS;
363                         } else
364                                 return on_off("trailers");
365                 } else if (strcmp(*argv, "arp") == 0) {
366                         NEXT_ARG();
367                         req->i.ifi_change |= IFF_NOARP;
368                         if (strcmp(*argv, "on") == 0) {
369                                 req->i.ifi_flags &= ~IFF_NOARP;
370                         } else if (strcmp(*argv, "off") == 0) {
371                                 req->i.ifi_flags |= IFF_NOARP;
372                         } else
373                                 return on_off("noarp");
374                 } else if (strcmp(*argv, "vf") == 0) {
375                         struct rtattr *vflist;
376                         NEXT_ARG();
377                         if (get_integer(&vf,  *argv, 0)) {
378                                 invarg("Invalid \"vf\" value\n", *argv);
379                         }
380                         vflist = addattr_nest(&req->n, sizeof(*req),
381                                               IFLA_VFINFO_LIST);
382                         len = iplink_parse_vf(vf, &argc, &argv, req);
383                         if (len < 0)
384                                 return -1;
385                         addattr_nest_end(&req->n, vflist);
386                 } else if (matches(*argv, "master") == 0) {
387                         int ifindex;
388                         NEXT_ARG();
389                         ifindex = ll_name_to_index(*argv);
390                         if (!ifindex)
391                                 invarg("Device does not exist\n", *argv);
392                         addattr_l(&req->n, sizeof(*req), IFLA_MASTER,
393                                   &ifindex, 4);
394                 } else if (matches(*argv, "nomaster") == 0) {
395                         int ifindex = 0;
396                         addattr_l(&req->n, sizeof(*req), IFLA_MASTER,
397                                   &ifindex, 4);
398                 } else if (matches(*argv, "dynamic") == 0) {
399                         NEXT_ARG();
400                         req->i.ifi_change |= IFF_DYNAMIC;
401                         if (strcmp(*argv, "on") == 0) {
402                                 req->i.ifi_flags |= IFF_DYNAMIC;
403                         } else if (strcmp(*argv, "off") == 0) {
404                                 req->i.ifi_flags &= ~IFF_DYNAMIC;
405                         } else
406                                 return on_off("dynamic");
407                 } else if (matches(*argv, "type") == 0) {
408                         NEXT_ARG();
409                         *type = *argv;
410                         argc--; argv++;
411                         break;
412                 } else if (matches(*argv, "alias") == 0) {
413                         NEXT_ARG();
414                         addattr_l(&req->n, sizeof(*req), IFLA_IFALIAS,
415                                   *argv, strlen(*argv));
416                         argc--; argv++;
417                         break;
418                 } else if (strcmp(*argv, "group") == 0) {
419                         NEXT_ARG();
420                         if (*group != -1)
421                                 duparg("group", *argv);
422                         if (rtnl_group_a2n(group, *argv))
423                                 invarg("Invalid \"group\" value\n", *argv);
424                 } else {
425                         if (strcmp(*argv, "dev") == 0) {
426                                 NEXT_ARG();
427                         }
428                         if (matches(*argv, "help") == 0)
429                                 usage();
430                         if (*dev)
431                                 duparg2("dev", *argv);
432                         *dev = *argv;
433                 }
434                 argc--; argv++;
435         }
436
437         return ret - argc;
438 }
439
440 static int iplink_modify(int cmd, unsigned int flags, int argc, char **argv)
441 {
442         int len;
443         char *dev = NULL;
444         char *name = NULL;
445         char *link = NULL;
446         char *type = NULL;
447         int group;
448         struct link_util *lu = NULL;
449         struct iplink_req req;
450         int ret;
451
452         memset(&req, 0, sizeof(req));
453
454         req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
455         req.n.nlmsg_flags = NLM_F_REQUEST|flags;
456         req.n.nlmsg_type = cmd;
457         req.i.ifi_family = preferred_family;
458
459         ret = iplink_parse(argc, argv, &req, &name, &type, &link, &dev, &group);
460         if (ret < 0)
461                 return ret;
462
463         argc -= ret;
464         argv += ret;
465
466         if (group != -1) {
467                 if (dev)
468                         addattr_l(&req.n, sizeof(req), IFLA_GROUP,
469                                         &group, sizeof(group));
470                 else {
471                         if (argc) {
472                                 fprintf(stderr, "Garbage instead of arguments "
473                                                 "\"%s ...\". Try \"ip link "
474                                                 "help\".\n", *argv);
475                                 return -1;
476                         }
477                         if (flags & NLM_F_CREATE) {
478                                 fprintf(stderr, "group cannot be used when "
479                                                 "creating devices.\n");
480                                 return -1;
481                         }
482
483                         req.i.ifi_index = 0;
484                         addattr32(&req.n, sizeof(req), IFLA_GROUP, group);
485                         if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0)
486                                 exit(2);
487                         return 0;
488                 }
489         }
490
491         ll_init_map(&rth);
492
493         if (type) {
494                 struct rtattr *linkinfo = NLMSG_TAIL(&req.n);
495                 addattr_l(&req.n, sizeof(req), IFLA_LINKINFO, NULL, 0);
496                 addattr_l(&req.n, sizeof(req), IFLA_INFO_KIND, type,
497                          strlen(type));
498
499                 lu = get_link_kind(type);
500                 if (lu && argc) {
501                         struct rtattr * data = NLMSG_TAIL(&req.n);
502                         addattr_l(&req.n, sizeof(req), IFLA_INFO_DATA, NULL, 0);
503
504                         if (lu->parse_opt &&
505                             lu->parse_opt(lu, argc, argv, &req.n))
506                                 return -1;
507
508                         data->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)data;
509                 } else if (argc) {
510                         if (matches(*argv, "help") == 0)
511                                 usage();
512                         fprintf(stderr, "Garbage instead of arguments \"%s ...\". "
513                                         "Try \"ip link help\".\n", *argv);
514                         return -1;
515                 }
516                 linkinfo->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)linkinfo;
517         } else if (flags & NLM_F_CREATE) {
518                 fprintf(stderr, "Not enough information: \"type\" argument "
519                                 "is required\n");
520                 return -1;
521         }
522
523         if (!(flags & NLM_F_CREATE)) {
524                 if (!dev) {
525                         fprintf(stderr, "Not enough information: \"dev\" "
526                                         "argument is required.\n");
527                         exit(-1);
528                 }
529
530                 req.i.ifi_index = ll_name_to_index(dev);
531                 if (req.i.ifi_index == 0) {
532                         fprintf(stderr, "Cannot find device \"%s\"\n", dev);
533                         return -1;
534                 }
535         } else {
536                 /* Allow "ip link add dev" and "ip link add name" */
537                 if (!name)
538                         name = dev;
539
540                 if (link) {
541                         int ifindex;
542
543                         ifindex = ll_name_to_index(link);
544                         if (ifindex == 0) {
545                                 fprintf(stderr, "Cannot find device \"%s\"\n",
546                                         link);
547                                 return -1;
548                         }
549                         addattr_l(&req.n, sizeof(req), IFLA_LINK, &ifindex, 4);
550                 }
551         }
552
553         if (name) {
554                 len = strlen(name) + 1;
555                 if (len == 1)
556                         invarg("\"\" is not a valid device identifier\n", "name");
557                 if (len > IFNAMSIZ)
558                         invarg("\"name\" too long\n", name);
559                 addattr_l(&req.n, sizeof(req), IFLA_IFNAME, name, len);
560         }
561
562         if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0)
563                 exit(2);
564
565         return 0;
566 }
567
568 #if IPLINK_IOCTL_COMPAT
569 static int get_ctl_fd(void)
570 {
571         int s_errno;
572         int fd;
573
574         fd = socket(PF_INET, SOCK_DGRAM, 0);
575         if (fd >= 0)
576                 return fd;
577         s_errno = errno;
578         fd = socket(PF_PACKET, SOCK_DGRAM, 0);
579         if (fd >= 0)
580                 return fd;
581         fd = socket(PF_INET6, SOCK_DGRAM, 0);
582         if (fd >= 0)
583                 return fd;
584         errno = s_errno;
585         perror("Cannot create control socket");
586         return -1;
587 }
588
589 static int do_chflags(const char *dev, __u32 flags, __u32 mask)
590 {
591         struct ifreq ifr;
592         int fd;
593         int err;
594
595         strncpy(ifr.ifr_name, dev, IFNAMSIZ);
596         fd = get_ctl_fd();
597         if (fd < 0)
598                 return -1;
599         err = ioctl(fd, SIOCGIFFLAGS, &ifr);
600         if (err) {
601                 perror("SIOCGIFFLAGS");
602                 close(fd);
603                 return -1;
604         }
605         if ((ifr.ifr_flags^flags)&mask) {
606                 ifr.ifr_flags &= ~mask;
607                 ifr.ifr_flags |= mask&flags;
608                 err = ioctl(fd, SIOCSIFFLAGS, &ifr);
609                 if (err)
610                         perror("SIOCSIFFLAGS");
611         }
612         close(fd);
613         return err;
614 }
615
616 static int do_changename(const char *dev, const char *newdev)
617 {
618         struct ifreq ifr;
619         int fd;
620         int err;
621
622         strncpy(ifr.ifr_name, dev, IFNAMSIZ);
623         strncpy(ifr.ifr_newname, newdev, IFNAMSIZ);
624         fd = get_ctl_fd();
625         if (fd < 0)
626                 return -1;
627         err = ioctl(fd, SIOCSIFNAME, &ifr);
628         if (err) {
629                 perror("SIOCSIFNAME");
630                 close(fd);
631                 return -1;
632         }
633         close(fd);
634         return err;
635 }
636
637 static int set_qlen(const char *dev, int qlen)
638 {
639         struct ifreq ifr;
640         int s;
641
642         s = get_ctl_fd();
643         if (s < 0)
644                 return -1;
645
646         memset(&ifr, 0, sizeof(ifr));
647         strncpy(ifr.ifr_name, dev, IFNAMSIZ);
648         ifr.ifr_qlen = qlen;
649         if (ioctl(s, SIOCSIFTXQLEN, &ifr) < 0) {
650                 perror("SIOCSIFXQLEN");
651                 close(s);
652                 return -1;
653         }
654         close(s);
655
656         return 0;
657 }
658
659 static int set_mtu(const char *dev, int mtu)
660 {
661         struct ifreq ifr;
662         int s;
663
664         s = get_ctl_fd();
665         if (s < 0)
666                 return -1;
667
668         memset(&ifr, 0, sizeof(ifr));
669         strncpy(ifr.ifr_name, dev, IFNAMSIZ);
670         ifr.ifr_mtu = mtu;
671         if (ioctl(s, SIOCSIFMTU, &ifr) < 0) {
672                 perror("SIOCSIFMTU");
673                 close(s);
674                 return -1;
675         }
676         close(s);
677
678         return 0;
679 }
680
681 static int get_address(const char *dev, int *htype)
682 {
683         struct ifreq ifr;
684         struct sockaddr_ll me;
685         socklen_t alen;
686         int s;
687
688         s = socket(PF_PACKET, SOCK_DGRAM, 0);
689         if (s < 0) {
690                 perror("socket(PF_PACKET)");
691                 return -1;
692         }
693
694         memset(&ifr, 0, sizeof(ifr));
695         strncpy(ifr.ifr_name, dev, IFNAMSIZ);
696         if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) {
697                 perror("SIOCGIFINDEX");
698                 close(s);
699                 return -1;
700         }
701
702         memset(&me, 0, sizeof(me));
703         me.sll_family = AF_PACKET;
704         me.sll_ifindex = ifr.ifr_ifindex;
705         me.sll_protocol = htons(ETH_P_LOOP);
706         if (bind(s, (struct sockaddr*)&me, sizeof(me)) == -1) {
707                 perror("bind");
708                 close(s);
709                 return -1;
710         }
711
712         alen = sizeof(me);
713         if (getsockname(s, (struct sockaddr*)&me, &alen) == -1) {
714                 perror("getsockname");
715                 close(s);
716                 return -1;
717         }
718         close(s);
719         *htype = me.sll_hatype;
720         return me.sll_halen;
721 }
722
723 static int parse_address(const char *dev, int hatype, int halen,
724                 char *lla, struct ifreq *ifr)
725 {
726         int alen;
727
728         memset(ifr, 0, sizeof(*ifr));
729         strncpy(ifr->ifr_name, dev, IFNAMSIZ);
730         ifr->ifr_hwaddr.sa_family = hatype;
731         alen = ll_addr_a2n(ifr->ifr_hwaddr.sa_data, 14, lla);
732         if (alen < 0)
733                 return -1;
734         if (alen != halen) {
735                 fprintf(stderr, "Wrong address (%s) length: expected %d bytes\n", lla, halen);
736                 return -1;
737         }
738         return 0;
739 }
740
741 static int set_address(struct ifreq *ifr, int brd)
742 {
743         int s;
744
745         s = get_ctl_fd();
746         if (s < 0)
747                 return -1;
748         if (ioctl(s, brd?SIOCSIFHWBROADCAST:SIOCSIFHWADDR, ifr) < 0) {
749                 perror(brd?"SIOCSIFHWBROADCAST":"SIOCSIFHWADDR");
750                 close(s);
751                 return -1;
752         }
753         close(s);
754         return 0;
755 }
756
757
758 static int do_set(int argc, char **argv)
759 {
760         char *dev = NULL;
761         __u32 mask = 0;
762         __u32 flags = 0;
763         int qlen = -1;
764         int mtu = -1;
765         char *newaddr = NULL;
766         char *newbrd = NULL;
767         struct ifreq ifr0, ifr1;
768         char *newname = NULL;
769         int htype, halen;
770
771         while (argc > 0) {
772                 if (strcmp(*argv, "up") == 0) {
773                         mask |= IFF_UP;
774                         flags |= IFF_UP;
775                 } else if (strcmp(*argv, "down") == 0) {
776                         mask |= IFF_UP;
777                         flags &= ~IFF_UP;
778                 } else if (strcmp(*argv, "name") == 0) {
779                         NEXT_ARG();
780                         newname = *argv;
781                 } else if (matches(*argv, "address") == 0) {
782                         NEXT_ARG();
783                         newaddr = *argv;
784                 } else if (matches(*argv, "broadcast") == 0 ||
785                            strcmp(*argv, "brd") == 0) {
786                         NEXT_ARG();
787                         newbrd = *argv;
788                 } else if (matches(*argv, "txqueuelen") == 0 ||
789                            strcmp(*argv, "qlen") == 0 ||
790                            matches(*argv, "txqlen") == 0) {
791                         NEXT_ARG();
792                         if (qlen != -1)
793                                 duparg("txqueuelen", *argv);
794                         if (get_integer(&qlen,  *argv, 0))
795                                 invarg("Invalid \"txqueuelen\" value\n", *argv);
796                 } else if (strcmp(*argv, "mtu") == 0) {
797                         NEXT_ARG();
798                         if (mtu != -1)
799                                 duparg("mtu", *argv);
800                         if (get_integer(&mtu, *argv, 0))
801                                 invarg("Invalid \"mtu\" value\n", *argv);
802                 } else if (strcmp(*argv, "multicast") == 0) {
803                         NEXT_ARG();
804                         mask |= IFF_MULTICAST;
805                         if (strcmp(*argv, "on") == 0) {
806                                 flags |= IFF_MULTICAST;
807                         } else if (strcmp(*argv, "off") == 0) {
808                                 flags &= ~IFF_MULTICAST;
809                         } else
810                                 return on_off("multicast");
811                 } else if (strcmp(*argv, "allmulticast") == 0) {
812                         NEXT_ARG();
813                         mask |= IFF_ALLMULTI;
814                         if (strcmp(*argv, "on") == 0) {
815                                 flags |= IFF_ALLMULTI;
816                         } else if (strcmp(*argv, "off") == 0) {
817                                 flags &= ~IFF_ALLMULTI;
818                         } else
819                                 return on_off("allmulticast");
820                 } else if (strcmp(*argv, "promisc") == 0) {
821                         NEXT_ARG();
822                         mask |= IFF_PROMISC;
823                         if (strcmp(*argv, "on") == 0) {
824                                 flags |= IFF_PROMISC;
825                         } else if (strcmp(*argv, "off") == 0) {
826                                 flags &= ~IFF_PROMISC;
827                         } else
828                                 return on_off("promisc");
829                 } else if (strcmp(*argv, "trailers") == 0) {
830                         NEXT_ARG();
831                         mask |= IFF_NOTRAILERS;
832                         if (strcmp(*argv, "off") == 0) {
833                                 flags |= IFF_NOTRAILERS;
834                         } else if (strcmp(*argv, "on") == 0) {
835                                 flags &= ~IFF_NOTRAILERS;
836                         } else
837                                 return on_off("trailers");
838                 } else if (strcmp(*argv, "arp") == 0) {
839                         NEXT_ARG();
840                         mask |= IFF_NOARP;
841                         if (strcmp(*argv, "on") == 0) {
842                                 flags &= ~IFF_NOARP;
843                         } else if (strcmp(*argv, "off") == 0) {
844                                 flags |= IFF_NOARP;
845                         } else
846                                 return on_off("noarp");
847                 } else if (matches(*argv, "dynamic") == 0) {
848                         NEXT_ARG();
849                         mask |= IFF_DYNAMIC;
850                         if (strcmp(*argv, "on") == 0) {
851                                 flags |= IFF_DYNAMIC;
852                         } else if (strcmp(*argv, "off") == 0) {
853                                 flags &= ~IFF_DYNAMIC;
854                         } else
855                                 return on_off("dynamic");
856                 } else {
857                         if (strcmp(*argv, "dev") == 0) {
858                                 NEXT_ARG();
859                         }
860                         if (matches(*argv, "help") == 0)
861                                 usage();
862                         if (dev)
863                                 duparg2("dev", *argv);
864                         dev = *argv;
865                 }
866                 argc--; argv++;
867         }
868
869         if (!dev) {
870                 fprintf(stderr, "Not enough of information: \"dev\" argument is required.\n");
871                 exit(-1);
872         }
873
874         if (newaddr || newbrd) {
875                 halen = get_address(dev, &htype);
876                 if (halen < 0)
877                         return -1;
878                 if (newaddr) {
879                         if (parse_address(dev, htype, halen, newaddr, &ifr0) < 0)
880                                 return -1;
881                 }
882                 if (newbrd) {
883                         if (parse_address(dev, htype, halen, newbrd, &ifr1) < 0)
884                                 return -1;
885                 }
886         }
887
888         if (newname && strcmp(dev, newname)) {
889                 if (strlen(newname) == 0)
890                         invarg("\"\" is not a valid device identifier\n", "name");
891                 if (do_changename(dev, newname) < 0)
892                         return -1;
893                 dev = newname;
894         }
895         if (qlen != -1) {
896                 if (set_qlen(dev, qlen) < 0)
897                         return -1;
898         }
899         if (mtu != -1) {
900                 if (set_mtu(dev, mtu) < 0)
901                         return -1;
902         }
903         if (newaddr || newbrd) {
904                 if (newbrd) {
905                         if (set_address(&ifr1, 1) < 0)
906                                 return -1;
907                 }
908                 if (newaddr) {
909                         if (set_address(&ifr0, 0) < 0)
910                                 return -1;
911                 }
912         }
913         if (mask)
914                 return do_chflags(dev, flags, mask);
915         return 0;
916 }
917 #endif /* IPLINK_IOCTL_COMPAT */
918
919 int do_iplink(int argc, char **argv)
920 {
921         if (argc > 0) {
922                 if (iplink_have_newlink()) {
923                         if (matches(*argv, "add") == 0)
924                                 return iplink_modify(RTM_NEWLINK,
925                                                      NLM_F_CREATE|NLM_F_EXCL,
926                                                      argc-1, argv+1);
927                         if (matches(*argv, "set") == 0 ||
928                             matches(*argv, "change") == 0)
929                                 return iplink_modify(RTM_NEWLINK, 0,
930                                                      argc-1, argv+1);
931                         if (matches(*argv, "replace") == 0)
932                                 return iplink_modify(RTM_NEWLINK,
933                                                      NLM_F_CREATE|NLM_F_REPLACE,
934                                                      argc-1, argv+1);
935                         if (matches(*argv, "delete") == 0)
936                                 return iplink_modify(RTM_DELLINK, 0,
937                                                      argc-1, argv+1);
938                 } else {
939 #if IPLINK_IOCTL_COMPAT
940                         if (matches(*argv, "set") == 0)
941                                 return do_set(argc-1, argv+1);
942 #endif
943                 }
944                 if (matches(*argv, "show") == 0 ||
945                     matches(*argv, "lst") == 0 ||
946                     matches(*argv, "list") == 0)
947                         return ipaddr_list_link(argc-1, argv+1);
948                 if (matches(*argv, "help") == 0)
949                         usage();
950         } else
951                 return ipaddr_list_link(0, NULL);
952
953         fprintf(stderr, "Command \"%s\" is unknown, try \"ip link help\".\n", *argv);
954         exit(-1);
955 }