xref: /haiku/src/bin/network/ifconfig/ifconfig.cpp (revision 8b33ac6bff6933d2477a84cdc9d01598c61ffe84)
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 				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
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
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, %Ld 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, %Ld 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
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
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
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 	// try to parse address
701 
702 	BNetworkAddress address;
703 	BNetworkAddress mask;
704 
705 	if (parse_address(family, args[i], address)) {
706 		i++;
707 
708 		if (parse_address(family, args[i], mask))
709 			i++;
710 	}
711 
712 	BNetworkInterface interface(name);
713 	if (!interface.Exists()) {
714 		// the interface does not exist yet, we have to add it first
715 		BNetworkRoster& roster = BNetworkRoster::Default();
716 
717 		status_t status = roster.AddInterface(interface);
718 		if (status != B_OK) {
719 			fprintf(stderr, "%s: Could not add interface: %s\n", kProgramName,
720 				strerror(status));
721 			exit(1);
722 		}
723 	}
724 
725 	BNetworkAddress broadcast;
726 	BNetworkAddress peer;
727 	int mtu = -1, metric = -1, media = -1;
728 	int addFlags = 0, currentFlags = 0, removeFlags = 0;
729 	bool doAutoConfig = false;
730 
731 	// parse parameters and flags
732 
733 	while (i < argCount) {
734 		if (!strcmp(args[i], "peer")) {
735 			if (!parse_address(family, args[i + 1], peer)) {
736 				fprintf(stderr, "%s: Option 'peer' needs valid address "
737 					"parameter\n", kProgramName);
738 				exit(1);
739 			}
740 			i++;
741 		} else if (!strcmp(args[i], "nm") || !strcmp(args[i], "netmask")) {
742 			if (!mask.IsEmpty()) {
743 				fprintf(stderr, "%s: Netmask or prefix length is specified "
744 					"twice\n", kProgramName);
745 				exit(1);
746 			}
747 			if (!parse_address(family, args[i + 1], mask)) {
748 				fprintf(stderr, "%s: Option 'netmask' needs valid address "
749 					"parameter\n", kProgramName);
750 				exit(1);
751 			}
752 			i++;
753 		} else if (!strcmp(args[i], "prefixlen") || !strcmp(args[i], "plen")
754 			|| !strcmp(args[i], "prefix-length")) {
755 			if (!mask.IsEmpty()) {
756 				fprintf(stderr, "%s: Netmask or prefix length is specified "
757 					"twice\n", kProgramName);
758 				exit(1);
759 			}
760 
761 			// default to AF_INET if no address family has been specified yet
762 			if (family == AF_UNSPEC)
763 				family = AF_INET;
764 
765 			if (!prefix_length_to_mask(family, args[i + 1], mask)) {
766 				fprintf(stderr, "%s: Option 'prefix-length %s' is invalid for "
767 					"this address family\n", kProgramName, args[i + 1]);
768 				exit(1);
769 			}
770 			i++;
771 		} else if (!strcmp(args[i], "bc") || !strcmp(args[i], "broadcast")) {
772 			if (!broadcast.IsEmpty()) {
773 				fprintf(stderr, "%s: broadcast address is specified twice\n",
774 					kProgramName);
775 				exit(1);
776 			}
777 			if (!parse_address(family, args[i + 1], broadcast)) {
778 				fprintf(stderr, "%s: Option 'broadcast' needs valid address "
779 					"parameter\n", kProgramName);
780 				exit(1);
781 			}
782 			addFlags |= IFF_BROADCAST;
783 			i++;
784 		} else if (!strcmp(args[i], "mtu")) {
785 			mtu = args[i + 1] ? strtol(args[i + 1], NULL, 0) : 0;
786 			if (mtu <= 500) {
787 				fprintf(stderr, "%s: Option 'mtu' expected valid max transfer "
788 					"unit size\n", kProgramName);
789 				exit(1);
790 			}
791 			i++;
792 		} else if (!strcmp(args[i], "metric")) {
793 			if (i + 1 >= argCount) {
794 				fprintf(stderr, "%s: Option 'metric' expected parameter\n",
795 					kProgramName);
796 				exit(1);
797 			}
798 			metric = strtol(args[i + 1], NULL, 0);
799 			i++;
800 		} else if (!strcmp(args[i], "media")) {
801 			media = interface.Media();
802 			if (media < 0) {
803 				fprintf(stderr, "%s: Unable to detect media type\n",
804 					kProgramName);
805 				exit(1);
806 			}
807 			if (i + 1 >= argCount) {
808 				fprintf(stderr, "%s: Option 'media' expected parameter\n",
809 					kProgramName);
810 				exit(1);
811 			}
812 			if (!media_parse_subtype(args[i + 1], IFM_TYPE(media), &media)) {
813 				fprintf(stderr, "%s: Invalid parameter for option 'media': "
814 					"'%s'\n", kProgramName, args[i + 1]);
815 				exit(1);
816 			}
817 			i++;
818 		} else if (!strcmp(args[i], "up") || !strcmp(args[i], "-down")) {
819 			addFlags |= IFF_UP;
820 		} else if (!strcmp(args[i], "down") || !strcmp(args[i], "-up")) {
821 			removeFlags |= IFF_UP;
822 		} else if (!strcmp(args[i], "bcast")) {
823 			addFlags |= IFF_BROADCAST;
824 		} else if (!strcmp(args[i], "-bcast")) {
825 			removeFlags |= IFF_BROADCAST;
826 		} else if (!strcmp(args[i], "promisc")) {
827 			addFlags |= IFF_PROMISC;
828 		} else if (!strcmp(args[i], "-promisc")) {
829 			removeFlags |= IFF_PROMISC;
830 		} else if (!strcmp(args[i], "allmulti")) {
831 			addFlags |= IFF_ALLMULTI;
832 		} else if (!strcmp(args[i], "-allmulti")) {
833 			removeFlags |= IFF_ALLMULTI;
834 		} else if (!strcmp(args[i], "loopback")) {
835 			addFlags |= IFF_LOOPBACK;
836 		} else if (!strcmp(args[i], "auto-config")) {
837 			doAutoConfig = true;
838 		} else
839 			usage(1);
840 
841 		i++;
842 	}
843 
844 	if ((addFlags & removeFlags) != 0) {
845 		fprintf(stderr, "%s: Contradicting flags specified\n", kProgramName);
846 		exit(1);
847 	}
848 
849 	if (doAutoConfig && (!address.IsEmpty() || !mask.IsEmpty()
850 			|| !broadcast.IsEmpty() || !peer.IsEmpty())) {
851 		fprintf(stderr, "%s: Contradicting changes specified\n", kProgramName);
852 		exit(1);
853 	}
854 
855 	// set address/mask/broadcast/peer
856 
857 	if (!address.IsEmpty() || !mask.IsEmpty() || !broadcast.IsEmpty()) {
858 		BNetworkInterfaceAddress interfaceAddress;
859 		interfaceAddress.SetAddress(address);
860 		interfaceAddress.SetMask(mask);
861 		if (!broadcast.IsEmpty())
862 			interfaceAddress.SetBroadcast(broadcast);
863 		else if (!peer.IsEmpty())
864 			interfaceAddress.SetDestination(peer);
865 
866 		status_t status = interface.SetAddress(interfaceAddress);
867 		if (status != B_OK) {
868 			fprintf(stderr, "%s: Setting address failed: %s\n", kProgramName,
869 				strerror(status));
870 			exit(1);
871 		}
872 	}
873 
874 	currentFlags = interface.Flags();
875 
876 	// set flags
877 
878 	if (!address.IsEmpty() || !mask.IsEmpty() || !broadcast.IsEmpty()
879 		|| !peer.IsEmpty())
880 		removeFlags = IFF_AUTO_CONFIGURED | IFF_CONFIGURING;
881 
882 	if (addFlags || removeFlags) {
883 		status_t status
884 			= interface.SetFlags((currentFlags & ~removeFlags) | addFlags);
885 		if (status != B_OK) {
886 			fprintf(stderr, "%s: Setting flags failed: %s\n", kProgramName,
887 				strerror(status));
888 		}
889 	}
890 
891 	// set options
892 
893 	if (mtu != -1) {
894 		status_t status = interface.SetMTU(mtu);
895 		if (status != B_OK) {
896 			fprintf(stderr, "%s: Setting MTU failed: %s\n", kProgramName,
897 				strerror(status));
898 		}
899 	}
900 
901 	if (metric != -1) {
902 		status_t status = interface.SetMetric(metric);
903 		if (status != B_OK) {
904 			fprintf(stderr, "%s: Setting metric failed: %s\n", kProgramName,
905 				strerror(status));
906 		}
907 	}
908 
909 	if (media != -1) {
910 		status_t status = interface.SetMedia(media);
911 		if (status != B_OK) {
912 			fprintf(stderr, "%s: Setting media failed: %s\n", kProgramName,
913 				strerror(status));
914 		}
915 	}
916 
917 	// start auto configuration, if asked for
918 
919 	if (doAutoConfig) {
920 		status_t status = interface.AutoConfigure(family);
921 		if (status == B_BAD_PORT_ID) {
922 			fprintf(stderr, "%s: The net_server needs to run for the auto "
923 				"configuration!\n", kProgramName);
924 		} else if (status != B_OK) {
925 			fprintf(stderr, "%s: Auto-configuring failed: %s\n", kProgramName,
926 				strerror(status));
927 		}
928 	}
929 }
930 
931 
932 //	#pragma mark -
933 
934 
935 int
936 main(int argc, char** argv)
937 {
938 	if (argc > 1 && (!strcmp(argv[1], "--help") || !strcmp(argv[1], "-h")))
939 		usage(0);
940 
941 	int socket = ::socket(AF_LINK, SOCK_DGRAM, 0);
942 	if (socket < 0) {
943 		fprintf(stderr, "%s: The networking stack doesn't seem to be "
944 			"available.\n", kProgramName);
945 		return 1;
946 	}
947 	close(socket);
948 
949 	if (argc > 1
950 		&& (!strcmp(argv[1], "--delete")
951 			|| !strcmp(argv[1], "--del")
952 			|| !strcmp(argv[1], "-d")
953 			|| !strcmp(argv[1], "del")
954 			|| !strcmp(argv[1], "delete"))) {
955 		// Delete interface (addresses)
956 
957 		if (argc < 3)
958 			usage(1);
959 
960 		const char* name = argv[2];
961 		delete_interface(name, argv + 3, argc - 3);
962 		return 0;
963 	}
964 
965 	if (argc > 1 && !strcmp(argv[1], "-a")) {
966 		// Accept an optional "-a" option to list all interfaces for those
967 		// that are used to it from other platforms.
968 
969 		if (argc > 2)
970 			usage(1);
971 
972 		list_interfaces(NULL);
973 		return 0;
974 	}
975 
976 	const char* name = argv[1];
977 	if (argc > 2) {
978 		if (configure_wireless(name, argv + 2, argc - 2))
979 			return 0;
980 
981 		// Add or configure an interface
982 
983 		configure_interface(name, argv + 2, argc - 2);
984 		return 0;
985 	}
986 
987 	// list interfaces
988 
989 	list_interfaces(name);
990 	return 0;
991 }
992