Use setlocale at program initialisation.
[oss-qm-packages.git] / ifconfig.c
blob0c6ce0806778e6f2e52af14680b0c604e48d146a
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.47 2001/04/08 17:05:05 pb 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.41 (2001-04-01)";
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,
98 unsigned long *nm, unsigned long *bc);
99 static int set_ifstate(char *parent,
100 unsigned long ip,
101 unsigned long nm,
102 unsigned long bc,
103 int flag);
106 static int if_print(char *ifname)
108 int res;
110 if (ife_short)
111 printf(_("Iface MTU Met RX-OK RX-ERR RX-DRP RX-OVR TX-OK TX-ERR TX-DRP TX-OVR Flg\n"));
113 if (!ifname) {
114 res = for_all_interfaces(do_if_print, &opt_a);
115 } else {
116 struct interface *ife;
118 ife = lookup_interface(ifname);
119 res = do_if_fetch(ife);
120 if (res >= 0)
121 ife_print(ife);
123 return res;
126 /* Set a certain interface flag. */
127 static int set_flag(char *ifname, short flag)
129 struct ifreq ifr;
131 strcpy(ifr.ifr_name, ifname);
132 if (ioctl(skfd, SIOCGIFFLAGS, &ifr) < 0) {
133 fprintf(stderr, _("%s: unknown interface: %s\n"),
134 ifname, strerror(errno));
135 return (-1);
137 strcpy(ifr.ifr_name, ifname);
138 ifr.ifr_flags |= flag;
139 if (ioctl(skfd, SIOCSIFFLAGS, &ifr) < 0) {
140 perror("SIOCSIFFLAGS");
141 return -1;
143 return (0);
146 /* Clear a certain interface flag. */
147 static int clr_flag(char *ifname, short flag)
149 struct ifreq ifr;
150 int fd;
152 if (strchr(ifname, ':')) {
153 /* This is a v4 alias interface. Downing it via a socket for
154 another AF may have bad consequences. */
155 fd = get_socket_for_af(AF_INET);
156 if (fd < 0) {
157 fprintf(stderr, _("No support for INET on this system.\n"));
158 return -1;
160 } else
161 fd = skfd;
163 strcpy(ifr.ifr_name, ifname);
164 if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) {
165 fprintf(stderr, _("%s: unknown interface: %s\n"),
166 ifname, strerror(errno));
167 return -1;
169 strcpy(ifr.ifr_name, ifname);
170 ifr.ifr_flags &= ~flag;
171 if (ioctl(fd, SIOCSIFFLAGS, &ifr) < 0) {
172 perror("SIOCSIFFLAGS");
173 return -1;
175 return (0);
178 static void usage(void)
180 fprintf(stderr, _("Usage:\n ifconfig [-a] [-i] [-v] [-s] <interface> [[<AF>] <address>]\n"));
181 #if HAVE_AFINET
182 fprintf(stderr, _(" [add <address>[/<prefixlen>]]\n"));
183 fprintf(stderr, _(" [del <address>[/<prefixlen>]]\n"));
184 fprintf(stderr, _(" [[-]broadcast [<address>]] [[-]pointopoint [<address>]]\n"));
185 fprintf(stderr, _(" [netmask <address>] [dstaddr <address>] [tunnel <address>]\n"));
186 #endif
187 #ifdef SIOCSKEEPALIVE
188 fprintf(stderr, _(" [outfill <NN>] [keepalive <NN>]\n"));
189 #endif
190 fprintf(stderr, _(" [hw <HW> <address>] [metric <NN>] [mtu <NN>]\n"));
191 fprintf(stderr, _(" [[-]trailers] [[-]arp] [[-]allmulti]\n"));
192 fprintf(stderr, _(" [multicast] [[-]promisc]\n"));
193 fprintf(stderr, _(" [mem_start <NN>] [io_addr <NN>] [irq <NN>] [media <type>]\n"));
194 #ifdef HAVE_TXQUEUELEN
195 fprintf(stderr, _(" [txqueuelen <NN>]\n"));
196 #endif
197 #ifdef HAVE_DYNAMIC
198 fprintf(stderr, _(" [[-]dynamic]\n"));
199 #endif
200 fprintf(stderr, _(" [up|down] ...\n\n"));
202 fprintf(stderr, _(" <HW>=Hardware Type.\n"));
203 fprintf(stderr, _(" List of possible hardware types:\n"));
204 print_hwlist(0); /* 1 = ARPable */
205 fprintf(stderr, _(" <AF>=Address family. Default: %s\n"), DFLT_AF);
206 fprintf(stderr, _(" List of possible address families:\n"));
207 print_aflist(0); /* 1 = routeable */
208 exit(E_USAGE);
211 static void version(void)
213 fprintf(stderr, "%s\n%s\n", Release, Version);
214 exit(1);
217 static int set_netmask(int skfd, struct ifreq *ifr, struct sockaddr *sa)
219 int err = 0;
221 memcpy((char *) &ifr->ifr_netmask, (char *) sa,
222 sizeof(struct sockaddr));
223 if (ioctl(skfd, SIOCSIFNETMASK, ifr) < 0) {
224 fprintf(stderr, "SIOCSIFNETMASK: %s\n",
225 strerror(errno));
226 err = 1;
228 return 0;
231 int main(int argc, char **argv)
233 struct sockaddr sa;
234 struct sockaddr_in sin;
235 char host[128];
236 struct aftype *ap;
237 struct hwtype *hw;
238 struct ifreq ifr;
239 int goterr = 0, didnetmask = 0;
240 char **spp;
241 int fd;
242 #if HAVE_AFINET6
243 extern struct aftype inet6_aftype;
244 struct sockaddr_in6 sa6;
245 struct in6_ifreq ifr6;
246 unsigned long prefix_len;
247 char *cp;
248 #endif
249 #if HAVE_AFINET
250 extern struct aftype inet_aftype;
251 #endif
253 #if I18N
254 setlocale (LC_ALL, "");
255 bindtextdomain("net-tools", "/usr/share/locale");
256 textdomain("net-tools");
257 #endif
259 /* Find any options. */
260 argc--;
261 argv++;
262 while (argc && *argv[0] == '-') {
263 if (!strcmp(*argv, "-a"))
264 opt_a = 1;
266 else if (!strcmp(*argv, "-s"))
267 ife_short = 1;
269 else if (!strcmp(*argv, "-v"))
270 opt_v = 1;
272 else if (!strcmp(*argv, "-V") || !strcmp(*argv, "-version") ||
273 !strcmp(*argv, "--version"))
274 version();
276 else if (!strcmp(*argv, "-?") || !strcmp(*argv, "-h") ||
277 !strcmp(*argv, "-help") || !strcmp(*argv, "--help"))
278 usage();
280 else {
281 fprintf(stderr, _("ifconfig: option `%s' not recognised.\n"),
282 argv[0]);
283 fprintf(stderr, _("ifconfig: `--help' gives usage information.\n"));
284 exit(1);
287 argv++;
288 argc--;
291 /* Create a channel to the NET kernel. */
292 if ((skfd = sockets_open(0)) < 0) {
293 perror("socket");
294 exit(1);
297 /* Do we have to show the current setup? */
298 if (argc == 0) {
299 int err = if_print((char *) NULL);
300 (void) close(skfd);
301 exit(err < 0);
303 /* No. Fetch the interface name. */
304 spp = argv;
305 safe_strncpy(ifr.ifr_name, *spp++, IFNAMSIZ);
306 if (*spp == (char *) NULL) {
307 int err = if_print(ifr.ifr_name);
308 (void) close(skfd);
309 exit(err < 0);
312 /* The next argument is either an address family name, or an option. */
313 if ((ap = get_aftype(*spp)) != NULL)
314 spp++; /* it was a AF name */
315 else
316 ap = get_aftype(DFLT_AF);
318 if (ap) {
319 addr_family = ap->af;
320 skfd = ap->fd;
323 /* Process the remaining arguments. */
324 while (*spp != (char *) NULL) {
325 if (!strcmp(*spp, "arp")) {
326 goterr |= clr_flag(ifr.ifr_name, IFF_NOARP);
327 spp++;
328 continue;
330 if (!strcmp(*spp, "-arp")) {
331 goterr |= set_flag(ifr.ifr_name, IFF_NOARP);
332 spp++;
333 continue;
335 #ifdef IFF_PORTSEL
336 if (!strcmp(*spp, "media") || !strcmp(*spp, "port")) {
337 if (*++spp == NULL)
338 usage();
339 if (!strcasecmp(*spp, "auto")) {
340 goterr |= set_flag(ifr.ifr_name, IFF_AUTOMEDIA);
341 } else {
342 int i, j, newport;
343 char *endp;
344 newport = strtol(*spp, &endp, 10);
345 if (*endp != 0) {
346 newport = -1;
347 for (i = 0; if_port_text[i][0] && newport == -1; i++) {
348 for (j = 0; if_port_text[i][j]; j++) {
349 if (!strcasecmp(*spp, if_port_text[i][j])) {
350 newport = i;
351 break;
356 spp++;
357 if (newport == -1) {
358 fprintf(stderr, _("Unknown media type.\n"));
359 goterr = 1;
360 } else {
361 if (ioctl(skfd, SIOCGIFMAP, &ifr) < 0) {
362 perror("port: SIOCGIFMAP");
363 goterr = 1;
364 continue;
366 ifr.ifr_map.port = newport;
367 if (ioctl(skfd, SIOCSIFMAP, &ifr) < 0) {
368 perror("port: SIOCSIFMAP");
369 goterr = 1;
373 continue;
375 #endif
377 if (!strcmp(*spp, "trailers")) {
378 goterr |= clr_flag(ifr.ifr_name, IFF_NOTRAILERS);
379 spp++;
380 continue;
382 if (!strcmp(*spp, "-trailers")) {
383 goterr |= set_flag(ifr.ifr_name, IFF_NOTRAILERS);
384 spp++;
385 continue;
387 if (!strcmp(*spp, "promisc")) {
388 goterr |= set_flag(ifr.ifr_name, IFF_PROMISC);
389 spp++;
390 continue;
392 if (!strcmp(*spp, "-promisc")) {
393 goterr |= clr_flag(ifr.ifr_name, IFF_PROMISC);
394 spp++;
395 continue;
397 if (!strcmp(*spp, "multicast")) {
398 goterr |= set_flag(ifr.ifr_name, IFF_MULTICAST);
399 spp++;
400 continue;
402 if (!strcmp(*spp, "-multicast")) {
403 goterr |= clr_flag(ifr.ifr_name, IFF_MULTICAST);
404 spp++;
405 continue;
407 if (!strcmp(*spp, "allmulti")) {
408 goterr |= set_flag(ifr.ifr_name, IFF_ALLMULTI);
409 spp++;
410 continue;
412 if (!strcmp(*spp, "-allmulti")) {
413 goterr |= clr_flag(ifr.ifr_name, IFF_ALLMULTI);
414 spp++;
415 continue;
417 if (!strcmp(*spp, "up")) {
418 goterr |= set_flag(ifr.ifr_name, (IFF_UP | IFF_RUNNING));
419 spp++;
420 continue;
422 if (!strcmp(*spp, "down")) {
423 goterr |= clr_flag(ifr.ifr_name, IFF_UP);
424 spp++;
425 continue;
427 #ifdef HAVE_DYNAMIC
428 if (!strcmp(*spp, "dynamic")) {
429 goterr |= set_flag(ifr.ifr_name, IFF_DYNAMIC);
430 spp++;
431 continue;
433 if (!strcmp(*spp, "-dynamic")) {
434 goterr |= clr_flag(ifr.ifr_name, IFF_DYNAMIC);
435 spp++;
436 continue;
438 #endif
440 if (!strcmp(*spp, "metric")) {
441 if (*++spp == NULL)
442 usage();
443 ifr.ifr_metric = atoi(*spp);
444 if (ioctl(skfd, SIOCSIFMETRIC, &ifr) < 0) {
445 fprintf(stderr, "SIOCSIFMETRIC: %s\n", strerror(errno));
446 goterr = 1;
448 spp++;
449 continue;
451 if (!strcmp(*spp, "mtu")) {
452 if (*++spp == NULL)
453 usage();
454 ifr.ifr_mtu = atoi(*spp);
455 if (ioctl(skfd, SIOCSIFMTU, &ifr) < 0) {
456 fprintf(stderr, "SIOCSIFMTU: %s\n", strerror(errno));
457 goterr = 1;
459 spp++;
460 continue;
462 #ifdef SIOCSKEEPALIVE
463 if (!strcmp(*spp, "keepalive")) {
464 if (*++spp == NULL)
465 usage();
466 ifr.ifr_data = (caddr_t) atoi(*spp);
467 if (ioctl(skfd, SIOCSKEEPALIVE, &ifr) < 0) {
468 fprintf(stderr, "SIOCSKEEPALIVE: %s\n", strerror(errno));
469 goterr = 1;
471 spp++;
472 continue;
474 #endif
476 #ifdef SIOCSOUTFILL
477 if (!strcmp(*spp, "outfill")) {
478 if (*++spp == NULL)
479 usage();
480 ifr.ifr_data = (caddr_t) atoi(*spp);
481 if (ioctl(skfd, SIOCSOUTFILL, &ifr) < 0) {
482 fprintf(stderr, "SIOCSOUTFILL: %s\n", strerror(errno));
483 goterr = 1;
485 spp++;
486 continue;
488 #endif
490 if (!strcmp(*spp, "-broadcast")) {
491 goterr |= clr_flag(ifr.ifr_name, IFF_BROADCAST);
492 spp++;
493 continue;
495 if (!strcmp(*spp, "broadcast")) {
496 if (*++spp != NULL) {
497 safe_strncpy(host, *spp, (sizeof host));
498 if (ap->input(0, host, &sa) < 0) {
499 ap->herror(host);
500 goterr = 1;
501 spp++;
502 continue;
504 memcpy((char *) &ifr.ifr_broadaddr, (char *) &sa,
505 sizeof(struct sockaddr));
506 if (ioctl(ap->fd, SIOCSIFBRDADDR, &ifr) < 0) {
507 fprintf(stderr, "SIOCSIFBRDADDR: %s\n",
508 strerror(errno));
509 goterr = 1;
511 spp++;
513 goterr |= set_flag(ifr.ifr_name, IFF_BROADCAST);
514 continue;
516 if (!strcmp(*spp, "dstaddr")) {
517 if (*++spp == NULL)
518 usage();
519 safe_strncpy(host, *spp, (sizeof host));
520 if (ap->input(0, host, &sa) < 0) {
521 ap->herror(host);
522 goterr = 1;
523 spp++;
524 continue;
526 memcpy((char *) &ifr.ifr_dstaddr, (char *) &sa,
527 sizeof(struct sockaddr));
528 if (ioctl(ap->fd, SIOCSIFDSTADDR, &ifr) < 0) {
529 fprintf(stderr, "SIOCSIFDSTADDR: %s\n",
530 strerror(errno));
531 goterr = 1;
533 spp++;
534 continue;
536 if (!strcmp(*spp, "netmask")) {
537 if (*++spp == NULL || didnetmask)
538 usage();
539 safe_strncpy(host, *spp, (sizeof host));
540 if (ap->input(0, host, &sa) < 0) {
541 ap->herror(host);
542 goterr = 1;
543 spp++;
544 continue;
546 didnetmask++;
547 goterr = set_netmask(ap->fd, &ifr, &sa);
548 spp++;
549 continue;
551 #ifdef HAVE_TXQUEUELEN
552 if (!strcmp(*spp, "txqueuelen")) {
553 if (*++spp == NULL)
554 usage();
555 ifr.ifr_qlen = strtoul(*spp, NULL, 0);
556 if (ioctl(skfd, SIOCSIFTXQLEN, &ifr) < 0) {
557 fprintf(stderr, "SIOCSIFTXQLEN: %s\n", strerror(errno));
558 goterr = 1;
560 spp++;
561 continue;
563 #endif
565 if (!strcmp(*spp, "mem_start")) {
566 if (*++spp == NULL)
567 usage();
568 if (ioctl(skfd, SIOCGIFMAP, &ifr) < 0) {
569 fprintf(stderr, "mem_start: SIOCGIFMAP: %s\n", strerror(errno));
570 spp++;
571 goterr = 1;
572 continue;
574 ifr.ifr_map.mem_start = strtoul(*spp, NULL, 0);
575 if (ioctl(skfd, SIOCSIFMAP, &ifr) < 0) {
576 fprintf(stderr, "mem_start: SIOCSIFMAP: %s\n", strerror(errno));
577 goterr = 1;
579 spp++;
580 continue;
582 if (!strcmp(*spp, "io_addr")) {
583 if (*++spp == NULL)
584 usage();
585 if (ioctl(skfd, SIOCGIFMAP, &ifr) < 0) {
586 fprintf(stderr, "io_addr: SIOCGIFMAP: %s\n", strerror(errno));
587 spp++;
588 goterr = 1;
589 continue;
591 ifr.ifr_map.base_addr = strtol(*spp, NULL, 0);
592 if (ioctl(skfd, SIOCSIFMAP, &ifr) < 0) {
593 fprintf(stderr, "io_addr: SIOCSIFMAP: %s\n", strerror(errno));
594 goterr = 1;
596 spp++;
597 continue;
599 if (!strcmp(*spp, "irq")) {
600 if (*++spp == NULL)
601 usage();
602 if (ioctl(skfd, SIOCGIFMAP, &ifr) < 0) {
603 fprintf(stderr, "irq: SIOCGIFMAP: %s\n", strerror(errno));
604 goterr = 1;
605 spp++;
606 continue;
608 ifr.ifr_map.irq = atoi(*spp);
609 if (ioctl(skfd, SIOCSIFMAP, &ifr) < 0) {
610 fprintf(stderr, "irq: SIOCSIFMAP: %s\n", strerror(errno));
611 goterr = 1;
613 spp++;
614 continue;
616 if (!strcmp(*spp, "-pointopoint")) {
617 goterr |= clr_flag(ifr.ifr_name, IFF_POINTOPOINT);
618 spp++;
619 continue;
621 if (!strcmp(*spp, "pointopoint")) {
622 if (*(spp + 1) != NULL) {
623 spp++;
624 safe_strncpy(host, *spp, (sizeof host));
625 if (ap->input(0, host, &sa)) {
626 ap->herror(host);
627 goterr = 1;
628 spp++;
629 continue;
631 memcpy((char *) &ifr.ifr_dstaddr, (char *) &sa,
632 sizeof(struct sockaddr));
633 if (ioctl(ap->fd, SIOCSIFDSTADDR, &ifr) < 0) {
634 fprintf(stderr, "SIOCSIFDSTADDR: %s\n",
635 strerror(errno));
636 goterr = 1;
639 goterr |= set_flag(ifr.ifr_name, IFF_POINTOPOINT);
640 spp++;
641 continue;
644 if (!strcmp(*spp, "hw")) {
645 if (*++spp == NULL)
646 usage();
647 if ((hw = get_hwtype(*spp)) == NULL)
648 usage();
649 if (hw->input == NULL) {
650 fprintf(stderr, _("hw address type `%s' has no handler to set address. failed.\n"), *spp);
651 spp+=2;
652 goterr = 1;
653 continue;
655 if (*++spp == NULL)
656 usage();
657 safe_strncpy(host, *spp, (sizeof host));
658 if (hw->input(host, &sa) < 0) {
659 fprintf(stderr, _("%s: invalid %s address.\n"), host, hw->name);
660 goterr = 1;
661 spp++;
662 continue;
664 memcpy((char *) &ifr.ifr_hwaddr, (char *) &sa,
665 sizeof(struct sockaddr));
666 if (ioctl(skfd, SIOCSIFHWADDR, &ifr) < 0) {
667 fprintf(stderr, "SIOCSIFHWADDR: %s\n",
668 strerror(errno));
669 goterr = 1;
671 spp++;
672 continue;
674 #if HAVE_AFINET || HAVE_AFINET6
675 if (!strcmp(*spp, "add")) {
676 if (*++spp == NULL)
677 usage();
678 #if HAVE_AFINET6
679 if (strchr(*spp, ':')) {
680 /* INET6 */
681 if ((cp = strchr(*spp, '/'))) {
682 prefix_len = atol(cp + 1);
683 if ((prefix_len < 0) || (prefix_len > 128))
684 usage();
685 *cp = 0;
686 } else {
687 prefix_len = 0;
689 safe_strncpy(host, *spp, (sizeof host));
690 if (inet6_aftype.input(1, host,
691 (struct sockaddr *) &sa6) < 0) {
692 inet6_aftype.herror(host);
693 goterr = 1;
694 spp++;
695 continue;
697 memcpy((char *) &ifr6.ifr6_addr, (char *) &sa6.sin6_addr,
698 sizeof(struct in6_addr));
700 fd = get_socket_for_af(AF_INET6);
701 if (fd < 0) {
702 fprintf(stderr,
703 _("No support for INET6 on this system.\n"));
704 goterr = 1;
705 spp++;
706 continue;
708 if (ioctl(fd, SIOGIFINDEX, &ifr) < 0) {
709 perror("SIOGIFINDEX");
710 goterr = 1;
711 spp++;
712 continue;
714 ifr6.ifr6_ifindex = ifr.ifr_ifindex;
715 ifr6.ifr6_prefixlen = prefix_len;
716 if (ioctl(fd, SIOCSIFADDR, &ifr6) < 0) {
717 perror("SIOCSIFADDR");
718 goterr = 1;
720 spp++;
721 continue;
723 #endif
724 #ifdef HAVE_AFINET
725 { /* ipv4 address a.b.c.d */
726 unsigned long ip, nm, bc;
727 safe_strncpy(host, *spp, (sizeof host));
728 if (inet_aftype.input(0, host, (struct sockaddr *)&sin) < 0) {
729 ap->herror(host);
730 goterr = 1;
731 spp++;
732 continue;
734 fd = get_socket_for_af(AF_INET);
735 if (fd < 0) {
736 fprintf(stderr,
737 _("No support for INET on this system.\n"));
738 goterr = 1;
739 spp++;
740 continue;
743 memcpy(&ip, &sin.sin_addr.s_addr, sizeof(unsigned long));
745 if (get_nmbc_parent(ifr.ifr_name, &nm, &bc) < 0) {
746 fprintf(stderr, _("Interface %s not initialized\n"),
747 ifr.ifr_name);
748 goterr = 1;
749 spp++;
750 continue;
752 set_ifstate(ifr.ifr_name, ip, nm, bc, 1);
755 spp++;
756 continue;
757 #else
758 fprintf(stderr, _("Bad address.\n"));
759 #endif
761 #endif
763 #if HAVE_AFINET || HAVE_AFINET6
764 if (!strcmp(*spp, "del")) {
765 if (*++spp == NULL)
766 usage();
768 #ifdef SIOCDIFADDR
769 #if HAVE_AFINET6
770 if (strchr(*spp, ':')) { /* INET6 */
771 if ((cp = strchr(*spp, '/'))) {
772 prefix_len = atol(cp + 1);
773 if ((prefix_len < 0) || (prefix_len > 128))
774 usage();
775 *cp = 0;
776 } else {
777 prefix_len = 0;
779 safe_strncpy(host, *spp, (sizeof host));
780 if (inet6_aftype.input(1, host,
781 (struct sockaddr *) &sa6) < 0) {
782 inet6_aftype.herror(host);
783 goterr = 1;
784 spp++;
785 continue;
787 memcpy((char *) &ifr6.ifr6_addr, (char *) &sa6.sin6_addr,
788 sizeof(struct in6_addr));
790 fd = get_socket_for_af(AF_INET6);
791 if (fd < 0) {
792 fprintf(stderr,
793 _("No support for INET6 on this system.\n"));
794 goterr = 1;
795 spp++;
796 continue;
798 if (ioctl(fd, SIOGIFINDEX, &ifr) < 0) {
799 perror("SIOGIFINDEX");
800 goterr = 1;
801 spp++;
802 continue;
804 ifr6.ifr6_ifindex = ifr.ifr_ifindex;
805 ifr6.ifr6_prefixlen = prefix_len;
806 if (ioctl(fd, SIOCDIFADDR, &ifr6) < 0) {
807 fprintf(stderr, "SIOCDIFADDR: %s\n",
808 strerror(errno));
809 goterr = 1;
811 spp++;
812 continue;
814 #endif
815 #ifdef HAVE_AFINET
817 /* ipv4 address a.b.c.d */
818 unsigned long ip, nm, bc;
819 safe_strncpy(host, *spp, (sizeof host));
820 if (inet_aftype.input(0, host, (struct sockaddr *)&sin) < 0) {
821 ap->herror(host);
822 goterr = 1;
823 spp++;
824 continue;
826 fd = get_socket_for_af(AF_INET);
827 if (fd < 0) {
828 fprintf(stderr, _("No support for INET on this system.\n"));
829 goterr = 1;
830 spp++;
831 continue;
834 memcpy(&ip, &sin.sin_addr.s_addr, sizeof(unsigned long));
836 if (get_nmbc_parent(ifr.ifr_name, &nm, &bc) < 0) {
837 fprintf(stderr, _("Interface %s not initialized\n"),
838 ifr.ifr_name);
839 goterr = 1;
840 spp++;
841 continue;
843 set_ifstate(ifr.ifr_name, ip, nm, bc, 0);
845 spp++;
846 continue;
847 #else
848 fprintf(stderr, _("Bad address.\n"));
849 #endif
850 #else
851 fprintf(stderr, _("Address deletion not supported on this system.\n"));
852 #endif
854 #endif
855 #if HAVE_AFINET6
856 if (!strcmp(*spp, "tunnel")) {
857 if (*++spp == NULL)
858 usage();
859 if ((cp = strchr(*spp, '/'))) {
860 prefix_len = atol(cp + 1);
861 if ((prefix_len < 0) || (prefix_len > 128))
862 usage();
863 *cp = 0;
864 } else {
865 prefix_len = 0;
867 safe_strncpy(host, *spp, (sizeof host));
868 if (inet6_aftype.input(1, host, (struct sockaddr *) &sa6) < 0) {
869 inet6_aftype.herror(host);
870 goterr = 1;
871 spp++;
872 continue;
874 memcpy((char *) &ifr6.ifr6_addr, (char *) &sa6.sin6_addr,
875 sizeof(struct in6_addr));
877 fd = get_socket_for_af(AF_INET6);
878 if (fd < 0) {
879 fprintf(stderr, _("No support for INET6 on this system.\n"));
880 goterr = 1;
881 spp++;
882 continue;
884 if (ioctl(fd, SIOGIFINDEX, &ifr) < 0) {
885 perror("SIOGIFINDEX");
886 goterr = 1;
887 spp++;
888 continue;
890 ifr6.ifr6_ifindex = ifr.ifr_ifindex;
891 ifr6.ifr6_prefixlen = prefix_len;
893 if (ioctl(fd, SIOCSIFDSTADDR, &ifr6) < 0) {
894 fprintf(stderr, "SIOCSIFDSTADDR: %s\n",
895 strerror(errno));
896 goterr = 1;
898 spp++;
899 continue;
901 #endif
903 /* If the next argument is a valid hostname, assume OK. */
904 safe_strncpy(host, *spp, (sizeof host));
906 /* FIXME: sa is too small for INET6 addresses, inet6 should use that too,
907 broadcast is unexpected */
908 if (ap->getmask) {
909 switch (ap->getmask(host, &sa, NULL)) {
910 case -1:
911 usage();
912 break;
913 case 1:
914 if (didnetmask)
915 usage();
917 goterr = set_netmask(skfd, &ifr, &sa);
918 didnetmask++;
919 break;
922 if (ap->input(0, host, &sa) < 0) {
923 ap->herror(host);
924 fprintf(stderr, _("ifconfig: `--help' gives usage information.\n"));
926 memcpy((char *) &ifr.ifr_addr, (char *) &sa, sizeof(struct sockaddr));
928 int r = 0; /* to shut gcc up */
929 switch (ap->af) {
930 #if HAVE_AFINET
931 case AF_INET:
932 fd = get_socket_for_af(AF_INET);
933 if (fd < 0) {
934 fprintf(stderr, _("No support for INET on this system.\n"));
935 exit(1);
937 r = ioctl(fd, SIOCSIFADDR, &ifr);
938 break;
939 #endif
940 #if HAVE_AFECONET
941 case AF_ECONET:
942 fd = get_socket_for_af(AF_ECONET);
943 if (fd < 0) {
944 fprintf(stderr, _("No support for ECONET on this system.\n"));
945 exit(1);
947 r = ioctl(fd, SIOCSIFADDR, &ifr);
948 break;
949 #endif
950 default:
951 fprintf(stderr,
952 _("Don't know how to set addresses for family %d.\n"), ap->af);
953 exit(1);
955 if (r < 0) {
956 perror("SIOCSIFADDR");
957 goterr = 1;
961 * Don't do the set_flag() if the address is an alias with a - at the
962 * end, since it's deleted already! - Roman
964 * Should really use regex.h here, not sure though how well it'll go
965 * with the cross-platform support etc.
968 char *ptr;
969 short int found_colon = 0;
970 for (ptr = ifr.ifr_name; *ptr; ptr++ )
971 if (*ptr == ':') found_colon++;
973 if (!(found_colon && *(ptr - 1) == '-'))
974 goterr |= set_flag(ifr.ifr_name, (IFF_UP | IFF_RUNNING));
977 spp++;
980 return (goterr);
982 struct ifcmd {
983 int flag;
984 unsigned long addr;
985 char *base;
986 int baselen;
988 static unsigned char searcher[256];
990 static int set_ip_using(const char *name, int c, unsigned long ip)
992 struct ifreq ifr;
993 struct sockaddr_in sin;
995 strcpy(ifr.ifr_name, name);
996 memset(&sin, 0, sizeof(struct sockaddr));
997 sin.sin_family = AF_INET;
998 sin.sin_addr.s_addr = ip;
999 memcpy(&ifr.ifr_addr, &sin, sizeof(struct sockaddr));
1000 if (ioctl(skfd, c, &ifr) < 0)
1001 return -1;
1002 return 0;
1004 static int do_ifcmd(struct interface *x, struct ifcmd *ptr)
1006 char *z, *e;
1007 struct sockaddr_in *sin;
1008 int i;
1010 if (do_if_fetch(x) < 0)
1011 return 0;
1012 if (strncmp(x->name, ptr->base, ptr->baselen) != 0)
1013 return 0; /* skip */
1014 z = strchr(x->name, ':');
1015 if (!z || !*z)
1016 return 0;
1017 z++;
1018 for (e = z; *e; e++)
1019 if (*e == '-') /* deleted */
1020 return 0;
1021 i = atoi(z);
1022 searcher[i] = 1;
1024 /* copy */
1025 sin = (struct sockaddr_in *)&x->dstaddr;
1026 if (sin->sin_addr.s_addr != ptr->addr) {
1027 return 0;
1030 if (ptr->flag) {
1031 /* turn UP */
1032 if (set_flag(x->name, IFF_UP | IFF_RUNNING) == -1)
1033 return -1;
1034 } else {
1035 /* turn DOWN */
1036 if (clr_flag(x->name, IFF_UP) == -1)
1037 return -1;
1040 return 1; /* all done! */
1044 static int get_nmbc_parent(char *parent,
1045 unsigned long *nm, unsigned long *bc)
1047 struct interface *i;
1048 struct sockaddr_in *sin;
1050 i = lookup_interface(parent);
1051 if (!i)
1052 return -1;
1053 if (do_if_fetch(i) < 0)
1054 return 0;
1055 sin = (struct sockaddr_in *)&i->netmask;
1056 memcpy(nm, &sin->sin_addr.s_addr, sizeof(unsigned long));
1057 sin = (struct sockaddr_in *)&i->broadaddr;
1058 memcpy(bc, &sin->sin_addr.s_addr, sizeof(unsigned long));
1059 return 0;
1062 static int set_ifstate(char *parent, unsigned long ip,
1063 unsigned long nm, unsigned long bc,
1064 int flag)
1066 char buf[IFNAMSIZ];
1067 struct ifcmd pt;
1068 int i;
1070 pt.base = parent;
1071 pt.baselen = strlen(parent);
1072 pt.addr = ip;
1073 pt.flag = flag;
1074 memset(searcher, 0, sizeof(searcher));
1075 i = for_all_interfaces((int (*)(struct interface *,void *))do_ifcmd,
1076 &pt);
1077 if (i == -1)
1078 return -1;
1079 if (i == 1)
1080 return 0;
1082 /* add a new interface */
1083 for (i = 0; i < 256; i++)
1084 if (searcher[i] == 0)
1085 break;
1086 if (i == 256)
1087 return -1; /* FAILURE!!! out of ip addresses */
1089 sprintf(buf, "%s:%d", parent, i);
1090 if (set_ip_using(buf, SIOCSIFADDR, ip) == -1)
1091 return -1;
1092 if (set_ip_using(buf, SIOCSIFNETMASK, nm) == -1)
1093 return -1;
1094 if (set_ip_using(buf, SIOCSIFBRDADDR, bc) == -1)
1095 return -1;
1096 if (set_flag(buf, IFF_BROADCAST) == -1)
1097 return -1;
1098 return 0;