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