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