i am sorry for that double change, didnt noticed, my cvs change mail seems
[oss-qm-packages.git] / ifconfig.c
blob74b9e9cc40f2155bb00737fbfbf62a0fe18781b0
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.44 2001/02/12 21:06:47 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)
27 #define DFLT_AF "inet"
29 #include "config.h"
31 #include <features.h>
32 #include <sys/types.h>
33 #include <sys/socket.h>
34 #include <sys/ioctl.h>
35 #include <netinet/in.h>
36 #include <net/if.h>
37 #include <net/if_arp.h>
38 #include <stdio.h>
39 #include <errno.h>
40 #include <fcntl.h>
41 #include <ctype.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <unistd.h>
45 #include <netdb.h>
47 /* Ugh. But libc5 doesn't provide POSIX types. */
48 #include <asm/types.h>
51 #ifdef HAVE_HWSLIP
52 #include <linux/if_slip.h>
53 #endif
55 #if HAVE_AFINET6
57 #ifndef _LINUX_IN6_H
59 * This is in linux/include/net/ipv6.h.
62 struct in6_ifreq {
63 struct in6_addr ifr6_addr;
64 __u32 ifr6_prefixlen;
65 unsigned int ifr6_ifindex;
68 #endif
70 #endif /* HAVE_AFINET6 */
72 #if HAVE_AFIPX
73 #if (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 1)
74 #include <netipx/ipx.h>
75 #else
76 #include "ipx.h"
77 #endif
78 #endif
79 #include "net-support.h"
80 #include "pathnames.h"
81 #include "version.h"
82 #include "../intl.h"
83 #include "interface.h"
84 #include "sockets.h"
85 #include "util.h"
87 char *Release = RELEASE, *Version = "ifconfig 1.40 (2000-05-21)";
89 int opt_a = 0; /* show all interfaces */
90 int opt_i = 0; /* show the statistics */
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,
97 unsigned long *nm, unsigned long *bc);
98 static int set_ifstate(char *parent,
99 unsigned long ip,
100 unsigned long nm,
101 unsigned long bc,
102 int flag);
105 static int if_print(char *ifname)
107 int res;
109 if (ife_short)
110 printf(_("Iface MTU Met RX-OK RX-ERR RX-DRP RX-OVR TX-OK TX-ERR TX-DRP TX-OVR Flg\n"));
112 if (!ifname) {
113 res = for_all_interfaces(do_if_print, &opt_a);
114 } else {
115 struct interface *ife;
117 ife = lookup_interface(ifname);
118 res = do_if_fetch(ife);
119 if (res >= 0)
120 ife_print(ife);
122 return res;
125 /* Set a certain interface flag. */
126 static int set_flag(char *ifname, short flag)
128 struct ifreq ifr;
130 strcpy(ifr.ifr_name, ifname);
131 if (ioctl(skfd, SIOCGIFFLAGS, &ifr) < 0) {
132 fprintf(stderr, _("%s: unknown interface: %s\n"),
133 ifname, strerror(errno));
134 return (-1);
136 strcpy(ifr.ifr_name, ifname);
137 ifr.ifr_flags |= flag;
138 if (ioctl(skfd, SIOCSIFFLAGS, &ifr) < 0) {
139 perror("SIOCSIFFLAGS");
140 return -1;
142 return (0);
145 /* Clear a certain interface flag. */
146 static int clr_flag(char *ifname, short flag)
148 struct ifreq ifr;
149 int fd;
151 if (strchr(ifname, ':')) {
152 /* This is a v4 alias interface. Downing it via a socket for
153 another AF may have bad consequences. */
154 fd = get_socket_for_af(AF_INET);
155 if (fd < 0) {
156 fprintf(stderr, _("No support for INET on this system.\n"));
157 return -1;
159 } else
160 fd = skfd;
162 strcpy(ifr.ifr_name, ifname);
163 if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) {
164 fprintf(stderr, _("%s: unknown interface: %s\n"),
165 ifname, strerror(errno));
166 return -1;
168 strcpy(ifr.ifr_name, ifname);
169 ifr.ifr_flags &= ~flag;
170 if (ioctl(fd, SIOCSIFFLAGS, &ifr) < 0) {
171 perror("SIOCSIFFLAGS");
172 return -1;
174 return (0);
177 static void usage(void)
179 fprintf(stderr, _("Usage:\n ifconfig [-a] [-i] [-v] [-s] <interface> [[<AF>] <address>]\n"));
180 #if HAVE_AFINET
181 fprintf(stderr, _(" [add <address>[/<prefixlen>]]\n"));
182 fprintf(stderr, _(" [del <address>[/<prefixlen>]]\n"));
183 fprintf(stderr, _(" [[-]broadcast [<address>]] [[-]pointopoint [<address>]]\n"));
184 fprintf(stderr, _(" [netmask <address>] [dstaddr <address>] [tunnel <address>]\n"));
185 #endif
186 #ifdef SIOCSKEEPALIVE
187 fprintf(stderr, _(" [outfill <NN>] [keepalive <NN>]\n"));
188 #endif
189 fprintf(stderr, _(" [hw <HW> <address>] [metric <NN>] [mtu <NN>]\n"));
190 fprintf(stderr, _(" [[-]trailers] [[-]arp] [[-]allmulti]\n"));
191 fprintf(stderr, _(" [multicast] [[-]promisc]\n"));
192 fprintf(stderr, _(" [mem_start <NN>] [io_addr <NN>] [irq <NN>] [media <type>]\n"));
193 #ifdef HAVE_TXQUEUELEN
194 fprintf(stderr, _(" [txqueuelen <NN>]\n"));
195 #endif
196 #ifdef HAVE_DYNAMIC
197 fprintf(stderr, _(" [[-]dynamic]\n"));
198 #endif
199 fprintf(stderr, _(" [up|down] ...\n\n"));
201 fprintf(stderr, _(" <HW>=Hardware Type.\n"));
202 fprintf(stderr, _(" List of possible hardware types:\n"));
203 print_hwlist(0); /* 1 = ARPable */
204 fprintf(stderr, _(" <AF>=Address family. Default: %s\n"), DFLT_AF);
205 fprintf(stderr, _(" List of possible address families:\n"));
206 print_aflist(0); /* 1 = routeable */
207 exit(E_USAGE);
210 static void version(void)
212 fprintf(stderr, "%s\n%s\n", Release, Version);
213 exit(1);
216 static int set_netmask(int skfd, struct ifreq *ifr, struct sockaddr *sa)
218 int err = 0;
220 memcpy((char *) &ifr->ifr_netmask, (char *) sa,
221 sizeof(struct sockaddr));
222 if (ioctl(skfd, SIOCSIFNETMASK, ifr) < 0) {
223 fprintf(stderr, "SIOCSIFNETMASK: %s\n",
224 strerror(errno));
225 err = 1;
227 return 0;
230 int main(int argc, char **argv)
232 struct sockaddr sa;
233 struct sockaddr_in sin;
234 char host[128];
235 struct aftype *ap;
236 struct hwtype *hw;
237 struct ifreq ifr;
238 int goterr = 0, didnetmask = 0;
239 char **spp;
240 int fd;
241 #if HAVE_AFINET6
242 extern struct aftype inet6_aftype;
243 struct sockaddr_in6 sa6;
244 struct in6_ifreq ifr6;
245 unsigned long prefix_len;
246 char *cp;
247 #endif
248 #if HAVE_AFINET
249 extern struct aftype inet_aftype;
250 #endif
252 #if I18N
253 bindtextdomain("net-tools", "/usr/share/locale");
254 textdomain("net-tools");
255 #endif
258 /* Find any options. */
259 argc--;
260 argv++;
261 while (argc && *argv[0] == '-') {
262 if (!strcmp(*argv, "-a"))
263 opt_a = 1;
265 else if (!strcmp(*argv, "-s"))
266 ife_short = 1;
268 else if (!strcmp(*argv, "-v"))
269 opt_v = 1;
271 else if (!strcmp(*argv, "-V") || !strcmp(*argv, "-version") ||
272 !strcmp(*argv, "--version"))
273 version();
275 else if (!strcmp(*argv, "-?") || !strcmp(*argv, "-h") ||
276 !strcmp(*argv, "-help") || !strcmp(*argv, "--help"))
277 usage();
279 else {
280 fprintf(stderr, "ifconfig: unknown option %s\n", argv[0]);
281 fprintf(stderr, "(Use --help for usage information.\n)");
282 exit(1);
285 argv++;
286 argc--;
289 /* Create a channel to the NET kernel. */
290 if ((skfd = sockets_open(0)) < 0) {
291 perror("socket");
292 exit(1);
295 /* Do we have to show the current setup? */
296 if (argc == 0) {
297 int err = if_print((char *) NULL);
298 (void) close(skfd);
299 exit(err < 0);
301 /* No. Fetch the interface name. */
302 spp = argv;
303 safe_strncpy(ifr.ifr_name, *spp++, IFNAMSIZ);
304 if (*spp == (char *) NULL) {
305 int err = if_print(ifr.ifr_name);
306 (void) close(skfd);
307 exit(err < 0);
309 /* The next argument is either an address family name, or an option. */
310 if ((ap = get_aftype(*spp)) != NULL)
311 spp++; /* it was a AF name */
312 else
313 ap = get_aftype(DFLT_AF);
315 if (ap) {
316 addr_family = ap->af;
317 if ((fd=sockets_open(addr_family)) < 0) {
318 perror("family socket");
319 exit(1);
320 } else {
321 if (skfd > 0 && skfd != fd) close(skfd);
322 skfd = fd;
326 /* Process the remaining arguments. */
327 while (*spp != (char *) NULL) {
328 if (!strcmp(*spp, "arp")) {
329 goterr |= clr_flag(ifr.ifr_name, IFF_NOARP);
330 spp++;
331 continue;
333 if (!strcmp(*spp, "-arp")) {
334 goterr |= set_flag(ifr.ifr_name, IFF_NOARP);
335 spp++;
336 continue;
338 #ifdef IFF_PORTSEL
339 if (!strcmp(*spp, "media") || !strcmp(*spp, "port")) {
340 if (*++spp == NULL)
341 usage();
342 if (!strcasecmp(*spp, "auto")) {
343 goterr |= set_flag(ifr.ifr_name, IFF_AUTOMEDIA);
344 } else {
345 int i, j, newport;
346 char *endp;
347 newport = strtol(*spp, &endp, 10);
348 if (*endp != 0) {
349 newport = -1;
350 for (i = 0; if_port_text[i][0] && newport == -1; i++) {
351 for (j = 0; if_port_text[i][j]; j++) {
352 if (!strcasecmp(*spp, if_port_text[i][j])) {
353 newport = i;
354 break;
359 spp++;
360 if (newport == -1) {
361 fprintf(stderr, _("Unknown media type.\n"));
362 goterr = 1;
363 } else {
364 if (ioctl(skfd, SIOCGIFMAP, &ifr) < 0) {
365 perror("port: SIOCGIFMAP");
366 goterr = 1;
367 continue;
369 ifr.ifr_map.port = newport;
370 if (ioctl(skfd, SIOCSIFMAP, &ifr) < 0) {
371 perror("port: SIOCSIFMAP");
372 goterr = 1;
376 continue;
378 #endif
380 if (!strcmp(*spp, "trailers")) {
381 goterr |= clr_flag(ifr.ifr_name, IFF_NOTRAILERS);
382 spp++;
383 continue;
385 if (!strcmp(*spp, "-trailers")) {
386 goterr |= set_flag(ifr.ifr_name, IFF_NOTRAILERS);
387 spp++;
388 continue;
390 if (!strcmp(*spp, "promisc")) {
391 goterr |= set_flag(ifr.ifr_name, IFF_PROMISC);
392 spp++;
393 continue;
395 if (!strcmp(*spp, "-promisc")) {
396 goterr |= clr_flag(ifr.ifr_name, IFF_PROMISC);
397 spp++;
398 continue;
400 if (!strcmp(*spp, "multicast")) {
401 goterr |= set_flag(ifr.ifr_name, IFF_MULTICAST);
402 spp++;
403 continue;
405 if (!strcmp(*spp, "-multicast")) {
406 goterr |= clr_flag(ifr.ifr_name, IFF_MULTICAST);
407 spp++;
408 continue;
410 if (!strcmp(*spp, "allmulti")) {
411 goterr |= set_flag(ifr.ifr_name, IFF_ALLMULTI);
412 spp++;
413 continue;
415 if (!strcmp(*spp, "-allmulti")) {
416 goterr |= clr_flag(ifr.ifr_name, IFF_ALLMULTI);
417 spp++;
418 continue;
420 if (!strcmp(*spp, "up")) {
421 goterr |= set_flag(ifr.ifr_name, (IFF_UP | IFF_RUNNING));
422 spp++;
423 continue;
425 if (!strcmp(*spp, "down")) {
426 goterr |= clr_flag(ifr.ifr_name, IFF_UP);
427 spp++;
428 continue;
430 #ifdef HAVE_DYNAMIC
431 if (!strcmp(*spp, "dynamic")) {
432 goterr |= set_flag(ifr.ifr_name, IFF_DYNAMIC);
433 spp++;
434 continue;
436 if (!strcmp(*spp, "-dynamic")) {
437 goterr |= clr_flag(ifr.ifr_name, IFF_DYNAMIC);
438 spp++;
439 continue;
441 #endif
443 if (!strcmp(*spp, "metric")) {
444 if (*++spp == NULL)
445 usage();
446 ifr.ifr_metric = atoi(*spp);
447 if (ioctl(skfd, SIOCSIFMETRIC, &ifr) < 0) {
448 fprintf(stderr, "SIOCSIFMETRIC: %s\n", strerror(errno));
449 goterr = 1;
451 spp++;
452 continue;
454 if (!strcmp(*spp, "mtu")) {
455 if (*++spp == NULL)
456 usage();
457 ifr.ifr_mtu = atoi(*spp);
458 if (ioctl(skfd, SIOCSIFMTU, &ifr) < 0) {
459 fprintf(stderr, "SIOCSIFMTU: %s\n", strerror(errno));
460 goterr = 1;
462 spp++;
463 continue;
465 #ifdef SIOCSKEEPALIVE
466 if (!strcmp(*spp, "keepalive")) {
467 if (*++spp == NULL)
468 usage();
469 ifr.ifr_data = (caddr_t) atoi(*spp);
470 if (ioctl(skfd, SIOCSKEEPALIVE, &ifr) < 0) {
471 fprintf(stderr, "SIOCSKEEPALIVE: %s\n", strerror(errno));
472 goterr = 1;
474 spp++;
475 continue;
477 #endif
479 #ifdef SIOCSOUTFILL
480 if (!strcmp(*spp, "outfill")) {
481 if (*++spp == NULL)
482 usage();
483 ifr.ifr_data = (caddr_t) atoi(*spp);
484 if (ioctl(skfd, SIOCSOUTFILL, &ifr) < 0) {
485 fprintf(stderr, "SIOCSOUTFILL: %s\n", strerror(errno));
486 goterr = 1;
488 spp++;
489 continue;
491 #endif
493 if (!strcmp(*spp, "-broadcast")) {
494 goterr |= clr_flag(ifr.ifr_name, IFF_BROADCAST);
495 spp++;
496 continue;
498 if (!strcmp(*spp, "broadcast")) {
499 if (*++spp != NULL) {
500 safe_strncpy(host, *spp, (sizeof host));
501 if (ap->input(0, host, &sa) < 0) {
502 ap->herror(host);
503 goterr = 1;
504 spp++;
505 continue;
507 memcpy((char *) &ifr.ifr_broadaddr, (char *) &sa,
508 sizeof(struct sockaddr));
509 if (ioctl(ap->fd, SIOCSIFBRDADDR, &ifr) < 0) {
510 fprintf(stderr, "SIOCSIFBRDADDR: %s\n",
511 strerror(errno));
512 goterr = 1;
514 spp++;
516 goterr |= set_flag(ifr.ifr_name, IFF_BROADCAST);
517 continue;
519 if (!strcmp(*spp, "dstaddr")) {
520 if (*++spp == NULL)
521 usage();
522 safe_strncpy(host, *spp, (sizeof host));
523 if (ap->input(0, host, &sa) < 0) {
524 ap->herror(host);
525 goterr = 1;
526 spp++;
527 continue;
529 memcpy((char *) &ifr.ifr_dstaddr, (char *) &sa,
530 sizeof(struct sockaddr));
531 if (ioctl(ap->fd, SIOCSIFDSTADDR, &ifr) < 0) {
532 fprintf(stderr, "SIOCSIFDSTADDR: %s\n",
533 strerror(errno));
534 goterr = 1;
536 spp++;
537 continue;
539 if (!strcmp(*spp, "netmask")) {
540 if (*++spp == NULL || didnetmask)
541 usage();
542 safe_strncpy(host, *spp, (sizeof host));
543 if (ap->input(0, host, &sa) < 0) {
544 ap->herror(host);
545 goterr = 1;
546 spp++;
547 continue;
549 didnetmask++;
550 goterr = set_netmask(ap->fd, &ifr, &sa);
551 spp++;
552 continue;
554 #ifdef HAVE_TXQUEUELEN
555 if (!strcmp(*spp, "txqueuelen")) {
556 if (*++spp == NULL)
557 usage();
558 ifr.ifr_qlen = strtoul(*spp, NULL, 0);
559 if (ioctl(skfd, SIOCSIFTXQLEN, &ifr) < 0) {
560 fprintf(stderr, "SIOCSIFTXQLEN: %s\n", strerror(errno));
561 goterr = 1;
563 spp++;
564 continue;
566 #endif
568 if (!strcmp(*spp, "mem_start")) {
569 if (*++spp == NULL)
570 usage();
571 if (ioctl(skfd, SIOCGIFMAP, &ifr) < 0) {
572 fprintf(stderr, "mem_start: SIOCGIFMAP: %s\n", strerror(errno));
573 spp++;
574 goterr = 1;
575 continue;
577 ifr.ifr_map.mem_start = strtoul(*spp, NULL, 0);
578 if (ioctl(skfd, SIOCSIFMAP, &ifr) < 0) {
579 fprintf(stderr, "mem_start: SIOCSIFMAP: %s\n", strerror(errno));
580 goterr = 1;
582 spp++;
583 continue;
585 if (!strcmp(*spp, "io_addr")) {
586 if (*++spp == NULL)
587 usage();
588 if (ioctl(skfd, SIOCGIFMAP, &ifr) < 0) {
589 fprintf(stderr, "io_addr: SIOCGIFMAP: %s\n", strerror(errno));
590 spp++;
591 goterr = 1;
592 continue;
594 ifr.ifr_map.base_addr = strtol(*spp, NULL, 0);
595 if (ioctl(skfd, SIOCSIFMAP, &ifr) < 0) {
596 fprintf(stderr, "io_addr: SIOCSIFMAP: %s\n", strerror(errno));
597 goterr = 1;
599 spp++;
600 continue;
602 if (!strcmp(*spp, "irq")) {
603 if (*++spp == NULL)
604 usage();
605 if (ioctl(skfd, SIOCGIFMAP, &ifr) < 0) {
606 fprintf(stderr, "irq: SIOCGIFMAP: %s\n", strerror(errno));
607 goterr = 1;
608 spp++;
609 continue;
611 ifr.ifr_map.irq = atoi(*spp);
612 if (ioctl(skfd, SIOCSIFMAP, &ifr) < 0) {
613 fprintf(stderr, "irq: SIOCSIFMAP: %s\n", strerror(errno));
614 goterr = 1;
616 spp++;
617 continue;
619 if (!strcmp(*spp, "-pointopoint")) {
620 goterr |= clr_flag(ifr.ifr_name, IFF_POINTOPOINT);
621 spp++;
622 continue;
624 if (!strcmp(*spp, "pointopoint")) {
625 if (*(spp + 1) != NULL) {
626 spp++;
627 safe_strncpy(host, *spp, (sizeof host));
628 if (ap->input(0, host, &sa)) {
629 ap->herror(host);
630 goterr = 1;
631 spp++;
632 continue;
634 memcpy((char *) &ifr.ifr_dstaddr, (char *) &sa,
635 sizeof(struct sockaddr));
636 if (ioctl(ap->fd, SIOCSIFDSTADDR, &ifr) < 0) {
637 fprintf(stderr, "SIOCSIFDSTADDR: %s\n",
638 strerror(errno));
639 goterr = 1;
642 goterr |= set_flag(ifr.ifr_name, IFF_POINTOPOINT);
643 spp++;
644 continue;
647 if (!strcmp(*spp, "hw")) {
648 if (*++spp == NULL)
649 usage();
650 if ((hw = get_hwtype(*spp)) == NULL)
651 usage();
652 if (hw->input == NULL) {
653 fprintf(stderr, _("hw address type `%s' has no handler to set address. failed.\n"), *spp);
654 spp+=2;
655 goterr = 1;
656 continue;
658 if (*++spp == NULL)
659 usage();
660 safe_strncpy(host, *spp, (sizeof host));
661 if (hw->input(host, &sa) < 0) {
662 fprintf(stderr, _("%s: invalid %s address.\n"), host, hw->name);
663 goterr = 1;
664 spp++;
665 continue;
667 memcpy((char *) &ifr.ifr_hwaddr, (char *) &sa,
668 sizeof(struct sockaddr));
669 if (ioctl(skfd, SIOCSIFHWADDR, &ifr) < 0) {
670 fprintf(stderr, "SIOCSIFHWADDR: %s\n",
671 strerror(errno));
672 goterr = 1;
674 spp++;
675 continue;
677 #if HAVE_AFINET || HAVE_AFINET6
678 if (!strcmp(*spp, "add")) {
679 if (*++spp == NULL)
680 usage();
681 #if HAVE_AFINET6
682 if (strchr(*spp, ':')) {
683 /* INET6 */
684 if ((cp = strchr(*spp, '/'))) {
685 prefix_len = atol(cp + 1);
686 if ((prefix_len < 0) || (prefix_len > 128))
687 usage();
688 *cp = 0;
689 } else {
690 prefix_len = 0;
692 safe_strncpy(host, *spp, (sizeof host));
693 if (inet6_aftype.input(1, host,
694 (struct sockaddr *) &sa6) < 0) {
695 inet6_aftype.herror(host);
696 goterr = 1;
697 spp++;
698 continue;
700 memcpy((char *) &ifr6.ifr6_addr, (char *) &sa6.sin6_addr,
701 sizeof(struct in6_addr));
703 fd = get_socket_for_af(AF_INET6);
704 if (fd < 0) {
705 fprintf(stderr,
706 _("No support for INET6 on this system.\n"));
707 goterr = 1;
708 spp++;
709 continue;
711 if (ioctl(fd, SIOGIFINDEX, &ifr) < 0) {
712 perror("SIOGIFINDEX");
713 goterr = 1;
714 spp++;
715 continue;
717 ifr6.ifr6_ifindex = ifr.ifr_ifindex;
718 ifr6.ifr6_prefixlen = prefix_len;
719 if (ioctl(fd, SIOCSIFADDR, &ifr6) < 0) {
720 perror("SIOCSIFADDR");
721 goterr = 1;
723 spp++;
724 continue;
726 #endif
727 #ifdef HAVE_AFINET
728 { /* ipv4 address a.b.c.d */
729 unsigned long ip, nm, bc;
730 safe_strncpy(host, *spp, (sizeof host));
731 if (inet_aftype.input(0, host, (struct sockaddr *)&sin) < 0) {
732 ap->herror(host);
733 goterr = 1;
734 spp++;
735 continue;
737 fd = get_socket_for_af(AF_INET);
738 if (fd < 0) {
739 fprintf(stderr,
740 _("No support for INET on this system.\n"));
741 goterr = 1;
742 spp++;
743 continue;
746 memcpy(&ip, &sin.sin_addr.s_addr, sizeof(unsigned long));
748 if (get_nmbc_parent(ifr.ifr_name, &nm, &bc) < 0) {
749 fprintf(stderr, _("Interface %s not initialized\n"),
750 ifr.ifr_name);
751 goterr = 1;
752 spp++;
753 continue;
755 set_ifstate(ifr.ifr_name, ip, nm, bc, 1);
758 spp++;
759 continue;
760 #else
761 fprintf(stderr, _("Bad address.\n"));
762 #endif
764 #endif
766 #if HAVE_AFINET || HAVE_AFINET6
767 if (!strcmp(*spp, "del")) {
768 if (*++spp == NULL)
769 usage();
771 #ifdef SIOCDIFADDR
772 #if HAVE_AFINET6
773 if (strchr(*spp, ':')) { /* INET6 */
774 if ((cp = strchr(*spp, '/'))) {
775 prefix_len = atol(cp + 1);
776 if ((prefix_len < 0) || (prefix_len > 128))
777 usage();
778 *cp = 0;
779 } else {
780 prefix_len = 0;
782 safe_strncpy(host, *spp, (sizeof host));
783 if (inet6_aftype.input(1, host,
784 (struct sockaddr *) &sa6) < 0) {
785 inet6_aftype.herror(host);
786 goterr = 1;
787 spp++;
788 continue;
790 memcpy((char *) &ifr6.ifr6_addr, (char *) &sa6.sin6_addr,
791 sizeof(struct in6_addr));
793 fd = get_socket_for_af(AF_INET6);
794 if (fd < 0) {
795 fprintf(stderr,
796 _("No support for INET6 on this system.\n"));
797 goterr = 1;
798 spp++;
799 continue;
801 if (ioctl(fd, SIOGIFINDEX, &ifr) < 0) {
802 perror("SIOGIFINDEX");
803 goterr = 1;
804 spp++;
805 continue;
807 ifr6.ifr6_ifindex = ifr.ifr_ifindex;
808 ifr6.ifr6_prefixlen = prefix_len;
809 if (ioctl(fd, SIOCDIFADDR, &ifr6) < 0) {
810 fprintf(stderr, "SIOCDIFADDR: %s\n",
811 strerror(errno));
812 goterr = 1;
814 spp++;
815 continue;
817 #endif
818 #ifdef HAVE_AFINET
820 /* ipv4 address a.b.c.d */
821 unsigned long ip, nm, bc;
822 safe_strncpy(host, *spp, (sizeof host));
823 if (inet_aftype.input(0, host, (struct sockaddr *)&sin) < 0) {
824 ap->herror(host);
825 goterr = 1;
826 spp++;
827 continue;
829 fd = get_socket_for_af(AF_INET);
830 if (fd < 0) {
831 fprintf(stderr, _("No support for INET on this system.\n"));
832 goterr = 1;
833 spp++;
834 continue;
837 memcpy(&ip, &sin.sin_addr.s_addr, sizeof(unsigned long));
839 if (get_nmbc_parent(ifr.ifr_name, &nm, &bc) < 0) {
840 fprintf(stderr, _("Interface %s not initialized\n"),
841 ifr.ifr_name);
842 goterr = 1;
843 spp++;
844 continue;
846 set_ifstate(ifr.ifr_name, ip, nm, bc, 0);
848 spp++;
849 continue;
850 #else
851 fprintf(stderr, _("Bad address.\n"));
852 #endif
853 #else
854 fprintf(stderr, _("Address deletion not supported on this system.\n"));
855 #endif
857 #endif
858 #if HAVE_AFINET6
859 if (!strcmp(*spp, "tunnel")) {
860 if (*++spp == NULL)
861 usage();
862 if ((cp = strchr(*spp, '/'))) {
863 prefix_len = atol(cp + 1);
864 if ((prefix_len < 0) || (prefix_len > 128))
865 usage();
866 *cp = 0;
867 } else {
868 prefix_len = 0;
870 safe_strncpy(host, *spp, (sizeof host));
871 if (inet6_aftype.input(1, host, (struct sockaddr *) &sa6) < 0) {
872 inet6_aftype.herror(host);
873 goterr = 1;
874 spp++;
875 continue;
877 memcpy((char *) &ifr6.ifr6_addr, (char *) &sa6.sin6_addr,
878 sizeof(struct in6_addr));
880 fd = get_socket_for_af(AF_INET6);
881 if (fd < 0) {
882 fprintf(stderr, _("No support for INET6 on this system.\n"));
883 goterr = 1;
884 spp++;
885 continue;
887 if (ioctl(fd, SIOGIFINDEX, &ifr) < 0) {
888 perror("SIOGIFINDEX");
889 goterr = 1;
890 spp++;
891 continue;
893 ifr6.ifr6_ifindex = ifr.ifr_ifindex;
894 ifr6.ifr6_prefixlen = prefix_len;
896 if (ioctl(fd, SIOCSIFDSTADDR, &ifr6) < 0) {
897 fprintf(stderr, "SIOCSIFDSTADDR: %s\n",
898 strerror(errno));
899 goterr = 1;
901 spp++;
902 continue;
904 #endif
906 /* If the next argument is a valid hostname, assume OK. */
907 safe_strncpy(host, *spp, (sizeof host));
909 /* FIXME: sa is too small for INET6 addresses, inet6 should use that too,
910 broadcast is unexpected */
911 if (ap->getmask) {
912 switch (ap->getmask(host, &sa, NULL)) {
913 case -1:
914 usage();
915 break;
916 case 1:
917 if (didnetmask)
918 usage();
920 goterr = set_netmask(skfd, &ifr, &sa);
921 didnetmask++;
922 break;
925 if (ap->input(0, host, &sa) < 0) {
926 ap->herror(host);
927 usage();
929 memcpy((char *) &ifr.ifr_addr, (char *) &sa, sizeof(struct sockaddr));
931 int r = 0; /* to shut gcc up */
932 switch (ap->af) {
933 #if HAVE_AFINET
934 case AF_INET:
935 fd = get_socket_for_af(AF_INET);
936 if (fd < 0) {
937 fprintf(stderr, _("No support for INET on this system.\n"));
938 exit(1);
940 r = ioctl(fd, SIOCSIFADDR, &ifr);
941 break;
942 #endif
943 #if HAVE_AFECONET
944 case AF_ECONET:
945 fd = get_socket_for_af(AF_ECONET);
946 if (fd < 0) {
947 fprintf(stderr, _("No support for ECONET on this system.\n"));
948 exit(1);
950 r = ioctl(fd, SIOCSIFADDR, &ifr);
951 break;
952 #endif
953 default:
954 fprintf(stderr,
955 _("Don't know how to set addresses for family %d.\n"), ap->af);
956 exit(1);
958 if (r < 0) {
959 perror("SIOCSIFADDR");
960 goterr = 1;
964 * Don't do the set_flag() if the address is an alias with a - at the
965 * end, since it's deleted already! - Roman
967 * Should really use regex.h here, not sure though how well it'll go
968 * with the cross-platform support etc.
971 char *ptr;
972 short int found_colon = 0;
973 for (ptr = ifr.ifr_name; *ptr; ptr++ )
974 if (*ptr == ':') found_colon++;
976 if (!(found_colon && *(ptr - 1) == '-'))
977 goterr |= set_flag(ifr.ifr_name, (IFF_UP | IFF_RUNNING));
980 spp++;
983 return (goterr);
985 struct ifcmd {
986 int flag;
987 unsigned long addr;
988 char *base;
989 int baselen;
991 static unsigned char searcher[256];
993 static int set_ip_using(const char *name, int c, unsigned long ip)
995 struct ifreq ifr;
996 struct sockaddr_in sin;
998 strcpy(ifr.ifr_name, name);
999 memset(&sin, 0, sizeof(struct sockaddr));
1000 sin.sin_family = AF_INET;
1001 sin.sin_addr.s_addr = ip;
1002 memcpy(&ifr.ifr_addr, &sin, sizeof(struct sockaddr));
1003 if (ioctl(skfd, c, &ifr) < 0)
1004 return -1;
1005 return 0;
1007 static int do_ifcmd(struct interface *x, struct ifcmd *ptr)
1009 char *z, *e;
1010 struct sockaddr_in *sin;
1011 int i;
1013 if (do_if_fetch(x) < 0)
1014 return 0;
1015 if (strncmp(x->name, ptr->base, ptr->baselen) != 0)
1016 return 0; /* skip */
1017 z = strchr(x->name, ':');
1018 if (!z || !*z)
1019 return 0;
1020 z++;
1021 for (e = z; *e; e++)
1022 if (*e == '-') /* deleted */
1023 return 0;
1024 i = atoi(z);
1025 searcher[i] = 1;
1027 /* copy */
1028 sin = (struct sockaddr_in *)&x->dstaddr;
1029 if (sin->sin_addr.s_addr != ptr->addr) {
1030 return 0;
1033 if (ptr->flag) {
1034 /* turn UP */
1035 if (set_flag(x->name, IFF_UP | IFF_RUNNING) == -1)
1036 return -1;
1037 } else {
1038 /* turn DOWN */
1039 if (clr_flag(x->name, IFF_UP) == -1)
1040 return -1;
1043 return 1; /* all done! */
1047 static int get_nmbc_parent(char *parent,
1048 unsigned long *nm, unsigned long *bc)
1050 struct interface *i;
1051 struct sockaddr_in *sin;
1053 i = lookup_interface(parent);
1054 if (!i)
1055 return -1;
1056 if (do_if_fetch(i) < 0)
1057 return 0;
1058 sin = (struct sockaddr_in *)&i->netmask;
1059 memcpy(nm, &sin->sin_addr.s_addr, sizeof(unsigned long));
1060 sin = (struct sockaddr_in *)&i->broadaddr;
1061 memcpy(bc, &sin->sin_addr.s_addr, sizeof(unsigned long));
1062 return 0;
1065 static int set_ifstate(char *parent, unsigned long ip,
1066 unsigned long nm, unsigned long bc,
1067 int flag)
1069 char buf[IFNAMSIZ];
1070 struct ifcmd pt;
1071 int i;
1073 pt.base = parent;
1074 pt.baselen = strlen(parent);
1075 pt.addr = ip;
1076 pt.flag = flag;
1077 memset(searcher, 0, sizeof(searcher));
1078 i = for_all_interfaces((int (*)(struct interface *,void *))do_ifcmd,
1079 &pt);
1080 if (i == -1)
1081 return -1;
1082 if (i == 1)
1083 return 0;
1085 /* add a new interface */
1086 for (i = 0; i < 256; i++)
1087 if (searcher[i] == 0)
1088 break;
1089 if (i == 256)
1090 return -1; /* FAILURE!!! out of ip addresses */
1092 sprintf(buf, "%s:%d", parent, i);
1093 if (set_ip_using(buf, SIOCSIFADDR, ip) == -1)
1094 return -1;
1095 if (set_ip_using(buf, SIOCSIFNETMASK, nm) == -1)
1096 return -1;
1097 if (set_ip_using(buf, SIOCSIFBRDADDR, bc) == -1)
1098 return -1;
1099 if (set_flag(buf, IFF_BROADCAST) == -1)
1100 return -1;
1101 return 0;