fbsd: bugfix for non-vxworks host routes
[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) | 3);
99   sdl_size = 1 + ((sizeof(struct sockaddr_dl) - 1) | 3);
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       rtm->rtm_flags |= RTF_CLONING;
180 #ifndef _WRS_KERNEL
181       rtm->rtm_flags &= ~RTF_HOST;
182 #endif
183       freeifaddrs(addrs);
184     }
185 #ifdef _WRS_KERNEL
186   }
187 #endif
188
189   /**********************************************************************
190    *                         SET  NETMASK
191    **********************************************************************/
192
193   if (0 == (rtm->rtm_flags & RTF_HOST)) {
194     olsr_prefix_to_netmask(&mask, rt->rt_dst.prefix_len);
195     sin4.sin_addr = mask.v4;
196     memcpy(walker, &sin4, sizeof(sin4));
197     walker += sin_size;
198     rtm->rtm_addrs |= RTA_NETMASK;
199   }
200
201   /**********************************************************************
202    *           WRITE CONFIGURATION MESSAGE TO THE ROUTING SOCKET
203    **********************************************************************/
204
205   rtm->rtm_msglen = (unsigned short)(walker - buff);
206   len = write(olsr_cnf->rts, buff, rtm->rtm_msglen);
207   if (0 != rtm->rtm_errno || len < rtm->rtm_msglen) {
208     fprintf(stderr, "\nCannot write to routing socket: (rtm_errno= 0x%x) (last error message: %s)\n", rtm->rtm_errno,
209             strerror(errno));
210   }
211   return 0;
212 }
213
214 int
215 olsr_ioctl_add_route(const struct rt_entry *rt)
216 {
217   return add_del_route(rt, 1);
218 }
219
220 int
221 olsr_ioctl_del_route(const struct rt_entry *rt)
222 {
223   return add_del_route(rt, 0);
224 }
225
226 static int
227 add_del_route6(const struct rt_entry *rt, int add)
228 {
229   struct rt_msghdr *rtm;
230   unsigned char buff[512];
231   unsigned char *walker;
232   struct sockaddr_in6 sin6;
233   struct sockaddr_dl sdl;
234   const struct rt_nexthop *nexthop;
235   int sin_size, sdl_size;
236   int len;
237
238   if (add) {
239     OLSR_PRINTF(2, "KERN: Adding %s\n", olsr_rtp_to_string(rt->rt_best));
240   } else {
241     OLSR_PRINTF(2, "KERN: Deleting %s\n", olsr_rt_to_string(rt));
242   }
243
244   memset(buff, 0, sizeof(buff));
245   memset(&sin6, 0, sizeof(sin6));
246   memset(&sdl, 0, sizeof(sdl));
247
248   sin6.sin6_len = sizeof(sin6);
249   sin6.sin6_family = AF_INET6;
250   sdl.sdl_len = sizeof(sdl);
251   sdl.sdl_family = AF_LINK;
252
253   sin_size = 1 + ((sizeof(struct sockaddr_in6) - 1) | 3);
254   sdl_size = 1 + ((sizeof(struct sockaddr_dl) - 1) | 3);
255
256   /**********************************************************************
257    *                  FILL THE ROUTING MESSAGE HEADER
258    **********************************************************************/
259
260   /* position header to the beginning of the buffer */
261   rtm = (struct rt_msghdr *)buff;
262   rtm->rtm_version = RTM_VERSION;
263   rtm->rtm_type = (add != 0) ? RTM_ADD : RTM_DELETE;
264   rtm->rtm_index = 0;
265   rtm->rtm_flags = olsr_rt_flags(rt);
266   rtm->rtm_pid = OLSR_PID;
267   rtm->rtm_seq = ++seq;
268
269   /* walk to the end of the header */
270   walker = buff + sizeof(struct rt_msghdr);
271
272   /**********************************************************************
273    *                  SET  DESTINATION OF THE ROUTE
274    **********************************************************************/
275
276   memcpy(&sin6.sin6_addr.s6_addr, &rt->rt_dst.prefix.v6, sizeof(struct in6_addr));
277   memcpy(walker, &sin6, sizeof(sin6));
278   walker += sin_size;
279   rtm->rtm_addrs = RTA_DST;
280
281   /**********************************************************************
282    *                  SET GATEWAY OF THE ROUTE
283    **********************************************************************/
284
285   nexthop = olsr_get_nh(rt);
286   if (0 != (rtm->rtm_flags & RTF_GATEWAY)) {
287     memcpy(&sin6.sin6_addr.s6_addr, &nexthop->gateway.v6, sizeof(struct in6_addr));
288     memset(&sin6.sin6_addr.s6_addr, 0, 8);
289     sin6.sin6_addr.s6_addr[0] = 0xfe;
290     sin6.sin6_addr.s6_addr[1] = 0x80;
291     sin6.sin6_scope_id = nexthop->iif_index;
292 #ifdef __KAME__
293     *(u_int16_t *) & sin6.sin6_addr.s6_addr[2] = htons(sin6.sin6_scope_id);
294     sin6.sin6_scope_id = 0;
295 #endif
296     memcpy(walker, &sin6, sizeof(sin6));
297     walker += sin_size;
298     rtm->rtm_addrs = RTA_GATEWAY;
299   }
300   else {
301     /*
302      * Host is directly reachable, so add
303      * the output interface MAC address.
304      */
305     memcpy(&sin6.sin6_addr.s6_addr, &rt->rt_dst.prefix.v6, sizeof(struct in6_addr));
306     memset(&sin6.sin6_addr.s6_addr, 0, 8);
307     sin6.sin6_addr.s6_addr[0] = 0xfe;
308     sin6.sin6_addr.s6_addr[1] = 0x80;
309     sin6.sin6_scope_id = nexthop->iif_index;
310 #ifdef __KAME__
311     *(u_int16_t *) & sin6.sin6_addr.s6_addr[2] = htons(sin6.sin6_scope_id);
312     sin6.sin6_scope_id = 0;
313 #endif
314     memcpy(walker, &sin6, sizeof(sin6));
315     walker += sin_size;
316     rtm->rtm_addrs = RTA_GATEWAY;
317     rtm->rtm_flags |= RTF_GATEWAY;
318   }
319
320   /**********************************************************************
321    *                         SET  NETMASK
322    **********************************************************************/
323
324   if (0 == (rtm->rtm_flags & RTF_HOST)) {
325     olsr_prefix_to_netmask((union olsr_ip_addr *)&sin6.sin6_addr, rt->rt_dst.prefix_len);
326     memcpy(walker, &sin6, sizeof(sin6));
327     walker += sin_size;
328     rtm->rtm_addrs |= RTA_NETMASK;
329   }
330
331   /**********************************************************************
332    *           WRITE CONFIGURATION MESSAGE TO THE ROUTING SOCKET
333    **********************************************************************/
334
335   rtm->rtm_msglen = (unsigned short)(walker - buff);
336   len = write(olsr_cnf->rts, buff, rtm->rtm_msglen);
337   if (len < 0 && !(errno == EEXIST || errno == ESRCH)) {
338     fprintf(stderr, "cannot write to routing socket: %s\n", strerror(errno));
339   }
340
341   /*
342    * If we get an EEXIST error while adding, delete and retry.
343    */
344   if (len < 0 && errno == EEXIST && rtm->rtm_type == RTM_ADD) {
345     struct rt_msghdr *drtm;
346     unsigned char dbuff[512];
347
348     memset(dbuff, 0, sizeof(dbuff));
349     drtm = (struct rt_msghdr *)dbuff;
350     drtm->rtm_version = RTM_VERSION;
351     drtm->rtm_type = RTM_DELETE;
352     drtm->rtm_index = 0;
353     drtm->rtm_flags = olsr_rt_flags(rt);
354     drtm->rtm_seq = ++seq;
355
356     walker = dbuff + sizeof(struct rt_msghdr);
357     memcpy(&sin6.sin6_addr.s6_addr, &rt->rt_dst.prefix.v6, sizeof(struct in6_addr));
358     memcpy(walker, &sin6, sizeof(sin6));
359     walker += sin_size;
360     drtm->rtm_addrs = RTA_DST;
361     drtm->rtm_msglen = (unsigned short)(walker - dbuff);
362     len = write(olsr_cnf->rts, dbuff, drtm->rtm_msglen);
363     if (len < 0) {
364       fprintf(stderr, "cannot delete route: %s\n", strerror(errno));
365     }
366     rtm->rtm_seq = ++seq;
367     len = write(olsr_cnf->rts, buff, rtm->rtm_msglen);
368     if (len < 0) {
369       fprintf(stderr, "still cannot add route: %s\n", strerror(errno));
370     }
371   }
372   return 0;
373 }
374
375 int
376 olsr_ioctl_add_route6(const struct rt_entry *rt)
377 {
378   return add_del_route6(rt, 1);
379 }
380
381 int
382 olsr_ioctl_del_route6(const struct rt_entry *rt)
383 {
384   return add_del_route6(rt, 0);
385 }
386
387 /*
388  * Local Variables:
389  * c-basic-offset: 2
390  * indent-tabs-mode: nil
391  * End:
392  */