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