Namespace cleanup of scheduler, remove "polling" sockets
[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 "scheduler.h"
56 #include "plugin_util.h"
57 #include "olsr_ip_prefix_list.h"
58 #include "net_olsr.h"
59
60 #define PLUGIN_DESCR    "Arproaming olsrd plugin v0.1"
61 #define PLUGIN_AUTHOR "amadeus"
62
63 static int arproaming_init(void);
64 static int arproaming_exit(void);
65
66 static void arproaming_schedule_event(void *);
67 static void arproaming_list_add(unsigned int timeout, const union olsr_ip_addr *ip, const struct olsr_mac48_addr *mac);
68 static void arproaming_list_remove(const struct olsr_mac48_addr *mac);
69 static void arproaming_client_add(void);
70 static void arproaming_client_remove(const union olsr_ip_addr *ip);
71 static int arproaming_client_probe(const union olsr_ip_addr *ip);
72 static void arproaming_client_update(void);
73 static void arproaming_systemconf(int arproaming_socketfd_system);
74
75 #if 0
76 static void arproaming_list_update(const union olsr_ip_addr *ip, unsigned int timeout);
77 #endif
78
79 struct arproaming_nodes {
80   struct list_entity node;
81   unsigned int timeout;
82   union olsr_ip_addr ip;
83   struct olsr_mac48_addr mac;
84 };
85
86 static struct olsr_timer_info *timer_info;
87 static struct olsr_timer_entry *event_timer;
88
89 static char arproaming_parameter_interface[25];
90 static int arproaming_parameter_timeout;
91
92 static int arproaming_socketfd_netlink = -1;
93 static int arproaming_socketfd_arp = -1;
94 static union olsr_ip_addr arproaming_srcip;
95
96 static struct olsr_mac48_addr arproaming_srcmac;
97
98 static struct list_entity arproaming_nodes;
99
100 static const struct olsrd_plugin_parameters plugin_parameters[] = {
101         { .name = "Interface", .set_plugin_parameter = &set_plugin_string, .data = &arproaming_parameter_interface, .addon.ui = sizeof(arproaming_srcmac)},
102         { .name = "Timeout", .set_plugin_parameter = &set_plugin_int, .data = &arproaming_parameter_timeout }
103 };
104
105 OLSR_PLUGIN6(plugin_parameters) {
106         .descr = PLUGIN_DESCR,
107         .author = PLUGIN_AUTHOR,
108         .init = arproaming_init,
109         .exit = arproaming_exit,
110         .deactivate = false
111 };
112
113 static void
114 arproaming_list_add(unsigned int timeout, const union olsr_ip_addr *ip, const struct olsr_mac48_addr *mac)
115 {
116         struct arproaming_nodes *new;
117
118         new = malloc(sizeof(*new));
119
120         new->timeout = timeout;
121         memcpy(&new->ip, ip, sizeof(*ip));
122         memcpy(&new->mac, mac, sizeof(*mac));
123
124         list_add_tail(&arproaming_nodes, &new->node);
125 }
126
127 static void
128 arproaming_list_remove(const struct olsr_mac48_addr *mac)
129 {
130         struct arproaming_nodes *element, *iterator;
131
132         list_for_each_element_safe(&arproaming_nodes, element, node, iterator) {
133                 if (memcmp(&element->mac, mac, sizeof(*mac)) == 0) {
134                   list_remove(&element->node);
135                         free(element);
136                 }
137         }
138 }
139
140 #if 0
141 static void
142 arproaming_list_update(const union olsr_ip_addr *ip, unsigned int timeout)
143 {
144         struct arproaming_nodes *element;
145
146         list_for_each_element(&arproaming_nodes, element, node) {
147                 if (olsr_ipcmp(&element->ip, ip) == 0) {
148                         element->timeout = timeout;
149                         break;
150                 }
151         }
152 }
153 #endif
154
155 static void
156 arproaming_client_add(void)
157 {
158         int status, rtattrlen, len;
159         char buf[10240];
160         struct olsr_mac48_addr mac;
161
162         struct {
163                 struct nlmsghdr n;
164                 struct ndmsg r;
165         } req;
166         struct rtattr *rta, *rtatp;
167         struct nlmsghdr *nlmsghdr;
168         struct ndmsg *ndmsg;
169         struct ifaddrmsg *ifa;
170         struct in_addr *in;
171         union olsr_ip_addr host_net;
172
173         memset(&req, 0, sizeof(req));
174         req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg));
175         req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT;
176         req.n.nlmsg_type = RTM_NEWNEIGH | RTM_GETNEIGH;
177         req.r.ndm_family = AF_INET;
178
179         rta = (struct rtattr *)(((char *)&req) + NLMSG_ALIGN(req.n.nlmsg_len));
180         rta->rta_len = RTA_LENGTH(4);
181
182         send(arproaming_socketfd_netlink, &req, req.n.nlmsg_len, 0);
183         status = recv(arproaming_socketfd_netlink, buf, sizeof(buf), 0);
184
185         for(nlmsghdr = (struct nlmsghdr *)buf; (unsigned int) status > sizeof(*nlmsghdr);) {
186                 len = nlmsghdr->nlmsg_len;
187                 ndmsg = (struct ndmsg *)NLMSG_DATA(nlmsghdr);
188                 rtatp = (struct rtattr *)IFA_RTA(ndmsg);
189                 rtattrlen = IFA_PAYLOAD(nlmsghdr);
190                 rtatp = RTA_NEXT(rtatp, rtattrlen);
191                 ifa = (struct ifaddrmsg *)NLMSG_DATA(nlmsghdr);
192
193
194                 if (rtatp->rta_type == IFA_ADDRESS && ndmsg->ndm_state & NUD_REACHABLE) {
195                         in = (struct in_addr *)RTA_DATA(rtatp);
196                         host_net.v4 = *in;
197
198                         if (ip_prefix_list_find(&olsr_cnf->hna_entries, &host_net, 32, 4) == NULL && if_nametoindex(arproaming_parameter_interface) == ifa->ifa_index) {
199 #if !defined REMOVE_LOG_DEBUG
200                           struct ipaddr_str ipbuf;
201 #endif
202                           memcpy(&mac, RTA_DATA(rtatp), sizeof(mac));
203
204                                 ip_prefix_list_add(&olsr_cnf->hna_entries, &host_net, 32);
205                                 arproaming_list_add(time(NULL) + arproaming_parameter_timeout, &host_net, &mac);
206
207                                 OLSR_DEBUG(LOG_PLUGINS, "[ARPROAMING] Adding host %s\n", olsr_ip_to_string(&ipbuf, &host_net));
208                         }
209                 }
210
211                 status -= NLMSG_ALIGN(len);
212                 nlmsghdr = (struct nlmsghdr*)((char*)nlmsghdr + NLMSG_ALIGN(len));
213         }
214 }
215
216 static void
217 arproaming_client_remove(const union olsr_ip_addr *ip)
218 {
219         int socketfd;
220         struct arpreq req;
221         struct sockaddr_in *sin;
222
223         socketfd = socket(AF_INET, SOCK_DGRAM, 0);
224
225         memset(&req, 0, sizeof(struct arpreq));
226         sin = (struct sockaddr_in *) &req.arp_pa;
227         sin->sin_family = AF_INET;
228         sin->sin_addr = ip->v4;
229         strcpy(req.arp_dev, arproaming_parameter_interface);
230
231         ioctl(socketfd, SIOCDARP, (caddr_t)&req);
232         close(socketfd);
233 }
234
235 static int
236 arproaming_client_probe(const union olsr_ip_addr *ip)
237 {
238         int ret = 0;
239         int     timeout = 1;
240         struct arpMsg {
241                 struct ethhdr ethhdr;
242                 u_short htype;
243                 u_short ptype;
244                 u_char  hlen;
245                 u_char  plen;
246                 u_short operation;
247                 u_char  sHaddr[6];
248                 u_char  sInaddr[4];
249                 u_char  tHaddr[6];
250                 u_char  tInaddr[4];
251         };
252         struct sockaddr addr;
253         struct arpMsg arp;
254         fd_set fdset;
255         struct timeval  tm;
256         time_t prevTime;
257
258         memset(&arp, 0, sizeof(arp));
259         memcpy(arp.ethhdr.h_dest, "\xFF\xFF\xFF\xFF\xFF\xFF", 6);
260         memcpy(arp.ethhdr.h_source, &arproaming_srcmac, sizeof(arproaming_srcmac));
261         arp.ethhdr.h_proto = htons(ETH_P_ARP);
262         arp.htype = htons(ARPHRD_ETHER);
263         arp.ptype = htons(ETH_P_IP);
264         arp.hlen = 6;
265         arp.plen = 4;
266         arp.operation = htons(ARPOP_REQUEST);
267         memcpy(arp.sInaddr, &arproaming_srcip, sizeof(arp.sInaddr));
268         memcpy(arp.sHaddr, &arproaming_srcmac, sizeof(arproaming_srcmac));
269         memcpy(arp.tInaddr, ip, sizeof(arp.tInaddr));
270
271         memset(&addr, 0, sizeof(addr));
272         strcpy(addr.sa_data, arproaming_parameter_interface);
273         sendto(arproaming_socketfd_arp, &arp, sizeof(arp), 0, &addr, sizeof(addr));
274
275         tm.tv_usec = 0;
276         time(&prevTime);
277         while (timeout > 0) {
278                 FD_ZERO(&fdset);
279                 FD_SET(arproaming_socketfd_arp, &fdset);
280                 tm.tv_sec = timeout;
281                 select(arproaming_socketfd_arp + 1, &fdset, (fd_set *) NULL, (fd_set *) NULL, &tm);
282
283                 if (FD_ISSET(arproaming_socketfd_arp, &fdset)) {
284                         recv(arproaming_socketfd_arp, &arp, sizeof(arp), 0);
285                         if (arp.operation == htons(ARPOP_REPLY)
286                             && memcmp(arp.tHaddr, &arproaming_srcmac, 6) == 0
287                             && memcmp(arp.sInaddr, &ip, sizeof(arp.sInaddr)) == 0) {
288                                 ret = 1;
289                                 break;
290                         }
291                 }
292
293                 timeout -= time(NULL) - prevTime;
294                 time(&prevTime);
295         }
296
297         return ret;
298 }
299
300 static void
301 arproaming_client_update(void)
302 {
303         struct arproaming_nodes *element, *iterator;
304 #if !defined REMOVE_LOG_DEBUG
305   struct ipaddr_str buf;
306 #endif
307
308   list_for_each_element_safe(&arproaming_nodes, element, node, iterator) {
309                 if (element->timeout > 0 && element->timeout <= (unsigned int)time(NULL)) {
310                         if (arproaming_client_probe(&element->ip) == 0) {
311                           OLSR_DEBUG(LOG_PLUGINS, "[ARPROAMING] Removing host %s\n", olsr_ip_to_string(&buf, &element->ip));
312                                 ip_prefix_list_remove(&olsr_cnf->hna_entries, &element->ip, 32, 4);
313                                 arproaming_client_remove(&element->ip);
314                                 arproaming_list_remove(&element->mac);
315                                 break;
316                         }
317                         else {
318                                 OLSR_DEBUG(LOG_PLUGINS, "[ARPROAMING] Renewing host %s\n", olsr_ip_to_string(&buf, &element->ip));
319                                 element->timeout = time(NULL) + arproaming_parameter_timeout;
320                         }
321                 }
322         }
323 }
324
325 static void
326 arproaming_systemconf(int arproaming_socketfd_system)
327 {
328         int i, optval = 1;
329         char buf[1024];
330         struct ifreq ifa, *IFR;
331         struct sockaddr_in *in;
332         struct ifconf ifc;
333
334         strcpy(ifa.ifr_name, arproaming_parameter_interface);
335         ioctl(arproaming_socketfd_system, SIOCGIFADDR, &ifa);
336         in = (struct sockaddr_in*)&ifa.ifr_addr;
337
338         memset(&arproaming_srcip, 0, sizeof(arproaming_srcip));
339         memcpy(&arproaming_srcip, &in->sin_addr, sizeof(in->sin_addr));
340
341         ifc.ifc_len = sizeof(buf);
342         ifc.ifc_buf = buf;
343         ioctl(arproaming_socketfd_system, SIOCGIFCONF, &ifc);
344
345         IFR = ifc.ifc_req;
346         for (i = ifc.ifc_len / sizeof(struct ifreq); i-- >= 0; IFR++) {
347                 strcpy(ifa.ifr_name, IFR->ifr_name);
348                 if (ioctl(arproaming_socketfd_system, SIOCGIFFLAGS, &ifa) == 0) {
349                         if (! (ifa.ifr_flags & IFF_LOOPBACK)) {
350                                 if (ioctl(arproaming_socketfd_system, SIOCGIFHWADDR, &ifa) == 0) {
351                                         break;
352                                 }
353                         }
354                 }
355         }
356         memcpy(ifa.ifr_hwaddr.sa_data, &arproaming_srcmac, sizeof(arproaming_srcmac));
357         close(arproaming_socketfd_system);
358
359         setsockopt(arproaming_socketfd_arp, SOL_SOCKET, SO_BROADCAST, &optval, sizeof(optval));
360 }
361
362 static void
363 arproaming_schedule_event(void *foo __attribute__ ((unused)))
364 {
365         arproaming_client_add();
366         arproaming_client_update();
367 }
368
369 static int
370 arproaming_init(void)
371 {
372         int arproaming_socketfd_system = -1;
373         struct olsr_mac48_addr mac;
374
375         list_init_head(&arproaming_nodes);
376
377         memset(&mac, 0, sizeof(mac));
378         arproaming_list_add(0, &all_zero, &mac);
379
380         arproaming_socketfd_netlink = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
381         if (arproaming_socketfd_netlink < 0) {
382           OLSR_WARN(LOG_PLUGINS, "Cannot open netlink socket for arproaming plugin: %s (%d)",
383               strerror(errno), errno);
384           return 1;
385         }
386
387         arproaming_socketfd_arp = socket(PF_PACKET, SOCK_PACKET, htons(ETH_P_ARP));
388         if (arproaming_socketfd_arp < 0) {
389     OLSR_WARN(LOG_PLUGINS, "Cannot open raw socket for arproaming plugin: %s (%d)",
390         strerror(errno), errno);
391           close (arproaming_socketfd_netlink);
392           return 1;
393         }
394
395         arproaming_socketfd_system = socket(AF_INET, SOCK_DGRAM, 0);
396   if (arproaming_socketfd_system < 0) {
397     OLSR_WARN(LOG_PLUGINS, "Cannot open configuration socket for arproaming plugin: %s (%d)",
398         strerror(errno), errno);
399     close (arproaming_socketfd_netlink);
400     close (arproaming_socketfd_arp);
401     return 1;
402   }
403
404         arproaming_systemconf(arproaming_socketfd_system);
405
406   timer_info = olsr_timer_add("arproaming", &arproaming_schedule_event, true);
407   event_timer = olsr_timer_start(MSEC_PER_SEC/3, 0, NULL, timer_info);
408
409         close(arproaming_socketfd_system);
410         return 0;
411 }
412
413 static int
414 arproaming_exit(void)
415 {
416   olsr_timer_stop(event_timer);
417
418         if (arproaming_socketfd_netlink >= 0) {
419                 OLSR_DEBUG(LOG_PLUGINS, "[ARPROAMING] Closing netlink socket.\n");
420                 close(arproaming_socketfd_netlink);
421         }
422
423         if (arproaming_socketfd_arp >= 0) {
424                 OLSR_DEBUG(LOG_PLUGINS, "[ARPROAMING] Closing arp socket.\n");
425                 close(arproaming_socketfd_arp);
426         }
427
428         OLSR_DEBUG(LOG_PLUGINS, "[ARPROAMING] Exiting.\n");
429
430         return 0;
431 }