better ioctl fallback handling for interface listing, avoids duplicate
[oss-qm-packages.git] / ifconfig.c
blob6f172cfec134e700932b13b6e4cdb5d1c7981579
1 /*
2 * ifconfig This file contains an implementation of the command
3 * that either displays or sets the characteristics of
4 * one or more of the system's networking interfaces.
6 * Version: $Id: ifconfig.c,v 1.56 2002/07/05 17:36:02 ecki Exp $
8 * Author: Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
9 * and others. Copyright 1993 MicroWalt Corporation
11 * This program is free software; you can redistribute it
12 * and/or modify it under the terms of the GNU General
13 * Public License as published by the Free Software
14 * Foundation; either version 2 of the License, or (at
15 * your option) any later version.
17 * Patched to support 'add' and 'del' keywords for INET(4) addresses
18 * by Mrs. Brisby <mrs.brisby@nimh.org>
20 * {1.34} - 19980630 - Arnaldo Carvalho de Melo <acme@conectiva.com.br>
21 * - gettext instead of catgets for i18n
22 * 10/1998 - Andi Kleen. Use interface list primitives.
23 * 20001008 - Bernd Eckenfels, Patch from RH for setting mtu
24 * (default AF was wrong)
25 * 20010404 - Arnaldo Carvalho de Melo, use setlocale
28 #define DFLT_AF "inet"
30 #include "config.h"
32 #include <features.h>
33 #include <sys/types.h>
34 #include <sys/socket.h>
35 #include <sys/ioctl.h>
36 #include <netinet/in.h>
37 #include <net/if.h>
38 #include <net/if_arp.h>
39 #include <stdio.h>
40 #include <errno.h>
41 #include <fcntl.h>
42 #include <ctype.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #include <unistd.h>
46 #include <netdb.h>
48 /* Ugh. But libc5 doesn't provide POSIX types. */
49 #include <asm/types.h>
52 #ifdef HAVE_HWSLIP
53 #include <linux/if_slip.h>
54 #endif
56 #if HAVE_AFINET6
58 #ifndef _LINUX_IN6_H
60 * This is in linux/include/net/ipv6.h.
63 struct in6_ifreq {
64 struct in6_addr ifr6_addr;
65 __u32 ifr6_prefixlen;
66 unsigned int ifr6_ifindex;
69 #endif
71 #endif /* HAVE_AFINET6 */
73 #if HAVE_AFIPX
74 #if (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 1)
75 #include <netipx/ipx.h>
76 #else
77 #include "ipx.h"
78 #endif
79 #endif
80 #include "net-support.h"
81 #include "pathnames.h"
82 #include "version.h"
83 #include "../intl.h"
84 #include "interface.h"
85 #include "sockets.h"
86 #include "util.h"
88 char *Release = RELEASE, *Version = "ifconfig 1.42 (2001-04-13)";
90 int opt_a = 0; /* show all interfaces */
91 int opt_v = 0; /* debugging output flag */
93 int addr_family = 0; /* currently selected AF */
95 /* for ipv4 add/del modes */
96 static int get_nmbc_parent(char *parent, unsigned long *nm,
97 unsigned long *bc);
98 static int set_ifstate(char *parent, unsigned long ip,
99 unsigned long nm, unsigned long bc,
100 int flag);
102 static int if_print(char *ifname)
104 int res;
106 if (ife_short)
107 printf(_("Iface MTU Met RX-OK RX-ERR RX-DRP RX-OVR TX-OK TX-ERR TX-DRP TX-OVR Flg\n"));
109 if (!ifname) {
110 res = for_all_interfaces(do_if_print, &opt_a);
111 } else {
112 struct interface *ife;
114 ife = lookup_interface(ifname);
115 res = do_if_fetch(ife);
116 if (res >= 0)
117 ife_print(ife);
119 return res;
122 /* Set a certain interface flag. */
123 static int set_flag(char *ifname, short flag)
125 struct ifreq ifr;
127 safe_strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
128 if (ioctl(skfd, SIOCGIFFLAGS, &ifr) < 0) {
129 fprintf(stderr, _("%s: ERROR while getting interface flags: %s\n"),
130 ifname, strerror(errno));
131 return (-1);
133 safe_strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
134 ifr.ifr_flags |= flag;
135 if (ioctl(skfd, SIOCSIFFLAGS, &ifr) < 0) {
136 perror("SIOCSIFFLAGS");
137 return -1;
139 return (0);
142 /* Clear a certain interface flag. */
143 static int clr_flag(char *ifname, short flag)
145 struct ifreq ifr;
146 int fd;
148 if (strchr(ifname, ':')) {
149 /* This is a v4 alias interface. Downing it via a socket for
150 another AF may have bad consequences. */
151 fd = get_socket_for_af(AF_INET);
152 if (fd < 0) {
153 fprintf(stderr, _("No support for INET on this system.\n"));
154 return -1;
156 } else
157 fd = skfd;
159 safe_strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
160 if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) {
161 fprintf(stderr, _("%s: ERROR while getting interface flags: %s\n"),
162 ifname, strerror(errno));
163 return -1;
165 safe_strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
166 ifr.ifr_flags &= ~flag;
167 if (ioctl(fd, SIOCSIFFLAGS, &ifr) < 0) {
168 perror("SIOCSIFFLAGS");
169 return -1;
171 return (0);
174 /** test is a specified flag is set */
175 static int test_flag(char *ifname, short flags)
177 struct ifreq ifr;
178 int fd;
180 if (strchr(ifname, ':')) {
181 /* This is a v4 alias interface. Downing it via a socket for
182 another AF may have bad consequences. */
183 fd = get_socket_for_af(AF_INET);
184 if (fd < 0) {
185 fprintf(stderr, _("No support for INET on this system.\n"));
186 return -1;
188 } else
189 fd = skfd;
191 safe_strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
192 if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) {
193 fprintf(stderr, _("%s: ERROR while testing interface flags: %s\n"),
194 ifname, strerror(errno));
195 return -1;
197 return (ifr.ifr_flags & flags);
200 static void usage(void)
202 fprintf(stderr, _("Usage:\n ifconfig [-a] [-v] [-s] <interface> [[<AF>] <address>]\n"));
203 #if HAVE_AFINET
204 fprintf(stderr, _(" [add <address>[/<prefixlen>]]\n"));
205 fprintf(stderr, _(" [del <address>[/<prefixlen>]]\n"));
206 fprintf(stderr, _(" [[-]broadcast [<address>]] [[-]pointopoint [<address>]]\n"));
207 fprintf(stderr, _(" [netmask <address>] [dstaddr <address>] [tunnel <address>]\n"));
208 #endif
209 #ifdef SIOCSKEEPALIVE
210 fprintf(stderr, _(" [outfill <NN>] [keepalive <NN>]\n"));
211 #endif
212 fprintf(stderr, _(" [hw <HW> <address>] [metric <NN>] [mtu <NN>]\n"));
213 fprintf(stderr, _(" [[-]trailers] [[-]arp] [[-]allmulti]\n"));
214 fprintf(stderr, _(" [multicast] [[-]promisc]\n"));
215 fprintf(stderr, _(" [mem_start <NN>] [io_addr <NN>] [irq <NN>] [media <type>]\n"));
216 #ifdef HAVE_TXQUEUELEN
217 fprintf(stderr, _(" [txqueuelen <NN>]\n"));
218 #endif
219 #ifdef HAVE_DYNAMIC
220 fprintf(stderr, _(" [[-]dynamic]\n"));
221 #endif
222 fprintf(stderr, _(" [up|down] ...\n\n"));
224 fprintf(stderr, _(" <HW>=Hardware Type.\n"));
225 fprintf(stderr, _(" List of possible hardware types:\n"));
226 print_hwlist(0); /* 1 = ARPable */
227 fprintf(stderr, _(" <AF>=Address family. Default: %s\n"), DFLT_AF);
228 fprintf(stderr, _(" List of possible address families:\n"));
229 print_aflist(0); /* 1 = routeable */
230 exit(E_USAGE);
233 static void version(void)
235 fprintf(stderr, "%s\n%s\n", Release, Version);
236 exit(E_USAGE);
239 static int set_netmask(int skfd, struct ifreq *ifr, struct sockaddr *sa)
241 int err = 0;
243 memcpy((char *) &ifr->ifr_netmask, (char *) sa,
244 sizeof(struct sockaddr));
245 if (ioctl(skfd, SIOCSIFNETMASK, ifr) < 0) {
246 fprintf(stderr, "SIOCSIFNETMASK: %s\n",
247 strerror(errno));
248 err = 1;
250 return err;
253 int main(int argc, char **argv)
255 struct sockaddr sa;
256 struct sockaddr samask;
257 struct sockaddr_in sin;
258 char host[128];
259 struct aftype *ap;
260 struct hwtype *hw;
261 struct ifreq ifr;
262 int goterr = 0, didnetmask = 0, neednetmask=0;
263 char **spp;
264 int fd;
265 #if HAVE_AFINET6
266 extern struct aftype inet6_aftype;
267 struct sockaddr_in6 sa6;
268 struct in6_ifreq ifr6;
269 unsigned long prefix_len;
270 char *cp;
271 #endif
272 #if HAVE_AFINET
273 extern struct aftype inet_aftype;
274 #endif
276 #if I18N
277 setlocale (LC_ALL, "");
278 bindtextdomain("net-tools", "/usr/share/locale");
279 textdomain("net-tools");
280 #endif
282 /* Find any options. */
283 argc--;
284 argv++;
285 while (argc && *argv[0] == '-') {
286 if (!strcmp(*argv, "-a"))
287 opt_a = 1;
289 else if (!strcmp(*argv, "-s"))
290 ife_short = 1;
292 else if (!strcmp(*argv, "-v"))
293 opt_v = 1;
295 else if (!strcmp(*argv, "-V") || !strcmp(*argv, "-version") ||
296 !strcmp(*argv, "--version"))
297 version();
299 else if (!strcmp(*argv, "-?") || !strcmp(*argv, "-h") ||
300 !strcmp(*argv, "-help") || !strcmp(*argv, "--help"))
301 usage();
303 else {
304 fprintf(stderr, _("ifconfig: option `%s' not recognised.\n"),
305 argv[0]);
306 fprintf(stderr, _("ifconfig: `--help' gives usage information.\n"));
307 exit(1);
310 argv++;
311 argc--;
314 /* Create a channel to the NET kernel. */
315 if ((skfd = sockets_open(0)) < 0) {
316 perror("socket");
317 exit(1);
320 /* Do we have to show the current setup? */
321 if (argc == 0) {
322 int err = if_print((char *) NULL);
323 (void) close(skfd);
324 exit(err < 0);
326 /* No. Fetch the interface name. */
327 spp = argv;
328 safe_strncpy(ifr.ifr_name, *spp++, IFNAMSIZ);
329 if (*spp == (char *) NULL) {
330 int err = if_print(ifr.ifr_name);
331 (void) close(skfd);
332 exit(err < 0);
335 /* The next argument is either an address family name, or an option. */
336 if ((ap = get_aftype(*spp)) != NULL)
337 spp++; /* it was a AF name */
338 else
339 ap = get_aftype(DFLT_AF);
341 if (ap) {
342 addr_family = ap->af;
343 skfd = ap->fd;
346 /* Process the remaining arguments. */
347 while (*spp != (char *) NULL) {
348 if (!strcmp(*spp, "arp")) {
349 goterr |= clr_flag(ifr.ifr_name, IFF_NOARP);
350 spp++;
351 continue;
353 if (!strcmp(*spp, "-arp")) {
354 goterr |= set_flag(ifr.ifr_name, IFF_NOARP);
355 spp++;
356 continue;
358 #ifdef IFF_PORTSEL
359 if (!strcmp(*spp, "media") || !strcmp(*spp, "port")) {
360 if (*++spp == NULL)
361 usage();
362 if (!strcasecmp(*spp, "auto")) {
363 goterr |= set_flag(ifr.ifr_name, IFF_AUTOMEDIA);
364 } else {
365 int i, j, newport;
366 char *endp;
367 newport = strtol(*spp, &endp, 10);
368 if (*endp != 0) {
369 newport = -1;
370 for (i = 0; if_port_text[i][0] && newport == -1; i++) {
371 for (j = 0; if_port_text[i][j]; j++) {
372 if (!strcasecmp(*spp, if_port_text[i][j])) {
373 newport = i;
374 break;
379 spp++;
380 if (newport == -1) {
381 fprintf(stderr, _("Unknown media type.\n"));
382 goterr = 1;
383 } else {
384 if (ioctl(skfd, SIOCGIFMAP, &ifr) < 0) {
385 perror("port: SIOCGIFMAP");
386 goterr = 1;
387 continue;
389 ifr.ifr_map.port = newport;
390 if (ioctl(skfd, SIOCSIFMAP, &ifr) < 0) {
391 perror("port: SIOCSIFMAP");
392 goterr = 1;
396 continue;
398 #endif
400 if (!strcmp(*spp, "trailers")) {
401 goterr |= clr_flag(ifr.ifr_name, IFF_NOTRAILERS);
402 spp++;
403 continue;
405 if (!strcmp(*spp, "-trailers")) {
406 goterr |= set_flag(ifr.ifr_name, IFF_NOTRAILERS);
407 spp++;
408 continue;
410 if (!strcmp(*spp, "promisc")) {
411 goterr |= set_flag(ifr.ifr_name, IFF_PROMISC);
412 spp++;
413 continue;
415 if (!strcmp(*spp, "-promisc")) {
416 goterr |= clr_flag(ifr.ifr_name, IFF_PROMISC);
417 if (test_flag(ifr.ifr_name, IFF_PROMISC) > 0)
418 fprintf(stderr, _("Warning: Interface %s still in promisc mode... maybe other application is running?\n"), ifr.ifr_name);
419 spp++;
420 continue;
422 if (!strcmp(*spp, "multicast")) {
423 goterr |= set_flag(ifr.ifr_name, IFF_MULTICAST);
424 spp++;
425 continue;
427 if (!strcmp(*spp, "-multicast")) {
428 goterr |= clr_flag(ifr.ifr_name, IFF_MULTICAST);
429 if (test_flag(ifr.ifr_name, IFF_MULTICAST) > 0)
430 fprintf(stderr, _("Warning: Interface %s still in MULTICAST mode.\n"), ifr.ifr_name);
431 spp++;
432 continue;
434 if (!strcmp(*spp, "allmulti")) {
435 goterr |= set_flag(ifr.ifr_name, IFF_ALLMULTI);
436 spp++;
437 continue;
439 if (!strcmp(*spp, "-allmulti")) {
440 goterr |= clr_flag(ifr.ifr_name, IFF_ALLMULTI);
441 if (test_flag(ifr.ifr_name, IFF_MULTICAST) > 0)
442 fprintf(stderr, _("Warning: Interface %s still in ALLMULTI mode.\n"), ifr.ifr_name);
443 spp++;
444 continue;
446 if (!strcmp(*spp, "up")) {
447 goterr |= set_flag(ifr.ifr_name, (IFF_UP | IFF_RUNNING));
448 spp++;
449 continue;
451 if (!strcmp(*spp, "down")) {
452 goterr |= clr_flag(ifr.ifr_name, IFF_UP);
453 spp++;
454 continue;
456 #ifdef HAVE_DYNAMIC
457 if (!strcmp(*spp, "dynamic")) {
458 goterr |= set_flag(ifr.ifr_name, IFF_DYNAMIC);
459 spp++;
460 continue;
462 if (!strcmp(*spp, "-dynamic")) {
463 goterr |= clr_flag(ifr.ifr_name, IFF_DYNAMIC);
464 spp++;
465 if (test_flag(ifr.ifr_name, IFF_MULTICAST) > 0)
466 fprintf(stderr, _("Warning: Interface %s still in DYNAMIC mode.\n"), ifr.ifr_name);
467 continue;
469 #endif
471 if (!strcmp(*spp, "metric")) {
472 if (*++spp == NULL)
473 usage();
474 ifr.ifr_metric = atoi(*spp);
475 if (ioctl(skfd, SIOCSIFMETRIC, &ifr) < 0) {
476 fprintf(stderr, "SIOCSIFMETRIC: %s\n", strerror(errno));
477 goterr = 1;
479 spp++;
480 continue;
482 if (!strcmp(*spp, "mtu")) {
483 if (*++spp == NULL)
484 usage();
485 ifr.ifr_mtu = atoi(*spp);
486 if (ioctl(skfd, SIOCSIFMTU, &ifr) < 0) {
487 fprintf(stderr, "SIOCSIFMTU: %s\n", strerror(errno));
488 goterr = 1;
490 spp++;
491 continue;
493 #ifdef SIOCSKEEPALIVE
494 if (!strcmp(*spp, "keepalive")) {
495 if (*++spp == NULL)
496 usage();
497 ifr.ifr_data = (caddr_t) atoi(*spp);
498 if (ioctl(skfd, SIOCSKEEPALIVE, &ifr) < 0) {
499 fprintf(stderr, "SIOCSKEEPALIVE: %s\n", strerror(errno));
500 goterr = 1;
502 spp++;
503 continue;
505 #endif
507 #ifdef SIOCSOUTFILL
508 if (!strcmp(*spp, "outfill")) {
509 if (*++spp == NULL)
510 usage();
511 ifr.ifr_data = (caddr_t) atoi(*spp);
512 if (ioctl(skfd, SIOCSOUTFILL, &ifr) < 0) {
513 fprintf(stderr, "SIOCSOUTFILL: %s\n", strerror(errno));
514 goterr = 1;
516 spp++;
517 continue;
519 #endif
521 if (!strcmp(*spp, "-broadcast")) {
522 goterr |= clr_flag(ifr.ifr_name, IFF_BROADCAST);
523 if (test_flag(ifr.ifr_name, IFF_MULTICAST) > 0)
524 fprintf(stderr, _("Warning: Interface %s still in BROADCAST mode.\n"), ifr.ifr_name);
525 spp++;
526 continue;
528 if (!strcmp(*spp, "broadcast")) {
529 if (*++spp != NULL) {
530 safe_strncpy(host, *spp, (sizeof host));
531 if (ap->input(0, host, &sa) < 0) {
532 ap->herror(host);
533 goterr = 1;
534 spp++;
535 continue;
537 memcpy((char *) &ifr.ifr_broadaddr, (char *) &sa,
538 sizeof(struct sockaddr));
539 if (ioctl(ap->fd, SIOCSIFBRDADDR, &ifr) < 0) {
540 fprintf(stderr, "SIOCSIFBRDADDR: %s\n",
541 strerror(errno));
542 goterr = 1;
544 spp++;
546 goterr |= set_flag(ifr.ifr_name, IFF_BROADCAST);
547 continue;
549 if (!strcmp(*spp, "dstaddr")) {
550 if (*++spp == NULL)
551 usage();
552 safe_strncpy(host, *spp, (sizeof host));
553 if (ap->input(0, host, &sa) < 0) {
554 ap->herror(host);
555 goterr = 1;
556 spp++;
557 continue;
559 memcpy((char *) &ifr.ifr_dstaddr, (char *) &sa,
560 sizeof(struct sockaddr));
561 if (ioctl(ap->fd, SIOCSIFDSTADDR, &ifr) < 0) {
562 fprintf(stderr, "SIOCSIFDSTADDR: %s\n",
563 strerror(errno));
564 goterr = 1;
566 spp++;
567 continue;
569 if (!strcmp(*spp, "netmask")) {
570 if (*++spp == NULL || didnetmask)
571 usage();
572 safe_strncpy(host, *spp, (sizeof host));
573 if (ap->input(0, host, &sa) < 0) {
574 ap->herror(host);
575 goterr = 1;
576 spp++;
577 continue;
579 didnetmask++;
580 goterr |= set_netmask(ap->fd, &ifr, &sa);
581 spp++;
582 continue;
584 #ifdef HAVE_TXQUEUELEN
585 if (!strcmp(*spp, "txqueuelen")) {
586 if (*++spp == NULL)
587 usage();
588 ifr.ifr_qlen = strtoul(*spp, NULL, 0);
589 if (ioctl(skfd, SIOCSIFTXQLEN, &ifr) < 0) {
590 fprintf(stderr, "SIOCSIFTXQLEN: %s\n", strerror(errno));
591 goterr = 1;
593 spp++;
594 continue;
596 #endif
598 if (!strcmp(*spp, "mem_start")) {
599 if (*++spp == NULL)
600 usage();
601 if (ioctl(skfd, SIOCGIFMAP, &ifr) < 0) {
602 fprintf(stderr, "mem_start: SIOCGIFMAP: %s\n", strerror(errno));
603 spp++;
604 goterr = 1;
605 continue;
607 ifr.ifr_map.mem_start = strtoul(*spp, NULL, 0);
608 if (ioctl(skfd, SIOCSIFMAP, &ifr) < 0) {
609 fprintf(stderr, "mem_start: SIOCSIFMAP: %s\n", strerror(errno));
610 goterr = 1;
612 spp++;
613 continue;
615 if (!strcmp(*spp, "io_addr")) {
616 if (*++spp == NULL)
617 usage();
618 if (ioctl(skfd, SIOCGIFMAP, &ifr) < 0) {
619 fprintf(stderr, "io_addr: SIOCGIFMAP: %s\n", strerror(errno));
620 spp++;
621 goterr = 1;
622 continue;
624 ifr.ifr_map.base_addr = strtol(*spp, NULL, 0);
625 if (ioctl(skfd, SIOCSIFMAP, &ifr) < 0) {
626 fprintf(stderr, "io_addr: SIOCSIFMAP: %s\n", strerror(errno));
627 goterr = 1;
629 spp++;
630 continue;
632 if (!strcmp(*spp, "irq")) {
633 if (*++spp == NULL)
634 usage();
635 if (ioctl(skfd, SIOCGIFMAP, &ifr) < 0) {
636 fprintf(stderr, "irq: SIOCGIFMAP: %s\n", strerror(errno));
637 goterr = 1;
638 spp++;
639 continue;
641 ifr.ifr_map.irq = atoi(*spp);
642 if (ioctl(skfd, SIOCSIFMAP, &ifr) < 0) {
643 fprintf(stderr, "irq: SIOCSIFMAP: %s\n", strerror(errno));
644 goterr = 1;
646 spp++;
647 continue;
649 if (!strcmp(*spp, "-pointopoint")) {
650 goterr |= clr_flag(ifr.ifr_name, IFF_POINTOPOINT);
651 spp++;
652 if (test_flag(ifr.ifr_name, IFF_MULTICAST) > 0)
653 fprintf(stderr, _("Warning: Interface %s still in POINTOPOINT mode.\n"), ifr.ifr_name);
654 continue;
656 if (!strcmp(*spp, "pointopoint")) {
657 if (*(spp + 1) != NULL) {
658 spp++;
659 safe_strncpy(host, *spp, (sizeof host));
660 if (ap->input(0, host, &sa)) {
661 ap->herror(host);
662 goterr = 1;
663 spp++;
664 continue;
666 memcpy((char *) &ifr.ifr_dstaddr, (char *) &sa,
667 sizeof(struct sockaddr));
668 if (ioctl(ap->fd, SIOCSIFDSTADDR, &ifr) < 0) {
669 fprintf(stderr, "SIOCSIFDSTADDR: %s\n",
670 strerror(errno));
671 goterr = 1;
674 goterr |= set_flag(ifr.ifr_name, IFF_POINTOPOINT);
675 spp++;
676 continue;
679 if (!strcmp(*spp, "hw")) {
680 if (*++spp == NULL)
681 usage();
682 if ((hw = get_hwtype(*spp)) == NULL)
683 usage();
684 if (hw->input == NULL) {
685 fprintf(stderr, _("hw address type `%s' has no handler to set address. failed.\n"), *spp);
686 spp+=2;
687 goterr = 1;
688 continue;
690 if (*++spp == NULL)
691 usage();
692 safe_strncpy(host, *spp, (sizeof host));
693 if (hw->input(host, &sa) < 0) {
694 fprintf(stderr, _("%s: invalid %s address.\n"), host, hw->name);
695 goterr = 1;
696 spp++;
697 continue;
699 memcpy((char *) &ifr.ifr_hwaddr, (char *) &sa,
700 sizeof(struct sockaddr));
701 if (ioctl(skfd, SIOCSIFHWADDR, &ifr) < 0) {
702 if (errno == EBUSY)
703 fprintf(stderr, "SIOCSIFHWADDR: %s - you may need to down the interface\n",
704 strerror(errno));
705 else
706 fprintf(stderr, "SIOCSIFHWADDR: %s\n",
707 strerror(errno));
708 goterr = 1;
710 spp++;
711 continue;
713 #if HAVE_AFINET || HAVE_AFINET6
714 if (!strcmp(*spp, "add")) {
715 if (*++spp == NULL)
716 usage();
717 #if HAVE_AFINET6
718 if (strchr(*spp, ':')) {
719 /* INET6 */
720 if ((cp = strchr(*spp, '/'))) {
721 prefix_len = atol(cp + 1);
722 if ((prefix_len < 0) || (prefix_len > 128))
723 usage();
724 *cp = 0;
725 } else {
726 prefix_len = 0;
728 safe_strncpy(host, *spp, (sizeof host));
729 if (inet6_aftype.input(1, host,
730 (struct sockaddr *) &sa6) < 0) {
731 inet6_aftype.herror(host);
732 goterr = 1;
733 spp++;
734 continue;
736 memcpy((char *) &ifr6.ifr6_addr, (char *) &sa6.sin6_addr,
737 sizeof(struct in6_addr));
739 fd = get_socket_for_af(AF_INET6);
740 if (fd < 0) {
741 fprintf(stderr,
742 _("No support for INET6 on this system.\n"));
743 goterr = 1;
744 spp++;
745 continue;
747 if (ioctl(fd, SIOGIFINDEX, &ifr) < 0) {
748 perror("SIOGIFINDEX");
749 goterr = 1;
750 spp++;
751 continue;
753 ifr6.ifr6_ifindex = ifr.ifr_ifindex;
754 ifr6.ifr6_prefixlen = prefix_len;
755 if (ioctl(fd, SIOCSIFADDR, &ifr6) < 0) {
756 perror("SIOCSIFADDR");
757 goterr = 1;
759 spp++;
760 continue;
762 #endif
763 #ifdef HAVE_AFINET
764 { /* ipv4 address a.b.c.d */
765 unsigned long ip, nm, bc;
766 safe_strncpy(host, *spp, (sizeof host));
767 if (inet_aftype.input(0, host, (struct sockaddr *)&sin) < 0) {
768 ap->herror(host);
769 goterr = 1;
770 spp++;
771 continue;
773 fd = get_socket_for_af(AF_INET);
774 if (fd < 0) {
775 fprintf(stderr,
776 _("No support for INET on this system.\n"));
777 goterr = 1;
778 spp++;
779 continue;
782 memcpy(&ip, &sin.sin_addr.s_addr, sizeof(unsigned long));
784 if (get_nmbc_parent(ifr.ifr_name, &nm, &bc) < 0) {
785 fprintf(stderr, _("Interface %s not initialized\n"),
786 ifr.ifr_name);
787 goterr = 1;
788 spp++;
789 continue;
791 set_ifstate(ifr.ifr_name, ip, nm, bc, 1);
794 spp++;
795 continue;
796 #else
797 fprintf(stderr, _("Bad address.\n"));
798 #endif
800 #endif
802 #if HAVE_AFINET || HAVE_AFINET6
803 if (!strcmp(*spp, "del")) {
804 if (*++spp == NULL)
805 usage();
807 #ifdef SIOCDIFADDR
808 #if HAVE_AFINET6
809 if (strchr(*spp, ':')) { /* INET6 */
810 if ((cp = strchr(*spp, '/'))) {
811 prefix_len = atol(cp + 1);
812 if ((prefix_len < 0) || (prefix_len > 128))
813 usage();
814 *cp = 0;
815 } else {
816 prefix_len = 0;
818 safe_strncpy(host, *spp, (sizeof host));
819 if (inet6_aftype.input(1, host,
820 (struct sockaddr *) &sa6) < 0) {
821 inet6_aftype.herror(host);
822 goterr = 1;
823 spp++;
824 continue;
826 memcpy((char *) &ifr6.ifr6_addr, (char *) &sa6.sin6_addr,
827 sizeof(struct in6_addr));
829 fd = get_socket_for_af(AF_INET6);
830 if (fd < 0) {
831 fprintf(stderr,
832 _("No support for INET6 on this system.\n"));
833 goterr = 1;
834 spp++;
835 continue;
837 if (ioctl(fd, SIOGIFINDEX, &ifr) < 0) {
838 perror("SIOGIFINDEX");
839 goterr = 1;
840 spp++;
841 continue;
843 ifr6.ifr6_ifindex = ifr.ifr_ifindex;
844 ifr6.ifr6_prefixlen = prefix_len;
845 if (ioctl(fd, SIOCDIFADDR, &ifr6) < 0) {
846 fprintf(stderr, "SIOCDIFADDR: %s\n",
847 strerror(errno));
848 goterr = 1;
850 spp++;
851 continue;
853 #endif
854 #ifdef HAVE_AFINET
856 /* ipv4 address a.b.c.d */
857 unsigned long ip, nm, bc;
858 safe_strncpy(host, *spp, (sizeof host));
859 if (inet_aftype.input(0, host, (struct sockaddr *)&sin) < 0) {
860 ap->herror(host);
861 goterr = 1;
862 spp++;
863 continue;
865 fd = get_socket_for_af(AF_INET);
866 if (fd < 0) {
867 fprintf(stderr, _("No support for INET on this system.\n"));
868 goterr = 1;
869 spp++;
870 continue;
873 memcpy(&ip, &sin.sin_addr.s_addr, sizeof(unsigned long));
875 if (get_nmbc_parent(ifr.ifr_name, &nm, &bc) < 0) {
876 fprintf(stderr, _("Interface %s not initialized\n"),
877 ifr.ifr_name);
878 goterr = 1;
879 spp++;
880 continue;
882 set_ifstate(ifr.ifr_name, ip, nm, bc, 0);
884 spp++;
885 continue;
886 #else
887 fprintf(stderr, _("Bad address.\n"));
888 #endif
889 #else
890 fprintf(stderr, _("Address deletion not supported on this system.\n"));
891 #endif
893 #endif
894 #if HAVE_AFINET6
895 if (!strcmp(*spp, "tunnel")) {
896 if (*++spp == NULL)
897 usage();
898 if ((cp = strchr(*spp, '/'))) {
899 prefix_len = atol(cp + 1);
900 if ((prefix_len < 0) || (prefix_len > 128))
901 usage();
902 *cp = 0;
903 } else {
904 prefix_len = 0;
906 safe_strncpy(host, *spp, (sizeof host));
907 if (inet6_aftype.input(1, host, (struct sockaddr *) &sa6) < 0) {
908 inet6_aftype.herror(host);
909 goterr = 1;
910 spp++;
911 continue;
913 memcpy((char *) &ifr6.ifr6_addr, (char *) &sa6.sin6_addr,
914 sizeof(struct in6_addr));
916 fd = get_socket_for_af(AF_INET6);
917 if (fd < 0) {
918 fprintf(stderr, _("No support for INET6 on this system.\n"));
919 goterr = 1;
920 spp++;
921 continue;
923 if (ioctl(fd, SIOGIFINDEX, &ifr) < 0) {
924 perror("SIOGIFINDEX");
925 goterr = 1;
926 spp++;
927 continue;
929 ifr6.ifr6_ifindex = ifr.ifr_ifindex;
930 ifr6.ifr6_prefixlen = prefix_len;
932 if (ioctl(fd, SIOCSIFDSTADDR, &ifr6) < 0) {
933 fprintf(stderr, "SIOCSIFDSTADDR: %s\n",
934 strerror(errno));
935 goterr = 1;
937 spp++;
938 continue;
940 #endif
942 /* If the next argument is a valid hostname, assume OK. */
943 safe_strncpy(host, *spp, (sizeof host));
945 /* FIXME: sa is too small for INET6 addresses, inet6 should use that too,
946 broadcast is unexpected */
947 if (ap->getmask) {
948 switch (ap->getmask(host, &samask, NULL)) {
949 case -1:
950 usage();
951 break;
952 case 1:
953 if (didnetmask)
954 usage();
956 // remeber to set the netmask from samask later
957 neednetmask = 1;
958 break;
961 if (ap->input == NULL) {
962 fprintf(stderr, _("ifconfig: Cannot set address for this protocol family.\n"));
963 exit(1);
965 if (ap->input(0, host, &sa) < 0) {
966 ap->herror(host);
967 fprintf(stderr, _("ifconfig: `--help' gives usage information.\n"));
968 exit(1);
970 memcpy((char *) &ifr.ifr_addr, (char *) &sa, sizeof(struct sockaddr));
972 int r = 0; /* to shut gcc up */
973 switch (ap->af) {
974 #if HAVE_AFINET
975 case AF_INET:
976 fd = get_socket_for_af(AF_INET);
977 if (fd < 0) {
978 fprintf(stderr, _("No support for INET on this system.\n"));
979 exit(1);
981 r = ioctl(fd, SIOCSIFADDR, &ifr);
982 break;
983 #endif
984 #if HAVE_AFECONET
985 case AF_ECONET:
986 fd = get_socket_for_af(AF_ECONET);
987 if (fd < 0) {
988 fprintf(stderr, _("No support for ECONET on this system.\n"));
989 exit(1);
991 r = ioctl(fd, SIOCSIFADDR, &ifr);
992 break;
993 #endif
994 default:
995 fprintf(stderr,
996 _("Don't know how to set addresses for family %d.\n"), ap->af);
997 exit(1);
999 if (r < 0) {
1000 perror("SIOCSIFADDR");
1001 goterr = 1;
1006 * Don't do the set_flag() if the address is an alias with a - at the
1007 * end, since it's deleted already! - Roman
1009 * Should really use regex.h here, not sure though how well it'll go
1010 * with the cross-platform support etc.
1013 char *ptr;
1014 short int found_colon = 0;
1015 for (ptr = ifr.ifr_name; *ptr; ptr++ )
1016 if (*ptr == ':') found_colon++;
1018 if (!(found_colon && *(ptr - 1) == '-'))
1019 goterr |= set_flag(ifr.ifr_name, (IFF_UP | IFF_RUNNING));
1022 spp++;
1025 if (neednetmask) {
1026 goterr |= set_netmask(skfd, &ifr, &samask);
1027 didnetmask++;
1030 if (opt_v && goterr)
1031 fprintf(stderr, _("WARNING: at least one error occured. (%d)\n"), goterr);
1033 return (goterr);
1036 struct ifcmd {
1037 int flag;
1038 unsigned long addr;
1039 char *base;
1040 int baselen;
1043 static unsigned char searcher[256];
1045 static int set_ip_using(const char *name, int c, unsigned long ip)
1047 struct ifreq ifr;
1048 struct sockaddr_in sin;
1050 safe_strncpy(ifr.ifr_name, name, IFNAMSIZ);
1051 memset(&sin, 0, sizeof(struct sockaddr));
1052 sin.sin_family = AF_INET;
1053 sin.sin_addr.s_addr = ip;
1054 memcpy(&ifr.ifr_addr, &sin, sizeof(struct sockaddr));
1055 if (ioctl(skfd, c, &ifr) < 0)
1056 return -1;
1057 return 0;
1060 static int do_ifcmd(struct interface *x, struct ifcmd *ptr)
1062 char *z, *e;
1063 struct sockaddr_in *sin;
1064 int i;
1066 if (do_if_fetch(x) < 0)
1067 return 0;
1068 if (strncmp(x->name, ptr->base, ptr->baselen) != 0)
1069 return 0; /* skip */
1070 z = strchr(x->name, ':');
1071 if (!z || !*z)
1072 return 0;
1073 z++;
1074 for (e = z; *e; e++)
1075 if (*e == '-') /* deleted */
1076 return 0;
1077 i = atoi(z);
1078 if (i < 0 || i > 255)
1079 abort();
1080 searcher[i] = 1;
1082 /* copy */
1083 sin = (struct sockaddr_in *)&x->dstaddr;
1084 if (sin->sin_addr.s_addr != ptr->addr) {
1085 return 0;
1088 if (ptr->flag) {
1089 /* turn UP */
1090 if (set_flag(x->name, IFF_UP | IFF_RUNNING) == -1)
1091 return -1;
1092 } else {
1093 /* turn DOWN */
1094 if (clr_flag(x->name, IFF_UP) == -1)
1095 return -1;
1098 return 1; /* all done! */
1102 static int get_nmbc_parent(char *parent,
1103 unsigned long *nm, unsigned long *bc)
1105 struct interface *i;
1106 struct sockaddr_in *sin;
1108 i = lookup_interface(parent);
1109 if (!i)
1110 return -1;
1111 if (do_if_fetch(i) < 0)
1112 return 0;
1113 sin = (struct sockaddr_in *)&i->netmask;
1114 memcpy(nm, &sin->sin_addr.s_addr, sizeof(unsigned long));
1115 sin = (struct sockaddr_in *)&i->broadaddr;
1116 memcpy(bc, &sin->sin_addr.s_addr, sizeof(unsigned long));
1117 return 0;
1120 static int set_ifstate(char *parent, unsigned long ip,
1121 unsigned long nm, unsigned long bc,
1122 int flag)
1124 char buf[IFNAMSIZ];
1125 struct ifcmd pt;
1126 int i;
1128 pt.base = parent;
1129 pt.baselen = strlen(parent);
1130 pt.addr = ip;
1131 pt.flag = flag;
1132 memset(searcher, 0, sizeof(searcher));
1133 i = for_all_interfaces((int (*)(struct interface *,void *))do_ifcmd,
1134 &pt);
1135 if (i == -1)
1136 return -1;
1137 if (i == 1)
1138 return 0;
1140 /* add a new interface */
1141 for (i = 0; i < 256; i++)
1142 if (searcher[i] == 0)
1143 break;
1145 if (i == 256)
1146 return -1; /* FAILURE!!! out of ip addresses */
1148 if (snprintf(buf, IFNAMSIZ, "%s:%d", parent, i) > IFNAMSIZ)
1149 return -1;
1150 if (set_ip_using(buf, SIOCSIFADDR, ip) == -1)
1151 return -1;
1152 if (set_ip_using(buf, SIOCSIFNETMASK, nm) == -1)
1153 return -1;
1154 if (set_ip_using(buf, SIOCSIFBRDADDR, bc) == -1)
1155 return -1;
1156 if (set_flag(buf, IFF_BROADCAST) == -1)
1157 return -1;
1158 return 0;