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