fixes for man page bugs reported by Hugh Redelmeier.
[oss-qm-packages.git] / ifconfig.c
blobac470b58476552e865c2230b9750da657994f1c9
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.57 2002/12/10 00:56:41 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 if (ap->herror)
533 ap->herror(host);
534 else
535 fprintf(stderr, _("ifconfig: Error resolving '%s' for broadcast\n"), host);
536 goterr = 1;
537 spp++;
538 continue;
540 memcpy((char *) &ifr.ifr_broadaddr, (char *) &sa,
541 sizeof(struct sockaddr));
542 if (ioctl(ap->fd, SIOCSIFBRDADDR, &ifr) < 0) {
543 fprintf(stderr, "SIOCSIFBRDADDR: %s\n",
544 strerror(errno));
545 goterr = 1;
547 spp++;
549 goterr |= set_flag(ifr.ifr_name, IFF_BROADCAST);
550 continue;
552 if (!strcmp(*spp, "dstaddr")) {
553 if (*++spp == NULL)
554 usage();
555 safe_strncpy(host, *spp, (sizeof host));
556 if (ap->input(0, host, &sa) < 0) {
557 if (ap->herror)
558 ap->herror(host);
559 else
560 fprintf(stderr, _("ifconfig: Error resolving '%s' for dstaddr\n"), host);
561 goterr = 1;
562 spp++;
563 continue;
565 memcpy((char *) &ifr.ifr_dstaddr, (char *) &sa,
566 sizeof(struct sockaddr));
567 if (ioctl(ap->fd, SIOCSIFDSTADDR, &ifr) < 0) {
568 fprintf(stderr, "SIOCSIFDSTADDR: %s\n",
569 strerror(errno));
570 goterr = 1;
572 spp++;
573 continue;
575 if (!strcmp(*spp, "netmask")) {
576 if (*++spp == NULL || didnetmask)
577 usage();
578 safe_strncpy(host, *spp, (sizeof host));
579 if (ap->input(0, host, &sa) < 0) {
580 if (ap->herror)
581 ap->herror(host);
582 else
583 fprintf(stderr, _("ifconfig: Error resolving '%s' for netmask\n"), host);
584 goterr = 1;
585 spp++;
586 continue;
588 didnetmask++;
589 goterr |= set_netmask(ap->fd, &ifr, &sa);
590 spp++;
591 continue;
593 #ifdef HAVE_TXQUEUELEN
594 if (!strcmp(*spp, "txqueuelen")) {
595 if (*++spp == NULL)
596 usage();
597 ifr.ifr_qlen = strtoul(*spp, NULL, 0);
598 if (ioctl(skfd, SIOCSIFTXQLEN, &ifr) < 0) {
599 fprintf(stderr, "SIOCSIFTXQLEN: %s\n", strerror(errno));
600 goterr = 1;
602 spp++;
603 continue;
605 #endif
607 if (!strcmp(*spp, "mem_start")) {
608 if (*++spp == NULL)
609 usage();
610 if (ioctl(skfd, SIOCGIFMAP, &ifr) < 0) {
611 fprintf(stderr, "mem_start: SIOCGIFMAP: %s\n", strerror(errno));
612 spp++;
613 goterr = 1;
614 continue;
616 ifr.ifr_map.mem_start = strtoul(*spp, NULL, 0);
617 if (ioctl(skfd, SIOCSIFMAP, &ifr) < 0) {
618 fprintf(stderr, "mem_start: SIOCSIFMAP: %s\n", strerror(errno));
619 goterr = 1;
621 spp++;
622 continue;
624 if (!strcmp(*spp, "io_addr")) {
625 if (*++spp == NULL)
626 usage();
627 if (ioctl(skfd, SIOCGIFMAP, &ifr) < 0) {
628 fprintf(stderr, "io_addr: SIOCGIFMAP: %s\n", strerror(errno));
629 spp++;
630 goterr = 1;
631 continue;
633 ifr.ifr_map.base_addr = strtol(*spp, NULL, 0);
634 if (ioctl(skfd, SIOCSIFMAP, &ifr) < 0) {
635 fprintf(stderr, "io_addr: SIOCSIFMAP: %s\n", strerror(errno));
636 goterr = 1;
638 spp++;
639 continue;
641 if (!strcmp(*spp, "irq")) {
642 if (*++spp == NULL)
643 usage();
644 if (ioctl(skfd, SIOCGIFMAP, &ifr) < 0) {
645 fprintf(stderr, "irq: SIOCGIFMAP: %s\n", strerror(errno));
646 goterr = 1;
647 spp++;
648 continue;
650 ifr.ifr_map.irq = atoi(*spp);
651 if (ioctl(skfd, SIOCSIFMAP, &ifr) < 0) {
652 fprintf(stderr, "irq: SIOCSIFMAP: %s\n", strerror(errno));
653 goterr = 1;
655 spp++;
656 continue;
658 if (!strcmp(*spp, "-pointopoint")) {
659 goterr |= clr_flag(ifr.ifr_name, IFF_POINTOPOINT);
660 spp++;
661 if (test_flag(ifr.ifr_name, IFF_MULTICAST) > 0)
662 fprintf(stderr, _("Warning: Interface %s still in POINTOPOINT mode.\n"), ifr.ifr_name);
663 continue;
665 if (!strcmp(*spp, "pointopoint")) {
666 if (*(spp + 1) != NULL) {
667 spp++;
668 safe_strncpy(host, *spp, (sizeof host));
669 if (ap->input(0, host, &sa)) {
670 if (ap->herror)
671 ap->herror(host);
672 else
673 fprintf(stderr, _("ifconfig: Error resolving '%s' for pointopoint\n"), host);
674 goterr = 1;
675 spp++;
676 continue;
678 memcpy((char *) &ifr.ifr_dstaddr, (char *) &sa,
679 sizeof(struct sockaddr));
680 if (ioctl(ap->fd, SIOCSIFDSTADDR, &ifr) < 0) {
681 fprintf(stderr, "SIOCSIFDSTADDR: %s\n",
682 strerror(errno));
683 goterr = 1;
686 goterr |= set_flag(ifr.ifr_name, IFF_POINTOPOINT);
687 spp++;
688 continue;
691 if (!strcmp(*spp, "hw")) {
692 if (*++spp == NULL)
693 usage();
694 if ((hw = get_hwtype(*spp)) == NULL)
695 usage();
696 if (hw->input == NULL) {
697 fprintf(stderr, _("hw address type `%s' has no handler to set address. failed.\n"), *spp);
698 spp+=2;
699 goterr = 1;
700 continue;
702 if (*++spp == NULL)
703 usage();
704 safe_strncpy(host, *spp, (sizeof host));
705 if (hw->input(host, &sa) < 0) {
706 fprintf(stderr, _("%s: invalid %s address.\n"), host, hw->name);
707 goterr = 1;
708 spp++;
709 continue;
711 memcpy((char *) &ifr.ifr_hwaddr, (char *) &sa,
712 sizeof(struct sockaddr));
713 if (ioctl(skfd, SIOCSIFHWADDR, &ifr) < 0) {
714 if (errno == EBUSY)
715 fprintf(stderr, "SIOCSIFHWADDR: %s - you may need to down the interface\n",
716 strerror(errno));
717 else
718 fprintf(stderr, "SIOCSIFHWADDR: %s\n",
719 strerror(errno));
720 goterr = 1;
722 spp++;
723 continue;
725 #if HAVE_AFINET || HAVE_AFINET6
726 if (!strcmp(*spp, "add")) {
727 if (*++spp == NULL)
728 usage();
729 #if HAVE_AFINET6
730 if (strchr(*spp, ':')) {
731 /* INET6 */
732 if ((cp = strchr(*spp, '/'))) {
733 prefix_len = atol(cp + 1);
734 if ((prefix_len < 0) || (prefix_len > 128))
735 usage();
736 *cp = 0;
737 } else {
738 prefix_len = 128;
740 safe_strncpy(host, *spp, (sizeof host));
741 if (inet6_aftype.input(1, host,
742 (struct sockaddr *) &sa6) < 0) {
743 if (inet6_aftype.herror)
744 inet6_aftype.herror(host);
745 else
746 fprintf(stderr, _("ifconfig: Error resolving '%s' for add\n"), host);
747 goterr = 1;
748 spp++;
749 continue;
751 memcpy((char *) &ifr6.ifr6_addr, (char *) &sa6.sin6_addr,
752 sizeof(struct in6_addr));
754 fd = get_socket_for_af(AF_INET6);
755 if (fd < 0) {
756 fprintf(stderr,
757 _("No support for INET6 on this system.\n"));
758 goterr = 1;
759 spp++;
760 continue;
762 if (ioctl(fd, SIOGIFINDEX, &ifr) < 0) {
763 perror("SIOGIFINDEX");
764 goterr = 1;
765 spp++;
766 continue;
768 ifr6.ifr6_ifindex = ifr.ifr_ifindex;
769 ifr6.ifr6_prefixlen = prefix_len;
770 if (ioctl(fd, SIOCSIFADDR, &ifr6) < 0) {
771 perror("SIOCSIFADDR");
772 goterr = 1;
774 spp++;
775 continue;
777 #endif
778 #ifdef HAVE_AFINET
779 { /* ipv4 address a.b.c.d */
780 unsigned long ip, nm, bc;
781 safe_strncpy(host, *spp, (sizeof host));
782 if (inet_aftype.input(0, host, (struct sockaddr *)&sin) < 0) {
783 ap->herror(host);
784 goterr = 1;
785 spp++;
786 continue;
788 fd = get_socket_for_af(AF_INET);
789 if (fd < 0) {
790 fprintf(stderr,
791 _("No support for INET on this system.\n"));
792 goterr = 1;
793 spp++;
794 continue;
797 memcpy(&ip, &sin.sin_addr.s_addr, sizeof(unsigned long));
799 if (get_nmbc_parent(ifr.ifr_name, &nm, &bc) < 0) {
800 fprintf(stderr, _("Interface %s not initialized\n"),
801 ifr.ifr_name);
802 goterr = 1;
803 spp++;
804 continue;
806 set_ifstate(ifr.ifr_name, ip, nm, bc, 1);
809 spp++;
810 continue;
811 #else
812 fprintf(stderr, _("Bad address.\n"));
813 #endif
815 #endif
817 #if HAVE_AFINET || HAVE_AFINET6
818 if (!strcmp(*spp, "del")) {
819 if (*++spp == NULL)
820 usage();
822 #ifdef SIOCDIFADDR
823 #if HAVE_AFINET6
824 if (strchr(*spp, ':')) { /* INET6 */
825 if ((cp = strchr(*spp, '/'))) {
826 prefix_len = atol(cp + 1);
827 if ((prefix_len < 0) || (prefix_len > 128))
828 usage();
829 *cp = 0;
830 } else {
831 prefix_len = 128;
833 safe_strncpy(host, *spp, (sizeof host));
834 if (inet6_aftype.input(1, host,
835 (struct sockaddr *) &sa6) < 0) {
836 inet6_aftype.herror(host);
837 goterr = 1;
838 spp++;
839 continue;
841 memcpy((char *) &ifr6.ifr6_addr, (char *) &sa6.sin6_addr,
842 sizeof(struct in6_addr));
844 fd = get_socket_for_af(AF_INET6);
845 if (fd < 0) {
846 fprintf(stderr,
847 _("No support for INET6 on this system.\n"));
848 goterr = 1;
849 spp++;
850 continue;
852 if (ioctl(fd, SIOGIFINDEX, &ifr) < 0) {
853 perror("SIOGIFINDEX");
854 goterr = 1;
855 spp++;
856 continue;
858 ifr6.ifr6_ifindex = ifr.ifr_ifindex;
859 ifr6.ifr6_prefixlen = prefix_len;
860 if (opt_v)
861 fprintf(stderr, "now deleting: ioctl(SIOCDIFADDR,{ifindex=%d,prefixlen=%ld})\n",ifr.ifr_ifindex,prefix_len);
862 if (ioctl(fd, SIOCDIFADDR, &ifr6) < 0) {
863 fprintf(stderr, "SIOCDIFADDR: %s\n",
864 strerror(errno));
865 goterr = 1;
867 spp++;
868 continue;
870 #endif
871 #ifdef HAVE_AFINET
873 /* ipv4 address a.b.c.d */
874 unsigned long ip, nm, bc;
875 safe_strncpy(host, *spp, (sizeof host));
876 if (inet_aftype.input(0, host, (struct sockaddr *)&sin) < 0) {
877 ap->herror(host);
878 goterr = 1;
879 spp++;
880 continue;
882 fd = get_socket_for_af(AF_INET);
883 if (fd < 0) {
884 fprintf(stderr, _("No support for INET on this system.\n"));
885 goterr = 1;
886 spp++;
887 continue;
890 memcpy(&ip, &sin.sin_addr.s_addr, sizeof(unsigned long));
892 if (get_nmbc_parent(ifr.ifr_name, &nm, &bc) < 0) {
893 fprintf(stderr, _("Interface %s not initialized\n"),
894 ifr.ifr_name);
895 goterr = 1;
896 spp++;
897 continue;
899 set_ifstate(ifr.ifr_name, ip, nm, bc, 0);
901 spp++;
902 continue;
903 #else
904 fprintf(stderr, _("Bad address.\n"));
905 #endif
906 #else
907 fprintf(stderr, _("Address deletion not supported on this system.\n"));
908 #endif
910 #endif
911 #if HAVE_AFINET6
912 if (!strcmp(*spp, "tunnel")) {
913 if (*++spp == NULL)
914 usage();
915 if ((cp = strchr(*spp, '/'))) {
916 prefix_len = atol(cp + 1);
917 if ((prefix_len < 0) || (prefix_len > 128))
918 usage();
919 *cp = 0;
920 } else {
921 prefix_len = 128;
923 safe_strncpy(host, *spp, (sizeof host));
924 if (inet6_aftype.input(1, host, (struct sockaddr *) &sa6) < 0) {
925 inet6_aftype.herror(host);
926 goterr = 1;
927 spp++;
928 continue;
930 memcpy((char *) &ifr6.ifr6_addr, (char *) &sa6.sin6_addr,
931 sizeof(struct in6_addr));
933 fd = get_socket_for_af(AF_INET6);
934 if (fd < 0) {
935 fprintf(stderr, _("No support for INET6 on this system.\n"));
936 goterr = 1;
937 spp++;
938 continue;
940 if (ioctl(fd, SIOGIFINDEX, &ifr) < 0) {
941 perror("SIOGIFINDEX");
942 goterr = 1;
943 spp++;
944 continue;
946 ifr6.ifr6_ifindex = ifr.ifr_ifindex;
947 ifr6.ifr6_prefixlen = prefix_len;
949 if (ioctl(fd, SIOCSIFDSTADDR, &ifr6) < 0) {
950 fprintf(stderr, "SIOCSIFDSTADDR: %s\n",
951 strerror(errno));
952 goterr = 1;
954 spp++;
955 continue;
957 #endif
959 /* If the next argument is a valid hostname, assume OK. */
960 safe_strncpy(host, *spp, (sizeof host));
962 /* FIXME: sa is too small for INET6 addresses, inet6 should use that too,
963 broadcast is unexpected */
964 if (ap->getmask) {
965 switch (ap->getmask(host, &samask, NULL)) {
966 case -1:
967 usage();
968 break;
969 case 1:
970 if (didnetmask)
971 usage();
973 // remeber to set the netmask from samask later
974 neednetmask = 1;
975 break;
978 if (ap->input == NULL) {
979 fprintf(stderr, _("ifconfig: Cannot set address for this protocol family.\n"));
980 exit(1);
982 if (ap->input(0, host, &sa) < 0) {
983 if (ap->herror)
984 ap->herror(host);
985 else
986 fprintf(stderr,_("ifconfig: error resolving '%s' to set address for af=%s\n"), host, ap->name); fprintf(stderr,
987 _("ifconfig: `--help' gives usage information.\n")); exit(1);
989 memcpy((char *) &ifr.ifr_addr, (char *) &sa, sizeof(struct sockaddr));
991 int r = 0; /* to shut gcc up */
992 switch (ap->af) {
993 #if HAVE_AFINET
994 case AF_INET:
995 fd = get_socket_for_af(AF_INET);
996 if (fd < 0) {
997 fprintf(stderr, _("No support for INET on this system.\n"));
998 exit(1);
1000 r = ioctl(fd, SIOCSIFADDR, &ifr);
1001 break;
1002 #endif
1003 #if HAVE_AFECONET
1004 case AF_ECONET:
1005 fd = get_socket_for_af(AF_ECONET);
1006 if (fd < 0) {
1007 fprintf(stderr, _("No support for ECONET on this system.\n"));
1008 exit(1);
1010 r = ioctl(fd, SIOCSIFADDR, &ifr);
1011 break;
1012 #endif
1013 default:
1014 fprintf(stderr,
1015 _("Don't know how to set addresses for family %d.\n"), ap->af);
1016 exit(1);
1018 if (r < 0) {
1019 perror("SIOCSIFADDR");
1020 goterr = 1;
1025 * Don't do the set_flag() if the address is an alias with a - at the
1026 * end, since it's deleted already! - Roman
1028 * Should really use regex.h here, not sure though how well it'll go
1029 * with the cross-platform support etc.
1032 char *ptr;
1033 short int found_colon = 0;
1034 for (ptr = ifr.ifr_name; *ptr; ptr++ )
1035 if (*ptr == ':') found_colon++;
1037 if (!(found_colon && *(ptr - 1) == '-'))
1038 goterr |= set_flag(ifr.ifr_name, (IFF_UP | IFF_RUNNING));
1041 spp++;
1044 if (neednetmask) {
1045 goterr |= set_netmask(skfd, &ifr, &samask);
1046 didnetmask++;
1049 if (opt_v && goterr)
1050 fprintf(stderr, _("WARNING: at least one error occured. (%d)\n"), goterr);
1052 return (goterr);
1055 struct ifcmd {
1056 int flag;
1057 unsigned long addr;
1058 char *base;
1059 int baselen;
1062 static unsigned char searcher[256];
1064 static int set_ip_using(const char *name, int c, unsigned long ip)
1066 struct ifreq ifr;
1067 struct sockaddr_in sin;
1069 safe_strncpy(ifr.ifr_name, name, IFNAMSIZ);
1070 memset(&sin, 0, sizeof(struct sockaddr));
1071 sin.sin_family = AF_INET;
1072 sin.sin_addr.s_addr = ip;
1073 memcpy(&ifr.ifr_addr, &sin, sizeof(struct sockaddr));
1074 if (ioctl(skfd, c, &ifr) < 0)
1075 return -1;
1076 return 0;
1079 static int do_ifcmd(struct interface *x, struct ifcmd *ptr)
1081 char *z, *e;
1082 struct sockaddr_in *sin;
1083 int i;
1085 if (do_if_fetch(x) < 0)
1086 return 0;
1087 if (strncmp(x->name, ptr->base, ptr->baselen) != 0)
1088 return 0; /* skip */
1089 z = strchr(x->name, ':');
1090 if (!z || !*z)
1091 return 0;
1092 z++;
1093 for (e = z; *e; e++)
1094 if (*e == '-') /* deleted */
1095 return 0;
1096 i = atoi(z);
1097 if (i < 0 || i > 255)
1098 abort();
1099 searcher[i] = 1;
1101 /* copy */
1102 sin = (struct sockaddr_in *)&x->dstaddr;
1103 if (sin->sin_addr.s_addr != ptr->addr) {
1104 return 0;
1107 if (ptr->flag) {
1108 /* turn UP */
1109 if (set_flag(x->name, IFF_UP | IFF_RUNNING) == -1)
1110 return -1;
1111 } else {
1112 /* turn DOWN */
1113 if (clr_flag(x->name, IFF_UP) == -1)
1114 return -1;
1117 return 1; /* all done! */
1121 static int get_nmbc_parent(char *parent,
1122 unsigned long *nm, unsigned long *bc)
1124 struct interface *i;
1125 struct sockaddr_in *sin;
1127 i = lookup_interface(parent);
1128 if (!i)
1129 return -1;
1130 if (do_if_fetch(i) < 0)
1131 return 0;
1132 sin = (struct sockaddr_in *)&i->netmask;
1133 memcpy(nm, &sin->sin_addr.s_addr, sizeof(unsigned long));
1134 sin = (struct sockaddr_in *)&i->broadaddr;
1135 memcpy(bc, &sin->sin_addr.s_addr, sizeof(unsigned long));
1136 return 0;
1139 static int set_ifstate(char *parent, unsigned long ip,
1140 unsigned long nm, unsigned long bc,
1141 int flag)
1143 char buf[IFNAMSIZ];
1144 struct ifcmd pt;
1145 int i;
1147 pt.base = parent;
1148 pt.baselen = strlen(parent);
1149 pt.addr = ip;
1150 pt.flag = flag;
1151 memset(searcher, 0, sizeof(searcher));
1152 i = for_all_interfaces((int (*)(struct interface *,void *))do_ifcmd,
1153 &pt);
1154 if (i == -1)
1155 return -1;
1156 if (i == 1)
1157 return 0;
1159 /* add a new interface */
1160 for (i = 0; i < 256; i++)
1161 if (searcher[i] == 0)
1162 break;
1164 if (i == 256)
1165 return -1; /* FAILURE!!! out of ip addresses */
1167 if (snprintf(buf, IFNAMSIZ, "%s:%d", parent, i) > IFNAMSIZ)
1168 return -1;
1169 if (set_ip_using(buf, SIOCSIFADDR, ip) == -1)
1170 return -1;
1171 if (set_ip_using(buf, SIOCSIFNETMASK, nm) == -1)
1172 return -1;
1173 if (set_ip_using(buf, SIOCSIFBRDADDR, bc) == -1)
1174 return -1;
1175 if (set_flag(buf, IFF_BROADCAST) == -1)
1176 return -1;
1177 return 0;