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