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