add more timer cookies
[olsrd.git] / lib / arprefresh / src / olsrd_arprefresh.c
1 /*
2  * Copyright (c) 2007, Sven-Ola Tuecke <sven-ola-aet-gmx.de>
3  * Copyright (c) 2004, Andreas T√łnnesen(andreto-at-olsr.org)
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 notice, 
11  *   this list of conditions and the following disclaimer.
12  * * Redistributions in binary form must reproduce the above copyright notice, 
13  *   this list of conditions and the following disclaimer in the documentation 
14  *   and/or other materials provided with the distribution.
15  * * Neither the name of the UniK olsr daemon nor the names of its contributors 
16  *   may be used to endorse or promote products derived from this software 
17  *   without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
21  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
22  * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 
23  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
24  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 
26  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 
27  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 
28  * OF THE POSSIBILITY OF SUCH DAMAGE.
29  *
30  */
31
32
33 /*
34  * Plugin to refresh the local ARP cache from received OLSR broadcasts
35  */
36
37 #include <stdio.h>
38 #include <string.h>
39 #include <stdlib.h>
40 #include <fcntl.h>
41 #include <sys/ioctl.h>
42 #include <sys/socket.h>
43 #include <net/if.h>
44 #include <net/if_arp.h>
45 #include <net/ethernet.h>
46 #include <netinet/ip.h>
47 #include <netinet/udp.h>
48 #include <netpacket/packet.h>
49 #include <linux/types.h>
50 #include <linux/filter.h>
51 #include <errno.h>
52 #include <unistd.h>
53
54 #include "olsrd_arprefresh.h"
55 #include "kernel_routes.h"
56 #include "scheduler.h"
57
58 #undef ARPREFRESH_DEBUG
59 #define PLUGIN_INTERFACE_VERSION 5
60
61 /****************************************************************************
62  *                Functions that the plugin MUST provide                    *
63  ****************************************************************************/
64  
65 /**
66  * Plugin interface version
67  * Used by main olsrd to check plugin interface version
68  */
69 int olsrd_plugin_interface_version(void)
70 {
71         return PLUGIN_INTERFACE_VERSION;
72 }
73
74 static const struct olsrd_plugin_parameters plugin_parameters[] = {
75 };
76
77 void olsrd_get_plugin_parameters(const struct olsrd_plugin_parameters **params, int *size)
78 {
79     *params = plugin_parameters;
80     *size = sizeof(plugin_parameters)/sizeof(*plugin_parameters);
81 }
82
83 typedef struct
84 {
85         struct ethhdr eth;
86         struct iphdr ip;
87         struct udphdr udp;
88 } __attribute__((packed)) arprefresh_buf;
89
90 static int arprefresh_sockfd = -1;
91 static const int arprefresh_portnum = 698;
92 static struct olsr_cookie_info *arp_event_timer_cookie;
93
94 /**
95  * Scheduled event to fetch gathered packets and update the ARP cache
96  * called from olsrd main thread
97  */
98 static void olsr_arp_event(void* foo __attribute__((unused)))
99 {
100         if (0 <= arprefresh_sockfd)
101         {
102                 arprefresh_buf buf;
103                 struct sockaddr_ll from;
104                 socklen_t fromlen = sizeof(from);
105                 
106                 /*
107                  * Grab a single snapshot on the packet socket. This only works
108                  * if not too much IP traffic is currently flowing through.
109                  */
110                 ssize_t size = recvfrom(arprefresh_sockfd, &buf, sizeof(buf),
111                         MSG_TRUNC, (struct sockaddr *)&from, &fromlen);
112
113                 if (0 <= size &&
114                     size >= (ssize_t)sizeof(buf) /*** &&
115                     ETH_P_IP == ntohs(buf.eth.h_proto) &&
116                     IPPROTO_UDP == buf.ip.protocol &&
117                     arprefresh_portnum == ntohs(buf.udp.source) &&
118                     arprefresh_portnum == ntohs(buf.udp.dest) ***/)
119                 {
120                         union
121                         {
122                                 struct arpreq arp;
123                                 struct sockaddr_in in_pa;
124                                 struct sockaddr_in6 in_pa6;
125                         } req;
126
127                         memset(&req, 0, sizeof(req));
128                         req.in_pa.sin_family = AF_INET;
129                         memcpy(&req.in_pa.sin_addr, &buf.ip.saddr, sizeof(buf.ip.saddr));
130                         req.arp.arp_ha.sa_family = AF_LOCAL;
131                         memcpy(&req.arp.arp_ha.sa_data, &buf.eth.h_source, sizeof(buf.eth.h_source));
132                         req.arp.arp_flags = ATF_COM;
133                         if_indextoname(from.sll_ifindex, req.arp.arp_dev);
134 #ifdef ARPREFRESH_DEBUG
135                         {
136                                 int i;
137                                 OLSR_PRINTF(0, "Refresh on %s, %s=", req.arp.arp_dev,
138                                         inet_ntoa(*((struct in_addr*)&buf.ip.saddr)));
139                                 for(i = 0; i < (ssize_t)sizeof(buf.eth.h_source); i++)
140                                 {
141                                         OLSR_PRINTF(0, "%02x%s", ((unsigned char *)&buf.eth.h_source)[i], i < (ssize_t)sizeof(buf.eth.h_source) -1 ? ":" : "\n");
142                                 }
143                         }
144 #endif
145                         if (ioctl(arprefresh_sockfd, SIOCSARP, &req) < 0) {
146                                 OLSR_PRINTF(1, "*** ARPREFRESH: SIOCSARP: %s\n", strerror(errno));
147                                 close(arprefresh_sockfd);
148                                 arprefresh_sockfd = -1;
149                                 return;
150                         }
151                 }
152         }
153 }
154
155 /**
156  * Initialize plugin
157  * Called after all parameters are passed
158  */
159 int olsrd_plugin_init(void)
160 {
161         int ret = 0;
162         arp_event_timer_cookie  = olsr_alloc_cookie("Arprefresh: event", OLSR_COOKIE_TYPE_TIMER);
163         if (AF_INET == olsr_cnf->ip_version)
164         {
165                 int flags;
166                 struct sock_fprog filter;
167                 struct sock_filter BPF_code[]=
168                 {
169                         /* tcpdump -s [sizeof(arprefresh_buf)] -ni lo udp and dst port [arprefresh_portnum] -dd */
170                         { 0x28, 0, 0, 0x0000000c },
171                         { 0x15, 0, 4, 0x000086dd },
172                         { 0x30, 0, 0, 0x00000014 },
173                         { 0x15, 0, 11, 0x00000011 },
174                         { 0x28, 0, 0, 0x00000038 },
175                         { 0x15, 8, 9, arprefresh_portnum },
176                         { 0x15, 0, 8, 0x00000800 },
177                         { 0x30, 0, 0, 0x00000017 },
178                         { 0x15, 0, 6, 0x00000011 },
179                         { 0x28, 0, 0, 0x00000014 },
180                         { 0x45, 4, 0, 0x00001fff },
181                         { 0xb1, 0, 0, 0x0000000e },
182                         { 0x48, 0, 0, 0x00000010 },
183                         { 0x15, 0, 1, arprefresh_portnum },
184                         { 0x6, 0, 0, sizeof(arprefresh_buf) },
185                         { 0x6, 0, 0, 0x00000000 }
186                 };
187                 filter.len = sizeof(BPF_code) / sizeof(BPF_code[0]);
188                 filter.filter = BPF_code;
189                 if (0 <= (arprefresh_sockfd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP))) &&
190                     0 <= (flags = fcntl(arprefresh_sockfd, F_GETFL)) &&
191                     0 <= fcntl(arprefresh_sockfd, F_SETFL, flags | O_NONBLOCK) &&
192                     0 <= setsockopt(arprefresh_sockfd, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter)))
193                 {
194                         /* Register the ARP refresh event */
195                         olsr_start_timer(2 * MSEC_PER_SEC, 0, OLSR_TIMER_PERIODIC,
196                                          &olsr_arp_event, NULL, arp_event_timer_cookie->ci_id);
197                         ret = 1;
198                 }
199                 else
200                 {
201                         OLSR_PRINTF(1, "*** ARPREFRESH: Cannot create non-blocking filtering packet socket: %s\n", strerror(errno));
202                 }
203         }
204         else
205         {
206                 OLSR_PRINTF(1, "*** ARPREFRESH: IPv6 not supported\n");
207         }
208         return ret;
209 }
210
211 /****************************************************************************
212  *       Optional private constructor and destructor functions              *
213  ****************************************************************************/
214
215 static void __attribute__ ((constructor)) my_init(void);
216 static void __attribute__ ((destructor)) my_fini(void);
217
218 static void my_init(void)
219 {
220         printf("OLSRD arprefresh plugin by Sven-Ola\n");
221 }
222
223 /**
224  * Optional Private Destructor
225  */
226 static void my_fini(void)
227 {
228         if (0 <= arprefresh_sockfd)
229         {
230                 close(arprefresh_sockfd);
231                 arprefresh_sockfd = -1;
232         }
233 }