+#if CONFIG_FEATURE_IPV6
+static int INET6_setroute(int action, int options, char **args)
+{
+ struct in6_rtmsg rt;
+ struct ifreq ifr;
+ struct sockaddr_in6 sa6;
+ char target[128], gateway[128] = "NONE";
+ int metric, prefix_len;
+ char *devname = NULL;
+ char *cp;
+ int skfd;
+
+ if (*args == NULL)
+ show_usage();
+
+ strcpy(target, *args++);
+ if (!strcmp(target, "default")) {
+ prefix_len = 0;
+ memset(&sa6, 0, sizeof(sa6));
+ } else {
+ if ((cp = strchr(target, '/'))) {
+ prefix_len = atol(cp + 1);
+ if ((prefix_len < 0) || (prefix_len > 128))
+ show_usage();
+ *cp = 0;
+ } else {
+ prefix_len = 128;
+ }
+ if (INET6_resolve(target, (struct sockaddr_in6 *) &sa6) < 0) {
+ error_msg(_("can't resolve %s"), target);
+ return EXIT_FAILURE; /* XXX change to E_something */
+ }
+ }
+
+ /* Clean out the RTREQ structure. */
+ memset((char *) &rt, 0, sizeof(struct in6_rtmsg));
+
+ memcpy(&rt.rtmsg_dst, sa6.sin6_addr.s6_addr, sizeof(struct in6_addr));
+
+ /* Fill in the other fields. */
+ rt.rtmsg_flags = RTF_UP;
+ if (prefix_len == 128)
+ rt.rtmsg_flags |= RTF_HOST;
+ rt.rtmsg_metric = 1;
+ rt.rtmsg_dst_len = prefix_len;
+
+ while (*args) {
+ if (!strcmp(*args, "metric")) {
+
+ args++;
+ if (!*args || !isdigit(**args))
+ show_usage();
+ metric = atoi(*args);
+ rt.rtmsg_metric = metric;
+ args++;
+ continue;
+ }
+ if (!strcmp(*args, "gw") || !strcmp(*args, "gateway")) {
+ args++;
+ if (!*args)
+ show_usage();
+ if (rt.rtmsg_flags & RTF_GATEWAY)
+ show_usage();
+ strcpy(gateway, *args);
+ if (INET6_resolve(gateway, (struct sockaddr_in6 *) &sa6) < 0) {
+ error_msg(_("can't resolve gw %s"), gateway);
+ return (E_LOOKUP);
+ }
+ memcpy(&rt.rtmsg_gateway, sa6.sin6_addr.s6_addr,
+ sizeof(struct in6_addr));
+ rt.rtmsg_flags |= RTF_GATEWAY;
+ args++;
+ continue;
+ }
+ if (!strcmp(*args, "mod")) {
+ args++;
+ rt.rtmsg_flags |= RTF_MODIFIED;
+ continue;
+ }
+ if (!strcmp(*args, "dyn")) {
+ args++;
+ rt.rtmsg_flags |= RTF_DYNAMIC;
+ continue;
+ }
+ if (!strcmp(*args, "device") || !strcmp(*args, "dev")) {
+ args++;
+ if (!*args)
+ show_usage();
+ } else if (args[1])
+ show_usage();
+
+ devname = *args;
+ args++;
+ }
+
+ /* Create a socket to the INET6 kernel. */
+ if ((skfd = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
+ perror("socket");
+ return (E_SOCK);
+ }
+ if (devname) {
+ memset(&ifr, 0, sizeof(ifr));
+ strcpy(ifr.ifr_name, devname);
+
+ if (ioctl(skfd, SIOGIFINDEX, &ifr) < 0) {
+ perror("SIOGIFINDEX");
+ return (E_SOCK);
+ }
+ rt.rtmsg_ifindex = ifr.ifr_ifindex;
+ } else
+ rt.rtmsg_ifindex = 0;
+
+ /* Tell the kernel to accept this route. */
+ if (action == RTACTION_DEL) {
+ if (ioctl(skfd, SIOCDELRT, &rt) < 0) {
+ perror("SIOCDELRT");
+ close(skfd);
+ return (E_SOCK);
+ }
+ } else {
+ if (ioctl(skfd, SIOCADDRT, &rt) < 0) {
+ perror("SIOCADDRT");
+ close(skfd);
+ return (E_SOCK);
+ }
+ }
+
+ /* Close the socket. */
+ (void) close(skfd);
+ return (0);
+}
+#endif
+
+#ifndef RTF_UP
+/* Keep this in sync with /usr/src/linux/include/linux/route.h */
+#define RTF_UP 0x0001 /* route usable */
+#define RTF_GATEWAY 0x0002 /* destination is a gateway */
+#define RTF_HOST 0x0004 /* host entry (net otherwise) */
+#define RTF_REINSTATE 0x0008 /* reinstate route after tmout */
+#define RTF_DYNAMIC 0x0010 /* created dyn. (by redirect) */
+#define RTF_MODIFIED 0x0020 /* modified dyn. (by redirect) */
+#define RTF_MTU 0x0040 /* specific MTU for this route */
+#ifndef RTF_MSS
+#define RTF_MSS RTF_MTU /* Compatibility :-( */
+#endif
+#define RTF_WINDOW 0x0080 /* per route window clamping */
+#define RTF_IRTT 0x0100 /* Initial round trip time */
+#define RTF_REJECT 0x0200 /* Reject route */
+#endif
+
+void displayroutes(int noresolve, int netstatfmt)