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