c7811eabdc797d4b81cf8c05e43646857aa036ad
[olsrd.git] / src / linux / link_layer.c
1 /*
2  * The olsr.org Optimized Link-State Routing daemon(olsrd)
3  * Copyright (c) 2004, Andreas T√łnnesen(andreto@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 
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: link_layer.c,v 1.11 2005/02/27 10:43:38 kattemat Exp $
40  */
41
42
43 #if 0 /* DEPRECATED - KEPT FOR REFERENCE */
44
45 /* Ugly fix to make this compile on wireless extentions < 16 */
46 #define _LINUX_ETHTOOL_H
47
48 #include "../link_layer.h"
49 #include "../olsr_protocol.h"
50 #include "../scheduler.h"
51 #include "../interfaces.h"
52 #include <linux/wireless.h>
53 #include <linux/icmp.h>
54 #include <errno.h>
55 #include <string.h>
56 #include <sys/ioctl.h>
57 #include <net/if_arp.h>
58 #include <unistd.h>
59 #include <stdlib.h>
60
61 #include "olsr_protocol.h"
62
63 void
64 init_link_layer_notification(void);
65
66 void
67 poll_link_layer(void *);
68
69 int
70 add_spy_node(union olsr_ip_addr *, char *);
71
72
73 extern char *
74 sockaddr_to_string(struct sockaddr *);
75
76 extern char *
77 olsr_ip_to_string(union olsr_ip_addr *);
78
79
80 #define MAXIPLEN        60
81 #define MAXICMPLEN      76
82
83 extern size_t ipsize;
84
85 extern int ioctl_s;
86
87 float poll_int = 0.2;
88
89 int
90 iw_get_range_info(char *, struct iw_range *);
91
92 int
93 clear_spy_list(char *);
94
95 int
96 convert_ip_to_mac(union olsr_ip_addr *, struct sockaddr *, char *);
97
98 void
99 send_ping(union olsr_ip_addr *);
100
101
102 void
103 init_link_layer_notification()
104 {
105   struct interface *ifd;
106
107   OLSR_PRINTF(1, "Initializing link-layer notification...\n")
108
109
110   for (ifd = ifnet; ifd ; ifd = ifd->int_next) 
111     {
112       if(ifd->is_wireless)
113         clear_spy_list(ifd->int_name);
114     }
115
116   olsr_register_scheduler_event(&poll_link_layer, NULL, poll_int, 0, NULL);
117
118   return;
119 }
120
121 int
122 clear_spy_list(char *ifname)
123 {
124   struct iwreq  wrq;
125
126   /* Time to do send addresses to the driver */
127   wrq.u.data.pointer = NULL;//(caddr_t) hw_address;
128   wrq.u.data.length = 0;
129   wrq.u.data.flags = 0;
130
131   /* Set device name */
132   strncpy(wrq.ifr_name, ifname, IFNAMSIZ);
133
134   if(ioctl(ioctl_s, SIOCSIWSPY, &wrq) < 0)
135     {
136       OLSR_PRINTF(1, "Could not clear spylist %s\n", strerror(errno))
137       return -1;
138     }
139
140   return 1;
141 }
142
143
144
145 int
146 add_spy_node(union olsr_ip_addr *addr, char *interface)
147 {
148   struct sockaddr       new_node;
149   struct iwreq          wrq;
150   int                   nbr;            /* Number of valid addresses */
151   struct sockaddr       hw_address[IW_MAX_SPY];
152   char  buffer[(sizeof(struct iw_quality) +
153                 sizeof(struct sockaddr)) * IW_MAX_SPY];
154   
155   OLSR_PRINTF(1, "Adding spynode!\n\n")
156   
157   /* get all addresses already in the driver */
158
159   wrq.u.data.pointer = (caddr_t) buffer;
160   wrq.u.data.length = IW_MAX_SPY;
161   wrq.u.data.flags = 0;
162
163   strncpy(wrq.ifr_name, interface, IFNAMSIZ);
164
165   if(ioctl(ioctl_s, SIOCGIWSPY, &wrq) < 0)
166     {
167       OLSR_PRINTF(1, "Could not get old spylist %s\n", strerror(errno))
168       return 0;
169     }
170
171   /* Copy old addresses */
172   nbr = wrq.u.data.length;
173   memcpy(hw_address, buffer, nbr * sizeof(struct sockaddr));
174
175   OLSR_PRINTF(1, "Old addresses: %d\n\n", nbr)
176
177   /* Check upper limit */
178   if(nbr >= IW_MAX_SPY)
179     return 0;
180
181   /* Add new address if MAC exists in ARP cache */
182   if(convert_ip_to_mac(addr, &new_node, interface) > 0)
183     {
184       memcpy(&hw_address[nbr], &new_node, sizeof(struct sockaddr));
185       nbr++;
186     }
187   else
188     return 0;
189   
190   /* Add all addresses */
191   wrq.u.data.pointer = (caddr_t) hw_address;
192   wrq.u.data.length = nbr;
193   wrq.u.data.flags = 0;
194   
195   /* Set device name */
196   strncpy(wrq.ifr_name, interface, IFNAMSIZ);
197   
198   if(ioctl(ioctl_s, SIOCSIWSPY, &wrq) < 0)
199     {
200       OLSR_PRINTF(1, "Could not clear spylist %s\n", strerror(errno))
201       return 0;
202     }
203
204
205   return 1;
206 }
207
208
209 int
210 convert_ip_to_mac(union olsr_ip_addr *ip, struct sockaddr *mac, char *interface)
211 {
212   struct arpreq arp_query;
213   struct sockaddr_in tmp_sockaddr;
214
215
216   memset(&arp_query, 0, sizeof(struct arpreq));
217
218   OLSR_PRINTF(1, "\nARP conversion for %s interface %s\n", 
219               olsr_ip_to_string(ip),
220               interface)
221
222   tmp_sockaddr.sin_family = AF_INET;
223   tmp_sockaddr.sin_port = 0;
224
225   memcpy(&tmp_sockaddr.sin_addr, ip, ipsize);
226
227   /* Translate IP addresses to MAC addresses */
228   memcpy(&arp_query.arp_pa, &tmp_sockaddr, sizeof(struct sockaddr_in));
229   arp_query.arp_ha.sa_family = 0;
230   arp_query.arp_flags = 0;
231
232   strncpy(arp_query.arp_dev, interface, IFNAMSIZ);
233   
234   if((ioctl(ioctl_s, SIOCGARP, &arp_query) < 0) ||
235      !(arp_query.arp_flags & ATF_COM)) /* ATF_COM - hw addr valid */
236     {
237       OLSR_PRINTF(1, "Arp failed: (%s) - trying lookup\n", strerror(errno))
238
239       /* No address - create a thread that sends a PING */
240       send_ping(ip);
241   
242       return -1;
243     }
244
245   OLSR_PRINTF(1, "Arp success!\n")
246
247   memcpy(mac, &arp_query.arp_ha, sizeof(struct sockaddr));
248
249   return 1;
250 }
251
252
253
254 /**
255  *A thread that sends a ICMP echo "ping" packet
256  *to a given destination to force the ARP cache
257  *to be updated... kind of a kludge....
258  *
259  *@param _ip the IP address to ping
260  */
261 /* ONLY IPv4 FOR NOW!!! */
262
263 void
264 send_ping(union olsr_ip_addr *ip)
265 {
266   int ping_s;
267   struct sockaddr dst;
268   struct sockaddr_in *dst_in;
269   char *packet;
270   struct icmphdr *icp;
271
272   dst_in = (struct sockaddr_in *) &dst;
273
274   dst_in->sin_family = AF_INET;
275   memcpy(&dst_in->sin_addr, ip, ipsize);
276
277   OLSR_PRINTF(1, "pinging %s\n\n", olsr_ip_to_string(ip))
278
279   if ((ping_s = socket(AF_INET, SOCK_RAW, PF_INET)) < 0) 
280     {
281       OLSR_PRINTF(1, "Could not create RAW socket for ping!\n%s\n", strerror(errno))
282       return;
283     }
284
285   /* Create packet */
286   packet = malloc(MAXIPLEN + MAXICMPLEN);
287   
288   
289   icp = (struct icmphdr *)packet;
290   icp->type = ICMP_ECHO;
291   icp->code = 0;
292   icp->checksum = 0;
293   icp->un.echo.sequence = 1;
294   icp->un.echo.id = getpid() & 0xFFFF;
295
296   if((sendto(ping_s, packet, MAXIPLEN + MAXICMPLEN + 8, 0, &dst, sizeof(struct sockaddr))) !=
297      MAXIPLEN + MAXICMPLEN + 8)
298     {
299       OLSR_PRINTF(1, "Error PING: %s\n", strerror(errno))
300     }
301
302   /* Nevermind the pong ;-) */
303
304   OLSR_PRINTF(1, "Ping complete...\n")
305   close(ping_s);
306
307   free(packet);
308
309   return;
310 }
311
312 void
313 poll_link_layer(void *foo)
314 {
315   struct iwreq          wrq;
316   char                  buffer[(sizeof(struct iw_quality) +
317                                sizeof(struct sockaddr)) * IW_MAX_SPY];
318   struct sockaddr       *hwa;
319   struct iw_quality     *qual;
320   int                   n;
321   struct iw_range       range;
322   int                   i, j;
323   int                   has_range = 0;
324   struct interface      *iflist;
325
326   //OLSR_PRINTF(1, "Polling link-layer notification...\n")
327
328   for(iflist = ifnet; iflist != NULL; iflist = iflist->int_next)
329     {
330       if(!iflist->is_wireless)
331         continue;
332
333       /* Collect stats */
334       wrq.u.data.pointer = (caddr_t) buffer;
335       wrq.u.data.length = IW_MAX_SPY;
336       wrq.u.data.flags = 0;
337       
338       /* Set device name */
339       strncpy(wrq.ifr_name, iflist->int_name, IFNAMSIZ);
340       
341       /* Do the request */
342       if(ioctl(ioctl_s, SIOCGIWSPY, &wrq) < 0)
343         {
344           OLSR_PRINTF(1, "%-8.16s  Interface doesn't support wireless statistic collection\n\n", iflist->int_name)
345           return;
346         }
347       
348       /* Get range info if we can */
349       if(iw_get_range_info(iflist->int_name, &(range)) >= 0)
350         has_range = 1;
351       
352       /* Number of addresses */
353       n = wrq.u.data.length;
354       
355       /* The two lists */
356       hwa = (struct sockaddr *) buffer;
357       qual = (struct iw_quality *) (buffer + (sizeof(struct sockaddr) * n));
358       
359       for(i = 0; i < n; i++)
360         {
361           if(!(qual->updated & 0x7))
362             continue;
363           
364           /* Print stats for each address */
365           OLSR_PRINTF(1, "MAC")
366           for(j = 0; j < 6; j++)
367             {
368               OLSR_PRINTF(1, ":%02x", (hwa[i].sa_data[j] % 0xffffff00))
369             }
370           if(!has_range)
371             OLSR_PRINTF(1, " : Quality:%d  Signal level:%d dBm  Noise level:%d dBm",
372                         qual[i].qual,
373                         qual[i].level - 0x100, 
374                         qual[i].noise - 0x100)
375           else
376             OLSR_PRINTF(1, " : Quality:%d/%d  Signal level:%d dBm  Noise level:%d dBm",
377                         qual[i].qual,
378                         range.max_qual.qual,
379                         qual[i].level - 0x100, 
380                         qual[i].noise - 0x100)
381           
382           OLSR_PRINTF(1, "\n")
383           
384         }
385     }
386
387   //OLSR_PRINTF(1, "\n")
388   return;
389 }
390
391
392
393
394
395 /*
396  * Get the range information out of the driver
397  */
398 int
399 iw_get_range_info(char            *ifname,
400                   struct iw_range *range)
401 {
402   struct iwreq          wrq;
403   char                  buffer[sizeof(struct iw_range) * 2];    /* Large enough */
404   union iw_range_raw    *range_raw;
405
406   /* Cleanup */
407   bzero(buffer, sizeof(buffer));
408
409   wrq.u.data.pointer = (caddr_t) buffer;
410   wrq.u.data.length = sizeof(buffer);
411   wrq.u.data.flags = 0;
412
413   /* Set device name */
414   strncpy(wrq.ifr_name, ifname, IFNAMSIZ);
415
416   if(ioctl(ioctl_s, SIOCGIWRANGE, &wrq) < 0)
417     {
418       OLSR_PRINTF(1, "NO RANGE\n")
419       return -1;
420     }
421
422   /* Point to the buffer */
423   range_raw = (union iw_range_raw *) buffer;
424
425   memcpy((char *) range, buffer, sizeof(struct iw_range));
426
427   return 1;
428 }
429
430
431 #endif