]> git.proxmox.com Git - mirror_iproute2.git/commitdiff
TUNNEL: Import ip6tunnel.c.
authorMasahide NAKAMURA <nakam@linux-ipv6.org>
Fri, 24 Nov 2006 03:27:06 +0000 (12:27 +0900)
committerStephen Hemminger <shemminger@osdl.org>
Mon, 27 Nov 2006 16:41:23 +0000 (08:41 -0800)
This file (ip6tunnel.c) is renamed from ipv6tunnel.c which is imported
from usagi cvs tree. It is originally ported by MIPL to work on their
2.4 kernel patch (MIPL1).

Signed-off-by: Masahide NAKAMURA <nakam@linux-ipv6.org>
Signed-off-by: Stephen Hemminger <shemminger@osdl.org>
ip/ip6tunnel.c [new file with mode: 0644]

diff --git a/ip/ip6tunnel.c b/ip/ip6tunnel.c
new file mode 100644 (file)
index 0000000..c8578e5
--- /dev/null
@@ -0,0 +1,402 @@
+/*
+ * Copyright (C)2006 USAGI/WIDE Project
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+/*
+ * based on:
+ * $Id: s.ipv6tunnel.c 1.7 02/12/11 11:21:51+02:00 antti@traci.mipl.mediapoli.com $
+ *
+ */
+/*
+ * Author:
+ *     Masahide NAKAMURA @USAGI
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <unistd.h>
+#include <arpa/inet.h>
+
+#include <asm/types.h>
+#include <linux/sockios.h>
+#include <linux/ip.h>
+#include <linux/if_tunnel.h>
+
+#include "ipv6_tunnel.h"
+
+
+int tunnel_local_packets = 0;
+
+static void usage(void)
+{
+       fprintf(stderr, "Usage: ipv6tunnel { add | change | del | show } [ NAME ]\n");
+       fprintf(stderr, "          [ --allow-local-packets ]\n");
+       fprintf(stderr, "          [ --use-original-traffic-class ]\n");
+       fprintf(stderr, "          [ remote ADDR local ADDR ]\n");
+       fprintf(stderr, "          [ dev PHYS_DEV ]\n");
+       fprintf(stderr, "          [ encaplimit TEL ]\n");
+       fprintf(stderr, "          [ hoplimit HOPLIMIT ]\n"); 
+       fprintf(stderr, "          [ flowlabel FL ]\n");
+       fprintf(stderr, "Where: NAME := STRING\n");
+       fprintf(stderr, "       ADDR := IPV6_ADDRESS\n");
+       fprintf(stderr, "       HOPLIMIT := 0..255\n");
+       fprintf(stderr, "       TEL := { none | 0..255 }\n");
+       fprintf(stderr, "       FL := 0x0..0xfffff\n");
+       fprintf(stderr, "       PHYS_DEV := STRING\n");
+       exit(-1);
+}
+
+static int do_ioctl_get_ifindex(char *dev)
+{
+       struct ifreq ifr;
+       int fd;
+       int err;
+
+//     fprintf(stderr, "do_ioctl_get_ifindex\n");
+
+       strcpy(ifr.ifr_name, dev);
+       fd = socket(AF_INET6, SOCK_DGRAM, 0);
+       err = ioctl(fd, SIOCGIFINDEX, &ifr);
+       if (err) {
+               perror("ioctl");
+               return 0;
+       }
+       close(fd);
+       return ifr.ifr_ifindex;
+}
+
+static char *do_ioctl_get_ifname(int idx)
+{
+       static struct ifreq ifr;
+       int fd;
+       int err;
+
+//     fprintf(stderr, "do_ioctl_get_ifname\n");
+
+       ifr.ifr_ifindex = idx;
+       fd = socket(AF_INET6, SOCK_DGRAM, 0);
+       err = ioctl(fd, SIOCGIFNAME, &ifr);
+       if (err) {
+               perror("ioctl");
+               return NULL;
+       }
+       close(fd);
+       return ifr.ifr_name;
+}
+
+static int do_get_ioctl(char *basedev, struct ipv6_tnl_parm *p)
+{
+       struct ifreq ifr;
+       int fd;
+       int err;
+
+//     fprintf(stderr, "do_get_ioctl\n");
+
+       strcpy(ifr.ifr_name, basedev);
+       ifr.ifr_ifru.ifru_data = (void *)p;
+       fd = socket(AF_INET6, SOCK_DGRAM, 0);
+       err = ioctl(fd, SIOCGETTUNNEL, &ifr);
+       if (err)
+               perror("ioctl");
+       close(fd);
+       return err;
+}
+
+static int do_add_ioctl(int cmd, char *basedev, struct ipv6_tnl_parm *p)
+{
+       struct ifreq ifr;
+       int fd;
+       int err;
+
+//     fprintf(stderr, "do_add_ioctl\n");
+
+       strcpy(ifr.ifr_name, basedev);
+       ifr.ifr_ifru.ifru_data = (void *)p;
+       fd = socket(AF_INET6, SOCK_DGRAM, 0);
+       err = ioctl(fd, cmd, &ifr);
+       if (err)
+               perror("ioctl");
+       close(fd);
+       return err;
+}
+
+
+static int do_del_ioctl(char *basedev, struct ipv6_tnl_parm *p)
+{
+       struct ifreq ifr;
+       int fd;
+       int err;
+
+//     fprintf(stderr, "do_del_ioctl\n");
+
+       strcpy(ifr.ifr_name, basedev);
+       ifr.ifr_ifru.ifru_data = (void *)p;
+       fd = socket(AF_INET6, SOCK_DGRAM, 0);
+       err = ioctl(fd, SIOCDELTUNNEL, &ifr);
+       if (err)
+               perror("ioctl");
+       close(fd);
+       return err;
+}
+
+void print_tunnel(struct ipv6_tnl_parm *p)
+{
+       char remote[64];
+       char local[64];
+       
+       inet_ntop(AF_INET6, &p->raddr, remote, sizeof(remote));
+       inet_ntop(AF_INET6, &p->laddr, local, sizeof(local));
+
+       printf("%s: %s/IPv6 remote %s local %s",
+              p->name,
+              (p->proto == IPPROTO_IPV6 ? "IPv6" : "unknown"),
+              remote, local);
+       if (p->link) {
+               char *n = do_ioctl_get_ifname(p->link);
+               if (n)
+                       printf(" dev %s", n);
+       }
+       if (p->encap_limit)
+               printf(" encaplimit %d", p->encap_limit);
+
+       printf(" hoplimit %d", p->hop_limit);
+
+       if (p->flow_lbl)
+               printf(" flowlabel 0x%x", p->flow_lbl);
+
+       if (p->flags) {
+               char flags[33];
+               char *fp = flags;
+               memset(flags, 0, 33);
+               if (p->flags & IPV6_TNL_F_IGN_ENCAP_LIMIT) {
+                       *fp = 'E';
+                       fp++;
+               }
+               if (p->flags & IPV6_TNL_F_USE_ORIG_TCLASS) {
+                       *fp = 'T';
+                       fp++;
+               }
+               if (p->flags & IPV6_TNL_F_ALLOW_LOCAL) {
+                       *fp = 'L';
+                       fp++;
+               }
+               if (p->flags & IPV6_TNL_F_KERNEL_DEV) {
+                       *fp = 'K';
+                       fp++;
+               }
+               if (p->flags & IPV6_TNL_F_MIPV6_DEV) {
+                       *fp = 'M';
+                       fp++;
+               }
+               if (p->flags & IPV6_TNL_F_RCV_ONLY) {
+                       *fp = 'R';
+                       fp++;
+               }
+               printf(" flags %s", flags);
+       }
+       printf("\n");
+}
+
+void resolve_name(char *name, struct in6_addr *ip6)
+{ 
+       struct addrinfo ai, *res; 
+       int err; 
+       memset(&ai, 0, sizeof(struct addrinfo)); 
+       ai.ai_family = AF_INET6; 
+       ai.ai_protocol = IPPROTO_IPV6; 
+       ai.ai_flags = AI_NUMERICHOST;
+       err = getaddrinfo(name, NULL, &ai, &res);
+       if (err)
+               exit(-1);
+
+       *ip6 = ((struct sockaddr_in6 *) (res->ai_addr))->sin6_addr;
+       freeaddrinfo(res); 
+} 
+
+int get_u8(__u8 *val, char *arg)
+{
+       unsigned long res = 0;
+       char *ptr;
+
+       if (!arg || !*arg)
+               return -1;
+       res = strtoul(arg, &ptr, 0);
+       if (!ptr || ptr == arg || *ptr || res > 0xFF)
+               return -1;
+       *val = (__u8) res;
+       return 0;
+}
+
+int get_u20(__u32 *val, char *arg)
+{
+       unsigned long res = 0;
+       char *ptr;
+
+       if (!arg || !*arg)
+               return -1;
+       res = strtoul(arg, &ptr, 0);
+       if (!ptr || ptr == arg || *ptr || res > 0xFFFFF)
+               return -1;
+       *val = res;
+       return 0;
+}
+
+static int parse_args(int argc, char **argv, struct ipv6_tnl_parm *p)
+{
+       char medium[IFNAMSIZ];
+
+//     fprintf(stderr, "parse_args\n");
+
+       memset(p, 0, sizeof(*p));
+       p->hop_limit = -1;
+       p->encap_limit = IPV6_DEFAULT_TNL_ENCAP_LIMIT;
+       p->proto = IPPROTO_IPV6;
+       memset(&medium, 0, sizeof(medium));
+
+       while (argc > 0) {
+               if (!strcmp(*argv, "--help") || !strcmp(*argv, "-h")) {
+                       usage();
+               } else if (!strcmp(*argv, "--allow-local-packets")) {
+                       p->flags |= IPV6_TNL_F_ALLOW_LOCAL;
+               } else if (!strcmp(*argv, "--use-original-traffic-class")) {
+                       p->flags |= IPV6_TNL_F_USE_ORIG_TCLASS;
+               } else if (!strcmp(*argv, "remote")) {
+                       argv++; 
+                       if (--argc <= 0) 
+                               usage();
+                       resolve_name(*argv, &p->raddr);
+               } else if (!strcmp(*argv, "local")) {
+                       argv++; 
+                       if (--argc <= 0) 
+                               usage();
+                       resolve_name(*argv, &p->laddr);
+               } else if (!strcmp(*argv, "dev")) {
+                       argv++; 
+                       if (--argc <= 0) 
+                               usage();
+                       strncpy(medium, *argv, IFNAMSIZ - 1);
+               } else if (!strcmp(*argv, "hoplimit")) {
+                       __u8 uval;
+                       argv++; 
+                       if (--argc <= 0) 
+                               usage();
+                       if (get_u8(&uval, *argv) < -1)
+                               usage();
+                       p->hop_limit = uval;
+               } else if (!strcmp(*argv, "flowlabel")) {
+                       __u32 uval;
+                       argv++; 
+                       if (--argc <= 0) 
+                               usage();
+                       if (get_u20(&uval, *argv) < -1)
+                               usage();
+                       p->flow_lbl = uval;
+               } else if (!strcmp(*argv, "encaplimit")) {
+                       argv++; 
+                       if (--argc <= 0) 
+                               usage();
+                       if (!strcmp(*argv, "none")) {
+                               p->flags |= IPV6_TNL_F_IGN_ENCAP_LIMIT;
+                       } else {
+                               __u8 uval;
+                               if (get_u8(&uval, *argv) < -1)
+                                       usage();
+                               p->encap_limit = uval;
+                       }
+               } else {
+                       if (p->name[0])
+                               usage();
+                       strncpy(p->name, *argv, IFNAMSIZ - 1);
+               }
+               argc--; argv++;
+       }
+       if (medium[0]) {
+               p->link = do_ioctl_get_ifindex(medium);
+               if (p->link == 0)
+                       return -1;
+       }
+       return 0;
+}
+
+static int do_show(int argc, char **argv)
+{
+        struct ipv6_tnl_parm p;
+
+        if (parse_args(argc, argv, &p) < 0)
+                return -1;
+
+       if (do_get_ioctl(p.name[0] ? p.name : "ip6tnl0", &p))
+                return -1;
+
+        print_tunnel(&p);
+        return 0;
+}
+
+
+
+
+static int do_add(int cmd, int argc, char **argv)
+{
+       struct ipv6_tnl_parm p;
+
+       if (parse_args(argc, argv, &p) < 0)
+               return -1;
+       
+       return do_add_ioctl(cmd, 
+                           cmd == SIOCCHGTUNNEL && p.name[0] ?
+                           p.name : "ip6tnl0", &p);
+}
+
+int do_del(int argc, char **argv)
+{
+       struct ipv6_tnl_parm p;
+
+       if (parse_args(argc, argv, &p) < 0)
+               return -1;
+
+       return do_del_ioctl(p.name[0] ? p.name : "ip6tnl0", &p);
+}
+
+
+int main(int argc, char **argv) 
+{ 
+       argc--;
+       argv++;
+       if (argc > 0) {
+               if (strcmp(*argv, "add") == 0)
+                       return do_add(SIOCADDTUNNEL, argc - 1, argv + 1);
+               else if (strcmp(*argv, "change") == 0)
+                       return do_add(SIOCCHGTUNNEL, argc - 1, argv + 1);
+               else if (strcmp(*argv, "del") == 0)
+                       return do_del(argc - 1, argv + 1);
+               else if (strcmp(*argv, "show") == 0)
+                       return do_show(argc - 1, argv + 1);
+               else
+                       usage();
+
+       } else
+               return do_show(0, NULL);
+
+       return 0;
+}