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