Merge branch 'master' into scheduler_cleanup
[olsrd.git] / lib / arproaming / src / olsrd_arproaming.c
1 /*
2  * OLSR ARPROAMING PLUGIN
3  * http://www.olsr.org
4  *
5  * Copyright (c) 2004, Andreas Tonnesen(andreto@olsr.org)
6  * Copyright (c) 2010, amadeus (amadeus@chemnitz.freifunk.net)
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or
10  * without modification, are permitted provided that the following
11  * conditions are met:
12  *
13  * * Redistributions of source code must retain the above copyright
14  *       notice, this list of conditions and the following disclaimer.
15  * * Redistributions in binary form must reproduce the above copyright
16  *       notice, this list of conditions and the following disclaimer in
17  *       the documentation and/or other materials provided with the
18  *       distribution.
19  * * Neither the name of olsrd, olsr.org nor the names of its
20  *       contributors may be used to endorse or promote products derived
21  *       from this software without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
29  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
31  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
33  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34  * POSSIBILITY OF SUCH DAMAGE.
35  *
36  */
37
38 #include <stdio.h>
39 #include <string.h>
40 #include <unistd.h>
41 #include <time.h>
42 #include <malloc.h>
43 #include <net/if_arp.h>
44 #include <netinet/in.h>
45 #include <netinet/if_ether.h>
46 #include <linux/rtnetlink.h>
47 #include <arpa/inet.h>
48 #include <sys/ioctl.h>
49 #include <sys/socket.h>
50
51 #include "olsr.h"
52 #include "defs.h"
53 #include "olsr_types.h"
54 #include "olsr_logging.h"
55 #include "olsr_timer.h"
56 #include "olsr_socket.h"
57 #include "plugin_util.h"
58 #include "olsr_ip_prefix_list.h"
59 #include "net_olsr.h"
60
61 #define PLUGIN_DESCR    "Arproaming olsrd plugin v0.1"
62 #define PLUGIN_AUTHOR "amadeus"
63
64 static int arproaming_init(void);
65 static int arproaming_exit(void);
66
67 static void arproaming_schedule_event(void *);
68 static void arproaming_list_add(unsigned int timeout, const union olsr_ip_addr *ip, const struct olsr_mac48_addr *mac);
69 static void arproaming_list_remove(const struct olsr_mac48_addr *mac);
70 static void arproaming_client_add(void);
71 static void arproaming_client_remove(const union olsr_ip_addr *ip);
72 static int arproaming_client_probe(const union olsr_ip_addr *ip);
73 static void arproaming_client_update(void);
74 static void arproaming_systemconf(int arproaming_socketfd_system);
75
76 #if 0
77 static void arproaming_list_update(const union olsr_ip_addr *ip, unsigned int timeout);
78 #endif
79
80 struct arproaming_nodes {
81   struct list_entity node;
82   unsigned int timeout;
83   union olsr_ip_addr ip;
84   struct olsr_mac48_addr mac;
85 };
86
87 static struct olsr_timer_info *timer_info;
88 static struct olsr_timer_entry *event_timer;
89
90 static char arproaming_parameter_interface[25];
91 static int arproaming_parameter_timeout;
92
93 static int arproaming_socketfd_netlink = -1;
94 static int arproaming_socketfd_arp = -1;
95 static union olsr_ip_addr arproaming_srcip;
96
97 static struct olsr_mac48_addr arproaming_srcmac;
98
99 static struct list_entity arproaming_nodes;
100
101 static const struct olsrd_plugin_parameters plugin_parameters[] = {
102         { .name = "Interface", .set_plugin_parameter = &set_plugin_string, .data = &arproaming_parameter_interface, .addon.ui = sizeof(arproaming_srcmac)},
103         { .name = "Timeout", .set_plugin_parameter = &set_plugin_int, .data = &arproaming_parameter_timeout }
104 };
105
106 OLSR_PLUGIN6(plugin_parameters) {
107         .descr = PLUGIN_DESCR,
108         .author = PLUGIN_AUTHOR,
109         .init = arproaming_init,
110         .exit = arproaming_exit,
111         .deactivate = false
112 };
113
114 static void
115 arproaming_list_add(unsigned int timeout, const union olsr_ip_addr *ip, const struct olsr_mac48_addr *mac)
116 {
117         struct arproaming_nodes *new;
118
119         new = malloc(sizeof(*new));
120
121         new->timeout = timeout;
122         memcpy(&new->ip, ip, sizeof(*ip));
123         memcpy(&new->mac, mac, sizeof(*mac));
124
125         list_add_tail(&arproaming_nodes, &new->node);
126 }
127
128 static void
129 arproaming_list_remove(const struct olsr_mac48_addr *mac)
130 {
131         struct arproaming_nodes *element, *iterator;
132
133         list_for_each_element_safe(&arproaming_nodes, element, node, iterator) {
134                 if (memcmp(&element->mac, mac, sizeof(*mac)) == 0) {
135                   list_remove(&element->node);
136                         free(element);
137                 }
138         }
139 }
140
141 #if 0
142 static void
143 arproaming_list_update(const union olsr_ip_addr *ip, unsigned int timeout)
144 {
145         struct arproaming_nodes *element;
146
147         list_for_each_element(&arproaming_nodes, element, node) {
148                 if (olsr_ipcmp(&element->ip, ip) == 0) {
149                         element->timeout = timeout;
150                         break;
151                 }
152         }
153 }
154 #endif
155
156 static void
157 arproaming_client_add(void)
158 {
159         int status, rtattrlen, len;
160         char buf[10240];
161         struct olsr_mac48_addr mac;
162
163         struct {
164                 struct nlmsghdr n;
165                 struct ndmsg r;
166         } req;
167         struct rtattr *rta, *rtatp;
168         struct nlmsghdr *nlmsghdr;
169         struct ndmsg *ndmsg;
170         struct ifaddrmsg *ifa;
171         struct in_addr *in;
172         union olsr_ip_addr host_net;
173
174         memset(&req, 0, sizeof(req));
175         req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg));
176         req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT;
177         req.n.nlmsg_type = RTM_NEWNEIGH | RTM_GETNEIGH;
178         req.r.ndm_family = AF_INET;
179
180         rta = (struct rtattr *)(((char *)&req) + NLMSG_ALIGN(req.n.nlmsg_len));
181         rta->rta_len = RTA_LENGTH(4);
182
183         send(arproaming_socketfd_netlink, &req, req.n.nlmsg_len, 0);
184         status = recv(arproaming_socketfd_netlink, buf, sizeof(buf), 0);
185
186         for(nlmsghdr = (struct nlmsghdr *)buf; (unsigned int) status > sizeof(*nlmsghdr);) {
187                 len = nlmsghdr->nlmsg_len;
188                 ndmsg = (struct ndmsg *)NLMSG_DATA(nlmsghdr);
189                 rtatp = (struct rtattr *)IFA_RTA(ndmsg);
190                 rtattrlen = IFA_PAYLOAD(nlmsghdr);
191                 rtatp = RTA_NEXT(rtatp, rtattrlen);
192                 ifa = (struct ifaddrmsg *)NLMSG_DATA(nlmsghdr);
193
194
195                 if (rtatp->rta_type == IFA_ADDRESS && ndmsg->ndm_state & NUD_REACHABLE) {
196                         in = (struct in_addr *)RTA_DATA(rtatp);
197                         host_net.v4 = *in;
198
199                         if (ip_prefix_list_find(&olsr_cnf->hna_entries, &host_net, 32, 4) == NULL && if_nametoindex(arproaming_parameter_interface) == ifa->ifa_index) {
200 #if !defined REMOVE_LOG_DEBUG
201                           struct ipaddr_str ipbuf;
202 #endif
203                           memcpy(&mac, RTA_DATA(rtatp), sizeof(mac));
204
205                                 ip_prefix_list_add(&olsr_cnf->hna_entries, &host_net, 32);
206                                 arproaming_list_add(time(NULL) + arproaming_parameter_timeout, &host_net, &mac);
207
208                                 OLSR_DEBUG(LOG_PLUGINS, "[ARPROAMING] Adding host %s\n", olsr_ip_to_string(&ipbuf, &host_net));
209                         }
210                 }
211
212                 status -= NLMSG_ALIGN(len);
213                 nlmsghdr = (struct nlmsghdr*)((char*)nlmsghdr + NLMSG_ALIGN(len));
214         }
215 }
216
217 static void
218 arproaming_client_remove(const union olsr_ip_addr *ip)
219 {
220         int socketfd;
221         struct arpreq req;
222         struct sockaddr_in *sin;
223
224         socketfd = socket(AF_INET, SOCK_DGRAM, 0);
225
226         memset(&req, 0, sizeof(struct arpreq));
227         sin = (struct sockaddr_in *) &req.arp_pa;
228         sin->sin_family = AF_INET;
229         sin->sin_addr = ip->v4;
230         strcpy(req.arp_dev, arproaming_parameter_interface);
231
232         ioctl(socketfd, SIOCDARP, (caddr_t)&req);
233         close(socketfd);
234 }
235
236 static int
237 arproaming_client_probe(const union olsr_ip_addr *ip)
238 {
239         int ret = 0;
240         int     timeout = 1;
241         struct arpMsg {
242                 struct ethhdr ethhdr;
243                 u_short htype;
244                 u_short ptype;
245                 u_char  hlen;
246                 u_char  plen;
247                 u_short operation;
248                 u_char  sHaddr[6];
249                 u_char  sInaddr[4];
250                 u_char  tHaddr[6];
251                 u_char  tInaddr[4];
252         };
253         struct sockaddr addr;
254         struct arpMsg arp;
255         fd_set fdset;
256         struct timeval  tm;
257         time_t prevTime;
258
259         memset(&arp, 0, sizeof(arp));
260         memcpy(arp.ethhdr.h_dest, "\xFF\xFF\xFF\xFF\xFF\xFF", 6);
261         memcpy(arp.ethhdr.h_source, &arproaming_srcmac, sizeof(arproaming_srcmac));
262         arp.ethhdr.h_proto = htons(ETH_P_ARP);
263         arp.htype = htons(ARPHRD_ETHER);
264         arp.ptype = htons(ETH_P_IP);
265         arp.hlen = 6;
266         arp.plen = 4;
267         arp.operation = htons(ARPOP_REQUEST);
268         memcpy(arp.sInaddr, &arproaming_srcip, sizeof(arp.sInaddr));
269         memcpy(arp.sHaddr, &arproaming_srcmac, sizeof(arproaming_srcmac));
270         memcpy(arp.tInaddr, ip, sizeof(arp.tInaddr));
271
272         memset(&addr, 0, sizeof(addr));
273         strcpy(addr.sa_data, arproaming_parameter_interface);
274         sendto(arproaming_socketfd_arp, &arp, sizeof(arp), 0, &addr, sizeof(addr));
275
276         tm.tv_usec = 0;
277         time(&prevTime);
278         while (timeout > 0) {
279                 FD_ZERO(&fdset);
280                 FD_SET(arproaming_socketfd_arp, &fdset);
281                 tm.tv_sec = timeout;
282                 select(arproaming_socketfd_arp + 1, &fdset, (fd_set *) NULL, (fd_set *) NULL, &tm);
283
284                 if (FD_ISSET(arproaming_socketfd_arp, &fdset)) {
285                         recv(arproaming_socketfd_arp, &arp, sizeof(arp), 0);
286                         if (arp.operation == htons(ARPOP_REPLY)
287                             && memcmp(arp.tHaddr, &arproaming_srcmac, 6) == 0
288                             && memcmp(arp.sInaddr, &ip, sizeof(arp.sInaddr)) == 0) {
289                                 ret = 1;
290                                 break;
291                         }
292                 }
293
294                 timeout -= time(NULL) - prevTime;
295                 time(&prevTime);
296         }
297
298         return ret;
299 }
300
301 static void
302 arproaming_client_update(void)
303 {
304         struct arproaming_nodes *element, *iterator;
305 #if !defined REMOVE_LOG_DEBUG
306   struct ipaddr_str buf;
307 #endif
308
309   list_for_each_element_safe(&arproaming_nodes, element, node, iterator) {
310                 if (element->timeout > 0 && element->timeout <= (unsigned int)time(NULL)) {
311                         if (arproaming_client_probe(&element->ip) == 0) {
312                           OLSR_DEBUG(LOG_PLUGINS, "[ARPROAMING] Removing host %s\n", olsr_ip_to_string(&buf, &element->ip));
313                                 ip_prefix_list_remove(&olsr_cnf->hna_entries, &element->ip, 32, 4);
314                                 arproaming_client_remove(&element->ip);
315                                 arproaming_list_remove(&element->mac);
316                                 break;
317                         }
318                         else {
319                                 OLSR_DEBUG(LOG_PLUGINS, "[ARPROAMING] Renewing host %s\n", olsr_ip_to_string(&buf, &element->ip));
320                                 element->timeout = time(NULL) + arproaming_parameter_timeout;
321                         }
322                 }
323         }
324 }
325
326 static void
327 arproaming_systemconf(int arproaming_socketfd_system)
328 {
329         int i, optval = 1;
330         char buf[1024];
331         struct ifreq ifa, *IFR;
332         struct sockaddr_in *in;
333         struct ifconf ifc;
334
335         strcpy(ifa.ifr_name, arproaming_parameter_interface);
336         ioctl(arproaming_socketfd_system, SIOCGIFADDR, &ifa);
337         in = (struct sockaddr_in*)&ifa.ifr_addr;
338
339         memset(&arproaming_srcip, 0, sizeof(arproaming_srcip));
340         memcpy(&arproaming_srcip, &in->sin_addr, sizeof(in->sin_addr));
341
342         ifc.ifc_len = sizeof(buf);
343         ifc.ifc_buf = buf;
344         ioctl(arproaming_socketfd_system, SIOCGIFCONF, &ifc);
345
346         IFR = ifc.ifc_req;
347         for (i = ifc.ifc_len / sizeof(struct ifreq); i-- >= 0; IFR++) {
348                 strcpy(ifa.ifr_name, IFR->ifr_name);
349                 if (ioctl(arproaming_socketfd_system, SIOCGIFFLAGS, &ifa) == 0) {
350                         if (! (ifa.ifr_flags & IFF_LOOPBACK)) {
351                                 if (ioctl(arproaming_socketfd_system, SIOCGIFHWADDR, &ifa) == 0) {
352                                         break;
353                                 }
354                         }
355                 }
356         }
357         memcpy(ifa.ifr_hwaddr.sa_data, &arproaming_srcmac, sizeof(arproaming_srcmac));
358         close(arproaming_socketfd_system);
359
360         setsockopt(arproaming_socketfd_arp, SOL_SOCKET, SO_BROADCAST, &optval, sizeof(optval));
361 }
362
363 static void
364 arproaming_schedule_event(void *foo __attribute__ ((unused)))
365 {
366         arproaming_client_add();
367         arproaming_client_update();
368 }
369
370 static int
371 arproaming_init(void)
372 {
373         int arproaming_socketfd_system = -1;
374         struct olsr_mac48_addr mac;
375
376         list_init_head(&arproaming_nodes);
377
378         memset(&mac, 0, sizeof(mac));
379         arproaming_list_add(0, &all_zero, &mac);
380
381         arproaming_socketfd_netlink = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
382         if (arproaming_socketfd_netlink < 0) {
383           OLSR_WARN(LOG_PLUGINS, "Cannot open netlink socket for arproaming plugin: %s (%d)",
384               strerror(errno), errno);
385           return 1;
386         }
387
388         arproaming_socketfd_arp = socket(PF_PACKET, SOCK_PACKET, htons(ETH_P_ARP));
389         if (arproaming_socketfd_arp < 0) {
390     OLSR_WARN(LOG_PLUGINS, "Cannot open raw socket for arproaming plugin: %s (%d)",
391         strerror(errno), errno);
392           close (arproaming_socketfd_netlink);
393           return 1;
394         }
395
396         arproaming_socketfd_system = socket(AF_INET, SOCK_DGRAM, 0);
397   if (arproaming_socketfd_system < 0) {
398     OLSR_WARN(LOG_PLUGINS, "Cannot open configuration socket for arproaming plugin: %s (%d)",
399         strerror(errno), errno);
400     close (arproaming_socketfd_netlink);
401     close (arproaming_socketfd_arp);
402     return 1;
403   }
404
405         arproaming_systemconf(arproaming_socketfd_system);
406
407   timer_info = olsr_timer_add("arproaming", &arproaming_schedule_event, true);
408   event_timer = olsr_timer_start(MSEC_PER_SEC/3, 0, NULL, timer_info);
409
410         close(arproaming_socketfd_system);
411         return 0;
412 }
413
414 static int
415 arproaming_exit(void)
416 {
417   olsr_timer_stop(event_timer);
418
419         if (arproaming_socketfd_netlink >= 0) {
420                 OLSR_DEBUG(LOG_PLUGINS, "[ARPROAMING] Closing netlink socket.\n");
421                 close(arproaming_socketfd_netlink);
422         }
423
424         if (arproaming_socketfd_arp >= 0) {
425                 OLSR_DEBUG(LOG_PLUGINS, "[ARPROAMING] Closing arp socket.\n");
426                 close(arproaming_socketfd_arp);
427         }
428
429         OLSR_DEBUG(LOG_PLUGINS, "[ARPROAMING] Exiting.\n");
430
431         return 0;
432 }