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