comment out freebsd build breaks
[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 <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 #ifdef CODE_IS_FIXED_ON_FBSD
131   OLSR_PRINTF(8, "\t- Setting Protocol: 0\n");
132   ((struct sockaddr_rt *)(&sin))->srt_proto = 0;
133   OLSR_PRINTF(8, "\t- Setting TOS: 0\n");
134   ((struct sockaddr_rt *)(&sin))->srt_tos = 0;
135 #endif
136
137   memcpy(walker, &sin, sizeof(sin));
138   walker += sin_size;
139
140   /**********************************************************************
141    *                  SET GATEWAY OF THE ROUTE
142    **********************************************************************/
143
144   if (add || (rtm->rtm_addrs & RTF_GATEWAY)) {
145     rtm->rtm_addrs |= RTA_GATEWAY;      /* part of the header */
146     nexthop = olsr_get_nh(rt);
147
148     if ((rtm->rtm_flags & RTF_GATEWAY)) {       /* GATEWAY */
149       sin.sin_addr = nexthop->gateway.v4;
150
151       memcpy(walker, &sin, sizeof(sin));
152       walker += sin_size;
153
154       OLSR_PRINTF(8, "\t- Gateway of the route: %s\n", inet_ntoa(sin.sin_addr));
155     }
156     /* NO GATEWAY - destination is directly reachable */
157     else {
158       rtm->rtm_flags |= RTF_CLONING;    /* part of the header! */
159
160       /*
161        * Host is directly reachable, so add the output interface MAC address.
162        */
163       if (getifaddrs(&addrs)) {
164         fprintf(stderr, "\ngetifaddrs() failed\n");
165         return -1;
166       }
167
168       for (awalker = addrs; awalker != NULL; awalker = awalker->ifa_next)
169         if (awalker->ifa_addr->sa_family == AF_LINK &&
170             strcmp(awalker->ifa_name,
171                    if_ifwithindex_name(nexthop->iif_index)) == 0)
172           break;
173
174       if (awalker == NULL) {
175         fprintf(stderr, "\nInterface %s not found\n",
176                 if_ifwithindex_name(nexthop->iif_index));
177         freeifaddrs(addrs);
178         return -1;
179       }
180
181       /* sdl is "struct sockaddr_dl" */
182       sdl = (struct sockaddr_dl *)awalker->ifa_addr;
183 #ifdef DEBUG
184       OLSR_PRINTF(8,"\t- Link layer address of the non gateway route: %s\n",
185                   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,
226               olsr_cnf->rts);
227
228   if (0 != rtm->rtm_errno || len < rtm->rtm_msglen) {
229     fprintf(stderr,
230             "\nCannot write to routing socket: (rtm_errno= 0x%x) (last error message: %s)\n",
231             rtm->rtm_errno, strerror(errno));
232   }
233
234   OLSR_PRINTF(8,
235               "\nWriting the following information to routing socket (message header):"
236               "\n\trtm_msglen: %u" "\n\trtm_version: %u" "\n\trtm_type: %u"
237               "\n\trtm_index: %u" "\n\trtm_flags: 0x%x" "\n\trtm_addrs: %u"
238               "\n\trtm_pid: 0x%x" "\n\trtm_seq: %u" "\n\trtm_errno: 0x%x"
239               "\n\trtm_use %u" "\n\trtm_inits: %u\n",
240               (unsigned int)rtm->rtm_msglen, (unsigned int)rtm->rtm_version,
241               (unsigned int)rtm->rtm_type, (unsigned int)rtm->rtm_index,
242               (unsigned int)rtm->rtm_flags, (unsigned int)rtm->rtm_addrs,
243               (unsigned int)rtm->rtm_pid, (unsigned int)rtm->rtm_seq,
244               (unsigned int)rtm->rtm_errno, (unsigned int)rtm->rtm_use,
245               (unsigned int)rtm->rtm_inits);
246
247   return 0;
248 }
249
250 int
251 olsr_ioctl_add_route(const struct rt_entry *rt)
252 {
253   return add_del_route(rt, 1);
254 }
255
256 int
257 olsr_ioctl_del_route(const struct rt_entry *rt)
258 {
259   return add_del_route(rt, 0);
260 }
261
262 static int
263 add_del_route6(const struct rt_entry *rt, int add)
264 {
265   struct rt_msghdr *rtm;
266   unsigned char buff[512];
267   unsigned char *walker;
268   struct sockaddr_in6 sin6;
269   struct sockaddr_dl sdl;
270   const struct rt_nexthop *nexthop;
271   int step, step_dl;
272   int len;
273
274   if (add) {
275     OLSR_PRINTF(2, "KERN: Adding %s\n", olsr_rtp_to_string(rt->rt_best));
276   } else {
277     OLSR_PRINTF(2, "KERN: Deleting %s\n", olsr_rt_to_string(rt));
278   }
279
280   memset(buff, 0, sizeof(buff));
281   memset(&sin6, 0, sizeof(sin6));
282   memset(&sdl, 0, sizeof(sdl));
283
284   sin6.sin6_len = sizeof(sin6);
285   sin6.sin6_family = AF_INET6;
286   sdl.sdl_len = sizeof(sdl);
287   sdl.sdl_family = AF_LINK;
288
289   step = 1 + ((sizeof(struct sockaddr_in6) - 1) | 3);
290   step_dl = 1 + ((sizeof(struct sockaddr_dl) - 1) | 3);
291
292   rtm = (struct rt_msghdr *)buff;
293   rtm->rtm_version = RTM_VERSION;
294   rtm->rtm_type = (add != 0) ? RTM_ADD : RTM_DELETE;
295   rtm->rtm_index = 0;
296   rtm->rtm_flags = olsr_rt_flags(rt);
297   rtm->rtm_addrs = RTA_DST | RTA_GATEWAY;
298   rtm->rtm_seq = ++seq;
299
300   walker = buff + sizeof(struct rt_msghdr);
301
302   memcpy(&sin6.sin6_addr.s6_addr, &rt->rt_dst.prefix.v6,
303          sizeof(struct in6_addr));
304
305   memcpy(walker, &sin6, sizeof(sin6));
306   walker += step;
307
308   nexthop = olsr_get_nh(rt);
309   if ((rtm->rtm_flags & RTF_GATEWAY) != 0) {
310     memcpy(&sin6.sin6_addr.s6_addr, &nexthop->gateway.v6,
311            sizeof(struct in6_addr));
312
313     memset(&sin6.sin6_addr.s6_addr, 0, 8);
314     sin6.sin6_addr.s6_addr[0] = 0xfe;
315     sin6.sin6_addr.s6_addr[1] = 0x80;
316     sin6.sin6_scope_id = nexthop->iif_index;
317 #ifdef __KAME__
318     *(u_int16_t *) & sin6.sin6_addr.s6_addr[2] = htons(sin6.sin6_scope_id);
319     sin6.sin6_scope_id = 0;
320 #endif
321     memcpy(walker, &sin6, sizeof(sin6));
322     walker += step;
323   }
324
325   /* the host is directly reachable, so add the output interface's address */
326
327   else {
328     memcpy(&sin6.sin6_addr.s6_addr, &rt->rt_dst.prefix.v6,
329            sizeof(struct in6_addr));
330     memset(&sin6.sin6_addr.s6_addr, 0, 8);
331     sin6.sin6_addr.s6_addr[0] = 0xfe;
332     sin6.sin6_addr.s6_addr[1] = 0x80;
333     sin6.sin6_scope_id = nexthop->iif_index;
334 #ifdef __KAME__
335     *(u_int16_t *) & sin6.sin6_addr.s6_addr[2] = htons(sin6.sin6_scope_id);
336     sin6.sin6_scope_id = 0;
337 #endif
338
339     memcpy(walker, &sin6, sizeof(sin6));
340     walker += step;
341     rtm->rtm_flags |= RTF_GATEWAY;
342   }
343
344   if ((rtm->rtm_flags & RTF_HOST) == 0) {
345     olsr_prefix_to_netmask((union olsr_ip_addr *)&sin6.sin6_addr,
346                            rt->rt_dst.prefix_len);
347     memcpy(walker, &sin6, sizeof(sin6));
348     walker += step;
349     rtm->rtm_addrs |= RTA_NETMASK;
350   }
351
352   rtm->rtm_msglen = (unsigned short)(walker - buff);
353
354   len = write(olsr_cnf->rts, buff, rtm->rtm_msglen);
355   if (len < 0 && !(errno == EEXIST || errno == ESRCH))
356     fprintf(stderr, "cannot write to routing socket: %s\n", strerror(errno));
357
358   /* If we get an EEXIST error while adding, delete and retry. */
359   if (len < 0 && errno == EEXIST && rtm->rtm_type == RTM_ADD) {
360     struct rt_msghdr *drtm;
361     unsigned char dbuff[512];
362
363     memset(dbuff, 0, sizeof(dbuff));
364     drtm = (struct rt_msghdr *)dbuff;
365     drtm->rtm_version = RTM_VERSION;
366     drtm->rtm_type = RTM_DELETE;
367     drtm->rtm_addrs = RTA_DST;
368     drtm->rtm_index = 0;
369     drtm->rtm_flags = olsr_rt_flags(rt);
370     drtm->rtm_seq = ++seq;
371
372     walker = dbuff + sizeof(struct rt_msghdr);
373     memcpy(&sin6.sin6_addr.s6_addr, &rt->rt_dst.prefix.v6,
374            sizeof(struct in6_addr));
375     memcpy(walker, &sin6, sizeof(sin6));
376     walker += step;
377     drtm->rtm_msglen = (unsigned short)(walker - dbuff);
378     len = write(olsr_cnf->rts, dbuff, drtm->rtm_msglen);
379     if (len < 0)
380       fprintf(stderr, "cannot delete route: %s\n", strerror(errno));
381     rtm->rtm_seq = ++seq;
382     len = write(olsr_cnf->rts, buff, rtm->rtm_msglen);
383     if (len < 0)
384       fprintf(stderr, "still cannot add route: %s\n", strerror(errno));
385   }
386
387   return 0;
388 }
389
390 int
391 olsr_ioctl_add_route6(const struct rt_entry *rt)
392 {
393   return add_del_route6(rt, 1);
394 }
395
396 int
397 olsr_ioctl_del_route6(const struct rt_entry *rt)
398 {
399   return add_del_route6(rt, 0);
400 }
401
402 /*
403  * Local Variables:
404  * c-basic-offset: 2
405  * End:
406  */