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