* applied rt-refactoring-6.diff from Hannes Gredler <hannes@gredler.at>
[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  * $Id: kernel_routes.c,v 1.12 2007/09/05 16:11:11 bernd67 Exp $
40  */
41
42
43 #include "kernel_routes.h"
44 #include "olsr.h"
45 #include "defs.h"
46
47 #include <net/if_dl.h>
48 #include <ifaddrs.h>
49
50 static unsigned int seq = 0;
51
52 static int add_del_route(struct rt_entry *rt, int add)
53 {
54   struct rt_msghdr *rtm;
55   unsigned char buff[512];
56   unsigned char *walker;
57   struct sockaddr_in sin;
58   struct sockaddr_dl *sdl;
59   struct ifaddrs *addrs;
60   struct ifaddrs *awalker;
61   struct rt_nexthop *nexthop;
62   union olsr_ip_addr mask;
63   int step, step2;
64   int len;
65   int flags;
66
67   if (add) {
68       OLSR_PRINTF(2, "KERN: Adding %s\n", olsr_rtp_to_string(rt->rt_best));
69   } else {
70       OLSR_PRINTF(2, "KERN: Deleting %s\n", olsr_rt_to_string(rt));
71   }
72
73   memset(buff, 0, sizeof (buff));
74   memset(&sin, 0, sizeof (sin));
75
76   sin.sin_len = sizeof (sin);
77   sin.sin_family = AF_INET;
78
79   step = 1 + ((sizeof (struct sockaddr_in) - 1) | 3);
80   step2 = 1 + ((sizeof (struct sockaddr_dl) - 1) | 3);
81
82   rtm = (struct rt_msghdr *)buff;
83
84   flags = olsr_rt_flags(rt);
85
86   // the host is directly reachable, so use cloning and a /32 net
87   // routing table entry
88
89   if ((flags & RTF_GATEWAY) == 0)
90   {
91     flags |= RTF_CLONING;
92     flags &= ~RTF_HOST;
93   }
94
95   rtm->rtm_version = RTM_VERSION;
96   rtm->rtm_type = (add != 0) ? RTM_ADD : RTM_DELETE;
97   rtm->rtm_index = 0;
98   rtm->rtm_flags = flags;
99   rtm->rtm_addrs = RTA_DST | RTA_NETMASK | RTA_GATEWAY;
100   rtm->rtm_seq = ++seq;
101
102   walker = buff + sizeof (struct rt_msghdr);
103
104   sin.sin_addr.s_addr = rt->rt_dst.prefix.v4;
105
106   memcpy(walker, &sin, sizeof (sin));
107   walker += step;
108
109   nexthop = olsr_get_nh(rt);
110   if ((flags & RTF_GATEWAY) != 0)
111   {
112     sin.sin_addr.s_addr = nexthop->gateway.v4;
113
114     memcpy(walker, &sin, sizeof (sin));
115     walker += step;
116   }
117
118   // the host is directly reachable, so add the output interface's
119   // MAC address
120
121   else
122   {
123     if (getifaddrs(&addrs))
124     {
125       fprintf(stderr, "getifaddrs() failed\n");
126       return -1;
127     }
128
129     for (awalker = addrs; awalker != NULL; awalker = awalker->ifa_next)
130       if (awalker->ifa_addr->sa_family == AF_LINK &&
131           strcmp(awalker->ifa_name, nexthop->iface->int_name) == 0)
132         break;
133
134     if (awalker == NULL)
135     {
136       fprintf(stderr, "interface %s not found\n", nexthop->iface->int_name);
137       freeifaddrs(addrs);
138       return -1;
139     }
140
141     sdl = (struct sockaddr_dl *)awalker->ifa_addr;
142
143     memcpy(walker, sdl, sdl->sdl_len);
144     walker += step2;
145
146     freeifaddrs(addrs);
147   }
148
149   if (!olsr_prefix_to_netmask(&mask, rt->rt_dst.prefix_len)) {
150     return -1;
151   }
152   sin.sin_addr.s_addr = mask.v4;
153
154   memcpy(walker, &sin, sizeof (sin));
155   walker += step;
156
157   rtm->rtm_msglen = (unsigned short)(walker - buff);
158
159   len = write(olsr_cnf->rts, buff, rtm->rtm_msglen);
160
161   if (len < rtm->rtm_msglen)
162     fprintf(stderr, "cannot write to routing socket: %s\n", strerror(errno));
163
164   return 0;
165 }
166
167 int olsr_ioctl_add_route(struct rt_entry *rt)
168 {
169   return add_del_route(rt, 1);
170 }
171
172 int olsr_ioctl_del_route(struct rt_entry *rt)
173 {
174   return add_del_route(rt, 0);
175 }
176
177 static int add_del_route6(struct rt_entry *rt, int add)
178 {
179   struct rt_msghdr *rtm;
180   unsigned char buff[512];
181   unsigned char *walker;
182   struct sockaddr_in6 sin6;
183   struct sockaddr_dl sdl;
184   struct rt_nexthop *nexthop;
185   int step, step_dl;
186   int len;
187
188   if (add) {
189       OLSR_PRINTF(2, "KERN: Adding %s\n", olsr_rtp_to_string(rt->rt_best));
190   } else {
191       OLSR_PRINTF(2, "KERN: Deleting %s\n", olsr_rt_to_string(rt));
192   }
193
194   memset(buff, 0, sizeof (buff));
195   memset(&sin6, 0, sizeof (sin6));
196   memset(&sdl, 0, sizeof (sdl));
197
198   sin6.sin6_len = sizeof (sin6);
199   sin6.sin6_family = AF_INET6;
200   sdl.sdl_len = sizeof (sdl);
201   sdl.sdl_family = AF_LINK;
202
203   step = 1 + ((sizeof (struct sockaddr_in6) - 1) | 3);
204   step_dl = 1 + ((sizeof (struct sockaddr_dl) - 1) | 3);
205
206   rtm = (struct rt_msghdr *)buff;
207   rtm->rtm_version = RTM_VERSION;
208   rtm->rtm_type = (add != 0) ? RTM_ADD : RTM_DELETE;
209   rtm->rtm_index = 0;
210   rtm->rtm_flags = olsr_rt_flags(rt);
211   rtm->rtm_addrs = RTA_DST | RTA_GATEWAY;
212   rtm->rtm_seq = ++seq;
213
214   walker = buff + sizeof (struct rt_msghdr);
215
216   memcpy(&sin6.sin6_addr.s6_addr, &rt->rt_dst.prefix.v6, sizeof(struct in6_addr));
217
218   memcpy(walker, &sin6, sizeof (sin6));
219   walker += step;
220
221   nexthop = olsr_get_nh(rt);
222   if ((rtm->rtm_flags & RTF_GATEWAY) != 0)
223   {
224     memcpy(&sin6.sin6_addr.s6_addr, &nexthop->gateway.v6, sizeof(struct in6_addr));
225
226     memcpy(walker, &sin6, sizeof (sin6));
227     walker += step;
228   }
229
230   // the host is directly reachable, so add the output interface's address
231
232   else
233   {
234     memcpy(&sin6.sin6_addr.s6_addr, &nexthop->iface->int6_addr.sin6_addr.s6_addr,
235       sizeof(struct in6_addr));
236
237     memcpy(walker, &sin6, sizeof (sin6));
238     walker += step;
239     rtm->rtm_flags |= RTF_LLINFO;
240   }
241
242   if ((rtm->rtm_flags & RTF_HOST) == 0)
243   {
244     olsr_prefix_to_netmask((union olsr_ip_addr *)&sin6.sin6_addr, rt->rt_dst.prefix_len);
245     memcpy(walker, &sin6, sizeof (sin6));
246     walker += step;
247     rtm->rtm_addrs |= RTA_NETMASK;
248   }
249
250   if ((rtm->rtm_flags & RTF_GATEWAY) != 0)
251   {
252     strcpy(&sdl.sdl_data[0], nexthop->iface->int_name);
253     sdl.sdl_nlen = (u_char)strlen(nexthop->iface->int_name);
254     memcpy(walker, &sdl, sizeof (sdl));
255     walker += step_dl;
256     rtm->rtm_addrs |= RTA_IFP;
257   }
258
259   rtm->rtm_msglen = (unsigned short)(walker - buff);
260
261   len = write(olsr_cnf->rts, buff, rtm->rtm_msglen);
262
263   if (len < rtm->rtm_msglen)
264     fprintf(stderr, "cannot write to routing socket: %s\n", strerror(errno));
265
266   return 0;
267 }
268
269 int olsr_ioctl_add_route6(struct rt_entry *rt)
270 {
271   return add_del_route6(rt, 1);
272 }
273
274 int olsr_ioctl_del_route6(struct rt_entry *rt)
275 {
276   return add_del_route6(rt, 0);
277 }
278
279 /*
280  * Local Variables:
281  * c-basic-offset: 2
282  * End:
283  */