xref: /haiku/src/bin/network/ifconfig/ifconfig.cpp (revision e0bc2fcce4c5ceb7b57d978b752cda01639d0098)
1 /*
2  * Copyright 2006-2010, 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 <arpa/inet.h>
13 #include <net/if.h>
14 #include <net/if_dl.h>
15 #include <net/if_media.h>
16 #include <net/if_types.h>
17 #include <netinet/in.h>
18 #include <sys/socket.h>
19 #include <sys/sockio.h>
20 
21 #include <errno.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <unistd.h>
26 
27 #include <Message.h>
28 #include <Messenger.h>
29 #include <NetworkInterface.h>
30 #include <NetworkRoster.h>
31 
32 #include <NetServer.h>
33 
34 
35 extern const char* __progname;
36 const char* kProgramName = __progname;
37 
38 
39 enum preferred_output_format {
40 	PREFER_OUTPUT_MASK,
41 	PREFER_OUTPUT_PREFIX_LENGTH,
42 };
43 
44 
45 struct address_family {
46 	int			family;
47 	const char*	name;
48 	const char*	identifiers[4];
49 	preferred_output_format	preferred_format;
50 	bool		(*parse_address)(const char* string, sockaddr* _address);
51 };
52 
53 
54 bool initialize_address_families();
55 
56 // AF_INET family
57 static bool inet_parse_address(const char* string, sockaddr* address);
58 
59 // AF_INET6 family
60 static bool inet6_parse_address(const char* string, sockaddr* address);
61 
62 static const address_family kFamilies[] = {
63 	{
64 		AF_INET,
65 		"inet",
66 		{"AF_INET", "inet", "ipv4", NULL},
67 		PREFER_OUTPUT_MASK,
68 		inet_parse_address,
69 	},
70 	{
71 		AF_INET6,
72 		"inet6",
73 		{"AF_INET6", "inet6", "ipv6", NULL},
74 		PREFER_OUTPUT_PREFIX_LENGTH,
75 		inet6_parse_address,
76 	},
77 	{ -1, NULL, {NULL}, PREFER_OUTPUT_MASK, NULL }
78 };
79 
80 
81 static int sAddressFamilySockets[sizeof(kFamilies) / sizeof(kFamilies[0])];
82 
83 
84 bool
85 initialize_address_families()
86 {
87 	bool ok = false;
88 	for (int32 i = 0; kFamilies[i].family >= 0; i++) {
89 		int fd = socket(kFamilies[i].family, SOCK_DGRAM, 0);
90 		if (fd != -1) {
91 			sAddressFamilySockets[i] = fd;
92 			ok = true;
93 		}
94 	}
95 	return ok;
96 }
97 
98 
99 // #pragma mark - IPv4
100 
101 
102 static bool
103 inet_parse_address(const char* string, sockaddr* _address)
104 {
105 	in_addr inetAddress;
106 
107 	if (inet_aton(string, &inetAddress) != 1)
108 		return false;
109 
110 	sockaddr_in& address = *(sockaddr_in*)_address;
111 	address.sin_family = AF_INET;
112 	address.sin_len = sizeof(sockaddr_in);
113 	address.sin_port = 0;
114 	address.sin_addr = inetAddress;
115 	memset(&address.sin_zero[0], 0, sizeof(address.sin_zero));
116 
117 	return true;
118 }
119 
120 
121 // #pragma mark - IPv6
122 
123 
124 static bool
125 inet6_parse_address(const char* string, sockaddr* _address)
126 {
127 	sockaddr_in6& address = *(sockaddr_in6*)_address;
128 
129 	if (inet_pton(AF_INET6, string, &address.sin6_addr) != 1)
130 		return false;
131 
132 	address.sin6_family = AF_INET6;
133 	address.sin6_len = sizeof(sockaddr_in6);
134 	address.sin6_port = 0;
135 	address.sin6_flowinfo = 0;
136 	address.sin6_scope_id = 0;
137 
138 	return true;
139 }
140 
141 
142 //	#pragma mark -
143 
144 
145 struct media_type {
146 	int			type;
147 	const char*	name;
148 	const char* pretty;
149 	struct {
150 		int subtype;
151 		const char* name;
152 		const char* pretty;
153 	} subtypes [6];
154 	struct {
155 		int option;
156 		bool ro;
157 		const char* name;
158 		const char* pretty;
159 	} options [6];
160 };
161 
162 
163 static const media_type kMediaTypes[] = {
164 	{
165 		0, // for generic options
166 		"all",
167 		"All",
168 		{
169 			{ IFM_AUTO, "auto", "Auto-select" },
170 			{ -1, NULL, NULL }
171 		},
172 		{
173 			{ IFM_FULL_DUPLEX, true, "fullduplex", "Full Duplex" },
174 			{ IFM_HALF_DUPLEX, true, "halfduplex", "Half Duplex" },
175 			{ IFM_LOOP, true, "loop", "Loop" },
176 			//{ IFM_ACTIVE, false, "active", "Active" },
177 			{ -1, false, NULL, NULL }
178 		}
179 	},
180 	{
181 		IFM_ETHER,
182 		"ether",
183 		"Ethernet",
184 		{
185 			//{ IFM_AUTO, "auto", "Auto-select" },
186 			//{ IFM_AUI, "AUI", "10 MBit, AUI" },
187 			//{ IFM_10_2, "10base2", "10 MBit, 10BASE-2" },
188 			{ IFM_10_T, "10baseT", "10 MBit, 10BASE-T" },
189 			{ IFM_100_TX, "100baseTX", "100 MBit, 100BASE-TX" },
190 			{ IFM_1000_T, "1000baseT", "1 GBit, 1000BASE-T" },
191 			{ IFM_1000_SX, "1000baseSX", "1 GBit, 1000BASE-SX" },
192 			{ -1, NULL, NULL }
193 		},
194 		{
195 			{ -1, false, NULL, NULL }
196 		}
197 	},
198 	{ -1, NULL, NULL, {{ -1, NULL, NULL }}, {{ -1, false, NULL, NULL }} }
199 };
200 
201 
202 static bool
203 media_parse_subtype(const char* string, int media, int* type)
204 {
205 	for (int32 i = 0; kMediaTypes[i].type >= 0; i++) {
206 		// only check for generic or correct subtypes
207 		if (kMediaTypes[i].type &&
208 			kMediaTypes[i].type != media)
209 			continue;
210 		for (int32 j = 0; kMediaTypes[i].subtypes[j].subtype >= 0; j++) {
211 			if (strcmp(kMediaTypes[i].subtypes[j].name, string) == 0) {
212 				// found a match
213 				*type = kMediaTypes[i].subtypes[j].subtype;
214 				return true;
215 			}
216 		}
217 	}
218 	return false;
219 }
220 
221 
222 //	#pragma mark -
223 
224 
225 void
226 usage(int status)
227 {
228 	printf("usage: %s [<interface> [<address family>] [<address> [<mask>] | "
229 			"auto-config] [<option/flags>...]]\n"
230 		"\t%s --delete interface [...]\n\n"
231 		"Where <option> can be the following:\n"
232 		"  netmask <addr>     - networking subnet mask\n"
233 		"  prefixlen <number> - subnet mask length in bits\n"
234 		"  broadcast <addr>   - set broadcast address\n"
235 		"  peer <addr>        - ppp-peer address\n"
236 		"  mtu <bytes>        - maximal transfer unit\n"
237 		"  metric <number>    - metric number to use (defaults to 0)\n"
238 		"  media <media>      - media type to use (defaults to auto)\n",
239 		kProgramName, kProgramName);
240 	for (int32 i = 0; kMediaTypes[i].type >= 0; i++) {
241 		printf("For %s <media> can be one of: ", kMediaTypes[i].pretty);
242 		for (int32 j = 0; kMediaTypes[i].subtypes[j].subtype >= 0; j++)
243 			printf("%s ", kMediaTypes[i].subtypes[j].name);
244 		printf("\n");
245 	}
246 	printf("And <flags> can be: up, down, [-]promisc, [-]allmulti, [-]bcast, "
247 			"loopback\n"
248 		"If you specify \"auto-config\" instead of an address, it will be "
249 			"configured automatically.\n\n"
250 		"Example:\n"
251 		"\t%s loop 127.0.0.1 255.0.0.0 up\n",
252 		kProgramName);
253 
254 	exit(status);
255 }
256 
257 
258 bool
259 prepare_request(struct ifreq& request, const char* name)
260 {
261 	if (strlen(name) >= IF_NAMESIZE) {
262 		fprintf(stderr, "%s: interface name \"%s\" is too long.\n",
263 			kProgramName, name);
264 		return false;
265 	}
266 
267 	memset(&request, 0, sizeof(ifreq));
268 	strcpy(request.ifr_name, name);
269 	return true;
270 }
271 
272 
273 bool
274 get_address_family(const char* argument, int32& familyIndex)
275 {
276 	for (int32 i = 0; kFamilies[i].family >= 0; i++) {
277 		for (int32 j = 0; kFamilies[i].identifiers[j]; j++) {
278 			if (!strcmp(argument, kFamilies[i].identifiers[j])) {
279 				// found a match
280 				familyIndex = i;
281 				return true;
282 			}
283 		}
284 	}
285 
286 	// defaults to AF_INET
287 	familyIndex = 0;
288 	return false;
289 }
290 
291 
292 const address_family*
293 get_address_family(int32 family)
294 {
295 	for (int32 i = 0; kFamilies[i].family >= 0; i++) {
296 		if (kFamilies[i].family == family)
297 			return &kFamilies[i];
298 	}
299 
300 	// defaults to AF_INET
301 	return &kFamilies[0];
302 }
303 
304 
305 bool
306 parse_address(int32 familyIndex, const char* argument, struct sockaddr& address)
307 {
308 	if (argument == NULL)
309 		return false;
310 
311 	return kFamilies[familyIndex].parse_address(argument, &address);
312 }
313 
314 
315 bool
316 prefix_length_to_mask(int32 familyIndex, const char* argument,
317 	struct sockaddr& mask)
318 {
319 	char *end;
320 	uint32 prefixLength = strtoul(argument, &end, 10);
321 	if (end == argument)
322 		return false;
323 
324 	BNetworkAddress address;
325 	if (address.SetToMask(kFamilies[familyIndex].family, prefixLength) != B_OK)
326 		return false;
327 
328 	memcpy(&mask, &address.SockAddr(), address.Length());
329 	return true;
330 }
331 
332 
333 //	#pragma mark -
334 
335 
336 int
337 find_socket(struct ifreq& request, int addressFamily)
338 {
339 	int socket = -1;
340 	bool socketExists = false;
341 	bool ok = false;
342 
343 	for (int32 i = 0; kFamilies[i].family >= 0; i++) {
344 		if (addressFamily != -1 && addressFamily != kFamilies[i].family)
345 			continue;
346 
347 		socket = sAddressFamilySockets[i];
348 		if (socket == -1)
349 			continue;
350 
351 		socketExists = true;
352 
353 		if (ioctl(socket, SIOCGIFINDEX, &request, sizeof(request)) >= 0) {
354 			ok = true;
355 			break;
356 		}
357 	}
358 
359 	if (socketExists && !ok) {
360 		fprintf(stderr, "%s: Interface \"%s\" does not exist.\n",
361 			kProgramName, request.ifr_name);
362 		return -1;
363 	}
364 
365 	return socket;
366 }
367 
368 
369 void
370 list_interface_addresses(BNetworkInterface& interface, uint32 flags)
371 {
372 	int32 count = interface.CountAddresses();
373 	for (int32 i = 0; i < count; i++) {
374 		BNetworkInterfaceAddress address;
375 		if (interface.GetAddressAt(i, address) != B_OK)
376 			break;
377 
378 		const address_family* family
379 			= get_address_family(address.Address().Family());
380 
381 		printf("\t%s addr: %s", family->name,
382 			address.Address().ToString().String());
383 
384 		if ((flags & IFF_BROADCAST) != 0)
385 			printf(", Bcast: %s", address.Broadcast().ToString().String());
386 
387 		switch (family->preferred_format) {
388 			case PREFER_OUTPUT_MASK:
389 				printf(", Mask: %s", address.Mask().ToString().String());
390 				break;
391 			case PREFER_OUTPUT_PREFIX_LENGTH:
392 				printf(", Prefix Length: %zu", address.Mask().PrefixLength());
393 				break;
394 		}
395 
396 		putchar('\n');
397 	}
398 }
399 
400 
401 bool
402 list_interface(const char* name)
403 {
404 	printf("%s", name);
405 	size_t length = strlen(name);
406 	if (length < 8)
407 		putchar('\t');
408 	else
409 		printf("\n\t");
410 
411 	// get link level interface for this interface
412 
413 	BNetworkInterface interface(name);
414 	BNetworkAddress linkAddress;
415 	status_t status = interface.GetHardwareAddress(linkAddress);
416 	if (status == B_OK) {
417 		const char *type = "unknown";
418 		char address[256];
419 		strcpy(address, "none");
420 
421 		switch (linkAddress.LinkLevelType()) {
422 			case IFT_ETHER:
423 			{
424 				type = "Ethernet";
425 
426 				if (linkAddress.LinkLevelAddressLength() > 0) {
427 					uint8 *mac = linkAddress.LinkLevelAddress();
428 					sprintf(address, "%02x:%02x:%02x:%02x:%02x:%02x",
429 						mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
430 				} else
431 					strcpy(address, "not available");
432 				break;
433 			}
434 			case IFT_LOOP:
435 				type = "Local Loopback";
436 				break;
437 			case IFT_MODEM:
438 				type = "Modem";
439 				break;
440 		}
441 
442 		printf("Hardware Type: %s, Address: %s\n", type, address);
443 	} else
444 		printf("No link level: %s\n", strerror(status));
445 
446 	int media = interface.Media();
447 	if ((media & IFM_ACTIVE) != 0) {
448 		// dump media state in case we're linked
449 		const char* type = "unknown";
450 		bool show = false;
451 
452 		for (int32 i = 0; kMediaTypes[i].type >= 0; i++) {
453 			// loopback don't really have a media anyway
454 			if (IFM_TYPE(media) == 0/*IFT_LOOP*/)
455 				break;
456 
457 			// only check for generic or correct subtypes
458 			if (kMediaTypes[i].type
459 				&& kMediaTypes[i].type != IFM_TYPE(media))
460 				continue;
461 
462 			for (int32 j = 0; kMediaTypes[i].subtypes[j].subtype >= 0; j++) {
463 				if (kMediaTypes[i].subtypes[j].subtype == IFM_SUBTYPE(media)) {
464 					// found a match
465 					type = kMediaTypes[i].subtypes[j].pretty;
466 					show = true;
467 					break;
468 				}
469 			}
470 		}
471 
472 		if (show)
473 			printf("\tMedia Type: %s\n", type);
474 	}
475 
476 	uint32 flags = interface.Flags();
477 
478 	list_interface_addresses(interface, flags);
479 
480 	// Print MTU, metric, flags
481 
482 	printf("\tMTU: %" B_PRId32 ", Metric: %" B_PRId32, interface.MTU(),
483 		interface.Metric());
484 
485 	if (flags != 0) {
486 		const struct {
487 			int			value;
488 			const char	*name;
489 		} kFlags[] = {
490 			{IFF_UP, "up"},
491 			{IFF_NOARP, "noarp"},
492 			{IFF_BROADCAST, "broadcast"},
493 			{IFF_LOOPBACK, "loopback"},
494 			{IFF_PROMISC, "promiscuous"},
495 			{IFF_ALLMULTI, "allmulti"},
496 			{IFF_AUTOUP, "autoup"},
497 			{IFF_LINK, "link"},
498 			{IFF_AUTO_CONFIGURED, "auto-configured"},
499 			{IFF_CONFIGURING, "configuring"},
500 		};
501 		bool first = true;
502 
503 		for (uint32 i = 0; i < sizeof(kFlags) / sizeof(kFlags[0]); i++) {
504 			if ((flags & kFlags[i].value) != 0) {
505 				if (first) {
506 					printf(",");
507 					first = false;
508 				}
509 				putchar(' ');
510 				printf(kFlags[i].name);
511 			}
512 		}
513 	}
514 
515 	putchar('\n');
516 
517 	// Print statistics
518 
519 	ifreq_stats stats;
520 	if (interface.GetStats(stats) == B_OK) {
521 		printf("\tReceive: %d packets, %d errors, %Ld bytes, %d mcasts, %d "
522 			"dropped\n", stats.receive.packets, stats.receive.errors,
523 			stats.receive.bytes, stats.receive.multicast_packets,
524 			stats.receive.dropped);
525 		printf("\tTransmit: %d packets, %d errors, %Ld bytes, %d mcasts, %d "
526 			"dropped\n", stats.send.packets, stats.send.errors,
527 			stats.send.bytes, stats.send.multicast_packets, stats.send.dropped);
528 		printf("\tCollisions: %d\n", stats.collisions);
529 	}
530 
531 	putchar('\n');
532 	return true;
533 }
534 
535 
536 void
537 list_interfaces(const char* name)
538 {
539 	if (name != NULL) {
540 		list_interface(name);
541 		return;
542 	}
543 
544 	// get a list of all interfaces
545 
546 	BNetworkRoster& roster = BNetworkRoster::Default();
547 
548 	BNetworkInterface interface;
549 	uint32 cookie = 0;
550 
551 	while (roster.GetNextInterface(&cookie, interface) == B_OK) {
552 		list_interface(interface.Name());
553 	}
554 }
555 
556 
557 /*!	If there are any arguments given, this will remove only the specified
558 	addresses from the interface named \a name.
559 	If there are no arguments, it will remove the complete interface with all
560 	of its addresses.
561 */
562 void
563 delete_interface(const char* name, char* const* args, int32 argCount)
564 {
565 	ifreq request;
566 	if (!prepare_request(request, name))
567 		return;
568 
569 	for (int32 i = 0; i < argCount; i++) {
570 		int32 familyIndex;
571 		if (get_address_family(args[i], familyIndex))
572 			i++;
573 
574 		// TODO: be smart enough to detect the family by the address
575 
576 		int socket = find_socket(request, kFamilies[familyIndex].family);
577 		if (socket == -1) {
578 			fprintf(stderr, "%s: Address family \"%s\" is not available.\n",
579 				kProgramName, kFamilies[familyIndex].name);
580 			exit(1);
581 		}
582 
583 		if (!parse_address(familyIndex, args[i], request.ifr_addr)) {
584 			fprintf(stderr, "%s: Could not parse address \"%s\".\n",
585 				kProgramName, args[i]);
586 			exit(1);
587 		}
588 
589 		if (ioctl(socket, SIOCDIFADDR, &request, sizeof(request)) < 0) {
590 			fprintf(stderr, "%s: Could not delete address %s from interface %s:"
591 				" %s\n", kProgramName, args[i], name, strerror(errno));
592 		}
593 	}
594 
595 	if (argCount == 0) {
596 		// Delete interface
597 		int socket = find_socket(request, -1);
598 		if (socket < 0)
599 			exit(1);
600 
601 		request.ifr_addr.sa_family = AF_UNSPEC;
602 
603 		if (ioctl(socket, SIOCDIFADDR, &request, sizeof(request)) < 0) {
604 			fprintf(stderr, "%s: Could not delete interface %s: %s\n",
605 				kProgramName, name, strerror(errno));
606 		}
607 	}
608 }
609 
610 
611 void
612 configure_interface(const char* name, char* const* args,
613 	int32 argCount)
614 {
615 	ifreq request;
616 	if (!prepare_request(request, name))
617 		return;
618 
619 	// try to parse address family
620 
621 	int32 familyIndex;
622 	int32 i = 0;
623 	if (get_address_family(args[i], familyIndex))
624 		i++;
625 
626 	int socket = sAddressFamilySockets[familyIndex];
627 	if (socket < 0) {
628 		fprintf(stderr, "%s: Address family \"%s\" is not available.\n",
629 			kProgramName, kFamilies[familyIndex].name);
630 		exit(1);
631 	}
632 
633 	uint32 index = 0;
634 	if (ioctl(socket, SIOCGIFINDEX, &request, sizeof(request)) >= 0)
635 		index = request.ifr_index;
636 
637 	bool hasAddress = false, hasMask = false, hasPeer = false;
638 	bool hasBroadcast = false, doAutoConfig = false;
639 	struct sockaddr address, mask, peer, broadcast;
640 	int mtu = -1, metric = -1, media = -1;
641 	int addFlags = 0, currentFlags = 0, removeFlags = 0;
642 
643 	if (index == 0) {
644 		// the interface does not exist yet, we have to add it first
645 		ifaliasreq request;
646 		memset(&request, 0, sizeof(ifaliasreq));
647 		strlcpy(request.ifra_name, name, IF_NAMESIZE);
648 
649 		if (ioctl(socket, SIOCAIFADDR, &request, sizeof(request)) < 0) {
650 			fprintf(stderr, "%s: Could not add interface: %s\n", kProgramName,
651 				strerror(errno));
652 			exit(1);
653 		}
654 	}
655 
656 	// try to parse address
657 
658 	if (parse_address(familyIndex, args[i], address)) {
659 		hasAddress = true;
660 		i++;
661 
662 		if (parse_address(familyIndex, args[i], mask)) {
663 			hasMask = true;
664 			i++;
665 		}
666 	}
667 
668 	// parse parameters and flags
669 
670 	while (i < argCount) {
671 		if (!strcmp(args[i], "peer")) {
672 			if (!parse_address(familyIndex, args[i + 1], peer)) {
673 				fprintf(stderr, "%s: Option 'peer' needs valid address "
674 					"parameter\n", kProgramName);
675 				exit(1);
676 			}
677 			hasPeer = true;
678 			i++;
679 		} else if (!strcmp(args[i], "nm") || !strcmp(args[i], "netmask")) {
680 			if (hasMask) {
681 				fprintf(stderr, "%s: Netmask or prefix length is specified "
682 					"twice\n", kProgramName);
683 				exit(1);
684 			}
685 			if (!parse_address(familyIndex, args[i + 1], mask)) {
686 				fprintf(stderr, "%s: Option 'netmask' needs valid address "
687 					"parameter\n", kProgramName);
688 				exit(1);
689 			}
690 			hasMask = true;
691 			i++;
692 		} else if (!strcmp(args[i], "prefixlen")
693 				|| !strcmp(args[i], "plen")) {
694 			if (hasMask) {
695 				fprintf(stderr, "%s: Netmask or prefix length is specified "
696 					"twice\n", kProgramName);
697 				exit(1);
698 			}
699 			if (!prefix_length_to_mask(familyIndex, args[i + 1], mask)) {
700 				fprintf(stderr, "%s: Option 'prefixlen' is invalid for this "
701 					"address family\n", kProgramName);
702 				exit(1);
703 			}
704 			hasMask = true;
705 			i++;
706 		} else if (!strcmp(args[i], "bc") || !strcmp(args[i], "broadcast")) {
707 			if (hasBroadcast) {
708 				fprintf(stderr, "%s: broadcast address is specified twice\n",
709 					kProgramName);
710 				exit(1);
711 			}
712 			if (!parse_address(familyIndex, args[i + 1], broadcast)) {
713 				fprintf(stderr, "%s: Option 'broadcast' needs valid address "
714 					"parameter\n", kProgramName);
715 				exit(1);
716 			}
717 			hasBroadcast = true;
718 			addFlags |= IFF_BROADCAST;
719 			i++;
720 		} else if (!strcmp(args[i], "mtu")) {
721 			mtu = args[i + 1] ? strtol(args[i + 1], NULL, 0) : 0;
722 			if (mtu <= 500) {
723 				fprintf(stderr, "%s: Option 'mtu' expected valid max transfer "
724 					"unit size\n", kProgramName);
725 				exit(1);
726 			}
727 			i++;
728 		} else if (!strcmp(args[i], "metric")) {
729 			if (i + 1 >= argCount) {
730 				fprintf(stderr, "%s: Option 'metric' exptected parameter\n",
731 					kProgramName);
732 				exit(1);
733 			}
734 			metric = strtol(args[i + 1], NULL, 0);
735 			i++;
736 		} else if (!strcmp(args[i], "media")) {
737 			if (ioctl(socket, SIOCGIFMEDIA, &request,
738 					sizeof(struct ifreq)) < 0) {
739 				fprintf(stderr, "%s: Unable to detect media type\n",
740 					kProgramName);
741 				exit(1);
742 			}
743 			if (i + 1 >= argCount) {
744 				fprintf(stderr, "%s: Option 'media' exptected parameter\n",
745 					kProgramName);
746 				exit(1);
747 			}
748 			if (!media_parse_subtype(args[i + 1], IFM_TYPE(request.ifr_media),
749 					&media)) {
750 				fprintf(stderr, "%s: Invalid parameter for option 'media': "
751 					"'%s'\n", kProgramName, args[i + 1]);
752 				exit(1);
753 			}
754 			i++;
755 		} else if (!strcmp(args[i], "up") || !strcmp(args[i], "-down")) {
756 			addFlags |= IFF_UP;
757 		} else if (!strcmp(args[i], "down") || !strcmp(args[i], "-up")) {
758 			removeFlags |= IFF_UP;
759 		} else if (!strcmp(args[i], "bcast")) {
760 			addFlags |= IFF_BROADCAST;
761 		} else if (!strcmp(args[i], "-bcast")) {
762 			removeFlags |= IFF_BROADCAST;
763 		} else if (!strcmp(args[i], "promisc")) {
764 			addFlags |= IFF_PROMISC;
765 		} else if (!strcmp(args[i], "-promisc")) {
766 			removeFlags |= IFF_PROMISC;
767 		} else if (!strcmp(args[i], "allmulti")) {
768 			addFlags |= IFF_ALLMULTI;
769 		} else if (!strcmp(args[i], "-allmulti")) {
770 			removeFlags |= IFF_ALLMULTI;
771 		} else if (!strcmp(args[i], "loopback")) {
772 			addFlags |= IFF_LOOPBACK;
773 		} else if (!strcmp(args[i], "auto-config")) {
774 			doAutoConfig = true;
775 		} else
776 			usage(1);
777 
778 		i++;
779 	}
780 
781 	if ((addFlags & removeFlags) != 0) {
782 		fprintf(stderr, "%s: Contradicting flags specified\n", kProgramName);
783 		exit(1);
784 	}
785 
786 	if (doAutoConfig && (hasAddress || hasMask || hasBroadcast || hasPeer)) {
787 		fprintf(stderr, "%s: Contradicting changes specified\n", kProgramName);
788 		exit(1);
789 	}
790 
791 	// set address/mask/broadcast/peer
792 
793 	if (hasAddress) {
794 		memcpy(&request.ifr_addr, &address, address.sa_len);
795 
796 		if (ioctl(socket, SIOCSIFADDR, &request, sizeof(struct ifreq)) < 0) {
797 			fprintf(stderr, "%s: Setting address failed: %s\n", kProgramName,
798 				strerror(errno));
799 			exit(1);
800 		}
801 	}
802 
803 	if (ioctl(socket, SIOCGIFFLAGS, &request, sizeof(struct ifreq)) < 0) {
804 		fprintf(stderr, "%s: Getting flags failed: %s\n", kProgramName,
805 			strerror(errno));
806 		exit(1);
807 	}
808 	currentFlags = request.ifr_flags;
809 
810 	if (hasMask) {
811 		memcpy(&request.ifr_mask, &mask, mask.sa_len);
812 
813 		if (ioctl(socket, SIOCSIFNETMASK, &request, sizeof(struct ifreq)) < 0) {
814 			fprintf(stderr, "%s: Setting subnet mask failed: %s\n",
815 				kProgramName, strerror(errno));
816 			exit(1);
817 		}
818 	}
819 
820 	if (hasBroadcast) {
821 		memcpy(&request.ifr_broadaddr, &broadcast, broadcast.sa_len);
822 
823 		if (ioctl(socket, SIOCSIFBRDADDR, &request, sizeof(struct ifreq)) < 0) {
824 			fprintf(stderr, "%s: Setting broadcast address failed: %s\n",
825 				kProgramName, strerror(errno));
826 			exit(1);
827 		}
828 	}
829 
830 	if (hasPeer) {
831 		memcpy(&request.ifr_dstaddr, &peer, peer.sa_len);
832 
833 		if (ioctl(socket, SIOCSIFDSTADDR, &request, sizeof(struct ifreq)) < 0) {
834 			fprintf(stderr, "%s: Setting peer address failed: %s\n",
835 				kProgramName, strerror(errno));
836 			exit(1);
837 		}
838 	}
839 
840 	// set flags
841 
842 	if (hasAddress || hasMask || hasBroadcast || hasPeer)
843 		removeFlags = IFF_AUTO_CONFIGURED | IFF_CONFIGURING;
844 
845 	if (addFlags || removeFlags) {
846 		request.ifr_flags = (currentFlags & ~removeFlags) | addFlags;
847 		if (ioctl(socket, SIOCSIFFLAGS, &request, sizeof(struct ifreq)) < 0) {
848 			fprintf(stderr, "%s: Setting flags failed: %s\n", kProgramName,
849 				strerror(errno));
850 		}
851 	}
852 
853 	// set options
854 
855 	if (mtu != -1) {
856 		request.ifr_mtu = mtu;
857 		if (ioctl(socket, SIOCSIFMTU, &request, sizeof(struct ifreq)) < 0) {
858 			fprintf(stderr, "%s: Setting MTU failed: %s\n", kProgramName,
859 				strerror(errno));
860 		}
861 	}
862 
863 	if (metric != -1) {
864 		request.ifr_metric = metric;
865 		if (ioctl(socket, SIOCSIFMETRIC, &request, sizeof(struct ifreq)) < 0) {
866 			fprintf(stderr, "%s: Setting metric failed: %s\n", kProgramName,
867 				strerror(errno));
868 		}
869 	}
870 
871 	if (media != -1) {
872 		request.ifr_media = media;
873 		if (ioctl(socket, SIOCSIFMEDIA, &request, sizeof(struct ifreq)) < 0) {
874 			fprintf(stderr, "%s: Setting media failed: %s\n", kProgramName,
875 				strerror(errno));
876 		}
877 	}
878 
879 	// start auto configuration, if asked for
880 
881 	if (doAutoConfig) {
882 		BMessage message(kMsgConfigureInterface);
883 		message.AddString("device", name);
884 		BMessage address;
885 		address.AddString("family", kFamilies[familyIndex].name);
886 		address.AddBool("auto_config", true);
887 		message.AddMessage("address", &address);
888 
889 		BMessenger networkServer(kNetServerSignature);
890 		if (networkServer.IsValid()) {
891 			BMessage reply;
892 			status_t status = networkServer.SendMessage(&message, &reply);
893 			if (status != B_OK) {
894 				fprintf(stderr, "%s: Sending auto-config message failed: %s\n",
895 					kProgramName, strerror(status));
896 			} else if (reply.FindInt32("status", &status) == B_OK
897 					&& status != B_OK) {
898 				fprintf(stderr, "%s: Auto-configuring failed: %s\n",
899 					kProgramName, strerror(status));
900 			}
901 		} else {
902 			fprintf(stderr, "%s: The net_server needs to run for the auto "
903 				"configuration!\n", kProgramName);
904 		}
905 	}
906 }
907 
908 
909 //	#pragma mark -
910 
911 
912 int
913 main(int argc, char** argv)
914 {
915 	if (argc > 1 && (!strcmp(argv[1], "--help") || !strcmp(argv[1], "-h")))
916 		usage(0);
917 
918 	if (!initialize_address_families()) {
919 		fprintf(stderr, "%s: The networking stack doesn't seem to be "
920 			"available.\n", kProgramName);
921 		return 1;
922 	}
923 
924 	if (argc > 1
925 		&& (!strcmp(argv[1], "--delete")
926 			|| !strcmp(argv[1], "--del")
927 			|| !strcmp(argv[1], "-d")
928 			|| !strcmp(argv[1], "del")
929 			|| !strcmp(argv[1], "delete"))) {
930 		// Delete interface (addresses)
931 
932 		if (argc < 3)
933 			usage(1);
934 
935 		const char* name = argv[2];
936 		delete_interface(name, argv + 3, argc - 3);
937 		return 0;
938 	}
939 
940 	if (argc > 1 && !strcmp(argv[1], "-a")) {
941 		// Accept an optional "-a" option to list all interfaces for those
942 		// that are used to it from other platforms.
943 
944 		if (argc > 2)
945 			usage(1);
946 
947 		list_interfaces(NULL);
948 		return 0;
949 	}
950 
951 	const char* name = argv[1];
952 	if (argc > 2) {
953 		// Add or configure an interface
954 
955 		configure_interface(name, argv + 2, argc - 2);
956 		return 0;
957 	}
958 
959 	// list interfaces
960 
961 	list_interfaces(name);
962 	return 0;
963 }
964 
965