Run through indent, fix comment
[oweals/busybox.git] / networking / route.c
1 /* route
2  *
3  * Similar to the standard Unix route, but with only the necessary
4  * parts for AF_INET and AF_INET6
5  *
6  * Bjorn Wesen, Axis Communications AB
7  *
8  * Author of the original route:
9  *              Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
10  *              (derived from FvK's 'route.c     1.70    01/04/94')
11  *
12  * This program is free software; you can redistribute it
13  * and/or  modify it under  the terms of  the GNU General
14  * Public  License as  published  by  the  Free  Software
15  * Foundation;  either  version 2 of the License, or  (at
16  * your option) any later version.
17  *
18  * $Id: route.c,v 1.18 2002/08/22 18:24:43 bug1 Exp $
19  *
20  * displayroute() code added by Vladimir N. Oleynik <dzo@simtreas.ru>
21  * adjustments by Larry Doolittle  <LRDoolittle@lbl.gov>
22  *
23  * IPV6 support added by Bart Visscher <magick@linux-fan.com>
24  */
25
26 #include <sys/types.h>
27 #include <sys/ioctl.h>
28 #include "inet_common.h"
29 #include <net/route.h>
30 #include <net/if.h>
31 #include <linux/param.h>        /* HZ */
32 #include <stdio.h>
33 #include <errno.h>
34 #include <fcntl.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <getopt.h>
38 #include <unistd.h>
39 #include <ctype.h>
40 #include "busybox.h"
41
42 #define _(x) x
43
44 #define RTACTION_ADD   1
45 #define RTACTION_DEL   2
46 #define RTACTION_HELP  3
47 #define RTACTION_FLUSH 4
48 #define RTACTION_SHOW  5
49
50 #define E_NOTFOUND      8
51 #define E_SOCK          7
52 #define E_LOOKUP        6
53 #define E_VERSION       5
54 #define E_USAGE         4
55 #define E_OPTERR        3
56 #define E_INTERN        2
57 #define E_NOSUPP        1
58
59 #if defined (SIOCADDRTOLD) || defined (RTF_IRTT)        /* route */
60 #define HAVE_NEW_ADDRT 1
61 #endif
62 #ifdef RTF_IRTT                 /* route */
63 #define HAVE_RTF_IRTT 1
64 #endif
65 #ifdef RTF_REJECT               /* route */
66 #define HAVE_RTF_REJECT 1
67 #endif
68
69 #if HAVE_NEW_ADDRT
70 #define mask_in_addr(x) (((struct sockaddr_in *)&((x).rt_genmask))->sin_addr.s_addr)
71 #define full_mask(x) (x)
72 #else
73 #define mask_in_addr(x) ((x).rt_genmask)
74 #define full_mask(x) (((struct sockaddr_in *)&(x))->sin_addr.s_addr)
75 #endif
76
77
78
79 /* add or delete a route depending on action */
80
81 static int INET_setroute(int action, int options, char **args)
82 {
83         struct rtentry rt;
84         char target[128], gateway[128] = "NONE";
85         const char *netmask = bb_INET_default;
86         int xflag, isnet;
87         int skfd;
88
89         xflag = 0;
90
91         if (*args == NULL)
92                 show_usage();
93         if (strcmp(*args, "-net") == 0) {
94                 xflag = 1;
95                 args++;
96         } else if (strcmp(*args, "-host") == 0) {
97                 xflag = 2;
98                 args++;
99         }
100         if (*args == NULL)
101                 show_usage();
102         safe_strncpy(target, *args++, (sizeof target));
103
104         /* Clean out the RTREQ structure. */
105         memset((char *) &rt, 0, sizeof(struct rtentry));
106
107
108         if ((isnet =
109                  INET_resolve(target, (struct sockaddr_in *) &rt.rt_dst,
110                                           xflag != 1)) < 0) {
111                 error_msg(_("can't resolve %s"), target);
112                 return EXIT_FAILURE;    /* XXX change to E_something */
113         }
114
115         switch (xflag) {
116         case 1:
117                 isnet = 1;
118                 break;
119
120         case 2:
121                 isnet = 0;
122                 break;
123
124         default:
125                 break;
126         }
127
128         /* Fill in the other fields. */
129         rt.rt_flags = (RTF_UP | RTF_HOST);
130         if (isnet)
131                 rt.rt_flags &= ~RTF_HOST;
132
133         while (*args) {
134                 if (strcmp(*args, "metric") == 0) {
135                         int metric;
136
137                         args++;
138                         if (!*args || !isdigit(**args))
139                                 show_usage();
140                         metric = atoi(*args);
141 #if HAVE_NEW_ADDRT
142                         rt.rt_metric = metric + 1;
143 #else
144                         ENOSUPP("inet_setroute", "NEW_ADDRT (metric)"); /* XXX Fixme */
145 #endif
146                         args++;
147                         continue;
148                 }
149
150                 if (strcmp(*args, "netmask") == 0) {
151                         struct sockaddr mask;
152
153                         args++;
154                         if (!*args || mask_in_addr(rt))
155                                 show_usage();
156                         netmask = *args;
157                         if ((isnet =
158                                  INET_resolve(netmask, (struct sockaddr_in *) &mask,
159                                                           0)) < 0) {
160                                 error_msg(_("can't resolve netmask %s"), netmask);
161                                 return E_LOOKUP;
162                         }
163                         rt.rt_genmask = full_mask(mask);
164                         args++;
165                         continue;
166                 }
167
168                 if (strcmp(*args, "gw") == 0 || strcmp(*args, "gateway") == 0) {
169                         args++;
170                         if (!*args)
171                                 show_usage();
172                         if (rt.rt_flags & RTF_GATEWAY)
173                                 show_usage();
174                         safe_strncpy(gateway, *args, (sizeof gateway));
175                         if ((isnet =
176                                  INET_resolve(gateway, (struct sockaddr_in *) &rt.rt_gateway,
177                                                           1)) < 0) {
178                                 error_msg(_("can't resolve gw %s"), gateway);
179                                 return E_LOOKUP;
180                         }
181                         if (isnet) {
182                                 error_msg(_("%s: cannot use a NETWORK as gateway!"), gateway);
183                                 return E_OPTERR;
184                         }
185                         rt.rt_flags |= RTF_GATEWAY;
186                         args++;
187                         continue;
188                 }
189
190                 if (strcmp(*args, "mss") == 0) {
191                         args++;
192                         rt.rt_flags |= RTF_MSS;
193                         if (!*args)
194                                 show_usage();
195                         rt.rt_mss = atoi(*args);
196                         args++;
197                         if (rt.rt_mss < 64 || rt.rt_mss > 32768) {
198                                 error_msg(_("Invalid MSS."));
199                                 return E_OPTERR;
200                         }
201                         continue;
202                 }
203
204                 if (strcmp(*args, "window") == 0) {
205                         args++;
206                         if (!*args)
207                                 show_usage();
208                         rt.rt_flags |= RTF_WINDOW;
209                         rt.rt_window = atoi(*args);
210                         args++;
211                         if (rt.rt_window < 128) {
212                                 error_msg(_("Invalid window."));
213                                 return E_OPTERR;
214                         }
215                         continue;
216                 }
217
218                 if (strcmp(*args, "irtt") == 0) {
219                         args++;
220                         if (!*args)
221                                 show_usage();
222                         args++;
223 #if HAVE_RTF_IRTT
224                         rt.rt_flags |= RTF_IRTT;
225                         rt.rt_irtt = atoi(*(args - 1));
226                         rt.rt_irtt *= (HZ / 100);       /* FIXME */
227 #if 0                                   /* FIXME: do we need to check anything of this? */
228                         if (rt.rt_irtt < 1 || rt.rt_irtt > (120 * HZ)) {
229                                 error_msg(_("Invalid initial rtt."));
230                                 return E_OPTERR;
231                         }
232 #endif
233 #else
234                         ENOSUPP("inet_setroute", "RTF_IRTT");   /* XXX Fixme */
235 #endif
236                         continue;
237                 }
238
239                 if (strcmp(*args, "reject") == 0) {
240                         args++;
241 #if HAVE_RTF_REJECT
242                         rt.rt_flags |= RTF_REJECT;
243 #else
244                         ENOSUPP("inet_setroute", "RTF_REJECT"); /* XXX Fixme */
245 #endif
246                         continue;
247                 }
248                 if (strcmp(*args, "mod") == 0) {
249                         args++;
250                         rt.rt_flags |= RTF_MODIFIED;
251                         continue;
252                 }
253                 if (strcmp(*args, "dyn") == 0) {
254                         args++;
255                         rt.rt_flags |= RTF_DYNAMIC;
256                         continue;
257                 }
258                 if (strcmp(*args, "reinstate") == 0) {
259                         args++;
260                         rt.rt_flags |= RTF_REINSTATE;
261                         continue;
262                 }
263                 if (strcmp(*args, "device") == 0 || strcmp(*args, "dev") == 0) {
264                         args++;
265                         if (rt.rt_dev || *args == NULL)
266                                 show_usage();
267                         rt.rt_dev = *args++;
268                         continue;
269                 }
270                 /* nothing matches */
271                 if (!rt.rt_dev) {
272                         rt.rt_dev = *args++;
273                         if (*args)
274                                 show_usage();   /* must be last to catch typos */
275                 } else {
276                         show_usage();
277                 }
278         }
279
280 #if HAVE_RTF_REJECT
281         if ((rt.rt_flags & RTF_REJECT) && !rt.rt_dev)
282                 rt.rt_dev = "lo";
283 #endif
284
285         /* sanity checks.. */
286         if (mask_in_addr(rt)) {
287                 unsigned long mask = mask_in_addr(rt);
288
289                 mask = ~ntohl(mask);
290                 if ((rt.rt_flags & RTF_HOST) && mask != 0xffffffff) {
291                         error_msg(_("netmask %.8x doesn't make sense with host route"),
292                                           (unsigned int) mask);
293                         return E_OPTERR;
294                 }
295                 if (mask & (mask + 1)) {
296                         error_msg(_("bogus netmask %s"), netmask);
297                         return E_OPTERR;
298                 }
299                 mask = ((struct sockaddr_in *) &rt.rt_dst)->sin_addr.s_addr;
300                 if (mask & ~mask_in_addr(rt)) {
301                         error_msg(_("netmask doesn't match route address"));
302                         return E_OPTERR;
303                 }
304         }
305         /* Fill out netmask if still unset */
306         if ((action == RTACTION_ADD) && rt.rt_flags & RTF_HOST)
307                 mask_in_addr(rt) = 0xffffffff;
308
309         /* Create a socket to the INET kernel. */
310         if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
311                 perror("socket");
312                 return E_SOCK;
313         }
314         /* Tell the kernel to accept this route. */
315         if (action == RTACTION_DEL) {
316                 if (ioctl(skfd, SIOCDELRT, &rt) < 0) {
317                         perror("SIOCDELRT");
318                         close(skfd);
319                         return E_SOCK;
320                 }
321         } else {
322                 if (ioctl(skfd, SIOCADDRT, &rt) < 0) {
323                         perror("SIOCADDRT");
324                         close(skfd);
325                         return E_SOCK;
326                 }
327         }
328
329         /* Close the socket. */
330         (void) close(skfd);
331         return EXIT_SUCCESS;
332 }
333
334 #if CONFIG_FEATURE_IPV6
335 static int INET6_setroute(int action, int options, char **args)
336 {
337         struct in6_rtmsg rt;
338         struct ifreq ifr;
339         struct sockaddr_in6 sa6;
340         char target[128], gateway[128] = "NONE";
341         int metric, prefix_len;
342         char *devname = NULL;
343         char *cp;
344         int skfd;
345
346         if (*args == NULL)
347                 show_usage();
348
349         strcpy(target, *args++);
350         if (!strcmp(target, "default")) {
351                 prefix_len = 0;
352                 memset(&sa6, 0, sizeof(sa6));
353         } else {
354                 if ((cp = strchr(target, '/'))) {
355                         prefix_len = atol(cp + 1);
356                         if ((prefix_len < 0) || (prefix_len > 128))
357                                 show_usage();
358                         *cp = 0;
359                 } else {
360                         prefix_len = 128;
361                 }
362                 if (INET6_resolve(target, (struct sockaddr_in6 *) &sa6) < 0) {
363                         error_msg(_("can't resolve %s"), target);
364                         return EXIT_FAILURE;    /* XXX change to E_something */
365                 }
366         }
367
368         /* Clean out the RTREQ structure. */
369         memset((char *) &rt, 0, sizeof(struct in6_rtmsg));
370
371         memcpy(&rt.rtmsg_dst, sa6.sin6_addr.s6_addr, sizeof(struct in6_addr));
372
373         /* Fill in the other fields. */
374         rt.rtmsg_flags = RTF_UP;
375         if (prefix_len == 128)
376                 rt.rtmsg_flags |= RTF_HOST;
377         rt.rtmsg_metric = 1;
378         rt.rtmsg_dst_len = prefix_len;
379
380         while (*args) {
381                 if (!strcmp(*args, "metric")) {
382
383                         args++;
384                         if (!*args || !isdigit(**args))
385                                 show_usage();
386                         metric = atoi(*args);
387                         rt.rtmsg_metric = metric;
388                         args++;
389                         continue;
390                 }
391                 if (!strcmp(*args, "gw") || !strcmp(*args, "gateway")) {
392                         args++;
393                         if (!*args)
394                                 show_usage();
395                         if (rt.rtmsg_flags & RTF_GATEWAY)
396                                 show_usage();
397                         strcpy(gateway, *args);
398                         if (INET6_resolve(gateway, (struct sockaddr_in6 *) &sa6) < 0) {
399                                 error_msg(_("can't resolve gw %s"), gateway);
400                                 return (E_LOOKUP);
401                         }
402                         memcpy(&rt.rtmsg_gateway, sa6.sin6_addr.s6_addr,
403                                    sizeof(struct in6_addr));
404                         rt.rtmsg_flags |= RTF_GATEWAY;
405                         args++;
406                         continue;
407                 }
408                 if (!strcmp(*args, "mod")) {
409                         args++;
410                         rt.rtmsg_flags |= RTF_MODIFIED;
411                         continue;
412                 }
413                 if (!strcmp(*args, "dyn")) {
414                         args++;
415                         rt.rtmsg_flags |= RTF_DYNAMIC;
416                         continue;
417                 }
418                 if (!strcmp(*args, "device") || !strcmp(*args, "dev")) {
419                         args++;
420                         if (!*args)
421                                 show_usage();
422                 } else if (args[1])
423                         show_usage();
424
425                 devname = *args;
426                 args++;
427         }
428
429         /* Create a socket to the INET6 kernel. */
430         if ((skfd = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
431                 perror("socket");
432                 return (E_SOCK);
433         }
434         if (devname) {
435                 memset(&ifr, 0, sizeof(ifr));
436                 strcpy(ifr.ifr_name, devname);
437
438                 if (ioctl(skfd, SIOGIFINDEX, &ifr) < 0) {
439                         perror("SIOGIFINDEX");
440                         return (E_SOCK);
441                 }
442                 rt.rtmsg_ifindex = ifr.ifr_ifindex;
443         } else
444                 rt.rtmsg_ifindex = 0;
445
446         /* Tell the kernel to accept this route. */
447         if (action == RTACTION_DEL) {
448                 if (ioctl(skfd, SIOCDELRT, &rt) < 0) {
449                         perror("SIOCDELRT");
450                         close(skfd);
451                         return (E_SOCK);
452                 }
453         } else {
454                 if (ioctl(skfd, SIOCADDRT, &rt) < 0) {
455                         perror("SIOCADDRT");
456                         close(skfd);
457                         return (E_SOCK);
458                 }
459         }
460
461         /* Close the socket. */
462         (void) close(skfd);
463         return (0);
464 }
465 #endif
466
467 #ifndef RTF_UP
468 /* Keep this in sync with /usr/src/linux/include/linux/route.h */
469 #define RTF_UP          0x0001  /* route usable                 */
470 #define RTF_GATEWAY     0x0002  /* destination is a gateway     */
471 #define RTF_HOST        0x0004  /* host entry (net otherwise)   */
472 #define RTF_REINSTATE   0x0008  /* reinstate route after tmout  */
473 #define RTF_DYNAMIC     0x0010  /* created dyn. (by redirect)   */
474 #define RTF_MODIFIED    0x0020  /* modified dyn. (by redirect)  */
475 #define RTF_MTU         0x0040  /* specific MTU for this route  */
476 #ifndef RTF_MSS
477 #define RTF_MSS         RTF_MTU /* Compatibility :-(            */
478 #endif
479 #define RTF_WINDOW      0x0080  /* per route window clamping    */
480 #define RTF_IRTT        0x0100  /* Initial round trip time      */
481 #define RTF_REJECT      0x0200  /* Reject route                 */
482 #endif
483
484 void displayroutes(int noresolve, int netstatfmt)
485 {
486         char buff[256];
487         int nl = 0;
488         struct in_addr dest;
489         struct in_addr gw;
490         struct in_addr mask;
491         int flgs, ref, use, metric, mtu, win, ir;
492         char flags[64];
493         unsigned long int d, g, m;
494
495         char sdest[16], sgw[16];
496
497         FILE *fp = xfopen("/proc/net/route", "r");
498
499         if (noresolve)
500                 noresolve = 0x0fff;
501
502         while (fgets(buff, sizeof(buff), fp) != NULL) {
503                 if (nl) {
504                         int ifl = 0;
505                         int numeric;
506                         struct sockaddr_in s_addr;
507
508                         while (buff[ifl] != ' ' && buff[ifl] != '\t' && buff[ifl] != '\0')
509                                 ifl++;
510                         buff[ifl] = 0;  /* interface */
511                         if (sscanf(buff + ifl + 1, "%lx%lx%X%d%d%d%lx%d%d%d",
512                                            &d, &g, &flgs, &ref, &use, &metric, &m, &mtu, &win,
513                                            &ir) != 10) {
514                                 error_msg_and_die("Unsuported kernel route format\n");
515                         }
516                         if (nl == 1) {
517                                 printf("Kernel IP routing table\n");
518                                 printf
519                                         ("Destination     Gateway         Genmask         Flags %s Iface\n",
520                                          netstatfmt ? "  MSS Window  irtt" : "Metric Ref    Use");
521                         }
522                         ifl = 0;        /* parse flags */
523                         if (flgs & RTF_UP) {
524                                 if (flgs & RTF_REJECT)
525                                         flags[ifl++] = '!';
526                                 else
527                                         flags[ifl++] = 'U';
528                                 if (flgs & RTF_GATEWAY)
529                                         flags[ifl++] = 'G';
530                                 if (flgs & RTF_HOST)
531                                         flags[ifl++] = 'H';
532                                 if (flgs & RTF_REINSTATE)
533                                         flags[ifl++] = 'R';
534                                 if (flgs & RTF_DYNAMIC)
535                                         flags[ifl++] = 'D';
536                                 if (flgs & RTF_MODIFIED)
537                                         flags[ifl++] = 'M';
538                                 flags[ifl] = 0;
539                                 dest.s_addr = d;
540                                 gw.s_addr = g;
541                                 mask.s_addr = m;
542                                 memset(&s_addr, 0, sizeof(struct sockaddr_in));
543                                 s_addr.sin_family = AF_INET;
544                                 s_addr.sin_addr = dest;
545                                 numeric = noresolve | 0x8000;   /* default instead of * */
546                                 INET_rresolve(sdest, sizeof(sdest), &s_addr, numeric, m);
547                                 numeric = noresolve | 0x4000;   /* host instead of net */
548                                 s_addr.sin_addr = gw;
549                                 INET_rresolve(sgw, sizeof(sgw), &s_addr, numeric, m);
550
551                                 printf("%-16s%-16s%-16s%-6s", sdest, sgw, inet_ntoa(mask),
552                                            flags);
553                                 if (netstatfmt)
554                                         printf("%5d %-5d %6d %s\n", mtu, win, ir, buff);
555                                 else
556                                         printf("%-6d %-2d %7d %s\n", metric, ref, use, buff);
557                         }
558                 }
559                 nl++;
560         }
561 }
562
563 #if CONFIG_FEATURE_IPV6
564 static void INET6_displayroutes(int noresolve)
565 {
566         char buff[256];
567         char iface[16], flags[16];
568         char addr6[128], naddr6[128];
569         struct sockaddr_in6 saddr6, snaddr6;
570         int iflags, metric, refcnt, use, prefix_len, slen;
571         int numeric;
572
573         char addr6p[8][5], saddr6p[8][5], naddr6p[8][5];
574
575         FILE *fp = xfopen("/proc/net/ipv6_route", "r");
576
577         flags[0] = 'U';
578
579         if (noresolve)
580                 noresolve = 0x0fff;
581         numeric = noresolve | 0x8000;   /* default instead of * */
582
583         printf("Kernel IPv6 routing table\n"
584                    "Destination                                 "
585                    "Next Hop                                "
586                    "Flags Metric Ref    Use Iface\n");
587
588         while (fgets(buff, sizeof(buff), fp) != NULL) {
589                 int ifl;
590
591                 if (sscanf(buff, "%4s%4s%4s%4s%4s%4s%4s%4s %02x "
592                                    "%4s%4s%4s%4s%4s%4s%4s%4s %02x "
593                                    "%4s%4s%4s%4s%4s%4s%4s%4s %08x %08x %08x %08x %s\n",
594                                    addr6p[0], addr6p[1], addr6p[2], addr6p[3],
595                                    addr6p[4], addr6p[5], addr6p[6], addr6p[7],
596                                    &prefix_len,
597                                    saddr6p[0], saddr6p[1], saddr6p[2], saddr6p[3],
598                                    saddr6p[4], saddr6p[5], saddr6p[6], saddr6p[7],
599                                    &slen,
600                                    naddr6p[0], naddr6p[1], naddr6p[2], naddr6p[3],
601                                    naddr6p[4], naddr6p[5], naddr6p[6], naddr6p[7],
602                                    &metric, &use, &refcnt, &iflags, iface) != 31) {
603                         error_msg_and_die("Unsuported kernel route format\n");
604                 }
605
606                 ifl = 1;                /* parse flags */
607                 if (!(iflags & RTF_UP))
608                         continue;
609                 if (iflags & RTF_GATEWAY)
610                         flags[ifl++] = 'G';
611                 if (iflags & RTF_HOST)
612                         flags[ifl++] = 'H';
613                 if (iflags & RTF_DEFAULT)
614                         flags[ifl++] = 'D';
615                 if (iflags & RTF_ADDRCONF)
616                         flags[ifl++] = 'A';
617                 if (iflags & RTF_CACHE)
618                         flags[ifl++] = 'C';
619                 flags[ifl] = 0;
620
621                 /* Fetch and resolve the target address. */
622                 snprintf(addr6, sizeof(addr6), "%s:%s:%s:%s:%s:%s:%s:%s",
623                                  addr6p[0], addr6p[1], addr6p[2], addr6p[3],
624                                  addr6p[4], addr6p[5], addr6p[6], addr6p[7]);
625                 inet_pton(AF_INET6, addr6, (struct sockaddr *) &saddr6.sin6_addr);
626                 saddr6.sin6_family = AF_INET6;
627
628                 INET6_rresolve(addr6, sizeof(addr6), (struct sockaddr_in6 *) &saddr6,
629                                            numeric);
630                 snprintf(addr6, sizeof(addr6), "%s/%d", addr6, prefix_len);
631
632                 /* Fetch and resolve the nexthop address. */
633                 snprintf(naddr6, sizeof(naddr6), "%s:%s:%s:%s:%s:%s:%s:%s",
634                                  naddr6p[0], naddr6p[1], naddr6p[2], naddr6p[3],
635                                  naddr6p[4], naddr6p[5], naddr6p[6], naddr6p[7]);
636                 inet_pton(AF_INET6, naddr6, (struct sockaddr *) &snaddr6.sin6_addr);
637                 snaddr6.sin6_family = AF_INET6;
638
639                 INET6_rresolve(naddr6, sizeof(naddr6),
640                                            (struct sockaddr_in6 *) &snaddr6, numeric);
641
642                 /* Print the info. */
643                 printf("%-43s %-39s %-5s %-6d %-2d %7d %-8s\n",
644                            addr6, naddr6, flags, metric, refcnt, use, iface);
645         }
646 }
647 #endif
648
649 int route_main(int argc, char **argv)
650 {
651         int opt;
652         int what = 0;
653
654 #if CONFIG_FEATURE_IPV6
655         int af = AF_INET;
656 #endif
657
658         if (!argv[1] || (argv[1][0] == '-')) {
659                 /* check options */
660                 int noresolve = 0;
661                 int extended = 0;
662
663                 while ((opt = getopt(argc, argv, "A:ne")) > 0) {
664                         switch (opt) {
665                         case 'n':
666                                 noresolve = 1;
667                                 break;
668                         case 'e':
669                                 extended = 1;
670                                 break;
671                         case 'A':
672 #if CONFIG_FEATURE_IPV6
673                                 if (strcmp(optarg, "inet6") == 0)
674                                         af = AF_INET6;
675                                 break;
676 #endif
677                         default:
678                                 show_usage();
679                         }
680                 }
681
682 #if CONFIG_FEATURE_IPV6
683                 if (af == AF_INET6)
684                         INET6_displayroutes(*argv != NULL);
685                 else
686 #endif
687                         displayroutes(noresolve, extended);
688                 return EXIT_SUCCESS;
689         } else {
690                 /* check verb */
691                 if (strcmp(argv[1], "add") == 0)
692                         what = RTACTION_ADD;
693                 else if (strcmp(argv[1], "del") == 0
694                                  || strcmp(argv[1], "delete") == 0)
695                         what = RTACTION_DEL;
696                 else if (strcmp(argv[1], "flush") == 0)
697                         what = RTACTION_FLUSH;
698                 else
699                         show_usage();
700         }
701
702 #if CONFIG_FEATURE_IPV6
703         if (af == AF_INET6)
704                 return INET6_setroute(what, 0, argv + 2);
705 #endif
706         return INET_setroute(what, 0, argv + 2);
707 }