Use correct RTM flags while deleting a route on BSD.
[olsrd.git] / src / bsd / kernel_routes.c
1 /*
2  * The olsr.org Optimized Link-State Routing daemon (olsrd)
3  *
4  * (c) by the OLSR project
5  *
6  * See our Git repository to find out who worked on this file
7  * and thus is a copyright holder on it.
8  *
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  *
15  * * Redistributions of source code must retain the above copyright
16  *   notice, this list of conditions and the following disclaimer.
17  * * Redistributions in binary form must reproduce the above copyright
18  *   notice, this list of conditions and the following disclaimer in
19  *   the documentation and/or other materials provided with the
20  *   distribution.
21  * * Neither the name of olsr.org, olsrd nor the names of its
22  *   contributors may be used to endorse or promote products derived
23  *   from this software without specific prior written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
28  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
29  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
30  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
31  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
32  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
33  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
35  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  * POSSIBILITY OF SUCH DAMAGE.
37  *
38  * Visit http://www.olsr.org for more information.
39  *
40  * If you find this software useful feel free to make a donation
41  * to the project. For more information see the website or contact
42  * the copyright holders.
43  *
44  */
45
46 #include "kernel_routes.h"
47 #include "olsr.h"
48 #include "defs.h"
49 #include "process_routes.h"
50 #include "net_olsr.h"
51 #include "ipcalc.h"
52
53 #include <errno.h>
54 #include <unistd.h>
55 #include <net/if_dl.h>
56
57 #ifdef _WRS_KERNEL
58 #include <net/ifaddrs.h>
59 #include <wrn/coreip/net/route.h>
60 #include <m2Lib.h>
61 #define OLSR_PID taskIdSelf ()
62 #else /* _WRS_KERNEL */
63 #include <ifaddrs.h>
64 #define OLSR_PID getpid ()
65 #endif /* _WRS_KERNEL */
66
67 static unsigned int seq = 0;
68
69 /*
70  * Sends an add or delete message via the routing socket.
71  * The message consists of:
72  *  - a header i.e. struct rt_msghdr
73  *  - 0-8 socket address structures
74  */
75 static int
76 add_del_route(const struct rt_entry *rt, int add)
77 {
78   struct rt_msghdr *rtm;               /* message to send to the routing socket */
79   unsigned char buff[512];
80   unsigned char *walker;               /* points within the buffer */
81   struct sockaddr_in sin4;             /* internet style sockaddr */
82   struct sockaddr_dl *sdl;             /* link level sockaddr */
83   struct ifaddrs *addrs;
84   struct ifaddrs *awalker;
85   const struct rt_nexthop *nexthop;
86   union olsr_ip_addr mask;             /* netmask as ip address */
87   int sin_size, sdl_size;              /* payload of the message */
88   int len;                             /* message size written to routing socket */
89
90   if (add) {
91     OLSR_PRINTF(2, "KERN: Adding %s\n", olsr_rtp_to_string(rt->rt_best));
92   } else {
93     OLSR_PRINTF(2, "KERN: Deleting %s\n", olsr_rt_to_string(rt));
94   }
95
96   memset(buff, 0, sizeof(buff));
97   memset(&sin4, 0, sizeof(sin4));
98
99   sin4.sin_len = sizeof(sin4);
100   sin4.sin_family = AF_INET;
101
102   sin_size = 1 + ((sizeof(struct sockaddr_in) - 1) | (sizeof(long) - 1));
103   sdl_size = 1 + ((sizeof(struct sockaddr_dl) - 1) | (sizeof(long) - 1));
104
105   /**********************************************************************
106    *                  FILL THE ROUTING MESSAGE HEADER
107    **********************************************************************/
108
109   /* position header to the beginning of the buffer */
110   rtm = (struct rt_msghdr *)buff;
111
112   rtm->rtm_version = RTM_VERSION;
113   rtm->rtm_type = add ? RTM_ADD : RTM_DELETE;
114   rtm->rtm_index = 0;           /* is ignored in outgoing messages */
115   rtm->rtm_flags = olsr_rt_flags(rt, add);
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 #ifdef _WRS_KERNEL
127   /*
128    * vxWorks: change proto or tos
129    */
130   OLSR_PRINTF(8, "\t- Setting Protocol: 0\n");
131   ((struct sockaddr_rt *)(&sin4))->srt_proto = 0;
132   OLSR_PRINTF(8, "\t- Setting TOS: 0\n");
133   ((struct sockaddr_rt *)(&sin4))->srt_tos = 0;
134 #endif /* _WRS_KERNEL */
135
136   sin4.sin_addr = rt->rt_dst.prefix.v4;
137   memcpy(walker, &sin4, sizeof(sin4));
138   walker += sin_size;
139   rtm->rtm_addrs = RTA_DST;
140
141   /**********************************************************************
142    *                  SET GATEWAY OF THE ROUTE
143    **********************************************************************/
144
145 #ifdef _WRS_KERNEL
146   /*
147    * vxWorks: Route with no gateway is deleted
148    */
149   if (add) {
150 #endif /* _WRS_KERNEL */
151     nexthop = olsr_get_nh(rt);
152     if (0 != (rtm->rtm_flags & RTF_GATEWAY)) {
153       sin4.sin_addr = nexthop->gateway.v4;
154       memcpy(walker, &sin4, sizeof(sin4));
155       walker += sin_size;
156       rtm->rtm_addrs |= RTA_GATEWAY;
157     }
158     else {
159       /*
160        * Host is directly reachable, so add
161        * 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 && strcmp(awalker->ifa_name, if_ifwithindex_name(nexthop->iif_index)) == 0)
170           break;
171
172       if (awalker == NULL) {
173         fprintf(stderr, "\nInterface %s not found\n", if_ifwithindex_name(nexthop->iif_index));
174         freeifaddrs(addrs);
175         return -1;
176       }
177
178       /* sdl is "struct sockaddr_dl" */
179       sdl = (struct sockaddr_dl *)awalker->ifa_addr;
180       memcpy(walker, sdl, sdl->sdl_len);
181       walker += sdl_size;
182       rtm->rtm_addrs |= RTA_GATEWAY;
183 #ifdef RTF_CLONING
184       rtm->rtm_flags |= RTF_CLONING;
185 #endif /* RTF_CLONING */
186 #ifndef _WRS_KERNEL
187       rtm->rtm_flags &= ~RTF_HOST;
188 #endif /* _WRS_KERNEL */
189       freeifaddrs(addrs);
190     }
191 #ifdef _WRS_KERNEL
192   }
193 #endif /* _WRS_KERNEL */
194
195   /**********************************************************************
196    *                         SET  NETMASK
197    **********************************************************************/
198
199   if (0 == (rtm->rtm_flags & RTF_HOST)) {
200     olsr_prefix_to_netmask(&mask, rt->rt_dst.prefix_len);
201     sin4.sin_addr = mask.v4;
202     memcpy(walker, &sin4, sizeof(sin4));
203     walker += sin_size;
204     rtm->rtm_addrs |= RTA_NETMASK;
205   }
206
207   /**********************************************************************
208    *           WRITE CONFIGURATION MESSAGE TO THE ROUTING SOCKET
209    **********************************************************************/
210
211   rtm->rtm_msglen = (unsigned short)(walker - buff);
212   len = write(olsr_cnf->rts, buff, rtm->rtm_msglen);
213   if (len < 0 && !(errno == EEXIST || errno == ESRCH)) {
214     fprintf(stderr, "cannot write to routing socket: %s\n", strerror(errno));
215   }
216
217   /*
218    * If we get an EEXIST error while adding, delete and retry.
219    */
220   if (len < 0 && errno == EEXIST && rtm->rtm_type == RTM_ADD) {
221     struct rt_msghdr *drtm;
222     unsigned char dbuff[512];
223
224     memset(dbuff, 0, sizeof(dbuff));
225     drtm = (struct rt_msghdr *)dbuff;
226     drtm->rtm_version = RTM_VERSION;
227     drtm->rtm_type = RTM_DELETE;
228     drtm->rtm_index = 0;
229     drtm->rtm_flags = olsr_rt_flags(rt, 0);
230     drtm->rtm_seq = ++seq;
231
232     walker = dbuff + sizeof(struct rt_msghdr);
233     sin4.sin_addr = rt->rt_dst.prefix.v4;
234     memcpy(walker, &sin4, sizeof(sin4));
235     walker += sin_size;
236     drtm->rtm_addrs = RTA_DST;
237     if (0 == (drtm->rtm_flags & RTF_HOST)) {
238       olsr_prefix_to_netmask(&mask, rt->rt_dst.prefix_len);
239       sin4.sin_addr = mask.v4;
240       memcpy(walker, &sin4, sizeof(sin4));
241       walker += sin_size;
242       drtm->rtm_addrs |= RTA_NETMASK;
243     }
244     drtm->rtm_msglen = (unsigned short)(walker - dbuff);
245     len = write(olsr_cnf->rts, dbuff, drtm->rtm_msglen);
246     if (len < 0) {
247       fprintf(stderr, "cannot delete route: %s\n", strerror(errno));
248     }
249     rtm->rtm_seq = ++seq;
250     len = write(olsr_cnf->rts, buff, rtm->rtm_msglen);
251     if (len < 0) {
252       fprintf(stderr, "still cannot add route: %s\n", strerror(errno));
253     }
254   }
255   return 0;
256 }
257
258 int
259 olsr_ioctl_add_route(const struct rt_entry *rt)
260 {
261   return add_del_route(rt, 1);
262 }
263
264 int
265 olsr_ioctl_del_route(const struct rt_entry *rt)
266 {
267   return add_del_route(rt, 0);
268 }
269
270 static int
271 add_del_route6(const struct rt_entry *rt, int add)
272 {
273   struct rt_msghdr *rtm;
274   unsigned char buff[512];
275   unsigned char *walker;
276   struct sockaddr_in6 sin6;
277   struct sockaddr_dl sdl;
278   const struct rt_nexthop *nexthop;
279   int sin_size, sdl_size;
280   int len;
281
282   if (add) {
283     OLSR_PRINTF(2, "KERN: Adding %s\n", olsr_rtp_to_string(rt->rt_best));
284   } else {
285     OLSR_PRINTF(2, "KERN: Deleting %s\n", olsr_rt_to_string(rt));
286   }
287
288   memset(buff, 0, sizeof(buff));
289   memset(&sin6, 0, sizeof(sin6));
290   memset(&sdl, 0, sizeof(sdl));
291
292   sin6.sin6_len = sizeof(sin6);
293   sin6.sin6_family = AF_INET6;
294   sdl.sdl_len = sizeof(sdl);
295   sdl.sdl_family = AF_LINK;
296
297   sin_size = 1 + ((sizeof(struct sockaddr_in6) - 1) | (sizeof(long) - 1));
298   sdl_size = 1 + ((sizeof(struct sockaddr_dl) - 1) | (sizeof(long) - 1));
299
300   /**********************************************************************
301    *                  FILL THE ROUTING MESSAGE HEADER
302    **********************************************************************/
303
304   /* position header to the beginning of the buffer */
305   rtm = (struct rt_msghdr *)buff;
306   rtm->rtm_version = RTM_VERSION;
307   rtm->rtm_type = (add != 0) ? RTM_ADD : RTM_DELETE;
308   rtm->rtm_index = 0;
309   rtm->rtm_flags = olsr_rt_flags(rt, add);
310   rtm->rtm_pid = OLSR_PID;
311   rtm->rtm_seq = ++seq;
312
313   /* walk to the end of the header */
314   walker = buff + sizeof(struct rt_msghdr);
315
316   /**********************************************************************
317    *                  SET  DESTINATION OF THE ROUTE
318    **********************************************************************/
319
320   memcpy(&sin6.sin6_addr.s6_addr, &rt->rt_dst.prefix.v6, sizeof(struct in6_addr));
321   memcpy(walker, &sin6, sizeof(sin6));
322   walker += sin_size;
323   rtm->rtm_addrs = RTA_DST;
324
325   /**********************************************************************
326    *                  SET GATEWAY OF THE ROUTE
327    **********************************************************************/
328
329   nexthop = olsr_get_nh(rt);
330   if (0 != (rtm->rtm_flags & RTF_GATEWAY)) {
331     memcpy(&sin6.sin6_addr.s6_addr, &nexthop->gateway.v6, sizeof(struct in6_addr));
332     memset(&sin6.sin6_addr.s6_addr, 0, 8);
333     sin6.sin6_addr.s6_addr[0] = 0xfe;
334     sin6.sin6_addr.s6_addr[1] = 0x80;
335     sin6.sin6_scope_id = nexthop->iif_index;
336 #ifdef __KAME__
337     *(u_int16_t *) & sin6.sin6_addr.s6_addr[2] = htons(sin6.sin6_scope_id);
338     sin6.sin6_scope_id = 0;
339 #endif /* __KAME__ */
340     memcpy(walker, &sin6, sizeof(sin6));
341     walker += sin_size;
342     rtm->rtm_addrs |= RTA_GATEWAY;
343   }
344   else {
345     /*
346      * Host is directly reachable, so add
347      * the output interface MAC address.
348      */
349     memcpy(&sin6.sin6_addr.s6_addr, &rt->rt_dst.prefix.v6, sizeof(struct in6_addr));
350     memset(&sin6.sin6_addr.s6_addr, 0, 8);
351     sin6.sin6_addr.s6_addr[0] = 0xfe;
352     sin6.sin6_addr.s6_addr[1] = 0x80;
353     sin6.sin6_scope_id = nexthop->iif_index;
354 #ifdef __KAME__
355     *(u_int16_t *) & sin6.sin6_addr.s6_addr[2] = htons(sin6.sin6_scope_id);
356     sin6.sin6_scope_id = 0;
357 #endif /* __KAME__ */
358     memcpy(walker, &sin6, sizeof(sin6));
359     walker += sin_size;
360     rtm->rtm_addrs |= RTA_GATEWAY;
361     rtm->rtm_flags |= RTF_GATEWAY;
362   }
363
364   /**********************************************************************
365    *                         SET  NETMASK
366    **********************************************************************/
367
368   if (0 == (rtm->rtm_flags & RTF_HOST)) {
369     olsr_prefix_to_netmask((union olsr_ip_addr *)&sin6.sin6_addr, rt->rt_dst.prefix_len);
370     memcpy(walker, &sin6, sizeof(sin6));
371     walker += sin_size;
372     rtm->rtm_addrs |= RTA_NETMASK;
373   }
374
375   /**********************************************************************
376    *           WRITE CONFIGURATION MESSAGE TO THE ROUTING SOCKET
377    **********************************************************************/
378
379   rtm->rtm_msglen = (unsigned short)(walker - buff);
380   len = write(olsr_cnf->rts, buff, rtm->rtm_msglen);
381   if (len < 0 && !(errno == EEXIST || errno == ESRCH)) {
382     fprintf(stderr, "cannot write to routing socket: %s\n", strerror(errno));
383   }
384
385   /*
386    * If we get an EEXIST error while adding, delete and retry.
387    */
388   if (len < 0 && errno == EEXIST && rtm->rtm_type == RTM_ADD) {
389     struct rt_msghdr *drtm;
390     unsigned char dbuff[512];
391
392     memset(dbuff, 0, sizeof(dbuff));
393     drtm = (struct rt_msghdr *)dbuff;
394     drtm->rtm_version = RTM_VERSION;
395     drtm->rtm_type = RTM_DELETE;
396     drtm->rtm_index = 0;
397     drtm->rtm_flags = olsr_rt_flags(rt, add);
398     drtm->rtm_seq = ++seq;
399
400     walker = dbuff + sizeof(struct rt_msghdr);
401     memcpy(&sin6.sin6_addr.s6_addr, &rt->rt_dst.prefix.v6, sizeof(struct in6_addr));
402     memcpy(walker, &sin6, sizeof(sin6));
403     walker += sin_size;
404     drtm->rtm_addrs = RTA_DST;
405     if (0 == (drtm->rtm_flags & RTF_HOST)) {
406       olsr_prefix_to_netmask((union olsr_ip_addr *)&sin6.sin6_addr, rt->rt_dst.prefix_len);
407       memcpy(walker, &sin6, sizeof(sin6));
408       walker += sin_size;
409       drtm->rtm_addrs |= RTA_NETMASK;
410     }
411     drtm->rtm_msglen = (unsigned short)(walker - dbuff);
412     len = write(olsr_cnf->rts, dbuff, drtm->rtm_msglen);
413     if (len < 0) {
414       fprintf(stderr, "cannot delete route: %s\n", strerror(errno));
415     }
416     rtm->rtm_seq = ++seq;
417     len = write(olsr_cnf->rts, buff, rtm->rtm_msglen);
418     if (len < 0) {
419       fprintf(stderr, "still cannot add route: %s\n", strerror(errno));
420     }
421   }
422   return 0;
423 }
424
425 int
426 olsr_ioctl_add_route6(const struct rt_entry *rt)
427 {
428   return add_del_route6(rt, 1);
429 }
430
431 int
432 olsr_ioctl_del_route6(const struct rt_entry *rt)
433 {
434   return add_del_route6(rt, 0);
435 }
436
437 /*
438  * Local Variables:
439  * c-basic-offset: 2
440  * indent-tabs-mode: nil
441  * End:
442  */