Use sys/xattr.h instead of attr/xattr.h
[platform/upstream/net-tools.git] / 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.59 2011-01-01 03:22:31 ecki 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 <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>
47
48 /* Ugh.  But libc5 doesn't provide POSIX types.  */
49 #include <asm/types.h>
50
51
52 #if HAVE_HWSLIP
53 #include <linux/if_slip.h>
54 #endif
55
56 #if HAVE_AFINET6
57
58 #ifndef _LINUX_IN6_H
59 /*
60  *    This is in linux/include/net/ipv6.h.
61  */
62
63 struct in6_ifreq {
64     struct in6_addr ifr6_addr;
65     __u32 ifr6_prefixlen;
66     unsigned int ifr6_ifindex;
67 };
68
69 #endif
70
71 #endif                          /* HAVE_AFINET6 */
72
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"
87
88 char *Release = RELEASE, *Version = "ifconfig 1.42 (2001-04-13)";
89
90 int opt_a = 0;                  /* show all interfaces          */
91 int opt_v = 0;                  /* debugging output flag        */
92
93 int addr_family = 0;            /* currently selected AF        */
94
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);
101
102 static int if_print(char *ifname)
103 {
104     int res;
105
106     if (ife_short)
107         printf(_("Iface      MTU    RX-OK RX-ERR RX-DRP RX-OVR    TX-OK TX-ERR TX-DRP TX-OVR Flg\n"));
108
109     if (!ifname) {
110         res = for_all_interfaces(do_if_print, &opt_a);
111     } else {
112         struct interface *ife;
113
114         ife = lookup_interface(ifname);
115         if (!ife) {
116                 return -1;
117         }
118         res = do_if_fetch(ife); 
119         if (res >= 0) 
120             ife_print(ife);
121     }
122     return res; 
123 }
124
125 /* Set a certain interface flag. */
126 static int set_flag(char *ifname, short flag)
127 {
128     struct ifreq ifr;
129
130     safe_strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
131     if (ioctl(skfd, SIOCGIFFLAGS, &ifr) < 0) {
132         fprintf(stderr, _("%s: ERROR while getting interface flags: %s\n"), 
133                 ifname, strerror(errno));
134         return (-1);
135     }
136     safe_strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
137     ifr.ifr_flags |= flag;
138     if (ioctl(skfd, SIOCSIFFLAGS, &ifr) < 0) {
139         perror("SIOCSIFFLAGS");
140         return -1;
141     }
142     return (0);
143 }
144
145 /* Clear a certain interface flag. */
146 static int clr_flag(char *ifname, short flag)
147 {
148     struct ifreq ifr;
149     int fd;
150
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;
158         }
159     } else
160         fd = skfd;
161
162     safe_strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
163     if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) {
164         fprintf(stderr, _("%s: ERROR while getting interface flags: %s\n"), 
165                 ifname, strerror(errno));
166         return -1;
167     }
168     safe_strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
169     ifr.ifr_flags &= ~flag;
170     if (ioctl(fd, SIOCSIFFLAGS, &ifr) < 0) {
171         perror("SIOCSIFFLAGS");
172         return -1;
173     }
174     return (0);
175 }
176
177 /** test is a specified flag is set */
178 static int test_flag(char *ifname, short flags)
179 {
180     struct ifreq ifr;
181     int fd;
182
183     if (strchr(ifname, ':')) {
184         /* This is a v4 alias interface.  Downing it via a socket for
185            another AF may have bad consequences. */
186         fd = get_socket_for_af(AF_INET);
187         if (fd < 0) {
188             fprintf(stderr, _("No support for INET on this system.\n"));
189             return -1;
190         }
191     } else
192         fd = skfd;
193
194     safe_strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
195     if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) {
196         fprintf(stderr, _("%s: ERROR while testing interface flags: %s\n"), 
197                 ifname, strerror(errno));
198         return -1;
199     }
200     return (ifr.ifr_flags & flags);
201 }
202
203 static void usage(void)
204 {
205     fprintf(stderr, _("Usage:\n  ifconfig [-a] [-v] [-s] <interface> [[<AF>] <address>]\n"));
206 #if HAVE_AFINET
207     fprintf(stderr, _("  [add <address>[/<prefixlen>]]\n"));
208     fprintf(stderr, _("  [del <address>[/<prefixlen>]]\n"));
209     fprintf(stderr, _("  [[-]broadcast [<address>]]  [[-]pointopoint [<address>]]\n"));
210     fprintf(stderr, _("  [netmask <address>]  [dstaddr <address>]  [tunnel <address>]\n"));
211 #endif
212 #ifdef SIOCSKEEPALIVE
213     fprintf(stderr, _("  [outfill <NN>] [keepalive <NN>]\n"));
214 #endif
215     fprintf(stderr, _("  [hw <HW> <address>]  [mtu <NN>]\n"));
216     fprintf(stderr, _("  [[-]trailers]  [[-]arp]  [[-]allmulti]\n"));
217     fprintf(stderr, _("  [multicast]  [[-]promisc]\n"));
218     fprintf(stderr, _("  [mem_start <NN>]  [io_addr <NN>]  [irq <NN>]  [media <type>]\n"));
219 #ifdef HAVE_TXQUEUELEN
220     fprintf(stderr, _("  [txqueuelen <NN>]\n"));
221 #endif
222 #ifdef HAVE_DYNAMIC
223     fprintf(stderr, _("  [[-]dynamic]\n"));
224 #endif
225     fprintf(stderr, _("  [up|down] ...\n\n"));
226
227     fprintf(stderr, _("  <HW>=Hardware Type.\n"));
228     fprintf(stderr, _("  List of possible hardware types:\n"));
229     print_hwlist(0); /* 1 = ARPable */
230     fprintf(stderr, _("  <AF>=Address family. Default: %s\n"), DFLT_AF);
231     fprintf(stderr, _("  List of possible address families:\n"));
232     print_aflist(0); /* 1 = routeable */
233     exit(E_USAGE);
234 }
235
236 static void version(void)
237 {
238     fprintf(stderr, "%s\n%s\n", Release, Version);
239     exit(E_VERSION);
240 }
241
242 static int set_netmask(int skfd, struct ifreq *ifr, struct sockaddr *sa)
243 {
244     int err = 0;
245
246     memcpy((char *) &ifr->ifr_netmask, (char *) sa,
247            sizeof(struct sockaddr));
248     if (ioctl(skfd, SIOCSIFNETMASK, ifr) < 0) {
249         fprintf(stderr, "SIOCSIFNETMASK: %s\n",
250                 strerror(errno));
251         err = 1;
252     }
253     return err;
254 }
255
256 int main(int argc, char **argv)
257 {
258     struct sockaddr sa;
259     struct sockaddr samask;
260     struct sockaddr_in sin;
261     char host[128];
262     struct aftype *ap;
263     struct hwtype *hw;
264     struct ifreq ifr;
265     int goterr = 0, didnetmask = 0, neednetmask=0;
266     char **spp;
267     int fd;
268 #if HAVE_AFINET6
269     extern struct aftype inet6_aftype;
270     struct sockaddr_in6 sa6;
271     struct in6_ifreq ifr6;
272     unsigned long prefix_len;
273     char *cp;
274 #endif
275 #if HAVE_AFINET
276     extern struct aftype inet_aftype;
277 #endif
278
279 #if I18N
280     setlocale (LC_ALL, "");
281     bindtextdomain("net-tools", "/usr/share/locale");
282     textdomain("net-tools");
283 #endif
284
285     /* Find any options. */
286     argc--;
287     argv++;
288     while (argc && *argv[0] == '-') {
289         if (!strcmp(*argv, "-a"))
290             opt_a = 1;
291
292         else if (!strcmp(*argv, "-s"))
293             ife_short = 1;
294
295         else if (!strcmp(*argv, "-v"))
296             opt_v = 1;
297         
298         else if (!strcmp(*argv, "-V") || !strcmp(*argv, "-version") ||
299             !strcmp(*argv, "--version"))
300             version();
301
302         else if (!strcmp(*argv, "-?") || !strcmp(*argv, "-h") ||
303             !strcmp(*argv, "-help") || !strcmp(*argv, "--help"))
304             usage();
305
306         else {
307             fprintf(stderr, _("ifconfig: option `%s' not recognised.\n"), 
308                     argv[0]);
309             fprintf(stderr, _("ifconfig: `--help' gives usage information.\n"));
310             exit(1);
311         }
312
313         argv++;
314         argc--;
315     }
316
317     /* Create a channel to the NET kernel. */
318     if ((skfd = sockets_open(0)) < 0) {
319         perror("socket");
320         exit(1);
321     }
322
323     /* Do we have to show the current setup? */
324     if (argc == 0) {
325         int err = if_print((char *) NULL);
326         (void) close(skfd);
327         exit(err < 0);
328     }
329     /* No. Fetch the interface name. */
330     spp = argv;
331     safe_strncpy(ifr.ifr_name, *spp++, IFNAMSIZ);
332     if (*spp == (char *) NULL) {
333         int err = if_print(ifr.ifr_name);
334         (void) close(skfd);
335         exit(err < 0);
336     }
337
338     /* The next argument is either an address family name, or an option. */
339     if ((ap = get_aftype(*spp)) != NULL)
340         spp++; /* it was a AF name */
341     else 
342         ap = get_aftype(DFLT_AF);
343         
344     if (ap) {
345         addr_family = ap->af;
346         skfd = ap->fd;
347     }
348
349     /* Process the remaining arguments. */
350     while (*spp != (char *) NULL) {
351         if (!strcmp(*spp, "arp")) {
352             goterr |= clr_flag(ifr.ifr_name, IFF_NOARP);
353             spp++;
354             continue;
355         }
356         if (!strcmp(*spp, "-arp")) {
357             goterr |= set_flag(ifr.ifr_name, IFF_NOARP);
358             spp++;
359             continue;
360         }
361 #ifdef IFF_PORTSEL
362         if (!strcmp(*spp, "media") || !strcmp(*spp, "port")) {
363             if (*++spp == NULL)
364                 usage();
365             if (!strcasecmp(*spp, "auto")) {
366                 goterr |= set_flag(ifr.ifr_name, IFF_AUTOMEDIA);
367             } else {
368                 int i, j, newport;
369                 char *endp;
370                 newport = strtol(*spp, &endp, 10);
371                 if (*endp != 0) {
372                     newport = -1;
373                     for (i = 0; if_port_text[i][0] && newport == -1; i++) {
374                         for (j = 0; if_port_text[i][j]; j++) {
375                             if (!strcasecmp(*spp, if_port_text[i][j])) {
376                                 newport = i;
377                                 break;
378                             }
379                         }
380                     }
381                 }
382                 spp++;
383                 if (newport == -1) {
384                     fprintf(stderr, _("Unknown media type.\n"));
385                     goterr = 1;
386                 } else {
387                     if (ioctl(skfd, SIOCGIFMAP, &ifr) < 0) {
388                         perror("port: SIOCGIFMAP"); 
389                         goterr = 1;
390                         continue;
391                     }
392                     ifr.ifr_map.port = newport;
393                     if (ioctl(skfd, SIOCSIFMAP, &ifr) < 0) {
394                         perror("port: SIOCSIFMAP");
395                         goterr = 1;
396                     }
397                 }
398             }
399             continue;
400         }
401 #endif
402
403         if (!strcmp(*spp, "trailers")) {
404             goterr |= clr_flag(ifr.ifr_name, IFF_NOTRAILERS);
405             spp++;
406             continue;
407         }
408         if (!strcmp(*spp, "-trailers")) {
409             goterr |= set_flag(ifr.ifr_name, IFF_NOTRAILERS);
410             spp++;
411             continue;
412         }
413         if (!strcmp(*spp, "promisc")) {
414             goterr |= set_flag(ifr.ifr_name, IFF_PROMISC);
415             spp++;
416             continue;
417         }
418         if (!strcmp(*spp, "-promisc")) {
419             goterr |= clr_flag(ifr.ifr_name, IFF_PROMISC);
420             if (test_flag(ifr.ifr_name, IFF_PROMISC) > 0)
421                 fprintf(stderr, _("Warning: Interface %s still in promisc mode... maybe other application is running?\n"), ifr.ifr_name);
422             spp++;
423             continue;
424         }
425         if (!strcmp(*spp, "multicast")) {
426             goterr |= set_flag(ifr.ifr_name, IFF_MULTICAST);
427             spp++;
428             continue;
429         }
430         if (!strcmp(*spp, "-multicast")) {
431             goterr |= clr_flag(ifr.ifr_name, IFF_MULTICAST);
432             if (test_flag(ifr.ifr_name, IFF_MULTICAST) > 0)
433                 fprintf(stderr, _("Warning: Interface %s still in MULTICAST mode.\n"), ifr.ifr_name);
434             spp++;
435             continue;
436         }
437         if (!strcmp(*spp, "allmulti")) {
438             goterr |= set_flag(ifr.ifr_name, IFF_ALLMULTI);
439             spp++;
440             continue;
441         }
442         if (!strcmp(*spp, "-allmulti")) {
443             goterr |= clr_flag(ifr.ifr_name, IFF_ALLMULTI);
444             if (test_flag(ifr.ifr_name, IFF_ALLMULTI) > 0)
445                 fprintf(stderr, _("Warning: Interface %s still in ALLMULTI mode.\n"), ifr.ifr_name);
446             spp++;
447             continue;
448         }
449         if (!strcmp(*spp, "up")) {
450             goterr |= set_flag(ifr.ifr_name, (IFF_UP | IFF_RUNNING));
451             spp++;
452             continue;
453         }
454         if (!strcmp(*spp, "down")) {
455             goterr |= clr_flag(ifr.ifr_name, IFF_UP);
456             spp++;
457             continue;
458         }
459 #ifdef HAVE_DYNAMIC
460         if (!strcmp(*spp, "dynamic")) {
461             goterr |= set_flag(ifr.ifr_name, IFF_DYNAMIC);
462             spp++;
463             continue;
464         }
465         if (!strcmp(*spp, "-dynamic")) {
466             goterr |= clr_flag(ifr.ifr_name, IFF_DYNAMIC);
467             spp++;
468             if (test_flag(ifr.ifr_name, IFF_DYNAMIC) > 0)
469                 fprintf(stderr, _("Warning: Interface %s still in DYNAMIC mode.\n"), ifr.ifr_name);
470             continue;
471         }
472 #endif
473
474         if (!strcmp(*spp, "mtu")) {
475             if (*++spp == NULL)
476                 usage();
477             ifr.ifr_mtu = atoi(*spp);
478             if (ioctl(skfd, SIOCSIFMTU, &ifr) < 0) {
479                 fprintf(stderr, "SIOCSIFMTU: %s\n", strerror(errno));
480                 goterr = 1;
481             }
482             spp++;
483             continue;
484         }
485 #ifdef SIOCSKEEPALIVE
486         if (!strcmp(*spp, "keepalive")) {
487             if (*++spp == NULL)
488                 usage();
489             ifr.ifr_data = (caddr_t) (uintptr_t) atoi(*spp);
490             if (ioctl(skfd, SIOCSKEEPALIVE, &ifr) < 0) {
491                 fprintf(stderr, "SIOCSKEEPALIVE: %s\n", strerror(errno));
492                 goterr = 1;
493             }
494             spp++;
495             continue;
496         }
497 #endif
498
499 #ifdef SIOCSOUTFILL
500         if (!strcmp(*spp, "outfill")) {
501             if (*++spp == NULL)
502                 usage();
503             ifr.ifr_data = (caddr_t) (uintptr_t) atoi(*spp);
504             if (ioctl(skfd, SIOCSOUTFILL, &ifr) < 0) {
505                 fprintf(stderr, "SIOCSOUTFILL: %s\n", strerror(errno));
506                 goterr = 1;
507             }
508             spp++;
509             continue;
510         }
511 #endif
512
513         if (!strcmp(*spp, "-broadcast")) {
514             goterr |= clr_flag(ifr.ifr_name, IFF_BROADCAST);
515             if (test_flag(ifr.ifr_name, IFF_BROADCAST) > 0)
516                 fprintf(stderr, _("Warning: Interface %s still in BROADCAST mode.\n"), ifr.ifr_name);
517             spp++;
518             continue;
519         }
520         if (!strcmp(*spp, "broadcast")) {
521             if (*++spp != NULL) {
522                 safe_strncpy(host, *spp, (sizeof host));
523                 if (ap->input(0, host, &sa) < 0) {
524                     if (ap->herror)
525                         ap->herror(host);
526                     else
527                         fprintf(stderr, _("ifconfig: Error resolving '%s' for broadcast\n"), host);
528                     goterr = 1;
529                     spp++;
530                     continue;
531                 }
532                 memcpy((char *) &ifr.ifr_broadaddr, (char *) &sa,
533                        sizeof(struct sockaddr));
534                 if (ioctl(ap->fd, SIOCSIFBRDADDR, &ifr) < 0) {
535                     fprintf(stderr, "SIOCSIFBRDADDR: %s\n",
536                             strerror(errno));
537                     goterr = 1;
538                 }
539                 spp++;
540             }
541             goterr |= set_flag(ifr.ifr_name, IFF_BROADCAST);
542             continue;
543         }
544         if (!strcmp(*spp, "dstaddr")) {
545             if (*++spp == NULL)
546                 usage();
547             safe_strncpy(host, *spp, (sizeof host));
548             if (ap->input(0, host, &sa) < 0) {
549                     if (ap->herror)
550                         ap->herror(host);
551                     else
552                         fprintf(stderr, _("ifconfig: Error resolving '%s' for dstaddr\n"), host);
553                 goterr = 1;
554                 spp++;
555                 continue;
556             }
557             memcpy((char *) &ifr.ifr_dstaddr, (char *) &sa,
558                    sizeof(struct sockaddr));
559             if (ioctl(ap->fd, SIOCSIFDSTADDR, &ifr) < 0) {
560                 fprintf(stderr, "SIOCSIFDSTADDR: %s\n",
561                         strerror(errno));
562                 goterr = 1;
563             }
564             spp++;
565             continue;
566         }
567         if (!strcmp(*spp, "netmask")) {
568             if (*++spp == NULL || didnetmask)
569                 usage();
570             safe_strncpy(host, *spp, (sizeof host));
571             if (ap->input(0, host, &sa) < 0) {
572                     if (ap->herror)
573                         ap->herror(host);
574                     else
575                         fprintf(stderr, _("ifconfig: Error resolving '%s' for netmask\n"), host);
576                 goterr = 1;
577                 spp++;
578                 continue;
579             }
580             didnetmask++;
581             goterr |= set_netmask(ap->fd, &ifr, &sa);
582             spp++;
583             continue;
584         }
585 #ifdef HAVE_TXQUEUELEN
586         if (!strcmp(*spp, "txqueuelen")) {
587             if (*++spp == NULL)
588                 usage();
589             ifr.ifr_qlen = strtoul(*spp, NULL, 0);
590             if (ioctl(skfd, SIOCSIFTXQLEN, &ifr) < 0) {
591                 fprintf(stderr, "SIOCSIFTXQLEN: %s\n", strerror(errno));
592                 goterr = 1;
593             }
594             spp++;
595             continue;
596         }
597 #endif
598
599         if (!strcmp(*spp, "mem_start")) {
600             if (*++spp == NULL)
601                 usage();
602             if (ioctl(skfd, SIOCGIFMAP, &ifr) < 0) {
603                 fprintf(stderr, "mem_start: SIOCGIFMAP: %s\n", strerror(errno)); 
604                 spp++; 
605                 goterr = 1;
606                 continue;
607             }
608             ifr.ifr_map.mem_start = strtoul(*spp, NULL, 0);
609             if (ioctl(skfd, SIOCSIFMAP, &ifr) < 0) {
610                 fprintf(stderr, "mem_start: SIOCSIFMAP: %s\n", strerror(errno));
611                 goterr = 1;
612             }
613             spp++;
614             continue;
615         }
616         if (!strcmp(*spp, "io_addr")) {
617             if (*++spp == NULL)
618                 usage();
619             if (ioctl(skfd, SIOCGIFMAP, &ifr) < 0) {
620                 fprintf(stderr, "io_addr: SIOCGIFMAP: %s\n", strerror(errno)); 
621                 spp++; 
622                 goterr = 1;
623                 continue;
624             }
625             ifr.ifr_map.base_addr = strtol(*spp, NULL, 0);
626             if (ioctl(skfd, SIOCSIFMAP, &ifr) < 0) {
627                 fprintf(stderr, "io_addr: SIOCSIFMAP: %s\n", strerror(errno));
628                 goterr = 1;
629             }
630             spp++;
631             continue;
632         }
633         if (!strcmp(*spp, "irq")) {
634             if (*++spp == NULL)
635                 usage();
636             if (ioctl(skfd, SIOCGIFMAP, &ifr) < 0) {
637                 fprintf(stderr, "irq: SIOCGIFMAP: %s\n", strerror(errno)); 
638                 goterr = 1;
639                 spp++; 
640                 continue;
641             }
642             ifr.ifr_map.irq = atoi(*spp);
643             if (ioctl(skfd, SIOCSIFMAP, &ifr) < 0) {
644                 fprintf(stderr, "irq: SIOCSIFMAP: %s\n", strerror(errno));
645                 goterr = 1;
646             }
647             spp++;
648             continue;
649         }
650         if (!strcmp(*spp, "-pointopoint")) {
651             goterr |= clr_flag(ifr.ifr_name, IFF_POINTOPOINT);
652             spp++;
653             if (test_flag(ifr.ifr_name, IFF_POINTOPOINT) > 0)
654                 fprintf(stderr, _("Warning: Interface %s still in POINTOPOINT mode.\n"), ifr.ifr_name);
655             continue;
656         }
657         if (!strcmp(*spp, "pointopoint")) {
658             if (*(spp + 1) != NULL) {
659                 spp++;
660                 safe_strncpy(host, *spp, (sizeof host));
661                 if (ap->input(0, host, &sa)) {
662                     if (ap->herror)
663                         ap->herror(host);
664                     else
665                         fprintf(stderr, _("ifconfig: Error resolving '%s' for pointopoint\n"), host);
666                     goterr = 1;
667                     spp++;
668                     continue;
669                 }
670                 memcpy((char *) &ifr.ifr_dstaddr, (char *) &sa,
671                        sizeof(struct sockaddr));
672                 if (ioctl(ap->fd, SIOCSIFDSTADDR, &ifr) < 0) {
673                     fprintf(stderr, "SIOCSIFDSTADDR: %s\n",
674                             strerror(errno));
675                     goterr = 1;
676                 }
677             }
678             goterr |= set_flag(ifr.ifr_name, IFF_POINTOPOINT);
679             spp++;
680             continue;
681         };
682
683         if (!strcmp(*spp, "hw")) {
684             if (*++spp == NULL)
685                 usage();
686             if ((hw = get_hwtype(*spp)) == NULL)
687                 usage();
688             if (hw->input == NULL) {
689                 fprintf(stderr, _("hw address type `%s' has no handler to set address. failed.\n"), *spp);
690                 spp+=2;
691                 goterr = 1;
692                 continue;
693             }
694             if (*++spp == NULL)
695                 usage();
696             safe_strncpy(host, *spp, (sizeof host));
697             if (hw->input(host, &sa) < 0) {
698                 fprintf(stderr, _("%s: invalid %s address.\n"), host, hw->name);
699                 goterr = 1;
700                 spp++;
701                 continue;
702             }
703             memcpy((char *) &ifr.ifr_hwaddr, (char *) &sa,
704                    sizeof(struct sockaddr));
705             if (ioctl(skfd, SIOCSIFHWADDR, &ifr) < 0) {
706                 if (errno == EBUSY)
707                         fprintf(stderr, "SIOCSIFHWADDR: %s - you may need to down the interface\n",
708                                 strerror(errno));
709                 else
710                         fprintf(stderr, "SIOCSIFHWADDR: %s\n",
711                                 strerror(errno));
712                 goterr = 1;
713             }
714             spp++;
715             continue;
716         }
717 #if HAVE_AFINET || HAVE_AFINET6
718         if (!strcmp(*spp, "add")) {
719             if (*++spp == NULL)
720                 usage();
721 #if HAVE_AFINET6
722             if (strchr(*spp, ':')) {
723                 /* INET6 */
724                 if ((cp = strchr(*spp, '/'))) {
725                     prefix_len = atol(cp + 1);
726                     if ((prefix_len < 0) || (prefix_len > 128))
727                         usage();
728                     *cp = 0;
729                 } else {
730                     prefix_len = 128;
731                 }
732                 safe_strncpy(host, *spp, (sizeof host));
733                 if (inet6_aftype.input(1, host, 
734                                        (struct sockaddr *) &sa6) < 0) {
735                     if (inet6_aftype.herror)
736                         inet6_aftype.herror(host);
737                     else
738                         fprintf(stderr, _("ifconfig: Error resolving '%s' for add\n"), host);
739                     goterr = 1;
740                     spp++;
741                     continue;
742                 }
743                 memcpy((char *) &ifr6.ifr6_addr, (char *) &sa6.sin6_addr,
744                        sizeof(struct in6_addr));
745
746                 fd = get_socket_for_af(AF_INET6);
747                 if (fd < 0) {
748                     fprintf(stderr, 
749                             _("No support for INET6 on this system.\n"));
750                     goterr = 1;
751                     spp++;
752                     continue;
753                 }
754                 if (ioctl(fd, SIOGIFINDEX, &ifr) < 0) {
755                     perror("SIOGIFINDEX");
756                     goterr = 1;
757                     spp++;
758                     continue;
759                 }
760                 ifr6.ifr6_ifindex = ifr.ifr_ifindex;
761                 ifr6.ifr6_prefixlen = prefix_len;
762                 if (ioctl(fd, SIOCSIFADDR, &ifr6) < 0) {
763                     perror("SIOCSIFADDR");
764                     goterr = 1;
765                 }
766                 spp++;
767                 continue;
768             }
769 #endif
770 #if HAVE_AFINET
771             { /* ipv4 address a.b.c.d */
772                 unsigned long ip, nm, bc;
773                 safe_strncpy(host, *spp, (sizeof host));
774                 if (inet_aftype.input(0, host, (struct sockaddr *)&sin) < 0) {
775                     ap->herror(host);
776                     goterr = 1;
777                     spp++;
778                     continue;
779                 }
780                 fd = get_socket_for_af(AF_INET);
781                 if (fd < 0) {
782                     fprintf(stderr, 
783                             _("No support for INET on this system.\n"));
784                     goterr = 1;
785                     spp++;
786                     continue;
787                 }
788
789                 memcpy(&ip, &sin.sin_addr.s_addr, sizeof(unsigned long));
790                 
791                 if (get_nmbc_parent(ifr.ifr_name, &nm, &bc) < 0) {
792                         fprintf(stderr, _("Interface %s not initialized\n"),
793                                 ifr.ifr_name);
794                         goterr = 1;
795                         spp++;
796                         continue;
797                 }
798                 set_ifstate(ifr.ifr_name, ip, nm, bc, 1);
799                 
800             }
801             spp++;
802             continue;
803 #else
804             fprintf(stderr, _("Bad address.\n"));
805 #endif
806         }
807 #endif
808
809 #if HAVE_AFINET || HAVE_AFINET6
810         if (!strcmp(*spp, "del")) {
811             if (*++spp == NULL)
812                 usage();
813
814 #ifdef SIOCDIFADDR
815 #if HAVE_AFINET6
816             if (strchr(*spp, ':')) {    /* INET6 */
817                 if ((cp = strchr(*spp, '/'))) {
818                     prefix_len = atol(cp + 1);
819                     if ((prefix_len < 0) || (prefix_len > 128))
820                         usage();
821                     *cp = 0;
822                 } else {
823                     prefix_len = 128;
824                 }
825                 safe_strncpy(host, *spp, (sizeof host));
826                 if (inet6_aftype.input(1, host, 
827                                        (struct sockaddr *) &sa6) < 0) {
828                     inet6_aftype.herror(host);
829                     goterr = 1;
830                     spp++;
831                     continue;
832                 }
833                 memcpy((char *) &ifr6.ifr6_addr, (char *) &sa6.sin6_addr,
834                        sizeof(struct in6_addr));
835                 
836                 fd = get_socket_for_af(AF_INET6);
837                 if (fd < 0) {
838                     fprintf(stderr, 
839                             _("No support for INET6 on this system.\n"));
840                     goterr = 1;
841                     spp++;
842                     continue;
843                 }
844                 if (ioctl(fd, SIOGIFINDEX, &ifr) < 0) {
845                     perror("SIOGIFINDEX");
846                     goterr = 1;
847                     spp++;
848                     continue;
849                 }
850                 ifr6.ifr6_ifindex = ifr.ifr_ifindex;
851                 ifr6.ifr6_prefixlen = prefix_len;
852                 if (opt_v)
853                         fprintf(stderr, "now deleting: ioctl(SIOCDIFADDR,{ifindex=%d,prefixlen=%ld})\n",ifr.ifr_ifindex,prefix_len);
854                 if (ioctl(fd, SIOCDIFADDR, &ifr6) < 0) {
855                     fprintf(stderr, "SIOCDIFADDR: %s\n",
856                             strerror(errno));
857                     goterr = 1;
858                 }
859                 spp++;
860                 continue;
861             }
862 #endif
863 #if HAVE_AFINET
864             {
865                 /* ipv4 address a.b.c.d */
866                 unsigned long ip, nm, bc;
867                 safe_strncpy(host, *spp, (sizeof host));
868                 if (inet_aftype.input(0, host, (struct sockaddr *)&sin) < 0) {
869                     ap->herror(host);
870                     goterr = 1;
871                     spp++;
872                     continue;
873                 }
874                 fd = get_socket_for_af(AF_INET);
875                 if (fd < 0) {
876                     fprintf(stderr, _("No support for INET on this system.\n"));
877                     goterr = 1;
878                     spp++;
879                     continue;
880                 }
881                 
882                 /* Clear "ip" in case sizeof(unsigned long) > sizeof(sin.sin_addr.s_addr) */
883                 ip = 0;
884                 memcpy(&ip, &sin.sin_addr.s_addr, sizeof(sin.sin_addr.s_addr));
885                 
886                 if (get_nmbc_parent(ifr.ifr_name, &nm, &bc) < 0) {
887                     fprintf(stderr, _("Interface %s not initialized\n"),
888                             ifr.ifr_name);
889                     goterr = 1;
890                     spp++;
891                     continue;
892                 }
893                 set_ifstate(ifr.ifr_name, ip, nm, bc, 0);
894             }
895             spp++;
896             continue;
897 #else
898             fprintf(stderr, _("Bad address.\n"));
899 #endif
900 #else
901             fprintf(stderr, _("Address deletion not supported on this system.\n"));
902 #endif
903         }
904 #endif
905 #if HAVE_AFINET6
906         if (!strcmp(*spp, "tunnel")) {
907             if (*++spp == NULL)
908                 usage();
909             if ((cp = strchr(*spp, '/'))) {
910                 prefix_len = atol(cp + 1);
911                 if ((prefix_len < 0) || (prefix_len > 128))
912                     usage();
913                 *cp = 0;
914             } else {
915                 prefix_len = 128;
916             }
917             safe_strncpy(host, *spp, (sizeof host));
918             if (inet6_aftype.input(1, host, (struct sockaddr *) &sa6) < 0) {
919                 inet6_aftype.herror(host);
920                 goterr = 1;
921                 spp++;
922                 continue;
923             }
924             memcpy((char *) &ifr6.ifr6_addr, (char *) &sa6.sin6_addr,
925                    sizeof(struct in6_addr));
926
927             fd = get_socket_for_af(AF_INET6);
928             if (fd < 0) {
929                 fprintf(stderr, _("No support for INET6 on this system.\n"));
930                 goterr = 1;
931                 spp++;
932                 continue;
933             }
934             if (ioctl(fd, SIOGIFINDEX, &ifr) < 0) {
935                 perror("SIOGIFINDEX");
936                 goterr = 1;
937                 spp++;
938                 continue;
939             }
940             ifr6.ifr6_ifindex = ifr.ifr_ifindex;
941             ifr6.ifr6_prefixlen = prefix_len;
942
943             if (ioctl(fd, SIOCSIFDSTADDR, &ifr6) < 0) {
944                 fprintf(stderr, "SIOCSIFDSTADDR: %s\n",
945                         strerror(errno));
946                 goterr = 1;
947             }
948             spp++;
949             continue;
950         }
951 #endif
952
953         /* If the next argument is a valid hostname, assume OK. */
954         safe_strncpy(host, *spp, (sizeof host));
955
956         /* FIXME: sa is too small for INET6 addresses, inet6 should use that too, 
957            broadcast is unexpected */
958         if (ap->getmask) {
959             switch (ap->getmask(host, &samask, NULL)) {
960             case -1:
961                 usage();
962                 break;
963             case 1:
964                 if (didnetmask)
965                     usage();
966
967                 // remeber to set the netmask from samask later
968                 neednetmask = 1;
969                 break;
970             }
971         }
972         if (ap->input == NULL) {
973            fprintf(stderr, _("ifconfig: Cannot set address for this protocol family.\n"));
974            exit(1);
975         }
976         if (ap->input(0, host, &sa) < 0) {
977             if (ap->herror)
978                 ap->herror(host);
979             else
980                 fprintf(stderr,_("ifconfig: error resolving '%s' to set address for af=%s\n"), host, ap->name); fprintf(stderr,
981             _("ifconfig: `--help' gives usage information.\n")); exit(1);
982         }
983         memcpy((char *) &ifr.ifr_addr, (char *) &sa, sizeof(struct sockaddr));
984         {
985             int r = 0;          /* to shut gcc up */
986             switch (ap->af) {
987 #if HAVE_AFINET
988             case AF_INET:
989                 fd = get_socket_for_af(AF_INET);
990                 if (fd < 0) {
991                     fprintf(stderr, _("No support for INET on this system.\n"));
992                     exit(1);
993                 }
994                 r = ioctl(fd, SIOCSIFADDR, &ifr);
995                 break;
996 #endif
997 #if HAVE_AFECONET
998             case AF_ECONET:
999                 fd = get_socket_for_af(AF_ECONET);
1000                 if (fd < 0) {
1001                     fprintf(stderr, _("No support for ECONET on this system.\n"));
1002                     exit(1);
1003                 }
1004                 r = ioctl(fd, SIOCSIFADDR, &ifr);
1005                 break;
1006 #endif
1007             default:
1008                 fprintf(stderr,
1009                 _("Don't know how to set addresses for family %d.\n"), ap->af);
1010                 exit(1);
1011             }
1012             if (r < 0) {
1013                 perror("SIOCSIFADDR");
1014                 goterr = 1;
1015             }
1016         }
1017
1018        /*
1019         * Don't do the set_flag() if the address is an alias with a - at the
1020         * end, since it's deleted already! - Roman
1021         *
1022         * Should really use regex.h here, not sure though how well it'll go
1023         * with the cross-platform support etc. 
1024         */
1025         {
1026             char *ptr;
1027             short int found_colon = 0;
1028             for (ptr = ifr.ifr_name; *ptr; ptr++ )
1029                 if (*ptr == ':') found_colon++;
1030                 
1031             if (!(found_colon && *(ptr - 1) == '-'))
1032                 goterr |= set_flag(ifr.ifr_name, (IFF_UP | IFF_RUNNING));
1033         }
1034
1035         spp++;
1036     }
1037
1038     if (neednetmask) {
1039         goterr |= set_netmask(skfd, &ifr, &samask);
1040         didnetmask++;
1041     }
1042
1043     if (opt_v && goterr)
1044         fprintf(stderr, _("WARNING: at least one error occured. (%d)\n"), goterr);
1045
1046     return (goterr);
1047 }
1048
1049 struct ifcmd {
1050     int flag;
1051     unsigned long addr;
1052     char *base;
1053     int baselen;
1054 };
1055
1056 static unsigned char searcher[256];
1057
1058 static int set_ip_using(const char *name, int c, unsigned long ip)
1059 {
1060     struct ifreq ifr;
1061     struct sockaddr_in sin;
1062
1063     safe_strncpy(ifr.ifr_name, name, IFNAMSIZ);
1064     memset(&sin, 0, sizeof(struct sockaddr));
1065     sin.sin_family = AF_INET;
1066     sin.sin_addr.s_addr = ip;
1067     memcpy(&ifr.ifr_addr, &sin, sizeof(struct sockaddr));
1068     if (ioctl(skfd, c, &ifr) < 0)
1069         return -1;
1070     return 0;
1071 }
1072
1073 static int do_ifcmd(struct interface *x, struct ifcmd *ptr)
1074 {
1075     char *z, *e;
1076     struct sockaddr_in *sin;
1077     int i;
1078     
1079     if (do_if_fetch(x) < 0)
1080         return 0;
1081     if (strncmp(x->name, ptr->base, ptr->baselen) != 0)
1082         return 0; /* skip */
1083     z = strchr(x->name, ':');
1084     if (!z || !*z)
1085         return 0;
1086     z++;
1087     for (e = z; *e; e++)
1088         if (*e == '-') /* deleted */
1089             return 0;
1090     i = atoi(z);
1091     if (i < 0 || i > 255)
1092         abort();
1093     searcher[i] = 1;
1094     
1095     /* copy */
1096     sin = (struct sockaddr_in *)&x->dstaddr;
1097     if (sin->sin_addr.s_addr != ptr->addr) {
1098         return 0;
1099     }
1100     
1101     if (ptr->flag) {
1102         /* turn UP */
1103         if (set_flag(x->name, IFF_UP | IFF_RUNNING) == -1)
1104             return -1;
1105     } else {
1106         /* turn DOWN */
1107         if (clr_flag(x->name, IFF_UP) == -1)
1108             return -1;
1109     }
1110     
1111     return 1; /* all done! */
1112 }
1113
1114
1115 static int get_nmbc_parent(char *parent,
1116                            unsigned long *nm, unsigned long *bc)
1117 {
1118     struct interface *i;
1119     struct sockaddr_in *sin;
1120     
1121     i = lookup_interface(parent);
1122     if (!i)
1123         return -1;
1124     if (do_if_fetch(i) < 0)
1125         return 0;
1126     sin = (struct sockaddr_in *)&i->netmask;
1127     memcpy(nm, &sin->sin_addr.s_addr, sizeof(unsigned long));
1128     sin = (struct sockaddr_in *)&i->broadaddr;
1129     memcpy(bc, &sin->sin_addr.s_addr, sizeof(unsigned long));
1130     return 0;
1131 }
1132
1133 static int set_ifstate(char *parent, unsigned long ip,
1134                        unsigned long nm, unsigned long bc,
1135                        int flag)
1136 {
1137     char buf[IFNAMSIZ];
1138     struct ifcmd pt;
1139     int i;
1140     
1141     pt.base = parent;
1142     pt.baselen = strlen(parent);
1143     pt.addr = ip;
1144     pt.flag = flag;
1145     memset(searcher, 0, sizeof(searcher));
1146     i = for_all_interfaces((int (*)(struct interface *,void *))do_ifcmd, 
1147                            &pt);
1148     if (i == -1)
1149         return -1;
1150     if (i == 1)
1151         return 0;
1152     
1153     /* add a new interface */
1154     for (i = 0; i < 256; i++)
1155         if (searcher[i] == 0)
1156             break;
1157
1158     if (i == 256)
1159         return -1; /* FAILURE!!! out of ip addresses */
1160     
1161     if (snprintf(buf, IFNAMSIZ, "%s:%d", parent, i) > IFNAMSIZ)
1162         return -1;
1163     if (set_ip_using(buf, SIOCSIFADDR, ip) == -1)
1164         return -1;
1165     if (set_ip_using(buf, SIOCSIFNETMASK, nm) == -1)
1166         return -1;
1167     if (set_ip_using(buf, SIOCSIFBRDADDR, bc) == -1)
1168         return -1;
1169     if (set_flag(buf, IFF_BROADCAST) == -1)
1170         return -1;
1171     return 0;
1172 }