55572da263d82a0d226135d7dfe1ab47b4bd3c96
[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 CODE_IS_FIXED_ON_FBSD
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 #endif
135
136   memcpy(walker, &sin, sizeof(sin));
137   walker += sin_size;
138
139   /**********************************************************************
140    *                  SET GATEWAY OF THE ROUTE
141    **********************************************************************/
142
143   if (add || (rtm->rtm_addrs & RTF_GATEWAY)) {
144     rtm->rtm_addrs |= RTA_GATEWAY;      /* part of the header */
145     nexthop = olsr_get_nh(rt);
146
147     if ((rtm->rtm_flags & RTF_GATEWAY)) {       /* GATEWAY */
148       sin.sin_addr = nexthop->gateway.v4;
149
150       memcpy(walker, &sin, sizeof(sin));
151       walker += sin_size;
152
153       OLSR_PRINTF(8, "\t- Gateway of the route: %s\n", inet_ntoa(sin.sin_addr));
154     }
155     /* NO GATEWAY - destination is directly reachable */
156     else {
157       rtm->rtm_flags |= RTF_CLONING;    /* part of the header! */
158
159       /*
160        * Host is directly reachable, so add the output interface MAC address.
161        */
162       if (getifaddrs(&addrs)) {
163         fprintf(stderr, "\ngetifaddrs() failed\n");
164         return -1;
165       }
166
167       for (awalker = addrs; awalker != NULL; awalker = awalker->ifa_next)
168         if (awalker->ifa_addr->sa_family == AF_LINK && strcmp(awalker->ifa_name, if_ifwithindex_name(nexthop->iif_index)) == 0)
169           break;
170
171       if (awalker == NULL) {
172         fprintf(stderr, "\nInterface %s not found\n", if_ifwithindex_name(nexthop->iif_index));
173         freeifaddrs(addrs);
174         return -1;
175       }
176
177       /* sdl is "struct sockaddr_dl" */
178       sdl = (struct sockaddr_dl *)awalker->ifa_addr;
179 #ifdef DEBUG
180       OLSR_PRINTF(8, "\t- Link layer address of the non gateway route: %s\n", LLADDR(sdl));
181 #endif
182
183       memcpy(walker, sdl, sdl->sdl_len);
184       walker += sdl_size;
185
186       freeifaddrs(addrs);
187     }
188   } else {
189     /* Route with no gateway is deleted */
190   }
191
192   /**********************************************************************
193    *                         SET  NETMASK
194    **********************************************************************/
195
196   if ((rtm->rtm_flags & RTF_HOST)) {
197     OLSR_PRINTF(8, "\t- No netmask needed for a host route.\n");
198   } else {                      /* NO! hoste route */
199
200     rtm->rtm_addrs |= RTA_NETMASK;      /* part of the header */
201
202     if (!olsr_prefix_to_netmask(&mask, rt->rt_dst.prefix_len)) {
203       return -1;
204     }
205     sin.sin_addr = mask.v4;
206
207     memcpy(walker, &sin, sizeof(sin));
208     walker += sin_size;
209
210     OLSR_PRINTF(8, "\t- Netmask of the route: %s\n", inet_ntoa(sin.sin_addr));
211   }
212
213   /**********************************************************************
214    *           WRITE CONFIGURATION MESSAGE TO THE ROUTING SOCKET
215    **********************************************************************/
216
217   rtm->rtm_msglen = (unsigned short)(walker - buff);
218
219   len = write(olsr_cnf->rts, buff, rtm->rtm_msglen);
220   OLSR_PRINTF(8, "\nWrote %d bytes to rts socket (FD=%d)\n", len, olsr_cnf->rts);
221
222   if (0 != rtm->rtm_errno || len < rtm->rtm_msglen) {
223     fprintf(stderr, "\nCannot write to routing socket: (rtm_errno= 0x%x) (last error message: %s)\n", rtm->rtm_errno,
224             strerror(errno));
225   }
226
227   OLSR_PRINTF(8,
228               "\nWriting the following information to routing socket (message header):" "\n\trtm_msglen: %u" "\n\trtm_version: %u"
229               "\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"
230               "\n\trtm_errno: 0x%x" "\n\trtm_use %u" "\n\trtm_inits: %u\n", (unsigned int)rtm->rtm_msglen,
231               (unsigned int)rtm->rtm_version, (unsigned int)rtm->rtm_type, (unsigned int)rtm->rtm_index,
232               (unsigned int)rtm->rtm_flags, (unsigned int)rtm->rtm_addrs, (unsigned int)rtm->rtm_pid, (unsigned int)rtm->rtm_seq,
233               (unsigned int)rtm->rtm_errno, (unsigned int)rtm->rtm_use, (unsigned int)rtm->rtm_inits);
234
235   return 0;
236 }
237
238 int
239 olsr_ioctl_add_route(const struct rt_entry *rt)
240 {
241   return add_del_route(rt, 1);
242 }
243
244 int
245 olsr_ioctl_del_route(const struct rt_entry *rt)
246 {
247   return add_del_route(rt, 0);
248 }
249
250 static int
251 add_del_route6(const struct rt_entry *rt, int add)
252 {
253   struct rt_msghdr *rtm;
254   unsigned char buff[512];
255   unsigned char *walker;
256   struct sockaddr_in6 sin6;
257   struct sockaddr_dl sdl;
258   const struct rt_nexthop *nexthop;
259   int step, step_dl;
260   int len;
261
262   if (add) {
263     OLSR_PRINTF(2, "KERN: Adding %s\n", olsr_rtp_to_string(rt->rt_best));
264   } else {
265     OLSR_PRINTF(2, "KERN: Deleting %s\n", olsr_rt_to_string(rt));
266   }
267
268   memset(buff, 0, sizeof(buff));
269   memset(&sin6, 0, sizeof(sin6));
270   memset(&sdl, 0, sizeof(sdl));
271
272   sin6.sin6_len = sizeof(sin6);
273   sin6.sin6_family = AF_INET6;
274   sdl.sdl_len = sizeof(sdl);
275   sdl.sdl_family = AF_LINK;
276
277   step = 1 + ((sizeof(struct sockaddr_in6) - 1) | 3);
278   step_dl = 1 + ((sizeof(struct sockaddr_dl) - 1) | 3);
279
280   rtm = (struct rt_msghdr *)buff;
281   rtm->rtm_version = RTM_VERSION;
282   rtm->rtm_type = (add != 0) ? RTM_ADD : RTM_DELETE;
283   rtm->rtm_index = 0;
284   rtm->rtm_flags = olsr_rt_flags(rt);
285   rtm->rtm_addrs = RTA_DST | RTA_GATEWAY;
286   rtm->rtm_seq = ++seq;
287
288   walker = buff + sizeof(struct rt_msghdr);
289
290   memcpy(&sin6.sin6_addr.s6_addr, &rt->rt_dst.prefix.v6, sizeof(struct in6_addr));
291
292   memcpy(walker, &sin6, sizeof(sin6));
293   walker += step;
294
295   nexthop = olsr_get_nh(rt);
296   if ((rtm->rtm_flags & RTF_GATEWAY) != 0) {
297     memcpy(&sin6.sin6_addr.s6_addr, &nexthop->gateway.v6, sizeof(struct in6_addr));
298
299     memset(&sin6.sin6_addr.s6_addr, 0, 8);
300     sin6.sin6_addr.s6_addr[0] = 0xfe;
301     sin6.sin6_addr.s6_addr[1] = 0x80;
302     sin6.sin6_scope_id = nexthop->iif_index;
303 #ifdef __KAME__
304     *(u_int16_t *) & sin6.sin6_addr.s6_addr[2] = htons(sin6.sin6_scope_id);
305     sin6.sin6_scope_id = 0;
306 #endif
307     memcpy(walker, &sin6, sizeof(sin6));
308     walker += step;
309   }
310
311   /* the host is directly reachable, so add the output interface's address */
312
313   else {
314     memcpy(&sin6.sin6_addr.s6_addr, &rt->rt_dst.prefix.v6, sizeof(struct in6_addr));
315     memset(&sin6.sin6_addr.s6_addr, 0, 8);
316     sin6.sin6_addr.s6_addr[0] = 0xfe;
317     sin6.sin6_addr.s6_addr[1] = 0x80;
318     sin6.sin6_scope_id = nexthop->iif_index;
319 #ifdef __KAME__
320     *(u_int16_t *) & sin6.sin6_addr.s6_addr[2] = htons(sin6.sin6_scope_id);
321     sin6.sin6_scope_id = 0;
322 #endif
323
324     memcpy(walker, &sin6, sizeof(sin6));
325     walker += step;
326     rtm->rtm_flags |= RTF_GATEWAY;
327   }
328
329   if ((rtm->rtm_flags & RTF_HOST) == 0) {
330     olsr_prefix_to_netmask((union olsr_ip_addr *)&sin6.sin6_addr, rt->rt_dst.prefix_len);
331     memcpy(walker, &sin6, sizeof(sin6));
332     walker += step;
333     rtm->rtm_addrs |= RTA_NETMASK;
334   }
335
336   rtm->rtm_msglen = (unsigned short)(walker - buff);
337
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   /* If we get an EEXIST error while adding, delete and retry. */
343   if (len < 0 && errno == EEXIST && rtm->rtm_type == RTM_ADD) {
344     struct rt_msghdr *drtm;
345     unsigned char dbuff[512];
346
347     memset(dbuff, 0, sizeof(dbuff));
348     drtm = (struct rt_msghdr *)dbuff;
349     drtm->rtm_version = RTM_VERSION;
350     drtm->rtm_type = RTM_DELETE;
351     drtm->rtm_addrs = RTA_DST;
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 += step;
360     drtm->rtm_msglen = (unsigned short)(walker - dbuff);
361     len = write(olsr_cnf->rts, dbuff, drtm->rtm_msglen);
362     if (len < 0)
363       fprintf(stderr, "cannot delete route: %s\n", strerror(errno));
364     rtm->rtm_seq = ++seq;
365     len = write(olsr_cnf->rts, buff, rtm->rtm_msglen);
366     if (len < 0)
367       fprintf(stderr, "still cannot add route: %s\n", strerror(errno));
368   }
369
370   return 0;
371 }
372
373 int
374 olsr_ioctl_add_route6(const struct rt_entry *rt)
375 {
376   return add_del_route6(rt, 1);
377 }
378
379 int
380 olsr_ioctl_del_route6(const struct rt_entry *rt)
381 {
382   return add_del_route6(rt, 0);
383 }
384
385 /*
386  * Local Variables:
387  * c-basic-offset: 2
388  * indent-tabs-mode: nil
389  * End:
390  */