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