6918189aff904216ba89d909f3dce3d15dc5bd9c
[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.11 2007/05/02 07:41:20 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 *dest, 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   int step, step2;
62   int len;
63   char Str1[16], Str2[16], Str3[16];
64   int flags;
65
66   inet_ntop(AF_INET, &dest->rt_dst.v4, Str1, 16);
67   inet_ntop(AF_INET, &dest->rt_mask.v4, Str2, 16);
68   inet_ntop(AF_INET, &dest->rt_router.v4, Str3, 16);
69
70   OLSR_PRINTF(1, "%s IPv4 route to %s/%s via %s.\n",
71     (add != 0) ? "Adding" : "Removing", Str1, Str2, Str3);
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 = dest->rt_flags;
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 = dest->rt_dst.v4;
105
106   memcpy(walker, &sin, sizeof (sin));
107   walker += step;
108
109   if ((flags & RTF_GATEWAY) != 0)
110   {
111     sin.sin_addr.s_addr = dest->rt_router.v4;
112
113     memcpy(walker, &sin, sizeof (sin));
114     walker += step;
115   }
116
117   // the host is directly reachable, so add the output interface's
118   // MAC address
119
120   else
121   {
122     if (getifaddrs(&addrs))
123     {
124       fprintf(stderr, "getifaddrs() failed\n");
125       return -1;
126     }
127
128     for (awalker = addrs; awalker != NULL; awalker = awalker->ifa_next)
129       if (awalker->ifa_addr->sa_family == AF_LINK &&
130           strcmp(awalker->ifa_name, dest->rt_if->int_name) == 0)
131         break;
132
133     if (awalker == NULL)
134     {
135       fprintf(stderr, "interface %s not found\n", dest->rt_if->int_name);
136       freeifaddrs(addrs);
137       return -1;
138     }
139
140     sdl = (struct sockaddr_dl *)awalker->ifa_addr;
141
142     memcpy(walker, sdl, sdl->sdl_len);
143     walker += step2;
144
145     freeifaddrs(addrs);
146   }
147
148   sin.sin_addr.s_addr = dest->rt_mask.v4;
149
150   memcpy(walker, &sin, sizeof (sin));
151   walker += step;
152
153   rtm->rtm_msglen = (unsigned short)(walker - buff);
154
155   len = write(olsr_cnf->rts, buff, rtm->rtm_msglen);
156
157   if (len < rtm->rtm_msglen)
158     fprintf(stderr, "cannot write to routing socket: %s\n", strerror(errno));
159
160   return 0;
161 }
162
163 int olsr_ioctl_add_route(struct rt_entry *dest)
164 {
165   return add_del_route(dest, 1);
166 }
167
168 int olsr_ioctl_del_route(struct rt_entry *dest)
169 {
170   return add_del_route(dest, 0);
171 }
172
173 static int add_del_route6(struct rt_entry *dest, int add)
174 {
175   struct rt_msghdr *rtm;
176   unsigned char buff[512];
177   unsigned char *walker;
178   struct sockaddr_in6 sin6;
179   struct sockaddr_dl sdl;
180   int step, step_dl;
181   int len;
182   char Str1[40], Str2[40];
183
184   inet_ntop(AF_INET6, &dest->rt_dst.v6, Str1, 40);
185   inet_ntop(AF_INET6, &dest->rt_router.v6, Str2, 40);
186
187   OLSR_PRINTF(1, "%s IPv6 route to %s/%d via %s.\n", 
188     (add != 0) ? "Adding" : "Removing", Str1, dest->rt_mask.v6, Str2);
189
190   memset(buff, 0, sizeof (buff));
191   memset(&sin6, 0, sizeof (sin6));
192   memset(&sdl, 0, sizeof (sdl));
193
194   sin6.sin6_len = sizeof (sin6);
195   sin6.sin6_family = AF_INET6;
196   sdl.sdl_len = sizeof (sdl);
197   sdl.sdl_family = AF_LINK;
198
199   step = 1 + ((sizeof (struct sockaddr_in6) - 1) | 3);
200   step_dl = 1 + ((sizeof (struct sockaddr_dl) - 1) | 3);
201
202   rtm = (struct rt_msghdr *)buff;
203   rtm->rtm_version = RTM_VERSION;
204   rtm->rtm_type = (add != 0) ? RTM_ADD : RTM_DELETE;
205   rtm->rtm_index = 0;
206   rtm->rtm_flags = dest->rt_flags;
207   rtm->rtm_addrs = RTA_DST | RTA_GATEWAY;
208   rtm->rtm_seq = ++seq;
209
210   walker = buff + sizeof (struct rt_msghdr);
211
212   memcpy(&sin6.sin6_addr.s6_addr, &dest->rt_dst.v6, sizeof(struct in6_addr));
213
214   memcpy(walker, &sin6, sizeof (sin6));
215   walker += step;
216
217   if ((rtm->rtm_flags & RTF_GATEWAY) != 0)
218   {
219     memcpy(&sin6.sin6_addr.s6_addr, &dest->rt_router.v6, sizeof(struct in6_addr));
220
221     memcpy(walker, &sin6, sizeof (sin6));
222     walker += step;
223   }
224
225   // the host is directly reachable, so add the output interface's address
226
227   else
228   {
229     memcpy(&sin6.sin6_addr.s6_addr, &dest->rt_if->int6_addr.sin6_addr.s6_addr,
230       sizeof(struct in6_addr));
231
232     memcpy(walker, &sin6, sizeof (sin6));
233     walker += step;
234     rtm->rtm_flags |= RTF_LLINFO;
235   }
236
237   if ((rtm->rtm_flags & RTF_HOST) == 0)
238   {
239     olsr_prefix_to_netmask((union olsr_ip_addr *)&sin6.sin6_addr, dest->rt_mask.v6);
240     memcpy(walker, &sin6, sizeof (sin6));
241     walker += step;
242     rtm->rtm_addrs |= RTA_NETMASK;
243   }
244
245   if ((rtm->rtm_flags & RTF_GATEWAY) != 0)
246   {
247     strcpy(&sdl.sdl_data[0], dest->rt_if->int_name);
248     sdl.sdl_nlen = (u_char)strlen(dest->rt_if->int_name);
249     memcpy(walker, &sdl, sizeof (sdl));
250     walker += step_dl;
251     rtm->rtm_addrs |= RTA_IFP;
252   }
253
254   rtm->rtm_msglen = (unsigned short)(walker - buff);
255
256   len = write(olsr_cnf->rts, buff, rtm->rtm_msglen);
257
258   if (len < rtm->rtm_msglen)
259     fprintf(stderr, "cannot write to routing socket: %s\n", strerror(errno));
260
261   return 0;
262 }
263
264 int olsr_ioctl_add_route6(struct rt_entry *dest)
265 {
266   return add_del_route6(dest, 1);
267 }
268
269 int olsr_ioctl_del_route6(struct rt_entry *dest)
270 {
271   return add_del_route6(dest, 0);
272 }