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