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