Added kernel_tunnel.c for linux
[olsrd.git] / src / linux / kernel_tunnel.c
1 /*
2  * The olsr.org Optimized Link-State Routing daemon(olsrd)
3  * Copyright (c) 2004, Andreas Tonnesen(andreto@olsr.org)
4  * Copyright (c) 2007, Sven-Ola for the policy routing stuff
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  *   notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above copyright
14  *   notice, this list of conditions and the following disclaimer in
15  *   the documentation and/or other materials provided with the
16  *   distribution.
17  * * Neither the name of olsr.org, olsrd nor the names of its
18  *   contributors may be used to endorse or promote products derived
19  *   from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *
34  * Visit http://www.olsr.org for more information.
35  *
36  * If you find this software useful feel free to make a donation
37  * to the project. For more information see the website or contact
38  * the copyright holders.
39  *
40  */
41
42 #include "kernel_tunnel.h"
43 #include "log.h"
44 #include "olsr_types.h"
45
46 #include <assert.h>
47
48 //ipip includes
49 #include <netinet/in.h>
50 #include <sys/ioctl.h>
51 #include <net/if.h>
52 #include <linux/ip.h>
53 #include <linux/if_tunnel.h>
54 #include <linux/ip6_tunnel.h>
55
56 //ifup includes
57 #include <sys/socket.h>
58 #include <sys/ioctl.h>
59 #include <sys/types.h>
60 #include <net/if.h>
61
62 static const char DEV_IPV4_TUNNEL[IFNAMSIZ] = "tunl0";
63 static const char DEV_IPV6_TUNNEL[IFNAMSIZ] = "ip6tnl0";
64
65 static const char *get_tunnelcmd_name(uint32_t cmd) {
66   static const char ADD[] = "add";
67   static const char CHANGE[] = "change";
68   static const char DELETE[] = "delete";
69
70   switch (cmd) {
71     case SIOCADDTUNNEL:
72       return ADD;
73     case SIOCCHGTUNNEL:
74       return CHANGE;
75     case SIOCDELTUNNEL:
76       return DELETE;
77     default:
78       return NULL;
79   }
80 }
81
82 static int os_ip4_tunnel(const char *name, in_addr_t *target, uint32_t cmd)
83 {
84   struct ifreq ifr;
85   int err;
86   struct ip_tunnel_parm p;
87
88   /* no IPIP tunnel if OLSR runs with IPv6 */
89   assert (olsr_cnf->ip_version == AF_INET);
90   memset(&p, 0, sizeof(p));
91   p.iph.version = 4;
92   p.iph.ihl = 5;
93   p.iph.protocol = IPPROTO_IPIP;
94   if (target) {
95     p.iph.daddr = *target;
96   }
97   strncpy(p.name, name, IFNAMSIZ);
98
99   memset(&ifr, 0, sizeof(ifr));
100   strncpy(ifr.ifr_name, cmd == SIOCADDTUNNEL ? DEV_IPV4_TUNNEL : name, IFNAMSIZ);
101   ifr.ifr_ifru.ifru_data = (void *) &p;
102
103   if ((err = ioctl(olsr_cnf->ioctl_s, cmd, &ifr))) {
104     olsr_syslog(OLSR_LOG_ERR, "Cannot %s a tunnel %s: %s (%d)\n",
105         get_tunnelcmd_name(cmd), name, strerror(errno), errno);
106   }
107   return err;
108 }
109
110 static int os_ip6_tunnel(const char *name, struct in6_addr *target, uint32_t cmd, uint8_t proto)
111 {
112   struct ifreq ifr;
113   int err;
114   struct ip6_tnl_parm p;
115
116   /* no IPIP tunnel if OLSR runs with IPv6 */
117   assert (olsr_cnf->ip_version == AF_INET6);
118   memset(&p, 0, sizeof(p));
119   p.proto = proto; //  ? IPPROTO_IPV6 : IPPROTO_IPIP;
120   if (target) {
121     p.raddr = *target;
122   }
123   strncpy(p.name, name, IFNAMSIZ);
124
125   memset(&ifr, 0, sizeof(ifr));
126   strncpy(ifr.ifr_name, cmd == SIOCADDTUNNEL ? DEV_IPV6_TUNNEL : name, IFNAMSIZ);
127   ifr.ifr_ifru.ifru_data = (void *) &p;
128
129   if ((err = ioctl(olsr_cnf->ioctl_s, cmd, &ifr))) {
130     olsr_syslog(OLSR_LOG_ERR, "Cannot %s a tunnel %s: %s (%d)\n",
131         get_tunnelcmd_name(cmd), name, strerror(errno), errno);
132   }
133   return err;
134 }
135
136 int olsr_os_add_ipip_tunnel(const char *name, union olsr_ip_addr *target, bool transportV4) {
137   if (olsr_cnf->ip_version == AF_INET) {
138     assert(transportV4);
139
140     return os_ip4_tunnel(name, &target->v4.s_addr, SIOCADDTUNNEL);
141   }
142   return os_ip6_tunnel(name, &target->v6, SIOCADDTUNNEL, transportV4 ? IPPROTO_IPIP : IPPROTO_IPV6);
143 }
144
145 int olsr_os_change_ipip_tunnel(const char *name, union olsr_ip_addr *target, bool transportV4) {
146   if (olsr_cnf->ip_version == AF_INET) {
147     assert(transportV4);
148
149     return os_ip4_tunnel(name, &target->v4.s_addr, SIOCCHGTUNNEL);
150   }
151   return os_ip6_tunnel(name, &target->v6, SIOCCHGTUNNEL, transportV4 ? IPPROTO_IPIP : IPPROTO_IPV6);
152 }
153
154 int olsr_os_del_ipip_tunnel(const char *name, bool transportV4) {
155   if (olsr_cnf->ip_version == AF_INET) {
156     assert(transportV4);
157
158     return os_ip4_tunnel(name, NULL, SIOCDELTUNNEL);
159   }
160   return os_ip6_tunnel(name, NULL, SIOCDELTUNNEL, transportV4 ? IPPROTO_IPIP : IPPROTO_IPV6);
161 }