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