1 /* 2 * Copyright 2006-2010, 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 * Atis Elsts, the.kfx@gmail.com 9 */ 10 11 12 #include <arpa/inet.h> 13 #include <net/if.h> 14 #include <net/if_dl.h> 15 #include <net/if_media.h> 16 #include <net/if_types.h> 17 #include <netinet/in.h> 18 #include <sys/socket.h> 19 #include <sys/sockio.h> 20 21 #include <errno.h> 22 #include <stdio.h> 23 #include <stdlib.h> 24 #include <string.h> 25 #include <unistd.h> 26 27 #include <Message.h> 28 #include <Messenger.h> 29 #include <NetworkInterface.h> 30 #include <NetworkRoster.h> 31 32 #include <NetServer.h> 33 34 35 extern const char* __progname; 36 const char* kProgramName = __progname; 37 38 39 enum preferred_output_format { 40 PREFER_OUTPUT_MASK, 41 PREFER_OUTPUT_PREFIX_LENGTH, 42 }; 43 44 45 struct address_family { 46 int family; 47 const char* name; 48 const char* identifiers[4]; 49 preferred_output_format preferred_format; 50 bool (*parse_address)(const char* string, sockaddr* _address); 51 }; 52 53 54 bool initialize_address_families(); 55 56 // AF_INET family 57 static bool inet_parse_address(const char* string, sockaddr* address); 58 59 // AF_INET6 family 60 static bool inet6_parse_address(const char* string, sockaddr* address); 61 62 static const address_family kFamilies[] = { 63 { 64 AF_INET, 65 "inet", 66 {"AF_INET", "inet", "ipv4", NULL}, 67 PREFER_OUTPUT_MASK, 68 inet_parse_address, 69 }, 70 { 71 AF_INET6, 72 "inet6", 73 {"AF_INET6", "inet6", "ipv6", NULL}, 74 PREFER_OUTPUT_PREFIX_LENGTH, 75 inet6_parse_address, 76 }, 77 { -1, NULL, {NULL}, PREFER_OUTPUT_MASK, NULL } 78 }; 79 80 81 static int sAddressFamilySockets[sizeof(kFamilies) / sizeof(kFamilies[0])]; 82 83 84 bool 85 initialize_address_families() 86 { 87 bool ok = false; 88 for (int32 i = 0; kFamilies[i].family >= 0; i++) { 89 int fd = socket(kFamilies[i].family, SOCK_DGRAM, 0); 90 if (fd != -1) { 91 sAddressFamilySockets[i] = fd; 92 ok = true; 93 } 94 } 95 return ok; 96 } 97 98 99 // #pragma mark - IPv4 100 101 102 static bool 103 inet_parse_address(const char* string, sockaddr* _address) 104 { 105 in_addr inetAddress; 106 107 if (inet_aton(string, &inetAddress) != 1) 108 return false; 109 110 sockaddr_in& address = *(sockaddr_in*)_address; 111 address.sin_family = AF_INET; 112 address.sin_len = sizeof(sockaddr_in); 113 address.sin_port = 0; 114 address.sin_addr = inetAddress; 115 memset(&address.sin_zero[0], 0, sizeof(address.sin_zero)); 116 117 return true; 118 } 119 120 121 // #pragma mark - IPv6 122 123 124 static bool 125 inet6_parse_address(const char* string, sockaddr* _address) 126 { 127 sockaddr_in6& address = *(sockaddr_in6*)_address; 128 129 if (inet_pton(AF_INET6, string, &address.sin6_addr) != 1) 130 return false; 131 132 address.sin6_family = AF_INET6; 133 address.sin6_len = sizeof(sockaddr_in6); 134 address.sin6_port = 0; 135 address.sin6_flowinfo = 0; 136 address.sin6_scope_id = 0; 137 138 return true; 139 } 140 141 142 // #pragma mark - 143 144 145 struct media_type { 146 int type; 147 const char* name; 148 const char* pretty; 149 struct { 150 int subtype; 151 const char* name; 152 const char* pretty; 153 } subtypes [6]; 154 struct { 155 int option; 156 bool ro; 157 const char* name; 158 const char* pretty; 159 } options [6]; 160 }; 161 162 163 static const media_type kMediaTypes[] = { 164 { 165 0, // for generic options 166 "all", 167 "All", 168 { 169 { IFM_AUTO, "auto", "Auto-select" }, 170 { -1, NULL, NULL } 171 }, 172 { 173 { IFM_FULL_DUPLEX, true, "fullduplex", "Full Duplex" }, 174 { IFM_HALF_DUPLEX, true, "halfduplex", "Half Duplex" }, 175 { IFM_LOOP, true, "loop", "Loop" }, 176 //{ IFM_ACTIVE, false, "active", "Active" }, 177 { -1, false, NULL, NULL } 178 } 179 }, 180 { 181 IFM_ETHER, 182 "ether", 183 "Ethernet", 184 { 185 //{ IFM_AUTO, "auto", "Auto-select" }, 186 //{ IFM_AUI, "AUI", "10 MBit, AUI" }, 187 //{ IFM_10_2, "10base2", "10 MBit, 10BASE-2" }, 188 { IFM_10_T, "10baseT", "10 MBit, 10BASE-T" }, 189 { IFM_100_TX, "100baseTX", "100 MBit, 100BASE-TX" }, 190 { IFM_1000_T, "1000baseT", "1 GBit, 1000BASE-T" }, 191 { IFM_1000_SX, "1000baseSX", "1 GBit, 1000BASE-SX" }, 192 { -1, NULL, NULL } 193 }, 194 { 195 { -1, false, NULL, NULL } 196 } 197 }, 198 { -1, NULL, NULL, {{ -1, NULL, NULL }}, {{ -1, false, NULL, NULL }} } 199 }; 200 201 202 static bool 203 media_parse_subtype(const char* string, int media, int* type) 204 { 205 for (int32 i = 0; kMediaTypes[i].type >= 0; i++) { 206 // only check for generic or correct subtypes 207 if (kMediaTypes[i].type && 208 kMediaTypes[i].type != media) 209 continue; 210 for (int32 j = 0; kMediaTypes[i].subtypes[j].subtype >= 0; j++) { 211 if (strcmp(kMediaTypes[i].subtypes[j].name, string) == 0) { 212 // found a match 213 *type = kMediaTypes[i].subtypes[j].subtype; 214 return true; 215 } 216 } 217 } 218 return false; 219 } 220 221 222 // #pragma mark - 223 224 225 void 226 usage(int status) 227 { 228 printf("usage: %s [<interface> [<address family>] [<address> [<mask>] | " 229 "auto-config] [<option/flags>...]]\n" 230 "\t%s --delete interface [...]\n\n" 231 "Where <option> can be the following:\n" 232 " netmask <addr> - networking subnet mask\n" 233 " prefixlen <number> - subnet mask length in bits\n" 234 " broadcast <addr> - set broadcast address\n" 235 " peer <addr> - ppp-peer address\n" 236 " mtu <bytes> - maximal transfer unit\n" 237 " metric <number> - metric number to use (defaults to 0)\n" 238 " media <media> - media type to use (defaults to auto)\n", 239 kProgramName, kProgramName); 240 for (int32 i = 0; kMediaTypes[i].type >= 0; i++) { 241 printf("For %s <media> can be one of: ", kMediaTypes[i].pretty); 242 for (int32 j = 0; kMediaTypes[i].subtypes[j].subtype >= 0; j++) 243 printf("%s ", kMediaTypes[i].subtypes[j].name); 244 printf("\n"); 245 } 246 printf("And <flags> can be: up, down, [-]promisc, [-]allmulti, [-]bcast, " 247 "loopback\n" 248 "If you specify \"auto-config\" instead of an address, it will be " 249 "configured automatically.\n\n" 250 "Example:\n" 251 "\t%s loop 127.0.0.1 255.0.0.0 up\n", 252 kProgramName); 253 254 exit(status); 255 } 256 257 258 bool 259 prepare_request(struct ifreq& request, const char* name) 260 { 261 if (strlen(name) >= IF_NAMESIZE) { 262 fprintf(stderr, "%s: interface name \"%s\" is too long.\n", 263 kProgramName, name); 264 return false; 265 } 266 267 memset(&request, 0, sizeof(ifreq)); 268 strcpy(request.ifr_name, name); 269 return true; 270 } 271 272 273 bool 274 get_address_family(const char* argument, int32& familyIndex) 275 { 276 for (int32 i = 0; kFamilies[i].family >= 0; i++) { 277 for (int32 j = 0; kFamilies[i].identifiers[j]; j++) { 278 if (!strcmp(argument, kFamilies[i].identifiers[j])) { 279 // found a match 280 familyIndex = i; 281 return true; 282 } 283 } 284 } 285 286 // defaults to AF_INET 287 familyIndex = 0; 288 return false; 289 } 290 291 292 const address_family* 293 get_address_family(int32 family) 294 { 295 for (int32 i = 0; kFamilies[i].family >= 0; i++) { 296 if (kFamilies[i].family == family) 297 return &kFamilies[i]; 298 } 299 300 // defaults to AF_INET 301 return &kFamilies[0]; 302 } 303 304 305 bool 306 parse_address(int32 familyIndex, const char* argument, struct sockaddr& address) 307 { 308 if (argument == NULL) 309 return false; 310 311 return kFamilies[familyIndex].parse_address(argument, &address); 312 } 313 314 315 bool 316 prefix_length_to_mask(int32 familyIndex, const char* argument, 317 struct sockaddr& mask) 318 { 319 char *end; 320 uint32 prefixLength = strtoul(argument, &end, 10); 321 if (end == argument) 322 return false; 323 324 BNetworkAddress address; 325 if (address.SetToMask(kFamilies[familyIndex].family, prefixLength) != B_OK) 326 return false; 327 328 memcpy(&mask, &address.SockAddr(), address.Length()); 329 return true; 330 } 331 332 333 // #pragma mark - 334 335 336 int 337 find_socket(struct ifreq& request, int addressFamily) 338 { 339 int socket = -1; 340 bool socketExists = false; 341 bool ok = false; 342 343 for (int32 i = 0; kFamilies[i].family >= 0; i++) { 344 if (addressFamily != -1 && addressFamily != kFamilies[i].family) 345 continue; 346 347 socket = sAddressFamilySockets[i]; 348 if (socket == -1) 349 continue; 350 351 socketExists = true; 352 353 if (ioctl(socket, SIOCGIFINDEX, &request, sizeof(request)) >= 0) { 354 ok = true; 355 break; 356 } 357 } 358 359 if (socketExists && !ok) { 360 fprintf(stderr, "%s: Interface \"%s\" does not exist.\n", 361 kProgramName, request.ifr_name); 362 return -1; 363 } 364 365 return socket; 366 } 367 368 369 void 370 list_interface_addresses(BNetworkInterface& interface, uint32 flags) 371 { 372 int32 count = interface.CountAddresses(); 373 for (int32 i = 0; i < count; i++) { 374 BNetworkInterfaceAddress address; 375 if (interface.GetAddressAt(i, address) != B_OK) 376 break; 377 378 const address_family* family 379 = get_address_family(address.Address().Family()); 380 381 printf("\t%s addr: %s", family->name, 382 address.Address().ToString().String()); 383 384 if ((flags & IFF_BROADCAST) != 0) 385 printf(", Bcast: %s", address.Broadcast().ToString().String()); 386 387 switch (family->preferred_format) { 388 case PREFER_OUTPUT_MASK: 389 printf(", Mask: %s", address.Mask().ToString().String()); 390 break; 391 case PREFER_OUTPUT_PREFIX_LENGTH: 392 printf(", Prefix Length: %zu", address.Mask().PrefixLength()); 393 break; 394 } 395 396 putchar('\n'); 397 } 398 } 399 400 401 bool 402 list_interface(const char* name) 403 { 404 printf("%s", name); 405 size_t length = strlen(name); 406 if (length < 8) 407 putchar('\t'); 408 else 409 printf("\n\t"); 410 411 // get link level interface for this interface 412 413 BNetworkInterface interface(name); 414 BNetworkAddress linkAddress; 415 status_t status = interface.GetHardwareAddress(linkAddress); 416 if (status == B_OK) { 417 const char *type = "unknown"; 418 char address[256]; 419 strcpy(address, "none"); 420 421 switch (linkAddress.LinkLevelType()) { 422 case IFT_ETHER: 423 { 424 type = "Ethernet"; 425 426 if (linkAddress.LinkLevelAddressLength() > 0) { 427 uint8 *mac = linkAddress.LinkLevelAddress(); 428 sprintf(address, "%02x:%02x:%02x:%02x:%02x:%02x", 429 mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); 430 } else 431 strcpy(address, "not available"); 432 break; 433 } 434 case IFT_LOOP: 435 type = "Local Loopback"; 436 break; 437 case IFT_MODEM: 438 type = "Modem"; 439 break; 440 } 441 442 printf("Hardware Type: %s, Address: %s\n", type, address); 443 } else 444 printf("No link level: %s\n", strerror(status)); 445 446 int media = interface.Media(); 447 if ((media & IFM_ACTIVE) != 0) { 448 // dump media state in case we're linked 449 const char* type = "unknown"; 450 bool show = false; 451 452 for (int32 i = 0; kMediaTypes[i].type >= 0; i++) { 453 // loopback don't really have a media anyway 454 if (IFM_TYPE(media) == 0/*IFT_LOOP*/) 455 break; 456 457 // only check for generic or correct subtypes 458 if (kMediaTypes[i].type 459 && kMediaTypes[i].type != IFM_TYPE(media)) 460 continue; 461 462 for (int32 j = 0; kMediaTypes[i].subtypes[j].subtype >= 0; j++) { 463 if (kMediaTypes[i].subtypes[j].subtype == IFM_SUBTYPE(media)) { 464 // found a match 465 type = kMediaTypes[i].subtypes[j].pretty; 466 show = true; 467 break; 468 } 469 } 470 } 471 472 if (show) 473 printf("\tMedia Type: %s\n", type); 474 } 475 476 uint32 flags = interface.Flags(); 477 478 list_interface_addresses(interface, flags); 479 480 // Print MTU, metric, flags 481 482 printf("\tMTU: %" B_PRId32 ", Metric: %" B_PRId32, interface.MTU(), 483 interface.Metric()); 484 485 if (flags != 0) { 486 const struct { 487 int value; 488 const char *name; 489 } kFlags[] = { 490 {IFF_UP, "up"}, 491 {IFF_NOARP, "noarp"}, 492 {IFF_BROADCAST, "broadcast"}, 493 {IFF_LOOPBACK, "loopback"}, 494 {IFF_PROMISC, "promiscuous"}, 495 {IFF_ALLMULTI, "allmulti"}, 496 {IFF_AUTOUP, "autoup"}, 497 {IFF_LINK, "link"}, 498 {IFF_AUTO_CONFIGURED, "auto-configured"}, 499 {IFF_CONFIGURING, "configuring"}, 500 }; 501 bool first = true; 502 503 for (uint32 i = 0; i < sizeof(kFlags) / sizeof(kFlags[0]); i++) { 504 if ((flags & kFlags[i].value) != 0) { 505 if (first) { 506 printf(","); 507 first = false; 508 } 509 putchar(' '); 510 printf(kFlags[i].name); 511 } 512 } 513 } 514 515 putchar('\n'); 516 517 // Print statistics 518 519 ifreq_stats stats; 520 if (interface.GetStats(stats) == B_OK) { 521 printf("\tReceive: %d packets, %d errors, %Ld bytes, %d mcasts, %d " 522 "dropped\n", stats.receive.packets, stats.receive.errors, 523 stats.receive.bytes, stats.receive.multicast_packets, 524 stats.receive.dropped); 525 printf("\tTransmit: %d packets, %d errors, %Ld bytes, %d mcasts, %d " 526 "dropped\n", stats.send.packets, stats.send.errors, 527 stats.send.bytes, stats.send.multicast_packets, stats.send.dropped); 528 printf("\tCollisions: %d\n", stats.collisions); 529 } 530 531 putchar('\n'); 532 return true; 533 } 534 535 536 void 537 list_interfaces(const char* name) 538 { 539 if (name != NULL) { 540 list_interface(name); 541 return; 542 } 543 544 // get a list of all interfaces 545 546 BNetworkRoster& roster = BNetworkRoster::Default(); 547 548 BNetworkInterface interface; 549 uint32 cookie = 0; 550 551 while (roster.GetNextInterface(&cookie, interface) == B_OK) { 552 list_interface(interface.Name()); 553 } 554 } 555 556 557 /*! If there are any arguments given, this will remove only the specified 558 addresses from the interface named \a name. 559 If there are no arguments, it will remove the complete interface with all 560 of its addresses. 561 */ 562 void 563 delete_interface(const char* name, char* const* args, int32 argCount) 564 { 565 ifreq request; 566 if (!prepare_request(request, name)) 567 return; 568 569 for (int32 i = 0; i < argCount; i++) { 570 int32 familyIndex; 571 if (get_address_family(args[i], familyIndex)) 572 i++; 573 574 // TODO: be smart enough to detect the family by the address 575 576 int socket = find_socket(request, kFamilies[familyIndex].family); 577 if (socket == -1) { 578 fprintf(stderr, "%s: Address family \"%s\" is not available.\n", 579 kProgramName, kFamilies[familyIndex].name); 580 exit(1); 581 } 582 583 if (!parse_address(familyIndex, args[i], request.ifr_addr)) { 584 fprintf(stderr, "%s: Could not parse address \"%s\".\n", 585 kProgramName, args[i]); 586 exit(1); 587 } 588 589 if (ioctl(socket, SIOCDIFADDR, &request, sizeof(request)) < 0) { 590 fprintf(stderr, "%s: Could not delete address %s from interface %s:" 591 " %s\n", kProgramName, args[i], name, strerror(errno)); 592 } 593 } 594 595 if (argCount == 0) { 596 // Delete interface 597 int socket = find_socket(request, -1); 598 if (socket < 0) 599 exit(1); 600 601 request.ifr_addr.sa_family = AF_UNSPEC; 602 603 if (ioctl(socket, SIOCDIFADDR, &request, sizeof(request)) < 0) { 604 fprintf(stderr, "%s: Could not delete interface %s: %s\n", 605 kProgramName, name, strerror(errno)); 606 } 607 } 608 } 609 610 611 void 612 configure_interface(const char* name, char* const* args, 613 int32 argCount) 614 { 615 ifreq request; 616 if (!prepare_request(request, name)) 617 return; 618 619 // try to parse address family 620 621 int32 familyIndex; 622 int32 i = 0; 623 if (get_address_family(args[i], familyIndex)) 624 i++; 625 626 int socket = sAddressFamilySockets[familyIndex]; 627 if (socket < 0) { 628 fprintf(stderr, "%s: Address family \"%s\" is not available.\n", 629 kProgramName, kFamilies[familyIndex].name); 630 exit(1); 631 } 632 633 uint32 index = 0; 634 if (ioctl(socket, SIOCGIFINDEX, &request, sizeof(request)) >= 0) 635 index = request.ifr_index; 636 637 bool hasAddress = false, hasMask = false, hasPeer = false; 638 bool hasBroadcast = false, doAutoConfig = false; 639 struct sockaddr address, mask, peer, broadcast; 640 int mtu = -1, metric = -1, media = -1; 641 int addFlags = 0, currentFlags = 0, removeFlags = 0; 642 643 if (index == 0) { 644 // the interface does not exist yet, we have to add it first 645 ifaliasreq request; 646 memset(&request, 0, sizeof(ifaliasreq)); 647 strlcpy(request.ifra_name, name, IF_NAMESIZE); 648 649 if (ioctl(socket, SIOCAIFADDR, &request, sizeof(request)) < 0) { 650 fprintf(stderr, "%s: Could not add interface: %s\n", kProgramName, 651 strerror(errno)); 652 exit(1); 653 } 654 } 655 656 // try to parse address 657 658 if (parse_address(familyIndex, args[i], address)) { 659 hasAddress = true; 660 i++; 661 662 if (parse_address(familyIndex, args[i], mask)) { 663 hasMask = true; 664 i++; 665 } 666 } 667 668 // parse parameters and flags 669 670 while (i < argCount) { 671 if (!strcmp(args[i], "peer")) { 672 if (!parse_address(familyIndex, args[i + 1], peer)) { 673 fprintf(stderr, "%s: Option 'peer' needs valid address " 674 "parameter\n", kProgramName); 675 exit(1); 676 } 677 hasPeer = true; 678 i++; 679 } else if (!strcmp(args[i], "nm") || !strcmp(args[i], "netmask")) { 680 if (hasMask) { 681 fprintf(stderr, "%s: Netmask or prefix length is specified " 682 "twice\n", kProgramName); 683 exit(1); 684 } 685 if (!parse_address(familyIndex, args[i + 1], mask)) { 686 fprintf(stderr, "%s: Option 'netmask' needs valid address " 687 "parameter\n", kProgramName); 688 exit(1); 689 } 690 hasMask = true; 691 i++; 692 } else if (!strcmp(args[i], "prefixlen") 693 || !strcmp(args[i], "plen")) { 694 if (hasMask) { 695 fprintf(stderr, "%s: Netmask or prefix length is specified " 696 "twice\n", kProgramName); 697 exit(1); 698 } 699 if (!prefix_length_to_mask(familyIndex, args[i + 1], mask)) { 700 fprintf(stderr, "%s: Option 'prefixlen' is invalid for this " 701 "address family\n", kProgramName); 702 exit(1); 703 } 704 hasMask = true; 705 i++; 706 } else if (!strcmp(args[i], "bc") || !strcmp(args[i], "broadcast")) { 707 if (hasBroadcast) { 708 fprintf(stderr, "%s: broadcast address is specified twice\n", 709 kProgramName); 710 exit(1); 711 } 712 if (!parse_address(familyIndex, args[i + 1], broadcast)) { 713 fprintf(stderr, "%s: Option 'broadcast' needs valid address " 714 "parameter\n", kProgramName); 715 exit(1); 716 } 717 hasBroadcast = true; 718 addFlags |= IFF_BROADCAST; 719 i++; 720 } else if (!strcmp(args[i], "mtu")) { 721 mtu = args[i + 1] ? strtol(args[i + 1], NULL, 0) : 0; 722 if (mtu <= 500) { 723 fprintf(stderr, "%s: Option 'mtu' expected valid max transfer " 724 "unit size\n", kProgramName); 725 exit(1); 726 } 727 i++; 728 } else if (!strcmp(args[i], "metric")) { 729 if (i + 1 >= argCount) { 730 fprintf(stderr, "%s: Option 'metric' exptected parameter\n", 731 kProgramName); 732 exit(1); 733 } 734 metric = strtol(args[i + 1], NULL, 0); 735 i++; 736 } else if (!strcmp(args[i], "media")) { 737 if (ioctl(socket, SIOCGIFMEDIA, &request, 738 sizeof(struct ifreq)) < 0) { 739 fprintf(stderr, "%s: Unable to detect media type\n", 740 kProgramName); 741 exit(1); 742 } 743 if (i + 1 >= argCount) { 744 fprintf(stderr, "%s: Option 'media' exptected parameter\n", 745 kProgramName); 746 exit(1); 747 } 748 if (!media_parse_subtype(args[i + 1], IFM_TYPE(request.ifr_media), 749 &media)) { 750 fprintf(stderr, "%s: Invalid parameter for option 'media': " 751 "'%s'\n", kProgramName, args[i + 1]); 752 exit(1); 753 } 754 i++; 755 } else if (!strcmp(args[i], "up") || !strcmp(args[i], "-down")) { 756 addFlags |= IFF_UP; 757 } else if (!strcmp(args[i], "down") || !strcmp(args[i], "-up")) { 758 removeFlags |= IFF_UP; 759 } else if (!strcmp(args[i], "bcast")) { 760 addFlags |= IFF_BROADCAST; 761 } else if (!strcmp(args[i], "-bcast")) { 762 removeFlags |= IFF_BROADCAST; 763 } else if (!strcmp(args[i], "promisc")) { 764 addFlags |= IFF_PROMISC; 765 } else if (!strcmp(args[i], "-promisc")) { 766 removeFlags |= IFF_PROMISC; 767 } else if (!strcmp(args[i], "allmulti")) { 768 addFlags |= IFF_ALLMULTI; 769 } else if (!strcmp(args[i], "-allmulti")) { 770 removeFlags |= IFF_ALLMULTI; 771 } else if (!strcmp(args[i], "loopback")) { 772 addFlags |= IFF_LOOPBACK; 773 } else if (!strcmp(args[i], "auto-config")) { 774 doAutoConfig = true; 775 } else 776 usage(1); 777 778 i++; 779 } 780 781 if ((addFlags & removeFlags) != 0) { 782 fprintf(stderr, "%s: Contradicting flags specified\n", kProgramName); 783 exit(1); 784 } 785 786 if (doAutoConfig && (hasAddress || hasMask || hasBroadcast || hasPeer)) { 787 fprintf(stderr, "%s: Contradicting changes specified\n", kProgramName); 788 exit(1); 789 } 790 791 // set address/mask/broadcast/peer 792 793 if (hasAddress) { 794 memcpy(&request.ifr_addr, &address, address.sa_len); 795 796 if (ioctl(socket, SIOCSIFADDR, &request, sizeof(struct ifreq)) < 0) { 797 fprintf(stderr, "%s: Setting address failed: %s\n", kProgramName, 798 strerror(errno)); 799 exit(1); 800 } 801 } 802 803 if (ioctl(socket, SIOCGIFFLAGS, &request, sizeof(struct ifreq)) < 0) { 804 fprintf(stderr, "%s: Getting flags failed: %s\n", kProgramName, 805 strerror(errno)); 806 exit(1); 807 } 808 currentFlags = request.ifr_flags; 809 810 if (hasMask) { 811 memcpy(&request.ifr_mask, &mask, mask.sa_len); 812 813 if (ioctl(socket, SIOCSIFNETMASK, &request, sizeof(struct ifreq)) < 0) { 814 fprintf(stderr, "%s: Setting subnet mask failed: %s\n", 815 kProgramName, strerror(errno)); 816 exit(1); 817 } 818 } 819 820 if (hasBroadcast) { 821 memcpy(&request.ifr_broadaddr, &broadcast, broadcast.sa_len); 822 823 if (ioctl(socket, SIOCSIFBRDADDR, &request, sizeof(struct ifreq)) < 0) { 824 fprintf(stderr, "%s: Setting broadcast address failed: %s\n", 825 kProgramName, strerror(errno)); 826 exit(1); 827 } 828 } 829 830 if (hasPeer) { 831 memcpy(&request.ifr_dstaddr, &peer, peer.sa_len); 832 833 if (ioctl(socket, SIOCSIFDSTADDR, &request, sizeof(struct ifreq)) < 0) { 834 fprintf(stderr, "%s: Setting peer address failed: %s\n", 835 kProgramName, strerror(errno)); 836 exit(1); 837 } 838 } 839 840 // set flags 841 842 if (hasAddress || hasMask || hasBroadcast || hasPeer) 843 removeFlags = IFF_AUTO_CONFIGURED | IFF_CONFIGURING; 844 845 if (addFlags || removeFlags) { 846 request.ifr_flags = (currentFlags & ~removeFlags) | addFlags; 847 if (ioctl(socket, SIOCSIFFLAGS, &request, sizeof(struct ifreq)) < 0) { 848 fprintf(stderr, "%s: Setting flags failed: %s\n", kProgramName, 849 strerror(errno)); 850 } 851 } 852 853 // set options 854 855 if (mtu != -1) { 856 request.ifr_mtu = mtu; 857 if (ioctl(socket, SIOCSIFMTU, &request, sizeof(struct ifreq)) < 0) { 858 fprintf(stderr, "%s: Setting MTU failed: %s\n", kProgramName, 859 strerror(errno)); 860 } 861 } 862 863 if (metric != -1) { 864 request.ifr_metric = metric; 865 if (ioctl(socket, SIOCSIFMETRIC, &request, sizeof(struct ifreq)) < 0) { 866 fprintf(stderr, "%s: Setting metric failed: %s\n", kProgramName, 867 strerror(errno)); 868 } 869 } 870 871 if (media != -1) { 872 request.ifr_media = media; 873 if (ioctl(socket, SIOCSIFMEDIA, &request, sizeof(struct ifreq)) < 0) { 874 fprintf(stderr, "%s: Setting media failed: %s\n", kProgramName, 875 strerror(errno)); 876 } 877 } 878 879 // start auto configuration, if asked for 880 881 if (doAutoConfig) { 882 BMessage message(kMsgConfigureInterface); 883 message.AddString("device", name); 884 BMessage address; 885 address.AddString("family", kFamilies[familyIndex].name); 886 address.AddBool("auto_config", true); 887 message.AddMessage("address", &address); 888 889 BMessenger networkServer(kNetServerSignature); 890 if (networkServer.IsValid()) { 891 BMessage reply; 892 status_t status = networkServer.SendMessage(&message, &reply); 893 if (status != B_OK) { 894 fprintf(stderr, "%s: Sending auto-config message failed: %s\n", 895 kProgramName, strerror(status)); 896 } else if (reply.FindInt32("status", &status) == B_OK 897 && status != B_OK) { 898 fprintf(stderr, "%s: Auto-configuring failed: %s\n", 899 kProgramName, strerror(status)); 900 } 901 } else { 902 fprintf(stderr, "%s: The net_server needs to run for the auto " 903 "configuration!\n", kProgramName); 904 } 905 } 906 } 907 908 909 // #pragma mark - 910 911 912 int 913 main(int argc, char** argv) 914 { 915 if (argc > 1 && (!strcmp(argv[1], "--help") || !strcmp(argv[1], "-h"))) 916 usage(0); 917 918 if (!initialize_address_families()) { 919 fprintf(stderr, "%s: The networking stack doesn't seem to be " 920 "available.\n", kProgramName); 921 return 1; 922 } 923 924 if (argc > 1 925 && (!strcmp(argv[1], "--delete") 926 || !strcmp(argv[1], "--del") 927 || !strcmp(argv[1], "-d") 928 || !strcmp(argv[1], "del") 929 || !strcmp(argv[1], "delete"))) { 930 // Delete interface (addresses) 931 932 if (argc < 3) 933 usage(1); 934 935 const char* name = argv[2]; 936 delete_interface(name, argv + 3, argc - 3); 937 return 0; 938 } 939 940 if (argc > 1 && !strcmp(argv[1], "-a")) { 941 // Accept an optional "-a" option to list all interfaces for those 942 // that are used to it from other platforms. 943 944 if (argc > 2) 945 usage(1); 946 947 list_interfaces(NULL); 948 return 0; 949 } 950 951 const char* name = argv[1]; 952 if (argc > 2) { 953 // Add or configure an interface 954 955 configure_interface(name, argv + 2, argc - 2); 956 return 0; 957 } 958 959 // list interfaces 960 961 list_interfaces(name); 962 return 0; 963 } 964 965