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