* applied rt-refactoring-6.diff from Hannes Gredler <hannes@gredler.at>
[olsrd.git] / src / linux / kernel_routes.c
1 /*
2  * The olsr.org Optimized Link-State Routing daemon(olsrd)
3  * Copyright (c) 2004, Andreas T√łnnesen(andreto@olsr.org)
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without 
7  * modification, are permitted provided that the following conditions 
8  * are met:
9  *
10  * * Redistributions of source code must retain the above copyright 
11  *   notice, this list of conditions and the following disclaimer.
12  * * Redistributions in binary form must reproduce the above copyright 
13  *   notice, this list of conditions and the following disclaimer in 
14  *   the documentation and/or other materials provided with the 
15  *   distribution.
16  * * Neither the name of olsr.org, olsrd nor the names of its 
17  *   contributors may be used to endorse or promote products derived 
18  *   from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
23  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
24  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
26  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
27  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
28  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
30  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
31  * POSSIBILITY OF SUCH DAMAGE.
32  *
33  * Visit http://www.olsr.org for more information.
34  *
35  * If you find this software useful feel free to make a donation
36  * to the project. For more information see the website or contact
37  * the copyright holders.
38  *
39  * $Id: kernel_routes.c,v 1.24 2007/09/05 16:11:11 bernd67 Exp $
40  */
41
42
43
44 #include "kernel_routes.h"
45 #include "link_set.h"
46 #include "olsr.h"
47 #include "log.h"
48 #include <net/if.h>
49 #include <sys/ioctl.h>
50 #include <unistd.h>
51
52
53 /**
54  * Insert a route in the kernel routing table
55  *
56  * @param destination the route to add
57  *
58  * @return negative on error
59  */
60 int
61 olsr_ioctl_add_route(struct rt_entry *rt)
62 {
63   struct rtentry kernel_route;
64   union olsr_ip_addr mask;
65   int rslt;
66
67   OLSR_PRINTF(2, "KERN: Adding %s\n", olsr_rtp_to_string(rt->rt_best));
68
69   memset(&kernel_route, 0, sizeof(struct rtentry));
70
71   ((struct sockaddr_in*)&kernel_route.rt_dst)->sin_family = AF_INET;
72   ((struct sockaddr_in*)&kernel_route.rt_gateway)->sin_family = AF_INET;
73   ((struct sockaddr_in*)&kernel_route.rt_genmask)->sin_family = AF_INET;
74
75   ((struct sockaddr_in *)&kernel_route.rt_dst)->sin_addr.s_addr =
76     rt->rt_dst.prefix.v4;
77
78   if (!olsr_prefix_to_netmask(&mask, rt->rt_dst.prefix_len)) {
79     return -1;
80   }
81   ((struct sockaddr_in *)&kernel_route.rt_genmask)->sin_addr.s_addr = mask.v4;
82
83   if (rt->rt_dst.prefix.v4 != rt->rt_best->rtp_nexthop.gateway.v4) {
84     ((struct sockaddr_in *)&kernel_route.rt_gateway)->sin_addr.s_addr =
85       rt->rt_best->rtp_nexthop.gateway.v4;
86   }
87
88   kernel_route.rt_flags = olsr_rt_flags(rt);
89   kernel_route.rt_metric = RT_METRIC_DEFAULT;
90
91   /*
92    * Set interface
93    */
94   kernel_route.rt_dev = rt->rt_best->rtp_nexthop.iface->int_name;
95
96   /* delete existing default route before ? */
97   if((olsr_cnf->del_gws) &&
98      (rt->rt_dst.prefix.v4 == INADDR_ANY) &&
99      (rt->rt_dst.prefix_len == INADDR_ANY)) {
100     delete_all_inet_gws();
101     olsr_cnf->del_gws = OLSR_FALSE;
102   }
103
104   if ((rslt = ioctl(olsr_cnf->ioctl_s, SIOCADDRT, &kernel_route)) >= 0) {
105
106     /*
107      * Send IPC route update message
108      */
109     ipc_route_send_rtentry(&rt->rt_dst.prefix, &rt->rt_best->rtp_nexthop.gateway,
110                            rt->rt_best->rtp_metric.hops, 1,
111                            rt->rt_best->rtp_nexthop.iface->int_name);
112   }
113
114   return rslt;
115 }
116
117
118 /**
119  *Insert a route in the kernel routing table
120  *
121  *@param destination the route to add
122  *
123  *@return negative on error
124  */
125 int
126 olsr_ioctl_add_route6(struct rt_entry *rt)
127 {
128
129   struct in6_rtmsg kernel_route;
130   int rslt;
131
132   OLSR_PRINTF(2, "KERN: Adding %s\n", olsr_rtp_to_string(rt->rt_best));
133
134   memset(&kernel_route, 0, sizeof(struct in6_rtmsg));
135
136   COPY_IP(&kernel_route.rtmsg_dst, &rt->rt_dst.prefix);
137   kernel_route.rtmsg_dst_len = rt->rt_dst.prefix_len;
138
139   COPY_IP(&kernel_route.rtmsg_gateway, &rt->rt_best->rtp_nexthop.gateway);
140
141   kernel_route.rtmsg_flags = olsr_rt_flags(rt);
142   kernel_route.rtmsg_metric = RT_METRIC_DEFAULT;
143   
144   /*
145    * set interface
146    */
147   kernel_route.rtmsg_ifindex = rt->rt_best->rtp_nexthop.iface->if_index;
148   
149   /* XXX delete 0/0 route before ? */
150
151   if((rslt = ioctl(olsr_cnf->ioctl_s, SIOCADDRT, &kernel_route)) >= 0) {
152
153     /*
154      * Send IPC route update message
155      */
156     ipc_route_send_rtentry(&rt->rt_dst.prefix, &rt->rt_best->rtp_nexthop.gateway, 
157                            rt->rt_best->rtp_metric.hops, 1,
158                            rt->rt_best->rtp_nexthop.iface->int_name);
159   }
160
161   return rslt;
162 }
163
164
165 /**
166  *Remove a route from the kernel
167  *
168  *@param destination the route to remove
169  *
170  *@return negative on error
171  */
172 int
173 olsr_ioctl_del_route(struct rt_entry *rt)
174 {
175   struct rtentry kernel_route;
176   union olsr_ip_addr mask;
177   int rslt;
178
179   OLSR_PRINTF(2, "KERN: Deleting %s\n", olsr_rt_to_string(rt));
180
181   memset(&kernel_route,0,sizeof(struct rtentry));
182
183   ((struct sockaddr_in*)&kernel_route.rt_dst)->sin_family = AF_INET;
184   ((struct sockaddr_in*)&kernel_route.rt_gateway)->sin_family = AF_INET;
185   ((struct sockaddr_in*)&kernel_route.rt_genmask)->sin_family = AF_INET;
186
187   ((struct sockaddr_in *)&kernel_route.rt_dst)->sin_addr.s_addr =
188     rt->rt_dst.prefix.v4;
189
190   if (rt->rt_dst.prefix.v4 != rt->rt_nexthop.gateway.v4) {
191     ((struct sockaddr_in *)&kernel_route.rt_gateway)->sin_addr.s_addr =
192       rt->rt_nexthop.gateway.v4;
193   }
194
195   if (!olsr_prefix_to_netmask(&mask, rt->rt_dst.prefix_len)) {
196     return -1;
197   } else {
198     ((struct sockaddr_in *)&kernel_route.rt_genmask)->sin_addr.s_addr = mask.v4;
199   }
200
201   kernel_route.rt_flags = olsr_rt_flags(rt);
202   kernel_route.rt_metric = RT_METRIC_DEFAULT;
203
204   /*
205    * Set interface
206    */
207   kernel_route.rt_dev = NULL;
208
209   if ((rslt = ioctl(olsr_cnf->ioctl_s, SIOCDELRT, &kernel_route)) >= 0) {
210
211     /*
212      * Send IPC route update message
213      */
214     ipc_route_send_rtentry(&rt->rt_dst.prefix, NULL, 0, 0, NULL);
215   }
216
217   return rslt;
218 }
219
220
221 /**
222  *Remove a route from the kernel
223  *
224  *@param destination the route to remove
225  *
226  *@return negative on error
227  */
228 int
229 olsr_ioctl_del_route6(struct rt_entry *rt)
230 {
231
232   struct in6_rtmsg kernel_route;
233   int rslt;
234
235   OLSR_PRINTF(2, "KERN: Deleting %s\n", olsr_rt_to_string(rt));
236
237   memset(&kernel_route,0,sizeof(struct in6_rtmsg));
238
239
240   COPY_IP(&kernel_route.rtmsg_dst, &rt->rt_dst.prefix);
241   kernel_route.rtmsg_dst_len = rt->rt_dst.prefix_len;
242
243   COPY_IP(&kernel_route.rtmsg_gateway, &rt->rt_best->rtp_nexthop.gateway);
244
245   kernel_route.rtmsg_flags = olsr_rt_flags(rt);
246   kernel_route.rtmsg_metric = RT_METRIC_DEFAULT;
247
248   if ((rslt = ioctl(olsr_cnf->ioctl_s, SIOCDELRT, &kernel_route) >= 0)) {
249
250     /*
251      * Send IPC route update message
252      */
253     ipc_route_send_rtentry(&rt->rt_dst.prefix, NULL, 0, 0, NULL);
254   }
255
256   return rslt;
257 }
258
259
260
261 int
262 delete_all_inet_gws(void)
263 {  
264   int s;
265   char buf[BUFSIZ], *cp, *cplim;
266   struct ifconf ifc;
267   struct ifreq *ifr;
268   
269   OLSR_PRINTF(1, "Internet gateway detected...\nTrying to delete default gateways\n");
270   
271   /* Get a socket */
272   if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) 
273     {
274       olsr_syslog(OLSR_LOG_ERR, "socket: %m");
275       close(s);
276       return -1;
277     }
278   
279   ifc.ifc_len = sizeof (buf);
280   ifc.ifc_buf = buf;
281   if (ioctl(s, SIOCGIFCONF, (char *)&ifc) < 0) 
282     {
283       olsr_syslog(OLSR_LOG_ERR, "ioctl (get interface configuration)");
284       close(s);
285       return -1;
286     }
287
288   ifr = ifc.ifc_req;
289   cplim = buf + ifc.ifc_len; /*skip over if's with big ifr_addr's */
290   for (cp = buf; cp < cplim; cp += sizeof (ifr->ifr_name) + sizeof(ifr->ifr_addr)) 
291     {
292       struct rtentry kernel_route;
293       ifr = (struct ifreq *)cp;
294       
295       
296       if(strcmp(ifr->ifr_ifrn.ifrn_name, "lo") == 0)
297         {
298           OLSR_PRINTF(1, "Skipping loopback...\n");
299           continue;
300         }
301
302       OLSR_PRINTF(1, "Trying 0.0.0.0/0 %s...", ifr->ifr_ifrn.ifrn_name);
303       
304       
305       memset(&kernel_route,0,sizeof(struct rtentry));
306       
307       ((struct sockaddr_in *)&kernel_route.rt_dst)->sin_addr.s_addr = 0;
308       ((struct sockaddr_in *)&kernel_route.rt_dst)->sin_family=AF_INET;
309       ((struct sockaddr_in *)&kernel_route.rt_genmask)->sin_addr.s_addr = 0;
310       ((struct sockaddr_in *)&kernel_route.rt_genmask)->sin_family=AF_INET;
311
312       ((struct sockaddr_in *)&kernel_route.rt_gateway)->sin_addr.s_addr = INADDR_ANY;
313       ((struct sockaddr_in *)&kernel_route.rt_gateway)->sin_family=AF_INET;
314       
315
316       kernel_route.rt_flags = RTF_UP | RTF_GATEWAY;
317            
318       kernel_route.rt_dev = ifr->ifr_ifrn.ifrn_name;
319
320       if((ioctl(s, SIOCDELRT, &kernel_route)) < 0)
321          OLSR_PRINTF(1, "NO\n");
322       else
323          OLSR_PRINTF(1, "YES\n");
324     }  
325   close(s);
326   return 0;
327        
328 }
329
330 /*
331  * Local Variables:
332  * c-basic-offset: 2
333  * End:
334  */