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