minor fix to return E_USAGE on -V instead of exit(0);
[oss-qm-packages.git] / ifconfig.c
blob52b4d6fceb38d95838b71ac2df223978844ce193
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.53 2001/11/01 01:54:49 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_i = 0; /* show the statistics */
92 int opt_v = 0; /* debugging output flag */
94 int addr_family = 0; /* currently selected AF */
96 /* for ipv4 add/del modes */
97 static int get_nmbc_parent(char *parent, unsigned long *nm,
98 unsigned long *bc);
99 static int set_ifstate(char *parent, unsigned long ip,
100 unsigned long nm, unsigned long bc,
101 int flag);
103 static int if_print(char *ifname)
105 int res;
107 if (ife_short)
108 printf(_("Iface MTU Met RX-OK RX-ERR RX-DRP RX-OVR TX-OK TX-ERR TX-DRP TX-OVR Flg\n"));
110 if (!ifname) {
111 res = for_all_interfaces(do_if_print, &opt_a);
112 } else {
113 struct interface *ife;
115 ife = lookup_interface(ifname);
116 res = do_if_fetch(ife);
117 if (res >= 0)
118 ife_print(ife);
120 return res;
123 /* Set a certain interface flag. */
124 static int set_flag(char *ifname, short flag)
126 struct ifreq ifr;
128 safe_strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
129 if (ioctl(skfd, SIOCGIFFLAGS, &ifr) < 0) {
130 fprintf(stderr, _("%s: ERROR while getting interface flags: %s\n"),
131 ifname, strerror(errno));
132 return (-1);
134 safe_strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
135 ifr.ifr_flags |= flag;
136 if (ioctl(skfd, SIOCSIFFLAGS, &ifr) < 0) {
137 perror("SIOCSIFFLAGS");
138 return -1;
140 return (0);
143 /* Clear a certain interface flag. */
144 static int clr_flag(char *ifname, short flag)
146 struct ifreq ifr;
147 int fd;
149 if (strchr(ifname, ':')) {
150 /* This is a v4 alias interface. Downing it via a socket for
151 another AF may have bad consequences. */
152 fd = get_socket_for_af(AF_INET);
153 if (fd < 0) {
154 fprintf(stderr, _("No support for INET on this system.\n"));
155 return -1;
157 } else
158 fd = skfd;
160 safe_strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
161 if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) {
162 fprintf(stderr, _("%s: ERROR while getting interface flags: %s\n"),
163 ifname, strerror(errno));
164 return -1;
166 safe_strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
167 ifr.ifr_flags &= ~flag;
168 if (ioctl(fd, SIOCSIFFLAGS, &ifr) < 0) {
169 perror("SIOCSIFFLAGS");
170 return -1;
172 return (0);
175 /** test is a specified flag is set */
176 static int test_flag(char *ifname, short flags)
178 struct ifreq ifr;
179 int fd;
181 if (strchr(ifname, ':')) {
182 /* This is a v4 alias interface. Downing it via a socket for
183 another AF may have bad consequences. */
184 fd = get_socket_for_af(AF_INET);
185 if (fd < 0) {
186 fprintf(stderr, _("No support for INET on this system.\n"));
187 return -1;
189 } else
190 fd = skfd;
192 safe_strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
193 if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) {
194 fprintf(stderr, _("%s: ERROR while testing interface flags: %s\n"),
195 ifname, strerror(errno));
196 return -1;
198 return (ifr.ifr_flags & flags);
201 static void usage(void)
203 fprintf(stderr, _("Usage:\n ifconfig [-a] [-i] [-v] [-s] <interface> [[<AF>] <address>]\n"));
204 #if HAVE_AFINET
205 fprintf(stderr, _(" [add <address>[/<prefixlen>]]\n"));
206 fprintf(stderr, _(" [del <address>[/<prefixlen>]]\n"));
207 fprintf(stderr, _(" [[-]broadcast [<address>]] [[-]pointopoint [<address>]]\n"));
208 fprintf(stderr, _(" [netmask <address>] [dstaddr <address>] [tunnel <address>]\n"));
209 #endif
210 #ifdef SIOCSKEEPALIVE
211 fprintf(stderr, _(" [outfill <NN>] [keepalive <NN>]\n"));
212 #endif
213 fprintf(stderr, _(" [hw <HW> <address>] [metric <NN>] [mtu <NN>]\n"));
214 fprintf(stderr, _(" [[-]trailers] [[-]arp] [[-]allmulti]\n"));
215 fprintf(stderr, _(" [multicast] [[-]promisc]\n"));
216 fprintf(stderr, _(" [mem_start <NN>] [io_addr <NN>] [irq <NN>] [media <type>]\n"));
217 #ifdef HAVE_TXQUEUELEN
218 fprintf(stderr, _(" [txqueuelen <NN>]\n"));
219 #endif
220 #ifdef HAVE_DYNAMIC
221 fprintf(stderr, _(" [[-]dynamic]\n"));
222 #endif
223 fprintf(stderr, _(" [up|down] ...\n\n"));
225 fprintf(stderr, _(" <HW>=Hardware Type.\n"));
226 fprintf(stderr, _(" List of possible hardware types:\n"));
227 print_hwlist(0); /* 1 = ARPable */
228 fprintf(stderr, _(" <AF>=Address family. Default: %s\n"), DFLT_AF);
229 fprintf(stderr, _(" List of possible address families:\n"));
230 print_aflist(0); /* 1 = routeable */
231 exit(E_USAGE);
234 static void version(void)
236 fprintf(stderr, "%s\n%s\n", Release, Version);
237 exit(E_USAGE);
240 static int set_netmask(int skfd, struct ifreq *ifr, struct sockaddr *sa)
242 int err = 0;
244 memcpy((char *) &ifr->ifr_netmask, (char *) sa,
245 sizeof(struct sockaddr));
246 if (ioctl(skfd, SIOCSIFNETMASK, ifr) < 0) {
247 fprintf(stderr, "SIOCSIFNETMASK: %s\n",
248 strerror(errno));
249 err = 1;
251 return err;
254 int main(int argc, char **argv)
256 struct sockaddr sa;
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;
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 fprintf(stderr, "SIOCSIFHWADDR: %s\n",
703 strerror(errno));
704 goterr = 1;
706 spp++;
707 continue;
709 #if HAVE_AFINET || HAVE_AFINET6
710 if (!strcmp(*spp, "add")) {
711 if (*++spp == NULL)
712 usage();
713 #if HAVE_AFINET6
714 if (strchr(*spp, ':')) {
715 /* INET6 */
716 if ((cp = strchr(*spp, '/'))) {
717 prefix_len = atol(cp + 1);
718 if ((prefix_len < 0) || (prefix_len > 128))
719 usage();
720 *cp = 0;
721 } else {
722 prefix_len = 0;
724 safe_strncpy(host, *spp, (sizeof host));
725 if (inet6_aftype.input(1, host,
726 (struct sockaddr *) &sa6) < 0) {
727 inet6_aftype.herror(host);
728 goterr = 1;
729 spp++;
730 continue;
732 memcpy((char *) &ifr6.ifr6_addr, (char *) &sa6.sin6_addr,
733 sizeof(struct in6_addr));
735 fd = get_socket_for_af(AF_INET6);
736 if (fd < 0) {
737 fprintf(stderr,
738 _("No support for INET6 on this system.\n"));
739 goterr = 1;
740 spp++;
741 continue;
743 if (ioctl(fd, SIOGIFINDEX, &ifr) < 0) {
744 perror("SIOGIFINDEX");
745 goterr = 1;
746 spp++;
747 continue;
749 ifr6.ifr6_ifindex = ifr.ifr_ifindex;
750 ifr6.ifr6_prefixlen = prefix_len;
751 if (ioctl(fd, SIOCSIFADDR, &ifr6) < 0) {
752 perror("SIOCSIFADDR");
753 goterr = 1;
755 spp++;
756 continue;
758 #endif
759 #ifdef HAVE_AFINET
760 { /* ipv4 address a.b.c.d */
761 unsigned long ip, nm, bc;
762 safe_strncpy(host, *spp, (sizeof host));
763 if (inet_aftype.input(0, host, (struct sockaddr *)&sin) < 0) {
764 ap->herror(host);
765 goterr = 1;
766 spp++;
767 continue;
769 fd = get_socket_for_af(AF_INET);
770 if (fd < 0) {
771 fprintf(stderr,
772 _("No support for INET on this system.\n"));
773 goterr = 1;
774 spp++;
775 continue;
778 memcpy(&ip, &sin.sin_addr.s_addr, sizeof(unsigned long));
780 if (get_nmbc_parent(ifr.ifr_name, &nm, &bc) < 0) {
781 fprintf(stderr, _("Interface %s not initialized\n"),
782 ifr.ifr_name);
783 goterr = 1;
784 spp++;
785 continue;
787 set_ifstate(ifr.ifr_name, ip, nm, bc, 1);
790 spp++;
791 continue;
792 #else
793 fprintf(stderr, _("Bad address.\n"));
794 #endif
796 #endif
798 #if HAVE_AFINET || HAVE_AFINET6
799 if (!strcmp(*spp, "del")) {
800 if (*++spp == NULL)
801 usage();
803 #ifdef SIOCDIFADDR
804 #if HAVE_AFINET6
805 if (strchr(*spp, ':')) { /* INET6 */
806 if ((cp = strchr(*spp, '/'))) {
807 prefix_len = atol(cp + 1);
808 if ((prefix_len < 0) || (prefix_len > 128))
809 usage();
810 *cp = 0;
811 } else {
812 prefix_len = 0;
814 safe_strncpy(host, *spp, (sizeof host));
815 if (inet6_aftype.input(1, host,
816 (struct sockaddr *) &sa6) < 0) {
817 inet6_aftype.herror(host);
818 goterr = 1;
819 spp++;
820 continue;
822 memcpy((char *) &ifr6.ifr6_addr, (char *) &sa6.sin6_addr,
823 sizeof(struct in6_addr));
825 fd = get_socket_for_af(AF_INET6);
826 if (fd < 0) {
827 fprintf(stderr,
828 _("No support for INET6 on this system.\n"));
829 goterr = 1;
830 spp++;
831 continue;
833 if (ioctl(fd, SIOGIFINDEX, &ifr) < 0) {
834 perror("SIOGIFINDEX");
835 goterr = 1;
836 spp++;
837 continue;
839 ifr6.ifr6_ifindex = ifr.ifr_ifindex;
840 ifr6.ifr6_prefixlen = prefix_len;
841 if (ioctl(fd, SIOCDIFADDR, &ifr6) < 0) {
842 fprintf(stderr, "SIOCDIFADDR: %s\n",
843 strerror(errno));
844 goterr = 1;
846 spp++;
847 continue;
849 #endif
850 #ifdef HAVE_AFINET
852 /* ipv4 address a.b.c.d */
853 unsigned long ip, nm, bc;
854 safe_strncpy(host, *spp, (sizeof host));
855 if (inet_aftype.input(0, host, (struct sockaddr *)&sin) < 0) {
856 ap->herror(host);
857 goterr = 1;
858 spp++;
859 continue;
861 fd = get_socket_for_af(AF_INET);
862 if (fd < 0) {
863 fprintf(stderr, _("No support for INET on this system.\n"));
864 goterr = 1;
865 spp++;
866 continue;
869 memcpy(&ip, &sin.sin_addr.s_addr, sizeof(unsigned long));
871 if (get_nmbc_parent(ifr.ifr_name, &nm, &bc) < 0) {
872 fprintf(stderr, _("Interface %s not initialized\n"),
873 ifr.ifr_name);
874 goterr = 1;
875 spp++;
876 continue;
878 set_ifstate(ifr.ifr_name, ip, nm, bc, 0);
880 spp++;
881 continue;
882 #else
883 fprintf(stderr, _("Bad address.\n"));
884 #endif
885 #else
886 fprintf(stderr, _("Address deletion not supported on this system.\n"));
887 #endif
889 #endif
890 #if HAVE_AFINET6
891 if (!strcmp(*spp, "tunnel")) {
892 if (*++spp == NULL)
893 usage();
894 if ((cp = strchr(*spp, '/'))) {
895 prefix_len = atol(cp + 1);
896 if ((prefix_len < 0) || (prefix_len > 128))
897 usage();
898 *cp = 0;
899 } else {
900 prefix_len = 0;
902 safe_strncpy(host, *spp, (sizeof host));
903 if (inet6_aftype.input(1, host, (struct sockaddr *) &sa6) < 0) {
904 inet6_aftype.herror(host);
905 goterr = 1;
906 spp++;
907 continue;
909 memcpy((char *) &ifr6.ifr6_addr, (char *) &sa6.sin6_addr,
910 sizeof(struct in6_addr));
912 fd = get_socket_for_af(AF_INET6);
913 if (fd < 0) {
914 fprintf(stderr, _("No support for INET6 on this system.\n"));
915 goterr = 1;
916 spp++;
917 continue;
919 if (ioctl(fd, SIOGIFINDEX, &ifr) < 0) {
920 perror("SIOGIFINDEX");
921 goterr = 1;
922 spp++;
923 continue;
925 ifr6.ifr6_ifindex = ifr.ifr_ifindex;
926 ifr6.ifr6_prefixlen = prefix_len;
928 if (ioctl(fd, SIOCSIFDSTADDR, &ifr6) < 0) {
929 fprintf(stderr, "SIOCSIFDSTADDR: %s\n",
930 strerror(errno));
931 goterr = 1;
933 spp++;
934 continue;
936 #endif
938 /* If the next argument is a valid hostname, assume OK. */
939 safe_strncpy(host, *spp, (sizeof host));
941 /* FIXME: sa is too small for INET6 addresses, inet6 should use that too,
942 broadcast is unexpected */
943 if (ap->getmask) {
944 switch (ap->getmask(host, &sa, NULL)) {
945 case -1:
946 usage();
947 break;
948 case 1:
949 if (didnetmask)
950 usage();
952 goterr |= set_netmask(skfd, &ifr, &sa);
953 didnetmask++;
954 break;
957 if (ap->input == NULL) {
958 fprintf(stderr, _("ifconfig: Cannot set address for this protocol family.\n"));
959 exit(1);
961 if (ap->input(0, host, &sa) < 0) {
962 ap->herror(host);
963 fprintf(stderr, _("ifconfig: `--help' gives usage information.\n"));
964 exit(1);
966 memcpy((char *) &ifr.ifr_addr, (char *) &sa, sizeof(struct sockaddr));
968 int r = 0; /* to shut gcc up */
969 switch (ap->af) {
970 #if HAVE_AFINET
971 case AF_INET:
972 fd = get_socket_for_af(AF_INET);
973 if (fd < 0) {
974 fprintf(stderr, _("No support for INET on this system.\n"));
975 exit(1);
977 r = ioctl(fd, SIOCSIFADDR, &ifr);
978 break;
979 #endif
980 #if HAVE_AFECONET
981 case AF_ECONET:
982 fd = get_socket_for_af(AF_ECONET);
983 if (fd < 0) {
984 fprintf(stderr, _("No support for ECONET on this system.\n"));
985 exit(1);
987 r = ioctl(fd, SIOCSIFADDR, &ifr);
988 break;
989 #endif
990 default:
991 fprintf(stderr,
992 _("Don't know how to set addresses for family %d.\n"), ap->af);
993 exit(1);
995 if (r < 0) {
996 perror("SIOCSIFADDR");
997 goterr = 1;
1002 * Don't do the set_flag() if the address is an alias with a - at the
1003 * end, since it's deleted already! - Roman
1005 * Should really use regex.h here, not sure though how well it'll go
1006 * with the cross-platform support etc.
1009 char *ptr;
1010 short int found_colon = 0;
1011 for (ptr = ifr.ifr_name; *ptr; ptr++ )
1012 if (*ptr == ':') found_colon++;
1014 if (!(found_colon && *(ptr - 1) == '-'))
1015 goterr |= set_flag(ifr.ifr_name, (IFF_UP | IFF_RUNNING));
1018 spp++;
1021 if (opt_v && goterr)
1022 fprintf(stderr, _("WARNING: at least one error occured. (%d)\n"), goterr);
1024 return (goterr);
1027 struct ifcmd {
1028 int flag;
1029 unsigned long addr;
1030 char *base;
1031 int baselen;
1034 static unsigned char searcher[256];
1036 static int set_ip_using(const char *name, int c, unsigned long ip)
1038 struct ifreq ifr;
1039 struct sockaddr_in sin;
1041 safe_strncpy(ifr.ifr_name, name, IFNAMSIZ);
1042 memset(&sin, 0, sizeof(struct sockaddr));
1043 sin.sin_family = AF_INET;
1044 sin.sin_addr.s_addr = ip;
1045 memcpy(&ifr.ifr_addr, &sin, sizeof(struct sockaddr));
1046 if (ioctl(skfd, c, &ifr) < 0)
1047 return -1;
1048 return 0;
1051 static int do_ifcmd(struct interface *x, struct ifcmd *ptr)
1053 char *z, *e;
1054 struct sockaddr_in *sin;
1055 int i;
1057 if (do_if_fetch(x) < 0)
1058 return 0;
1059 if (strncmp(x->name, ptr->base, ptr->baselen) != 0)
1060 return 0; /* skip */
1061 z = strchr(x->name, ':');
1062 if (!z || !*z)
1063 return 0;
1064 z++;
1065 for (e = z; *e; e++)
1066 if (*e == '-') /* deleted */
1067 return 0;
1068 i = atoi(z);
1069 if (i < 0 || i > 255)
1070 abort();
1071 searcher[i] = 1;
1073 /* copy */
1074 sin = (struct sockaddr_in *)&x->dstaddr;
1075 if (sin->sin_addr.s_addr != ptr->addr) {
1076 return 0;
1079 if (ptr->flag) {
1080 /* turn UP */
1081 if (set_flag(x->name, IFF_UP | IFF_RUNNING) == -1)
1082 return -1;
1083 } else {
1084 /* turn DOWN */
1085 if (clr_flag(x->name, IFF_UP) == -1)
1086 return -1;
1089 return 1; /* all done! */
1093 static int get_nmbc_parent(char *parent,
1094 unsigned long *nm, unsigned long *bc)
1096 struct interface *i;
1097 struct sockaddr_in *sin;
1099 i = lookup_interface(parent);
1100 if (!i)
1101 return -1;
1102 if (do_if_fetch(i) < 0)
1103 return 0;
1104 sin = (struct sockaddr_in *)&i->netmask;
1105 memcpy(nm, &sin->sin_addr.s_addr, sizeof(unsigned long));
1106 sin = (struct sockaddr_in *)&i->broadaddr;
1107 memcpy(bc, &sin->sin_addr.s_addr, sizeof(unsigned long));
1108 return 0;
1111 static int set_ifstate(char *parent, unsigned long ip,
1112 unsigned long nm, unsigned long bc,
1113 int flag)
1115 char buf[IFNAMSIZ];
1116 struct ifcmd pt;
1117 int i;
1119 pt.base = parent;
1120 pt.baselen = strlen(parent);
1121 pt.addr = ip;
1122 pt.flag = flag;
1123 memset(searcher, 0, sizeof(searcher));
1124 i = for_all_interfaces((int (*)(struct interface *,void *))do_ifcmd,
1125 &pt);
1126 if (i == -1)
1127 return -1;
1128 if (i == 1)
1129 return 0;
1131 /* add a new interface */
1132 for (i = 0; i < 256; i++)
1133 if (searcher[i] == 0)
1134 break;
1136 if (i == 256)
1137 return -1; /* FAILURE!!! out of ip addresses */
1139 if (snprintf(buf, IFNAMSIZ, "%s:%d", parent, i) > IFNAMSIZ)
1140 return -1;
1141 if (set_ip_using(buf, SIOCSIFADDR, ip) == -1)
1142 return -1;
1143 if (set_ip_using(buf, SIOCSIFNETMASK, nm) == -1)
1144 return -1;
1145 if (set_ip_using(buf, SIOCSIFBRDADDR, bc) == -1)
1146 return -1;
1147 if (set_flag(buf, IFF_BROADCAST) == -1)
1148 return -1;
1149 return 0;