xref: /haiku/src/bin/network/ifconfig/ifconfig.cpp (revision a4ef4a49150f118d47324242917a596a3f8f8bd5)
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, name);
214 		return false;
215 	}
216 
217 	strcpy(request.ifr_name, name);
218 	return true;
219 }
220 
221 
222 bool
223 get_address_family(const char* argument, int32& familyIndex)
224 {
225 	for (int32 i = 0; kFamilies[i].family >= 0; i++) {
226 		for (int32 j = 0; kFamilies[i].identifiers[j]; j++) {
227 			if (!strcmp(argument, kFamilies[i].identifiers[j])) {
228 				// found a match
229 				familyIndex = i;
230 				return true;
231 			}
232 		}
233 	}
234 
235 	// defaults to AF_INET
236 	familyIndex = 0;
237 	return false;
238 }
239 
240 
241 bool
242 parse_address(int32 familyIndex, const char* argument, struct sockaddr& address)
243 {
244 	if (argument == NULL)
245 		return false;
246 
247 	return kFamilies[familyIndex].parse_address(argument, &address);
248 }
249 
250 
251 //	#pragma mark -
252 
253 
254 void
255 list_interface(int socket, const char* name)
256 {
257 	ifreq request;
258 	if (!prepare_request(request, name))
259 		return;
260 
261 	if (ioctl(socket, SIOCGIFINDEX, &request, sizeof(request)) < 0) {
262 		fprintf(stderr, "%s: Interface \"%s\" does not exist.\n", kProgramName, name);
263 		return;
264 	}
265 
266 	printf("%s", name);
267 	size_t length = strlen(name);
268 	if (length < 8)
269 		putchar('\t');
270 	else
271 		printf("\n\t");
272 
273 	// get link level interface for this interface
274 
275 	int linkSocket = ::socket(AF_LINK, SOCK_DGRAM, 0);
276 	if (linkSocket < 0) {
277 		printf("No link level: %s\n", strerror(errno));
278 	} else {
279 		const char *type = "unknown";
280 		char address[256];
281 		strcpy(address, "none");
282 
283 		if (ioctl(socket, SIOCGIFPARAM, &request, sizeof(struct ifreq)) == 0) {
284 			prepare_request(request, request.ifr_parameter.device);
285 			if (ioctl(linkSocket, SIOCGIFADDR, &request, sizeof(struct ifreq)) == 0) {
286 				sockaddr_dl &link = *(sockaddr_dl *)&request.ifr_addr;
287 
288 				switch (link.sdl_type) {
289 					case IFT_ETHER:
290 					{
291 						type = "Ethernet";
292 
293 						if (link.sdl_alen > 0) {
294 							uint8 *mac = (uint8 *)LLADDR(&link);
295 							sprintf(address, "%02x:%02x:%02x:%02x:%02x:%02x",
296 								mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
297 						} else
298 							strcpy(address, "not available");
299 						break;
300 					}
301 					case IFT_LOOP:
302 						type = "Local Loopback";
303 						break;
304 					case IFT_MODEM:
305 						type = "Modem";
306 						break;
307 				}
308 			}
309 		}
310 
311 		printf("Hardware Type: %s, Address: %s\n", type, address);
312 		close(linkSocket);
313 	}
314 
315 	if (ioctl(socket, SIOCGIFMEDIA, &request, sizeof(struct ifreq)) == 0
316 		&& (request.ifr_media & IFM_ACTIVE) != 0) {
317 		// dump media state in case we're linked
318 		const char* type = "unknown";
319 		bool show = false;
320 
321 		for (int32 i = 0; kMediaTypes[i].type >= 0; i++) {
322 			// loopback don't really have a media anyway
323 			if (IFM_TYPE(request.ifr_media) == 0/*IFT_LOOP*/)
324 				break;
325 			// only check for generic or correct subtypes
326 			if (kMediaTypes[i].type &&
327 				kMediaTypes[i].type != IFM_TYPE(request.ifr_media))
328 				continue;
329 			for (int32 j = 0; kMediaTypes[i].subtypes[j].subtype >= 0; j++) {
330 				if (kMediaTypes[i].subtypes[j].subtype == IFM_SUBTYPE(request.ifr_media)) {
331 					// found a match
332 					type = kMediaTypes[i].subtypes[j].pretty;
333 					show = true;
334 					break;
335 				}
336 			}
337 		}
338 
339 		if (show)
340 			printf("\tMedia Type: %s\n", type);
341 	}
342 
343 	uint32 flags = 0;
344 	if (ioctl(socket, SIOCGIFFLAGS, &request, sizeof(struct ifreq)) == 0)
345 		flags = request.ifr_flags;
346 
347 	for (int32 i = 0; kFamilies[i].family >= 0; i++) {
348 		int familySocket = ::socket(kFamilies[i].family, SOCK_DGRAM, 0);
349 		if (familySocket < 0)
350 			continue;
351 
352 		if (ioctl(familySocket, SIOCGIFADDR, &request, sizeof(struct ifreq)) == 0) {
353 			printf("\t%s addr: ", kFamilies[i].name);
354 			kFamilies[i].print_address(&request.ifr_addr);
355 
356 			if ((flags & IFF_BROADCAST) != 0
357 				&& ioctl(familySocket, SIOCGIFBRDADDR, &request, sizeof(struct ifreq)) == 0
358 				&& request.ifr_broadaddr.sa_family == kFamilies[i].family) {
359 				printf(", Bcast: ");
360 				kFamilies[i].print_address(&request.ifr_broadaddr);
361 			}
362 			if (ioctl(familySocket, SIOCGIFNETMASK, &request, sizeof(struct ifreq)) == 0
363 				&& request.ifr_mask.sa_family == kFamilies[i].family) {
364 				printf(", Mask: ");
365 				kFamilies[i].print_address(&request.ifr_mask);
366 			}
367 			putchar('\n');
368 		}
369 
370 		close(familySocket);
371 	}
372 
373 	// Print MTU, metric, flags
374 
375 	printf("\tMTU: ");
376 	if (ioctl(socket, SIOCGIFMTU, &request, sizeof(struct ifreq)) == 0)
377 		printf("%d", request.ifr_mtu);
378 	else
379 		printf("-");
380 
381 	printf(", Metric: ");
382 	if (ioctl(socket, SIOCGIFMETRIC, &request, sizeof(struct ifreq)) == 0)
383 		printf("%d", request.ifr_metric);
384 	else
385 		printf("-");
386 
387 	if (flags != 0) {
388 		const struct {
389 			int			value;
390 			const char	*name;
391 		} kFlags[] = {
392 			{IFF_UP, "up"},
393 			{IFF_NOARP, "noarp"},
394 			{IFF_BROADCAST, "broadcast"},
395 			{IFF_LOOPBACK, "loopback"},
396 			{IFF_PROMISC, "promiscuous"},
397 			{IFF_ALLMULTI, "allmulti"},
398 			{IFF_AUTOUP, "autoup"},
399 			{IFF_LINK, "link"},
400 			{IFF_AUTO_CONFIGURED, "auto-configured"},
401 			{IFF_CONFIGURING, "configuring"},
402 		};
403 		bool first = true;
404 
405 		for (uint32 i = 0; i < sizeof(kFlags) / sizeof(kFlags[0]); i++) {
406 			if ((flags & kFlags[i].value) != 0) {
407 				if (first) {
408 					printf(",");
409 					first = false;
410 				}
411 				putchar(' ');
412 				printf(kFlags[i].name);
413 			}
414 		}
415 	}
416 
417 	putchar('\n');
418 
419 	// Print statistics
420 
421 	if (ioctl(socket, SIOCGIFSTATS, &request, sizeof(struct ifreq)) == 0) {
422 		printf("\tReceive: %d packets, %d errors, %Ld bytes, %d mcasts, %d dropped\n",
423 			request.ifr_stats.receive.packets, request.ifr_stats.receive.errors,
424 			request.ifr_stats.receive.bytes, request.ifr_stats.receive.multicast_packets,
425 			request.ifr_stats.receive.dropped);
426 		printf("\tTransmit: %d packets, %d errors, %Ld bytes, %d mcasts, %d dropped\n",
427 			request.ifr_stats.send.packets, request.ifr_stats.send.errors,
428 			request.ifr_stats.send.bytes, request.ifr_stats.send.multicast_packets,
429 			request.ifr_stats.send.dropped);
430 		printf("\tCollisions: %d\n", request.ifr_stats.collisions);
431 	}
432 
433 	putchar('\n');
434 }
435 
436 
437 void
438 list_interfaces(int socket, const char* name)
439 {
440 	if (name != NULL) {
441 		list_interface(socket, name);
442 		return;
443 	}
444 
445 	// get a list of all interfaces
446 
447 	ifconf config;
448 	config.ifc_len = sizeof(config.ifc_value);
449 	if (ioctl(socket, SIOCGIFCOUNT, &config, sizeof(struct ifconf)) < 0)
450 		return;
451 
452 	uint32 count = (uint32)config.ifc_value;
453 	if (count == 0) {
454 		fprintf(stderr, "%s: There are no interfaces yet!\n", kProgramName);
455 		return;
456 	}
457 
458 	void *buffer = malloc(count * sizeof(struct ifreq));
459 	if (buffer == NULL) {
460 		fprintf(stderr, "%s: Out of memory.\n", kProgramName);
461 		return;
462 	}
463 
464 	config.ifc_len = count * sizeof(struct ifreq);
465 	config.ifc_buf = buffer;
466 	if (ioctl(socket, SIOCGIFCONF, &config, sizeof(struct ifconf)) < 0)
467 		return;
468 
469 	ifreq *interface = (ifreq *)buffer;
470 
471 	for (uint32 i = 0; i < count; i++) {
472 		list_interface(socket, interface->ifr_name);
473 
474 		interface = (ifreq *)((addr_t)interface + IF_NAMESIZE + interface->ifr_addr.sa_len);
475 	}
476 
477 	free(buffer);
478 }
479 
480 
481 void
482 delete_interface(int socket, const char* name)
483 {
484 	ifreq request;
485 	if (!prepare_request(request, name))
486 		return;
487 
488 	if (ioctl(socket, SIOCDIFADDR, &request, sizeof(request)) < 0) {
489 		fprintf(stderr, "%s: Could not delete interface %s: %s\n",
490 			kProgramName, name, strerror(errno));
491 	}
492 }
493 
494 
495 void
496 configure_interface(int socket, const char* name, char* const* args,
497 	int32 argCount)
498 {
499 	ifreq request;
500 	if (!prepare_request(request, name))
501 		return;
502 
503 	uint32 index = 0;
504 	if (ioctl(socket, SIOCGIFINDEX, &request, sizeof(request)) >= 0)
505 		index = request.ifr_index;
506 
507 	bool hasAddress = false, hasMask = false, hasPeer = false;
508 	bool hasBroadcast = false, doAutoConfig = false;
509 	struct sockaddr address, mask, peer, broadcast;
510 	int mtu = -1, metric = -1, media = -1;
511 	int addFlags = 0, currentFlags = 0, removeFlags = 0;
512 
513 	// try to parse address family
514 
515 	int32 familyIndex;
516 	int32 i = 0;
517 	if (get_address_family(args[i], familyIndex))
518 		i++;
519 
520 	if (kFamilies[familyIndex].family != AF_INET) {
521 		close(socket);
522 
523 		// replace socket with one of the correct address family
524 		socket = ::socket(kFamilies[familyIndex].family, SOCK_DGRAM, 0);
525 		if (socket < 0) {
526 			fprintf(stderr, "%s: Address family \"%s\" is not available.\n",
527 				kProgramName, kFamilies[familyIndex].name);
528 			exit(1);
529 		}
530 	}
531 
532 	if (index == 0) {
533 		// the interface does not exist yet, we have to add it first
534 		request.ifr_parameter.base_name[0] = '\0';
535 		request.ifr_parameter.device[0] = '\0';
536 		request.ifr_parameter.sub_type = 0;
537 			// the default device is okay for us
538 
539 		if (ioctl(socket, SIOCAIFADDR, &request, sizeof(request)) < 0) {
540 			fprintf(stderr, "%s: Could not add interface: %s\n", kProgramName,
541 				strerror(errno));
542 			exit(1);
543 		}
544 	}
545 
546 	// try to parse address
547 
548 	if (parse_address(familyIndex, args[i], address)) {
549 		hasAddress = true;
550 		i++;
551 
552 		if (parse_address(familyIndex, args[i], mask)) {
553 			hasMask = true;
554 			i++;
555 		}
556 	}
557 
558 	// parse parameters and flags
559 
560 	while (i < argCount) {
561 		if (!strcmp(args[i], "peer")) {
562 			if (!parse_address(familyIndex, args[i + 1], peer)) {
563 				fprintf(stderr, "%s: Option 'peer' needs valid address "
564 					"parameter\n", kProgramName);
565 				exit(1);
566 			}
567 			hasPeer = true;
568 			i++;
569 		} else if (!strcmp(args[i], "nm") || !strcmp(args[i], "netmask")) {
570 			if (hasMask) {
571 				fprintf(stderr, "%s: Netmask is specified twice\n",
572 					kProgramName);
573 				exit(1);
574 			}
575 			if (!parse_address(familyIndex, args[i + 1], mask)) {
576 				fprintf(stderr, "%s: Option 'netmask' needs valid address "
577 					"parameter\n", kProgramName);
578 				exit(1);
579 			}
580 			hasMask = true;
581 			i++;
582 		} else if (!strcmp(args[i], "bc") || !strcmp(args[i], "broadcast")) {
583 			if (hasBroadcast) {
584 				fprintf(stderr, "%s: broadcast address is specified twice\n",
585 					kProgramName);
586 				exit(1);
587 			}
588 			if (!parse_address(familyIndex, args[i + 1], broadcast)) {
589 				fprintf(stderr, "%s: Option 'broadcast' needs valid address "
590 					"parameter\n", kProgramName);
591 				exit(1);
592 			}
593 			hasBroadcast = true;
594 			addFlags |= IFF_BROADCAST;
595 			i++;
596 		} else if (!strcmp(args[i], "mtu")) {
597 			mtu = args[i + 1] ? strtol(args[i + 1], NULL, 0) : 0;
598 			if (mtu <= 500) {
599 				fprintf(stderr, "%s: Option 'mtu' expected valid max transfer "
600 					"unit size\n", kProgramName);
601 				exit(1);
602 			}
603 			i++;
604 		} else if (!strcmp(args[i], "metric")) {
605 			if (i + 1 >= argCount) {
606 				fprintf(stderr, "%s: Option 'metric' exptected parameter\n",
607 					kProgramName);
608 				exit(1);
609 			}
610 			metric = strtol(args[i + 1], NULL, 0);
611 			i++;
612 		} else if (!strcmp(args[i], "media")) {
613 			if (ioctl(socket, SIOCGIFMEDIA, &request,
614 					sizeof(struct ifreq)) < 0) {
615 				fprintf(stderr, "%s: Unable to detect media type\n",
616 					kProgramName);
617 				exit(1);
618 			}
619 			if (i + 1 >= argCount) {
620 				fprintf(stderr, "%s: Option 'media' exptected parameter\n",
621 					kProgramName);
622 				exit(1);
623 			}
624 			if (!media_parse_subtype(args[i + 1], IFM_TYPE(request.ifr_media),
625 					&media)) {
626 				fprintf(stderr, "%s: Invalid parameter for option 'media': "
627 					"'%s'\n", kProgramName, args[i + 1]);
628 				exit(1);
629 			}
630 			i++;
631 		} else if (!strcmp(args[i], "up") || !strcmp(args[i], "-down")) {
632 			addFlags |= IFF_UP;
633 		} else if (!strcmp(args[i], "down") || !strcmp(args[i], "-up")) {
634 			removeFlags |= IFF_UP;
635 		} else if (!strcmp(args[i], "bcast")) {
636 			addFlags |= IFF_BROADCAST;
637 		} else if (!strcmp(args[i], "-bcast")) {
638 			removeFlags |= IFF_BROADCAST;
639 		} else if (!strcmp(args[i], "promisc")) {
640 			addFlags |= IFF_PROMISC;
641 		} else if (!strcmp(args[i], "-promisc")) {
642 			removeFlags |= IFF_PROMISC;
643 		} else if (!strcmp(args[i], "allmulti")) {
644 			addFlags |= IFF_ALLMULTI;
645 		} else if (!strcmp(args[i], "-allmulti")) {
646 			removeFlags |= IFF_ALLMULTI;
647 		} else if (!strcmp(args[i], "loopback")) {
648 			addFlags |= IFF_LOOPBACK;
649 		} else if (!strcmp(args[i], "auto-config")) {
650 			doAutoConfig = true;
651 		} else
652 			usage(1);
653 
654 		i++;
655 	}
656 
657 	if ((addFlags & removeFlags) != 0) {
658 		fprintf(stderr, "%s: Contradicting flags specified\n", kProgramName);
659 		exit(1);
660 	}
661 
662 	if (doAutoConfig && (hasAddress || hasMask || hasBroadcast || hasPeer)) {
663 		fprintf(stderr, "%s: Contradicting changes specified\n", kProgramName);
664 		exit(1);
665 	}
666 
667 	// set address/mask/broadcast/peer
668 
669 	if (hasAddress) {
670 		memcpy(&request.ifr_addr, &address, address.sa_len);
671 
672 		if (ioctl(socket, SIOCSIFADDR, &request, sizeof(struct ifreq)) < 0) {
673 			fprintf(stderr, "%s: Setting address failed: %s\n", kProgramName,
674 				strerror(errno));
675 			exit(1);
676 		}
677 	}
678 
679 	if (ioctl(socket, SIOCGIFFLAGS, &request, sizeof(struct ifreq)) < 0) {
680 		fprintf(stderr, "%s: Getting flags failed: %s\n", kProgramName,
681 			strerror(errno));
682 		exit(1);
683 	}
684 	currentFlags = request.ifr_flags;
685 
686 	if (hasMask) {
687 		memcpy(&request.ifr_mask, &mask, mask.sa_len);
688 
689 		if (ioctl(socket, SIOCSIFNETMASK, &request, sizeof(struct ifreq)) < 0) {
690 			fprintf(stderr, "%s: Setting subnet mask failed: %s\n",
691 				kProgramName, strerror(errno));
692 			exit(1);
693 		}
694 	}
695 
696 	if (hasBroadcast) {
697 		memcpy(&request.ifr_broadaddr, &broadcast, broadcast.sa_len);
698 
699 		if (ioctl(socket, SIOCSIFBRDADDR, &request, sizeof(struct ifreq)) < 0) {
700 			fprintf(stderr, "%s: Setting broadcast address failed: %s\n",
701 				kProgramName, strerror(errno));
702 			exit(1);
703 		}
704 	}
705 
706 	if (hasPeer) {
707 		memcpy(&request.ifr_dstaddr, &peer, peer.sa_len);
708 
709 		if (ioctl(socket, SIOCSIFDSTADDR, &request, sizeof(struct ifreq)) < 0) {
710 			fprintf(stderr, "%s: Setting peer address failed: %s\n",
711 				kProgramName, strerror(errno));
712 			exit(1);
713 		}
714 	}
715 
716 	// set flags
717 
718 	if (hasAddress || hasMask || hasBroadcast || hasPeer) {
719 		removeFlags = IFF_AUTO_CONFIGURED | IFF_CONFIGURING;
720 	}
721 printf("set flags: current %x, remove %x, add %x\n", currentFlags, removeFlags, addFlags);
722 	if (addFlags || removeFlags) {
723 		request.ifr_flags = (currentFlags & ~removeFlags) | addFlags;
724 printf(" --> set %x\n", request.ifr_flags);
725 		if (ioctl(socket, SIOCSIFFLAGS, &request, sizeof(struct ifreq)) < 0) {
726 			fprintf(stderr, "%s: Setting flags failed: %s\n", kProgramName,
727 				strerror(errno));
728 		}
729 	}
730 
731 	// set options
732 
733 	if (mtu != -1) {
734 		request.ifr_mtu = mtu;
735 		if (ioctl(socket, SIOCSIFMTU, &request, sizeof(struct ifreq)) < 0) {
736 			fprintf(stderr, "%s: Setting MTU failed: %s\n", kProgramName,
737 				strerror(errno));
738 		}
739 	}
740 
741 	if (metric != -1) {
742 		request.ifr_metric = metric;
743 		if (ioctl(socket, SIOCSIFMETRIC, &request, sizeof(struct ifreq)) < 0) {
744 			fprintf(stderr, "%s: Setting metric failed: %s\n", kProgramName,
745 				strerror(errno));
746 		}
747 	}
748 
749 	if (media != -1) {
750 		request.ifr_media = media;
751 		if (ioctl(socket, SIOCSIFMEDIA, &request, sizeof(struct ifreq)) < 0) {
752 			fprintf(stderr, "%s: Setting media failed: %s\n", kProgramName,
753 				strerror(errno));
754 		}
755 	}
756 
757 	// start auto configuration, if asked for
758 
759 	if (doAutoConfig) {
760 		BMessage message(kMsgConfigureInterface);
761 		message.AddString("device", name);
762 		BMessage address;
763 		address.AddString("family", "inet");
764 		address.AddBool("auto config", true);
765 		message.AddMessage("address", &address);
766 
767 		BMessenger networkServer(kNetServerSignature);
768 		if (networkServer.IsValid()) {
769 			BMessage reply;
770 			status_t status = networkServer.SendMessage(&message, &reply);
771 			if (status != B_OK) {
772 				fprintf(stderr, "%s: Sending auto-config message failed: %s\n",
773 					kProgramName, strerror(status));
774 			} else if (reply.FindInt32("status", &status) == B_OK
775 					&& status != B_OK) {
776 				fprintf(stderr, "%s: Auto-configuring failed: %s\n",
777 					kProgramName, strerror(status));
778 			}
779 		} else {
780 			fprintf(stderr, "%s: The net_server needs to run for the auto "
781 				"configuration!\n", kProgramName);
782 		}
783 	}
784 }
785 
786 
787 //	#pragma mark -
788 
789 
790 int
791 main(int argc, char** argv)
792 {
793 	if (argc > 1 && (!strcmp(argv[1], "--help") || !strcmp(argv[1], "-h")))
794 		usage(0);
795 
796 	bool deleteInterfaces = false;
797 
798 	if (argc > 1
799 		&& (!strcmp(argv[1], "--delete")
800 			|| !strcmp(argv[1], "--del")
801 			|| !strcmp(argv[1], "-d"))) {
802 		// delete interfaces
803 		if (argc < 3)
804 			usage(1);
805 
806 		deleteInterfaces = true;
807 	}
808 
809 	// we need a socket to talk to the networking stack
810 	int socket = ::socket(AF_INET, SOCK_DGRAM, 0);
811 	if (socket < 0) {
812 		fprintf(stderr, "%s: The networking stack doesn't seem to be "
813 			"available.\n", kProgramName);
814 		return 1;
815 	}
816 
817 	if (deleteInterfaces) {
818 		for (int i = 2; i < argc; i++) {
819 			delete_interface(socket, argv[i]);
820 		}
821 		return 0;
822 	} else if (argc > 1 && !strcmp(argv[1], "-a")) {
823 		// accept -a option for those that are used to it from other platforms
824 		if (argc > 2)
825 			usage(1);
826 
827 		list_interfaces(socket, NULL);
828 		return 0;
829 	}
830 
831 	const char* name = argv[1];
832 	if (argc > 2) {
833 		// add or configure an interface
834 
835 		configure_interface(socket, name, argv + 2, argc - 2);
836 		return 0;
837 	}
838 
839 	// list interfaces
840 
841 	list_interfaces(socket, name);
842 	return 0;
843 }
844 
845