89773446f50a20567640df5a8b25efe213d6be52
[olsrd.git] / src / bsd / kernel_routes.c
1
2 /*
3  * The olsr.org Optimized Link-State Routing daemon(olsrd)
4  * Copyright (c) 2004-2009, the olsr.org team - see HISTORY file
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_routes.h"
43 #include "olsr.h"
44 #include "defs.h"
45 #include "process_routes.h"
46 #include "net_olsr.h"
47 #include "ipcalc.h"
48 #include "olsr_logging.h"
49
50 #include <errno.h>
51 #include <unistd.h>
52 #include <net/if_dl.h>
53
54 #ifdef _WRS_KERNEL
55 #include <net/ifaddrs.h>
56 #include <wrn/coreip/net/route.h>
57 #include <m2Lib.h>
58 #define OLSR_PID taskIdSelf ()
59 #else
60 #include <ifaddrs.h>
61 #define OLSR_PID getpid ()
62 #endif
63
64 /**
65  *
66  * Calculate the kernel route flags.
67  * Called before enqueuing a change/delete operation
68  *
69  */
70 static uint8_t
71 olsr_rt_flags(const struct rt_entry *rt)
72 {
73   const struct rt_nexthop *nh;
74   uint8_t flags = RTF_UP;
75
76   /* destination is host */
77   if (rt->rt_dst.prefix_len == 8 * olsr_cnf->ipsize) {
78     flags |= RTF_HOST;
79   }
80
81   nh = olsr_get_nh(rt);
82
83   if (olsr_ipcmp(&rt->rt_dst.prefix, &nh->gateway) != 0) {
84     flags |= RTF_GATEWAY;
85   }
86
87   return flags;
88 }
89
90 static unsigned int seq = 0;
91
92 /*
93  * Sends an add or delete message via the routing socket.
94  * The message consists of:
95  *  - a header i.e. struct rt_msghdr
96  *  - 0-8 socket address structures
97  */
98 static int
99 add_del_route(const struct rt_entry *rt, int add)
100 {
101   struct rt_msghdr *rtm;               /* message to send to the routing socket */
102   unsigned char buff[512];
103   unsigned char *walker;               /* points within the buffer */
104   struct sockaddr_in sin4;             /* internet style sockaddr */
105   struct sockaddr_dl *sdl;             /* link level sockaddr */
106   struct ifaddrs *addrs;
107   struct ifaddrs *awalker;
108   const struct rt_nexthop *nexthop;
109   union olsr_ip_addr mask;             /* netmask as ip address */
110   int sin_size, sdl_size;              /* payload of the message */
111   int len;                             /* message size written to routing socket */
112
113   if (add) {
114     OLSR_DEBUG(LOG_ROUTING, "KERN: Adding %s\n", olsr_rtp_to_string(rt->rt_best));
115   } else {
116     OLSR_DEBUG(LOG_ROUTING, "KERN: Deleting %s\n", olsr_rt_to_string(rt));
117   }
118
119   memset(buff, 0, sizeof(buff));
120   memset(&sin4, 0, sizeof(sin4));
121
122   sin4.sin_len = sizeof(sin4);
123   sin4.sin_family = AF_INET;
124
125   sin_size = 1 + ((sizeof(struct sockaddr_in) - 1) | 3);
126   sdl_size = 1 + ((sizeof(struct sockaddr_dl) - 1) | 3);
127
128   /**********************************************************************
129    *                  FILL THE ROUTING MESSAGE HEADER
130    **********************************************************************/
131
132   /* position header to the beginning of the buffer */
133   rtm = (struct rt_msghdr *)buff;
134
135   rtm->rtm_version = RTM_VERSION;
136   rtm->rtm_type = add ? RTM_ADD : RTM_DELETE;
137   rtm->rtm_index = 0;           /* is ignored in outgoing messages */
138   rtm->rtm_flags = olsr_rt_flags(rt);
139   rtm->rtm_pid = OLSR_PID;
140   rtm->rtm_seq = ++seq;
141
142   /* walk to the end of the header */
143   walker = buff + sizeof(struct rt_msghdr);
144
145   /**********************************************************************
146    *                  SET  DESTINATION OF THE ROUTE
147    **********************************************************************/
148
149 #ifdef _WRS_KERNEL
150   /*
151    * vxWorks: change proto or tos
152    */
153   OLSR_DEBUG(LOG_ROUTING, "\t- Setting Protocol: 0\n");
154   ((struct sockaddr_rt *)(&sin4))->srt_proto = 0;
155   OLSR_DEBUG(LOG_ROUTING, "\t- Setting TOS: 0\n");
156   ((struct sockaddr_rt *)(&sin4))->srt_tos = 0;
157 #endif
158
159   sin4.sin_addr = rt->rt_dst.prefix.v4;
160   memcpy(walker, &sin4, sizeof(sin4));
161   walker += sin_size;
162   rtm->rtm_addrs = RTA_DST;
163
164   /**********************************************************************
165    *                  SET GATEWAY OF THE ROUTE
166    **********************************************************************/
167
168 #ifdef _WRS_KERNEL
169   /*
170    * vxWorks: Route with no gateway is deleted
171    */
172   if (add) {
173 #endif
174     nexthop = olsr_get_nh(rt);
175     if (0 != (rtm->rtm_flags & RTF_GATEWAY)) {
176       sin4.sin_addr = nexthop->gateway.v4;
177       memcpy(walker, &sin4, sizeof(sin4));
178       walker += sin_size;
179       rtm->rtm_addrs |= RTA_GATEWAY;
180     } else {
181       /*
182        * Host is directly reachable, so add
183        * the output interface MAC address.
184        */
185       if (getifaddrs(&addrs)) {
186         OLSR_WARN(LOG_ROUTING, "\ngetifaddrs() failed\n");
187         return -1;
188       }
189
190       for (awalker = addrs; awalker != NULL; awalker = awalker->ifa_next)
191         if (awalker->ifa_addr->sa_family == AF_LINK && strcmp(awalker->ifa_name, nexthop->interface->int_name) == 0)
192           break;
193
194       if (awalker == NULL) {
195         OLSR_WARN(LOG_ROUTING, "\nInterface %s not found\n", nexthop->interface->int_name);
196         freeifaddrs(addrs);
197         return -1;
198       }
199
200       /* sdl is "struct sockaddr_dl" */
201       sdl = (struct sockaddr_dl *)awalker->ifa_addr;
202       memcpy(walker, sdl, sdl->sdl_len);
203       walker += sdl_size;
204       rtm->rtm_addrs |= RTA_GATEWAY;
205 #ifdef RTF_CLONING
206       rtm->rtm_flags |= RTF_CLONING;
207 #endif
208 #ifndef _WRS_KERNEL
209       rtm->rtm_flags &= ~RTF_HOST;
210 #endif
211       freeifaddrs(addrs);
212     }
213 #ifdef _WRS_KERNEL
214   }
215 #endif
216
217   /**********************************************************************
218    *                         SET  NETMASK
219    **********************************************************************/
220
221   if (0 == (rtm->rtm_flags & RTF_HOST)) {
222     olsr_prefix_to_netmask(&mask, rt->rt_dst.prefix_len);
223     sin4.sin_addr = mask.v4;
224     memcpy(walker, &sin4, sizeof(sin4));
225     walker += sin_size;
226     rtm->rtm_addrs |= RTA_NETMASK;
227   }
228
229   /**********************************************************************
230    *           WRITE CONFIGURATION MESSAGE TO THE ROUTING SOCKET
231    **********************************************************************/
232
233   rtm->rtm_msglen = (unsigned short)(walker - buff);
234   len = write(olsr_cnf->rts_bsd, buff, rtm->rtm_msglen);
235   if (0 != rtm->rtm_errno || len < rtm->rtm_msglen) {
236     OLSR_WARN(LOG_ROUTING, "\nCannot write to routing socket: (rtm_errno= 0x%x) (last error message: %s)\n", rtm->rtm_errno,
237               strerror(errno));
238   }
239   return 0;
240 }
241
242 static int
243 add_del_route6(const struct rt_entry *rt, int add)
244 {
245   struct rt_msghdr *rtm;
246   unsigned char buff[512];
247   unsigned char *walker;
248   struct sockaddr_in6 sin6;
249   struct sockaddr_dl sdl;
250   const struct rt_nexthop *nexthop;
251   int sin_size, sdl_size;
252   int len;
253
254   if (add) {
255     OLSR_DEBUG(LOG_ROUTING, "KERN: Adding %s\n", olsr_rtp_to_string(rt->rt_best));
256   } else {
257     OLSR_DEBUG(LOG_ROUTING, "KERN: Deleting %s\n", olsr_rt_to_string(rt));
258   }
259
260   memset(buff, 0, sizeof(buff));
261   memset(&sin6, 0, sizeof(sin6));
262   memset(&sdl, 0, sizeof(sdl));
263
264   sin6.sin6_len = sizeof(sin6);
265   sin6.sin6_family = AF_INET6;
266   sdl.sdl_len = sizeof(sdl);
267   sdl.sdl_family = AF_LINK;
268
269   sin_size = 1 + ((sizeof(struct sockaddr_in6) - 1) | 3);
270   sdl_size = 1 + ((sizeof(struct sockaddr_dl) - 1) | 3);
271
272   /**********************************************************************
273    *                  FILL THE ROUTING MESSAGE HEADER
274    **********************************************************************/
275
276   /* position header to the beginning of the buffer */
277   rtm = (struct rt_msghdr *)buff;
278   rtm->rtm_version = RTM_VERSION;
279   rtm->rtm_type = (add != 0) ? RTM_ADD : RTM_DELETE;
280   rtm->rtm_index = 0;
281   rtm->rtm_flags = olsr_rt_flags(rt);
282   rtm->rtm_pid = OLSR_PID;
283   rtm->rtm_seq = ++seq;
284
285   /* walk to the end of the header */
286   walker = buff + sizeof(struct rt_msghdr);
287
288   /**********************************************************************
289    *                  SET  DESTINATION OF THE ROUTE
290    **********************************************************************/
291
292   memcpy(&sin6.sin6_addr.s6_addr, &rt->rt_dst.prefix.v6, sizeof(struct in6_addr));
293   memcpy(walker, &sin6, sizeof(sin6));
294   walker += sin_size;
295   rtm->rtm_addrs = RTA_DST;
296
297   /**********************************************************************
298    *                  SET GATEWAY OF THE ROUTE
299    **********************************************************************/
300
301   nexthop = olsr_get_nh(rt);
302   if (0 != (rtm->rtm_flags & RTF_GATEWAY)) {
303     memcpy(&sin6.sin6_addr.s6_addr, &nexthop->gateway.v6, sizeof(struct in6_addr));
304     memset(&sin6.sin6_addr.s6_addr, 0, 8);
305     sin6.sin6_addr.s6_addr[0] = 0xfe;
306     sin6.sin6_addr.s6_addr[1] = 0x80;
307     sin6.sin6_scope_id = nexthop->interface->if_index;
308 #ifdef __KAME__
309     *(u_int16_t *) & sin6.sin6_addr.s6_addr[2] = htons(sin6.sin6_scope_id);
310     sin6.sin6_scope_id = 0;
311 #endif
312     memcpy(walker, &sin6, sizeof(sin6));
313     walker += sin_size;
314     rtm->rtm_addrs |= RTA_GATEWAY;
315   } else {
316     /*
317      * Host is directly reachable, so add
318      * the output interface MAC address.
319      */
320     memcpy(&sin6.sin6_addr.s6_addr, &rt->rt_dst.prefix.v6, sizeof(struct in6_addr));
321     memset(&sin6.sin6_addr.s6_addr, 0, 8);
322     sin6.sin6_addr.s6_addr[0] = 0xfe;
323     sin6.sin6_addr.s6_addr[1] = 0x80;
324     sin6.sin6_scope_id = nexthop->interface->if_index;
325 #ifdef __KAME__
326     *(u_int16_t *) & sin6.sin6_addr.s6_addr[2] = htons(sin6.sin6_scope_id);
327     sin6.sin6_scope_id = 0;
328 #endif
329     memcpy(walker, &sin6, sizeof(sin6));
330     walker += sin_size;
331     rtm->rtm_addrs |= RTA_GATEWAY;
332     rtm->rtm_flags |= RTF_GATEWAY;
333   }
334
335   /**********************************************************************
336    *                         SET  NETMASK
337    **********************************************************************/
338
339   if (0 == (rtm->rtm_flags & RTF_HOST)) {
340     olsr_prefix_to_netmask((union olsr_ip_addr *)&sin6.sin6_addr, rt->rt_dst.prefix_len);
341     memcpy(walker, &sin6, sizeof(sin6));
342     walker += sin_size;
343     rtm->rtm_addrs |= RTA_NETMASK;
344   }
345
346   /**********************************************************************
347    *           WRITE CONFIGURATION MESSAGE TO THE ROUTING SOCKET
348    **********************************************************************/
349
350   rtm->rtm_msglen = (unsigned short)(walker - buff);
351   len = write(olsr_cnf->rts_bsd, buff, rtm->rtm_msglen);
352   if (len < 0 && !(errno == EEXIST || errno == ESRCH)) {
353     OLSR_WARN(LOG_ROUTING, "cannot write to routing socket: %s\n", strerror(errno));
354   }
355
356   /*
357    * If we get an EEXIST error while adding, delete and retry.
358    */
359   if (len < 0 && errno == EEXIST && rtm->rtm_type == RTM_ADD) {
360     struct rt_msghdr *drtm;
361     unsigned char dbuff[512];
362
363     memset(dbuff, 0, sizeof(dbuff));
364     drtm = (struct rt_msghdr *)dbuff;
365     drtm->rtm_version = RTM_VERSION;
366     drtm->rtm_type = RTM_DELETE;
367     drtm->rtm_index = 0;
368     drtm->rtm_flags = olsr_rt_flags(rt);
369     drtm->rtm_seq = ++seq;
370
371     walker = dbuff + sizeof(struct rt_msghdr);
372     memcpy(&sin6.sin6_addr.s6_addr, &rt->rt_dst.prefix.v6, sizeof(struct in6_addr));
373     memcpy(walker, &sin6, sizeof(sin6));
374     walker += sin_size;
375     drtm->rtm_addrs = RTA_DST;
376     drtm->rtm_msglen = (unsigned short)(walker - dbuff);
377     len = write(olsr_cnf->rts_bsd, dbuff, drtm->rtm_msglen);
378     if (len < 0) {
379       OLSR_WARN(LOG_ROUTING, "cannot delete route: %s\n", strerror(errno));
380     }
381     rtm->rtm_seq = ++seq;
382     len = write(olsr_cnf->rts_bsd, buff, rtm->rtm_msglen);
383     if (len < 0) {
384       OLSR_WARN(LOG_ROUTING, "still cannot add route: %s\n", strerror(errno));
385     }
386   }
387   return 0;
388 }
389
390 int
391 olsr_kernel_add_route(const struct rt_entry *rt, int ip_version)
392 {
393   return AF_INET == ip_version ? add_del_route(rt, 1) : add_del_route6(rt, 1);
394 }
395
396 int
397 olsr_kernel_del_route(const struct rt_entry *rt, int ip_version)
398 {
399   return AF_INET == ip_version ? add_del_route(rt, 0) : add_del_route6(rt, 0);
400 }
401
402 /*
403  * Local Variables:
404  * c-basic-offset: 2
405  * indent-tabs-mode: nil
406  * End:
407  */