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