some better error/debug messages
[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 send to the routing socket */
75   unsigned char buff[512];
76   unsigned char *walker;               /* points within the buffer */
77   struct sockaddr_in sin4;             /* 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;              /* 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(&sin4, 0, sizeof(sin4));
94
95   sin4.sin_len = sizeof(sin4);
96   sin4.sin_family = AF_INET;
97
98   sin_size = 1 + ((sizeof(struct sockaddr_in) - 1) | (sizeof(long) - 1));
99   sdl_size = 1 + ((sizeof(struct sockaddr_dl) - 1) | (sizeof(long) - 1));
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   rtm->rtm_flags = olsr_rt_flags(rt);
112   rtm->rtm_pid = OLSR_PID;
113   rtm->rtm_seq = ++seq;
114
115   /* walk to the end of the header */
116   walker = buff + sizeof(struct rt_msghdr);
117
118   /**********************************************************************
119    *                  SET  DESTINATION OF THE ROUTE
120    **********************************************************************/
121
122 #ifdef _WRS_KERNEL
123   /*
124    * vxWorks: change proto or tos
125    */
126   OLSR_PRINTF(8, "\t- Setting Protocol: 0\n");
127   ((struct sockaddr_rt *)(&sin4))->srt_proto = 0;
128   OLSR_PRINTF(8, "\t- Setting TOS: 0\n");
129   ((struct sockaddr_rt *)(&sin4))->srt_tos = 0;
130 #endif
131
132   sin4.sin_addr = rt->rt_dst.prefix.v4;
133   memcpy(walker, &sin4, sizeof(sin4));
134   walker += sin_size;
135   rtm->rtm_addrs = RTA_DST;
136
137   /**********************************************************************
138    *                  SET GATEWAY OF THE ROUTE
139    **********************************************************************/
140
141 #ifdef _WRS_KERNEL
142   /*
143    * vxWorks: Route with no gateway is deleted
144    */
145   if (add) {
146 #endif
147     nexthop = olsr_get_nh(rt);
148     if (0 != (rtm->rtm_flags & RTF_GATEWAY)) {
149       sin4.sin_addr = nexthop->gateway.v4;
150       memcpy(walker, &sin4, sizeof(sin4));
151       walker += sin_size;
152       rtm->rtm_addrs |= RTA_GATEWAY;
153     }
154     else {
155       /*
156        * Host is directly reachable, so add
157        * the output interface MAC address.
158        */
159       if (getifaddrs(&addrs)) {
160         fprintf(stderr, "\ngetifaddrs() failed\n");
161         return -1;
162       }
163
164       for (awalker = addrs; awalker != NULL; awalker = awalker->ifa_next)
165         if (awalker->ifa_addr->sa_family == AF_LINK && strcmp(awalker->ifa_name, if_ifwithindex_name(nexthop->iif_index)) == 0)
166           break;
167
168       if (awalker == NULL) {
169         fprintf(stderr, "\nInterface %s not found\n", if_ifwithindex_name(nexthop->iif_index));
170         freeifaddrs(addrs);
171         return -1;
172       }
173
174       /* sdl is "struct sockaddr_dl" */
175       sdl = (struct sockaddr_dl *)awalker->ifa_addr;
176       memcpy(walker, sdl, sdl->sdl_len);
177       walker += sdl_size;
178       rtm->rtm_addrs |= RTA_GATEWAY;
179 #ifdef RTF_CLONING
180       rtm->rtm_flags |= RTF_CLONING;
181 #endif
182 #ifndef _WRS_KERNEL
183       rtm->rtm_flags &= ~RTF_HOST;
184 #endif
185       freeifaddrs(addrs);
186     }
187 #ifdef _WRS_KERNEL
188   }
189 #endif
190
191   /**********************************************************************
192    *                         SET  NETMASK
193    **********************************************************************/
194
195   if (0 == (rtm->rtm_flags & RTF_HOST)) {
196     olsr_prefix_to_netmask(&mask, rt->rt_dst.prefix_len);
197     sin4.sin_addr = mask.v4;
198     memcpy(walker, &sin4, sizeof(sin4));
199     walker += sin_size;
200     rtm->rtm_addrs |= RTA_NETMASK;
201   }
202
203   /**********************************************************************
204    *           WRITE CONFIGURATION MESSAGE TO THE ROUTING SOCKET
205    **********************************************************************/
206
207   rtm->rtm_msglen = (unsigned short)(walker - buff);
208   len = write(olsr_cnf->rts, buff, rtm->rtm_msglen);
209   if (0 != rtm->rtm_errno || len < rtm->rtm_msglen) {
210     if (add) {
211       fprintf(stderr, "\nCannot write to routing socket: (rtm_errno= 0x%x) last error message: %s (Adding %s)\n", 
212               rtm->rtm_errno,strerror(errno),olsr_rtp_to_string(rt->rt_best));
213     } else {
214       fprintf(stderr, "\nCannot write to routing socket: (rtm_errno= 0x%x) last error message: %s (Deleting %s)\n", 
215               rtm->rtm_errno,strerror(errno),olsr_rt_to_string(rt));
216     }
217   }
218   return 0;
219 }
220
221 int
222 olsr_ioctl_add_route(const struct rt_entry *rt)
223 {
224   return add_del_route(rt, 1);
225 }
226
227 int
228 olsr_ioctl_del_route(const struct rt_entry *rt)
229 {
230   return add_del_route(rt, 0);
231 }
232
233 static int
234 add_del_route6(const struct rt_entry *rt, int add)
235 {
236   struct rt_msghdr *rtm;
237   unsigned char buff[512];
238   unsigned char *walker;
239   struct sockaddr_in6 sin6;
240   struct sockaddr_dl sdl;
241   const struct rt_nexthop *nexthop;
242   int sin_size, sdl_size;
243   int len;
244
245   if (add) {
246     OLSR_PRINTF(2, "KERN: Adding %s\n", olsr_rtp_to_string(rt->rt_best));
247   } else {
248     OLSR_PRINTF(2, "KERN: Deleting %s\n", olsr_rt_to_string(rt));
249   }
250
251   memset(buff, 0, sizeof(buff));
252   memset(&sin6, 0, sizeof(sin6));
253   memset(&sdl, 0, sizeof(sdl));
254
255   sin6.sin6_len = sizeof(sin6);
256   sin6.sin6_family = AF_INET6;
257   sdl.sdl_len = sizeof(sdl);
258   sdl.sdl_family = AF_LINK;
259
260   sin_size = 1 + ((sizeof(struct sockaddr_in6) - 1) | (sizeof(long) - 1));
261   sdl_size = 1 + ((sizeof(struct sockaddr_dl) - 1) | (sizeof(long) - 1));
262
263   /**********************************************************************
264    *                  FILL THE ROUTING MESSAGE HEADER
265    **********************************************************************/
266
267   /* position header to the beginning of the buffer */
268   rtm = (struct rt_msghdr *)buff;
269   rtm->rtm_version = RTM_VERSION;
270   rtm->rtm_type = (add != 0) ? RTM_ADD : RTM_DELETE;
271   rtm->rtm_index = 0;
272   rtm->rtm_flags = olsr_rt_flags(rt);
273   rtm->rtm_pid = OLSR_PID;
274   rtm->rtm_seq = ++seq;
275
276   /* walk to the end of the header */
277   walker = buff + sizeof(struct rt_msghdr);
278
279   /**********************************************************************
280    *                  SET  DESTINATION OF THE ROUTE
281    **********************************************************************/
282
283   memcpy(&sin6.sin6_addr.s6_addr, &rt->rt_dst.prefix.v6, sizeof(struct in6_addr));
284   memcpy(walker, &sin6, sizeof(sin6));
285   walker += sin_size;
286   rtm->rtm_addrs = RTA_DST;
287
288   /**********************************************************************
289    *                  SET GATEWAY OF THE ROUTE
290    **********************************************************************/
291
292   nexthop = olsr_get_nh(rt);
293   if (0 != (rtm->rtm_flags & RTF_GATEWAY)) {
294     memcpy(&sin6.sin6_addr.s6_addr, &nexthop->gateway.v6, sizeof(struct in6_addr));
295     memset(&sin6.sin6_addr.s6_addr, 0, 8);
296     sin6.sin6_addr.s6_addr[0] = 0xfe;
297     sin6.sin6_addr.s6_addr[1] = 0x80;
298     sin6.sin6_scope_id = nexthop->iif_index;
299 #ifdef __KAME__
300     *(u_int16_t *) & sin6.sin6_addr.s6_addr[2] = htons(sin6.sin6_scope_id);
301     sin6.sin6_scope_id = 0;
302 #endif
303     memcpy(walker, &sin6, sizeof(sin6));
304     walker += sin_size;
305     rtm->rtm_addrs |= RTA_GATEWAY;
306   }
307   else {
308     /*
309      * Host is directly reachable, so add
310      * the output interface MAC address.
311      */
312     memcpy(&sin6.sin6_addr.s6_addr, &rt->rt_dst.prefix.v6, sizeof(struct in6_addr));
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 += sin_size;
323     rtm->rtm_addrs |= RTA_GATEWAY;
324     rtm->rtm_flags |= RTF_GATEWAY;
325   }
326
327   /**********************************************************************
328    *                         SET  NETMASK
329    **********************************************************************/
330
331   if (0 == (rtm->rtm_flags & RTF_HOST)) {
332     olsr_prefix_to_netmask((union olsr_ip_addr *)&sin6.sin6_addr, rt->rt_dst.prefix_len);
333     memcpy(walker, &sin6, sizeof(sin6));
334     walker += sin_size;
335     rtm->rtm_addrs |= RTA_NETMASK;
336   }
337
338   /**********************************************************************
339    *           WRITE CONFIGURATION MESSAGE TO THE ROUTING SOCKET
340    **********************************************************************/
341
342   rtm->rtm_msglen = (unsigned short)(walker - buff);
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
348   /*
349    * If we get an EEXIST error while adding, delete and retry.
350    */
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_index = 0;
360     drtm->rtm_flags = olsr_rt_flags(rt);
361     drtm->rtm_seq = ++seq;
362
363     walker = dbuff + sizeof(struct rt_msghdr);
364     memcpy(&sin6.sin6_addr.s6_addr, &rt->rt_dst.prefix.v6, sizeof(struct in6_addr));
365     memcpy(walker, &sin6, sizeof(sin6));
366     walker += sin_size;
367     drtm->rtm_addrs = RTA_DST;
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     }
373     rtm->rtm_seq = ++seq;
374     len = write(olsr_cnf->rts, buff, rtm->rtm_msglen);
375     if (len < 0) {
376       fprintf(stderr, "still cannot add route: %s\n", strerror(errno));
377     }
378   }
379   return 0;
380 }
381
382 int
383 olsr_ioctl_add_route6(const struct rt_entry *rt)
384 {
385   return add_del_route6(rt, 1);
386 }
387
388 int
389 olsr_ioctl_del_route6(const struct rt_entry *rt)
390 {
391   return add_del_route6(rt, 0);
392 }
393
394 /*
395  * Local Variables:
396  * c-basic-offset: 2
397  * indent-tabs-mode: nil
398  * End:
399  */