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