linux: put #ifdef __linux__ around code
[olsrd.git] / src / linux / net.c
1
2 /*
3  * The olsr.org Optimized Link-State Routing daemon(olsrd)
4  * Copyright (c) 2004, Andreas Tonnesen(andreto@olsr.org)
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  *   notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above copyright
14  *   notice, this list of conditions and the following disclaimer in
15  *   the documentation and/or other materials provided with the
16  *   distribution.
17  * * Neither the name of olsr.org, olsrd nor the names of its
18  *   contributors may be used to endorse or promote products derived
19  *   from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *
34  * Visit http://www.olsr.org for more information.
35  *
36  * If you find this software useful feel free to make a donation
37  * to the project. For more information see the website or contact
38  * the copyright holders.
39  *
40  */
41
42 /*
43  * Linux specific code
44  */
45
46 #ifdef __linux__
47 #define __BSD_SOURCE 1
48
49 #include "../net_os.h"
50 #include "../ipcalc.h"
51 #include "../olsr.h"
52 #include "../log.h"
53 #include "kernel_tunnel.h"
54
55 #include <net/if.h>
56
57 #include <sys/ioctl.h>
58 #include <sys/utsname.h>
59
60 #include <fcntl.h>
61 #include <string.h>
62 #include <stdio.h>
63 #include <syslog.h>
64 #include <unistd.h>
65
66 /**
67  * Fix bug in GLIBC, see https://bugzilla.redhat.com/show_bug.cgi?id=635260
68  */
69 #ifdef IPTOS_CLASS
70 #undef IPTOS_CLASS
71 #endif /* IPTOS_CLASS */
72 #define IPTOS_CLASS(class)    ((class) & IPTOS_CLASS_MASK)
73
74 #define IPV6_ADDR_LOOPBACK      0x0010U
75 #define IPV6_ADDR_LINKLOCAL     0x0020U
76 #define IPV6_ADDR_SITELOCAL     0x0040U
77
78 /* ip forwarding */
79 #define PROC_IPFORWARD_V4 "/proc/sys/net/ipv4/ip_forward"
80 #define PROC_IPFORWARD_V6 "/proc/sys/net/ipv6/conf/all/forwarding"
81
82 /* Redirect proc entry */
83 #define PROC_IF_REDIRECT "/proc/sys/net/ipv4/conf/%s/send_redirects"
84 #define PROC_ALL_REDIRECT "/proc/sys/net/ipv4/conf/all/send_redirects"
85
86 /* IP spoof proc entry */
87 #define PROC_IF_SPOOF "/proc/sys/net/ipv4/conf/%s/rp_filter"
88 #define PROC_ALL_SPOOF "/proc/sys/net/ipv4/conf/all/rp_filter"
89
90 /* list of IPv6 interfaces */
91 #define PATH_PROCNET_IFINET6           "/proc/net/if_inet6"
92
93 /* values olsrd wants in procfs */
94 #define OLSRD_FORWARD_VALUE '1'
95 #define OLSRD_REDIRECT_VALUE '0'
96 #define OLSRD_SPOOF_VALUE '0'
97
98 /*
99  *Wireless definitions for ioctl calls
100  *(from linux/wireless.h)
101  */
102 #define SIOCGIWNAME     0x8B01  /* get name == wireless protocol */
103 #define SIOCGIWRATE     0x8B21  /* get default bit rate (bps) */
104
105 /* The original state of the IP forwarding proc entry */
106 static char orig_fwd_state;
107 static char orig_global_redirect_state;
108 static char orig_global_rp_filter;
109 static char orig_tunnel_rp_filter;
110
111 /**
112  *Bind a socket to a device
113  *
114  *@param sock the socket to bind
115  *@param dev_name name of the device
116  *
117  *@return negative if error
118  */
119
120 int
121 bind_socket_to_device(int sock, char *dev_name)
122 {
123   /*
124    *Bind to device using the SO_BINDTODEVICE flag
125    */
126   OLSR_PRINTF(3, "Binding socket %d to device %s\n", sock, dev_name);
127   return setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, dev_name, strlen(dev_name) + 1);
128 }
129
130 static int writeToProc(const char *file, char *old, char value) {
131   int fd;
132   char rv;
133
134   if ((fd = open(file, O_RDWR)) < 0) {
135     OLSR_PRINTF(0, "Error, cannot open proc entry %s: %s (%d)\n", file, strerror(errno), errno);
136     return -1;
137   }
138
139   if (read(fd, &rv, 1) != 1) {
140     OLSR_PRINTF(0, "Error, cannot read proc entry %s: %s (%d)\n", file, strerror(errno), errno);
141     goto writeToProcError;
142   }
143
144   if (rv != value && value != 0) {
145     if (lseek(fd, SEEK_SET, 0) == -1) {
146       OLSR_PRINTF(0, "Error, cannot rewind proc entry %s: %s (%d)\n", file, strerror(errno), errno);
147       goto writeToProcError;
148     }
149
150     if (write(fd, &value, 1) != 1) {
151       OLSR_PRINTF(0, "Error, cannot write proc entry %s: %s (%d)\n", file, strerror(errno), errno);
152       goto writeToProcError;
153     }
154   }
155
156   close(fd);
157
158   if (old) {
159     *old = rv;
160   }
161
162   if (value) {
163     olsr_syslog(OLSR_LOG_INFO, "Writing '%c' (was %c) to %s", value, rv, file);
164   }
165   return 0;
166
167 writeToProcError:
168   close (fd);
169   return -1;
170 }
171
172 /* write new value to proc file if current value is different*/
173 static int restoreProc(const char *file, char original, char value) {
174   if ( original == value ) return 0;
175   else return writeToProc(file, NULL, original);
176 }
177
178 static bool is_at_least_linuxkernel_2_6_31(void) {
179   struct utsname uts;
180   char *next;
181   int first = 0, second = 0, third = 0;
182
183   memset(&uts, 0, sizeof(uts));
184   if (uname(&uts)) {
185     OLSR_PRINTF(1, "Error, could not read kernel version: %s (%d)\n", strerror(errno), errno);
186     return false;
187   }
188
189   first = strtol(uts.release, &next, 10);
190   /* check for linux 3.x */
191   if (first >= 3) {
192     return true;
193   }
194
195   if (*next != '.') {
196     goto kernel_parse_error;
197   }
198
199   second = strtol(next+1, &next, 10);
200   if (*next != '.') {
201     goto kernel_parse_error;
202   }
203
204   third = strtol(next+1, NULL, 10);
205
206   /* better or equal than linux 2.6.31 ? */
207   return first == 2 && second == 6 && third >= 31;
208
209 kernel_parse_error:
210   OLSR_PRINTF(1, "Error, cannot parse kernel version: %s\n", uts.release);
211   return false;
212 }
213
214 /**
215  * Setup global interface options (icmp redirect, ip forwarding, rp_filter)
216  * @return 1 on success 0 on failure
217  */
218 void
219 net_os_set_global_ifoptions(void) {
220
221   if (writeToProc(olsr_cnf->ip_version == AF_INET ? PROC_IPFORWARD_V4 : PROC_IPFORWARD_V6, &orig_fwd_state,
222           olsr_cnf->set_ip_forward ? OLSRD_FORWARD_VALUE : 0 )) {
223     OLSR_PRINTF(1, "Warning, could not enable IP forwarding!\n"
224         "you should manually ensure that IP forwarding is enabled!\n\n");
225     olsr_startup_sleep(3);
226   }
227   else if ((!olsr_cnf->set_ip_forward) && (orig_fwd_state != OLSRD_FORWARD_VALUE)) {
228     olsr_exit("IP forwarding not activated, shutting down.\n", 1);
229   }
230
231   if (olsr_cnf->smart_gw_active) {
232     char procfile[FILENAME_MAX];
233
234     /* Generate the procfile name */
235     if (olsr_cnf->ip_version == AF_INET || olsr_cnf->use_niit) {
236       snprintf(procfile, sizeof(procfile), PROC_IF_SPOOF, TUNNEL_ENDPOINT_IF);
237       if (writeToProc(procfile, &orig_tunnel_rp_filter, OLSRD_SPOOF_VALUE)) {
238         OLSR_PRINTF(0, "WARNING! Could not disable the IP spoof filter for tunnel!\n"
239             "you should manually ensure that IP spoof filtering is disabled!\n\n");
240
241         olsr_startup_sleep(3);
242       }
243     }
244   }
245
246   if (olsr_cnf->ip_version == AF_INET) {
247     if (writeToProc(PROC_ALL_REDIRECT, &orig_global_redirect_state, OLSRD_REDIRECT_VALUE)) {
248       OLSR_PRINTF(1, "WARNING! Could not disable ICMP redirects!\n"
249           "you should manually ensure that ICMP redirects are disabled!\n\n");
250
251       olsr_startup_sleep(3);
252     }
253
254     /* check kernel version and disable global rp_filter */
255     if (is_at_least_linuxkernel_2_6_31()) {
256       if (writeToProc(PROC_ALL_SPOOF, &orig_global_rp_filter, OLSRD_SPOOF_VALUE)) {
257         OLSR_PRINTF(1, "WARNING! Could not disable global rp_filter (necessary for kernel 2.6.31 and higher!\n"
258             "you should manually ensure that rp_filter is disabled!\n\n");
259
260         olsr_startup_sleep(3);
261       }
262     }
263   }
264   return;
265 }
266
267 /**
268  *
269  *@return 1 on sucess 0 on failiure
270  */
271 int
272 net_os_set_ifoptions(const char *if_name, struct interface *iface)
273 {
274   char procfile[FILENAME_MAX];
275   if (olsr_cnf->ip_version == AF_INET6)
276     return -1;
277
278   /* Generate the procfile name */
279   snprintf(procfile, sizeof(procfile), PROC_IF_REDIRECT, if_name);
280
281   if (writeToProc(procfile, &iface->nic_state.redirect, OLSRD_REDIRECT_VALUE)) {
282     OLSR_PRINTF(0, "WARNING! Could not disable ICMP redirects!\n"
283         "you should manually ensure that ICMP redirects are disabled!\n\n");
284     olsr_startup_sleep(3);
285     return 0;
286   }
287
288   /* Generate the procfile name */
289   snprintf(procfile, sizeof(procfile), PROC_IF_SPOOF, if_name);
290
291   if (writeToProc(procfile, &iface->nic_state.spoof, OLSRD_SPOOF_VALUE)) {
292     OLSR_PRINTF(0, "WARNING! Could not disable the IP spoof filter!\n"
293         "you should manually ensure that IP spoof filtering is disabled!\n\n");
294
295     olsr_startup_sleep(3);
296     return 0;
297   }
298   return 1;
299 }
300
301 /**
302  *Resets the spoof filter and ICMP redirect settings
303  */
304 int
305 net_os_restore_ifoptions(void)
306 {
307   struct interface *ifs;
308   char procfile[FILENAME_MAX];
309
310   OLSR_PRINTF(1, "Restoring network state\n");
311
312   /* Restore IP forwarding to original value */
313   if (olsr_cnf->set_ip_forward) {
314     if (restoreProc(olsr_cnf->ip_version == AF_INET ? PROC_IPFORWARD_V4 : PROC_IPFORWARD_V6, orig_fwd_state, OLSRD_FORWARD_VALUE)) {
315       OLSR_PRINTF(1, "Error, could not restore ip_forward settings\n");
316     }
317   }
318
319   if (olsr_cnf->smart_gw_active && (olsr_cnf->ip_version == AF_INET || olsr_cnf->use_niit)) {
320     /* Generate the procfile name */
321     snprintf(procfile, sizeof(procfile), PROC_IF_SPOOF, TUNNEL_ENDPOINT_IF);
322     if (restoreProc(procfile, orig_tunnel_rp_filter, OLSRD_SPOOF_VALUE)) {
323       OLSR_PRINTF(0, "WARNING! Could not restore the IP spoof filter for tunnel!\n");
324     }
325   }
326
327   if (olsr_cnf->ip_version == AF_INET) {
328     /* Restore global ICMP redirect setting */
329     if (restoreProc(PROC_ALL_REDIRECT, orig_global_redirect_state, OLSRD_REDIRECT_VALUE)) {
330       OLSR_PRINTF(1, "Error, could not restore global icmp_redirect setting\n");
331     }
332
333     /* Restore global rp_filter setting for linux 2.6.31+ */
334     if (is_at_least_linuxkernel_2_6_31()) {
335       if (restoreProc(PROC_ALL_SPOOF, orig_global_rp_filter, OLSRD_SPOOF_VALUE)) {
336         OLSR_PRINTF(1, "Error, could not restore global rp_filter setting\n");
337       }
338     }
339     for (ifs = ifnet; ifs != NULL; ifs = ifs->int_next) {
340       /* Discard host-emulation interfaces */
341       if (ifs->is_hcif)
342         continue;
343
344       /* ICMP redirects */
345       snprintf(procfile, sizeof(procfile), PROC_IF_REDIRECT, ifs->int_name);
346       if (restoreProc(procfile, ifs->nic_state.redirect, OLSRD_REDIRECT_VALUE)) {
347         OLSR_PRINTF(1, "Error, could not restore icmp_redirect for interface %s\n", ifs->int_name);
348       }
349
350       /* Spoof filter */
351       sprintf(procfile, PROC_IF_SPOOF, ifs->int_name);
352       if (restoreProc(procfile, ifs->nic_state.spoof, OLSRD_SPOOF_VALUE)) {
353         OLSR_PRINTF(1, "Error, could not restore rp_filter for interface %s\n", ifs->int_name);
354       }
355     }
356   }
357   return 1;
358 }
359
360 /**
361  *Creates a blocking tcp socket for communication with switch daemon.
362  *@param sa sockaddr struct. Used for bind(2).
363  *@return the FD of the socket or -1 on error.
364  */
365 int
366 gethemusocket(struct sockaddr_in *pin)
367 {
368   int sock, on = 1;
369
370   OLSR_PRINTF(1, "       Connecting to switch daemon port 10150...");
371   if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
372     perror("hcsocket");
373     syslog(LOG_ERR, "hcsocket: %m");
374     return -1;
375   }
376
377   if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) {
378     perror("SO_REUSEADDR failed");
379     close(sock);
380     return -1;
381   }
382   /* connect to PORT on HOST */
383   if (connect(sock, (struct sockaddr *)pin, sizeof(*pin)) < 0) {
384     printf("FAILED\n");
385     fprintf(stderr, "Error connecting %d - %s\n", errno, strerror(errno));
386     printf("connection refused\n");
387     close(sock);
388     return -1;
389   }
390
391   printf("OK\n");
392
393   /* Keep TCP socket blocking */
394   return sock;
395 }
396
397 /**
398  *Creates a nonblocking broadcast socket.
399  *@param sa sockaddr struct. Used for bind(2).
400  *@return the FD of the socket or -1 on error.
401  */
402 int
403 getsocket(int bufspace, struct interface *ifp)
404 {
405   struct sockaddr_in sin;
406   int on;
407   int sock = socket(AF_INET, SOCK_DGRAM, 0);
408   if (sock < 0) {
409     perror("socket");
410     syslog(LOG_ERR, "socket: %m");
411     return -1;
412   }
413
414   on = 1;
415 #ifdef SO_BROADCAST
416   if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)) < 0) {
417     perror("setsockopt");
418     syslog(LOG_ERR, "setsockopt SO_BROADCAST: %m");
419     close(sock);
420     return -1;
421   }
422 #endif /* SO_BROADCAST */
423
424   if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) {
425     perror("SO_REUSEADDR failed");
426     close(sock);
427     return -1;
428   }
429 #ifdef SO_RCVBUF
430   if(bufspace > 0) {
431     for (on = bufspace;; on -= 1024) {
432       if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &on, sizeof(on)) == 0)
433         break;
434       if (on <= 8 * 1024) {
435         perror("setsockopt");
436         syslog(LOG_ERR, "setsockopt SO_RCVBUF: %m");
437         break;
438       }
439     }
440   }
441 #endif /* SO_RCVBUF */
442
443   /*
444    * WHEN USING KERNEL 2.6 THIS MUST HAPPEN PRIOR TO THE PORT BINDING!!!!
445    */
446
447   /* Bind to device */
448   if (bind_socket_to_device(sock, ifp->int_name) < 0) {
449     fprintf(stderr, "Could not bind socket to device... exiting!\n\n");
450     syslog(LOG_ERR, "Could not bind socket to device... exiting!\n\n");
451     close(sock);
452     return -1;
453   }
454
455   memset(&sin, 0, sizeof(sin));
456   sin.sin_family = AF_INET;
457   sin.sin_port = htons(olsr_cnf->olsrport);
458
459   if(bufspace <= 0) {
460     sin.sin_addr.s_addr = ifp->int_addr.sin_addr.s_addr;
461   }
462
463   if (bind(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
464     perror("bind");
465     syslog(LOG_ERR, "bind: %m");
466     close(sock);
467     return -1;
468   }
469
470   on = fcntl(sock, F_GETFL);
471   if (on == -1) {
472     syslog(LOG_ERR, "fcntl (F_GETFL): %m\n");
473   } else {
474     if (fcntl(sock, F_SETFL, on | O_NONBLOCK) == -1) {
475       syslog(LOG_ERR, "fcntl O_NONBLOCK: %m\n");
476     }
477   }
478   return sock;
479 }
480
481 /**
482  *Creates a nonblocking IPv6 socket
483  *@param sin sockaddr_in6 struct. Used for bind(2).
484  *@return the FD of the socket or -1 on error.
485  */
486 int
487 getsocket6(int bufspace, struct interface *ifp)
488 {
489   struct sockaddr_in6 sin;
490   int on;
491   int sock = socket(AF_INET6, SOCK_DGRAM, 0);
492   if (sock < 0) {
493     perror("socket");
494     syslog(LOG_ERR, "socket: %m");
495     return (-1);
496   }
497 #ifdef IPV6_V6ONLY
498   on = 1;
499   if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0) {
500     perror("setsockopt(IPV6_V6ONLY)");
501     syslog(LOG_ERR, "setsockopt(IPV6_V6ONLY): %m");
502   }
503 #endif /* IPV6_V6ONLY */
504
505   //#ifdef SO_BROADCAST
506   /*
507      if (setsockopt(sock, SOL_SOCKET, SO_MULTICAST, &on, sizeof (on)) < 0)
508      {
509      perror("setsockopt");
510      syslog(LOG_ERR, "setsockopt SO_BROADCAST: %m");
511      close(sock);
512      return (-1);
513      }
514    */
515   //#endif /* SO_BROADCAST */
516
517 #ifdef SO_RCVBUF
518   if(bufspace > 0) {
519     for (on = bufspace;; on -= 1024) {
520       if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &on, sizeof(on)) == 0)
521         break;
522       if (on <= 8 * 1024) {
523         perror("setsockopt");
524         syslog(LOG_ERR, "setsockopt SO_RCVBUF: %m");
525         break;
526       }
527     }
528   }
529 #endif /* SO_RCVBUF */
530
531   if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) {
532     perror("SO_REUSEADDR failed");
533     close(sock);
534     return (-1);
535   }
536
537   /*
538    * WHEN USING KERNEL 2.6 THIS MUST HAPPEN PRIOR TO THE PORT BINDING!!!!
539    */
540
541   /* Bind to device */
542   if (bind_socket_to_device(sock, ifp->int_name) < 0) {
543     fprintf(stderr, "Could not bind socket to device... exiting!\n\n");
544     syslog(LOG_ERR, "Could not bind socket to device... exiting!\n\n");
545     close(sock);
546     return -1;
547   }
548
549   memset(&sin, 0, sizeof(sin));
550   sin.sin6_family = AF_INET6;
551   sin.sin6_port = htons(olsr_cnf->olsrport);
552   sin.sin6_scope_id = ifp->if_index;
553
554   if(bufspace <= 0) {
555     memcpy(&sin.sin6_addr, &ifp->int6_addr.sin6_addr, sizeof(struct in6_addr));
556   }
557
558   if (bind(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
559     struct ipaddr_str buf;
560     OLSR_PRINTF(1, "Error, cannot bind address %s to %s-socket: %s (%d)\n",
561         inet_ntop(sin.sin6_family, &sin.sin6_addr, buf.buf, sizeof(buf)),
562         bufspace <= 0 ? "transmit" : "receive",
563         strerror(errno), errno);
564     syslog(LOG_ERR, "bind: %m");
565     close(sock);
566     return (-1);
567   }
568
569   on = fcntl(sock, F_GETFL);
570   if (on == -1) {
571     syslog(LOG_ERR, "fcntl (F_GETFL): %m\n");
572   } else {
573     if (fcntl(sock, F_SETFL, on | O_NONBLOCK) == -1) {
574       syslog(LOG_ERR, "fcntl O_NONBLOCK: %m\n");
575     }
576   }
577   return sock;
578 }
579
580 int
581 join_mcast(struct interface *ifs, int sock)
582 {
583   /* See linux/in6.h */
584   struct ipaddr_str buf;
585   struct ipv6_mreq mcastreq;
586
587   mcastreq.ipv6mr_multiaddr = ifs->int6_multaddr.sin6_addr;
588   mcastreq.ipv6mr_interface = ifs->if_index;
589
590 #if !defined __FreeBSD__ && !defined __FreeBSD_kernel__ && !defined __APPLE__ && !defined __NetBSD__
591   OLSR_PRINTF(3, "Interface %s joining multicast %s...", ifs->int_name, ip6_to_string(&buf, &ifs->int6_multaddr.sin6_addr));
592   /* Send multicast */
593   if (setsockopt(sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, (char *)&mcastreq, sizeof(struct ipv6_mreq)) < 0) {
594     perror("Join multicast");
595     return -1;
596   }
597 #else /* !defined __FreeBSD__ && !defined __FreeBSD_kernel__ && !defined __APPLE__ && !defined __NetBSD__ */
598 #warning implement IPV6_ADD_MEMBERSHIP
599 #endif /* !defined __FreeBSD__ && !defined __FreeBSD_kernel__ && !defined __APPLE__ && !defined __NetBSD__ */
600
601   /* Old libc fix */
602 #ifdef IPV6_JOIN_GROUP
603   /* Join receiver group */
604   if (setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, (char *)&mcastreq, sizeof(struct ipv6_mreq)) < 0)
605 #else /* IPV6_JOIN_GROUP */
606   /* Join receiver group */
607   if (setsockopt(sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, (char *)&mcastreq, sizeof(struct ipv6_mreq)) < 0)
608 #endif /* IPV6_JOIN_GROUP */
609   {
610     perror("Join multicast send");
611     return -1;
612   }
613
614   if (setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_IF, (char *)&mcastreq.ipv6mr_interface, sizeof(mcastreq.ipv6mr_interface)) < 0) {
615     perror("Set multicast if");
616     return -1;
617   }
618
619   OLSR_PRINTF(3, "OK\n");
620   return 0;
621 }
622
623 /*
624  *From net-tools lib/interface.c
625  *
626  */
627 int
628 get_ipv6_address(char *ifname, struct sockaddr_in6 *saddr6, struct olsr_ip_prefix *prefix)
629 {
630   char addr6[40], devname[IFNAMSIZ];
631   char addr6p[8][5];
632   int plen, scope, dad_status, if_idx;
633   FILE *f;
634   union olsr_ip_addr tmp_ip;
635
636   if ((f = fopen(PATH_PROCNET_IFINET6, "r")) != NULL) {
637     while (fscanf
638            (f, "%4s%4s%4s%4s%4s%4s%4s%4s %x %02x %02x %02x %16s\n", addr6p[0], addr6p[1], addr6p[2], addr6p[3], addr6p[4],
639             addr6p[5], addr6p[6], addr6p[7], &if_idx, &plen, &scope, &dad_status, devname) != EOF) {
640       if (!strcmp(devname, ifname)) {
641         bool isNetWide = false;
642         sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s", addr6p[0], addr6p[1], addr6p[2], addr6p[3], addr6p[4], addr6p[5], addr6p[6],
643                 addr6p[7]);
644         OLSR_PRINTF(5, "\tinet6 addr: %s\n", addr6);
645         OLSR_PRINTF(5, "\tScope: %d\n", scope);
646
647         if (inet_pton(AF_INET6, addr6, &tmp_ip.v6)) {
648           continue;
649         }
650
651         isNetWide = (scope != IPV6_ADDR_LOOPBACK) && (scope != IPV6_ADDR_LINKLOCAL) && (scope != IPV6_ADDR_SITELOCAL);
652
653         if ((prefix == NULL && isNetWide) || (prefix != NULL && ip_in_net(&tmp_ip, prefix))) {
654           OLSR_PRINTF(4, "Found addr: %s:%s:%s:%s:%s:%s:%s:%s\n", addr6p[0], addr6p[1], addr6p[2], addr6p[3], addr6p[4], addr6p[5],
655                       addr6p[6], addr6p[7]);
656           memcpy(&saddr6->sin6_addr, &tmp_ip.v6, sizeof(struct in6_addr));
657           fclose(f);
658           return 1;
659         }
660       }
661     }
662     fclose(f);
663   }
664   return 0;
665 }
666
667 /**
668  * Wrapper for sendto(2)
669  */
670 ssize_t
671 olsr_sendto(int s, const void *buf, size_t len, int flags, const struct sockaddr * to, socklen_t tolen)
672 {
673   return sendto(s, buf, len, flags, to, tolen);
674 }
675
676 /**
677  * Wrapper for recvfrom(2)
678  */
679
680 ssize_t
681 olsr_recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr * from, socklen_t * fromlen)
682 {
683   return recvfrom(s, buf, len, flags, from, fromlen);
684 }
685
686 /**
687  * Wrapper for select(2)
688  */
689
690 int
691 olsr_select(int nfds, fd_set * readfds, fd_set * writefds, fd_set * exceptfds, struct timeval *timeout)
692 {
693   return select(nfds, readfds, writefds, exceptfds, timeout);
694 }
695
696 int
697 check_wireless_interface(char *ifname)
698 {
699   struct ifreq ifr;
700
701   memset(&ifr, 0, sizeof(ifr));
702   strscpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
703
704   return (ioctl(olsr_cnf->ioctl_s, SIOCGIWNAME, &ifr) >= 0) ? 1 : 0;
705 }
706
707 int
708 calculate_if_metric(char *ifname)
709 {
710   return check_wireless_interface(ifname);
711 }
712
713 bool olsr_if_isup(const char * dev)
714 {
715   struct ifreq ifr;
716
717   memset(&ifr, 0, sizeof(ifr));
718   strscpy(ifr.ifr_name, dev, IFNAMSIZ);
719
720   if (ioctl(olsr_cnf->ioctl_s, SIOCGIFFLAGS, &ifr) < 0) {
721     OLSR_PRINTF(1, "ioctl SIOCGIFFLAGS (get flags) error on device %s: %s (%d)\n",
722         dev, strerror(errno), errno);
723     return 1;
724   }
725   return (ifr.ifr_flags & IFF_UP) != 0;
726 }
727
728 int olsr_if_set_state(const char *dev, bool up) {
729   int oldflags;
730   struct ifreq ifr;
731
732   memset(&ifr, 0, sizeof(ifr));
733   strscpy(ifr.ifr_name, dev, IFNAMSIZ);
734
735   if (ioctl(olsr_cnf->ioctl_s, SIOCGIFFLAGS, &ifr) < 0) {
736     OLSR_PRINTF(1, "ioctl SIOCGIFFLAGS (get flags) error on device %s: %s (%d)\n",
737         dev, strerror(errno), errno);
738     return 1;
739   }
740
741   oldflags = ifr.ifr_flags;
742   if (up) {
743     ifr.ifr_flags |= IFF_UP;
744   }
745   else {
746     ifr.ifr_flags &= ~IFF_UP;
747   }
748
749   if (oldflags == ifr.ifr_flags) {
750     /* interface is already up/down */
751     return 0;
752   }
753
754   if (ioctl(olsr_cnf->ioctl_s, SIOCSIFFLAGS, &ifr) < 0) {
755     OLSR_PRINTF(1, "ioctl SIOCSIFFLAGS (set flags %s) error on device %s: %s (%d)\n",
756         up ? "up" : "down", dev, strerror(errno), errno);
757     return 1;
758   }
759   return 0;
760 }
761 #endif /* __linux__ */
762
763 /*
764  * Local Variables:
765  * c-basic-offset: 2
766  * indent-tabs-mode: nil
767  * End:
768  */