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