OSDN Git Service

Fix no pic
[uclinux-h8/uClinux-dist.git] / user / net-tools / ifconfig.c
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.
5  *
6  * Version:     $Id: ifconfig.c,v 1.50 2001/04/13 18:25:18 pb Exp $
7  *
8  * Author:      Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
9  *              and others.  Copyright 1993 MicroWalt Corporation
10  *
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.
16  *
17  * Patched to support 'add' and 'del' keywords for INET(4) addresses
18  * by Mrs. Brisby <mrs.brisby@nimh.org>
19  *
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
26  */
27
28 #define DFLT_AF "inet"
29
30 #include "config.h"
31
32 #include <features.h>
33 #include <sys/types.h>
34 #include <sys/socket.h>
35 #include <sys/ioctl.h>
36 #include <sys/wait.h>
37 #include <netinet/in.h>
38 #include <net/if.h>
39 #include <net/if_arp.h>
40 #include <stdio.h>
41 #include <errno.h>
42 #include <fcntl.h>
43 #include <ctype.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <unistd.h>
47 #include <netdb.h>
48
49 /* Ugh.  But libc5 doesn't provide POSIX types.  */
50 #include <asm/types.h>
51
52
53 #ifdef HAVE_HWSLIP
54 #include <linux/if_slip.h>
55 #endif
56
57 #if HAVE_AFINET6
58
59 #ifndef _LINUX_IN6_H
60 /*
61  *    This is in linux/include/net/ipv6.h.
62  */
63
64 struct in6_ifreq {
65     struct in6_addr ifr6_addr;
66     __u32 ifr6_prefixlen;
67     unsigned int ifr6_ifindex;
68 };
69
70 #endif
71
72 #endif                          /* HAVE_AFINET6 */
73
74 #if HAVE_AFIPX
75 #if (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 1)
76 #include <netipx/ipx.h>
77 #else
78 #include "ipx.h"
79 #endif
80 #endif
81 #include "net-support.h"
82 #include "pathnames.h"
83 #include "version.h"
84 #include "../intl.h"
85 #include "interface.h"
86 #include "sockets.h"
87 #include "util.h"
88
89 char *Release = RELEASE, *Version = "ifconfig 1.42 (2001-04-13)";
90
91 int opt_a = 0;                  /* show all interfaces          */
92 int opt_i = 0;                  /* show the statistics          */
93 int opt_v = 0;                  /* debugging output flag        */
94
95 int addr_family = 0;            /* currently selected AF        */
96
97 /* for ipv4 add/del modes */
98 static int get_nmbc_parent(char *parent, unsigned long *nm, 
99                            unsigned long *bc);
100 static int set_ifstate(char *parent, unsigned long ip,
101                        unsigned long nm, unsigned long bc,
102                        int flag);
103
104 static int if_print(char *ifname)
105 {
106     int res;
107
108     if (ife_short)
109         printf(_("Iface   MTU Met    RX-OK RX-ERR RX-DRP RX-OVR    TX-OK TX-ERR TX-DRP TX-OVR Flg\n"));
110
111     if (!ifname) {
112         res = for_all_interfaces(do_if_print, &opt_a);
113     } else {
114         struct interface *ife;
115
116         ife = lookup_interface(ifname);
117         res = do_if_fetch(ife); 
118         if (res >= 0) 
119             ife_print(ife);
120     }
121     return res; 
122 }
123
124 /* Set a certain interface flag. */
125 static int set_flag(char *ifname, short flag)
126 {
127     struct ifreq ifr;
128
129     safe_strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
130     if (ioctl(skfd, SIOCGIFFLAGS, &ifr) < 0) {
131         fprintf(stderr, _("%s: unknown interface: %s\n"), 
132                 ifname, strerror(errno));
133         return (-1);
134     }
135     safe_strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
136     ifr.ifr_flags |= flag;
137     if (ioctl(skfd, SIOCSIFFLAGS, &ifr) < 0) {
138         perror("SIOCSIFFLAGS");
139         return -1;
140     }
141     return (0);
142 }
143
144 /* Clear a certain interface flag. */
145 static int clr_flag(char *ifname, short flag)
146 {
147     struct ifreq ifr;
148     int fd;
149
150     if (strchr(ifname, ':')) {
151         /* This is a v4 alias interface.  Downing it via a socket for
152            another AF may have bad consequences. */
153         fd = get_socket_for_af(AF_INET);
154         if (fd < 0) {
155             fprintf(stderr, _("No support for INET on this system.\n"));
156             return -1;
157         }
158     } else
159         fd = skfd;
160
161     safe_strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
162     if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) {
163         fprintf(stderr, _("%s: unknown interface: %s\n"), 
164                 ifname, strerror(errno));
165         return -1;
166     }
167     safe_strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
168     ifr.ifr_flags &= ~flag;
169     if (ioctl(fd, SIOCSIFFLAGS, &ifr) < 0) {
170         perror("SIOCSIFFLAGS");
171         return -1;
172     }
173     return (0);
174 }
175
176 static void usage(void)
177 {
178     fprintf(stderr, _("Usage:\n  ifconfig [-a] [-i] [-v] [-s] <interface> [[<AF>] <address>]\n"));
179 #if HAVE_AFINET
180     fprintf(stderr, _("  [add <address>[/<prefixlen>]]\n"));
181     fprintf(stderr, _("  [del <address>[/<prefixlen>]]\n"));
182     fprintf(stderr, _("  [[-]broadcast [<address>]]  [[-]pointopoint [<address>]]\n"));
183     fprintf(stderr, _("  [netmask <address>]  [dstaddr <address>]  [tunnel <address>]\n"));
184 #endif
185 #ifdef SIOCSKEEPALIVE
186     fprintf(stderr, _("  [outfill <NN>] [keepalive <NN>]\n"));
187 #endif
188     fprintf(stderr, _("  [hw <HW> <address>]  [metric <NN>]  [mtu <NN>]\n"));
189     fprintf(stderr, _("  [[-]trailers]  [[-]arp]  [[-]allmulti]\n"));
190     fprintf(stderr, _("  [multicast]  [[-]promisc]\n"));
191     fprintf(stderr, _("  [mem_start <NN>]  [io_addr <NN>]  [irq <NN>]  [media <type>]\n"));
192 #ifdef HAVE_TXQUEUELEN
193     fprintf(stderr, _("  [txqueuelen <NN>]\n"));
194 #endif
195 #ifdef HAVE_DYNAMIC
196     fprintf(stderr, _("  [[-]dynamic]\n"));
197 #endif
198     fprintf(stderr, _("  [up|down] ...\n\n"));
199
200     fprintf(stderr, _("  <HW>=Hardware Type.\n"));
201     fprintf(stderr, _("  List of possible hardware types:\n"));
202     print_hwlist(0); /* 1 = ARPable */
203     fprintf(stderr, _("  <AF>=Address family. Default: %s\n"), DFLT_AF);
204     fprintf(stderr, _("  List of possible address families:\n"));
205     print_aflist(0); /* 1 = routeable */
206     exit(E_USAGE);
207 }
208
209 static void version(void)
210 {
211     fprintf(stderr, "%s\n%s\n", Release, Version);
212     exit(0);
213 }
214
215 static int set_netmask(int skfd, struct ifreq *ifr, struct sockaddr *sa)
216 {
217     int err = 0;
218
219     memcpy((char *) &ifr->ifr_netmask, (char *) sa,
220            sizeof(struct sockaddr));
221     if (ioctl(skfd, SIOCSIFNETMASK, ifr) < 0) {
222         fprintf(stderr, "SIOCSIFNETMASK: %s\n",
223                 strerror(errno));
224         err = 1;
225     }
226     return 0;
227 }
228
229 int main(int argc, char **argv)
230 {
231     struct sockaddr sa;
232     struct sockaddr sanetmask;
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, gotnetmask;
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
251
252 #if I18N
253     setlocale (LC_ALL, "");
254     bindtextdomain("net-tools", "/usr/share/locale");
255     textdomain("net-tools");
256 #endif
257
258     /* Find any options. */
259     argc--;
260     argv++;
261     while (argc && *argv[0] == '-') {
262         if (!strcmp(*argv, "-a"))
263             opt_a = 1;
264
265         else if (!strcmp(*argv, "-s"))
266             ife_short = 1;
267
268         else if (!strcmp(*argv, "-v"))
269             opt_v = 1;
270         
271         else if (!strcmp(*argv, "-V") || !strcmp(*argv, "-version") ||
272             !strcmp(*argv, "--version"))
273             version();
274
275         else if (!strcmp(*argv, "-?") || !strcmp(*argv, "-h") ||
276             !strcmp(*argv, "-help") || !strcmp(*argv, "--help"))
277             usage();
278
279         else {
280             fprintf(stderr, _("ifconfig: option `%s' not recognised.\n"), 
281                     argv[0]);
282             fprintf(stderr, _("ifconfig: `--help' gives usage information.\n"));
283             exit(1);
284         }
285
286         argv++;
287         argc--;
288     }
289
290     /* Create a channel to the NET kernel. */
291     if ((skfd = sockets_open(0)) < 0) {
292         perror("socket");
293         exit(1);
294     }
295
296     /* Do we have to show the current setup? */
297     if (argc == 0) {
298         int err = if_print((char *) NULL);
299         (void) close(skfd);
300         exit(err < 0);
301     }
302     /* No. Fetch the interface name. */
303     spp = argv;
304     safe_strncpy(ifr.ifr_name, *spp++, IFNAMSIZ);
305     if (*spp == (char *) NULL) {
306         int err = if_print(ifr.ifr_name);
307         (void) close(skfd);
308         exit(err < 0);
309     }
310
311
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);
317         
318     if (ap) {
319         addr_family = ap->af;
320         skfd = ap->fd;
321     }
322
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;
329         }
330         if (!strcmp(*spp, "-arp")) {
331             goterr |= set_flag(ifr.ifr_name, IFF_NOARP);
332             spp++;
333             continue;
334         }
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;
352                             }
353                         }
354                     }
355                 }
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;
365                     }
366                     ifr.ifr_map.port = newport;
367                     if (ioctl(skfd, SIOCSIFMAP, &ifr) < 0) {
368                         perror("port: SIOCSIFMAP");
369                         goterr = 1;
370                     }
371                 }
372             }
373             continue;
374         }
375 #endif
376
377         if (!strcmp(*spp, "trailers")) {
378             goterr |= clr_flag(ifr.ifr_name, IFF_NOTRAILERS);
379             spp++;
380             continue;
381         }
382         if (!strcmp(*spp, "-trailers")) {
383             goterr |= set_flag(ifr.ifr_name, IFF_NOTRAILERS);
384             spp++;
385             continue;
386         }
387         if (!strcmp(*spp, "promisc")) {
388             goterr |= set_flag(ifr.ifr_name, IFF_PROMISC);
389             spp++;
390             continue;
391         }
392         if (!strcmp(*spp, "-promisc")) {
393             goterr |= clr_flag(ifr.ifr_name, IFF_PROMISC);
394             spp++;
395             continue;
396         }
397         if (!strcmp(*spp, "multicast")) {
398             goterr |= set_flag(ifr.ifr_name, IFF_MULTICAST);
399             spp++;
400             continue;
401         }
402         if (!strcmp(*spp, "-multicast")) {
403             goterr |= clr_flag(ifr.ifr_name, IFF_MULTICAST);
404             spp++;
405             continue;
406         }
407         if (!strcmp(*spp, "allmulti")) {
408             goterr |= set_flag(ifr.ifr_name, IFF_ALLMULTI);
409             spp++;
410             continue;
411         }
412         if (!strcmp(*spp, "-allmulti")) {
413             goterr |= clr_flag(ifr.ifr_name, IFF_ALLMULTI);
414             spp++;
415             continue;
416         }
417         if (!strcmp(*spp, "up")) {
418             goterr |= set_flag(ifr.ifr_name, (IFF_UP | IFF_RUNNING));
419             spp++;
420             continue;
421         }
422         if (!strcmp(*spp, "down")) {
423             goterr |= clr_flag(ifr.ifr_name, IFF_UP);
424             spp++;
425             continue;
426         }
427 #ifdef HAVE_DYNAMIC
428         if (!strcmp(*spp, "dynamic")) {
429             goterr |= set_flag(ifr.ifr_name, IFF_DYNAMIC);
430             spp++;
431             continue;
432         }
433         if (!strcmp(*spp, "-dynamic")) {
434             goterr |= clr_flag(ifr.ifr_name, IFF_DYNAMIC);
435             spp++;
436             continue;
437         }
438 #endif
439
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;
447             }
448             spp++;
449             continue;
450         }
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;
458             }
459             spp++;
460             continue;
461         }
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;
470             }
471             spp++;
472             continue;
473         }
474 #endif
475
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;
484             }
485             spp++;
486             continue;
487         }
488 #endif
489
490         if (!strcmp(*spp, "-broadcast")) {
491             goterr |= clr_flag(ifr.ifr_name, IFF_BROADCAST);
492             spp++;
493             continue;
494         }
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;
503                 }
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;
510                 }
511                 spp++;
512             }
513             goterr |= set_flag(ifr.ifr_name, IFF_BROADCAST);
514             continue;
515         }
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;
525             }
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;
532             }
533             spp++;
534             continue;
535         }
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;
545             }
546             didnetmask++;
547             goterr = set_netmask(ap->fd, &ifr, &sa);
548             spp++;
549             continue;
550         }
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;
559             }
560             spp++;
561             continue;
562         }
563 #endif
564
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;
573             }
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;
578             }
579             spp++;
580             continue;
581         }
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;
590             }
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;
595             }
596             spp++;
597             continue;
598         }
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;
607             }
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;
612             }
613             spp++;
614             continue;
615         }
616         if (!strcmp(*spp, "-pointopoint")) {
617             goterr |= clr_flag(ifr.ifr_name, IFF_POINTOPOINT);
618             spp++;
619             continue;
620         }
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;
630                 }
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;
637                 }
638             }
639             goterr |= set_flag(ifr.ifr_name, IFF_POINTOPOINT);
640             spp++;
641             continue;
642         };
643
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;
654             }
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;
663             }
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;
670             }
671             spp++;
672             continue;
673         }
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;
688                 }
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;
696                 }
697                 memcpy((char *) &ifr6.ifr6_addr, (char *) &sa6.sin6_addr,
698                        sizeof(struct in6_addr));
699
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;
707                 }
708                 if (ioctl(fd, SIOGIFINDEX, &ifr) < 0) {
709                     perror("SIOGIFINDEX");
710                     goterr = 1;
711                     spp++;
712                     continue;
713                 }
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;
719                 }
720                 spp++;
721                 continue;
722             }
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;
733                 }
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;
741                 }
742
743                 memcpy(&ip, &sin.sin_addr.s_addr, sizeof(unsigned long));
744                 
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;
751                 }
752                 set_ifstate(ifr.ifr_name, ip, nm, bc, 1);
753                 
754             }
755             spp++;
756             continue;
757 #else
758             fprintf(stderr, _("Bad address.\n"));
759 #endif
760         }
761 #endif
762
763 #if HAVE_AFINET || HAVE_AFINET6
764         if (!strcmp(*spp, "del")) {
765             if (*++spp == NULL)
766                 usage();
767
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;
778                 }
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;
786                 }
787                 memcpy((char *) &ifr6.ifr6_addr, (char *) &sa6.sin6_addr,
788                        sizeof(struct in6_addr));
789                 
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;
797                 }
798                 if (ioctl(fd, SIOGIFINDEX, &ifr) < 0) {
799                     perror("SIOGIFINDEX");
800                     goterr = 1;
801                     spp++;
802                     continue;
803                 }
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;
810                 }
811                 spp++;
812                 continue;
813             }
814 #endif
815 #ifdef HAVE_AFINET
816             {
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;
825                 }
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;
832                 }
833                 
834                 memcpy(&ip, &sin.sin_addr.s_addr, sizeof(unsigned long));
835                 
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;
842                 }
843                 set_ifstate(ifr.ifr_name, ip, nm, bc, 0);
844             }
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
853         }
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;
866             }
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;
873             }
874             memcpy((char *) &ifr6.ifr6_addr, (char *) &sa6.sin6_addr,
875                    sizeof(struct in6_addr));
876
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;
883             }
884             if (ioctl(fd, SIOGIFINDEX, &ifr) < 0) {
885                 perror("SIOGIFINDEX");
886                 goterr = 1;
887                 spp++;
888                 continue;
889             }
890             ifr6.ifr6_ifindex = ifr.ifr_ifindex;
891             ifr6.ifr6_prefixlen = prefix_len;
892
893             if (ioctl(fd, SIOCSIFDSTADDR, &ifr6) < 0) {
894                 fprintf(stderr, "SIOCSIFDSTADDR: %s\n",
895                         strerror(errno));
896                 goterr = 1;
897             }
898             spp++;
899             continue;
900         }
901 #endif
902
903         /* If the next argument is a valid hostname, assume OK. */
904         safe_strncpy(host, *spp, (sizeof host));
905
906         /* FIXME: sa is too small for INET6 addresses, inet6 should use that too, 
907            broadcast is unexpected */
908         gotnetmask = 0;
909         if (ap->getmask) {
910             switch (ap->getmask(host, &sanetmask, NULL)) {
911             case -1:
912                 usage();
913                 break;
914             case 1:
915                 if (didnetmask)
916                     usage();
917                 gotnetmask = 1;
918                 break;
919             }
920         }
921         if (ap->input == NULL) {
922            fprintf(stderr, _("ifconfig: Cannot set address for this protocol family.\n"));
923            exit(1);
924         }
925         if (ap->input(0, host, &sa) < 0) {
926             ap->herror(host);
927             fprintf(stderr, _("ifconfig: `--help' gives usage information.\n"));
928             exit(1);
929         }
930         memcpy((char *) &ifr.ifr_addr, (char *) &sa, sizeof(struct sockaddr));
931         {
932             int r = 0;          /* to shut gcc up */
933             switch (ap->af) {
934 #if HAVE_AFINET
935             case AF_INET:
936                 fd = get_socket_for_af(AF_INET);
937                 if (fd < 0) {
938                     fprintf(stderr, _("No support for INET on this system.\n"));
939                     exit(1);
940                 }
941                 r = ioctl(fd, SIOCSIFADDR, &ifr);
942                 break;
943 #endif
944 #if HAVE_AFECONET
945             case AF_ECONET:
946                 fd = get_socket_for_af(AF_ECONET);
947                 if (fd < 0) {
948                     fprintf(stderr, _("No support for ECONET on this system.\n"));
949                     exit(1);
950                 }
951                 r = ioctl(fd, SIOCSIFADDR, &ifr);
952                 break;
953 #endif
954             default:
955                 fprintf(stderr,
956                 _("Don't know how to set addresses for family %d.\n"), ap->af);
957                 exit(1);
958             }
959             if (r < 0) {
960                 perror("SIOCSIFADDR");
961                 goterr = 1;
962             }
963         }
964         if (gotnetmask) {
965                 goterr |= set_netmask(skfd, &ifr, &sanetmask);
966                 didnetmask++;
967         }
968
969        /*
970         * Don't do the set_flag() if the address is an alias with a - at the
971         * end, since it's deleted already! - Roman
972         *
973         * Should really use regex.h here, not sure though how well it'll go
974         * with the cross-platform support etc. 
975         */
976         {
977             char *ptr;
978             short int found_colon = 0;
979             for (ptr = ifr.ifr_name; *ptr; ptr++ )
980                 if (*ptr == ':') found_colon++;
981                 
982             if (!(found_colon && *(ptr - 1) == '-'))
983                 goterr |= set_flag(ifr.ifr_name, (IFF_UP | IFF_RUNNING));
984         }
985
986         spp++;
987     }
988
989     return (goterr);
990 }
991
992 struct ifcmd {
993     int flag;
994     unsigned long addr;
995     char *base;
996     int baselen;
997 };
998
999 static unsigned char searcher[256];
1000
1001 static int set_ip_using(const char *name, int c, unsigned long ip)
1002 {
1003     struct ifreq ifr;
1004     struct sockaddr_in sin;
1005
1006     safe_strncpy(ifr.ifr_name, name, IFNAMSIZ);
1007     memset(&sin, 0, sizeof(struct sockaddr));
1008     sin.sin_family = AF_INET;
1009     sin.sin_addr.s_addr = ip;
1010     memcpy(&ifr.ifr_addr, &sin, sizeof(struct sockaddr));
1011     if (ioctl(skfd, c, &ifr) < 0)
1012         return -1;
1013     return 0;
1014 }
1015
1016 static int do_ifcmd(struct interface *x, struct ifcmd *ptr)
1017 {
1018     char *z, *e;
1019     struct sockaddr_in *sin;
1020     int i;
1021     
1022     if (do_if_fetch(x) < 0)
1023         return 0;
1024     if (strncmp(x->name, ptr->base, ptr->baselen) != 0)
1025         return 0; /* skip */
1026     z = strchr(x->name, ':');
1027     if (!z || !*z)
1028         return 0;
1029     z++;
1030     for (e = z; *e; e++)
1031         if (*e == '-') /* deleted */
1032             return 0;
1033     i = atoi(z);
1034     if (i < 0 || i > 255)
1035         abort();
1036     searcher[i] = 1;
1037     
1038     /* copy */
1039     sin = (struct sockaddr_in *)&x->dstaddr;
1040     if (sin->sin_addr.s_addr != ptr->addr) {
1041         return 0;
1042     }
1043     
1044     if (ptr->flag) {
1045         /* turn UP */
1046         if (set_flag(x->name, IFF_UP | IFF_RUNNING) == -1)
1047             return -1;
1048     } else {
1049         /* turn DOWN */
1050         if (clr_flag(x->name, IFF_UP) == -1)
1051             return -1;
1052     }
1053     
1054     return 1; /* all done! */
1055 }
1056
1057
1058 static int get_nmbc_parent(char *parent,
1059                            unsigned long *nm, unsigned long *bc)
1060 {
1061     struct interface *i;
1062     struct sockaddr_in *sin;
1063     
1064     i = lookup_interface(parent);
1065     if (!i)
1066         return -1;
1067     if (do_if_fetch(i) < 0)
1068         return 0;
1069     sin = (struct sockaddr_in *)&i->netmask;
1070     memcpy(nm, &sin->sin_addr.s_addr, sizeof(unsigned long));
1071     sin = (struct sockaddr_in *)&i->broadaddr;
1072     memcpy(bc, &sin->sin_addr.s_addr, sizeof(unsigned long));
1073     return 0;
1074 }
1075
1076 static int set_ifstate(char *parent, unsigned long ip,
1077                        unsigned long nm, unsigned long bc,
1078                        int flag)
1079 {
1080     char buf[IFNAMSIZ];
1081     struct ifcmd pt;
1082     int i;
1083     
1084     pt.base = parent;
1085     pt.baselen = strlen(parent);
1086     pt.addr = ip;
1087     pt.flag = flag;
1088     memset(searcher, 0, sizeof(searcher));
1089     i = for_all_interfaces((int (*)(struct interface *,void *))do_ifcmd, 
1090                            &pt);
1091     if (i == -1)
1092         return -1;
1093     if (i == 1)
1094         return 0;
1095     
1096     /* add a new interface */
1097     for (i = 0; i < 256; i++)
1098         if (searcher[i] == 0)
1099             break;
1100
1101     if (i == 256)
1102         return -1; /* FAILURE!!! out of ip addresses */
1103     
1104     if (snprintf(buf, IFNAMSIZ, "%s:%d", parent, i) > IFNAMSIZ)
1105         return -1;
1106     if (set_ip_using(buf, SIOCSIFADDR, ip) == -1)
1107         return -1;
1108     if (set_ip_using(buf, SIOCSIFNETMASK, nm) == -1)
1109         return -1;
1110     if (set_ip_using(buf, SIOCSIFBRDADDR, bc) == -1)
1111         return -1;
1112     if (set_flag(buf, IFF_BROADCAST) == -1)
1113         return -1;
1114     return 0;
1115 }
1116
1117