ec986fffa4b3ea0ccffb01ae09a727fd2827732d
[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
48 #include <net/if_dl.h>
49 #include <ifaddrs.h>
50
51 static unsigned int seq = 0;
52
53 static int add_del_route(const struct rt_entry *rt, int add)
54 {
55   struct rt_msghdr *rtm;
56   unsigned char buff[512];
57   unsigned char *walker;
58   struct sockaddr_in sin;
59   struct sockaddr_dl *sdl;
60   struct ifaddrs *addrs;
61   struct ifaddrs *awalker;
62   const struct rt_nexthop *nexthop;
63   union olsr_ip_addr mask;
64   int step, step2;
65   int len;
66   int flags;
67
68   if (add) {
69       OLSR_PRINTF(2, "KERN: Adding %s\n", olsr_rtp_to_string(rt->rt_best));
70   } else {
71       OLSR_PRINTF(2, "KERN: Deleting %s\n", olsr_rt_to_string(rt));
72   }
73
74   memset(buff, 0, sizeof (buff));
75   memset(&sin, 0, sizeof (sin));
76
77   sin.sin_len = sizeof (sin);
78   sin.sin_family = AF_INET;
79
80   step = 1 + ((sizeof (struct sockaddr_in) - 1) | 3);
81   step2 = 1 + ((sizeof (struct sockaddr_dl) - 1) | 3);
82
83   rtm = (struct rt_msghdr *)buff;
84
85   flags = olsr_rt_flags(rt);
86
87   // the host is directly reachable, so use cloning and a /32 net
88   // routing table entry
89
90   if ((flags & RTF_GATEWAY) == 0)
91   {
92     flags |= RTF_CLONING;
93     flags &= ~RTF_HOST;
94   }
95
96   rtm->rtm_version = RTM_VERSION;
97   rtm->rtm_type = (add != 0) ? RTM_ADD : RTM_DELETE;
98   rtm->rtm_index = 0;
99   rtm->rtm_flags = flags;
100   rtm->rtm_addrs = RTA_DST | RTA_NETMASK | RTA_GATEWAY;
101   rtm->rtm_seq = ++seq;
102
103   walker = buff + sizeof (struct rt_msghdr);
104
105   sin.sin_addr = rt->rt_dst.prefix.v4;
106
107   memcpy(walker, &sin, sizeof (sin));
108   walker += step;
109
110   nexthop = olsr_get_nh(rt);
111   if ((flags & RTF_GATEWAY) != 0)
112   {
113     sin.sin_addr = nexthop->gateway.v4;
114
115     memcpy(walker, &sin, sizeof (sin));
116     walker += step;
117   }
118
119   // the host is directly reachable, so add the output interface's
120   // MAC address
121
122   else
123   {
124     if (getifaddrs(&addrs))
125     {
126       fprintf(stderr, "getifaddrs() failed\n");
127       return -1;
128     }
129
130     for (awalker = addrs; awalker != NULL; awalker = awalker->ifa_next)
131       if (awalker->ifa_addr->sa_family == AF_LINK &&
132           strcmp(awalker->ifa_name, if_ifwithindex_name(nexthop->iif_index)) == 0)
133         break;
134
135     if (awalker == NULL)
136     {
137       fprintf(stderr, "interface %s not found\n", if_ifwithindex_name(nexthop->iif_index));
138       freeifaddrs(addrs);
139       return -1;
140     }
141
142     sdl = (struct sockaddr_dl *)awalker->ifa_addr;
143
144     memcpy(walker, sdl, sdl->sdl_len);
145     walker += step2;
146
147     freeifaddrs(addrs);
148   }
149
150   if (!olsr_prefix_to_netmask(&mask, rt->rt_dst.prefix_len)) {
151     return -1;
152   }
153   sin.sin_addr = mask.v4;
154
155   memcpy(walker, &sin, sizeof (sin));
156   walker += step;
157
158   rtm->rtm_msglen = (unsigned short)(walker - buff);
159
160   len = write(olsr_cnf->rts, buff, rtm->rtm_msglen);
161
162   if (len < rtm->rtm_msglen)
163     fprintf(stderr, "cannot write to routing socket: %s\n", strerror(errno));
164
165   return 0;
166 }
167
168 int olsr_ioctl_add_route(const struct rt_entry *rt)
169 {
170   return add_del_route(rt, 1);
171 }
172
173 int olsr_ioctl_del_route(const struct rt_entry *rt)
174 {
175   return add_del_route(rt, 0);
176 }
177
178 static int add_del_route6(const struct rt_entry *rt, int add)
179 {
180   struct rt_msghdr *rtm;
181   unsigned char buff[512];
182   unsigned char *walker;
183   struct sockaddr_in6 sin6;
184   struct sockaddr_dl sdl;
185   const struct rt_nexthop *nexthop;
186   int step, step_dl;
187   int len;
188
189   if (add) {
190       OLSR_PRINTF(2, "KERN: Adding %s\n", olsr_rtp_to_string(rt->rt_best));
191   } else {
192       OLSR_PRINTF(2, "KERN: Deleting %s\n", olsr_rt_to_string(rt));
193   }
194
195   memset(buff, 0, sizeof (buff));
196   memset(&sin6, 0, sizeof (sin6));
197   memset(&sdl, 0, sizeof (sdl));
198
199   sin6.sin6_len = sizeof (sin6);
200   sin6.sin6_family = AF_INET6;
201   sdl.sdl_len = sizeof (sdl);
202   sdl.sdl_family = AF_LINK;
203
204   step = 1 + ((sizeof (struct sockaddr_in6) - 1) | 3);
205   step_dl = 1 + ((sizeof (struct sockaddr_dl) - 1) | 3);
206
207   rtm = (struct rt_msghdr *)buff;
208   rtm->rtm_version = RTM_VERSION;
209   rtm->rtm_type = (add != 0) ? RTM_ADD : RTM_DELETE;
210   rtm->rtm_index = 0;
211   rtm->rtm_flags = olsr_rt_flags(rt);
212   rtm->rtm_addrs = RTA_DST | RTA_GATEWAY;
213   rtm->rtm_seq = ++seq;
214
215   walker = buff + sizeof (struct rt_msghdr);
216
217   memcpy(&sin6.sin6_addr.s6_addr, &rt->rt_dst.prefix.v6, sizeof(struct in6_addr));
218
219   memcpy(walker, &sin6, sizeof (sin6));
220   walker += step;
221
222   nexthop = olsr_get_nh(rt);
223   if ((rtm->rtm_flags & RTF_GATEWAY) != 0)
224   {
225     memcpy(&sin6.sin6_addr.s6_addr, &nexthop->gateway.v6, sizeof(struct in6_addr));
226
227     memset(&sin6.sin6_addr.s6_addr, 0, 8);
228     sin6.sin6_addr.s6_addr[0] = 0xfe;
229     sin6.sin6_addr.s6_addr[1] = 0x80;
230     sin6.sin6_scope_id = nexthop->iif_index;
231 #ifdef __KAME__
232     *(u_int16_t *)&sin6.sin6_addr.s6_addr[2] = htons(sin6.sin6_scope_id);
233     sin6.sin6_scope_id = 0;
234 #endif
235     memcpy(walker, &sin6, sizeof (sin6));
236     walker += step;
237   }
238
239   // the host is directly reachable, so add the output interface's address
240
241   else
242   {
243     memcpy(&sin6.sin6_addr.s6_addr,  &rt->rt_dst.prefix.v6, sizeof(struct in6_addr));
244     memset(&sin6.sin6_addr.s6_addr, 0, 8);
245     sin6.sin6_addr.s6_addr[0] = 0xfe;
246     sin6.sin6_addr.s6_addr[1] = 0x80;
247     sin6.sin6_scope_id = nexthop->iif_index;
248 #ifdef __KAME__
249     *(u_int16_t *)&sin6.sin6_addr.s6_addr[2] = htons(sin6.sin6_scope_id);
250     sin6.sin6_scope_id = 0;
251 #endif
252
253     memcpy(walker, &sin6, sizeof (sin6));
254     walker += step;
255     rtm->rtm_flags |= RTF_GATEWAY;
256   }
257
258   if ((rtm->rtm_flags & RTF_HOST) == 0)
259   {
260     olsr_prefix_to_netmask((union olsr_ip_addr *)&sin6.sin6_addr, rt->rt_dst.prefix_len);
261     memcpy(walker, &sin6, sizeof (sin6));
262     walker += step;
263     rtm->rtm_addrs |= RTA_NETMASK;
264   }
265
266   rtm->rtm_msglen = (unsigned short)(walker - buff);
267
268   len = write(olsr_cnf->rts, buff, rtm->rtm_msglen);
269   if (len < 0 && !(errno == EEXIST || errno == ESRCH))
270     fprintf(stderr, "cannot write to routing socket: %s\n", strerror(errno));
271
272   /* If we get an EEXIST error while adding, delete and retry. */
273   if (len < 0 && errno == EEXIST && rtm->rtm_type == RTM_ADD) {
274     struct rt_msghdr *drtm;
275     unsigned char dbuff[512];
276
277     memset(dbuff, 0, sizeof (dbuff));
278     drtm = (struct rt_msghdr *)dbuff;
279     drtm->rtm_version = RTM_VERSION;
280     drtm->rtm_type = RTM_DELETE;
281     drtm->rtm_addrs = RTA_DST;
282     drtm->rtm_index = 0;
283     drtm->rtm_flags = olsr_rt_flags(rt);
284     drtm->rtm_seq = ++seq;
285
286     walker = dbuff + sizeof (struct rt_msghdr);
287     memcpy(&sin6.sin6_addr.s6_addr, &rt->rt_dst.prefix.v6,
288         sizeof(struct in6_addr));
289     memcpy(walker, &sin6, sizeof (sin6));
290     walker += step;
291     drtm->rtm_msglen = (unsigned short)(walker - dbuff);
292     len = write(olsr_cnf->rts, dbuff, drtm->rtm_msglen);
293     if (len < 0)
294       fprintf(stderr, "cannot delete route: %s\n", strerror(errno));
295     rtm->rtm_seq = ++seq;
296     len = write(olsr_cnf->rts, buff, rtm->rtm_msglen);
297     if (len < 0)
298       fprintf(stderr, "still cannot add route: %s\n", strerror(errno));
299   }
300
301   return 0;
302 }
303
304 int olsr_ioctl_add_route6(const struct rt_entry *rt)
305 {
306   return add_del_route6(rt, 1);
307 }
308
309 int olsr_ioctl_del_route6(const struct rt_entry *rt)
310 {
311   return add_del_route6(rt, 0);
312 }
313
314 /*
315  * Local Variables:
316  * c-basic-offset: 2
317  * End:
318  */