xref: /haiku/src/bin/network/ifconfig/ifconfig.cpp (revision 4b3b81da9e459443d75329cfd08bc9a57ad02653)
1 /*
2  * Copyright 2006-2008, 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  */
9 
10 
11 #include <SupportDefs.h>
12 
13 #include <arpa/inet.h>
14 #include <net/if.h>
15 #include <net/if_dl.h>
16 #include <net/if_media.h>
17 #include <net/if_types.h>
18 #include <netinet/in.h>
19 #include <sys/socket.h>
20 #include <sys/sockio.h>
21 
22 #include <errno.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <unistd.h>
27 
28 
29 extern const char* __progname;
30 const char* kProgramName = __progname;
31 
32 
33 struct address_family {
34 	int			family;
35 	const char*	name;
36 	const char*	identifiers[4];
37 	bool		(*parse_address)(const char* string, sockaddr* _address);
38 	void		(*print_address)(sockaddr* address);
39 };
40 
41 // AF_INET family
42 static bool inet_parse_address(const char* string, sockaddr* address);
43 static void inet_print_address(sockaddr* address);
44 
45 static const address_family kFamilies[] = {
46 	{
47 		AF_INET,
48 		"inet",
49 		{"AF_INET", "inet", "ipv4", NULL},
50 		inet_parse_address,
51 		inet_print_address
52 	},
53 	{ -1, NULL, {NULL}, NULL, NULL }
54 };
55 
56 
57 static bool
58 inet_parse_address(const char* string, sockaddr* _address)
59 {
60 	in_addr inetAddress;
61 
62 	if (inet_aton(string, &inetAddress) != 1)
63 		return false;
64 
65 	sockaddr_in& address = *(sockaddr_in *)_address;
66 	address.sin_family = AF_INET;
67 	address.sin_len = sizeof(struct sockaddr_in);
68 	address.sin_port = 0;
69 	address.sin_addr = inetAddress;
70 	memset(&address.sin_zero[0], 0, sizeof(address.sin_zero));
71 
72 	return true;
73 }
74 
75 
76 static void
77 inet_print_address(sockaddr* _address)
78 {
79 	sockaddr_in& address = *(sockaddr_in *)_address;
80 
81 	if (address.sin_family != AF_INET)
82 		return;
83 
84 	printf("%s", inet_ntoa(address.sin_addr));
85 }
86 
87 
88 //	#pragma mark -
89 
90 
91 struct media_type {
92 	int			type;
93 	const char*	name;
94 	const char* pretty;
95 	struct {
96 		int subtype;
97 		const char* name;
98 		const char* pretty;
99 	} subtypes [6];
100 	struct {
101 		int option;
102 		bool ro;
103 		const char* name;
104 		const char* pretty;
105 	} options [6];
106 };
107 
108 
109 static const media_type kMediaTypes[] = {
110 	{
111 		0, // for generic options
112 		"all",
113 		"All",
114 		{
115 			{ IFM_AUTO, "auto", "Auto-select" },
116 			{ -1, NULL, NULL }
117 		},
118 		{
119 			{ IFM_FULL_DUPLEX, true, "fullduplex", "Full Duplex" },
120 			{ IFM_HALF_DUPLEX, true, "halfduplex", "Half Duplex" },
121 			{ IFM_LOOP, true, "loop", "Loop" },
122 			//{ IFM_ACTIVE, false, "active", "Active" },
123 			{ -1, false, NULL, NULL }
124 		}
125 	},
126 	{
127 		IFM_ETHER,
128 		"ether",
129 		"Ethernet",
130 		{
131 			//{ IFM_AUTO, "auto", "Auto-select" },
132 			//{ IFM_AUI, "AUI", "10 MBit, AUI" },
133 			//{ IFM_10_2, "10base2", "10 MBit, 10BASE-2" },
134 			{ IFM_10_T, "10baseT", "10 MBit, 10BASE-T" },
135 			{ IFM_100_TX, "100baseTX", "100 MBit, 100BASE-TX" },
136 			{ IFM_1000_T, "1000baseT", "1 GBit, 1000BASE-T" },
137 			{ IFM_1000_SX, "1000baseSX", "1 GBit, 1000BASE-SX" },
138 			{ -1, NULL, NULL }
139 		},
140 		{
141 			{ -1, false, NULL, NULL }
142 		}
143 	},
144 	{ -1, NULL, NULL, {{ -1, NULL, NULL }}, {{ -1, false, NULL, NULL }} }
145 };
146 
147 
148 static bool media_parse_subtype(const char* string, int media, int* type);
149 
150 
151 static bool
152 media_parse_subtype(const char* string, int media, int* type)
153 {
154 	for (int32 i = 0; kMediaTypes[i].type >= 0; i++) {
155 		// only check for generic or correct subtypes
156 		if (kMediaTypes[i].type &&
157 			kMediaTypes[i].type != media)
158 			continue;
159 		for (int32 j = 0; kMediaTypes[i].subtypes[j].subtype >= 0; j++) {
160 			if (strcmp(kMediaTypes[i].subtypes[j].name, string) == 0) {
161 				// found a match
162 				*type = kMediaTypes[i].subtypes[j].subtype;
163 				return true;
164 			}
165 		}
166 	}
167 	return false;
168 }
169 
170 
171 //	#pragma mark -
172 
173 
174 void
175 usage(int status)
176 {
177 	printf("usage: %s [<interface> [<address family>] [<address> [<mask>]] [<option/flags>...]]\n"
178 		"\t%s --delete interface [...]\n\n"
179 		"Where <option> can be the following:\n"
180 		"  netmask <addr>   - networking subnet mask\n"
181 		"  broadcast <addr> - set broadcast address\n"
182 		"  peer <addr>      - ppp-peer address\n"
183 		"  mtu <bytes>      - maximal transfer unit\n"
184 		"  metric <number>  - metric number to use (defaults to 0)\n"
185 		"  media <media>    - media type to use (defaults to auto)\n",
186 		kProgramName, kProgramName);
187 	for (int32 i = 0; kMediaTypes[i].type >= 0; i++) {
188 		printf("For %s <media> can be one of: ", kMediaTypes[i].pretty);
189 		for (int32 j = 0; kMediaTypes[i].subtypes[j].subtype >= 0; j++)
190 			printf("%s ", kMediaTypes[i].subtypes[j].name);
191 		printf("\n");
192 	}
193 	printf("And <flags> can be: up, down, [-]promisc, [-]allmulti, [-]bcast, loopback\n\n"
194 		"Example:\n"
195 		"\t%s loop 127.0.0.1 255.0.0.0 up\n",
196 		kProgramName);
197 
198 	exit(status);
199 }
200 
201 
202 bool
203 prepare_request(struct ifreq& request, const char* name)
204 {
205 	if (strlen(name) > IF_NAMESIZE) {
206 		fprintf(stderr, "%s: interface name \"%s\" is too long.\n", kProgramName, name);
207 		return false;
208 	}
209 
210 	strcpy(request.ifr_name, name);
211 	return true;
212 }
213 
214 
215 bool
216 get_address_family(const char* argument, int32& familyIndex)
217 {
218 	for (int32 i = 0; kFamilies[i].family >= 0; i++) {
219 		for (int32 j = 0; kFamilies[i].identifiers[j]; j++) {
220 			if (!strcmp(argument, kFamilies[i].identifiers[j])) {
221 				// found a match
222 				familyIndex = i;
223 				return true;
224 			}
225 		}
226 	}
227 
228 	// defaults to AF_INET
229 	familyIndex = 0;
230 	return false;
231 }
232 
233 
234 bool
235 parse_address(int32 familyIndex, const char* argument, struct sockaddr& address)
236 {
237 	if (argument == NULL)
238 		return false;
239 
240 	return kFamilies[familyIndex].parse_address(argument, &address);
241 }
242 
243 
244 //	#pragma mark -
245 
246 
247 void
248 list_interface(int socket, const char* name)
249 {
250 	ifreq request;
251 	if (!prepare_request(request, name))
252 		return;
253 
254 	if (ioctl(socket, SIOCGIFINDEX, &request, sizeof(request)) < 0) {
255 		fprintf(stderr, "%s: Interface \"%s\" does not exist.\n", kProgramName, name);
256 		return;
257 	}
258 
259 	printf("%s", name);
260 	size_t length = strlen(name);
261 	if (length < 8)
262 		putchar('\t');
263 	else
264 		printf("\n\t");
265 
266 	// get link level interface for this interface
267 
268 	int linkSocket = ::socket(AF_LINK, SOCK_DGRAM, 0);
269 	if (linkSocket < 0) {
270 		printf("No link level: %s\n", strerror(errno));
271 	} else {
272 		const char *type = "unknown";
273 		char address[256];
274 		strcpy(address, "none");
275 
276 		if (ioctl(socket, SIOCGIFPARAM, &request, sizeof(struct ifreq)) == 0) {
277 			prepare_request(request, request.ifr_parameter.device);
278 			if (ioctl(linkSocket, SIOCGIFADDR, &request, sizeof(struct ifreq)) == 0) {
279 				sockaddr_dl &link = *(sockaddr_dl *)&request.ifr_addr;
280 
281 				switch (link.sdl_type) {
282 					case IFT_ETHER:
283 					{
284 						type = "Ethernet";
285 
286 						if (link.sdl_alen > 0) {
287 							uint8 *mac = (uint8 *)LLADDR(&link);
288 							sprintf(address, "%02x:%02x:%02x:%02x:%02x:%02x",
289 								mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
290 						} else
291 							strcpy(address, "not available");
292 						break;
293 					}
294 					case IFT_LOOP:
295 						type = "Local Loopback";
296 						break;
297 					case IFT_MODEM:
298 						type = "Modem";
299 						break;
300 				}
301 			}
302 		}
303 
304 		printf("Hardware Type: %s, Address: %s\n", type, address);
305 		close(linkSocket);
306 	}
307 
308 	if (ioctl(socket, SIOCGIFMEDIA, &request, sizeof(struct ifreq)) == 0
309 		&& (request.ifr_media & IFM_ACTIVE) != 0) {
310 		// dump media state in case we're linked
311 		const char* type = "unknown";
312 		bool show = false;
313 
314 		for (int32 i = 0; kMediaTypes[i].type >= 0; i++) {
315 			// loopback don't really have a media anyway
316 			if (IFM_TYPE(request.ifr_media) == 0/*IFT_LOOP*/)
317 				break;
318 			// only check for generic or correct subtypes
319 			if (kMediaTypes[i].type &&
320 				kMediaTypes[i].type != IFM_TYPE(request.ifr_media))
321 				continue;
322 			for (int32 j = 0; kMediaTypes[i].subtypes[j].subtype >= 0; j++) {
323 				if (kMediaTypes[i].subtypes[j].subtype == IFM_SUBTYPE(request.ifr_media)) {
324 					// found a match
325 					type = kMediaTypes[i].subtypes[j].pretty;
326 					show = true;
327 					break;
328 				}
329 			}
330 		}
331 
332 		if (show)
333 			printf("\tMedia Type: %s\n", type);
334 	}
335 
336 	uint32 flags = 0;
337 	if (ioctl(socket, SIOCGIFFLAGS, &request, sizeof(struct ifreq)) == 0)
338 		flags = request.ifr_flags;
339 
340 	for (int32 i = 0; kFamilies[i].family >= 0; i++) {
341 		int familySocket = ::socket(kFamilies[i].family, SOCK_DGRAM, 0);
342 		if (familySocket < 0)
343 			continue;
344 
345 		if (ioctl(familySocket, SIOCGIFADDR, &request, sizeof(struct ifreq)) == 0) {
346 			printf("\t%s addr: ", kFamilies[i].name);
347 			kFamilies[i].print_address(&request.ifr_addr);
348 
349 			if ((flags & IFF_BROADCAST) != 0
350 				&& ioctl(familySocket, SIOCGIFBRDADDR, &request, sizeof(struct ifreq)) == 0
351 				&& request.ifr_broadaddr.sa_family == kFamilies[i].family) {
352 				printf(", Bcast: ");
353 				kFamilies[i].print_address(&request.ifr_broadaddr);
354 			}
355 			if (ioctl(familySocket, SIOCGIFNETMASK, &request, sizeof(struct ifreq)) == 0
356 				&& request.ifr_mask.sa_family == kFamilies[i].family) {
357 				printf(", Mask: ");
358 				kFamilies[i].print_address(&request.ifr_mask);
359 			}
360 			putchar('\n');
361 		}
362 
363 		close(familySocket);
364 	}
365 
366 	// Print MTU, metric, flags
367 
368 	printf("\tMTU: ");
369 	if (ioctl(socket, SIOCGIFMTU, &request, sizeof(struct ifreq)) == 0)
370 		printf("%d", request.ifr_mtu);
371 	else
372 		printf("-");
373 
374 	printf(", Metric: ");
375 	if (ioctl(socket, SIOCGIFMETRIC, &request, sizeof(struct ifreq)) == 0)
376 		printf("%d", request.ifr_metric);
377 	else
378 		printf("-");
379 
380 	if (flags != 0) {
381 		const struct {
382 			int			value;
383 			const char	*name;
384 		} kFlags[] = {
385 			{IFF_UP, "up"},
386 			{IFF_NOARP, "noarp"},
387 			{IFF_BROADCAST, "broadcast"},
388 			{IFF_LOOPBACK, "loopback"},
389 			{IFF_PROMISC, "promiscuous"},
390 			{IFF_ALLMULTI, "allmulti"},
391 			{IFF_AUTOUP, "autoup"},
392 			{IFF_LINK, "link"},
393 			{IFF_AUTO_CONFIGURED, "auto-configured"},
394 			{IFF_CONFIGURING, "configuring"},
395 		};
396 		bool first = true;
397 
398 		for (uint32 i = 0; i < sizeof(kFlags) / sizeof(kFlags[0]); i++) {
399 			if ((flags & kFlags[i].value) != 0) {
400 				if (first) {
401 					printf(",");
402 					first = false;
403 				}
404 				putchar(' ');
405 				printf(kFlags[i].name);
406 			}
407 		}
408 	}
409 
410 	putchar('\n');
411 
412 	// Print statistics
413 
414 	if (ioctl(socket, SIOCGIFSTATS, &request, sizeof(struct ifreq)) == 0) {
415 		printf("\tReceive: %d packets, %d errors, %Ld bytes, %d mcasts, %d dropped\n",
416 			request.ifr_stats.receive.packets, request.ifr_stats.receive.errors,
417 			request.ifr_stats.receive.bytes, request.ifr_stats.receive.multicast_packets,
418 			request.ifr_stats.receive.dropped);
419 		printf("\tTransmit: %d packets, %d errors, %Ld bytes, %d mcasts, %d dropped\n",
420 			request.ifr_stats.send.packets, request.ifr_stats.send.errors,
421 			request.ifr_stats.send.bytes, request.ifr_stats.send.multicast_packets,
422 			request.ifr_stats.send.dropped);
423 		printf("\tCollisions: %d\n", request.ifr_stats.collisions);
424 	}
425 
426 	putchar('\n');
427 }
428 
429 
430 void
431 list_interfaces(int socket, const char* name)
432 {
433 	if (name != NULL) {
434 		list_interface(socket, name);
435 		return;
436 	}
437 
438 	// get a list of all interfaces
439 
440 	ifconf config;
441 	config.ifc_len = sizeof(config.ifc_value);
442 	if (ioctl(socket, SIOCGIFCOUNT, &config, sizeof(struct ifconf)) < 0)
443 		return;
444 
445 	uint32 count = (uint32)config.ifc_value;
446 	if (count == 0) {
447 		fprintf(stderr, "%s: There are no interfaces yet!\n", kProgramName);
448 		return;
449 	}
450 
451 	void *buffer = malloc(count * sizeof(struct ifreq));
452 	if (buffer == NULL) {
453 		fprintf(stderr, "%s: Out of memory.\n", kProgramName);
454 		return;
455 	}
456 
457 	config.ifc_len = count * sizeof(struct ifreq);
458 	config.ifc_buf = buffer;
459 	if (ioctl(socket, SIOCGIFCONF, &config, sizeof(struct ifconf)) < 0)
460 		return;
461 
462 	ifreq *interface = (ifreq *)buffer;
463 
464 	for (uint32 i = 0; i < count; i++) {
465 		list_interface(socket, interface->ifr_name);
466 
467 		interface = (ifreq *)((addr_t)interface + IF_NAMESIZE + interface->ifr_addr.sa_len);
468 	}
469 
470 	free(buffer);
471 }
472 
473 
474 void
475 delete_interface(int socket, const char* name)
476 {
477 	ifreq request;
478 	if (!prepare_request(request, name))
479 		return;
480 
481 	if (ioctl(socket, SIOCDIFADDR, &request, sizeof(request)) < 0) {
482 		fprintf(stderr, "%s: Could not delete interface %s: %s\n",
483 			kProgramName, name, strerror(errno));
484 	}
485 }
486 
487 
488 void
489 configure_interface(int socket, const char* name, char* const* args,
490 	int32 argCount)
491 {
492 	ifreq request;
493 	if (!prepare_request(request, name))
494 		return;
495 
496 	uint32 index = 0;
497 	if (ioctl(socket, SIOCGIFINDEX, &request, sizeof(request)) >= 0)
498 		index = request.ifr_index;
499 
500 	bool hasAddress = false, hasMask = false, hasPeer = false, hasBroadcast = false;
501 	struct sockaddr address, mask, peer, broadcast;
502 	int mtu = -1, metric = -1, media = -1;
503 	int addFlags = 0, removeFlags = 0, currentFlags = 0;
504 
505 	// try to parse address family
506 
507 	int32 familyIndex;
508 	int32 i = 0;
509 	if (get_address_family(args[i], familyIndex))
510 		i++;
511 
512 	if (kFamilies[familyIndex].family != AF_INET) {
513 		close(socket);
514 
515 		// replace socket with one of the correct address family
516 		socket = ::socket(kFamilies[familyIndex].family, SOCK_DGRAM, 0);
517 		if (socket < 0) {
518 			fprintf(stderr, "%s: Address family \"%s\" is not available.\n",
519 				kProgramName, kFamilies[familyIndex].name);
520 			exit(1);
521 		}
522 	}
523 
524 	if (index == 0) {
525 		// the interface does not exist yet, we have to add it first
526 		request.ifr_parameter.base_name[0] = '\0';
527 		request.ifr_parameter.device[0] = '\0';
528 		request.ifr_parameter.sub_type = 0;
529 			// the default device is okay for us
530 
531 		if (ioctl(socket, SIOCAIFADDR, &request, sizeof(request)) < 0) {
532 			fprintf(stderr, "%s: Could not add interface: %s\n", kProgramName,
533 				strerror(errno));
534 			exit(1);
535 		}
536 	}
537 
538 	// try to parse address
539 
540 	if (parse_address(familyIndex, args[i], address)) {
541 		hasAddress = true;
542 		i++;
543 
544 		if (parse_address(familyIndex, args[i], mask)) {
545 			hasMask = true;
546 			i++;
547 		}
548 	}
549 
550 	// parse parameters and flags
551 
552 	while (i < argCount) {
553 		if (!strcmp(args[i], "peer")) {
554 			if (!parse_address(familyIndex, args[i + 1], peer)) {
555 				fprintf(stderr, "%s: Option 'peer' needs valid address parameter\n",
556 					kProgramName);
557 				exit(1);
558 			}
559 			hasPeer = true;
560 			i++;
561 		} else if (!strcmp(args[i], "nm") || !strcmp(args[i], "netmask")) {
562 			if (hasMask) {
563 				fprintf(stderr, "%s: Netmask is specified twice\n",
564 					kProgramName);
565 				exit(1);
566 			}
567 			if (!parse_address(familyIndex, args[i + 1], mask)) {
568 				fprintf(stderr, "%s: Option 'netmask' needs valid address parameter\n",
569 					kProgramName);
570 				exit(1);
571 			}
572 			hasMask = true;
573 			i++;
574 		} else if (!strcmp(args[i], "bc") || !strcmp(args[i], "broadcast")) {
575 			if (hasBroadcast) {
576 				fprintf(stderr, "%s: broadcast address is specified twice\n",
577 					kProgramName);
578 				exit(1);
579 			}
580 			if (!parse_address(familyIndex, args[i + 1], broadcast)) {
581 				fprintf(stderr, "%s: Option 'broadcast' needs valid address parameter\n",
582 					kProgramName);
583 				exit(1);
584 			}
585 			hasBroadcast = true;
586 			addFlags |= IFF_BROADCAST;
587 			i++;
588 		} else if (!strcmp(args[i], "mtu")) {
589 			mtu = args[i + 1] ? strtol(args[i + 1], NULL, 0) : 0;
590 			if (mtu <= 500) {
591 				fprintf(stderr, "%s: Option 'mtu' expected valid max transfer unit size\n",
592 					kProgramName);
593 				exit(1);
594 			}
595 			i++;
596 		} else if (!strcmp(args[i], "metric")) {
597 			if (i + 1 >= argCount) {
598 				fprintf(stderr, "%s: Option 'metric' exptected parameter\n",
599 					kProgramName);
600 				exit(1);
601 			}
602 			metric = strtol(args[i + 1], NULL, 0);
603 			i++;
604 		} else if (!strcmp(args[i], "media")) {
605 			if (ioctl(socket, SIOCGIFMEDIA, &request, sizeof(struct ifreq)) < 0) {
606 				fprintf(stderr, "%s: Unable to detect media type\n",
607 					kProgramName);
608 				exit(1);
609 			}
610 			if (i + 1 >= argCount) {
611 				fprintf(stderr, "%s: Option 'media' exptected parameter\n",
612 					kProgramName);
613 				exit(1);
614 			}
615 			if (!media_parse_subtype(args[i + 1], IFM_TYPE(request.ifr_media), &media)) {
616 				fprintf(stderr, "%s: Invalid parameter for option 'media': '%s'\n",
617 					kProgramName, args[i + 1]);
618 				exit(1);
619 			}
620 			i++;
621 		} else if (!strcmp(args[i], "up") || !strcmp(args[i], "-down")) {
622 			addFlags |= IFF_UP;
623 		} else if (!strcmp(args[i], "down") || !strcmp(args[i], "-up")) {
624 			removeFlags |= IFF_UP;
625 		} else if (!strcmp(args[i], "bcast")) {
626 			addFlags |= IFF_BROADCAST;
627 		} else if (!strcmp(args[i], "-bcast")) {
628 			removeFlags |= IFF_BROADCAST;
629 		} else if (!strcmp(args[i], "promisc")) {
630 			addFlags |= IFF_PROMISC;
631 		} else if (!strcmp(args[i], "-promisc")) {
632 			removeFlags |= IFF_PROMISC;
633 		} else if (!strcmp(args[i], "allmulti")) {
634 			addFlags |= IFF_ALLMULTI;
635 		} else if (!strcmp(args[i], "-allmulti")) {
636 			removeFlags |= IFF_ALLMULTI;
637 		} else if (!strcmp(args[i], "loopback")) {
638 			addFlags |= IFF_LOOPBACK;
639 		} else
640 			usage(1);
641 
642 		i++;
643 	}
644 
645 	if ((addFlags & removeFlags) != 0) {
646 		fprintf(stderr, "%s: Contradicting flags specified\n", kProgramName);
647 		exit(1);
648 	}
649 
650 	// set address/mask/broadcast/peer
651 
652 	if (hasAddress) {
653 		memcpy(&request.ifr_addr, &address, address.sa_len);
654 
655 		if (ioctl(socket, SIOCSIFADDR, &request, sizeof(struct ifreq)) < 0) {
656 			fprintf(stderr, "%s: Setting address failed: %s\n", kProgramName, strerror(errno));
657 			exit(1);
658 		}
659 	}
660 
661 	if (ioctl(socket, SIOCGIFFLAGS, &request, sizeof(struct ifreq)) < 0) {
662 		fprintf(stderr, "%s: Getting flags failed: %s\n", kProgramName, strerror(errno));
663 		exit(1);
664 	}
665 	currentFlags = request.ifr_flags;
666 
667 	if (hasMask) {
668 		memcpy(&request.ifr_mask, &mask, mask.sa_len);
669 
670 		if (ioctl(socket, SIOCSIFNETMASK, &request, sizeof(struct ifreq)) < 0) {
671 			fprintf(stderr, "%s: Setting subnet mask failed: %s\n", kProgramName, strerror(errno));
672 			exit(1);
673 		}
674 	}
675 
676 	if (hasBroadcast) {
677 		memcpy(&request.ifr_broadaddr, &broadcast, broadcast.sa_len);
678 
679 		if (ioctl(socket, SIOCSIFBRDADDR, &request, sizeof(struct ifreq)) < 0) {
680 			fprintf(stderr, "%s: Setting broadcast address failed: %s\n", kProgramName, strerror(errno));
681 			exit(1);
682 		}
683 	}
684 
685 	if (hasPeer) {
686 		memcpy(&request.ifr_dstaddr, &peer, peer.sa_len);
687 
688 		if (ioctl(socket, SIOCSIFDSTADDR, &request, sizeof(struct ifreq)) < 0) {
689 			fprintf(stderr, "%s: Setting peer address failed: %s\n", kProgramName, strerror(errno));
690 			exit(1);
691 		}
692 	}
693 
694 	// set flags
695 
696 	if (addFlags || removeFlags) {
697 		request.ifr_flags = (currentFlags & ~removeFlags) | addFlags;
698 		if (ioctl(socket, SIOCSIFFLAGS, &request, sizeof(struct ifreq)) < 0)
699 			fprintf(stderr, "%s: Setting flags failed: %s\n", kProgramName, strerror(errno));
700 	}
701 
702 	// set options
703 
704 	if (mtu != -1) {
705 		request.ifr_mtu = mtu;
706 		if (ioctl(socket, SIOCSIFMTU, &request, sizeof(struct ifreq)) < 0)
707 			fprintf(stderr, "%s: Setting MTU failed: %s\n", kProgramName, strerror(errno));
708 	}
709 
710 	if (metric != -1) {
711 		request.ifr_metric = metric;
712 		if (ioctl(socket, SIOCSIFMETRIC, &request, sizeof(struct ifreq)) < 0)
713 			fprintf(stderr, "%s: Setting metric failed: %s\n", kProgramName, strerror(errno));
714 	}
715 
716 	if (media != -1) {
717 		request.ifr_media = media;
718 		if (ioctl(socket, SIOCSIFMEDIA, &request, sizeof(struct ifreq)) < 0)
719 			fprintf(stderr, "%s: Setting media failed: %s\n", kProgramName, strerror(errno));
720 	}
721 }
722 
723 
724 //	#pragma mark -
725 
726 
727 int
728 main(int argc, char** argv)
729 {
730 	if (argc > 1 && (!strcmp(argv[1], "--help") || !strcmp(argv[1], "-h")))
731 		usage(0);
732 
733 	bool deleteInterfaces = false;
734 
735 	if (argc > 1
736 		&& (!strcmp(argv[1], "--delete")
737 			|| !strcmp(argv[1], "--del")
738 			|| !strcmp(argv[1], "-d"))) {
739 		// delete interfaces
740 		if (argc < 3)
741 			usage(1);
742 
743 		deleteInterfaces = true;
744 	}
745 
746 	// we need a socket to talk to the networking stack
747 	int socket = ::socket(AF_INET, SOCK_DGRAM, 0);
748 	if (socket < 0) {
749 		fprintf(stderr, "%s: The networking stack doesn't seem to be available.\n",
750 			kProgramName);
751 		return 1;
752 	}
753 
754 	if (deleteInterfaces) {
755 		for (int i = 2; i < argc; i++) {
756 			delete_interface(socket, argv[i]);
757 		}
758 		return 0;
759 	} else if (argc > 1 && !strcmp(argv[1], "-a")) {
760 		// accept -a option for those that are used to it from other platforms
761 		if (argc > 2)
762 			usage(1);
763 
764 		list_interfaces(socket, NULL);
765 		return 0;
766 	}
767 
768 	const char* name = argv[1];
769 	if (argc > 2) {
770 		// add or configure an interface
771 
772 		configure_interface(socket, name, argv + 2, argc - 2);
773 		return 0;
774 	}
775 
776 	// list interfaces
777 
778 	list_interfaces(socket, name);
779 	return 0;
780 }
781 
782