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