cf3ebecb9af219151ab8962bceb5690954019a3f
[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 #include "net_os.h"
46
47 #include <assert.h>
48
49 //ipip includes
50 #include <netinet/in.h>
51 #include <sys/ioctl.h>
52 #include <net/if.h>
53 #include <linux/ip.h>
54 #include <linux/if_tunnel.h>
55 #include <linux/ip6_tunnel.h>
56
57 //ifup includes
58 #include <sys/socket.h>
59 #include <sys/ioctl.h>
60 #include <sys/types.h>
61 #include <net/if.h>
62
63 static const char DEV_IPV4_TUNNEL[IFNAMSIZ] = "tunl0";
64 static const char DEV_IPV6_TUNNEL[IFNAMSIZ] = "ip6tnl0";
65
66 static bool store_iptunnel_state;
67
68 int olsr_os_init_iptunnel(void) {
69   const char *dev = olsr_cnf->ip_version == AF_INET ? DEV_IPV4_TUNNEL : DEV_IPV6_TUNNEL;
70
71   store_iptunnel_state = olsr_if_isup(dev);
72   if (store_iptunnel_state) {
73     return 0;
74   }
75   return olsr_if_set_state(dev, true);
76 }
77
78 void olsr_os_cleanup_iptunnel(void) {
79   if (!store_iptunnel_state) {
80     olsr_if_set_state(olsr_cnf->ip_version == AF_INET ? DEV_IPV4_TUNNEL : DEV_IPV6_TUNNEL, false);
81   }
82 }
83
84 static const char *get_tunnelcmd_name(uint32_t cmd) {
85   static const char ADD[] = "add";
86   static const char CHANGE[] = "change";
87   static const char DELETE[] = "delete";
88
89   switch (cmd) {
90     case SIOCADDTUNNEL:
91       return ADD;
92     case SIOCCHGTUNNEL:
93       return CHANGE;
94     case SIOCDELTUNNEL:
95       return DELETE;
96     default:
97       return NULL;
98   }
99 }
100
101 static int os_ip4_tunnel(const char *name, in_addr_t *target, uint32_t cmd)
102 {
103   struct ifreq ifr;
104   int err;
105   struct ip_tunnel_parm p;
106
107   /* only IPIP tunnel if OLSR runs with IPv6 */
108   assert (olsr_cnf->ip_version == AF_INET);
109   memset(&p, 0, sizeof(p));
110   p.iph.version = 4;
111   p.iph.ihl = 5;
112   p.iph.protocol = IPPROTO_IPIP;
113   if (target) {
114     p.iph.daddr = *target;
115   }
116   strncpy(p.name, name, IFNAMSIZ);
117
118   memset(&ifr, 0, sizeof(ifr));
119   strncpy(ifr.ifr_name, cmd == SIOCADDTUNNEL ? DEV_IPV4_TUNNEL : name, IFNAMSIZ);
120   ifr.ifr_ifru.ifru_data = (void *) &p;
121
122   if ((err = ioctl(olsr_cnf->ioctl_s, cmd, &ifr))) {
123     olsr_syslog(OLSR_LOG_ERR, "Cannot %s a tunnel %s: %s (%d)\n",
124         get_tunnelcmd_name(cmd), name, strerror(errno), errno);
125   }
126   return err;
127 }
128
129 static int os_ip6_tunnel(const char *name, struct in6_addr *target, uint32_t cmd, uint8_t proto)
130 {
131   struct ifreq ifr;
132   int err;
133   struct ip6_tnl_parm p;
134
135   /* only IP6 tunnel if OLSR runs with IPv6 */
136   assert (olsr_cnf->ip_version == AF_INET6);
137   memset(&p, 0, sizeof(p));
138   p.proto = proto;
139   if (target) {
140     p.raddr = *target;
141   }
142   strncpy(p.name, name, IFNAMSIZ);
143
144   memset(&ifr, 0, sizeof(ifr));
145   strncpy(ifr.ifr_name, cmd == SIOCADDTUNNEL ? DEV_IPV6_TUNNEL : name, IFNAMSIZ);
146   ifr.ifr_ifru.ifru_data = (void *) &p;
147
148   if ((err = ioctl(olsr_cnf->ioctl_s, cmd, &ifr))) {
149     olsr_syslog(OLSR_LOG_ERR, "Cannot %s a tunnel %s: %s (%d)\n",
150         get_tunnelcmd_name(cmd), name, strerror(errno), errno);
151   }
152   return err;
153 }
154
155 int olsr_os_add_ipip_tunnel(const char *name, union olsr_ip_addr *target, bool transportV4) {
156   if (olsr_cnf->ip_version == AF_INET) {
157     assert(transportV4);
158
159     return os_ip4_tunnel(name, &target->v4.s_addr, SIOCADDTUNNEL);
160   }
161   return os_ip6_tunnel(name, &target->v6, SIOCADDTUNNEL, transportV4 ? IPPROTO_IPIP : IPPROTO_IPV6);
162 }
163
164 int olsr_os_change_ipip_tunnel(const char *name, union olsr_ip_addr *target, bool transportV4) {
165   if (olsr_cnf->ip_version == AF_INET) {
166     assert(transportV4);
167
168     return os_ip4_tunnel(name, &target->v4.s_addr, SIOCCHGTUNNEL);
169   }
170   return os_ip6_tunnel(name, &target->v6, SIOCCHGTUNNEL, transportV4 ? IPPROTO_IPIP : IPPROTO_IPV6);
171 }
172
173 int olsr_os_del_ipip_tunnel(const char *name, bool transportV4) {
174   if (olsr_cnf->ip_version == AF_INET) {
175     assert(transportV4);
176
177     return os_ip4_tunnel(name, NULL, SIOCDELTUNNEL);
178   }
179   return os_ip6_tunnel(name, NULL, SIOCDELTUNNEL, transportV4 ? IPPROTO_IPIP : IPPROTO_IPV6);
180 }