xref: /haiku/src/bin/network/ifconfig/ifconfig.cpp (revision 02354704729d38c3b078c696adc1bbbd33cbcf72)
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
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
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*
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
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
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
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*
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*
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*
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
263 show_wireless_network_header(bool verbose)
264 {
265 	printf("%-32s %-20s %s  %s\n", "name", "address", "signal", "auth");
266 }
267 
268 
269 void
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
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 				wireless_network network;
371 				uint32 cookie = 0;
372 				while (device.GetNextNetwork(cookie, network) == B_OK)
373 					show_wireless_network(network, verbose);
374 			}
375 			break;
376 		}
377 
378 		case JOIN:
379 		{
380 			// join a wireless network
381 			if (argCount > 2) {
382 				fprintf(stderr, "usage: %s %s join <network> [<password>]\n",
383 					kProgramName, name);
384 				exit(1);
385 			}
386 
387 			const char* password = NULL;
388 			if (argCount == 2)
389 				password = args[1];
390 
391 			BNetworkAddress link;
392 			status_t status;
393 			if (link.SetTo(AF_LINK, args[0]) == B_OK)
394 				status = device.JoinNetwork(link, password);
395 			else
396 				status = device.JoinNetwork(args[0], password);
397 			if (status != B_OK) {
398 				fprintf(stderr, "%s: Joining network failed: %s\n",
399 					kProgramName, strerror(status));
400 				exit(1);
401 			}
402 			break;
403 		}
404 
405 		case LEAVE:
406 		{
407 			// leave a wireless network
408 			if (argCount != 1) {
409 				fprintf(stderr, "usage: %s %s leave <network>\n", kProgramName,
410 					name);
411 				exit(1);
412 			}
413 
414 			BNetworkAddress link;
415 			status_t status;
416 			if (link.SetTo(AF_LINK, args[0]) == B_OK)
417 				status = device.LeaveNetwork(link);
418 			else
419 				status = device.LeaveNetwork(args[0]);
420 			if (status != B_OK) {
421 				fprintf(stderr, "%s: Leaving network failed: %s\n",
422 					kProgramName, strerror(status));
423 				exit(1);
424 			}
425 			break;
426 		}
427 
428 		case CONTROL:
429 		{
430 			ieee80211req request;
431 			memset(&request, 0, sizeof(request));
432 			request.i_type = controlOption;
433 			request.i_val = controlValue;
434 			status_t status = device.Control(SIOCS80211, &request);
435 			if (status != B_OK) {
436 				fprintf(stderr, "%s: Control failed: %s\n", kProgramName,
437 					strerror(status));
438 				exit(1);
439 			}
440 			break;
441 		}
442 
443 		case NONE:
444 			break;
445 	}
446 
447 	return true;
448 }
449 
450 
451 //	#pragma mark -
452 
453 
454 void
455 list_interface_addresses(BNetworkInterface& interface, uint32 flags)
456 {
457 	int32 count = interface.CountAddresses();
458 	for (int32 i = 0; i < count; i++) {
459 		BNetworkInterfaceAddress address;
460 		if (interface.GetAddressAt(i, address) != B_OK)
461 			break;
462 
463 		const address_family* family
464 			= address_family_for(address.Address().Family());
465 
466 		printf("\t%s addr: %s", family->name,
467 			to_string(address.Address()).String());
468 
469 		if ((flags & IFF_BROADCAST) != 0)
470 			printf(", Bcast: %s", to_string(address.Broadcast()).String());
471 
472 		switch (family->preferred_format) {
473 			case PREFER_OUTPUT_MASK:
474 				printf(", Mask: %s", to_string(address.Mask()).String());
475 				break;
476 			case PREFER_OUTPUT_PREFIX_LENGTH:
477 				printf(", Prefix Length: %zu", address.Mask().PrefixLength());
478 				break;
479 		}
480 
481 		putchar('\n');
482 	}
483 }
484 
485 
486 bool
487 list_interface(const char* name)
488 {
489 	printf("%s", name);
490 	size_t length = strlen(name);
491 	if (length < 8)
492 		putchar('\t');
493 	else
494 		printf("\n\t");
495 
496 	// get link level interface for this interface
497 
498 	BNetworkInterface interface(name);
499 	if (!interface.Exists()) {
500 		printf("Interface not found!\n");
501 		return false;
502 	}
503 
504 	BNetworkAddress linkAddress;
505 	status_t status = interface.GetHardwareAddress(linkAddress);
506 	if (status == B_OK) {
507 		const char *type = "unknown";
508 		switch (linkAddress.LinkLevelType()) {
509 			case IFT_ETHER:
510 				type = "Ethernet";
511 				break;
512 			case IFT_LOOP:
513 				type = "Local Loopback";
514 				break;
515 			case IFT_MODEM:
516 				type = "Modem";
517 				break;
518 		}
519 
520 		BString address = linkAddress.ToString();
521 		if (address.Length() == 0)
522 			address = "none";
523 
524 		printf("Hardware type: %s, Address: %s\n", type, address.String());
525 	} else
526 		printf("No link level: %s\n", strerror(status));
527 
528 	int media = interface.Media();
529 	if ((media & IFM_ACTIVE) != 0) {
530 		// dump media state in case we're linked
531 		const char* type = media_type_to_string(media);
532 		if (type != NULL)
533 			printf("\tMedia type: %s\n", type);
534 	}
535 
536 	// Print associated wireless network(s)
537 
538 	BNetworkDevice device(name);
539 	if (device.IsWireless()) {
540 		wireless_network network;
541 		bool first = true;
542 		uint32 cookie = 0;
543 		while (device.GetNextAssociatedNetwork(cookie, network) == B_OK) {
544 			if (first) {
545 				printf("\tNetwork: ");
546 				first = false;
547 			} else
548 				printf("\t\t");
549 
550 			printf("%s, Address: %s, %s", network.name,
551 				network.address.ToString().String(),
552 				get_authentication_mode(network.authentication_mode,
553 					network.flags));
554 			const char* keyMode = get_key_mode(network.key_mode);
555 			if (keyMode != NULL)
556 				printf(", %s/%s", keyMode, get_cipher(network.cipher));
557 			putchar('\n');
558 		}
559 	}
560 
561 	uint32 flags = interface.Flags();
562 
563 	list_interface_addresses(interface, flags);
564 
565 	// Print MTU, metric, flags
566 
567 	printf("\tMTU: %" B_PRId32 ", Metric: %" B_PRId32, interface.MTU(),
568 		interface.Metric());
569 
570 	if (flags != 0) {
571 		const struct {
572 			int			value;
573 			const char	*name;
574 		} kFlags[] = {
575 			{IFF_UP, "up"},
576 			{IFF_NOARP, "noarp"},
577 			{IFF_BROADCAST, "broadcast"},
578 			{IFF_LOOPBACK, "loopback"},
579 			{IFF_PROMISC, "promiscuous"},
580 			{IFF_ALLMULTI, "allmulti"},
581 			{IFF_AUTOUP, "autoup"},
582 			{IFF_LINK, "link"},
583 			{IFF_AUTO_CONFIGURED, "auto-configured"},
584 			{IFF_CONFIGURING, "configuring"},
585 		};
586 		bool first = true;
587 
588 		for (uint32 i = 0; i < sizeof(kFlags) / sizeof(kFlags[0]); i++) {
589 			if ((flags & kFlags[i].value) != 0) {
590 				if (first) {
591 					printf(",");
592 					first = false;
593 				}
594 				putchar(' ');
595 				fputs(kFlags[i].name, stdout);
596 			}
597 		}
598 	}
599 
600 	putchar('\n');
601 
602 	// Print statistics
603 
604 	ifreq_stats stats;
605 	if (interface.GetStats(stats) == B_OK) {
606 		printf("\tReceive: %d packets, %d errors, %Ld bytes, %d mcasts, %d "
607 			"dropped\n", stats.receive.packets, stats.receive.errors,
608 			stats.receive.bytes, stats.receive.multicast_packets,
609 			stats.receive.dropped);
610 		printf("\tTransmit: %d packets, %d errors, %Ld bytes, %d mcasts, %d "
611 			"dropped\n", stats.send.packets, stats.send.errors,
612 			stats.send.bytes, stats.send.multicast_packets, stats.send.dropped);
613 		printf("\tCollisions: %d\n", stats.collisions);
614 	}
615 
616 	putchar('\n');
617 	return true;
618 }
619 
620 
621 void
622 list_interfaces(const char* name)
623 {
624 	if (name != NULL) {
625 		list_interface(name);
626 		return;
627 	}
628 
629 	// get a list of all interfaces
630 
631 	BNetworkRoster& roster = BNetworkRoster::Default();
632 
633 	BNetworkInterface interface;
634 	uint32 cookie = 0;
635 
636 	while (roster.GetNextInterface(&cookie, interface) == B_OK) {
637 		list_interface(interface.Name());
638 	}
639 }
640 
641 
642 /*!	If there are any arguments given, this will remove only the specified
643 	addresses from the interface named \a name.
644 	If there are no arguments, it will remove the complete interface with all
645 	of its addresses.
646 */
647 void
648 delete_interface(const char* name, char* const* args, int32 argCount)
649 {
650 	BNetworkInterface interface(name);
651 
652 	for (int32 i = 0; i < argCount; i++) {
653 		int family = get_address_family(args[i]);
654 		if (family != AF_UNSPEC)
655 			i++;
656 
657 		BNetworkAddress address;
658 		if (!parse_address(family, args[i], address)) {
659 			fprintf(stderr, "%s: Could not parse address \"%s\".\n",
660 				kProgramName, args[i]);
661 			exit(1);
662 		}
663 
664 		status_t status = interface.RemoveAddress(address);
665 		if (status != B_OK) {
666 			fprintf(stderr, "%s: Could not delete address %s from interface %s:"
667 				" %s\n", kProgramName, args[i], name, strerror(status));
668 		}
669 	}
670 
671 	if (argCount == 0) {
672 		// Delete interface
673 		BNetworkRoster& roster = BNetworkRoster::Default();
674 
675 		status_t status = roster.RemoveInterface(interface);
676 		if (status != B_OK) {
677 			fprintf(stderr, "%s: Could not delete interface %s: %s\n",
678 				kProgramName, name, strerror(errno));
679 		}
680 	}
681 }
682 
683 
684 void
685 configure_interface(const char* name, char* const* args, int32 argCount)
686 {
687 	// try to parse address family
688 
689 	int32 i = 0;
690 	int family = get_address_family(args[i]);
691 	if (family != AF_UNSPEC)
692 		i++;
693 
694 	// try to parse address
695 
696 	BNetworkAddress address;
697 	BNetworkAddress mask;
698 
699 	if (parse_address(family, args[i], address)) {
700 		i++;
701 
702 		if (parse_address(family, args[i], mask))
703 			i++;
704 	}
705 
706 	BNetworkInterface interface(name);
707 	if (!interface.Exists()) {
708 		// the interface does not exist yet, we have to add it first
709 		BNetworkRoster& roster = BNetworkRoster::Default();
710 
711 		status_t status = roster.AddInterface(interface);
712 		if (status != B_OK) {
713 			fprintf(stderr, "%s: Could not add interface: %s\n", kProgramName,
714 				strerror(status));
715 			exit(1);
716 		}
717 	}
718 
719 	BNetworkAddress broadcast;
720 	BNetworkAddress peer;
721 	int mtu = -1, metric = -1, media = -1;
722 	int addFlags = 0, currentFlags = 0, removeFlags = 0;
723 	bool doAutoConfig = false;
724 
725 	// parse parameters and flags
726 
727 	while (i < argCount) {
728 		if (!strcmp(args[i], "peer")) {
729 			if (!parse_address(family, args[i + 1], peer)) {
730 				fprintf(stderr, "%s: Option 'peer' needs valid address "
731 					"parameter\n", kProgramName);
732 				exit(1);
733 			}
734 			i++;
735 		} else if (!strcmp(args[i], "nm") || !strcmp(args[i], "netmask")) {
736 			if (!mask.IsEmpty()) {
737 				fprintf(stderr, "%s: Netmask or prefix length is specified "
738 					"twice\n", kProgramName);
739 				exit(1);
740 			}
741 			if (!parse_address(family, args[i + 1], mask)) {
742 				fprintf(stderr, "%s: Option 'netmask' needs valid address "
743 					"parameter\n", kProgramName);
744 				exit(1);
745 			}
746 			i++;
747 		} else if (!strcmp(args[i], "prefixlen") || !strcmp(args[i], "plen")
748 			|| !strcmp(args[i], "prefix-length")) {
749 			if (!mask.IsEmpty()) {
750 				fprintf(stderr, "%s: Netmask or prefix length is specified "
751 					"twice\n", kProgramName);
752 				exit(1);
753 			}
754 
755 			// default to AF_INET if no address family has been specified yet
756 			if (family == AF_UNSPEC)
757 				family = AF_INET;
758 
759 			if (!prefix_length_to_mask(family, args[i + 1], mask)) {
760 				fprintf(stderr, "%s: Option 'prefix-length %s' is invalid for "
761 					"this address family\n", kProgramName, args[i + 1]);
762 				exit(1);
763 			}
764 			i++;
765 		} else if (!strcmp(args[i], "bc") || !strcmp(args[i], "broadcast")) {
766 			if (!broadcast.IsEmpty()) {
767 				fprintf(stderr, "%s: broadcast address is specified twice\n",
768 					kProgramName);
769 				exit(1);
770 			}
771 			if (!parse_address(family, args[i + 1], broadcast)) {
772 				fprintf(stderr, "%s: Option 'broadcast' needs valid address "
773 					"parameter\n", kProgramName);
774 				exit(1);
775 			}
776 			addFlags |= IFF_BROADCAST;
777 			i++;
778 		} else if (!strcmp(args[i], "mtu")) {
779 			mtu = args[i + 1] ? strtol(args[i + 1], NULL, 0) : 0;
780 			if (mtu <= 500) {
781 				fprintf(stderr, "%s: Option 'mtu' expected valid max transfer "
782 					"unit size\n", kProgramName);
783 				exit(1);
784 			}
785 			i++;
786 		} else if (!strcmp(args[i], "metric")) {
787 			if (i + 1 >= argCount) {
788 				fprintf(stderr, "%s: Option 'metric' expected parameter\n",
789 					kProgramName);
790 				exit(1);
791 			}
792 			metric = strtol(args[i + 1], NULL, 0);
793 			i++;
794 		} else if (!strcmp(args[i], "media")) {
795 			media = interface.Media();
796 			if (media < 0) {
797 				fprintf(stderr, "%s: Unable to detect media type\n",
798 					kProgramName);
799 				exit(1);
800 			}
801 			if (i + 1 >= argCount) {
802 				fprintf(stderr, "%s: Option 'media' expected parameter\n",
803 					kProgramName);
804 				exit(1);
805 			}
806 			if (!media_parse_subtype(args[i + 1], IFM_TYPE(media), &media)) {
807 				fprintf(stderr, "%s: Invalid parameter for option 'media': "
808 					"'%s'\n", kProgramName, args[i + 1]);
809 				exit(1);
810 			}
811 			i++;
812 		} else if (!strcmp(args[i], "up") || !strcmp(args[i], "-down")) {
813 			addFlags |= IFF_UP;
814 		} else if (!strcmp(args[i], "down") || !strcmp(args[i], "-up")) {
815 			removeFlags |= IFF_UP;
816 		} else if (!strcmp(args[i], "bcast")) {
817 			addFlags |= IFF_BROADCAST;
818 		} else if (!strcmp(args[i], "-bcast")) {
819 			removeFlags |= IFF_BROADCAST;
820 		} else if (!strcmp(args[i], "promisc")) {
821 			addFlags |= IFF_PROMISC;
822 		} else if (!strcmp(args[i], "-promisc")) {
823 			removeFlags |= IFF_PROMISC;
824 		} else if (!strcmp(args[i], "allmulti")) {
825 			addFlags |= IFF_ALLMULTI;
826 		} else if (!strcmp(args[i], "-allmulti")) {
827 			removeFlags |= IFF_ALLMULTI;
828 		} else if (!strcmp(args[i], "loopback")) {
829 			addFlags |= IFF_LOOPBACK;
830 		} else if (!strcmp(args[i], "auto-config")) {
831 			doAutoConfig = true;
832 		} else
833 			usage(1);
834 
835 		i++;
836 	}
837 
838 	if ((addFlags & removeFlags) != 0) {
839 		fprintf(stderr, "%s: Contradicting flags specified\n", kProgramName);
840 		exit(1);
841 	}
842 
843 	if (doAutoConfig && (!address.IsEmpty() || !mask.IsEmpty()
844 			|| !broadcast.IsEmpty() || !peer.IsEmpty())) {
845 		fprintf(stderr, "%s: Contradicting changes specified\n", kProgramName);
846 		exit(1);
847 	}
848 
849 	// set address/mask/broadcast/peer
850 
851 	if (!address.IsEmpty() || !mask.IsEmpty() || !broadcast.IsEmpty()) {
852 		BNetworkInterfaceAddress interfaceAddress;
853 		interfaceAddress.SetAddress(address);
854 		interfaceAddress.SetMask(mask);
855 		if (!broadcast.IsEmpty())
856 			interfaceAddress.SetBroadcast(broadcast);
857 		else if (!peer.IsEmpty())
858 			interfaceAddress.SetDestination(peer);
859 
860 		status_t status = interface.SetAddress(interfaceAddress);
861 		if (status != B_OK) {
862 			fprintf(stderr, "%s: Setting address failed: %s\n", kProgramName,
863 				strerror(status));
864 			exit(1);
865 		}
866 	}
867 
868 	currentFlags = interface.Flags();
869 
870 	// set flags
871 
872 	if (!address.IsEmpty() || !mask.IsEmpty() || !broadcast.IsEmpty()
873 		|| !peer.IsEmpty())
874 		removeFlags = IFF_AUTO_CONFIGURED | IFF_CONFIGURING;
875 
876 	if (addFlags || removeFlags) {
877 		status_t status
878 			= interface.SetFlags((currentFlags & ~removeFlags) | addFlags);
879 		if (status != B_OK) {
880 			fprintf(stderr, "%s: Setting flags failed: %s\n", kProgramName,
881 				strerror(status));
882 		}
883 	}
884 
885 	// set options
886 
887 	if (mtu != -1) {
888 		status_t status = interface.SetMTU(mtu);
889 		if (status != B_OK) {
890 			fprintf(stderr, "%s: Setting MTU failed: %s\n", kProgramName,
891 				strerror(status));
892 		}
893 	}
894 
895 	if (metric != -1) {
896 		status_t status = interface.SetMetric(metric);
897 		if (status != B_OK) {
898 			fprintf(stderr, "%s: Setting metric failed: %s\n", kProgramName,
899 				strerror(status));
900 		}
901 	}
902 
903 	if (media != -1) {
904 		status_t status = interface.SetMedia(media);
905 		if (status != B_OK) {
906 			fprintf(stderr, "%s: Setting media failed: %s\n", kProgramName,
907 				strerror(status));
908 		}
909 	}
910 
911 	// start auto configuration, if asked for
912 
913 	if (doAutoConfig) {
914 		status_t status = interface.AutoConfigure(family);
915 		if (status == B_BAD_PORT_ID) {
916 			fprintf(stderr, "%s: The net_server needs to run for the auto "
917 				"configuration!\n", kProgramName);
918 		} else if (status != B_OK) {
919 			fprintf(stderr, "%s: Auto-configuring failed: %s\n", kProgramName,
920 				strerror(status));
921 		}
922 	}
923 }
924 
925 
926 //	#pragma mark -
927 
928 
929 int
930 main(int argc, char** argv)
931 {
932 	if (argc > 1 && (!strcmp(argv[1], "--help") || !strcmp(argv[1], "-h")))
933 		usage(0);
934 
935 	int socket = ::socket(AF_LINK, SOCK_DGRAM, 0);
936 	if (socket < 0) {
937 		fprintf(stderr, "%s: The networking stack doesn't seem to be "
938 			"available.\n", kProgramName);
939 		return 1;
940 	}
941 	close(socket);
942 
943 	if (argc > 1
944 		&& (!strcmp(argv[1], "--delete")
945 			|| !strcmp(argv[1], "--del")
946 			|| !strcmp(argv[1], "-d")
947 			|| !strcmp(argv[1], "del")
948 			|| !strcmp(argv[1], "delete"))) {
949 		// Delete interface (addresses)
950 
951 		if (argc < 3)
952 			usage(1);
953 
954 		const char* name = argv[2];
955 		delete_interface(name, argv + 3, argc - 3);
956 		return 0;
957 	}
958 
959 	if (argc > 1 && !strcmp(argv[1], "-a")) {
960 		// Accept an optional "-a" option to list all interfaces for those
961 		// that are used to it from other platforms.
962 
963 		if (argc > 2)
964 			usage(1);
965 
966 		list_interfaces(NULL);
967 		return 0;
968 	}
969 
970 	const char* name = argv[1];
971 	if (argc > 2) {
972 		if (configure_wireless(name, argv + 2, argc - 2))
973 			return 0;
974 
975 		// Add or configure an interface
976 
977 		configure_interface(name, argv + 2, argc - 2);
978 		return 0;
979 	}
980 
981 	// list interfaces
982 
983 	list_interfaces(name);
984 	return 0;
985 }
986