99cd90cad64da2e5de7b213ced9c0f0f77581f31
[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 <net/if_dl.h>
50 #include <ifaddrs.h>
51
52 #ifdef _WRS_KERNEL
53 #include <wrn/coreip/net/route.h>
54 #include <m2Lib.h>
55 #define OLSR_PID taskIdSelf ()
56 #else
57 #define OLSR_PID getpid ()
58 #endif
59
60 static unsigned int seq = 0;
61
62 /*
63  * Sends an add or delete message via the routing socket.
64  * The message consists of:
65  *  - a header i.e. struct rt_msghdr
66  *  - 0-8 socket address structures
67  */
68 static int
69 add_del_route(const struct rt_entry *rt, int add)
70 {
71   struct rt_msghdr *rtm;               /* message to configure a route */
72   /* contains data to be written to the
73      routing socket */
74   unsigned char buff[512];
75   unsigned char *walker;               /* points within the buffer */
76   struct sockaddr_in sin;              /* internet style sockaddr */
77   struct sockaddr_dl *sdl;             /* link level sockaddr */
78   struct ifaddrs *addrs;
79   struct ifaddrs *awalker;
80   const struct rt_nexthop *nexthop;
81   union olsr_ip_addr mask;             /* netmask as ip address */
82   int sin_size, sdl_size;              /* size of addresses - e.g. destination
83                                           (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(&sin, 0, sizeof(sin));
94
95   sin.sin_len = sizeof(sin);
96   sin.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   /* RTF_UP [and RTF_HOST and/or RTF_GATEWAY] */
112   rtm->rtm_flags = olsr_rt_flags(rt);
113   rtm->rtm_pid = OLSR_PID;
114   rtm->rtm_seq = ++seq;
115
116   /* walk to the end of the header */
117   walker = buff + sizeof(struct rt_msghdr);
118
119   /**********************************************************************
120    *                  SET  DESTINATION OF THE ROUTE
121    **********************************************************************/
122
123   rtm->rtm_addrs = RTA_DST;     /* part of the header */
124
125   sin.sin_addr = rt->rt_dst.prefix.v4;
126   OLSR_PRINTF(8, "\t- Destination of the route: %s\n", inet_ntoa(sin.sin_addr));
127
128   /* change proto or tos here */
129 #ifdef _WRS_KERNEL
130   /*
131    * These statements do not compile on Fbsd, but they
132    * where added during VxWorks cleanup. May be necessary
133    * for VxWorks operation - pls. correct me (Sven-Ola)
134    */
135   OLSR_PRINTF(8, "\t- Setting Protocol: 0\n");
136   ((struct sockaddr_rt *)(&sin))->srt_proto = 0;
137   OLSR_PRINTF(8, "\t- Setting TOS: 0\n");
138   ((struct sockaddr_rt *)(&sin))->srt_tos = 0;
139 #endif
140
141   memcpy(walker, &sin, sizeof(sin));
142   walker += sin_size;
143
144   /**********************************************************************
145    *                  SET GATEWAY OF THE ROUTE
146    **********************************************************************/
147
148   if (add || (rtm->rtm_addrs & RTF_GATEWAY)) {
149     rtm->rtm_addrs |= RTA_GATEWAY;      /* part of the header */
150     nexthop = olsr_get_nh(rt);
151
152     if ((rtm->rtm_flags & RTF_GATEWAY)) {       /* GATEWAY */
153       sin.sin_addr = nexthop->gateway.v4;
154
155       memcpy(walker, &sin, sizeof(sin));
156       walker += sin_size;
157
158       OLSR_PRINTF(8, "\t- Gateway of the route: %s\n", inet_ntoa(sin.sin_addr));
159     }
160     /* NO GATEWAY - destination is directly reachable */
161     else {
162       rtm->rtm_flags |= RTF_CLONING;    /* part of the header! */
163
164       /*
165        * Host is directly reachable, so add the output interface MAC address.
166        */
167       if (getifaddrs(&addrs)) {
168         fprintf(stderr, "\ngetifaddrs() failed\n");
169         return -1;
170       }
171
172       for (awalker = addrs; awalker != NULL; awalker = awalker->ifa_next)
173         if (awalker->ifa_addr->sa_family == AF_LINK && strcmp(awalker->ifa_name, if_ifwithindex_name(nexthop->iif_index)) == 0)
174           break;
175
176       if (awalker == NULL) {
177         fprintf(stderr, "\nInterface %s not found\n", if_ifwithindex_name(nexthop->iif_index));
178         freeifaddrs(addrs);
179         return -1;
180       }
181
182       /* sdl is "struct sockaddr_dl" */
183       sdl = (struct sockaddr_dl *)awalker->ifa_addr;
184 #ifdef DEBUG
185       OLSR_PRINTF(8, "\t- Link layer address of the non gateway route: %s\n", LLADDR(sdl));
186 #endif
187
188       memcpy(walker, sdl, sdl->sdl_len);
189       walker += sdl_size;
190
191       freeifaddrs(addrs);
192     }
193   } else {
194     /* Route with no gateway is deleted */
195   }
196
197   /**********************************************************************
198    *                         SET  NETMASK
199    **********************************************************************/
200
201   if ((rtm->rtm_flags & RTF_HOST)) {
202     OLSR_PRINTF(8, "\t- No netmask needed for a host route.\n");
203   } else {                      /* NO! hoste route */
204
205     rtm->rtm_addrs |= RTA_NETMASK;      /* part of the header */
206
207     if (!olsr_prefix_to_netmask(&mask, rt->rt_dst.prefix_len)) {
208       return -1;
209     }
210     sin.sin_addr = mask.v4;
211
212     memcpy(walker, &sin, sizeof(sin));
213     walker += sin_size;
214
215     OLSR_PRINTF(8, "\t- Netmask of the route: %s\n", inet_ntoa(sin.sin_addr));
216   }
217
218   /**********************************************************************
219    *           WRITE CONFIGURATION MESSAGE TO THE ROUTING SOCKET
220    **********************************************************************/
221
222   rtm->rtm_msglen = (unsigned short)(walker - buff);
223
224   len = write(olsr_cnf->rts, buff, rtm->rtm_msglen);
225   OLSR_PRINTF(8, "\nWrote %d bytes to rts socket (FD=%d)\n", len, olsr_cnf->rts);
226
227   if (0 != rtm->rtm_errno || len < rtm->rtm_msglen) {
228     fprintf(stderr, "\nCannot write to routing socket: (rtm_errno= 0x%x) (last error message: %s)\n", rtm->rtm_errno,
229             strerror(errno));
230   }
231
232   OLSR_PRINTF(8,
233               "\nWriting the following information to routing socket (message header):" "\n\trtm_msglen: %u" "\n\trtm_version: %u"
234               "\n\trtm_type: %u" "\n\trtm_index: %u" "\n\trtm_flags: 0x%x" "\n\trtm_addrs: %u" "\n\trtm_pid: 0x%x" "\n\trtm_seq: %u"
235               "\n\trtm_errno: 0x%x" "\n\trtm_use %u" "\n\trtm_inits: %u\n", (unsigned int)rtm->rtm_msglen,
236               (unsigned int)rtm->rtm_version, (unsigned int)rtm->rtm_type, (unsigned int)rtm->rtm_index,
237               (unsigned int)rtm->rtm_flags, (unsigned int)rtm->rtm_addrs, (unsigned int)rtm->rtm_pid, (unsigned int)rtm->rtm_seq,
238               (unsigned int)rtm->rtm_errno, (unsigned int)rtm->rtm_use, (unsigned int)rtm->rtm_inits);
239
240   return 0;
241 }
242
243 int
244 olsr_ioctl_add_route(const struct rt_entry *rt)
245 {
246   return add_del_route(rt, 1);
247 }
248
249 int
250 olsr_ioctl_del_route(const struct rt_entry *rt)
251 {
252   return add_del_route(rt, 0);
253 }
254
255 static int
256 add_del_route6(const struct rt_entry *rt, int add)
257 {
258   struct rt_msghdr *rtm;
259   unsigned char buff[512];
260   unsigned char *walker;
261   struct sockaddr_in6 sin6;
262   struct sockaddr_dl sdl;
263   const struct rt_nexthop *nexthop;
264   int sin_size, sdl_size;
265   int len;
266
267   if (add) {
268     OLSR_PRINTF(2, "KERN: Adding %s\n", olsr_rtp_to_string(rt->rt_best));
269   } else {
270     OLSR_PRINTF(2, "KERN: Deleting %s\n", olsr_rt_to_string(rt));
271   }
272
273   memset(buff, 0, sizeof(buff));
274   memset(&sin6, 0, sizeof(sin6));
275   memset(&sdl, 0, sizeof(sdl));
276
277   sin6.sin6_len = sizeof(sin6);
278   sin6.sin6_family = AF_INET6;
279   sdl.sdl_len = sizeof(sdl);
280   sdl.sdl_family = AF_LINK;
281
282   sin_size = 1 + ((sizeof(struct sockaddr_in6) - 1) | 3);
283   sdl_size = 1 + ((sizeof(struct sockaddr_dl) - 1) | 3);
284
285   rtm = (struct rt_msghdr *)buff;
286   rtm->rtm_version = RTM_VERSION;
287   rtm->rtm_type = (add != 0) ? RTM_ADD : RTM_DELETE;
288   rtm->rtm_index = 0;
289   rtm->rtm_flags = olsr_rt_flags(rt);
290   rtm->rtm_addrs = RTA_DST | RTA_GATEWAY;
291   rtm->rtm_seq = ++seq;
292
293   walker = buff + sizeof(struct rt_msghdr);
294
295   memcpy(&sin6.sin6_addr.s6_addr, &rt->rt_dst.prefix.v6, sizeof(struct in6_addr));
296
297   memcpy(walker, &sin6, sizeof(sin6));
298   walker += sin_size;
299
300   nexthop = olsr_get_nh(rt);
301   if ((rtm->rtm_flags & RTF_GATEWAY) != 0) {
302     memcpy(&sin6.sin6_addr.s6_addr, &nexthop->gateway.v6, sizeof(struct in6_addr));
303
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->iif_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   }
315
316   /* the host is directly reachable, so add the output interface's address */
317
318   else {
319     memcpy(&sin6.sin6_addr.s6_addr, &rt->rt_dst.prefix.v6, sizeof(struct in6_addr));
320     memset(&sin6.sin6_addr.s6_addr, 0, 8);
321     sin6.sin6_addr.s6_addr[0] = 0xfe;
322     sin6.sin6_addr.s6_addr[1] = 0x80;
323     sin6.sin6_scope_id = nexthop->iif_index;
324 #ifdef __KAME__
325     *(u_int16_t *) & sin6.sin6_addr.s6_addr[2] = htons(sin6.sin6_scope_id);
326     sin6.sin6_scope_id = 0;
327 #endif
328
329     memcpy(walker, &sin6, sizeof(sin6));
330     walker += sin_size;
331     rtm->rtm_flags |= RTF_GATEWAY;
332   }
333
334   if ((rtm->rtm_flags & RTF_HOST) == 0) {
335     olsr_prefix_to_netmask((union olsr_ip_addr *)&sin6.sin6_addr, rt->rt_dst.prefix_len);
336     memcpy(walker, &sin6, sizeof(sin6));
337     walker += sin_size;
338     rtm->rtm_addrs |= RTA_NETMASK;
339   }
340
341   rtm->rtm_msglen = (unsigned short)(walker - buff);
342
343   len = write(olsr_cnf->rts, buff, rtm->rtm_msglen);
344   if (len < 0 && !(errno == EEXIST || errno == ESRCH))
345     fprintf(stderr, "cannot write to routing socket: %s\n", strerror(errno));
346
347   /* If we get an EEXIST error while adding, delete and retry. */
348   if (len < 0 && errno == EEXIST && rtm->rtm_type == RTM_ADD) {
349     struct rt_msghdr *drtm;
350     unsigned char dbuff[512];
351
352     memset(dbuff, 0, sizeof(dbuff));
353     drtm = (struct rt_msghdr *)dbuff;
354     drtm->rtm_version = RTM_VERSION;
355     drtm->rtm_type = RTM_DELETE;
356     drtm->rtm_addrs = RTA_DST;
357     drtm->rtm_index = 0;
358     drtm->rtm_flags = olsr_rt_flags(rt);
359     drtm->rtm_seq = ++seq;
360
361     walker = dbuff + sizeof(struct rt_msghdr);
362     memcpy(&sin6.sin6_addr.s6_addr, &rt->rt_dst.prefix.v6, sizeof(struct in6_addr));
363     memcpy(walker, &sin6, sizeof(sin6));
364     walker += sin_size;
365     drtm->rtm_msglen = (unsigned short)(walker - dbuff);
366     len = write(olsr_cnf->rts, dbuff, drtm->rtm_msglen);
367     if (len < 0)
368       fprintf(stderr, "cannot delete route: %s\n", strerror(errno));
369     rtm->rtm_seq = ++seq;
370     len = write(olsr_cnf->rts, buff, rtm->rtm_msglen);
371     if (len < 0)
372       fprintf(stderr, "still cannot add route: %s\n", strerror(errno));
373   }
374
375   return 0;
376 }
377
378 int
379 olsr_ioctl_add_route6(const struct rt_entry *rt)
380 {
381   return add_del_route6(rt, 1);
382 }
383
384 int
385 olsr_ioctl_del_route6(const struct rt_entry *rt)
386 {
387   return add_del_route6(rt, 0);
388 }
389
390 /*
391  * Local Variables:
392  * c-basic-offset: 2
393  * indent-tabs-mode: nil
394  * End:
395  */