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, name); 214 return false; 215 } 216 217 strcpy(request.ifr_name, name); 218 return true; 219 } 220 221 222 bool 223 get_address_family(const char* argument, int32& familyIndex) 224 { 225 for (int32 i = 0; kFamilies[i].family >= 0; i++) { 226 for (int32 j = 0; kFamilies[i].identifiers[j]; j++) { 227 if (!strcmp(argument, kFamilies[i].identifiers[j])) { 228 // found a match 229 familyIndex = i; 230 return true; 231 } 232 } 233 } 234 235 // defaults to AF_INET 236 familyIndex = 0; 237 return false; 238 } 239 240 241 bool 242 parse_address(int32 familyIndex, const char* argument, struct sockaddr& address) 243 { 244 if (argument == NULL) 245 return false; 246 247 return kFamilies[familyIndex].parse_address(argument, &address); 248 } 249 250 251 // #pragma mark - 252 253 254 void 255 list_interface(int socket, const char* name) 256 { 257 ifreq request; 258 if (!prepare_request(request, name)) 259 return; 260 261 if (ioctl(socket, SIOCGIFINDEX, &request, sizeof(request)) < 0) { 262 fprintf(stderr, "%s: Interface \"%s\" does not exist.\n", kProgramName, name); 263 return; 264 } 265 266 printf("%s", name); 267 size_t length = strlen(name); 268 if (length < 8) 269 putchar('\t'); 270 else 271 printf("\n\t"); 272 273 // get link level interface for this interface 274 275 int linkSocket = ::socket(AF_LINK, SOCK_DGRAM, 0); 276 if (linkSocket < 0) { 277 printf("No link level: %s\n", strerror(errno)); 278 } else { 279 const char *type = "unknown"; 280 char address[256]; 281 strcpy(address, "none"); 282 283 if (ioctl(socket, SIOCGIFPARAM, &request, sizeof(struct ifreq)) == 0) { 284 prepare_request(request, request.ifr_parameter.device); 285 if (ioctl(linkSocket, SIOCGIFADDR, &request, sizeof(struct ifreq)) == 0) { 286 sockaddr_dl &link = *(sockaddr_dl *)&request.ifr_addr; 287 288 switch (link.sdl_type) { 289 case IFT_ETHER: 290 { 291 type = "Ethernet"; 292 293 if (link.sdl_alen > 0) { 294 uint8 *mac = (uint8 *)LLADDR(&link); 295 sprintf(address, "%02x:%02x:%02x:%02x:%02x:%02x", 296 mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); 297 } else 298 strcpy(address, "not available"); 299 break; 300 } 301 case IFT_LOOP: 302 type = "Local Loopback"; 303 break; 304 case IFT_MODEM: 305 type = "Modem"; 306 break; 307 } 308 } 309 } 310 311 printf("Hardware Type: %s, Address: %s\n", type, address); 312 close(linkSocket); 313 } 314 315 if (ioctl(socket, SIOCGIFMEDIA, &request, sizeof(struct ifreq)) == 0 316 && (request.ifr_media & IFM_ACTIVE) != 0) { 317 // dump media state in case we're linked 318 const char* type = "unknown"; 319 bool show = false; 320 321 for (int32 i = 0; kMediaTypes[i].type >= 0; i++) { 322 // loopback don't really have a media anyway 323 if (IFM_TYPE(request.ifr_media) == 0/*IFT_LOOP*/) 324 break; 325 // only check for generic or correct subtypes 326 if (kMediaTypes[i].type && 327 kMediaTypes[i].type != IFM_TYPE(request.ifr_media)) 328 continue; 329 for (int32 j = 0; kMediaTypes[i].subtypes[j].subtype >= 0; j++) { 330 if (kMediaTypes[i].subtypes[j].subtype == IFM_SUBTYPE(request.ifr_media)) { 331 // found a match 332 type = kMediaTypes[i].subtypes[j].pretty; 333 show = true; 334 break; 335 } 336 } 337 } 338 339 if (show) 340 printf("\tMedia Type: %s\n", type); 341 } 342 343 uint32 flags = 0; 344 if (ioctl(socket, SIOCGIFFLAGS, &request, sizeof(struct ifreq)) == 0) 345 flags = request.ifr_flags; 346 347 for (int32 i = 0; kFamilies[i].family >= 0; i++) { 348 int familySocket = ::socket(kFamilies[i].family, SOCK_DGRAM, 0); 349 if (familySocket < 0) 350 continue; 351 352 if (ioctl(familySocket, SIOCGIFADDR, &request, sizeof(struct ifreq)) == 0) { 353 printf("\t%s addr: ", kFamilies[i].name); 354 kFamilies[i].print_address(&request.ifr_addr); 355 356 if ((flags & IFF_BROADCAST) != 0 357 && ioctl(familySocket, SIOCGIFBRDADDR, &request, sizeof(struct ifreq)) == 0 358 && request.ifr_broadaddr.sa_family == kFamilies[i].family) { 359 printf(", Bcast: "); 360 kFamilies[i].print_address(&request.ifr_broadaddr); 361 } 362 if (ioctl(familySocket, SIOCGIFNETMASK, &request, sizeof(struct ifreq)) == 0 363 && request.ifr_mask.sa_family == kFamilies[i].family) { 364 printf(", Mask: "); 365 kFamilies[i].print_address(&request.ifr_mask); 366 } 367 putchar('\n'); 368 } 369 370 close(familySocket); 371 } 372 373 // Print MTU, metric, flags 374 375 printf("\tMTU: "); 376 if (ioctl(socket, SIOCGIFMTU, &request, sizeof(struct ifreq)) == 0) 377 printf("%d", request.ifr_mtu); 378 else 379 printf("-"); 380 381 printf(", Metric: "); 382 if (ioctl(socket, SIOCGIFMETRIC, &request, sizeof(struct ifreq)) == 0) 383 printf("%d", request.ifr_metric); 384 else 385 printf("-"); 386 387 if (flags != 0) { 388 const struct { 389 int value; 390 const char *name; 391 } kFlags[] = { 392 {IFF_UP, "up"}, 393 {IFF_NOARP, "noarp"}, 394 {IFF_BROADCAST, "broadcast"}, 395 {IFF_LOOPBACK, "loopback"}, 396 {IFF_PROMISC, "promiscuous"}, 397 {IFF_ALLMULTI, "allmulti"}, 398 {IFF_AUTOUP, "autoup"}, 399 {IFF_LINK, "link"}, 400 {IFF_AUTO_CONFIGURED, "auto-configured"}, 401 {IFF_CONFIGURING, "configuring"}, 402 }; 403 bool first = true; 404 405 for (uint32 i = 0; i < sizeof(kFlags) / sizeof(kFlags[0]); i++) { 406 if ((flags & kFlags[i].value) != 0) { 407 if (first) { 408 printf(","); 409 first = false; 410 } 411 putchar(' '); 412 printf(kFlags[i].name); 413 } 414 } 415 } 416 417 putchar('\n'); 418 419 // Print statistics 420 421 if (ioctl(socket, SIOCGIFSTATS, &request, sizeof(struct ifreq)) == 0) { 422 printf("\tReceive: %d packets, %d errors, %Ld bytes, %d mcasts, %d dropped\n", 423 request.ifr_stats.receive.packets, request.ifr_stats.receive.errors, 424 request.ifr_stats.receive.bytes, request.ifr_stats.receive.multicast_packets, 425 request.ifr_stats.receive.dropped); 426 printf("\tTransmit: %d packets, %d errors, %Ld bytes, %d mcasts, %d dropped\n", 427 request.ifr_stats.send.packets, request.ifr_stats.send.errors, 428 request.ifr_stats.send.bytes, request.ifr_stats.send.multicast_packets, 429 request.ifr_stats.send.dropped); 430 printf("\tCollisions: %d\n", request.ifr_stats.collisions); 431 } 432 433 putchar('\n'); 434 } 435 436 437 void 438 list_interfaces(int socket, const char* name) 439 { 440 if (name != NULL) { 441 list_interface(socket, name); 442 return; 443 } 444 445 // get a list of all interfaces 446 447 ifconf config; 448 config.ifc_len = sizeof(config.ifc_value); 449 if (ioctl(socket, SIOCGIFCOUNT, &config, sizeof(struct ifconf)) < 0) 450 return; 451 452 uint32 count = (uint32)config.ifc_value; 453 if (count == 0) { 454 fprintf(stderr, "%s: There are no interfaces yet!\n", kProgramName); 455 return; 456 } 457 458 void *buffer = malloc(count * sizeof(struct ifreq)); 459 if (buffer == NULL) { 460 fprintf(stderr, "%s: Out of memory.\n", kProgramName); 461 return; 462 } 463 464 config.ifc_len = count * sizeof(struct ifreq); 465 config.ifc_buf = buffer; 466 if (ioctl(socket, SIOCGIFCONF, &config, sizeof(struct ifconf)) < 0) 467 return; 468 469 ifreq *interface = (ifreq *)buffer; 470 471 for (uint32 i = 0; i < count; i++) { 472 list_interface(socket, interface->ifr_name); 473 474 interface = (ifreq *)((addr_t)interface + IF_NAMESIZE + interface->ifr_addr.sa_len); 475 } 476 477 free(buffer); 478 } 479 480 481 void 482 delete_interface(int socket, const char* name) 483 { 484 ifreq request; 485 if (!prepare_request(request, name)) 486 return; 487 488 if (ioctl(socket, SIOCDIFADDR, &request, sizeof(request)) < 0) { 489 fprintf(stderr, "%s: Could not delete interface %s: %s\n", 490 kProgramName, name, strerror(errno)); 491 } 492 } 493 494 495 void 496 configure_interface(int socket, const char* name, char* const* args, 497 int32 argCount) 498 { 499 ifreq request; 500 if (!prepare_request(request, name)) 501 return; 502 503 uint32 index = 0; 504 if (ioctl(socket, SIOCGIFINDEX, &request, sizeof(request)) >= 0) 505 index = request.ifr_index; 506 507 bool hasAddress = false, hasMask = false, hasPeer = false; 508 bool hasBroadcast = false, doAutoConfig = false; 509 struct sockaddr address, mask, peer, broadcast; 510 int mtu = -1, metric = -1, media = -1; 511 int addFlags = 0, currentFlags = 0, removeFlags = 0; 512 513 // try to parse address family 514 515 int32 familyIndex; 516 int32 i = 0; 517 if (get_address_family(args[i], familyIndex)) 518 i++; 519 520 if (kFamilies[familyIndex].family != AF_INET) { 521 close(socket); 522 523 // replace socket with one of the correct address family 524 socket = ::socket(kFamilies[familyIndex].family, SOCK_DGRAM, 0); 525 if (socket < 0) { 526 fprintf(stderr, "%s: Address family \"%s\" is not available.\n", 527 kProgramName, kFamilies[familyIndex].name); 528 exit(1); 529 } 530 } 531 532 if (index == 0) { 533 // the interface does not exist yet, we have to add it first 534 request.ifr_parameter.base_name[0] = '\0'; 535 request.ifr_parameter.device[0] = '\0'; 536 request.ifr_parameter.sub_type = 0; 537 // the default device is okay for us 538 539 if (ioctl(socket, SIOCAIFADDR, &request, sizeof(request)) < 0) { 540 fprintf(stderr, "%s: Could not add interface: %s\n", kProgramName, 541 strerror(errno)); 542 exit(1); 543 } 544 } 545 546 // try to parse address 547 548 if (parse_address(familyIndex, args[i], address)) { 549 hasAddress = true; 550 i++; 551 552 if (parse_address(familyIndex, args[i], mask)) { 553 hasMask = true; 554 i++; 555 } 556 } 557 558 // parse parameters and flags 559 560 while (i < argCount) { 561 if (!strcmp(args[i], "peer")) { 562 if (!parse_address(familyIndex, args[i + 1], peer)) { 563 fprintf(stderr, "%s: Option 'peer' needs valid address " 564 "parameter\n", kProgramName); 565 exit(1); 566 } 567 hasPeer = true; 568 i++; 569 } else if (!strcmp(args[i], "nm") || !strcmp(args[i], "netmask")) { 570 if (hasMask) { 571 fprintf(stderr, "%s: Netmask is specified twice\n", 572 kProgramName); 573 exit(1); 574 } 575 if (!parse_address(familyIndex, args[i + 1], mask)) { 576 fprintf(stderr, "%s: Option 'netmask' needs valid address " 577 "parameter\n", kProgramName); 578 exit(1); 579 } 580 hasMask = true; 581 i++; 582 } else if (!strcmp(args[i], "bc") || !strcmp(args[i], "broadcast")) { 583 if (hasBroadcast) { 584 fprintf(stderr, "%s: broadcast address is specified twice\n", 585 kProgramName); 586 exit(1); 587 } 588 if (!parse_address(familyIndex, args[i + 1], broadcast)) { 589 fprintf(stderr, "%s: Option 'broadcast' needs valid address " 590 "parameter\n", kProgramName); 591 exit(1); 592 } 593 hasBroadcast = true; 594 addFlags |= IFF_BROADCAST; 595 i++; 596 } else if (!strcmp(args[i], "mtu")) { 597 mtu = args[i + 1] ? strtol(args[i + 1], NULL, 0) : 0; 598 if (mtu <= 500) { 599 fprintf(stderr, "%s: Option 'mtu' expected valid max transfer " 600 "unit size\n", kProgramName); 601 exit(1); 602 } 603 i++; 604 } else if (!strcmp(args[i], "metric")) { 605 if (i + 1 >= argCount) { 606 fprintf(stderr, "%s: Option 'metric' exptected parameter\n", 607 kProgramName); 608 exit(1); 609 } 610 metric = strtol(args[i + 1], NULL, 0); 611 i++; 612 } else if (!strcmp(args[i], "media")) { 613 if (ioctl(socket, SIOCGIFMEDIA, &request, 614 sizeof(struct ifreq)) < 0) { 615 fprintf(stderr, "%s: Unable to detect media type\n", 616 kProgramName); 617 exit(1); 618 } 619 if (i + 1 >= argCount) { 620 fprintf(stderr, "%s: Option 'media' exptected parameter\n", 621 kProgramName); 622 exit(1); 623 } 624 if (!media_parse_subtype(args[i + 1], IFM_TYPE(request.ifr_media), 625 &media)) { 626 fprintf(stderr, "%s: Invalid parameter for option 'media': " 627 "'%s'\n", kProgramName, args[i + 1]); 628 exit(1); 629 } 630 i++; 631 } else if (!strcmp(args[i], "up") || !strcmp(args[i], "-down")) { 632 addFlags |= IFF_UP; 633 } else if (!strcmp(args[i], "down") || !strcmp(args[i], "-up")) { 634 removeFlags |= IFF_UP; 635 } else if (!strcmp(args[i], "bcast")) { 636 addFlags |= IFF_BROADCAST; 637 } else if (!strcmp(args[i], "-bcast")) { 638 removeFlags |= IFF_BROADCAST; 639 } else if (!strcmp(args[i], "promisc")) { 640 addFlags |= IFF_PROMISC; 641 } else if (!strcmp(args[i], "-promisc")) { 642 removeFlags |= IFF_PROMISC; 643 } else if (!strcmp(args[i], "allmulti")) { 644 addFlags |= IFF_ALLMULTI; 645 } else if (!strcmp(args[i], "-allmulti")) { 646 removeFlags |= IFF_ALLMULTI; 647 } else if (!strcmp(args[i], "loopback")) { 648 addFlags |= IFF_LOOPBACK; 649 } else if (!strcmp(args[i], "auto-config")) { 650 doAutoConfig = true; 651 } else 652 usage(1); 653 654 i++; 655 } 656 657 if ((addFlags & removeFlags) != 0) { 658 fprintf(stderr, "%s: Contradicting flags specified\n", kProgramName); 659 exit(1); 660 } 661 662 if (doAutoConfig && (hasAddress || hasMask || hasBroadcast || hasPeer)) { 663 fprintf(stderr, "%s: Contradicting changes specified\n", kProgramName); 664 exit(1); 665 } 666 667 // set address/mask/broadcast/peer 668 669 if (hasAddress) { 670 memcpy(&request.ifr_addr, &address, address.sa_len); 671 672 if (ioctl(socket, SIOCSIFADDR, &request, sizeof(struct ifreq)) < 0) { 673 fprintf(stderr, "%s: Setting address failed: %s\n", kProgramName, 674 strerror(errno)); 675 exit(1); 676 } 677 } 678 679 if (ioctl(socket, SIOCGIFFLAGS, &request, sizeof(struct ifreq)) < 0) { 680 fprintf(stderr, "%s: Getting flags failed: %s\n", kProgramName, 681 strerror(errno)); 682 exit(1); 683 } 684 currentFlags = request.ifr_flags; 685 686 if (hasMask) { 687 memcpy(&request.ifr_mask, &mask, mask.sa_len); 688 689 if (ioctl(socket, SIOCSIFNETMASK, &request, sizeof(struct ifreq)) < 0) { 690 fprintf(stderr, "%s: Setting subnet mask failed: %s\n", 691 kProgramName, strerror(errno)); 692 exit(1); 693 } 694 } 695 696 if (hasBroadcast) { 697 memcpy(&request.ifr_broadaddr, &broadcast, broadcast.sa_len); 698 699 if (ioctl(socket, SIOCSIFBRDADDR, &request, sizeof(struct ifreq)) < 0) { 700 fprintf(stderr, "%s: Setting broadcast address failed: %s\n", 701 kProgramName, strerror(errno)); 702 exit(1); 703 } 704 } 705 706 if (hasPeer) { 707 memcpy(&request.ifr_dstaddr, &peer, peer.sa_len); 708 709 if (ioctl(socket, SIOCSIFDSTADDR, &request, sizeof(struct ifreq)) < 0) { 710 fprintf(stderr, "%s: Setting peer address failed: %s\n", 711 kProgramName, strerror(errno)); 712 exit(1); 713 } 714 } 715 716 // set flags 717 718 if (hasAddress || hasMask || hasBroadcast || hasPeer) { 719 removeFlags = IFF_AUTO_CONFIGURED | IFF_CONFIGURING; 720 } 721 printf("set flags: current %x, remove %x, add %x\n", currentFlags, removeFlags, addFlags); 722 if (addFlags || removeFlags) { 723 request.ifr_flags = (currentFlags & ~removeFlags) | addFlags; 724 printf(" --> set %x\n", request.ifr_flags); 725 if (ioctl(socket, SIOCSIFFLAGS, &request, sizeof(struct ifreq)) < 0) { 726 fprintf(stderr, "%s: Setting flags failed: %s\n", kProgramName, 727 strerror(errno)); 728 } 729 } 730 731 // set options 732 733 if (mtu != -1) { 734 request.ifr_mtu = mtu; 735 if (ioctl(socket, SIOCSIFMTU, &request, sizeof(struct ifreq)) < 0) { 736 fprintf(stderr, "%s: Setting MTU failed: %s\n", kProgramName, 737 strerror(errno)); 738 } 739 } 740 741 if (metric != -1) { 742 request.ifr_metric = metric; 743 if (ioctl(socket, SIOCSIFMETRIC, &request, sizeof(struct ifreq)) < 0) { 744 fprintf(stderr, "%s: Setting metric failed: %s\n", kProgramName, 745 strerror(errno)); 746 } 747 } 748 749 if (media != -1) { 750 request.ifr_media = media; 751 if (ioctl(socket, SIOCSIFMEDIA, &request, sizeof(struct ifreq)) < 0) { 752 fprintf(stderr, "%s: Setting media failed: %s\n", kProgramName, 753 strerror(errno)); 754 } 755 } 756 757 // start auto configuration, if asked for 758 759 if (doAutoConfig) { 760 BMessage message(kMsgConfigureInterface); 761 message.AddString("device", name); 762 BMessage address; 763 address.AddString("family", "inet"); 764 address.AddBool("auto config", true); 765 message.AddMessage("address", &address); 766 767 BMessenger networkServer(kNetServerSignature); 768 if (networkServer.IsValid()) { 769 BMessage reply; 770 status_t status = networkServer.SendMessage(&message, &reply); 771 if (status != B_OK) { 772 fprintf(stderr, "%s: Sending auto-config message failed: %s\n", 773 kProgramName, strerror(status)); 774 } else if (reply.FindInt32("status", &status) == B_OK 775 && status != B_OK) { 776 fprintf(stderr, "%s: Auto-configuring failed: %s\n", 777 kProgramName, strerror(status)); 778 } 779 } else { 780 fprintf(stderr, "%s: The net_server needs to run for the auto " 781 "configuration!\n", kProgramName); 782 } 783 } 784 } 785 786 787 // #pragma mark - 788 789 790 int 791 main(int argc, char** argv) 792 { 793 if (argc > 1 && (!strcmp(argv[1], "--help") || !strcmp(argv[1], "-h"))) 794 usage(0); 795 796 bool deleteInterfaces = false; 797 798 if (argc > 1 799 && (!strcmp(argv[1], "--delete") 800 || !strcmp(argv[1], "--del") 801 || !strcmp(argv[1], "-d"))) { 802 // delete interfaces 803 if (argc < 3) 804 usage(1); 805 806 deleteInterfaces = true; 807 } 808 809 // we need a socket to talk to the networking stack 810 int socket = ::socket(AF_INET, SOCK_DGRAM, 0); 811 if (socket < 0) { 812 fprintf(stderr, "%s: The networking stack doesn't seem to be " 813 "available.\n", kProgramName); 814 return 1; 815 } 816 817 if (deleteInterfaces) { 818 for (int i = 2; i < argc; i++) { 819 delete_interface(socket, argv[i]); 820 } 821 return 0; 822 } else if (argc > 1 && !strcmp(argv[1], "-a")) { 823 // accept -a option for those that are used to it from other platforms 824 if (argc > 2) 825 usage(1); 826 827 list_interfaces(socket, NULL); 828 return 0; 829 } 830 831 const char* name = argv[1]; 832 if (argc > 2) { 833 // add or configure an interface 834 835 configure_interface(socket, name, argv + 2, argc - 2); 836 return 0; 837 } 838 839 // list interfaces 840 841 list_interfaces(socket, name); 842 return 0; 843 } 844 845