xref: /haiku/src/bin/network/ifconfig/ifconfig.cpp (revision 0c93c0a807b27096abbfad677436afb7d1712d4a)
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_10_T:
227 						type = "10 MBit, 10BASE-T";
228 						break;
229 					case IFM_100_TX:
230 						type = "100 MBit, 100BASE-TX";
231 						break;
232 					case IFM_1000_T:
233 						type = "1 GBit, 1000BASE-T";
234 						break;
235 					case IFM_1000_SX:
236 						type = "1 GBit, 1000BASE-SX";
237 						break;
238 				}
239 				break;
240 
241 			default:
242 				show = false;
243 				break;
244 		}
245 
246 		if (show)
247 			printf("\tMedia Type: %s\n", type);
248 	}
249 
250 	uint32 flags = 0;
251 	if (ioctl(socket, SIOCGIFFLAGS, &request, sizeof(struct ifreq)) == 0)
252 		flags = request.ifr_flags;
253 
254 	for (int32 i = 0; kFamilies[i].family >= 0; i++) {
255 		int familySocket = ::socket(kFamilies[i].family, SOCK_DGRAM, 0);
256 		if (familySocket < 0)
257 			continue;
258 
259 		if (ioctl(familySocket, SIOCGIFADDR, &request, sizeof(struct ifreq)) == 0) {
260 			printf("\t%s addr: ", kFamilies[i].name);
261 			kFamilies[i].print_address(&request.ifr_addr);
262 
263 			if ((flags & IFF_BROADCAST) != 0
264 				&& ioctl(familySocket, SIOCGIFBRDADDR, &request, sizeof(struct ifreq)) == 0
265 				&& request.ifr_broadaddr.sa_family == kFamilies[i].family) {
266 				printf(", Bcast: ");
267 				kFamilies[i].print_address(&request.ifr_broadaddr);
268 			}
269 			if (ioctl(familySocket, SIOCGIFNETMASK, &request, sizeof(struct ifreq)) == 0
270 				&& request.ifr_mask.sa_family == kFamilies[i].family) {
271 				printf(", Mask: ");
272 				kFamilies[i].print_address(&request.ifr_mask);
273 			}
274 			putchar('\n');
275 		}
276 
277 		close(familySocket);
278 	}
279 
280 	// Print MTU, metric, flags
281 
282 	printf("\tMTU: ");
283 	if (ioctl(socket, SIOCGIFMTU, &request, sizeof(struct ifreq)) == 0)
284 		printf("%d", request.ifr_mtu);
285 	else
286 		printf("-");
287 
288 	printf(", Metric: ");
289 	if (ioctl(socket, SIOCGIFMETRIC, &request, sizeof(struct ifreq)) == 0)
290 		printf("%d", request.ifr_metric);
291 	else
292 		printf("-");
293 
294 	if (flags != 0) {
295 		const struct {
296 			int			value;
297 			const char	*name;
298 		} kFlags[] = {
299 			{IFF_UP, "up"},
300 			{IFF_NOARP, "noarp"},
301 			{IFF_BROADCAST, "broadcast"},
302 			{IFF_LOOPBACK, "loopback"},
303 			{IFF_PROMISC, "promiscuous"},
304 			{IFF_ALLMULTI, "allmulti"},
305 			{IFF_AUTOUP, "autoup"},
306 			{IFF_LINK, "link"},
307 			{IFF_AUTO_CONFIGURED, "auto-configured"},
308 			{IFF_CONFIGURING, "configuring"},
309 		};
310 		bool first = true;
311 
312 		for (uint32 i = 0; i < sizeof(kFlags) / sizeof(kFlags[0]); i++) {
313 			if ((flags & kFlags[i].value) != 0) {
314 				if (first) {
315 					printf(",");
316 					first = false;
317 				}
318 				putchar(' ');
319 				printf(kFlags[i].name);
320 			}
321 		}
322 	}
323 
324 	putchar('\n');
325 
326 	// Print statistics
327 
328 	if (ioctl(socket, SIOCGIFSTATS, &request, sizeof(struct ifreq)) == 0) {
329 		printf("\tReceive: %ld packets, %ld errors, %Ld bytes, %ld mcasts, %ld dropped\n",
330 			request.ifr_stats.receive.packets, request.ifr_stats.receive.errors,
331 			request.ifr_stats.receive.bytes, request.ifr_stats.receive.multicast_packets,
332 			request.ifr_stats.receive.dropped);
333 		printf("\tTransmit: %ld packets, %ld errors, %Ld bytes, %ld mcasts, %ld dropped\n",
334 			request.ifr_stats.send.packets, request.ifr_stats.send.errors,
335 			request.ifr_stats.send.bytes, request.ifr_stats.send.multicast_packets,
336 			request.ifr_stats.send.dropped);
337 		printf("\tCollisions: %ld\n", request.ifr_stats.collisions);
338 	}
339 
340 	putchar('\n');
341 }
342 
343 
344 void
345 list_interfaces(int socket, const char* name)
346 {
347 	if (name != NULL) {
348 		list_interface(socket, name);
349 		return;
350 	}
351 
352 	// get a list of all interfaces
353 
354 	ifconf config;
355 	config.ifc_len = sizeof(config.ifc_value);
356 	if (ioctl(socket, SIOCGIFCOUNT, &config, sizeof(struct ifconf)) < 0)
357 		return;
358 
359 	uint32 count = (uint32)config.ifc_value;
360 	if (count == 0) {
361 		fprintf(stderr, "%s: There are no interfaces yet!\n", kProgramName);
362 		return;
363 	}
364 
365 	void *buffer = malloc(count * sizeof(struct ifreq));
366 	if (buffer == NULL) {
367 		fprintf(stderr, "%s: Out of memory.\n", kProgramName);
368 		return;
369 	}
370 
371 	config.ifc_len = count * sizeof(struct ifreq);
372 	config.ifc_buf = buffer;
373 	if (ioctl(socket, SIOCGIFCONF, &config, sizeof(struct ifconf)) < 0)
374 		return;
375 
376 	ifreq *interface = (ifreq *)buffer;
377 
378 	for (uint32 i = 0; i < count; i++) {
379 		list_interface(socket, interface->ifr_name);
380 
381 		interface = (ifreq *)((addr_t)interface + IF_NAMESIZE + interface->ifr_addr.sa_len);
382 	}
383 
384 	free(buffer);
385 }
386 
387 
388 void
389 delete_interface(int socket, const char* name)
390 {
391 	ifreq request;
392 	if (!prepare_request(request, name))
393 		return;
394 
395 	if (ioctl(socket, SIOCDIFADDR, &request, sizeof(request)) < 0) {
396 		fprintf(stderr, "%s: Could not delete interface %s: %s\n",
397 			kProgramName, name, strerror(errno));
398 	}
399 }
400 
401 
402 void
403 configure_interface(int socket, const char* name, char* const* args,
404 	int32 argCount)
405 {
406 	ifreq request;
407 	if (!prepare_request(request, name))
408 		return;
409 
410 	uint32 index = 0;
411 	if (ioctl(socket, SIOCGIFINDEX, &request, sizeof(request)) >= 0)
412 		index = request.ifr_index;
413 
414 	bool hasAddress = false, hasMask = false, hasPeer = false, hasBroadcast = false;
415 	struct sockaddr address, mask, peer, broadcast;
416 	int mtu = -1, metric = -1, addFlags = 0, removeFlags = 0, currentFlags = 0;
417 
418 	// try to parse address family
419 
420 	int32 familyIndex;
421 	int32 i = 0;
422 	if (get_address_family(args[i], familyIndex))
423 		i++;
424 
425 	if (kFamilies[familyIndex].family != AF_INET) {
426 		close(socket);
427 
428 		// replace socket with one of the correct address family
429 		socket = ::socket(kFamilies[familyIndex].family, SOCK_DGRAM, 0);
430 		if (socket < 0) {
431 			fprintf(stderr, "%s: Address family \"%s\" is not available.\n",
432 				kProgramName, kFamilies[familyIndex].name);
433 			exit(1);
434 		}
435 	}
436 
437 	if (index == 0) {
438 		// the interface does not exist yet, we have to add it first
439 		request.ifr_parameter.base_name[0] = '\0';
440 		request.ifr_parameter.device[0] = '\0';
441 		request.ifr_parameter.sub_type = 0;
442 			// the default device is okay for us
443 
444 		if (ioctl(socket, SIOCAIFADDR, &request, sizeof(request)) < 0) {
445 			fprintf(stderr, "%s: Could not add interface: %s\n", kProgramName,
446 				strerror(errno));
447 			exit(1);
448 		}
449 	}
450 
451 	// try to parse address
452 
453 	if (parse_address(familyIndex, args[i], address)) {
454 		hasAddress = true;
455 		i++;
456 
457 		if (parse_address(familyIndex, args[i], mask)) {
458 			hasMask = true;
459 			i++;
460 		}
461 	}
462 
463 	// parse parameters and flags
464 
465 	while (i < argCount) {
466 		if (!strcmp(args[i], "peer")) {
467 			if (!parse_address(familyIndex, args[i + 1], peer)) {
468 				fprintf(stderr, "%s: Option 'peer' needs valid address parameter\n",
469 					kProgramName);
470 				exit(1);
471 			}
472 			hasPeer = true;
473 			i++;
474 		} else if (!strcmp(args[i], "nm") || !strcmp(args[i], "netmask")) {
475 			if (hasMask) {
476 				fprintf(stderr, "%s: Netmask is specified twice\n",
477 					kProgramName);
478 				exit(1);
479 			}
480 			if (!parse_address(familyIndex, args[i + 1], mask)) {
481 				fprintf(stderr, "%s: Option 'netmask' needs valid address parameter\n",
482 					kProgramName);
483 				exit(1);
484 			}
485 			hasMask = true;
486 			i++;
487 		} else if (!strcmp(args[i], "bc") || !strcmp(args[i], "broadcast")) {
488 			if (hasBroadcast) {
489 				fprintf(stderr, "%s: broadcast address is specified twice\n",
490 					kProgramName);
491 				exit(1);
492 			}
493 			if (!parse_address(familyIndex, args[i + 1], broadcast)) {
494 				fprintf(stderr, "%s: Option 'broadcast' needs valid address parameter\n",
495 					kProgramName);
496 				exit(1);
497 			}
498 			hasBroadcast = true;
499 			addFlags |= IFF_BROADCAST;
500 			i++;
501 		} else if (!strcmp(args[i], "mtu")) {
502 			mtu = args[i + 1] ? strtol(args[i + 1], NULL, 0) : 0;
503 			if (mtu <= 500) {
504 				fprintf(stderr, "%s: Option 'mtu' expected valid max transfer unit size\n",
505 					kProgramName);
506 				exit(1);
507 			}
508 			i++;
509 		} else if (!strcmp(args[i], "metric")) {
510 			if (i + 1 >= argCount) {
511 				fprintf(stderr, "%s: Option 'metric' exptected parameter\n",
512 					kProgramName);
513 				exit(1);
514 			}
515 			metric = strtol(args[i + 1], NULL, 0);
516 			i++;
517 		} else if (!strcmp(args[i], "up") || !strcmp(args[i], "-down")) {
518 			addFlags |= IFF_UP;
519 		} else if (!strcmp(args[i], "down") || !strcmp(args[i], "-up")) {
520 			removeFlags |= IFF_UP;
521 		} else if (!strcmp(args[i], "bcast")) {
522 			addFlags |= IFF_BROADCAST;
523 		} else if (!strcmp(args[i], "-bcast")) {
524 			removeFlags |= IFF_BROADCAST;
525 		} else if (!strcmp(args[i], "promisc")) {
526 			addFlags |= IFF_PROMISC;
527 		} else if (!strcmp(args[i], "-promisc")) {
528 			removeFlags |= IFF_PROMISC;
529 		} else if (!strcmp(args[i], "allmulti")) {
530 			addFlags |= IFF_ALLMULTI;
531 		} else if (!strcmp(args[i], "-allmulti")) {
532 			removeFlags |= IFF_ALLMULTI;
533 		} else if (!strcmp(args[i], "loopback")) {
534 			addFlags |= IFF_LOOPBACK;
535 		} else
536 			usage(1);
537 
538 		i++;
539 	}
540 
541 	if ((addFlags & removeFlags) != 0) {
542 		fprintf(stderr, "%s: Contradicting flags specified\n", kProgramName);
543 		exit(1);
544 	}
545 
546 	// set address/mask/broadcast/peer
547 
548 	if (hasAddress) {
549 		memcpy(&request.ifr_addr, &address, address.sa_len);
550 
551 		if (ioctl(socket, SIOCSIFADDR, &request, sizeof(struct ifreq)) < 0) {
552 			fprintf(stderr, "%s: Setting address failed: %s\n", kProgramName, strerror(errno));
553 			exit(1);
554 		}
555 	}
556 
557 	if (ioctl(socket, SIOCGIFFLAGS, &request, sizeof(struct ifreq)) < 0) {
558 		fprintf(stderr, "%s: Getting flags failed: %s\n", kProgramName, strerror(errno));
559 		exit(1);
560 	}
561 	currentFlags = request.ifr_flags;
562 
563 	if (!hasMask && hasAddress && kFamilies[familyIndex].family == AF_INET
564 		&& ioctl(socket, SIOCGIFNETMASK, &request, sizeof(struct ifreq)) == 0
565 		&& request.ifr_mask.sa_family == AF_UNSPEC) {
566 		// generate standard netmask if it doesn't have one yet
567 		sockaddr_in *netmask = (sockaddr_in *)&mask;
568 		netmask->sin_len = sizeof(sockaddr_in);
569 		netmask->sin_family = AF_INET;
570 
571 		// choose default netmask depending on the class of the address
572 		in_addr_t net = ((sockaddr_in *)&address)->sin_addr.s_addr;
573 		if (IN_CLASSA(net)
574 			|| (ntohl(net) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET) {
575 			// class A, or loopback
576 			netmask->sin_addr.s_addr = IN_CLASSA_NET;
577 		} else if (IN_CLASSB(net)) {
578 			// class B
579 			netmask->sin_addr.s_addr = IN_CLASSB_NET;
580 		} else {
581 			// class C and rest
582 			netmask->sin_addr.s_addr = IN_CLASSC_NET;
583 		}
584 
585 		hasMask = true;
586 	}
587 	if (hasMask) {
588 		memcpy(&request.ifr_mask, &mask, mask.sa_len);
589 
590 		if (ioctl(socket, SIOCSIFNETMASK, &request, sizeof(struct ifreq)) < 0) {
591 			fprintf(stderr, "%s: Setting subnet mask failed: %s\n", kProgramName, strerror(errno));
592 			exit(1);
593 		}
594 	}
595 
596 	if (!hasBroadcast && hasAddress && (currentFlags & IFF_BROADCAST)
597 		&& kFamilies[familyIndex].family == AF_INET
598 		&& ioctl(socket, SIOCGIFBRDADDR, &request, sizeof(struct ifreq)) == 0
599 		&& request.ifr_mask.sa_family == AF_UNSPEC) {
600 			// generate standard broadcast address if it doesn't have one yet
601 		sockaddr_in *broadcastAddr = (sockaddr_in *)&broadcast;
602 		uint32 maskValue = ((sockaddr_in *)&mask)->sin_addr.s_addr;
603 		uint32 broadcastValue = ((sockaddr_in *)&address)->sin_addr.s_addr;
604 		broadcastValue = (broadcastValue & maskValue) | ~maskValue;
605 		broadcastAddr->sin_len = sizeof(sockaddr_in);
606 		broadcastAddr->sin_family = AF_INET;
607 		broadcastAddr->sin_addr.s_addr = broadcastValue;
608 		hasBroadcast = true;
609 	}
610 	if (hasBroadcast) {
611 		memcpy(&request.ifr_broadaddr, &broadcast, broadcast.sa_len);
612 
613 		if (ioctl(socket, SIOCSIFBRDADDR, &request, sizeof(struct ifreq)) < 0) {
614 			fprintf(stderr, "%s: Setting broadcast address failed: %s\n", kProgramName, strerror(errno));
615 			exit(1);
616 		}
617 	}
618 
619 	if (hasPeer) {
620 		memcpy(&request.ifr_dstaddr, &peer, peer.sa_len);
621 
622 		if (ioctl(socket, SIOCSIFDSTADDR, &request, sizeof(struct ifreq)) < 0) {
623 			fprintf(stderr, "%s: Setting peer address failed: %s\n", kProgramName, strerror(errno));
624 			exit(1);
625 		}
626 	}
627 
628 	// set flags
629 
630 	if (addFlags || removeFlags) {
631 		request.ifr_flags = (currentFlags & ~removeFlags) | addFlags;
632 		if (ioctl(socket, SIOCSIFFLAGS, &request, sizeof(struct ifreq)) < 0)
633 			fprintf(stderr, "%s: Setting flags failed: %s\n", kProgramName, strerror(errno));
634 	}
635 
636 	// set options
637 
638 	if (mtu != -1) {
639 		request.ifr_mtu = mtu;
640 		if (ioctl(socket, SIOCSIFMTU, &request, sizeof(struct ifreq)) < 0)
641 			fprintf(stderr, "%s: Setting MTU failed: %s\n", kProgramName, strerror(errno));
642 	}
643 
644 	if (metric != -1) {
645 		request.ifr_metric = metric;
646 		if (ioctl(socket, SIOCSIFMETRIC, &request, sizeof(struct ifreq)) < 0)
647 			fprintf(stderr, "%s: Setting metric failed: %s\n", kProgramName, strerror(errno));
648 	}
649 }
650 
651 
652 //	#pragma mark -
653 
654 
655 int
656 main(int argc, char** argv)
657 {
658 	if (argc > 1 && (!strcmp(argv[1], "--help") || !strcmp(argv[1], "-h")))
659 		usage(0);
660 
661 	bool deleteInterfaces = false;
662 
663 	if (argc > 1
664 		&& (!strcmp(argv[1], "--delete")
665 			|| !strcmp(argv[1], "--del")
666 			|| !strcmp(argv[1], "-d"))) {
667 		// delete interfaces
668 		if (argc < 3)
669 			usage(1);
670 
671 		deleteInterfaces = true;
672 	}
673 
674 	// we need a socket to talk to the networking stack
675 	int socket = ::socket(AF_INET, SOCK_DGRAM, 0);
676 	if (socket < 0) {
677 		fprintf(stderr, "%s: The networking stack doesn't seem to be available.\n",
678 			kProgramName);
679 		return 1;
680 	}
681 
682 	if (deleteInterfaces) {
683 		for (int i = 2; i < argc; i++) {
684 			delete_interface(socket, argv[i]);
685 		}
686 		return 0;
687 	} else if (argc > 1 && !strcmp(argv[1], "-a")) {
688 		// accept -a option for those that are used to it from other platforms
689 		if (argc > 2)
690 			usage(1);
691 
692 		list_interfaces(socket, NULL);
693 		return 0;
694 	}
695 
696 	const char* name = argv[1];
697 	if (argc > 2) {
698 		// add or configure an interface
699 
700 		configure_interface(socket, name, argv + 2, argc - 2);
701 		return 0;
702 	}
703 
704 	// list interfaces
705 
706 	list_interfaces(socket, name);
707 	return 0;
708 }
709 
710