15adca30aSAxel Dörfler/*
254c34be7SAxel Dörfler * Copyright 2006-2015, Haiku, Inc. All Rights Reserved.
35adca30aSAxel Dörfler * Distributed under the terms of the MIT License.
45adca30aSAxel Dörfler *
55adca30aSAxel Dörfler * Authors:
65adca30aSAxel Dörfler *		Axel D��rfler, axeld@pinc-software.de
75adca30aSAxel Dörfler *		Oliver Tappe, zooey@hirschkaefer.de
8cc2a443dSAxel Dörfler *		Atis Elsts, the.kfx@gmail.com
95adca30aSAxel Dörfler */
105adca30aSAxel Dörfler
115adca30aSAxel Dörfler
1297dfb56dSAxel Dörfler#include <errno.h>
136d60dde7SAxel Dörfler#include <net/if_media.h>
145adca30aSAxel Dörfler#include <net/if_types.h>
155adca30aSAxel Dörfler#include <stdio.h>
165adca30aSAxel Dörfler#include <stdlib.h>
175adca30aSAxel Dörfler#include <string.h>
184fab1ac6SJulian Harnath#include <sys/sockio.h>
195adca30aSAxel Dörfler#include <unistd.h>
205adca30aSAxel Dörfler
21b2a400e5SAxel Dörfler#include <Message.h>
22b2a400e5SAxel Dörfler#include <Messenger.h>
23cd8dbcdcSAxel Dörfler#include <NetworkDevice.h>
24b2a400e5SAxel Dörfler#include <NetworkInterface.h>
25b2a400e5SAxel Dörfler#include <NetworkRoster.h>
26b2a400e5SAxel Dörfler
27fd95a7e1SAxel Dörfler#include <NetServer.h>
28fd95a7e1SAxel Dörfler
294fab1ac6SJulian Harnathextern "C" {
30dba28784SAugustin Cavalier#	include <freebsd_network/compat/sys/cdefs.h>
31dba28784SAugustin Cavalier#	include <freebsd_network/compat/sys/ioccom.h>
324fab1ac6SJulian Harnath#	include <net80211/ieee80211_ioctl.h>
334fab1ac6SJulian Harnath}
344fab1ac6SJulian Harnath
3554c34be7SAxel Dörfler#include "MediaTypes.h"
3654c34be7SAxel Dörfler
375adca30aSAxel Dörfler
385adca30aSAxel Dörflerextern const char* __progname;
395adca30aSAxel Dörflerconst char* kProgramName = __progname;
405adca30aSAxel Dörfler
415adca30aSAxel Dörfler
42cc2a443dSAxel Dörflerenum preferred_output_format {
43cc2a443dSAxel Dörfler	PREFER_OUTPUT_MASK,
44cc2a443dSAxel Dörfler	PREFER_OUTPUT_PREFIX_LENGTH,
45cc2a443dSAxel Dörfler};
46cc2a443dSAxel Dörfler
4754c34be7SAxel Dörfler
485adca30aSAxel Dörflerstruct address_family {
495adca30aSAxel Dörfler	int			family;
505adca30aSAxel Dörfler	const char*	name;
515adca30aSAxel Dörfler	const char*	identifiers[4];
52cc2a443dSAxel Dörfler	preferred_output_format	preferred_format;
535adca30aSAxel Dörfler};
545adca30aSAxel Dörfler
5576ec752fSFrançois Revol
5697dfb56dSAxel Dörflerstatic const address_family kFamilies[] = {
5797dfb56dSAxel Dörfler	{
5897dfb56dSAxel Dörfler		AF_INET,
5997dfb56dSAxel Dörfler		"inet",
6097dfb56dSAxel Dörfler		{"AF_INET", "inet", "ipv4", NULL},
6197dfb56dSAxel Dörfler		PREFER_OUTPUT_MASK
6297dfb56dSAxel Dörfler	},
6397dfb56dSAxel Dörfler	{
6497dfb56dSAxel Dörfler		AF_INET6,
6597dfb56dSAxel Dörfler		"inet6",
6697dfb56dSAxel Dörfler		{"AF_INET6", "inet6", "ipv6", NULL},
6797dfb56dSAxel Dörfler		PREFER_OUTPUT_PREFIX_LENGTH
6897dfb56dSAxel Dörfler	},
6997dfb56dSAxel Dörfler	{ -1, NULL, {NULL}, PREFER_OUTPUT_MASK }
7097dfb56dSAxel Dörfler};
7197dfb56dSAxel Dörfler
7276ec752fSFrançois Revol
7397dfb56dSAxel Dörflerstatic void
745adca30aSAxel Dörflerusage(int status)
755adca30aSAxel Dörfler{
76fd95a7e1SAxel Dörfler	printf("usage: %s [<interface> [<address family>] [<address> [<mask>] | "
77fd95a7e1SAxel Dörfler			"auto-config] [<option/flags>...]]\n"
78cd8dbcdcSAxel Dörfler		"       %s --delete <interface> [...]\n"
79cd8dbcdcSAxel Dörfler		"       %s <interface> [scan|join|leave] [<network> "
80cd8dbcdcSAxel Dörfler			"[<password>]]\n\n"
815adca30aSAxel Dörfler		"Where <option> can be the following:\n"
82cc2a443dSAxel Dörfler		"  netmask <addr>     - networking subnet mask\n"
83cc2a443dSAxel Dörfler		"  prefixlen <number> - subnet mask length in bits\n"
84cc2a443dSAxel Dörfler		"  broadcast <addr>   - set broadcast address\n"
85cc2a443dSAxel Dörfler		"  peer <addr>        - ppp-peer address\n"
86cc2a443dSAxel Dörfler		"  mtu <bytes>        - maximal transfer unit\n"
87cc2a443dSAxel Dörfler		"  metric <number>    - metric number to use (defaults to 0)\n"
88cc2a443dSAxel Dörfler		"  media <media>      - media type to use (defaults to auto)\n",
89cd8dbcdcSAxel Dörfler		kProgramName, kProgramName, kProgramName);
90cd8dbcdcSAxel Dörfler
9154c34be7SAxel Dörfler	for (int32 i = 0; const char* type = get_media_type_name(i); i++) {
9254c34be7SAxel Dörfler		printf("For %s <media> can be one of: ", type);
9354c34be7SAxel Dörfler		for (int32 j = 0; const char* subType = get_media_subtype_name(i, j);
9454c34be7SAxel Dörfler				j++) {
9554c34be7SAxel Dörfler			printf("%s ", subType);
9654c34be7SAxel Dörfler		}
9776ec752fSFrançois Revol		printf("\n");
9876ec752fSFrançois Revol	}
99fd95a7e1SAxel Dörfler	printf("And <flags> can be: up, down, [-]promisc, [-]allmulti, [-]bcast, "
1004fab1ac6SJulian Harnath			"[-]ht, loopback\n"
101fd95a7e1SAxel Dörfler		"If you specify \"auto-config\" instead of an address, it will be "
102fd95a7e1SAxel Dörfler			"configured automatically.\n\n"
1035adca30aSAxel Dörfler		"Example:\n"
1045adca30aSAxel Dörfler		"\t%s loop 127.0.0.1 255.0.0.0 up\n",
10576ec752fSFrançois Revol		kProgramName);
1065adca30aSAxel Dörfler
1075adca30aSAxel Dörfler	exit(status);
1085adca30aSAxel Dörfler}
1095adca30aSAxel Dörfler
1105adca30aSAxel Dörfler
11101308f21SAxel Dörflerint
11201308f21SAxel Dörflerget_address_family(const char* argument)
1135adca30aSAxel Dörfler{
1145adca30aSAxel Dörfler	for (int32 i = 0; kFamilies[i].family >= 0; i++) {
1155adca30aSAxel Dörfler		for (int32 j = 0; kFamilies[i].identifiers[j]; j++) {
1165adca30aSAxel Dörfler			if (!strcmp(argument, kFamilies[i].identifiers[j])) {
1175adca30aSAxel Dörfler				// found a match
11801308f21SAxel Dörfler				return kFamilies[i].family;
1195adca30aSAxel Dörfler			}
1205adca30aSAxel Dörfler		}
1215adca30aSAxel Dörfler	}
1225adca30aSAxel Dörfler
12301308f21SAxel Dörfler	return AF_UNSPEC;
1245adca30aSAxel Dörfler}
1255adca30aSAxel Dörfler
1265adca30aSAxel Dörfler
12797dfb56dSAxel Dörflerstatic const address_family*
12897dfb56dSAxel Dörfleraddress_family_for(int family)
129b2a400e5SAxel Dörfler{
130b2a400e5SAxel Dörfler	for (int32 i = 0; kFamilies[i].family >= 0; i++) {
131b2a400e5SAxel Dörfler		if (kFamilies[i].family == family)
132b2a400e5SAxel Dörfler			return &kFamilies[i];
133b2a400e5SAxel Dörfler	}
134b2a400e5SAxel Dörfler
135b2a400e5SAxel Dörfler	// defaults to AF_INET
136b2a400e5SAxel Dörfler	return &kFamilies[0];
137b2a400e5SAxel Dörfler}
138b2a400e5SAxel Dörfler
139b2a400e5SAxel Dörfler
14097dfb56dSAxel Dörfler/*!	Parses the \a argument as network \a address for the specified \a family.
14197dfb56dSAxel Dörfler	If \a family is \c AF_UNSPEC, \a family will be overwritten with the family
14297dfb56dSAxel Dörfler	of the successfully parsed address.
14397dfb56dSAxel Dörfler*/
1445adca30aSAxel Dörflerbool
14597dfb56dSAxel Dörflerparse_address(int& family, const char* argument, BNetworkAddress& address)
1465adca30aSAxel Dörfler{
1475adca30aSAxel Dörfler	if (argument == NULL)
1485adca30aSAxel Dörfler		return false;
1495adca30aSAxel Dörfler
15097dfb56dSAxel Dörfler	status_t status = address.SetTo(family, argument, (uint16)0,
15197dfb56dSAxel Dörfler		B_NO_ADDRESS_RESOLUTION);
15297dfb56dSAxel Dörfler	if (status != B_OK)
15397dfb56dSAxel Dörfler		return false;
15497dfb56dSAxel Dörfler
15597dfb56dSAxel Dörfler	if (family == AF_UNSPEC) {
15697dfb56dSAxel Dörfler		// Test if we support the resulting address family
15797dfb56dSAxel Dörfler		bool supported = false;
15801308f21SAxel Dörfler
15997dfb56dSAxel Dörfler		for (int32 i = 0; kFamilies[i].family >= 0; i++) {
16097dfb56dSAxel Dörfler			if (kFamilies[i].family == address.Family()) {
16197dfb56dSAxel Dörfler				supported = true;
16297dfb56dSAxel Dörfler				break;
16397dfb56dSAxel Dörfler			}
16497dfb56dSAxel Dörfler		}
16597dfb56dSAxel Dörfler		if (!supported)
16697dfb56dSAxel Dörfler			return false;
16797dfb56dSAxel Dörfler
16897dfb56dSAxel Dörfler		// Take over family from address
16997dfb56dSAxel Dörfler		family = address.Family();
17097dfb56dSAxel Dörfler	}
17197dfb56dSAxel Dörfler
17297dfb56dSAxel Dörfler	return true;
1735adca30aSAxel Dörfler}
1745adca30aSAxel Dörfler
1755adca30aSAxel Dörfler
176cc2a443dSAxel Dörflerbool
17797dfb56dSAxel Dörflerprefix_length_to_mask(int family, const char* argument, BNetworkAddress& mask)
178cc2a443dSAxel Dörfler{
179cc2a443dSAxel Dörfler	char *end;
180cc2a443dSAxel Dörfler	uint32 prefixLength = strtoul(argument, &end, 10);
181cc2a443dSAxel Dörfler	if (end == argument)
182cc2a443dSAxel Dörfler		return false;
183cc2a443dSAxel Dörfler
18497dfb56dSAxel Dörfler	return mask.SetToMask(family, prefixLength) == B_OK;
185cc2a443dSAxel Dörfler}
186cc2a443dSAxel Dörfler
187cc2a443dSAxel Dörfler
18820ead9a8SAxel DörflerBString
18920ead9a8SAxel Dörflerto_string(const BNetworkAddress& address)
19020ead9a8SAxel Dörfler{
19120ead9a8SAxel Dörfler	if (address.IsEmpty())
19220ead9a8SAxel Dörfler		return "--";
19320ead9a8SAxel Dörfler
19420ead9a8SAxel Dörfler	return address.ToString();
19520ead9a8SAxel Dörfler}
19620ead9a8SAxel Dörfler
19720ead9a8SAxel Dörfler
198cd8dbcdcSAxel Dörfler//	#pragma mark - wireless support
199cd8dbcdcSAxel Dörfler
200cd8dbcdcSAxel Dörfler
201cd8dbcdcSAxel Dörflerconst char*
202cd8dbcdcSAxel Dörflerget_key_mode(uint32 mode)
203cd8dbcdcSAxel Dörfler{
204cd8dbcdcSAxel Dörfler	if ((mode & B_KEY_MODE_WPS) != 0)
205cd8dbcdcSAxel Dörfler		return "WPS";
206cd8dbcdcSAxel Dörfler	if ((mode & B_KEY_MODE_PSK_SHA256) != 0)
207cd8dbcdcSAxel Dörfler		return "PSK-SHA256";
208cd8dbcdcSAxel Dörfler	if ((mode & B_KEY_MODE_IEEE802_1X_SHA256) != 0)
209cd8dbcdcSAxel Dörfler		return "IEEE 802.1x-SHA256";
210cd8dbcdcSAxel Dörfler	if ((mode & B_KEY_MODE_FT_PSK) != 0)
211cd8dbcdcSAxel Dörfler		return "FT-PSK";
212cd8dbcdcSAxel Dörfler	if ((mode & B_KEY_MODE_FT_IEEE802_1X) != 0)
213cd8dbcdcSAxel Dörfler		return "FT-IEEE 802.1x";
214cd8dbcdcSAxel Dörfler	if ((mode & B_KEY_MODE_NONE) != 0)
215cd8dbcdcSAxel Dörfler		return "-";
216cd8dbcdcSAxel Dörfler	if ((mode & B_KEY_MODE_PSK) != 0)
217cd8dbcdcSAxel Dörfler		return "PSK";
218cd8dbcdcSAxel Dörfler	if ((mode & B_KEY_MODE_IEEE802_1X) != 0)
219cd8dbcdcSAxel Dörfler		return "IEEE 802.1x";
220cd8dbcdcSAxel Dörfler
221cd8dbcdcSAxel Dörfler	return "";
222cd8dbcdcSAxel Dörfler}
223cd8dbcdcSAxel Dörfler
224cd8dbcdcSAxel Dörfler
225cd8dbcdcSAxel Dörflerconst char*
226cd8dbcdcSAxel Dörflerget_cipher(uint32 cipher)
227cd8dbcdcSAxel Dörfler{
228cd8dbcdcSAxel Dörfler	if ((cipher & B_NETWORK_CIPHER_AES_128_CMAC) != 0)
229cd8dbcdcSAxel Dörfler		return "AES-128-CMAC";
230cd8dbcdcSAxel Dörfler	if ((cipher & B_NETWORK_CIPHER_CCMP) != 0)
231cd8dbcdcSAxel Dörfler		return "CCMP";
232cd8dbcdcSAxel Dörfler	if ((cipher & B_NETWORK_CIPHER_TKIP) != 0)
233cd8dbcdcSAxel Dörfler		return "TKIP";
234cd8dbcdcSAxel Dörfler	if ((cipher & B_NETWORK_CIPHER_WEP_104) != 0)
235cd8dbcdcSAxel Dörfler		return "WEP-104";
236cd8dbcdcSAxel Dörfler	if ((cipher & B_NETWORK_CIPHER_WEP_40) != 0)
237cd8dbcdcSAxel Dörfler		return "WEP-40";
238cd8dbcdcSAxel Dörfler
239cd8dbcdcSAxel Dörfler	return "";
240cd8dbcdcSAxel Dörfler}
241cd8dbcdcSAxel Dörfler
242cd8dbcdcSAxel Dörfler
243cd8dbcdcSAxel Dörflerconst char*
244cd8dbcdcSAxel Dörflerget_authentication_mode(uint32 mode, uint32 flags)
245cd8dbcdcSAxel Dörfler{
246cd8dbcdcSAxel Dörfler	switch (mode) {
247cd8dbcdcSAxel Dörfler		default:
248cd8dbcdcSAxel Dörfler		case B_NETWORK_AUTHENTICATION_NONE:
249cd8dbcdcSAxel Dörfler			if ((flags & B_NETWORK_IS_ENCRYPTED) != 0)
250cd8dbcdcSAxel Dörfler				return "(encrypted)";
251cd8dbcdcSAxel Dörfler			return "-";
252cd8dbcdcSAxel Dörfler		case B_NETWORK_AUTHENTICATION_WEP:
253cd8dbcdcSAxel Dörfler			return "WEP";
254cd8dbcdcSAxel Dörfler		case B_NETWORK_AUTHENTICATION_WPA:
255cd8dbcdcSAxel Dörfler			return "WPA";
256cd8dbcdcSAxel Dörfler		case B_NETWORK_AUTHENTICATION_WPA2:
257cd8dbcdcSAxel Dörfler			return "WPA2";
258cd8dbcdcSAxel Dörfler	}
259cd8dbcdcSAxel Dörfler}
260cd8dbcdcSAxel Dörfler
261cd8dbcdcSAxel Dörfler
262cd8dbcdcSAxel Dörflervoid
263cd8dbcdcSAxel Dörflershow_wireless_network_header(bool verbose)
264cd8dbcdcSAxel Dörfler{
265cd8dbcdcSAxel Dörfler	printf("%-32s %-20s %s  %s\n", "name", "address", "signal", "auth");
266cd8dbcdcSAxel Dörfler}
267cd8dbcdcSAxel Dörfler
268cd8dbcdcSAxel Dörfler
269cd8dbcdcSAxel Dörflervoid
270cd8dbcdcSAxel Dörflershow_wireless_network(const wireless_network& network, bool verbose)
271cd8dbcdcSAxel Dörfler{
272cd8dbcdcSAxel Dörfler	printf("%-32s %-20s %6u  %s\n", network.name,
273cd8dbcdcSAxel Dörfler		network.address.ToString().String(),
274cd8dbcdcSAxel Dörfler		network.signal_strength / 2,
275cd8dbcdcSAxel Dörfler		get_authentication_mode(network.authentication_mode, network.flags));
276cd8dbcdcSAxel Dörfler}
277cd8dbcdcSAxel Dörfler
278cd8dbcdcSAxel Dörfler
279cd8dbcdcSAxel Dörflerbool
280cd8dbcdcSAxel Dörflerconfigure_wireless(const char* name, char* const* args, int32 argCount)
281cd8dbcdcSAxel Dörfler{
282cd8dbcdcSAxel Dörfler	enum {
283cd8dbcdcSAxel Dörfler		NONE,
28445bc01d2SAugustin Cavalier		SCAN,
285cd8dbcdcSAxel Dörfler		LIST,
286cd8dbcdcSAxel Dörfler		JOIN,
2874fab1ac6SJulian Harnath		LEAVE,
2884fab1ac6SJulian Harnath		CONTROL
289cd8dbcdcSAxel Dörfler	} mode = NONE;
290cd8dbcdcSAxel Dörfler
2914fab1ac6SJulian Harnath	int controlOption = -1;
2924fab1ac6SJulian Harnath	int controlValue = -1;
2934fab1ac6SJulian Harnath
29445bc01d2SAugustin Cavalier	if (!strcmp(args[0], "scan"))
29545bc01d2SAugustin Cavalier		mode = SCAN;
29645bc01d2SAugustin Cavalier	else if (!strcmp(args[0], "list"))
297cd8dbcdcSAxel Dörfler		mode = LIST;
298cd8dbcdcSAxel Dörfler	else if (!strcmp(args[0], "join"))
299cd8dbcdcSAxel Dörfler		mode = JOIN;
300cd8dbcdcSAxel Dörfler	else if (!strcmp(args[0], "leave"))
301cd8dbcdcSAxel Dörfler		mode = LEAVE;
3024fab1ac6SJulian Harnath	else if (!strcmp(args[0], "ht")) {
3034fab1ac6SJulian Harnath		mode = CONTROL;
3044fab1ac6SJulian Harnath		controlOption = IEEE80211_IOC_HTCONF;
3054fab1ac6SJulian Harnath		controlValue = 3;
3064fab1ac6SJulian Harnath	} else if (!strcmp(args[0], "-ht")) {
3074fab1ac6SJulian Harnath		mode = CONTROL;
3084fab1ac6SJulian Harnath		controlOption = IEEE80211_IOC_HTCONF;
3094fab1ac6SJulian Harnath		controlValue = 0;
3104fab1ac6SJulian Harnath	}
311cd8dbcdcSAxel Dörfler
312cd8dbcdcSAxel Dörfler	if (mode == NONE)
313cd8dbcdcSAxel Dörfler		return false;
314cd8dbcdcSAxel Dörfler
315cd8dbcdcSAxel Dörfler	BNetworkDevice device(name);
316cd8dbcdcSAxel Dörfler	if (!device.Exists()) {
317cd8dbcdcSAxel Dörfler		fprintf(stderr, "%s: \"%s\" does not exist!\n", kProgramName, name);
318cd8dbcdcSAxel Dörfler		exit(1);
319cd8dbcdcSAxel Dörfler	}
320cd8dbcdcSAxel Dörfler	if (!device.IsWireless()) {
321cd8dbcdcSAxel Dörfler		fprintf(stderr, "%s: \"%s\" is not a WLAN device!\n", kProgramName,
322cd8dbcdcSAxel Dörfler			name);
323cd8dbcdcSAxel Dörfler		exit(1);
324cd8dbcdcSAxel Dörfler	}
325cd8dbcdcSAxel Dörfler
326cd8dbcdcSAxel Dörfler	args++;
327cd8dbcdcSAxel Dörfler	argCount--;
328cd8dbcdcSAxel Dörfler
329cd8dbcdcSAxel Dörfler	switch (mode) {
33045bc01d2SAugustin Cavalier		case SCAN:
33145bc01d2SAugustin Cavalier		{
33245bc01d2SAugustin Cavalier			status_t status = device.Scan(true, true);
33345bc01d2SAugustin Cavalier			if (status != B_OK) {
33445bc01d2SAugustin Cavalier				fprintf(stderr, "%s: Scan on \"%s\" failed: %s\n", kProgramName,
33545bc01d2SAugustin Cavalier					name, strerror(status));
33645bc01d2SAugustin Cavalier				exit(1);
33745bc01d2SAugustin Cavalier			}
33845bc01d2SAugustin Cavalier			// fall through
33945bc01d2SAugustin Cavalier		}
340cd8dbcdcSAxel Dörfler		case LIST:
341cd8dbcdcSAxel Dörfler		{
342cd8dbcdcSAxel Dörfler			// list wireless network(s)
343cd8dbcdcSAxel Dörfler
344cd8dbcdcSAxel Dörfler			bool verbose = false;
345cd8dbcdcSAxel Dörfler			if (argCount > 0 && !strcmp(args[0], "-v")) {
346cd8dbcdcSAxel Dörfler				verbose = true;
347cd8dbcdcSAxel Dörfler				args++;
348cd8dbcdcSAxel Dörfler				argCount--;
349cd8dbcdcSAxel Dörfler			}
350cd8dbcdcSAxel Dörfler			show_wireless_network_header(verbose);
351cd8dbcdcSAxel Dörfler
352cd8dbcdcSAxel Dörfler			if (argCount > 0) {
353cd8dbcdcSAxel Dörfler				// list the named entries
354cd8dbcdcSAxel Dörfler				for (int32 i = 0; i < argCount; i++) {
355cd8dbcdcSAxel Dörfler					wireless_network network;
356cd8dbcdcSAxel Dörfler					BNetworkAddress link;
357cd8dbcdcSAxel Dörfler					status_t status;
358cd8dbcdcSAxel Dörfler					if (link.SetTo(AF_LINK, args[i]) == B_OK)
359cd8dbcdcSAxel Dörfler						status = device.GetNetwork(link, network);
360cd8dbcdcSAxel Dörfler					else
361cd8dbcdcSAxel Dörfler						status = device.GetNetwork(args[i], network);
362cd8dbcdcSAxel Dörfler					if (status != B_OK) {
363cd8dbcdcSAxel Dörfler						fprintf(stderr, "%s: Getting network failed: %s\n",
364cd8dbcdcSAxel Dörfler							kProgramName, strerror(status));
365cd8dbcdcSAxel Dörfler					} else
366cd8dbcdcSAxel Dörfler						show_wireless_network(network, verbose);
367cd8dbcdcSAxel Dörfler				}
368cd8dbcdcSAxel Dörfler			} else {
369cd8dbcdcSAxel Dörfler				// list them all
370cd8dbcdcSAxel Dörfler				wireless_network network;
371cd8dbcdcSAxel Dörfler				uint32 cookie = 0;
372cd8dbcdcSAxel Dörfler				while (device.GetNextNetwork(cookie, network) == B_OK)
373cd8dbcdcSAxel Dörfler					show_wireless_network(network, verbose);
374cd8dbcdcSAxel Dörfler			}
375cd8dbcdcSAxel Dörfler			break;
376cd8dbcdcSAxel Dörfler		}
377cd8dbcdcSAxel Dörfler
378cd8dbcdcSAxel Dörfler		case JOIN:
379cd8dbcdcSAxel Dörfler		{
380cd8dbcdcSAxel Dörfler			// join a wireless network
381cd8dbcdcSAxel Dörfler			if (argCount > 2) {
382cd8dbcdcSAxel Dörfler				fprintf(stderr, "usage: %s %s join <network> [<password>]\n",
383cd8dbcdcSAxel Dörfler					kProgramName, name);
384cd8dbcdcSAxel Dörfler				exit(1);
385cd8dbcdcSAxel Dörfler			}
386cd8dbcdcSAxel Dörfler
387cd8dbcdcSAxel Dörfler			const char* password = NULL;
388cd8dbcdcSAxel Dörfler			if (argCount == 2)
389cd8dbcdcSAxel Dörfler				password = args[1];
390cd8dbcdcSAxel Dörfler
391cd8dbcdcSAxel Dörfler			BNetworkAddress link;
392cd8dbcdcSAxel Dörfler			status_t status;
393cd8dbcdcSAxel Dörfler			if (link.SetTo(AF_LINK, args[0]) == B_OK)
394cd8dbcdcSAxel Dörfler				status = device.JoinNetwork(link, password);
395cd8dbcdcSAxel Dörfler			else
396cd8dbcdcSAxel Dörfler				status = device.JoinNetwork(args[0], password);
397cd8dbcdcSAxel Dörfler			if (status != B_OK) {
398cd8dbcdcSAxel Dörfler				fprintf(stderr, "%s: Joining network failed: %s\n",
399cd8dbcdcSAxel Dörfler					kProgramName, strerror(status));
400cd8dbcdcSAxel Dörfler				exit(1);
401cd8dbcdcSAxel Dörfler			}
402cd8dbcdcSAxel Dörfler			break;
403cd8dbcdcSAxel Dörfler		}
404cd8dbcdcSAxel Dörfler
405cd8dbcdcSAxel Dörfler		case LEAVE:
406cd8dbcdcSAxel Dörfler		{
407cd8dbcdcSAxel Dörfler			// leave a wireless network
408cd8dbcdcSAxel Dörfler			if (argCount != 1) {
409cd8dbcdcSAxel Dörfler				fprintf(stderr, "usage: %s %s leave <network>\n", kProgramName,
410cd8dbcdcSAxel Dörfler					name);
411cd8dbcdcSAxel Dörfler				exit(1);
412cd8dbcdcSAxel Dörfler			}
413cd8dbcdcSAxel Dörfler
414cd8dbcdcSAxel Dörfler			BNetworkAddress link;
415cd8dbcdcSAxel Dörfler			status_t status;
416cd8dbcdcSAxel Dörfler			if (link.SetTo(AF_LINK, args[0]) == B_OK)
417cd8dbcdcSAxel Dörfler				status = device.LeaveNetwork(link);
418cd8dbcdcSAxel Dörfler			else
419cd8dbcdcSAxel Dörfler				status = device.LeaveNetwork(args[0]);
420cd8dbcdcSAxel Dörfler			if (status != B_OK) {
421cd8dbcdcSAxel Dörfler				fprintf(stderr, "%s: Leaving network failed: %s\n",
422cd8dbcdcSAxel Dörfler					kProgramName, strerror(status));
423cd8dbcdcSAxel Dörfler				exit(1);
424cd8dbcdcSAxel Dörfler			}
425cd8dbcdcSAxel Dörfler			break;
426cd8dbcdcSAxel Dörfler		}
427cd8dbcdcSAxel Dörfler
4284fab1ac6SJulian Harnath		case CONTROL:
4294fab1ac6SJulian Harnath		{
4304fab1ac6SJulian Harnath			ieee80211req request;
4314fab1ac6SJulian Harnath			memset(&request, 0, sizeof(request));
4324fab1ac6SJulian Harnath			request.i_type = controlOption;
4334fab1ac6SJulian Harnath			request.i_val = controlValue;
4344fab1ac6SJulian Harnath			status_t status = device.Control(SIOCS80211, &request);
4354fab1ac6SJulian Harnath			if (status != B_OK) {
4364fab1ac6SJulian Harnath				fprintf(stderr, "%s: Control failed: %s\n", kProgramName,
4374fab1ac6SJulian Harnath					strerror(status));
4384fab1ac6SJulian Harnath				exit(1);
4394fab1ac6SJulian Harnath			}
4404fab1ac6SJulian Harnath			break;
4414fab1ac6SJulian Harnath		}
4424fab1ac6SJulian Harnath
443cd8dbcdcSAxel Dörfler		case NONE:
444cd8dbcdcSAxel Dörfler			break;
445cd8dbcdcSAxel Dörfler	}
446cd8dbcdcSAxel Dörfler
447cd8dbcdcSAxel Dörfler	return true;
448cd8dbcdcSAxel Dörfler}
449cd8dbcdcSAxel Dörfler
450cd8dbcdcSAxel Dörfler
4515adca30aSAxel Dörfler//	#pragma mark -
4525adca30aSAxel Dörfler
4535adca30aSAxel Dörfler
4545adca30aSAxel Dörflervoid
455b2a400e5SAxel Dörflerlist_interface_addresses(BNetworkInterface& interface, uint32 flags)
4565adca30aSAxel Dörfler{
457b2a400e5SAxel Dörfler	int32 count = interface.CountAddresses();
458b2a400e5SAxel Dörfler	for (int32 i = 0; i < count; i++) {
459b2a400e5SAxel Dörfler		BNetworkInterfaceAddress address;
460b2a400e5SAxel Dörfler		if (interface.GetAddressAt(i, address) != B_OK)
461b2a400e5SAxel Dörfler			break;
4625adca30aSAxel Dörfler
463b2a400e5SAxel Dörfler		const address_family* family
46477206143SAxel Dörfler			= address_family_for(address.Address().Family());
465cc2a443dSAxel Dörfler
466aa6c140bSAxel Dörfler		printf("\t%s addr: %s", family->name,
46720ead9a8SAxel Dörfler			to_string(address.Address()).String());
468aa6c140bSAxel Dörfler
46977206143SAxel Dörfler		if ((flags & IFF_BROADCAST) != 0)
47020ead9a8SAxel Dörfler			printf(", Bcast: %s", to_string(address.Broadcast()).String());
471b2a400e5SAxel Dörfler
472cc2a443dSAxel Dörfler		switch (family->preferred_format) {
473cc2a443dSAxel Dörfler			case PREFER_OUTPUT_MASK:
47420ead9a8SAxel Dörfler				printf(", Mask: %s", to_string(address.Mask()).String());
475cc2a443dSAxel Dörfler				break;
476cc2a443dSAxel Dörfler			case PREFER_OUTPUT_PREFIX_LENGTH:
47777206143SAxel Dörfler				printf(", Prefix Length: %zu", address.Mask().PrefixLength());
478cc2a443dSAxel Dörfler				break;
479cc2a443dSAxel Dörfler		}
480b2a400e5SAxel Dörfler
481b2a400e5SAxel Dörfler		putchar('\n');
4825adca30aSAxel Dörfler	}
483cc2a443dSAxel Dörfler}
484cc2a443dSAxel Dörfler
485cc2a443dSAxel Dörfler
486cc2a443dSAxel Dörflerbool
487b2a400e5SAxel Dörflerlist_interface(const char* name)
488cc2a443dSAxel Dörfler{
4895adca30aSAxel Dörfler	printf("%s", name);
4905adca30aSAxel Dörfler	size_t length = strlen(name);
4915adca30aSAxel Dörfler	if (length < 8)
4925adca30aSAxel Dörfler		putchar('\t');
4935adca30aSAxel Dörfler	else
4945adca30aSAxel Dörfler		printf("\n\t");
4955adca30aSAxel Dörfler
4965adca30aSAxel Dörfler	// get link level interface for this interface
4976d60dde7SAxel Dörfler
498b2a400e5SAxel Dörfler	BNetworkInterface interface(name);
499056b2e33SStefano Ceccherini	if (!interface.Exists()) {
500056b2e33SStefano Ceccherini		printf("Interface not found!\n");
501056b2e33SStefano Ceccherini		return false;
502056b2e33SStefano Ceccherini	}
503056b2e33SStefano Ceccherini
504b2a400e5SAxel Dörfler	BNetworkAddress linkAddress;
505b2a400e5SAxel Dörfler	status_t status = interface.GetHardwareAddress(linkAddress);
506b2a400e5SAxel Dörfler	if (status == B_OK) {
5075adca30aSAxel Dörfler		const char *type = "unknown";
508b2a400e5SAxel Dörfler		switch (linkAddress.LinkLevelType()) {
509b2a400e5SAxel Dörfler			case IFT_ETHER:
510b2a400e5SAxel Dörfler				type = "Ethernet";
511b2a400e5SAxel Dörfler				break;
512b2a400e5SAxel Dörfler			case IFT_LOOP:
513b2a400e5SAxel Dörfler				type = "Local Loopback";
514b2a400e5SAxel Dörfler				break;
515b2a400e5SAxel Dörfler			case IFT_MODEM:
516b2a400e5SAxel Dörfler				type = "Modem";
517b2a400e5SAxel Dörfler				break;
5185adca30aSAxel Dörfler		}
5195adca30aSAxel Dörfler
52097dfb56dSAxel Dörfler		BString address = linkAddress.ToString();
52197dfb56dSAxel Dörfler		if (address.Length() == 0)
52297dfb56dSAxel Dörfler			address = "none";
52397dfb56dSAxel Dörfler
524cd8dbcdcSAxel Dörfler		printf("Hardware type: %s, Address: %s\n", type, address.String());
525b2a400e5SAxel Dörfler	} else
526b2a400e5SAxel Dörfler		printf("No link level: %s\n", strerror(status));
5275adca30aSAxel Dörfler
528b2a400e5SAxel Dörfler	int media = interface.Media();
529b2a400e5SAxel Dörfler	if ((media & IFM_ACTIVE) != 0) {
530bf256341SAxel Dörfler		// dump media state in case we're linked
53154c34be7SAxel Dörfler		const char* type = media_type_to_string(media);
53254c34be7SAxel Dörfler		if (type != NULL)
533cd8dbcdcSAxel Dörfler			printf("\tMedia type: %s\n", type);
534cd8dbcdcSAxel Dörfler	}
535cd8dbcdcSAxel Dörfler
536cd8dbcdcSAxel Dörfler	// Print associated wireless network(s)
537cd8dbcdcSAxel Dörfler
538cd8dbcdcSAxel Dörfler	BNetworkDevice device(name);
539cd8dbcdcSAxel Dörfler	if (device.IsWireless()) {
540cd8dbcdcSAxel Dörfler		wireless_network network;
541cd8dbcdcSAxel Dörfler		bool first = true;
542cd8dbcdcSAxel Dörfler		uint32 cookie = 0;
543cd8dbcdcSAxel Dörfler		while (device.GetNextAssociatedNetwork(cookie, network) == B_OK) {
544cd8dbcdcSAxel Dörfler			if (first) {
545cd8dbcdcSAxel Dörfler				printf("\tNetwork: ");
546cd8dbcdcSAxel Dörfler				first = false;
547cd8dbcdcSAxel Dörfler			} else
548cd8dbcdcSAxel Dörfler				printf("\t\t");
549cd8dbcdcSAxel Dörfler
550cd8dbcdcSAxel Dörfler			printf("%s, Address: %s, %s", network.name,
551cd8dbcdcSAxel Dörfler				network.address.ToString().String(),
552cd8dbcdcSAxel Dörfler				get_authentication_mode(network.authentication_mode,
553cd8dbcdcSAxel Dörfler					network.flags));
554cd8dbcdcSAxel Dörfler			const char* keyMode = get_key_mode(network.key_mode);
555cd8dbcdcSAxel Dörfler			if (keyMode != NULL)
556cd8dbcdcSAxel Dörfler				printf(", %s/%s", keyMode, get_cipher(network.cipher));
557cd8dbcdcSAxel Dörfler			putchar('\n');
558cd8dbcdcSAxel Dörfler		}
5596d60dde7SAxel Dörfler	}
5606d60dde7SAxel Dörfler
561b2a400e5SAxel Dörfler	uint32 flags = interface.Flags();
5625adca30aSAxel Dörfler
563b2a400e5SAxel Dörfler	list_interface_addresses(interface, flags);
5645adca30aSAxel Dörfler
5655adca30aSAxel Dörfler	// Print MTU, metric, flags
5665adca30aSAxel Dörfler
567b2a400e5SAxel Dörfler	printf("\tMTU: %" B_PRId32 ", Metric: %" B_PRId32, interface.MTU(),
568b2a400e5SAxel Dörfler		interface.Metric());
5695adca30aSAxel Dörfler
5705adca30aSAxel Dörfler	if (flags != 0) {
5715adca30aSAxel Dörfler		const struct {
5725adca30aSAxel Dörfler			int			value;
5735adca30aSAxel Dörfler			const char	*name;
5745adca30aSAxel Dörfler		} kFlags[] = {
5755adca30aSAxel Dörfler			{IFF_UP, "up"},
5765adca30aSAxel Dörfler			{IFF_NOARP, "noarp"},
5775adca30aSAxel Dörfler			{IFF_BROADCAST, "broadcast"},
5785adca30aSAxel Dörfler			{IFF_LOOPBACK, "loopback"},
5795adca30aSAxel Dörfler			{IFF_PROMISC, "promiscuous"},
5805adca30aSAxel Dörfler			{IFF_ALLMULTI, "allmulti"},
5815adca30aSAxel Dörfler			{IFF_AUTOUP, "autoup"},
582c57dbb8bSHugo Santos			{IFF_LINK, "link"},
5836d60dde7SAxel Dörfler			{IFF_AUTO_CONFIGURED, "auto-configured"},
584c57dbb8bSHugo Santos			{IFF_CONFIGURING, "configuring"},
5855adca30aSAxel Dörfler		};
5865adca30aSAxel Dörfler		bool first = true;
5875adca30aSAxel Dörfler
5885adca30aSAxel Dörfler		for (uint32 i = 0; i < sizeof(kFlags) / sizeof(kFlags[0]); i++) {
5895adca30aSAxel Dörfler			if ((flags & kFlags[i].value) != 0) {
5905adca30aSAxel Dörfler				if (first) {
5915adca30aSAxel Dörfler					printf(",");
5925adca30aSAxel Dörfler					first = false;
5935adca30aSAxel Dörfler				}
5945adca30aSAxel Dörfler				putchar(' ');
5955adca30aSAxel Dörfler				printf(kFlags[i].name);
5965adca30aSAxel Dörfler			}
5975adca30aSAxel Dörfler		}
5985adca30aSAxel Dörfler	}
5995adca30aSAxel Dörfler
6005adca30aSAxel Dörfler	putchar('\n');
6015adca30aSAxel Dörfler
6025adca30aSAxel Dörfler	// Print statistics
6035adca30aSAxel Dörfler
604b2a400e5SAxel Dörfler	ifreq_stats stats;
605b2a400e5SAxel Dörfler	if (interface.GetStats(stats) == B_OK) {
606b2a400e5SAxel Dörfler		printf("\tReceive: %d packets, %d errors, %Ld bytes, %d mcasts, %d "
607b2a400e5SAxel Dörfler			"dropped\n", stats.receive.packets, stats.receive.errors,
608b2a400e5SAxel Dörfler			stats.receive.bytes, stats.receive.multicast_packets,
609b2a400e5SAxel Dörfler			stats.receive.dropped);
610b2a400e5SAxel Dörfler		printf("\tTransmit: %d packets, %d errors, %Ld bytes, %d mcasts, %d "
611b2a400e5SAxel Dörfler			"dropped\n", stats.send.packets, stats.send.errors,
612b2a400e5SAxel Dörfler			stats.send.bytes, stats.send.multicast_packets, stats.send.dropped);
613b2a400e5SAxel Dörfler		printf("\tCollisions: %d\n", stats.collisions);
6145adca30aSAxel Dörfler	}
6155adca30aSAxel Dörfler
6165adca30aSAxel Dörfler	putchar('\n');
617cc2a443dSAxel Dörfler	return true;
6185adca30aSAxel Dörfler}
6195adca30aSAxel Dörfler
6205adca30aSAxel Dörfler
6215adca30aSAxel Dörflervoid
622cc2a443dSAxel Dörflerlist_interfaces(const char* name)
6235adca30aSAxel Dörfler{
6245adca30aSAxel Dörfler	if (name != NULL) {
625b2a400e5SAxel Dörfler		list_interface(name);
6265adca30aSAxel Dörfler		return;
6275adca30aSAxel Dörfler	}
6285adca30aSAxel Dörfler
6295adca30aSAxel Dörfler	// get a list of all interfaces
6305adca30aSAxel Dörfler
631b2a400e5SAxel Dörfler	BNetworkRoster& roster = BNetworkRoster::Default();
632cc2a443dSAxel Dörfler
633b2a400e5SAxel Dörfler	BNetworkInterface interface;
634b2a400e5SAxel Dörfler	uint32 cookie = 0;
6355adca30aSAxel Dörfler
636b2a400e5SAxel Dörfler	while (roster.GetNextInterface(&cookie, interface) == B_OK) {
637b2a400e5SAxel Dörfler		list_interface(interface.Name());
6385adca30aSAxel Dörfler	}
6395adca30aSAxel Dörfler}
6405adca30aSAxel Dörfler
6415adca30aSAxel Dörfler
6422b1c0755SAxel Dörfler/*!	If there are any arguments given, this will remove only the specified
6432b1c0755SAxel Dörfler	addresses from the interface named \a name.
6442b1c0755SAxel Dörfler	If there are no arguments, it will remove the complete interface with all
6452b1c0755SAxel Dörfler	of its addresses.
6462b1c0755SAxel Dörfler*/
6475adca30aSAxel Dörflervoid
6482b1c0755SAxel Dörflerdelete_interface(const char* name, char* const* args, int32 argCount)
6495adca30aSAxel Dörfler{
65097dfb56dSAxel Dörfler	BNetworkInterface interface(name);
6515adca30aSAxel Dörfler
6522b1c0755SAxel Dörfler	for (int32 i = 0; i < argCount; i++) {
65301308f21SAxel Dörfler		int family = get_address_family(args[i]);
65401308f21SAxel Dörfler		if (family != AF_UNSPEC)
6552b1c0755SAxel Dörfler			i++;
6562b1c0755SAxel Dörfler
65797dfb56dSAxel Dörfler		BNetworkAddress address;
65897dfb56dSAxel Dörfler		if (!parse_address(family, args[i], address)) {
6592b1c0755SAxel Dörfler			fprintf(stderr, "%s: Could not parse address \"%s\".\n",
6602b1c0755SAxel Dörfler				kProgramName, args[i]);
6612b1c0755SAxel Dörfler			exit(1);
6622b1c0755SAxel Dörfler		}
6632b1c0755SAxel Dörfler
66497dfb56dSAxel Dörfler		status_t status = interface.RemoveAddress(address);
66597dfb56dSAxel Dörfler		if (status != B_OK) {
6662b1c0755SAxel Dörfler			fprintf(stderr, "%s: Could not delete address %s from interface %s:"
66797dfb56dSAxel Dörfler				" %s\n", kProgramName, args[i], name, strerror(status));
6682b1c0755SAxel Dörfler		}
6692b1c0755SAxel Dörfler	}
6702b1c0755SAxel Dörfler
6712b1c0755SAxel Dörfler	if (argCount == 0) {
6722b1c0755SAxel Dörfler		// Delete interface
67397dfb56dSAxel Dörfler		BNetworkRoster& roster = BNetworkRoster::Default();
67401308f21SAxel Dörfler
67597dfb56dSAxel Dörfler		status_t status = roster.RemoveInterface(interface);
67697dfb56dSAxel Dörfler		if (status != B_OK) {
6772b1c0755SAxel Dörfler			fprintf(stderr, "%s: Could not delete interface %s: %s\n",
6782b1c0755SAxel Dörfler				kProgramName, name, strerror(errno));
6792b1c0755SAxel Dörfler		}
6805adca30aSAxel Dörfler	}
6815adca30aSAxel Dörfler}
6825adca30aSAxel Dörfler
6835adca30aSAxel Dörfler
6845adca30aSAxel Dörflervoid
685cd8dbcdcSAxel Dörflerconfigure_interface(const char* name, char* const* args, int32 argCount)
6865adca30aSAxel Dörfler{
687cc2a443dSAxel Dörfler	// try to parse address family
688cc2a443dSAxel Dörfler
689cc2a443dSAxel Dörfler	int32 i = 0;
69001308f21SAxel Dörfler	int family = get_address_family(args[i]);
69101308f21SAxel Dörfler	if (family != AF_UNSPEC)
692cc2a443dSAxel Dörfler		i++;
693cc2a443dSAxel Dörfler
69497dfb56dSAxel Dörfler	// try to parse address
695cc2a443dSAxel Dörfler
69697dfb56dSAxel Dörfler	BNetworkAddress address;
69797dfb56dSAxel Dörfler	BNetworkAddress mask;
69801308f21SAxel Dörfler
69997dfb56dSAxel Dörfler	if (parse_address(family, args[i], address)) {
70097dfb56dSAxel Dörfler		i++;
7015adca30aSAxel Dörfler
70297dfb56dSAxel Dörfler		if (parse_address(family, args[i], mask))
70397dfb56dSAxel Dörfler			i++;
70497dfb56dSAxel Dörfler	}
7055adca30aSAxel Dörfler
70697dfb56dSAxel Dörfler	BNetworkInterface interface(name);
70797dfb56dSAxel Dörfler	if (!interface.Exists()) {
7085adca30aSAxel Dörfler		// the interface does not exist yet, we have to add it first
70997dfb56dSAxel Dörfler		BNetworkRoster& roster = BNetworkRoster::Default();
71001308f21SAxel Dörfler
71197dfb56dSAxel Dörfler		status_t status = roster.AddInterface(interface);
71297dfb56dSAxel Dörfler		if (status != B_OK) {
7135adca30aSAxel Dörfler			fprintf(stderr, "%s: Could not add interface: %s\n", kProgramName,
71497dfb56dSAxel Dörfler				strerror(status));
7155adca30aSAxel Dörfler			exit(1);
7165adca30aSAxel Dörfler		}
7175adca30aSAxel Dörfler	}
7185adca30aSAxel Dörfler
71997dfb56dSAxel Dörfler	BNetworkAddress broadcast;
72097dfb56dSAxel Dörfler	BNetworkAddress peer;
72197dfb56dSAxel Dörfler	int mtu = -1, metric = -1, media = -1;
72297dfb56dSAxel Dörfler	int addFlags = 0, currentFlags = 0, removeFlags = 0;
72397dfb56dSAxel Dörfler	bool doAutoConfig = false;
7245adca30aSAxel Dörfler
7255adca30aSAxel Dörfler	// parse parameters and flags
7265adca30aSAxel Dörfler
7275adca30aSAxel Dörfler	while (i < argCount) {
7285adca30aSAxel Dörfler		if (!strcmp(args[i], "peer")) {
72997dfb56dSAxel Dörfler			if (!parse_address(family, args[i + 1], peer)) {
730fd95a7e1SAxel Dörfler				fprintf(stderr, "%s: Option 'peer' needs valid address "
731fd95a7e1SAxel Dörfler					"parameter\n", kProgramName);
7325adca30aSAxel Dörfler				exit(1);
7335adca30aSAxel Dörfler			}
7345adca30aSAxel Dörfler			i++;
7355adca30aSAxel Dörfler		} else if (!strcmp(args[i], "nm") || !strcmp(args[i], "netmask")) {
73697dfb56dSAxel Dörfler			if (!mask.IsEmpty()) {
737cc2a443dSAxel Dörfler				fprintf(stderr, "%s: Netmask or prefix length is specified "
738cc2a443dSAxel Dörfler					"twice\n", kProgramName);
7395adca30aSAxel Dörfler				exit(1);
7405adca30aSAxel Dörfler			}
74197dfb56dSAxel Dörfler			if (!parse_address(family, args[i + 1], mask)) {
742fd95a7e1SAxel Dörfler				fprintf(stderr, "%s: Option 'netmask' needs valid address "
743fd95a7e1SAxel Dörfler					"parameter\n", kProgramName);
7445adca30aSAxel Dörfler				exit(1);
7455adca30aSAxel Dörfler			}
7465adca30aSAxel Dörfler			i++;
74797dfb56dSAxel Dörfler		} else if (!strcmp(args[i], "prefixlen") || !strcmp(args[i], "plen")
74897dfb56dSAxel Dörfler			|| !strcmp(args[i], "prefix-length")) {
74997dfb56dSAxel Dörfler			if (!mask.IsEmpty()) {
750cc2a443dSAxel Dörfler				fprintf(stderr, "%s: Netmask or prefix length is specified "
751cc2a443dSAxel Dörfler					"twice\n", kProgramName);
752cc2a443dSAxel Dörfler				exit(1);
753cc2a443dSAxel Dörfler			}
75497dfb56dSAxel Dörfler
75597dfb56dSAxel Dörfler			// default to AF_INET if no address family has been specified yet
75697dfb56dSAxel Dörfler			if (family == AF_UNSPEC)
75797dfb56dSAxel Dörfler				family = AF_INET;
75897dfb56dSAxel Dörfler
75997dfb56dSAxel Dörfler			if (!prefix_length_to_mask(family, args[i + 1], mask)) {
76097dfb56dSAxel Dörfler				fprintf(stderr, "%s: Option 'prefix-length %s' is invalid for "
76197dfb56dSAxel Dörfler					"this address family\n", kProgramName, args[i + 1]);
762cc2a443dSAxel Dörfler				exit(1);
763cc2a443dSAxel Dörfler			}
764cc2a443dSAxel Dörfler			i++;
7655adca30aSAxel Dörfler		} else if (!strcmp(args[i], "bc") || !strcmp(args[i], "broadcast")) {
76697dfb56dSAxel Dörfler			if (!broadcast.IsEmpty()) {
7675adca30aSAxel Dörfler				fprintf(stderr, "%s: broadcast address is specified twice\n",
7685adca30aSAxel Dörfler					kProgramName);
7695adca30aSAxel Dörfler				exit(1);
7705adca30aSAxel Dörfler			}
771