Moved wireless detection to OS spesific direesific directories and tories and added...
[olsrd.git] / src / linux / net.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: net.c,v 1.17 2005/02/15 20:49:21 kattemat Exp $
40  */
41
42
43 /*
44  * Linux spesific code
45  */
46
47 #include "net.h"
48 #include "../defs.h"
49 #include "../net_os.h"
50 #include "../parser.h"
51
52 /*
53  *Wireless definitions for ioctl calls
54  *(from linux/wireless.h)
55  */
56 #define SIOCGIWNAME     0x8B01          /* get name == wireless protocol */
57
58 /**
59  *Bind a socket to a device
60  *
61  *@param sock the socket to bind
62  *@param dev_name name of the device
63  *
64  *@return negative if error
65  */
66
67 int
68 bind_socket_to_device(int sock, char *dev_name)
69 {
70   /*
71    *Bind to device using the SO_BINDTODEVICE flag
72    */
73   olsr_printf(3, "Binding socket %d to device %s\n", sock, dev_name);
74   return setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, dev_name, strlen(dev_name)+1);
75
76 }
77
78
79
80
81 /**
82  *Enable IP forwarding.
83  *Just writing "1" to the /proc/sys/net/ipv4/ip_forward
84  *if using IPv4 or /proc/sys/net/ipv6/conf/all/forwarding
85  *if using IPv6.
86  *Could probably drop the check for
87  *"0" here and write "1" anyways.
88  *
89  *@param version IP version.
90  *
91  *@return 1 on sucess 0 on failiure
92  */ 
93 int
94 enable_ip_forwarding(int version)
95 {
96   FILE *proc_fwd;
97   char procfile[FILENAME_MAX];
98
99   if(version == AF_INET)
100     {
101       strcpy(procfile, "/proc/sys/net/ipv4/ip_forward");
102     }
103   else
104     if(version == AF_INET6)
105       {
106         strcpy(procfile, "/proc/sys/net/ipv6/conf/all/forwarding");
107       }
108     else
109       return -1;
110
111
112   if ((proc_fwd=fopen(procfile, "r"))==NULL)
113     {
114       /* IPv4 */
115       if(version == AF_INET)
116         fprintf(stderr, "WARNING! Could not open the %s file to check/enable IP forwarding!\nAre you using the procfile filesystem?\nDoes your system support IPv4?\nI will continue(in 3 sec) - but you should mannually ensure that IP forwarding is enabeled!\n\n", procfile);
117       /* IPv6 */
118       else
119         fprintf(stderr, "WARNING! Could not open the %s file to check/enable IP forwarding!\nAre you using the procfile filesystem?\nDoes your system support IPv6?\nI will continue(in 3 sec) - but you should mannually ensure that IP forwarding is enabeled!\n\n", procfile);
120       
121       sleep(3);
122       return 0;
123     }
124   
125   else
126     {
127       orig_fwd_state = fgetc(proc_fwd);
128       fclose(proc_fwd);
129       if(orig_fwd_state == '1')
130         {
131           olsr_printf(3, "\nIP forwarding is enabled on this system\n");
132         }
133       else
134         {
135           if ((proc_fwd=fopen(procfile, "w"))==NULL)
136             {
137               fprintf(stderr, "Could not open %s for writing!\n", procfile);
138               fprintf(stderr, "I will continue(in 3 sec) - but you should mannually ensure that IP forwarding is enabeled!\n\n");
139               sleep(3);
140               return 0;
141             }
142           else
143             {
144               syslog(LOG_INFO, "Writing \"1\" to %s\n", procfile);
145               fputs("1", proc_fwd);
146             }
147           fclose(proc_fwd);
148
149         }
150     }
151   return 1;
152       
153 }
154
155
156 /**
157  *
158  *@return 1 on sucess 0 on failiure
159  */ 
160 int
161 disable_redirects(char *if_name, int index, int version)
162 {
163   FILE *proc_redirect;
164   char procfile[FILENAME_MAX];
165
166   if(version == AF_INET6)
167     return -1;
168
169   /* Generate the procfile name */
170   sprintf(procfile, REDIRECT_PROC, if_name);
171
172
173   if((proc_redirect = fopen(procfile, "r")) == NULL)
174     {
175       fprintf(stderr, "WARNING! Could not open the %s file to check/disable ICMP redirects!\nAre you using the procfile filesystem?\nDoes your system support IPv4?\nI will continue(in 3 sec) - but you should mannually ensure that ICMP redirects are disabled!\n\n", procfile);
176       
177       sleep(3);
178       return 0;
179     }
180   else
181     {
182       nic_states[index].redirect = fgetc(proc_redirect);
183       fclose(proc_redirect);
184       
185     }
186
187   if ((proc_redirect = fopen(procfile, "w"))==NULL)
188     {
189       fprintf(stderr, "Could not open %s for writing!\n", procfile);
190       fprintf(stderr, "I will continue(in 3 sec) - but you should mannually ensure that ICMP redirect is disabeled!\n\n");
191       sleep(3);
192       return 0;
193     }
194   else
195     {
196       syslog(LOG_INFO, "Writing \"0\" to %s", procfile);
197       fputs("0", proc_redirect);
198     }
199   fclose(proc_redirect);
200
201   return 1;
202 }
203
204
205
206 /**
207  *
208  *@return 1 on sucess 0 on failiure
209  */ 
210 int
211 deactivate_spoof(char *if_name, int index, int version)
212 {
213   FILE *proc_spoof;
214   char procfile[FILENAME_MAX];
215
216   if(version == AF_INET6)
217     return -1;
218
219
220   /* Generate the procfile name */
221   sprintf(procfile, SPOOF_PROC, if_name);
222
223
224   if((proc_spoof = fopen(procfile, "r")) == NULL)
225     {
226       fprintf(stderr, "WARNING! Could not open the %s file to check/disable the IP spoof filter!\nAre you using the procfile filesystem?\nDoes your system support IPv4?\nI will continue(in 3 sec) - but you should mannually ensure that IP spoof filtering is disabled!\n\n", procfile);
227       
228       sleep(3);
229       return 0;
230     }
231   else
232     {
233       nic_states[index].spoof = fgetc(proc_spoof);
234       fclose(proc_spoof);
235       
236     }
237
238   if ((proc_spoof = fopen(procfile, "w")) == NULL)
239     {
240       fprintf(stderr, "Could not open %s for writing!\n", procfile);
241       fprintf(stderr, "I will continue(in 3 sec) - but you should mannually ensure that IP spoof filtering is disabeled!\n\n");
242       sleep(3);
243       return 0;
244     }
245   else
246     {
247       syslog(LOG_INFO, "Writing \"0\" to %s", procfile);
248       fputs("0", proc_spoof);
249     }
250   fclose(proc_spoof);
251
252   return 1;
253 }
254
255
256
257 /**
258  *Resets the spoof filter and ICMP redirect settings
259  */
260
261 int
262 restore_settings(int version)
263 {
264   FILE *proc_fd;
265   char procfile[FILENAME_MAX];
266   struct interface *ifs;
267
268   olsr_printf(1, "Restoring network state\n");
269
270   /* Restore IP forwarding to "off" */
271   if(orig_fwd_state == '0')
272     {
273       if(version == AF_INET)
274         {
275           strcpy(procfile, "/proc/sys/net/ipv4/ip_forward");
276         }
277       else if(version == AF_INET6)
278         {
279           strcpy(procfile, "/proc/sys/net/ipv6/conf/all/forwarding");
280         }
281
282       if ((proc_fd = fopen(procfile, "w")) == NULL)
283         {
284           fprintf(stderr, "Could not open %s for writing!\nSettings not restored!\n", procfile);
285         }
286       else
287         {
288           syslog(LOG_INFO, "Resetting %s to %c\n", procfile, orig_fwd_state);
289           fputc(orig_fwd_state, proc_fd);
290           fclose(proc_fd);
291         }
292
293     }
294
295   if(version == AF_INET6)
296     return 0;
297
298   for(ifs = ifnet; ifs != NULL; ifs = ifs->int_next)
299     {
300       /* ICMP redirects */
301       
302       /* Generate the procfile name */
303       sprintf(procfile, REDIRECT_PROC, ifs->int_name);
304       
305       if ((proc_fd = fopen(procfile, "w")) == NULL)
306         {
307           fprintf(stderr, "Could not open %s for writing!\nSettings not restored!\n", procfile);
308         }
309       else
310         {
311           syslog(LOG_INFO, "Resetting %s to %c\n", procfile, nic_states[ifs->if_nr].redirect);
312
313           fputc(nic_states[ifs->if_nr].redirect, proc_fd);
314           fclose(proc_fd);
315         }
316
317       
318       /* Spoof filter */
319       
320       /* Generate the procfile name */
321       sprintf(procfile, SPOOF_PROC, ifs->int_name);
322
323       if ((proc_fd = fopen(procfile, "w")) == NULL)
324         {
325           fprintf(stderr, "Could not open %s for writing!\nSettings not restored!\n", procfile);
326         }
327       else
328         {
329           syslog(LOG_INFO, "Resetting %s to %c\n", procfile, nic_states[ifs->if_nr].spoof);
330
331           fputc(nic_states[ifs->if_nr].spoof, proc_fd);
332           fclose(proc_fd);
333         }
334
335     }
336   return 1;
337
338 }
339
340
341
342 /**
343  *Creates a nonblocking broadcast socket.
344  *@param sa sockaddr struct. Used for bind(2).
345  *@return the FD of the socket or -1 on error.
346  */
347 int
348 getsocket(struct sockaddr *sa, int bufspace, char *int_name)
349 {
350   struct sockaddr_in *sin=(struct sockaddr_in *)sa;
351   int sock, on = 1;
352
353
354
355   if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) 
356     {
357       perror("socket");
358       syslog(LOG_ERR, "socket: %m");
359       return (-1);
360     }
361
362
363
364 #ifdef SO_BROADCAST
365   if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &on, sizeof (on)) < 0)
366     {
367       perror("setsockopt");
368       syslog(LOG_ERR, "setsockopt SO_BROADCAST: %m");
369       close(sock);
370       return (-1);
371     }
372 #endif
373
374   if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) 
375     {
376       perror("SO_REUSEADDR failed");
377       return (-1);
378     }
379
380
381
382 #ifdef SO_RCVBUF
383
384   for (on = bufspace; ; on -= 1024) 
385     {
386       if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF,
387                      &on, sizeof (on)) == 0)
388         break;
389       if (on <= 8*1024) 
390         {
391           perror("setsockopt");
392           syslog(LOG_ERR, "setsockopt SO_RCVBUF: %m");
393           break;
394         }
395     }
396
397
398 #endif
399
400
401   /*
402    * WHEN USING KERNEL 2.6 THIS MUST HAPPEN PRIOR TO THE PORT BINDING!!!!
403    */
404
405   /* Bind to device */
406   if(bind_socket_to_device(sock, int_name) < 0)
407     {
408       fprintf(stderr, "Could not bind socket to device... exiting!\n\n");
409       syslog(LOG_ERR, "Could not bind socket to device... exiting!\n\n");
410       return -1;
411     }
412
413
414   if (bind(sock, (struct sockaddr *)sin, sizeof (*sin)) < 0) 
415     {
416       perror("bind");
417       syslog(LOG_ERR, "bind: %m");
418       close(sock);
419       return (-1);
420     }
421
422   /*
423    *One should probably fetch the flags first
424    *using F_GETFL....
425    */
426   if (fcntl(sock, F_SETFL, O_NONBLOCK) == -1)
427     syslog(LOG_ERR, "fcntl O_NONBLOCK: %m\n");
428
429   return (sock);
430 }
431
432
433 /**
434  *Creates a nonblocking IPv6 socket
435  *@param sin sockaddr_in6 struct. Used for bind(2).
436  *@return the FD of the socket or -1 on error.
437  */
438 int
439 getsocket6(struct sockaddr_in6 *sin, int bufspace, char *int_name)
440 {
441   int sock, on = 1;
442
443
444
445   if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) 
446     {
447       perror("socket");
448       syslog(LOG_ERR, "socket: %m");
449       return (-1);
450     }
451
452
453
454   //#ifdef SO_BROADCAST
455   /*
456   if (setsockopt(sock, SOL_SOCKET, SO_MULTICAST, &on, sizeof (on)) < 0)
457     {
458       perror("setsockopt");
459       syslog(LOG_ERR, "setsockopt SO_BROADCAST: %m");
460       close(sock);
461       return (-1);
462     }
463   */
464   //#endif
465
466
467
468
469 #ifdef SO_RCVBUF
470   for (on = bufspace; ; on -= 1024) 
471     {
472       if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF,
473                      &on, sizeof (on)) == 0)
474         break;
475       if (on <= 8*1024) 
476         {
477           perror("setsockopt");
478           syslog(LOG_ERR, "setsockopt SO_RCVBUF: %m");
479           break;
480         }
481     }
482
483
484 #endif
485
486   if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) 
487     {
488       perror("SO_REUSEADDR failed");
489       return (-1);
490     }
491
492
493   /*
494    * WHEN USING KERNEL 2.6 THIS MUST HAPPEN PRIOR TO THE PORT BINDING!!!!
495    */
496
497   /* Bind to device */
498   if(bind_socket_to_device(sock, int_name) < 0)
499     {
500       fprintf(stderr, "Could not bind socket to device... exiting!\n\n");
501       syslog(LOG_ERR, "Could not bind socket to device... exiting!\n\n");
502       return -1;
503     }
504
505
506   if (bind(sock, (struct sockaddr *)sin, sizeof (*sin)) < 0) 
507     {
508       perror("bind");
509       syslog(LOG_ERR, "bind: %m");
510       close(sock);
511       return (-1);
512     }
513
514   /*
515    *One should probably fetch the flags first
516    *using F_GETFL....
517    */
518   if (fcntl(sock, F_SETFL, O_NONBLOCK) == -1)
519     syslog(LOG_ERR, "fcntl O_NONBLOCK: %m\n");
520
521
522
523   return (sock);
524 }
525
526
527 /*
528  *From net-tools lib/interface.c
529  *
530  */
531
532 int
533 get_ipv6_address(char *ifname, struct sockaddr_in6 *saddr6, int scope_in)
534 {
535   char addr6[40], devname[IFNAMSIZ];
536   char addr6p[8][5];
537   int plen, scope, dad_status, if_idx;
538   FILE *f;
539   struct sockaddr_in6 tmp_sockaddr6;
540
541   if ((f = fopen(_PATH_PROCNET_IFINET6, "r")) != NULL) 
542     {
543       while (fscanf(f, "%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %20s\n",
544                     addr6p[0], addr6p[1], addr6p[2], addr6p[3],
545                     addr6p[4], addr6p[5], addr6p[6], addr6p[7],
546                     &if_idx, &plen, &scope, &dad_status, devname) != EOF) 
547         {
548           if (!strcmp(devname, ifname)) 
549             {
550               sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s",
551                       addr6p[0], addr6p[1], addr6p[2], addr6p[3],
552                       addr6p[4], addr6p[5], addr6p[6], addr6p[7]);
553               olsr_printf(5, "\tinet6 addr: %s\n", addr6);
554               olsr_printf(5, "\tScope: %d", scope);
555               if(scope == scope_in)
556                 {
557                   olsr_printf(4, "IPv6 addr:\n");
558                   inet_pton(AF_INET6,addr6,&tmp_sockaddr6);
559                   memcpy(&saddr6->sin6_addr, &tmp_sockaddr6, sizeof(struct in6_addr));    
560                   fclose(f);
561                   return 1;
562                 }
563             }
564         }
565       fclose(f);
566     }
567   
568   return 0;
569 }
570
571
572 /**
573  * Wrapper for sendto(2)
574  */
575
576 ssize_t
577 olsr_sendto(int s, 
578             const void *buf, 
579             size_t len, 
580             int flags, 
581             const struct sockaddr *to, 
582             socklen_t tolen)
583 {
584   return sendto(s, buf, len, flags, to, tolen);
585 }
586
587 /**
588  * Wrapper for recvfrom(2)
589  */
590
591 ssize_t  
592 olsr_recvfrom(int  s, 
593               void *buf, 
594               size_t len, 
595               int flags, 
596               struct sockaddr *from,
597               socklen_t *fromlen)
598 {
599   return recvfrom(s, 
600                   buf, 
601                   len, 
602                   0, 
603                   from, 
604                   fromlen);
605 }
606
607
608
609 int
610 check_wireless_interface(char *ifname)
611 {
612   struct ifreq ifr;
613
614   memset(&ifr, 0, sizeof(ifr));
615   strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
616
617   if(ioctl(ioctl_s, SIOCGIWNAME, &ifr) >= 0)
618     {
619       return 1;
620     }
621   else
622     {
623       return 0;
624     }
625
626 }