iplink.c revision db02608b6f408998ea8c823fb791cead3e574f50
1/* 2 * iplink.c "ip link". 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public License 6 * as published by the Free Software Foundation; either version 7 * 2 of the License, or (at your option) any later version. 8 * 9 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> 10 * 11 */ 12 13#include <stdio.h> 14#include <stdlib.h> 15#include <unistd.h> 16#include <syslog.h> 17#include <fcntl.h> 18#include <dlfcn.h> 19#include <errno.h> 20#include <sys/socket.h> 21#include <linux/if.h> 22#include <linux/if_packet.h> 23#include <linux/if_ether.h> 24#include <linux/sockios.h> 25#include <netinet/in.h> 26#include <arpa/inet.h> 27#include <string.h> 28#include <sys/ioctl.h> 29#include <linux/sockios.h> 30 31#include "rt_names.h" 32#include "utils.h" 33#include "ip_common.h" 34 35#define IPLINK_IOCTL_COMPAT 1 36#ifndef LIBDIR 37#define LIBDIR "/usr/lib/" 38#endif 39 40static void usage(void) __attribute__((noreturn)); 41static int iplink_have_newlink(void); 42 43void 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, " [ 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 | group GROUP ]\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 83static void usage(void) 84{ 85 iplink_usage(); 86} 87 88static 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 94static void *BODY; /* cached dlopen(NULL) handle */ 95static struct link_util *linkutil_list; 96 97struct 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 130static int have_rtnl_newlink = -1; 131 132static 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 145static 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 */ 167static int iplink_have_newlink(void) 168{ 169 return 1; 170} 171#endif /* ! IPLINK_IOCTL_COMPAT */ 172 173struct iplink_req { 174 struct nlmsghdr n; 175 struct ifinfomsg i; 176 char buf[1024]; 177}; 178 179int 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 246int iplink_parse(int argc, char **argv, struct iplink_req *req, 247 char **name, char **type, char **link, char **dev, int *group) 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 *group = -1; 257 ret = argc; 258 259 while (argc > 0) { 260 if (strcmp(*argv, "up") == 0) { 261 req->i.ifi_change |= IFF_UP; 262 req->i.ifi_flags |= IFF_UP; 263 } else if (strcmp(*argv, "down") == 0) { 264 req->i.ifi_change |= IFF_UP; 265 req->i.ifi_flags &= ~IFF_UP; 266 } else if (strcmp(*argv, "name") == 0) { 267 NEXT_ARG(); 268 *name = *argv; 269 } else if (matches(*argv, "link") == 0) { 270 NEXT_ARG(); 271 *link = *argv; 272 } else if (matches(*argv, "address") == 0) { 273 NEXT_ARG(); 274 len = ll_addr_a2n(abuf, sizeof(abuf), *argv); 275 if (len < 0) 276 return -1; 277 addattr_l(&req->n, sizeof(*req), IFLA_ADDRESS, abuf, len); 278 } else if (matches(*argv, "broadcast") == 0 || 279 strcmp(*argv, "brd") == 0) { 280 NEXT_ARG(); 281 len = ll_addr_a2n(abuf, sizeof(abuf), *argv); 282 if (len < 0) 283 return -1; 284 addattr_l(&req->n, sizeof(*req), IFLA_BROADCAST, abuf, len); 285 } else if (matches(*argv, "txqueuelen") == 0 || 286 strcmp(*argv, "qlen") == 0 || 287 matches(*argv, "txqlen") == 0) { 288 NEXT_ARG(); 289 if (qlen != -1) 290 duparg("txqueuelen", *argv); 291 if (get_integer(&qlen, *argv, 0)) 292 invarg("Invalid \"txqueuelen\" value\n", *argv); 293 addattr_l(&req->n, sizeof(*req), IFLA_TXQLEN, &qlen, 4); 294 } else if (strcmp(*argv, "mtu") == 0) { 295 NEXT_ARG(); 296 if (mtu != -1) 297 duparg("mtu", *argv); 298 if (get_integer(&mtu, *argv, 0)) 299 invarg("Invalid \"mtu\" value\n", *argv); 300 addattr_l(&req->n, sizeof(*req), IFLA_MTU, &mtu, 4); 301 } else if (strcmp(*argv, "netns") == 0) { 302 NEXT_ARG(); 303 if (netns != -1) 304 duparg("netns", *argv); 305 if (get_integer(&netns, *argv, 0)) 306 invarg("Invalid \"netns\" value\n", *argv); 307 addattr_l(&req->n, sizeof(*req), IFLA_NET_NS_PID, &netns, 4); 308 } else if (strcmp(*argv, "multicast") == 0) { 309 NEXT_ARG(); 310 req->i.ifi_change |= IFF_MULTICAST; 311 if (strcmp(*argv, "on") == 0) { 312 req->i.ifi_flags |= IFF_MULTICAST; 313 } else if (strcmp(*argv, "off") == 0) { 314 req->i.ifi_flags &= ~IFF_MULTICAST; 315 } else 316 return on_off("multicast"); 317 } else if (strcmp(*argv, "allmulticast") == 0) { 318 NEXT_ARG(); 319 req->i.ifi_change |= IFF_ALLMULTI; 320 if (strcmp(*argv, "on") == 0) { 321 req->i.ifi_flags |= IFF_ALLMULTI; 322 } else if (strcmp(*argv, "off") == 0) { 323 req->i.ifi_flags &= ~IFF_ALLMULTI; 324 } else 325 return on_off("allmulticast"); 326 } else if (strcmp(*argv, "promisc") == 0) { 327 NEXT_ARG(); 328 req->i.ifi_change |= IFF_PROMISC; 329 if (strcmp(*argv, "on") == 0) { 330 req->i.ifi_flags |= IFF_PROMISC; 331 } else if (strcmp(*argv, "off") == 0) { 332 req->i.ifi_flags &= ~IFF_PROMISC; 333 } else 334 return on_off("promisc"); 335 } else if (strcmp(*argv, "trailers") == 0) { 336 NEXT_ARG(); 337 req->i.ifi_change |= IFF_NOTRAILERS; 338 if (strcmp(*argv, "off") == 0) { 339 req->i.ifi_flags |= IFF_NOTRAILERS; 340 } else if (strcmp(*argv, "on") == 0) { 341 req->i.ifi_flags &= ~IFF_NOTRAILERS; 342 } else 343 return on_off("trailers"); 344 } else if (strcmp(*argv, "arp") == 0) { 345 NEXT_ARG(); 346 req->i.ifi_change |= IFF_NOARP; 347 if (strcmp(*argv, "on") == 0) { 348 req->i.ifi_flags &= ~IFF_NOARP; 349 } else if (strcmp(*argv, "off") == 0) { 350 req->i.ifi_flags |= IFF_NOARP; 351 } else 352 return on_off("noarp"); 353 } else if (strcmp(*argv, "vf") == 0) { 354 struct rtattr *vflist; 355 NEXT_ARG(); 356 if (get_integer(&vf, *argv, 0)) { 357 invarg("Invalid \"vf\" value\n", *argv); 358 } 359 vflist = addattr_nest(&req->n, sizeof(*req), 360 IFLA_VFINFO_LIST); 361 len = iplink_parse_vf(vf, &argc, &argv, req); 362 if (len < 0) 363 return -1; 364 addattr_nest_end(&req->n, vflist); 365#ifdef IFF_DYNAMIC 366 } else if (matches(*argv, "dynamic") == 0) { 367 NEXT_ARG(); 368 req->i.ifi_change |= IFF_DYNAMIC; 369 if (strcmp(*argv, "on") == 0) { 370 req->i.ifi_flags |= IFF_DYNAMIC; 371 } else if (strcmp(*argv, "off") == 0) { 372 req->i.ifi_flags &= ~IFF_DYNAMIC; 373 } else 374 return on_off("dynamic"); 375#endif 376 } else if (matches(*argv, "type") == 0) { 377 NEXT_ARG(); 378 *type = *argv; 379 argc--; argv++; 380 break; 381 } else if (matches(*argv, "alias") == 0) { 382 NEXT_ARG(); 383 addattr_l(&req->n, sizeof(*req), IFLA_IFALIAS, 384 *argv, strlen(*argv)); 385 argc--; argv++; 386 break; 387 } else if (strcmp(*argv, "group") == 0) { 388 NEXT_ARG(); 389 if (*group != -1) 390 duparg("group", *argv); 391 if (rtnl_group_a2n(group, *argv)) 392 invarg("Invalid \"group\" value\n", *argv); 393 } else { 394 if (strcmp(*argv, "dev") == 0) { 395 NEXT_ARG(); 396 } 397 if (matches(*argv, "help") == 0) 398 usage(); 399 if (*dev) 400 duparg2("dev", *argv); 401 *dev = *argv; 402 } 403 argc--; argv++; 404 } 405 406 return ret - argc; 407} 408 409static int iplink_modify(int cmd, unsigned int flags, int argc, char **argv) 410{ 411 int len; 412 char *dev = NULL; 413 char *name = NULL; 414 char *link = NULL; 415 char *type = NULL; 416 int group; 417 struct link_util *lu = NULL; 418 struct iplink_req req; 419 int ret; 420 421 memset(&req, 0, sizeof(req)); 422 423 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); 424 req.n.nlmsg_flags = NLM_F_REQUEST|flags; 425 req.n.nlmsg_type = cmd; 426 req.i.ifi_family = preferred_family; 427 428 ret = iplink_parse(argc, argv, &req, &name, &type, &link, &dev, &group); 429 if (ret < 0) 430 return ret; 431 432 argc -= ret; 433 argv += ret; 434 435 if (group != -1) { 436 if (dev) 437 addattr_l(&req.n, sizeof(req), IFLA_GROUP, 438 &group, sizeof(group)); 439 else { 440 if (argc) { 441 fprintf(stderr, "Garbage instead of arguments " 442 "\"%s ...\". Try \"ip link " 443 "help\".\n", *argv); 444 return -1; 445 } 446 if (flags & NLM_F_CREATE) { 447 fprintf(stderr, "group cannot be used when " 448 "creating devices.\n"); 449 return -1; 450 } 451 452 req.i.ifi_index = 0; 453 addattr32(&req.n, sizeof(req), IFLA_GROUP, group); 454 if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0) 455 exit(2); 456 return 0; 457 } 458 } 459 460 ll_init_map(&rth); 461 462 if (type) { 463 struct rtattr *linkinfo = NLMSG_TAIL(&req.n); 464 addattr_l(&req.n, sizeof(req), IFLA_LINKINFO, NULL, 0); 465 addattr_l(&req.n, sizeof(req), IFLA_INFO_KIND, type, 466 strlen(type)); 467 468 lu = get_link_kind(type); 469 if (lu && argc) { 470 struct rtattr * data = NLMSG_TAIL(&req.n); 471 addattr_l(&req.n, sizeof(req), IFLA_INFO_DATA, NULL, 0); 472 473 if (lu->parse_opt && 474 lu->parse_opt(lu, argc, argv, &req.n)) 475 return -1; 476 477 data->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)data; 478 } else if (argc) { 479 if (matches(*argv, "help") == 0) 480 usage(); 481 fprintf(stderr, "Garbage instead of arguments \"%s ...\". " 482 "Try \"ip link help\".\n", *argv); 483 return -1; 484 } 485 linkinfo->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)linkinfo; 486 } else if (flags & NLM_F_CREATE) { 487 fprintf(stderr, "Not enough information: \"type\" argument " 488 "is required\n"); 489 return -1; 490 } 491 492 if (!(flags & NLM_F_CREATE)) { 493 if (!dev) { 494 fprintf(stderr, "Not enough information: \"dev\" " 495 "argument is required.\n"); 496 exit(-1); 497 } 498 499 req.i.ifi_index = ll_name_to_index(dev); 500 if (req.i.ifi_index == 0) { 501 fprintf(stderr, "Cannot find device \"%s\"\n", dev); 502 return -1; 503 } 504 } else { 505 /* Allow "ip link add dev" and "ip link add name" */ 506 if (!name) 507 name = dev; 508 509 if (link) { 510 int ifindex; 511 512 ifindex = ll_name_to_index(link); 513 if (ifindex == 0) { 514 fprintf(stderr, "Cannot find device \"%s\"\n", 515 link); 516 return -1; 517 } 518 addattr_l(&req.n, sizeof(req), IFLA_LINK, &ifindex, 4); 519 } 520 } 521 522 if (name) { 523 len = strlen(name) + 1; 524 if (len == 1) 525 invarg("\"\" is not a valid device identifier\n", "name"); 526 if (len > IFNAMSIZ) 527 invarg("\"name\" too long\n", name); 528 addattr_l(&req.n, sizeof(req), IFLA_IFNAME, name, len); 529 } 530 531 if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0) 532 exit(2); 533 534 return 0; 535} 536 537#if IPLINK_IOCTL_COMPAT 538static int get_ctl_fd(void) 539{ 540 int s_errno; 541 int fd; 542 543 fd = socket(PF_INET, SOCK_DGRAM, 0); 544 if (fd >= 0) 545 return fd; 546 s_errno = errno; 547 fd = socket(PF_PACKET, SOCK_DGRAM, 0); 548 if (fd >= 0) 549 return fd; 550 fd = socket(PF_INET6, SOCK_DGRAM, 0); 551 if (fd >= 0) 552 return fd; 553 errno = s_errno; 554 perror("Cannot create control socket"); 555 return -1; 556} 557 558static int do_chflags(const char *dev, __u32 flags, __u32 mask) 559{ 560 struct ifreq ifr; 561 int fd; 562 int err; 563 564 strncpy(ifr.ifr_name, dev, IFNAMSIZ); 565 fd = get_ctl_fd(); 566 if (fd < 0) 567 return -1; 568 err = ioctl(fd, SIOCGIFFLAGS, &ifr); 569 if (err) { 570 perror("SIOCGIFFLAGS"); 571 close(fd); 572 return -1; 573 } 574 if ((ifr.ifr_flags^flags)&mask) { 575 ifr.ifr_flags &= ~mask; 576 ifr.ifr_flags |= mask&flags; 577 err = ioctl(fd, SIOCSIFFLAGS, &ifr); 578 if (err) 579 perror("SIOCSIFFLAGS"); 580 } 581 close(fd); 582 return err; 583} 584 585static int do_changename(const char *dev, const char *newdev) 586{ 587 struct ifreq ifr; 588 int fd; 589 int err; 590 591 strncpy(ifr.ifr_name, dev, IFNAMSIZ); 592 strncpy(ifr.ifr_newname, newdev, IFNAMSIZ); 593 fd = get_ctl_fd(); 594 if (fd < 0) 595 return -1; 596 err = ioctl(fd, SIOCSIFNAME, &ifr); 597 if (err) { 598 perror("SIOCSIFNAME"); 599 close(fd); 600 return -1; 601 } 602 close(fd); 603 return err; 604} 605 606static int set_qlen(const char *dev, int qlen) 607{ 608 struct ifreq ifr; 609 int s; 610 611 s = get_ctl_fd(); 612 if (s < 0) 613 return -1; 614 615 memset(&ifr, 0, sizeof(ifr)); 616 strncpy(ifr.ifr_name, dev, IFNAMSIZ); 617 ifr.ifr_qlen = qlen; 618 if (ioctl(s, SIOCSIFTXQLEN, &ifr) < 0) { 619 perror("SIOCSIFXQLEN"); 620 close(s); 621 return -1; 622 } 623 close(s); 624 625 return 0; 626} 627 628static int set_mtu(const char *dev, int mtu) 629{ 630 struct ifreq ifr; 631 int s; 632 633 s = get_ctl_fd(); 634 if (s < 0) 635 return -1; 636 637 memset(&ifr, 0, sizeof(ifr)); 638 strncpy(ifr.ifr_name, dev, IFNAMSIZ); 639 ifr.ifr_mtu = mtu; 640 if (ioctl(s, SIOCSIFMTU, &ifr) < 0) { 641 perror("SIOCSIFMTU"); 642 close(s); 643 return -1; 644 } 645 close(s); 646 647 return 0; 648} 649 650static int get_address(const char *dev, int *htype) 651{ 652 struct ifreq ifr; 653 struct sockaddr_ll me; 654 socklen_t alen; 655 int s; 656 657 s = socket(PF_PACKET, SOCK_DGRAM, 0); 658 if (s < 0) { 659 perror("socket(PF_PACKET)"); 660 return -1; 661 } 662 663 memset(&ifr, 0, sizeof(ifr)); 664 strncpy(ifr.ifr_name, dev, IFNAMSIZ); 665 if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) { 666 perror("SIOCGIFINDEX"); 667 close(s); 668 return -1; 669 } 670 671 memset(&me, 0, sizeof(me)); 672 me.sll_family = AF_PACKET; 673 me.sll_ifindex = ifr.ifr_ifindex; 674 me.sll_protocol = htons(ETH_P_LOOP); 675 if (bind(s, (struct sockaddr*)&me, sizeof(me)) == -1) { 676 perror("bind"); 677 close(s); 678 return -1; 679 } 680 681 alen = sizeof(me); 682 if (getsockname(s, (struct sockaddr*)&me, &alen) == -1) { 683 perror("getsockname"); 684 close(s); 685 return -1; 686 } 687 close(s); 688 *htype = me.sll_hatype; 689 return me.sll_halen; 690} 691 692static int parse_address(const char *dev, int hatype, int halen, 693 char *lla, struct ifreq *ifr) 694{ 695 int alen; 696 697 memset(ifr, 0, sizeof(*ifr)); 698 strncpy(ifr->ifr_name, dev, IFNAMSIZ); 699 ifr->ifr_hwaddr.sa_family = hatype; 700 alen = ll_addr_a2n(ifr->ifr_hwaddr.sa_data, 14, lla); 701 if (alen < 0) 702 return -1; 703 if (alen != halen) { 704 fprintf(stderr, "Wrong address (%s) length: expected %d bytes\n", lla, halen); 705 return -1; 706 } 707 return 0; 708} 709 710static int set_address(struct ifreq *ifr, int brd) 711{ 712 int s; 713 714 s = get_ctl_fd(); 715 if (s < 0) 716 return -1; 717 if (ioctl(s, brd?SIOCSIFHWBROADCAST:SIOCSIFHWADDR, ifr) < 0) { 718 perror(brd?"SIOCSIFHWBROADCAST":"SIOCSIFHWADDR"); 719 close(s); 720 return -1; 721 } 722 close(s); 723 return 0; 724} 725 726 727static int do_set(int argc, char **argv) 728{ 729 char *dev = NULL; 730 __u32 mask = 0; 731 __u32 flags = 0; 732 int qlen = -1; 733 int mtu = -1; 734 char *newaddr = NULL; 735 char *newbrd = NULL; 736 struct ifreq ifr0, ifr1; 737 char *newname = NULL; 738 int htype, halen; 739 740 while (argc > 0) { 741 if (strcmp(*argv, "up") == 0) { 742 mask |= IFF_UP; 743 flags |= IFF_UP; 744 } else if (strcmp(*argv, "down") == 0) { 745 mask |= IFF_UP; 746 flags &= ~IFF_UP; 747 } else if (strcmp(*argv, "name") == 0) { 748 NEXT_ARG(); 749 newname = *argv; 750 } else if (matches(*argv, "address") == 0) { 751 NEXT_ARG(); 752 newaddr = *argv; 753 } else if (matches(*argv, "broadcast") == 0 || 754 strcmp(*argv, "brd") == 0) { 755 NEXT_ARG(); 756 newbrd = *argv; 757 } else if (matches(*argv, "txqueuelen") == 0 || 758 strcmp(*argv, "qlen") == 0 || 759 matches(*argv, "txqlen") == 0) { 760 NEXT_ARG(); 761 if (qlen != -1) 762 duparg("txqueuelen", *argv); 763 if (get_integer(&qlen, *argv, 0)) 764 invarg("Invalid \"txqueuelen\" value\n", *argv); 765 } else if (strcmp(*argv, "mtu") == 0) { 766 NEXT_ARG(); 767 if (mtu != -1) 768 duparg("mtu", *argv); 769 if (get_integer(&mtu, *argv, 0)) 770 invarg("Invalid \"mtu\" value\n", *argv); 771 } else if (strcmp(*argv, "multicast") == 0) { 772 NEXT_ARG(); 773 mask |= IFF_MULTICAST; 774 if (strcmp(*argv, "on") == 0) { 775 flags |= IFF_MULTICAST; 776 } else if (strcmp(*argv, "off") == 0) { 777 flags &= ~IFF_MULTICAST; 778 } else 779 return on_off("multicast"); 780 } else if (strcmp(*argv, "allmulticast") == 0) { 781 NEXT_ARG(); 782 mask |= IFF_ALLMULTI; 783 if (strcmp(*argv, "on") == 0) { 784 flags |= IFF_ALLMULTI; 785 } else if (strcmp(*argv, "off") == 0) { 786 flags &= ~IFF_ALLMULTI; 787 } else 788 return on_off("allmulticast"); 789 } else if (strcmp(*argv, "promisc") == 0) { 790 NEXT_ARG(); 791 mask |= IFF_PROMISC; 792 if (strcmp(*argv, "on") == 0) { 793 flags |= IFF_PROMISC; 794 } else if (strcmp(*argv, "off") == 0) { 795 flags &= ~IFF_PROMISC; 796 } else 797 return on_off("promisc"); 798 } else if (strcmp(*argv, "trailers") == 0) { 799 NEXT_ARG(); 800 mask |= IFF_NOTRAILERS; 801 if (strcmp(*argv, "off") == 0) { 802 flags |= IFF_NOTRAILERS; 803 } else if (strcmp(*argv, "on") == 0) { 804 flags &= ~IFF_NOTRAILERS; 805 } else 806 return on_off("trailers"); 807 } else if (strcmp(*argv, "arp") == 0) { 808 NEXT_ARG(); 809 mask |= IFF_NOARP; 810 if (strcmp(*argv, "on") == 0) { 811 flags &= ~IFF_NOARP; 812 } else if (strcmp(*argv, "off") == 0) { 813 flags |= IFF_NOARP; 814 } else 815 return on_off("noarp"); 816#ifdef IFF_DYNAMIC 817 } else if (matches(*argv, "dynamic") == 0) { 818 NEXT_ARG(); 819 mask |= IFF_DYNAMIC; 820 if (strcmp(*argv, "on") == 0) { 821 flags |= IFF_DYNAMIC; 822 } else if (strcmp(*argv, "off") == 0) { 823 flags &= ~IFF_DYNAMIC; 824 } else 825 return on_off("dynamic"); 826#endif 827 } else { 828 if (strcmp(*argv, "dev") == 0) { 829 NEXT_ARG(); 830 } 831 if (matches(*argv, "help") == 0) 832 usage(); 833 if (dev) 834 duparg2("dev", *argv); 835 dev = *argv; 836 } 837 argc--; argv++; 838 } 839 840 if (!dev) { 841 fprintf(stderr, "Not enough of information: \"dev\" argument is required.\n"); 842 exit(-1); 843 } 844 845 if (newaddr || newbrd) { 846 halen = get_address(dev, &htype); 847 if (halen < 0) 848 return -1; 849 if (newaddr) { 850 if (parse_address(dev, htype, halen, newaddr, &ifr0) < 0) 851 return -1; 852 } 853 if (newbrd) { 854 if (parse_address(dev, htype, halen, newbrd, &ifr1) < 0) 855 return -1; 856 } 857 } 858 859 if (newname && strcmp(dev, newname)) { 860 if (strlen(newname) == 0) 861 invarg("\"\" is not a valid device identifier\n", "name"); 862 if (do_changename(dev, newname) < 0) 863 return -1; 864 dev = newname; 865 } 866 if (qlen != -1) { 867 if (set_qlen(dev, qlen) < 0) 868 return -1; 869 } 870 if (mtu != -1) { 871 if (set_mtu(dev, mtu) < 0) 872 return -1; 873 } 874 if (newaddr || newbrd) { 875 if (newbrd) { 876 if (set_address(&ifr1, 1) < 0) 877 return -1; 878 } 879 if (newaddr) { 880 if (set_address(&ifr0, 0) < 0) 881 return -1; 882 } 883 } 884 if (mask) 885 return do_chflags(dev, flags, mask); 886 return 0; 887} 888#endif /* IPLINK_IOCTL_COMPAT */ 889 890int do_iplink(int argc, char **argv) 891{ 892 if (argc > 0) { 893 if (iplink_have_newlink()) { 894 if (matches(*argv, "add") == 0) 895 return iplink_modify(RTM_NEWLINK, 896 NLM_F_CREATE|NLM_F_EXCL, 897 argc-1, argv+1); 898 if (matches(*argv, "set") == 0 || 899 matches(*argv, "change") == 0) 900 return iplink_modify(RTM_NEWLINK, 0, 901 argc-1, argv+1); 902 if (matches(*argv, "replace") == 0) 903 return iplink_modify(RTM_NEWLINK, 904 NLM_F_CREATE|NLM_F_REPLACE, 905 argc-1, argv+1); 906 if (matches(*argv, "delete") == 0) 907 return iplink_modify(RTM_DELLINK, 0, 908 argc-1, argv+1); 909 } else { 910#if IPLINK_IOCTL_COMPAT 911 if (matches(*argv, "set") == 0) 912 return do_set(argc-1, argv+1); 913#endif 914 } 915 if (matches(*argv, "show") == 0 || 916 matches(*argv, "lst") == 0 || 917 matches(*argv, "list") == 0) 918 return ipaddr_list_link(argc-1, argv+1); 919 if (matches(*argv, "help") == 0) 920 usage(); 921 } else 922 return ipaddr_list_link(0, NULL); 923 924 fprintf(stderr, "Command \"%s\" is unknown, try \"ip link help\".\n", *argv); 925 exit(-1); 926} 927