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