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
29extern "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
38extern const char* __progname;
39const char* kProgramName = __progname;
40
41
42enum preferred_output_format {
43	PREFER_OUTPUT_MASK,
44	PREFER_OUTPUT_PREFIX_LENGTH,
45};
46
47
48struct address_family {
49	int			family;
50	const char*	name;
51	const char*	identifiers[4];
52	preferred_output_format	preferred_format;
53};
54
55
56static 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
73static void
74usage(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
111int
112get_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
127static const address_family*
128address_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*/
144bool
145parse_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
176bool
177prefix_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
188BString
189to_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
201const char*
202get_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
225const char*
226get_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
243const char*
244get_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
262void
263show_wireless_network_header(bool verbose)
264{
265	printf("%-32s %-20s %s  %s\n", "name", "address", "signal", "auth");
266}
267
268
269void
270show_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
279bool
280configure_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
460void
461list_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
492bool
493list_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
627void
628list_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*/
653void
654delete_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
690void
691configure_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
945int
946main(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