info: java: update workspace
[olsrd.git] / src / linux / kernel_tunnel.c
1 /*
2  * The olsr.org Optimized Link-State Routing daemon (olsrd)
3  *
4  * (c) by the OLSR project
5  *
6  * See our Git repository to find out who worked on this file
7  * and thus is a copyright holder on it.
8  *
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  *
15  * * Redistributions of source code must retain the above copyright
16  *   notice, this list of conditions and the following disclaimer.
17  * * Redistributions in binary form must reproduce the above copyright
18  *   notice, this list of conditions and the following disclaimer in
19  *   the documentation and/or other materials provided with the
20  *   distribution.
21  * * Neither the name of olsr.org, olsrd nor the names of its
22  *   contributors may be used to endorse or promote products derived
23  *   from this software without specific prior written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
28  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
29  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
30  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
31  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
32  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
33  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
35  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  * POSSIBILITY OF SUCH DAMAGE.
37  *
38  * Visit http://www.olsr.org for more information.
39  *
40  * If you find this software useful feel free to make a donation
41  * to the project. For more information see the website or contact
42  * the copyright holders.
43  *
44  */
45
46 #ifdef __linux__
47
48 #include "kernel_tunnel.h"
49 #include "kernel_routes.h"
50 #include "log.h"
51 #include "olsr_types.h"
52 #include "net_os.h"
53 #include "olsr_cookie.h"
54 #include "ipcalc.h"
55
56 #include <assert.h>
57
58 //ipip includes
59 #include <arpa/inet.h>
60 #include <netinet/in.h>
61 #include <sys/ioctl.h>
62 #include <net/if.h>
63 #include <linux/ip.h>
64 #include <linux/if_tunnel.h>
65 #include <linux/version.h>
66
67 #if !defined LINUX_VERSION_CODE || !defined KERNEL_VERSION
68   #error "Both LINUX_VERSION_CODE and KERNEL_VERSION need to be defined"
69 #endif /* !defined LINUX_VERSION_CODE || !defined KERNEL_VERSION */
70
71 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
72   #define LINUX_IPV6_TUNNEL
73 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24) */
74
75 #ifdef LINUX_IPV6_TUNNEL
76 #include <linux/ip6_tunnel.h>
77 #endif /* LINUX_IPV6_TUNNEL */
78
79 //ifup includes
80 #include <sys/socket.h>
81 #include <sys/ioctl.h>
82 #include <sys/types.h>
83 #include <net/if.h>
84
85 static bool store_iptunnel_state;
86 static struct olsr_cookie_info *tunnel_cookie;
87 static struct avl_tree tunnel_tree;
88
89 int olsr_os_init_iptunnel(const char * dev) {
90   tunnel_cookie = olsr_alloc_cookie("iptunnel", OLSR_COOKIE_TYPE_MEMORY);
91   olsr_cookie_set_memory_size(tunnel_cookie, sizeof(struct olsr_iptunnel_entry));
92   avl_init(&tunnel_tree, avl_comp_default);
93
94   store_iptunnel_state = olsr_if_isup(dev);
95   if (store_iptunnel_state) {
96     return 0;
97   }
98   if (olsr_if_set_state(dev, true)) {
99     return -1;
100   }
101
102   return olsr_os_ifip(if_nametoindex(dev), &olsr_cnf->main_addr, true);
103 }
104
105 void olsr_os_cleanup_iptunnel(const char * dev) {
106   while (tunnel_tree.count > 0) {
107     struct olsr_iptunnel_entry *t;
108
109     /* kill tunnel */
110     t = (struct olsr_iptunnel_entry *)avl_walk_first(&tunnel_tree);
111     t->usage = 1;
112
113     olsr_os_del_ipip_tunnel(t);
114   }
115   if (olsr_cnf->smart_gw_always_remove_server_tunnel || !store_iptunnel_state) {
116     olsr_if_set_state(dev, false);
117   }
118
119   olsr_free_cookie(tunnel_cookie);
120 }
121
122 /**
123  * creates an ipip tunnel (for ipv4 or ipv6)
124  *
125  * @param name interface name
126  * @param target pointer to tunnel target IP, NULL if tunnel should be removed.
127  * Must be of type 'in_addr_t *' for ipv4 and of type 'struct in6_addr *' for
128  * ipv6
129  * @return 0 if an error happened,
130  *   if_index for successful created tunnel, 1 for successful deleted tunnel
131  */
132 int os_ip_tunnel(const char *name, void *target) {
133         struct ifreq ifr;
134         int err;
135         void * p;
136         char buffer[INET6_ADDRSTRLEN];
137         const char * tunName;
138         struct ip_tunnel_parm p4;
139 #ifdef LINUX_IPV6_TUNNEL
140         struct ip6_tnl_parm p6;
141 #endif /* LINUX_IPV6_TUNNEL */
142
143         assert (name != NULL);
144
145         memset(&ifr, 0, sizeof(ifr));
146
147         if (olsr_cnf->ip_version == AF_INET) {
148                 p = &p4;
149                 tunName = TUNNEL_ENDPOINT_IF;
150
151                 memset(&p4, 0, sizeof(p4));
152                 p4.iph.version = 4;
153                 p4.iph.ihl = 5;
154                 p4.iph.ttl = 64;
155                 p4.iph.protocol = IPPROTO_IPIP;
156                 if (target) {
157                         p4.iph.daddr = *((in_addr_t *) target);
158                 }
159                 strscpy(p4.name, name, sizeof(p4.name));
160         } else {
161 #ifdef LINUX_IPV6_TUNNEL
162                 p = (void *) &p6;
163                 tunName = TUNNEL_ENDPOINT_IF6;
164
165                 memset(&p6, 0, sizeof(p6));
166                 p6.proto = 0; /* any protocol */
167                 if (target) {
168                         p6.raddr = *((struct in6_addr *) target);
169                 }
170                 strscpy(p6.name, name, sizeof(p6.name));
171 #else /* LINUX_IPV6_TUNNEL */
172                 return 0;
173 #endif /* LINUX_IPV6_TUNNEL */
174         }
175
176         strscpy(ifr.ifr_name, target != NULL ? tunName : name, sizeof(ifr.ifr_name));
177         ifr.ifr_ifru.ifru_data = p;
178
179         if ((err = ioctl(olsr_cnf->ioctl_s, target != NULL ? SIOCADDTUNNEL : SIOCDELTUNNEL, &ifr))) {
180                 olsr_syslog(OLSR_LOG_ERR, "Cannot %s tunnel %s to %s: %s (%d)\n", target != NULL ? "add" : "remove", name,
181                                 target != NULL ? inet_ntop(olsr_cnf->ip_version, target, buffer, sizeof(buffer)) : "-", strerror(errno),
182                                 errno);
183                 return 0;
184         }
185
186         olsr_syslog(OLSR_LOG_INFO, "Tunnel %s %s, to %s", name, target != NULL ? "added" : "removed",
187                         target != NULL ? inet_ntop(olsr_cnf->ip_version, target, buffer, sizeof(buffer)) : "-");
188
189         return target != NULL ? if_nametoindex(name) : 1;
190 }
191
192 /**
193  * demands an ipip tunnel to a certain target. If no tunnel exists it will be created
194  * @param target ip address of the target
195  * @param transportV4 true if IPv4 traffic is used, false for IPv6 traffic
196  * @param name pointer to name string buffer (length IFNAMSIZ)
197  * @return NULL if an error happened, pointer to olsr_iptunnel_entry otherwise
198  */
199 struct olsr_iptunnel_entry *olsr_os_add_ipip_tunnel(union olsr_ip_addr *target, bool transportV4 __attribute__ ((unused)), char *name) {
200   struct olsr_iptunnel_entry *t;
201
202   assert(olsr_cnf->ip_version == AF_INET6 || transportV4);
203
204   t = (struct olsr_iptunnel_entry *)avl_find(&tunnel_tree, target);
205   if (t == NULL) {
206     int if_idx;
207     struct ipaddr_str buf;
208
209     if_idx = os_ip_tunnel(name, (olsr_cnf->ip_version == AF_INET) ? (void *) &target->v4.s_addr : (void *) &target->v6);
210     if (if_idx == 0) {
211       // cannot create tunnel
212       olsr_syslog(OLSR_LOG_ERR, "Cannot create tunnel %s\n", name);
213       return NULL;
214     }
215
216     if (olsr_if_set_state(name, true)) {
217       os_ip_tunnel(name, NULL);
218       return NULL;
219     }
220
221     /* set originator IP for tunnel */
222     olsr_os_ifip(if_idx, &olsr_cnf->main_addr, true);
223
224     t = olsr_cookie_malloc(tunnel_cookie);
225     memcpy(&t->target, target, sizeof(*target));
226     t->node.key = &t->target;
227
228     strscpy(t->if_name, name, sizeof(t->if_name));
229     t->if_index = if_idx;
230
231     avl_insert(&tunnel_tree, &t->node, AVL_DUP_NO);
232   }
233
234   t->usage++;
235   return t;
236 }
237
238 /**
239  * Release an olsr ipip tunnel. Tunnel will be deleted
240  * if this was the last user
241  * @param t pointer to olsr_iptunnel_entry
242  */
243 void olsr_os_del_ipip_tunnel(struct olsr_iptunnel_entry *t) {
244   if (t->usage == 0) {
245     return;
246   }
247   t->usage--;
248
249   if (t->usage > 0) {
250     return;
251   }
252
253   olsr_if_set_state(t->if_name, false);
254   os_ip_tunnel(t->if_name, NULL);
255
256   avl_delete(&tunnel_tree, &t->node);
257   olsr_cookie_free(tunnel_cookie, t);
258 }
259 #endif /* __linux__ */