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