1 /* 2 * Copyright 2006-2008, Haiku, Inc. All Rights Reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Axel Dörfler, axeld@pinc-software.de 7 * Oliver Tappe, zooey@hirschkaefer.de 8 */ 9 10 11 #include <SupportDefs.h> 12 13 #include <arpa/inet.h> 14 #include <net/if.h> 15 #include <net/if_dl.h> 16 #include <net/if_media.h> 17 #include <net/if_types.h> 18 #include <netinet/in.h> 19 #include <sys/socket.h> 20 #include <sys/sockio.h> 21 22 #include <errno.h> 23 #include <stdio.h> 24 #include <stdlib.h> 25 #include <string.h> 26 #include <unistd.h> 27 28 29 extern const char* __progname; 30 const char* kProgramName = __progname; 31 32 33 struct address_family { 34 int family; 35 const char* name; 36 const char* identifiers[4]; 37 bool (*parse_address)(const char* string, sockaddr* _address); 38 void (*print_address)(sockaddr* address); 39 }; 40 41 // AF_INET family 42 static bool inet_parse_address(const char* string, sockaddr* address); 43 static void inet_print_address(sockaddr* address); 44 45 static const address_family kFamilies[] = { 46 { 47 AF_INET, 48 "inet", 49 {"AF_INET", "inet", "ipv4", NULL}, 50 inet_parse_address, 51 inet_print_address 52 }, 53 { -1, NULL, {NULL}, NULL, NULL } 54 }; 55 56 57 static bool 58 inet_parse_address(const char* string, sockaddr* _address) 59 { 60 in_addr inetAddress; 61 62 if (inet_aton(string, &inetAddress) != 1) 63 return false; 64 65 sockaddr_in& address = *(sockaddr_in *)_address; 66 address.sin_family = AF_INET; 67 address.sin_len = sizeof(struct sockaddr_in); 68 address.sin_port = 0; 69 address.sin_addr = inetAddress; 70 memset(&address.sin_zero[0], 0, sizeof(address.sin_zero)); 71 72 return true; 73 } 74 75 76 static void 77 inet_print_address(sockaddr* _address) 78 { 79 sockaddr_in& address = *(sockaddr_in *)_address; 80 81 if (address.sin_family != AF_INET) 82 return; 83 84 printf("%s", inet_ntoa(address.sin_addr)); 85 } 86 87 88 // #pragma mark - 89 90 91 struct media_type { 92 int type; 93 const char* name; 94 const char* pretty; 95 struct { 96 int subtype; 97 const char* name; 98 const char* pretty; 99 } subtypes [6]; 100 struct { 101 int option; 102 bool ro; 103 const char* name; 104 const char* pretty; 105 } options [6]; 106 }; 107 108 109 static const media_type kMediaTypes[] = { 110 { 111 0, // for generic options 112 "all", 113 "All", 114 { 115 { IFM_AUTO, "auto", "Auto-select" }, 116 { -1, NULL, NULL } 117 }, 118 { 119 { IFM_FULL_DUPLEX, true, "fullduplex", "Full Duplex" }, 120 { IFM_HALF_DUPLEX, true, "halfduplex", "Half Duplex" }, 121 { IFM_LOOP, true, "loop", "Loop" }, 122 //{ IFM_ACTIVE, false, "active", "Active" }, 123 { -1, false, NULL, NULL } 124 } 125 }, 126 { 127 IFM_ETHER, 128 "ether", 129 "Ethernet", 130 { 131 //{ IFM_AUTO, "auto", "Auto-select" }, 132 //{ IFM_AUI, "AUI", "10 MBit, AUI" }, 133 //{ IFM_10_2, "10base2", "10 MBit, 10BASE-2" }, 134 { IFM_10_T, "10baseT", "10 MBit, 10BASE-T" }, 135 { IFM_100_TX, "100baseTX", "100 MBit, 100BASE-TX" }, 136 { IFM_1000_T, "1000baseT", "1 GBit, 1000BASE-T" }, 137 { IFM_1000_SX, "1000baseSX", "1 GBit, 1000BASE-SX" }, 138 { -1, NULL, NULL } 139 }, 140 { 141 { -1, false, NULL, NULL } 142 } 143 }, 144 { -1, NULL, NULL, {{ -1, NULL, NULL }}, {{ -1, false, NULL, NULL }} } 145 }; 146 147 148 static bool media_parse_subtype(const char* string, int media, int* type); 149 150 151 static bool 152 media_parse_subtype(const char* string, int media, int* type) 153 { 154 for (int32 i = 0; kMediaTypes[i].type >= 0; i++) { 155 // only check for generic or correct subtypes 156 if (kMediaTypes[i].type && 157 kMediaTypes[i].type != media) 158 continue; 159 for (int32 j = 0; kMediaTypes[i].subtypes[j].subtype >= 0; j++) { 160 if (strcmp(kMediaTypes[i].subtypes[j].name, string) == 0) { 161 // found a match 162 *type = kMediaTypes[i].subtypes[j].subtype; 163 return true; 164 } 165 } 166 } 167 return false; 168 } 169 170 171 // #pragma mark - 172 173 174 void 175 usage(int status) 176 { 177 printf("usage: %s [<interface> [<address family>] [<address> [<mask>]] [<option/flags>...]]\n" 178 "\t%s --delete interface [...]\n\n" 179 "Where <option> can be the following:\n" 180 " netmask <addr> - networking subnet mask\n" 181 " broadcast <addr> - set broadcast address\n" 182 " peer <addr> - ppp-peer address\n" 183 " mtu <bytes> - maximal transfer unit\n" 184 " metric <number> - metric number to use (defaults to 0)\n" 185 " media <media> - media type to use (defaults to auto)\n", 186 kProgramName, kProgramName); 187 for (int32 i = 0; kMediaTypes[i].type >= 0; i++) { 188 printf("For %s <media> can be one of: ", kMediaTypes[i].pretty); 189 for (int32 j = 0; kMediaTypes[i].subtypes[j].subtype >= 0; j++) 190 printf("%s ", kMediaTypes[i].subtypes[j].name); 191 printf("\n"); 192 } 193 printf("And <flags> can be: up, down, [-]promisc, [-]allmulti, [-]bcast, loopback\n\n" 194 "Example:\n" 195 "\t%s loop 127.0.0.1 255.0.0.0 up\n", 196 kProgramName); 197 198 exit(status); 199 } 200 201 202 bool 203 prepare_request(struct ifreq& request, const char* name) 204 { 205 if (strlen(name) > IF_NAMESIZE) { 206 fprintf(stderr, "%s: interface name \"%s\" is too long.\n", kProgramName, name); 207 return false; 208 } 209 210 strcpy(request.ifr_name, name); 211 return true; 212 } 213 214 215 bool 216 get_address_family(const char* argument, int32& familyIndex) 217 { 218 for (int32 i = 0; kFamilies[i].family >= 0; i++) { 219 for (int32 j = 0; kFamilies[i].identifiers[j]; j++) { 220 if (!strcmp(argument, kFamilies[i].identifiers[j])) { 221 // found a match 222 familyIndex = i; 223 return true; 224 } 225 } 226 } 227 228 // defaults to AF_INET 229 familyIndex = 0; 230 return false; 231 } 232 233 234 bool 235 parse_address(int32 familyIndex, const char* argument, struct sockaddr& address) 236 { 237 if (argument == NULL) 238 return false; 239 240 return kFamilies[familyIndex].parse_address(argument, &address); 241 } 242 243 244 // #pragma mark - 245 246 247 void 248 list_interface(int socket, const char* name) 249 { 250 ifreq request; 251 if (!prepare_request(request, name)) 252 return; 253 254 if (ioctl(socket, SIOCGIFINDEX, &request, sizeof(request)) < 0) { 255 fprintf(stderr, "%s: Interface \"%s\" does not exist.\n", kProgramName, name); 256 return; 257 } 258 259 printf("%s", name); 260 size_t length = strlen(name); 261 if (length < 8) 262 putchar('\t'); 263 else 264 printf("\n\t"); 265 266 // get link level interface for this interface 267 268 int linkSocket = ::socket(AF_LINK, SOCK_DGRAM, 0); 269 if (linkSocket < 0) { 270 printf("No link level: %s\n", strerror(errno)); 271 } else { 272 const char *type = "unknown"; 273 char address[256]; 274 strcpy(address, "none"); 275 276 if (ioctl(socket, SIOCGIFPARAM, &request, sizeof(struct ifreq)) == 0) { 277 prepare_request(request, request.ifr_parameter.device); 278 if (ioctl(linkSocket, SIOCGIFADDR, &request, sizeof(struct ifreq)) == 0) { 279 sockaddr_dl &link = *(sockaddr_dl *)&request.ifr_addr; 280 281 switch (link.sdl_type) { 282 case IFT_ETHER: 283 { 284 type = "Ethernet"; 285 286 if (link.sdl_alen > 0) { 287 uint8 *mac = (uint8 *)LLADDR(&link); 288 sprintf(address, "%02x:%02x:%02x:%02x:%02x:%02x", 289 mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); 290 } else 291 strcpy(address, "not available"); 292 break; 293 } 294 case IFT_LOOP: 295 type = "Local Loopback"; 296 break; 297 case IFT_MODEM: 298 type = "Modem"; 299 break; 300 } 301 } 302 } 303 304 printf("Hardware Type: %s, Address: %s\n", type, address); 305 close(linkSocket); 306 } 307 308 if (ioctl(socket, SIOCGIFMEDIA, &request, sizeof(struct ifreq)) == 0 309 && (request.ifr_media & IFM_ACTIVE) != 0) { 310 // dump media state in case we're linked 311 const char* type = "unknown"; 312 bool show = false; 313 314 for (int32 i = 0; kMediaTypes[i].type >= 0; i++) { 315 // loopback don't really have a media anyway 316 if (IFM_TYPE(request.ifr_media) == 0/*IFT_LOOP*/) 317 break; 318 // only check for generic or correct subtypes 319 if (kMediaTypes[i].type && 320 kMediaTypes[i].type != IFM_TYPE(request.ifr_media)) 321 continue; 322 for (int32 j = 0; kMediaTypes[i].subtypes[j].subtype >= 0; j++) { 323 if (kMediaTypes[i].subtypes[j].subtype == IFM_SUBTYPE(request.ifr_media)) { 324 // found a match 325 type = kMediaTypes[i].subtypes[j].pretty; 326 show = true; 327 break; 328 } 329 } 330 } 331 332 if (show) 333 printf("\tMedia Type: %s\n", type); 334 } 335 336 uint32 flags = 0; 337 if (ioctl(socket, SIOCGIFFLAGS, &request, sizeof(struct ifreq)) == 0) 338 flags = request.ifr_flags; 339 340 for (int32 i = 0; kFamilies[i].family >= 0; i++) { 341 int familySocket = ::socket(kFamilies[i].family, SOCK_DGRAM, 0); 342 if (familySocket < 0) 343 continue; 344 345 if (ioctl(familySocket, SIOCGIFADDR, &request, sizeof(struct ifreq)) == 0) { 346 printf("\t%s addr: ", kFamilies[i].name); 347 kFamilies[i].print_address(&request.ifr_addr); 348 349 if ((flags & IFF_BROADCAST) != 0 350 && ioctl(familySocket, SIOCGIFBRDADDR, &request, sizeof(struct ifreq)) == 0 351 && request.ifr_broadaddr.sa_family == kFamilies[i].family) { 352 printf(", Bcast: "); 353 kFamilies[i].print_address(&request.ifr_broadaddr); 354 } 355 if (ioctl(familySocket, SIOCGIFNETMASK, &request, sizeof(struct ifreq)) == 0 356 && request.ifr_mask.sa_family == kFamilies[i].family) { 357 printf(", Mask: "); 358 kFamilies[i].print_address(&request.ifr_mask); 359 } 360 putchar('\n'); 361 } 362 363 close(familySocket); 364 } 365 366 // Print MTU, metric, flags 367 368 printf("\tMTU: "); 369 if (ioctl(socket, SIOCGIFMTU, &request, sizeof(struct ifreq)) == 0) 370 printf("%d", request.ifr_mtu); 371 else 372 printf("-"); 373 374 printf(", Metric: "); 375 if (ioctl(socket, SIOCGIFMETRIC, &request, sizeof(struct ifreq)) == 0) 376 printf("%d", request.ifr_metric); 377 else 378 printf("-"); 379 380 if (flags != 0) { 381 const struct { 382 int value; 383 const char *name; 384 } kFlags[] = { 385 {IFF_UP, "up"}, 386 {IFF_NOARP, "noarp"}, 387 {IFF_BROADCAST, "broadcast"}, 388 {IFF_LOOPBACK, "loopback"}, 389 {IFF_PROMISC, "promiscuous"}, 390 {IFF_ALLMULTI, "allmulti"}, 391 {IFF_AUTOUP, "autoup"}, 392 {IFF_LINK, "link"}, 393 {IFF_AUTO_CONFIGURED, "auto-configured"}, 394 {IFF_CONFIGURING, "configuring"}, 395 }; 396 bool first = true; 397 398 for (uint32 i = 0; i < sizeof(kFlags) / sizeof(kFlags[0]); i++) { 399 if ((flags & kFlags[i].value) != 0) { 400 if (first) { 401 printf(","); 402 first = false; 403 } 404 putchar(' '); 405 printf(kFlags[i].name); 406 } 407 } 408 } 409 410 putchar('\n'); 411 412 // Print statistics 413 414 if (ioctl(socket, SIOCGIFSTATS, &request, sizeof(struct ifreq)) == 0) { 415 printf("\tReceive: %d packets, %d errors, %Ld bytes, %d mcasts, %d dropped\n", 416 request.ifr_stats.receive.packets, request.ifr_stats.receive.errors, 417 request.ifr_stats.receive.bytes, request.ifr_stats.receive.multicast_packets, 418 request.ifr_stats.receive.dropped); 419 printf("\tTransmit: %d packets, %d errors, %Ld bytes, %d mcasts, %d dropped\n", 420 request.ifr_stats.send.packets, request.ifr_stats.send.errors, 421 request.ifr_stats.send.bytes, request.ifr_stats.send.multicast_packets, 422 request.ifr_stats.send.dropped); 423 printf("\tCollisions: %d\n", request.ifr_stats.collisions); 424 } 425 426 putchar('\n'); 427 } 428 429 430 void 431 list_interfaces(int socket, const char* name) 432 { 433 if (name != NULL) { 434 list_interface(socket, name); 435 return; 436 } 437 438 // get a list of all interfaces 439 440 ifconf config; 441 config.ifc_len = sizeof(config.ifc_value); 442 if (ioctl(socket, SIOCGIFCOUNT, &config, sizeof(struct ifconf)) < 0) 443 return; 444 445 uint32 count = (uint32)config.ifc_value; 446 if (count == 0) { 447 fprintf(stderr, "%s: There are no interfaces yet!\n", kProgramName); 448 return; 449 } 450 451 void *buffer = malloc(count * sizeof(struct ifreq)); 452 if (buffer == NULL) { 453 fprintf(stderr, "%s: Out of memory.\n", kProgramName); 454 return; 455 } 456 457 config.ifc_len = count * sizeof(struct ifreq); 458 config.ifc_buf = buffer; 459 if (ioctl(socket, SIOCGIFCONF, &config, sizeof(struct ifconf)) < 0) 460 return; 461 462 ifreq *interface = (ifreq *)buffer; 463 464 for (uint32 i = 0; i < count; i++) { 465 list_interface(socket, interface->ifr_name); 466 467 interface = (ifreq *)((addr_t)interface + IF_NAMESIZE + interface->ifr_addr.sa_len); 468 } 469 470 free(buffer); 471 } 472 473 474 void 475 delete_interface(int socket, const char* name) 476 { 477 ifreq request; 478 if (!prepare_request(request, name)) 479 return; 480 481 if (ioctl(socket, SIOCDIFADDR, &request, sizeof(request)) < 0) { 482 fprintf(stderr, "%s: Could not delete interface %s: %s\n", 483 kProgramName, name, strerror(errno)); 484 } 485 } 486 487 488 void 489 configure_interface(int socket, const char* name, char* const* args, 490 int32 argCount) 491 { 492 ifreq request; 493 if (!prepare_request(request, name)) 494 return; 495 496 uint32 index = 0; 497 if (ioctl(socket, SIOCGIFINDEX, &request, sizeof(request)) >= 0) 498 index = request.ifr_index; 499 500 bool hasAddress = false, hasMask = false, hasPeer = false, hasBroadcast = false; 501 struct sockaddr address, mask, peer, broadcast; 502 int mtu = -1, metric = -1, media = -1; 503 int addFlags = 0, removeFlags = 0, currentFlags = 0; 504 505 // try to parse address family 506 507 int32 familyIndex; 508 int32 i = 0; 509 if (get_address_family(args[i], familyIndex)) 510 i++; 511 512 if (kFamilies[familyIndex].family != AF_INET) { 513 close(socket); 514 515 // replace socket with one of the correct address family 516 socket = ::socket(kFamilies[familyIndex].family, SOCK_DGRAM, 0); 517 if (socket < 0) { 518 fprintf(stderr, "%s: Address family \"%s\" is not available.\n", 519 kProgramName, kFamilies[familyIndex].name); 520 exit(1); 521 } 522 } 523 524 if (index == 0) { 525 // the interface does not exist yet, we have to add it first 526 request.ifr_parameter.base_name[0] = '\0'; 527 request.ifr_parameter.device[0] = '\0'; 528 request.ifr_parameter.sub_type = 0; 529 // the default device is okay for us 530 531 if (ioctl(socket, SIOCAIFADDR, &request, sizeof(request)) < 0) { 532 fprintf(stderr, "%s: Could not add interface: %s\n", kProgramName, 533 strerror(errno)); 534 exit(1); 535 } 536 } 537 538 // try to parse address 539 540 if (parse_address(familyIndex, args[i], address)) { 541 hasAddress = true; 542 i++; 543 544 if (parse_address(familyIndex, args[i], mask)) { 545 hasMask = true; 546 i++; 547 } 548 } 549 550 // parse parameters and flags 551 552 while (i < argCount) { 553 if (!strcmp(args[i], "peer")) { 554 if (!parse_address(familyIndex, args[i + 1], peer)) { 555 fprintf(stderr, "%s: Option 'peer' needs valid address parameter\n", 556 kProgramName); 557 exit(1); 558 } 559 hasPeer = true; 560 i++; 561 } else if (!strcmp(args[i], "nm") || !strcmp(args[i], "netmask")) { 562 if (hasMask) { 563 fprintf(stderr, "%s: Netmask is specified twice\n", 564 kProgramName); 565 exit(1); 566 } 567 if (!parse_address(familyIndex, args[i + 1], mask)) { 568 fprintf(stderr, "%s: Option 'netmask' needs valid address parameter\n", 569 kProgramName); 570 exit(1); 571 } 572 hasMask = true; 573 i++; 574 } else if (!strcmp(args[i], "bc") || !strcmp(args[i], "broadcast")) { 575 if (hasBroadcast) { 576 fprintf(stderr, "%s: broadcast address is specified twice\n", 577 kProgramName); 578 exit(1); 579 } 580 if (!parse_address(familyIndex, args[i + 1], broadcast)) { 581 fprintf(stderr, "%s: Option 'broadcast' needs valid address parameter\n", 582 kProgramName); 583 exit(1); 584 } 585 hasBroadcast = true; 586 addFlags |= IFF_BROADCAST; 587 i++; 588 } else if (!strcmp(args[i], "mtu")) { 589 mtu = args[i + 1] ? strtol(args[i + 1], NULL, 0) : 0; 590 if (mtu <= 500) { 591 fprintf(stderr, "%s: Option 'mtu' expected valid max transfer unit size\n", 592 kProgramName); 593 exit(1); 594 } 595 i++; 596 } else if (!strcmp(args[i], "metric")) { 597 if (i + 1 >= argCount) { 598 fprintf(stderr, "%s: Option 'metric' exptected parameter\n", 599 kProgramName); 600 exit(1); 601 } 602 metric = strtol(args[i + 1], NULL, 0); 603 i++; 604 } else if (!strcmp(args[i], "media")) { 605 if (ioctl(socket, SIOCGIFMEDIA, &request, sizeof(struct ifreq)) < 0) { 606 fprintf(stderr, "%s: Unable to detect media type\n", 607 kProgramName); 608 exit(1); 609 } 610 if (i + 1 >= argCount) { 611 fprintf(stderr, "%s: Option 'media' exptected parameter\n", 612 kProgramName); 613 exit(1); 614 } 615 if (!media_parse_subtype(args[i + 1], IFM_TYPE(request.ifr_media), &media)) { 616 fprintf(stderr, "%s: Invalid parameter for option 'media': '%s'\n", 617 kProgramName, args[i + 1]); 618 exit(1); 619 } 620 i++; 621 } else if (!strcmp(args[i], "up") || !strcmp(args[i], "-down")) { 622 addFlags |= IFF_UP; 623 } else if (!strcmp(args[i], "down") || !strcmp(args[i], "-up")) { 624 removeFlags |= IFF_UP; 625 } else if (!strcmp(args[i], "bcast")) { 626 addFlags |= IFF_BROADCAST; 627 } else if (!strcmp(args[i], "-bcast")) { 628 removeFlags |= IFF_BROADCAST; 629 } else if (!strcmp(args[i], "promisc")) { 630 addFlags |= IFF_PROMISC; 631 } else if (!strcmp(args[i], "-promisc")) { 632 removeFlags |= IFF_PROMISC; 633 } else if (!strcmp(args[i], "allmulti")) { 634 addFlags |= IFF_ALLMULTI; 635 } else if (!strcmp(args[i], "-allmulti")) { 636 removeFlags |= IFF_ALLMULTI; 637 } else if (!strcmp(args[i], "loopback")) { 638 addFlags |= IFF_LOOPBACK; 639 } else 640 usage(1); 641 642 i++; 643 } 644 645 if ((addFlags & removeFlags) != 0) { 646 fprintf(stderr, "%s: Contradicting flags specified\n", kProgramName); 647 exit(1); 648 } 649 650 // set address/mask/broadcast/peer 651 652 if (hasAddress) { 653 memcpy(&request.ifr_addr, &address, address.sa_len); 654 655 if (ioctl(socket, SIOCSIFADDR, &request, sizeof(struct ifreq)) < 0) { 656 fprintf(stderr, "%s: Setting address failed: %s\n", kProgramName, strerror(errno)); 657 exit(1); 658 } 659 } 660 661 if (ioctl(socket, SIOCGIFFLAGS, &request, sizeof(struct ifreq)) < 0) { 662 fprintf(stderr, "%s: Getting flags failed: %s\n", kProgramName, strerror(errno)); 663 exit(1); 664 } 665 currentFlags = request.ifr_flags; 666 667 if (hasMask) { 668 memcpy(&request.ifr_mask, &mask, mask.sa_len); 669 670 if (ioctl(socket, SIOCSIFNETMASK, &request, sizeof(struct ifreq)) < 0) { 671 fprintf(stderr, "%s: Setting subnet mask failed: %s\n", kProgramName, strerror(errno)); 672 exit(1); 673 } 674 } 675 676 if (hasBroadcast) { 677 memcpy(&request.ifr_broadaddr, &broadcast, broadcast.sa_len); 678 679 if (ioctl(socket, SIOCSIFBRDADDR, &request, sizeof(struct ifreq)) < 0) { 680 fprintf(stderr, "%s: Setting broadcast address failed: %s\n", kProgramName, strerror(errno)); 681 exit(1); 682 } 683 } 684 685 if (hasPeer) { 686 memcpy(&request.ifr_dstaddr, &peer, peer.sa_len); 687 688 if (ioctl(socket, SIOCSIFDSTADDR, &request, sizeof(struct ifreq)) < 0) { 689 fprintf(stderr, "%s: Setting peer address failed: %s\n", kProgramName, strerror(errno)); 690 exit(1); 691 } 692 } 693 694 // set flags 695 696 if (addFlags || removeFlags) { 697 request.ifr_flags = (currentFlags & ~removeFlags) | addFlags; 698 if (ioctl(socket, SIOCSIFFLAGS, &request, sizeof(struct ifreq)) < 0) 699 fprintf(stderr, "%s: Setting flags failed: %s\n", kProgramName, strerror(errno)); 700 } 701 702 // set options 703 704 if (mtu != -1) { 705 request.ifr_mtu = mtu; 706 if (ioctl(socket, SIOCSIFMTU, &request, sizeof(struct ifreq)) < 0) 707 fprintf(stderr, "%s: Setting MTU failed: %s\n", kProgramName, strerror(errno)); 708 } 709 710 if (metric != -1) { 711 request.ifr_metric = metric; 712 if (ioctl(socket, SIOCSIFMETRIC, &request, sizeof(struct ifreq)) < 0) 713 fprintf(stderr, "%s: Setting metric failed: %s\n", kProgramName, strerror(errno)); 714 } 715 716 if (media != -1) { 717 request.ifr_media = media; 718 if (ioctl(socket, SIOCSIFMEDIA, &request, sizeof(struct ifreq)) < 0) 719 fprintf(stderr, "%s: Setting media failed: %s\n", kProgramName, strerror(errno)); 720 } 721 } 722 723 724 // #pragma mark - 725 726 727 int 728 main(int argc, char** argv) 729 { 730 if (argc > 1 && (!strcmp(argv[1], "--help") || !strcmp(argv[1], "-h"))) 731 usage(0); 732 733 bool deleteInterfaces = false; 734 735 if (argc > 1 736 && (!strcmp(argv[1], "--delete") 737 || !strcmp(argv[1], "--del") 738 || !strcmp(argv[1], "-d"))) { 739 // delete interfaces 740 if (argc < 3) 741 usage(1); 742 743 deleteInterfaces = true; 744 } 745 746 // we need a socket to talk to the networking stack 747 int socket = ::socket(AF_INET, SOCK_DGRAM, 0); 748 if (socket < 0) { 749 fprintf(stderr, "%s: The networking stack doesn't seem to be available.\n", 750 kProgramName); 751 return 1; 752 } 753 754 if (deleteInterfaces) { 755 for (int i = 2; i < argc; i++) { 756 delete_interface(socket, argv[i]); 757 } 758 return 0; 759 } else if (argc > 1 && !strcmp(argv[1], "-a")) { 760 // accept -a option for those that are used to it from other platforms 761 if (argc > 2) 762 usage(1); 763 764 list_interfaces(socket, NULL); 765 return 0; 766 } 767 768 const char* name = argv[1]; 769 if (argc > 2) { 770 // add or configure an interface 771 772 configure_interface(socket, name, argv + 2, argc - 2); 773 return 0; 774 } 775 776 // list interfaces 777 778 list_interfaces(socket, name); 779 return 0; 780 } 781 782