From Lorenz Shori <lorenz.schori@gmx.ch>: Mac OSX fixes
[olsrd.git] / src / bsd / kernel_routes.c
1 /*
2  * The olsr.org Optimized Link-State Routing daemon(olsrd)
3  * Copyright (c) 2004, Thomas Lopatic (thomas@lopatic.de)
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without 
7  * modification, are permitted provided that the following conditions 
8  * are met:
9  *
10  * * Redistributions of source code must retain the above copyright 
11  *   notice, this list of conditions and the following disclaimer.
12  * * Redistributions in binary form must reproduce the above copyright 
13  *   notice, this list of conditions and the following disclaimer in 
14  *   the documentation and/or other materials provided with the 
15  *   distribution.
16  * * Neither the name of olsr.org, olsrd nor the names of its 
17  *   contributors may be used to endorse or promote products derived 
18  *   from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
23  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
24  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
26  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
27  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
28  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
30  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
31  * POSSIBILITY OF SUCH DAMAGE.
32  *
33  * Visit http://www.olsr.org for more information.
34  *
35  * If you find this software useful feel free to make a donation
36  * to the project. For more information see the website or contact
37  * the copyright holders.
38  *
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 static unsigned int seq = 0;
53
54 static int add_del_route(const struct rt_entry *rt, int add)
55 {
56   struct rt_msghdr *rtm;
57   unsigned char buff[512];
58   unsigned char *walker;
59   struct sockaddr_in sin;
60   struct sockaddr_dl *sdl;
61   struct ifaddrs *addrs;
62   struct ifaddrs *awalker;
63   const struct rt_nexthop *nexthop;
64   union olsr_ip_addr mask;
65   int step, step2;
66   int len;
67   int flags;
68
69   if (add) {
70       OLSR_PRINTF(2, "KERN: Adding %s\n", olsr_rtp_to_string(rt->rt_best));
71   } else {
72       OLSR_PRINTF(2, "KERN: Deleting %s\n", olsr_rt_to_string(rt));
73   }
74
75   memset(buff, 0, sizeof (buff));
76   memset(&sin, 0, sizeof (sin));
77
78   sin.sin_len = sizeof (sin);
79   sin.sin_family = AF_INET;
80
81   step = 1 + ((sizeof (struct sockaddr_in) - 1) | 3);
82   step2 = 1 + ((sizeof (struct sockaddr_dl) - 1) | 3);
83
84   rtm = (struct rt_msghdr *)buff;
85
86   flags = olsr_rt_flags(rt);
87
88   // the host is directly reachable, so use cloning and a /32 net
89   // routing table entry
90
91   if ((flags & RTF_GATEWAY) == 0)
92   {
93     flags |= RTF_CLONING;
94     flags &= ~RTF_HOST;
95   }
96
97   rtm->rtm_version = RTM_VERSION;
98   rtm->rtm_type = (add != 0) ? RTM_ADD : RTM_DELETE;
99   rtm->rtm_index = 0;
100   rtm->rtm_flags = flags;
101   rtm->rtm_addrs = RTA_DST | RTA_NETMASK | RTA_GATEWAY;
102   rtm->rtm_seq = ++seq;
103
104   walker = buff + sizeof (struct rt_msghdr);
105
106   sin.sin_addr = rt->rt_dst.prefix.v4;
107
108   memcpy(walker, &sin, sizeof (sin));
109   walker += step;
110
111   nexthop = olsr_get_nh(rt);
112   if ((flags & RTF_GATEWAY) != 0)
113   {
114     sin.sin_addr = nexthop->gateway.v4;
115
116     memcpy(walker, &sin, sizeof (sin));
117     walker += step;
118   }
119
120   // the host is directly reachable, so add the output interface's
121   // MAC address
122
123   else
124   {
125     if (getifaddrs(&addrs))
126     {
127       fprintf(stderr, "getifaddrs() failed\n");
128       return -1;
129     }
130
131     for (awalker = addrs; awalker != NULL; awalker = awalker->ifa_next)
132       if (awalker->ifa_addr->sa_family == AF_LINK &&
133           strcmp(awalker->ifa_name, if_ifwithindex_name(nexthop->iif_index)) == 0)
134         break;
135
136     if (awalker == NULL)
137     {
138       fprintf(stderr, "interface %s not found\n", if_ifwithindex_name(nexthop->iif_index));
139       freeifaddrs(addrs);
140       return -1;
141     }
142
143     sdl = (struct sockaddr_dl *)awalker->ifa_addr;
144
145     memcpy(walker, sdl, sdl->sdl_len);
146     walker += step2;
147
148     freeifaddrs(addrs);
149   }
150
151   if (!olsr_prefix_to_netmask(&mask, rt->rt_dst.prefix_len)) {
152     return -1;
153   }
154   sin.sin_addr = mask.v4;
155
156   memcpy(walker, &sin, sizeof (sin));
157   walker += step;
158
159   rtm->rtm_msglen = (unsigned short)(walker - buff);
160
161   len = write(olsr_cnf->rts, buff, rtm->rtm_msglen);
162
163   if (len < rtm->rtm_msglen)
164     fprintf(stderr, "cannot write to routing socket: %s\n", strerror(errno));
165
166   return 0;
167 }
168
169 int olsr_ioctl_add_route(const struct rt_entry *rt)
170 {
171   return add_del_route(rt, 1);
172 }
173
174 int olsr_ioctl_del_route(const struct rt_entry *rt)
175 {
176   return add_del_route(rt, 0);
177 }
178
179 static int add_del_route6(const struct rt_entry *rt, int add)
180 {
181   struct rt_msghdr *rtm;
182   unsigned char buff[512];
183   unsigned char *walker;
184   struct sockaddr_in6 sin6;
185   struct sockaddr_dl sdl;
186   const struct rt_nexthop *nexthop;
187   int step, step_dl;
188   int len;
189
190   if (add) {
191       OLSR_PRINTF(2, "KERN: Adding %s\n", olsr_rtp_to_string(rt->rt_best));
192   } else {
193       OLSR_PRINTF(2, "KERN: Deleting %s\n", olsr_rt_to_string(rt));
194   }
195
196   memset(buff, 0, sizeof (buff));
197   memset(&sin6, 0, sizeof (sin6));
198   memset(&sdl, 0, sizeof (sdl));
199
200   sin6.sin6_len = sizeof (sin6);
201   sin6.sin6_family = AF_INET6;
202   sdl.sdl_len = sizeof (sdl);
203   sdl.sdl_family = AF_LINK;
204
205   step = 1 + ((sizeof (struct sockaddr_in6) - 1) | 3);
206   step_dl = 1 + ((sizeof (struct sockaddr_dl) - 1) | 3);
207
208   rtm = (struct rt_msghdr *)buff;
209   rtm->rtm_version = RTM_VERSION;
210   rtm->rtm_type = (add != 0) ? RTM_ADD : RTM_DELETE;
211   rtm->rtm_index = 0;
212   rtm->rtm_flags = olsr_rt_flags(rt);
213   rtm->rtm_addrs = RTA_DST | RTA_GATEWAY;
214   rtm->rtm_seq = ++seq;
215
216   walker = buff + sizeof (struct rt_msghdr);
217
218   memcpy(&sin6.sin6_addr.s6_addr, &rt->rt_dst.prefix.v6, sizeof(struct in6_addr));
219
220   memcpy(walker, &sin6, sizeof (sin6));
221   walker += step;
222
223   nexthop = olsr_get_nh(rt);
224   if ((rtm->rtm_flags & RTF_GATEWAY) != 0)
225   {
226     memcpy(&sin6.sin6_addr.s6_addr, &nexthop->gateway.v6, sizeof(struct in6_addr));
227
228     memset(&sin6.sin6_addr.s6_addr, 0, 8);
229     sin6.sin6_addr.s6_addr[0] = 0xfe;
230     sin6.sin6_addr.s6_addr[1] = 0x80;
231     sin6.sin6_scope_id = nexthop->iif_index;
232 #ifdef __KAME__
233     *(u_int16_t *)&sin6.sin6_addr.s6_addr[2] = htons(sin6.sin6_scope_id);
234     sin6.sin6_scope_id = 0;
235 #endif
236     memcpy(walker, &sin6, sizeof (sin6));
237     walker += step;
238   }
239
240   // the host is directly reachable, so add the output interface's address
241
242   else
243   {
244     memcpy(&sin6.sin6_addr.s6_addr,  &rt->rt_dst.prefix.v6, sizeof(struct in6_addr));
245     memset(&sin6.sin6_addr.s6_addr, 0, 8);
246     sin6.sin6_addr.s6_addr[0] = 0xfe;
247     sin6.sin6_addr.s6_addr[1] = 0x80;
248     sin6.sin6_scope_id = nexthop->iif_index;
249 #ifdef __KAME__
250     *(u_int16_t *)&sin6.sin6_addr.s6_addr[2] = htons(sin6.sin6_scope_id);
251     sin6.sin6_scope_id = 0;
252 #endif
253
254     memcpy(walker, &sin6, sizeof (sin6));
255     walker += step;
256     rtm->rtm_flags |= RTF_GATEWAY;
257   }
258
259   if ((rtm->rtm_flags & RTF_HOST) == 0)
260   {
261     olsr_prefix_to_netmask((union olsr_ip_addr *)&sin6.sin6_addr, rt->rt_dst.prefix_len);
262     memcpy(walker, &sin6, sizeof (sin6));
263     walker += step;
264     rtm->rtm_addrs |= RTA_NETMASK;
265   }
266
267   rtm->rtm_msglen = (unsigned short)(walker - buff);
268
269   len = write(olsr_cnf->rts, buff, rtm->rtm_msglen);
270   if (len < 0 && !(errno == EEXIST || errno == ESRCH))
271     fprintf(stderr, "cannot write to routing socket: %s\n", strerror(errno));
272
273   /* If we get an EEXIST error while adding, delete and retry. */
274   if (len < 0 && errno == EEXIST && rtm->rtm_type == RTM_ADD) {
275     struct rt_msghdr *drtm;
276     unsigned char dbuff[512];
277
278     memset(dbuff, 0, sizeof (dbuff));
279     drtm = (struct rt_msghdr *)dbuff;
280     drtm->rtm_version = RTM_VERSION;
281     drtm->rtm_type = RTM_DELETE;
282     drtm->rtm_addrs = RTA_DST;
283     drtm->rtm_index = 0;
284     drtm->rtm_flags = olsr_rt_flags(rt);
285     drtm->rtm_seq = ++seq;
286
287     walker = dbuff + sizeof (struct rt_msghdr);
288     memcpy(&sin6.sin6_addr.s6_addr, &rt->rt_dst.prefix.v6,
289         sizeof(struct in6_addr));
290     memcpy(walker, &sin6, sizeof (sin6));
291     walker += step;
292     drtm->rtm_msglen = (unsigned short)(walker - dbuff);
293     len = write(olsr_cnf->rts, dbuff, drtm->rtm_msglen);
294     if (len < 0)
295       fprintf(stderr, "cannot delete route: %s\n", strerror(errno));
296     rtm->rtm_seq = ++seq;
297     len = write(olsr_cnf->rts, buff, rtm->rtm_msglen);
298     if (len < 0)
299       fprintf(stderr, "still cannot add route: %s\n", strerror(errno));
300   }
301
302   return 0;
303 }
304
305 int olsr_ioctl_add_route6(const struct rt_entry *rt)
306 {
307   return add_del_route6(rt, 1);
308 }
309
310 int olsr_ioctl_del_route6(const struct rt_entry *rt)
311 {
312   return add_del_route6(rt, 0);
313 }
314
315 /*
316  * Local Variables:
317  * c-basic-offset: 2
318  * End:
319  */