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