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