nameif crash for long interface names (RHBZ #209120)
[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 Met   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>]  [metric <NN>]  [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_USAGE);
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_MULTICAST) > 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_MULTICAST) > 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, "metric")) {
475             if (*++spp == NULL)
476                 usage();
477             ifr.ifr_metric = atoi(*spp);
478             if (ioctl(skfd, SIOCSIFMETRIC, &ifr) < 0) {
479                 fprintf(stderr, "SIOCSIFMETRIC: %s\n", strerror(errno));
480                 goterr = 1;
481             }
482             spp++;
483             continue;
484         }
485         if (!strcmp(*spp, "mtu")) {
486             if (*++spp == NULL)
487                 usage();
488             ifr.ifr_mtu = atoi(*spp);
489             if (ioctl(skfd, SIOCSIFMTU, &ifr) < 0) {
490                 fprintf(stderr, "SIOCSIFMTU: %s\n", strerror(errno));
491                 goterr = 1;
492             }
493             spp++;
494             continue;
495         }
496 #ifdef SIOCSKEEPALIVE
497         if (!strcmp(*spp, "keepalive")) {
498             if (*++spp == NULL)
499                 usage();
500             ifr.ifr_data = (caddr_t) (uintptr_t) atoi(*spp);
501             if (ioctl(skfd, SIOCSKEEPALIVE, &ifr) < 0) {
502                 fprintf(stderr, "SIOCSKEEPALIVE: %s\n", strerror(errno));
503                 goterr = 1;
504             }
505             spp++;
506             continue;
507         }
508 #endif
509
510 #ifdef SIOCSOUTFILL
511         if (!strcmp(*spp, "outfill")) {
512             if (*++spp == NULL)
513                 usage();
514             ifr.ifr_data = (caddr_t) (uintptr_t) atoi(*spp);
515             if (ioctl(skfd, SIOCSOUTFILL, &ifr) < 0) {
516                 fprintf(stderr, "SIOCSOUTFILL: %s\n", strerror(errno));
517                 goterr = 1;
518             }
519             spp++;
520             continue;
521         }
522 #endif
523
524         if (!strcmp(*spp, "-broadcast")) {
525             goterr |= clr_flag(ifr.ifr_name, IFF_BROADCAST);
526             if (test_flag(ifr.ifr_name, IFF_MULTICAST) > 0)
527                 fprintf(stderr, _("Warning: Interface %s still in BROADCAST mode.\n"), ifr.ifr_name);
528             spp++;
529             continue;
530         }
531         if (!strcmp(*spp, "broadcast")) {
532             if (*++spp != NULL) {
533                 safe_strncpy(host, *spp, (sizeof host));
534                 if (ap->input(0, host, &sa) < 0) {
535                     if (ap->herror)
536                         ap->herror(host);
537                     else
538                         fprintf(stderr, _("ifconfig: Error resolving '%s' for broadcast\n"), host);
539                     goterr = 1;
540                     spp++;
541                     continue;
542                 }
543                 memcpy((char *) &ifr.ifr_broadaddr, (char *) &sa,
544                        sizeof(struct sockaddr));
545                 if (ioctl(ap->fd, SIOCSIFBRDADDR, &ifr) < 0) {
546                     fprintf(stderr, "SIOCSIFBRDADDR: %s\n",
547                             strerror(errno));
548                     goterr = 1;
549                 }
550                 spp++;
551             }
552             goterr |= set_flag(ifr.ifr_name, IFF_BROADCAST);
553             continue;
554         }
555         if (!strcmp(*spp, "dstaddr")) {
556             if (*++spp == NULL)
557                 usage();
558             safe_strncpy(host, *spp, (sizeof host));
559             if (ap->input(0, host, &sa) < 0) {
560                     if (ap->herror)
561                         ap->herror(host);
562                     else
563                         fprintf(stderr, _("ifconfig: Error resolving '%s' for dstaddr\n"), host);
564                 goterr = 1;
565                 spp++;
566                 continue;
567             }
568             memcpy((char *) &ifr.ifr_dstaddr, (char *) &sa,
569                    sizeof(struct sockaddr));
570             if (ioctl(ap->fd, SIOCSIFDSTADDR, &ifr) < 0) {
571                 fprintf(stderr, "SIOCSIFDSTADDR: %s\n",
572                         strerror(errno));
573                 goterr = 1;
574             }
575             spp++;
576             continue;
577         }
578         if (!strcmp(*spp, "netmask")) {
579             if (*++spp == NULL || didnetmask)
580                 usage();
581             safe_strncpy(host, *spp, (sizeof host));
582             if (ap->input(0, host, &sa) < 0) {
583                     if (ap->herror)
584                         ap->herror(host);
585                     else
586                         fprintf(stderr, _("ifconfig: Error resolving '%s' for netmask\n"), host);
587                 goterr = 1;
588                 spp++;
589                 continue;
590             }
591             didnetmask++;
592             goterr |= set_netmask(ap->fd, &ifr, &sa);
593             spp++;
594             continue;
595         }
596 #ifdef HAVE_TXQUEUELEN
597         if (!strcmp(*spp, "txqueuelen")) {
598             if (*++spp == NULL)
599                 usage();
600             ifr.ifr_qlen = strtoul(*spp, NULL, 0);
601             if (ioctl(skfd, SIOCSIFTXQLEN, &ifr) < 0) {
602                 fprintf(stderr, "SIOCSIFTXQLEN: %s\n", strerror(errno));
603                 goterr = 1;
604             }
605             spp++;
606             continue;
607         }
608 #endif
609
610         if (!strcmp(*spp, "mem_start")) {
611             if (*++spp == NULL)
612                 usage();
613             if (ioctl(skfd, SIOCGIFMAP, &ifr) < 0) {
614                 fprintf(stderr, "mem_start: SIOCGIFMAP: %s\n", strerror(errno)); 
615                 spp++; 
616                 goterr = 1;
617                 continue;
618             }
619             ifr.ifr_map.mem_start = strtoul(*spp, NULL, 0);
620             if (ioctl(skfd, SIOCSIFMAP, &ifr) < 0) {
621                 fprintf(stderr, "mem_start: SIOCSIFMAP: %s\n", strerror(errno));
622                 goterr = 1;
623             }
624             spp++;
625             continue;
626         }
627         if (!strcmp(*spp, "io_addr")) {
628             if (*++spp == NULL)
629                 usage();
630             if (ioctl(skfd, SIOCGIFMAP, &ifr) < 0) {
631                 fprintf(stderr, "io_addr: SIOCGIFMAP: %s\n", strerror(errno)); 
632                 spp++; 
633                 goterr = 1;
634                 continue;
635             }
636             ifr.ifr_map.base_addr = strtol(*spp, NULL, 0);
637             if (ioctl(skfd, SIOCSIFMAP, &ifr) < 0) {
638                 fprintf(stderr, "io_addr: SIOCSIFMAP: %s\n", strerror(errno));
639                 goterr = 1;
640             }
641             spp++;
642             continue;
643         }
644         if (!strcmp(*spp, "irq")) {
645             if (*++spp == NULL)
646                 usage();
647             if (ioctl(skfd, SIOCGIFMAP, &ifr) < 0) {
648                 fprintf(stderr, "irq: SIOCGIFMAP: %s\n", strerror(errno)); 
649                 goterr = 1;
650                 spp++; 
651                 continue;
652             }
653             ifr.ifr_map.irq = atoi(*spp);
654             if (ioctl(skfd, SIOCSIFMAP, &ifr) < 0) {
655                 fprintf(stderr, "irq: SIOCSIFMAP: %s\n", strerror(errno));
656                 goterr = 1;
657             }
658             spp++;
659             continue;
660         }
661         if (!strcmp(*spp, "-pointopoint")) {
662             goterr |= clr_flag(ifr.ifr_name, IFF_POINTOPOINT);
663             spp++;
664             if (test_flag(ifr.ifr_name, IFF_MULTICAST) > 0)
665                 fprintf(stderr, _("Warning: Interface %s still in POINTOPOINT mode.\n"), ifr.ifr_name);
666             continue;
667         }
668         if (!strcmp(*spp, "pointopoint")) {
669             if (*(spp + 1) != NULL) {
670                 spp++;
671                 safe_strncpy(host, *spp, (sizeof host));
672                 if (ap->input(0, host, &sa)) {
673                     if (ap->herror)
674                         ap->herror(host);
675                     else
676                         fprintf(stderr, _("ifconfig: Error resolving '%s' for pointopoint\n"), host);
677                     goterr = 1;
678                     spp++;
679                     continue;
680                 }
681                 memcpy((char *) &ifr.ifr_dstaddr, (char *) &sa,
682                        sizeof(struct sockaddr));
683                 if (ioctl(ap->fd, SIOCSIFDSTADDR, &ifr) < 0) {
684                     fprintf(stderr, "SIOCSIFDSTADDR: %s\n",
685                             strerror(errno));
686                     goterr = 1;
687                 }
688             }
689             goterr |= set_flag(ifr.ifr_name, IFF_POINTOPOINT);
690             spp++;
691             continue;
692         };
693
694         if (!strcmp(*spp, "hw")) {
695             if (*++spp == NULL)
696                 usage();
697             if ((hw = get_hwtype(*spp)) == NULL)
698                 usage();
699             if (hw->input == NULL) {
700                 fprintf(stderr, _("hw address type `%s' has no handler to set address. failed.\n"), *spp);
701                 spp+=2;
702                 goterr = 1;
703                 continue;
704             }
705             if (*++spp == NULL)
706                 usage();
707             safe_strncpy(host, *spp, (sizeof host));
708             if (hw->input(host, &sa) < 0) {
709                 fprintf(stderr, _("%s: invalid %s address.\n"), host, hw->name);
710                 goterr = 1;
711                 spp++;
712                 continue;
713             }
714             memcpy((char *) &ifr.ifr_hwaddr, (char *) &sa,
715                    sizeof(struct sockaddr));
716             if (ioctl(skfd, SIOCSIFHWADDR, &ifr) < 0) {
717                 if (errno == EBUSY)
718                         fprintf(stderr, "SIOCSIFHWADDR: %s - you may need to down the interface\n",
719                                 strerror(errno));
720                 else
721                         fprintf(stderr, "SIOCSIFHWADDR: %s\n",
722                                 strerror(errno));
723                 goterr = 1;
724             }
725             spp++;
726             continue;
727         }
728 #if HAVE_AFINET || HAVE_AFINET6
729         if (!strcmp(*spp, "add")) {
730             if (*++spp == NULL)
731                 usage();
732 #if HAVE_AFINET6
733             if (strchr(*spp, ':')) {
734                 /* INET6 */
735                 if ((cp = strchr(*spp, '/'))) {
736                     prefix_len = atol(cp + 1);
737                     if ((prefix_len < 0) || (prefix_len > 128))
738                         usage();
739                     *cp = 0;
740                 } else {
741                     prefix_len = 128;
742                 }
743                 safe_strncpy(host, *spp, (sizeof host));
744                 if (inet6_aftype.input(1, host, 
745                                        (struct sockaddr *) &sa6) < 0) {
746                     if (inet6_aftype.herror)
747                         inet6_aftype.herror(host);
748                     else
749                         fprintf(stderr, _("ifconfig: Error resolving '%s' for add\n"), host);
750                     goterr = 1;
751                     spp++;
752                     continue;
753                 }
754                 memcpy((char *) &ifr6.ifr6_addr, (char *) &sa6.sin6_addr,
755                        sizeof(struct in6_addr));
756
757                 fd = get_socket_for_af(AF_INET6);
758                 if (fd < 0) {
759                     fprintf(stderr, 
760                             _("No support for INET6 on this system.\n"));
761                     goterr = 1;
762                     spp++;
763                     continue;
764                 }
765                 if (ioctl(fd, SIOGIFINDEX, &ifr) < 0) {
766                     perror("SIOGIFINDEX");
767                     goterr = 1;
768                     spp++;
769                     continue;
770                 }
771                 ifr6.ifr6_ifindex = ifr.ifr_ifindex;
772                 ifr6.ifr6_prefixlen = prefix_len;
773                 if (ioctl(fd, SIOCSIFADDR, &ifr6) < 0) {
774                     perror("SIOCSIFADDR");
775                     goterr = 1;
776                 }
777                 spp++;
778                 continue;
779             }
780 #endif
781 #if HAVE_AFINET
782             { /* ipv4 address a.b.c.d */
783                 unsigned long ip, nm, bc;
784                 safe_strncpy(host, *spp, (sizeof host));
785                 if (inet_aftype.input(0, host, (struct sockaddr *)&sin) < 0) {
786                     ap->herror(host);
787                     goterr = 1;
788                     spp++;
789                     continue;
790                 }
791                 fd = get_socket_for_af(AF_INET);
792                 if (fd < 0) {
793                     fprintf(stderr, 
794                             _("No support for INET on this system.\n"));
795                     goterr = 1;
796                     spp++;
797                     continue;
798                 }
799
800                 memcpy(&ip, &sin.sin_addr.s_addr, sizeof(unsigned long));
801                 
802                 if (get_nmbc_parent(ifr.ifr_name, &nm, &bc) < 0) {
803                         fprintf(stderr, _("Interface %s not initialized\n"),
804                                 ifr.ifr_name);
805                         goterr = 1;
806                         spp++;
807                         continue;
808                 }
809                 set_ifstate(ifr.ifr_name, ip, nm, bc, 1);
810                 
811             }
812             spp++;
813             continue;
814 #else
815             fprintf(stderr, _("Bad address.\n"));
816 #endif
817         }
818 #endif
819
820 #if HAVE_AFINET || HAVE_AFINET6
821         if (!strcmp(*spp, "del")) {
822             if (*++spp == NULL)
823                 usage();
824
825 #ifdef SIOCDIFADDR
826 #if HAVE_AFINET6
827             if (strchr(*spp, ':')) {    /* INET6 */
828                 if ((cp = strchr(*spp, '/'))) {
829                     prefix_len = atol(cp + 1);
830                     if ((prefix_len < 0) || (prefix_len > 128))
831                         usage();
832                     *cp = 0;
833                 } else {
834                     prefix_len = 128;
835                 }
836                 safe_strncpy(host, *spp, (sizeof host));
837                 if (inet6_aftype.input(1, host, 
838                                        (struct sockaddr *) &sa6) < 0) {
839                     inet6_aftype.herror(host);
840                     goterr = 1;
841                     spp++;
842                     continue;
843                 }
844                 memcpy((char *) &ifr6.ifr6_addr, (char *) &sa6.sin6_addr,
845                        sizeof(struct in6_addr));
846                 
847                 fd = get_socket_for_af(AF_INET6);
848                 if (fd < 0) {
849                     fprintf(stderr, 
850                             _("No support for INET6 on this system.\n"));
851                     goterr = 1;
852                     spp++;
853                     continue;
854                 }
855                 if (ioctl(fd, SIOGIFINDEX, &ifr) < 0) {
856                     perror("SIOGIFINDEX");
857                     goterr = 1;
858                     spp++;
859                     continue;
860                 }
861                 ifr6.ifr6_ifindex = ifr.ifr_ifindex;
862                 ifr6.ifr6_prefixlen = prefix_len;
863                 if (opt_v)
864                         fprintf(stderr, "now deleting: ioctl(SIOCDIFADDR,{ifindex=%d,prefixlen=%ld})\n",ifr.ifr_ifindex,prefix_len);
865                 if (ioctl(fd, SIOCDIFADDR, &ifr6) < 0) {
866                     fprintf(stderr, "SIOCDIFADDR: %s\n",
867                             strerror(errno));
868                     goterr = 1;
869                 }
870                 spp++;
871                 continue;
872             }
873 #endif
874 #if HAVE_AFINET
875             {
876                 /* ipv4 address a.b.c.d */
877                 unsigned long ip, nm, bc;
878                 safe_strncpy(host, *spp, (sizeof host));
879                 if (inet_aftype.input(0, host, (struct sockaddr *)&sin) < 0) {
880                     ap->herror(host);
881                     goterr = 1;
882                     spp++;
883                     continue;
884                 }
885                 fd = get_socket_for_af(AF_INET);
886                 if (fd < 0) {
887                     fprintf(stderr, _("No support for INET on this system.\n"));
888                     goterr = 1;
889                     spp++;
890                     continue;
891                 }
892                 
893                 memcpy(&ip, &sin.sin_addr.s_addr, sizeof(unsigned long));
894                 
895                 if (get_nmbc_parent(ifr.ifr_name, &nm, &bc) < 0) {
896                     fprintf(stderr, _("Interface %s not initialized\n"),
897                             ifr.ifr_name);
898                     goterr = 1;
899                     spp++;
900                     continue;
901                 }
902                 set_ifstate(ifr.ifr_name, ip, nm, bc, 0);
903             }
904             spp++;
905             continue;
906 #else
907             fprintf(stderr, _("Bad address.\n"));
908 #endif
909 #else
910             fprintf(stderr, _("Address deletion not supported on this system.\n"));
911 #endif
912         }
913 #endif
914 #if HAVE_AFINET6
915         if (!strcmp(*spp, "tunnel")) {
916             if (*++spp == NULL)
917                 usage();
918             if ((cp = strchr(*spp, '/'))) {
919                 prefix_len = atol(cp + 1);
920                 if ((prefix_len < 0) || (prefix_len > 128))
921                     usage();
922                 *cp = 0;
923             } else {
924                 prefix_len = 128;
925             }
926             safe_strncpy(host, *spp, (sizeof host));
927             if (inet6_aftype.input(1, host, (struct sockaddr *) &sa6) < 0) {
928                 inet6_aftype.herror(host);
929                 goterr = 1;
930                 spp++;
931                 continue;
932             }
933             memcpy((char *) &ifr6.ifr6_addr, (char *) &sa6.sin6_addr,
934                    sizeof(struct in6_addr));
935
936             fd = get_socket_for_af(AF_INET6);
937             if (fd < 0) {
938                 fprintf(stderr, _("No support for INET6 on this system.\n"));
939                 goterr = 1;
940                 spp++;
941                 continue;
942             }
943             if (ioctl(fd, SIOGIFINDEX, &ifr) < 0) {
944                 perror("SIOGIFINDEX");
945                 goterr = 1;
946                 spp++;
947                 continue;
948             }
949             ifr6.ifr6_ifindex = ifr.ifr_ifindex;
950             ifr6.ifr6_prefixlen = prefix_len;
951
952             if (ioctl(fd, SIOCSIFDSTADDR, &ifr6) < 0) {
953                 fprintf(stderr, "SIOCSIFDSTADDR: %s\n",
954                         strerror(errno));
955                 goterr = 1;
956             }
957             spp++;
958             continue;
959         }
960 #endif
961
962         /* If the next argument is a valid hostname, assume OK. */
963         safe_strncpy(host, *spp, (sizeof host));
964
965         /* FIXME: sa is too small for INET6 addresses, inet6 should use that too, 
966            broadcast is unexpected */
967         if (ap->getmask) {
968             switch (ap->getmask(host, &samask, NULL)) {
969             case -1:
970                 usage();
971                 break;
972             case 1:
973                 if (didnetmask)
974                     usage();
975
976                 // remeber to set the netmask from samask later
977                 neednetmask = 1;
978                 break;
979             }
980         }
981         if (ap->input == NULL) {
982            fprintf(stderr, _("ifconfig: Cannot set address for this protocol family.\n"));
983            exit(1);
984         }
985         if (ap->input(0, host, &sa) < 0) {
986             if (ap->herror)
987                 ap->herror(host);
988             else
989                 fprintf(stderr,_("ifconfig: error resolving '%s' to set address for af=%s\n"), host, ap->name); fprintf(stderr,
990             _("ifconfig: `--help' gives usage information.\n")); exit(1);
991         }
992         memcpy((char *) &ifr.ifr_addr, (char *) &sa, sizeof(struct sockaddr));
993         {
994             int r = 0;          /* to shut gcc up */
995             switch (ap->af) {
996 #if HAVE_AFINET
997             case AF_INET:
998                 fd = get_socket_for_af(AF_INET);
999                 if (fd < 0) {
1000                     fprintf(stderr, _("No support for INET on this system.\n"));
1001                     exit(1);
1002                 }
1003                 r = ioctl(fd, SIOCSIFADDR, &ifr);
1004                 break;
1005 #endif
1006 #if HAVE_AFECONET
1007             case AF_ECONET:
1008                 fd = get_socket_for_af(AF_ECONET);
1009                 if (fd < 0) {
1010                     fprintf(stderr, _("No support for ECONET on this system.\n"));
1011                     exit(1);
1012                 }
1013                 r = ioctl(fd, SIOCSIFADDR, &ifr);
1014                 break;
1015 #endif
1016             default:
1017                 fprintf(stderr,
1018                 _("Don't know how to set addresses for family %d.\n"), ap->af);
1019                 exit(1);
1020             }
1021             if (r < 0) {
1022                 perror("SIOCSIFADDR");
1023                 goterr = 1;
1024             }
1025         }
1026
1027        /*
1028         * Don't do the set_flag() if the address is an alias with a - at the
1029         * end, since it's deleted already! - Roman
1030         *
1031         * Should really use regex.h here, not sure though how well it'll go
1032         * with the cross-platform support etc. 
1033         */
1034         {
1035             char *ptr;
1036             short int found_colon = 0;
1037             for (ptr = ifr.ifr_name; *ptr; ptr++ )
1038                 if (*ptr == ':') found_colon++;
1039                 
1040             if (!(found_colon && *(ptr - 1) == '-'))
1041                 goterr |= set_flag(ifr.ifr_name, (IFF_UP | IFF_RUNNING));
1042         }
1043
1044         spp++;
1045     }
1046
1047     if (neednetmask) {
1048         goterr |= set_netmask(skfd, &ifr, &samask);
1049         didnetmask++;
1050     }
1051
1052     if (opt_v && goterr)
1053         fprintf(stderr, _("WARNING: at least one error occured. (%d)\n"), goterr);
1054
1055     return (goterr);
1056 }
1057
1058 struct ifcmd {
1059     int flag;
1060     unsigned long addr;
1061     char *base;
1062     int baselen;
1063 };
1064
1065 static unsigned char searcher[256];
1066
1067 static int set_ip_using(const char *name, int c, unsigned long ip)
1068 {
1069     struct ifreq ifr;
1070     struct sockaddr_in sin;
1071
1072     safe_strncpy(ifr.ifr_name, name, IFNAMSIZ);
1073     memset(&sin, 0, sizeof(struct sockaddr));
1074     sin.sin_family = AF_INET;
1075     sin.sin_addr.s_addr = ip;
1076     memcpy(&ifr.ifr_addr, &sin, sizeof(struct sockaddr));
1077     if (ioctl(skfd, c, &ifr) < 0)
1078         return -1;
1079     return 0;
1080 }
1081
1082 static int do_ifcmd(struct interface *x, struct ifcmd *ptr)
1083 {
1084     char *z, *e;
1085     struct sockaddr_in *sin;
1086     int i;
1087     
1088     if (do_if_fetch(x) < 0)
1089         return 0;
1090     if (strncmp(x->name, ptr->base, ptr->baselen) != 0)
1091         return 0; /* skip */
1092     z = strchr(x->name, ':');
1093     if (!z || !*z)
1094         return 0;
1095     z++;
1096     for (e = z; *e; e++)
1097         if (*e == '-') /* deleted */
1098             return 0;
1099     i = atoi(z);
1100     if (i < 0 || i > 255)
1101         abort();
1102     searcher[i] = 1;
1103     
1104     /* copy */
1105     sin = (struct sockaddr_in *)&x->dstaddr;
1106     if (sin->sin_addr.s_addr != ptr->addr) {
1107         return 0;
1108     }
1109     
1110     if (ptr->flag) {
1111         /* turn UP */
1112         if (set_flag(x->name, IFF_UP | IFF_RUNNING) == -1)
1113             return -1;
1114     } else {
1115         /* turn DOWN */
1116         if (clr_flag(x->name, IFF_UP) == -1)
1117             return -1;
1118     }
1119     
1120     return 1; /* all done! */
1121 }
1122
1123
1124 static int get_nmbc_parent(char *parent,
1125                            unsigned long *nm, unsigned long *bc)
1126 {
1127     struct interface *i;
1128     struct sockaddr_in *sin;
1129     
1130     i = lookup_interface(parent);
1131     if (!i)
1132         return -1;
1133     if (do_if_fetch(i) < 0)
1134         return 0;
1135     sin = (struct sockaddr_in *)&i->netmask;
1136     memcpy(nm, &sin->sin_addr.s_addr, sizeof(unsigned long));
1137     sin = (struct sockaddr_in *)&i->broadaddr;
1138     memcpy(bc, &sin->sin_addr.s_addr, sizeof(unsigned long));
1139     return 0;
1140 }
1141
1142 static int set_ifstate(char *parent, unsigned long ip,
1143                        unsigned long nm, unsigned long bc,
1144                        int flag)
1145 {
1146     char buf[IFNAMSIZ];
1147     struct ifcmd pt;
1148     int i;
1149     
1150     pt.base = parent;
1151     pt.baselen = strlen(parent);
1152     pt.addr = ip;
1153     pt.flag = flag;
1154     memset(searcher, 0, sizeof(searcher));
1155     i = for_all_interfaces((int (*)(struct interface *,void *))do_ifcmd, 
1156                            &pt);
1157     if (i == -1)
1158         return -1;
1159     if (i == 1)
1160         return 0;
1161     
1162     /* add a new interface */
1163     for (i = 0; i < 256; i++)
1164         if (searcher[i] == 0)
1165             break;
1166
1167     if (i == 256)
1168         return -1; /* FAILURE!!! out of ip addresses */
1169     
1170     if (snprintf(buf, IFNAMSIZ, "%s:%d", parent, i) > IFNAMSIZ)
1171         return -1;
1172     if (set_ip_using(buf, SIOCSIFADDR, ip) == -1)
1173         return -1;
1174     if (set_ip_using(buf, SIOCSIFNETMASK, nm) == -1)
1175         return -1;
1176     if (set_ip_using(buf, SIOCSIFBRDADDR, bc) == -1)
1177         return -1;
1178     if (set_flag(buf, IFF_BROADCAST) == -1)
1179         return -1;
1180     return 0;
1181 }