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