eb4d22a76ecd9abee3b3961ecff5ee06939f78e2
[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
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 #if 0 // should not be necessary for IPv6 */
110 static char orig_tunnel6_rp_filter;
111 #endif
112
113 /**
114  *Bind a socket to a device
115  *
116  *@param sock the socket to bind
117  *@param dev_name name of the device
118  *
119  *@return negative if error
120  */
121
122 int
123 bind_socket_to_device(int sock, char *dev_name)
124 {
125   /*
126    *Bind to device using the SO_BINDTODEVICE flag
127    */
128   OLSR_PRINTF(3, "Binding socket %d to device %s\n", sock, dev_name);
129   return setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, dev_name, strlen(dev_name) + 1);
130 }
131
132 static int writeToProc(const char *file, char *old, char value) {
133   int fd;
134   char rv;
135
136   if ((fd = open(file, O_RDWR)) < 0) {
137     OLSR_PRINTF(0, "Error, cannot open proc entry %s: %s (%d)\n", file, strerror(errno), errno);
138     return -1;
139   }
140
141   if (read(fd, &rv, 1) != 1) {
142     OLSR_PRINTF(0, "Error, cannot read proc entry %s: %s (%d)\n", file, strerror(errno), errno);
143     return -1;
144   }
145
146   if (rv != value && value != 0) {
147     if (lseek(fd, SEEK_SET, 0) == -1) {
148       OLSR_PRINTF(0, "Error, cannot rewind proc entry %s: %s (%d)\n", file, strerror(errno), errno);
149       return -1;
150     }
151
152     if (write(fd, &value, 1) != 1) {
153       OLSR_PRINTF(0, "Error, cannot write proc entry %s: %s (%d)\n", file, strerror(errno), errno);
154       return -1;
155     }
156   }
157
158   if (close(fd) != 0) {
159     OLSR_PRINTF(0, "Error while closing proc entry %s: %s (%d)\n", file, strerror(errno), errno);
160     return -1;
161   }
162
163   if (old) {
164     *old = rv;
165   }
166
167   if (value) {
168     olsr_syslog(OLSR_LOG_INFO, "Writing '%c' (was %c) to %s", value, rv, file);
169   }
170   return 0;
171 }
172
173 /* write new value to proc file if current value is different*/
174 static int restoreProc(const char *file, char original, char value) {
175   if ( original == value ) return 0;
176   else return writeToProc(file, NULL, original);
177 }
178
179 static bool is_at_least_linuxkernel_2_6_31(void) {
180   struct utsname uts;
181   char *next;
182   int first = 0, second = 0, third = 0;
183
184   memset(&uts, 0, sizeof(uts));
185   if (uname(&uts)) {
186     OLSR_PRINTF(1, "Error, could not read kernel version: %s (%d)\n", strerror(errno), errno);
187     return false;
188   }
189
190   first = strtol(uts.release, &next, 10);
191   /* check for linux 3.x */
192   if (first >= 3) {
193     return true;
194   }
195
196   if (*next != '.') {
197     goto kernel_parse_error;
198   }
199
200   second = strtol(next+1, &next, 10);
201   if (*next != '.') {
202     goto kernel_parse_error;
203   }
204
205   third = strtol(next+1, NULL, 10);
206
207   /* better or equal than linux 2.6.31 ? */
208   return first == 2 && second == 6 && third >= 31;
209
210 kernel_parse_error:
211   OLSR_PRINTF(1, "Error, cannot parse kernel version: %s\n", uts.release);
212   return false;
213 }
214
215 /**
216  * Setup global interface options (icmp redirect, ip forwarding, rp_filter)
217  * @return 1 on success 0 on failure
218  */
219 void
220 net_os_set_global_ifoptions(void) {
221
222   if (writeToProc(olsr_cnf->ip_version == AF_INET ? PROC_IPFORWARD_V4 : PROC_IPFORWARD_V6, &orig_fwd_state, OLSRD_FORWARD_VALUE)) {
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 mannually ensure that IP spoof filtering is disabled!\n\n");
240
241         olsr_startup_sleep(3);
242       }
243     }
244
245 #if 0 // should not be necessary for IPv6
246     if (olsr_cnf->ip_version == AF_INET6) {
247       snprintf(procfile, sizeof(procfile), PROC_IF_SPOOF, TUNNEL_ENDPOINT_IF6);
248       if (writeToProc(procfile, &orig_tunnel6_rp_filter, OLSRD_SPOOF_VALUE)) {
249         OLSR_PRINTF(0, "WARNING! Could not disable the IP spoof filter for tunnel6!\n"
250             "you should mannually ensure that IP spoof filtering is disabled!\n\n");
251
252         olsr_startup_sleep(3);
253       }
254     }
255 #endif
256   }
257
258   if (olsr_cnf->ip_version == AF_INET) {
259     if (writeToProc(PROC_ALL_REDIRECT, &orig_global_redirect_state, OLSRD_REDIRECT_VALUE)) {
260       OLSR_PRINTF(1, "WARNING! Could not disable ICMP redirects!\n"
261           "you should manually ensure that ICMP redirects are disabled!\n\n");
262
263       olsr_startup_sleep(3);
264     }
265
266     /* check kernel version and disable global rp_filter */
267     if (is_at_least_linuxkernel_2_6_31()) {
268       if (writeToProc(PROC_ALL_SPOOF, &orig_global_rp_filter, OLSRD_SPOOF_VALUE)) {
269         OLSR_PRINTF(1, "WARNING! Could not disable global rp_filter (necessary for kernel 2.6.31 and higher!\n"
270             "you should manually ensure that rp_filter is disabled!\n\n");
271
272         olsr_startup_sleep(3);
273       }
274     }
275   }
276   return;
277 }
278
279 /**
280  *
281  *@return 1 on sucess 0 on failiure
282  */
283 int
284 net_os_set_ifoptions(const char *if_name, struct interface *iface)
285 {
286   char procfile[FILENAME_MAX];
287   if (olsr_cnf->ip_version == AF_INET6)
288     return -1;
289
290   /* Generate the procfile name */
291   snprintf(procfile, sizeof(procfile), PROC_IF_REDIRECT, if_name);
292
293   if (writeToProc(procfile, &iface->nic_state.redirect, OLSRD_REDIRECT_VALUE)) {
294     OLSR_PRINTF(0, "WARNING! Could not disable ICMP redirects!\n"
295         "you should mannually ensure that ICMP redirects are disabled!\n\n");
296     olsr_startup_sleep(3);
297     return 0;
298   }
299
300   /* Generate the procfile name */
301   snprintf(procfile, sizeof(procfile), PROC_IF_SPOOF, if_name);
302
303   if (writeToProc(procfile, &iface->nic_state.spoof, OLSRD_SPOOF_VALUE)) {
304     OLSR_PRINTF(0, "WARNING! Could not disable the IP spoof filter!\n"
305         "you should mannually ensure that IP spoof filtering is disabled!\n\n");
306
307     olsr_startup_sleep(3);
308     return 0;
309   }
310   return 1;
311 }
312
313 /**
314  *Resets the spoof filter and ICMP redirect settings
315  */
316 int
317 net_os_restore_ifoptions(void)
318 {
319   struct interface *ifs;
320   char procfile[FILENAME_MAX];
321
322   OLSR_PRINTF(1, "Restoring network state\n");
323
324   /* Restore IP forwarding to original value */
325   if (olsr_cnf->set_ip_forward) {
326     if (restoreProc(olsr_cnf->ip_version == AF_INET ? PROC_IPFORWARD_V4 : PROC_IPFORWARD_V6, orig_fwd_state, OLSRD_FORWARD_VALUE)) {
327       OLSR_PRINTF(1, "Error, could not restore ip_forward settings\n");
328     }
329   }
330
331   if (olsr_cnf->smart_gw_active && (olsr_cnf->ip_version == AF_INET || olsr_cnf->use_niit)) {
332     /* Generate the procfile name */
333     snprintf(procfile, sizeof(procfile), PROC_IF_SPOOF, TUNNEL_ENDPOINT_IF);
334     if (restoreProc(procfile, orig_tunnel_rp_filter, OLSRD_SPOOF_VALUE)) {
335       OLSR_PRINTF(0, "WARNING! Could not restore the IP spoof filter for tunnel!\n");
336     }
337
338 #if 0 // should not be necessary for IPv6
339     if (olsr_cnf->ip_version == AF_INET6) {
340       snprintf(procfile, sizeof(procfile), PROC_IF_SPOOF, TUNNEL_ENDPOINT_IF6);
341       if (restoreProc(procfile, orig_tunnel6_rp_filter, OLSRD_SPOOF_VALUE)) {
342         OLSR_PRINTF(0, "WARNING! Could not restore the IP spoof filter for tunnel6!\n");
343       }
344     }
345 #endif
346   }
347
348   if (olsr_cnf->ip_version == AF_INET) {
349     /* Restore global ICMP redirect setting */
350     if (restoreProc(PROC_ALL_REDIRECT, orig_global_redirect_state, OLSRD_REDIRECT_VALUE)) {
351       OLSR_PRINTF(1, "Error, could not restore global icmp_redirect setting\n");
352     }
353
354     /* Restore global rp_filter setting for linux 2.6.31+ */
355     if (is_at_least_linuxkernel_2_6_31()) {
356       if (restoreProc(PROC_ALL_SPOOF, orig_global_rp_filter, OLSRD_SPOOF_VALUE)) {
357         OLSR_PRINTF(1, "Error, could not restore global rp_filter setting\n");
358       }
359     }
360     for (ifs = ifnet; ifs != NULL; ifs = ifs->int_next) {
361       /* Discard host-emulation interfaces */
362       if (ifs->is_hcif)
363         continue;
364
365       /* ICMP redirects */
366       snprintf(procfile, sizeof(procfile), PROC_IF_REDIRECT, ifs->int_name);
367       if (restoreProc(procfile, ifs->nic_state.redirect, OLSRD_REDIRECT_VALUE)) {
368         OLSR_PRINTF(1, "Error, could not restore icmp_redirect for interface %s\n", ifs->int_name);
369       }
370
371       /* Spoof filter */
372       sprintf(procfile, PROC_IF_SPOOF, ifs->int_name);
373       if (restoreProc(procfile, ifs->nic_state.spoof, OLSRD_SPOOF_VALUE)) {
374         OLSR_PRINTF(1, "Error, could not restore rp_filter for interface %s\n", ifs->int_name);
375       }
376     }
377   }
378   return 1;
379 }
380
381 /**
382  *Creates a blocking tcp socket for communication with switch daemon.
383  *@param sa sockaddr struct. Used for bind(2).
384  *@return the FD of the socket or -1 on error.
385  */
386 int
387 gethemusocket(struct sockaddr_in *pin)
388 {
389   int sock, on = 1;
390
391   OLSR_PRINTF(1, "       Connecting to switch daemon port 10150...");
392   if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
393     perror("hcsocket");
394     syslog(LOG_ERR, "hcsocket: %m");
395     return -1;
396   }
397
398   if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) {
399     perror("SO_REUSEADDR failed");
400     close(sock);
401     return -1;
402   }
403   /* connect to PORT on HOST */
404   if (connect(sock, (struct sockaddr *)pin, sizeof(*pin)) < 0) {
405     printf("FAILED\n");
406     fprintf(stderr, "Error connecting %d - %s\n", errno, strerror(errno));
407     printf("connection refused\n");
408     close(sock);
409     return -1;
410   }
411
412   printf("OK\n");
413
414   /* Keep TCP socket blocking */
415   return sock;
416 }
417
418 /**
419  *Creates a nonblocking broadcast socket.
420  *@param sa sockaddr struct. Used for bind(2).
421  *@return the FD of the socket or -1 on error.
422  */
423 int
424 getsocket(int bufspace, struct interface *ifp)
425 {
426   struct sockaddr_in sin;
427   int on;
428   int sock = socket(AF_INET, SOCK_DGRAM, 0);
429   if (sock < 0) {
430     perror("socket");
431     syslog(LOG_ERR, "socket: %m");
432     return -1;
433   }
434
435   on = 1;
436 #ifdef SO_BROADCAST
437   if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)) < 0) {
438     perror("setsockopt");
439     syslog(LOG_ERR, "setsockopt SO_BROADCAST: %m");
440     close(sock);
441     return -1;
442   }
443 #endif
444
445   if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) {
446     perror("SO_REUSEADDR failed");
447     close(sock);
448     return -1;
449   }
450 #ifdef SO_RCVBUF
451   if(bufspace > 0) {
452     for (on = bufspace;; on -= 1024) {
453       if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &on, sizeof(on)) == 0)
454         break;
455       if (on <= 8 * 1024) {
456         perror("setsockopt");
457         syslog(LOG_ERR, "setsockopt SO_RCVBUF: %m");
458         break;
459       }
460     }
461   }
462 #endif
463
464   /*
465    * WHEN USING KERNEL 2.6 THIS MUST HAPPEN PRIOR TO THE PORT BINDING!!!!
466    */
467
468   /* Bind to device */
469   if (bind_socket_to_device(sock, ifp->int_name) < 0) {
470     fprintf(stderr, "Could not bind socket to device... exiting!\n\n");
471     syslog(LOG_ERR, "Could not bind socket to device... exiting!\n\n");
472     close(sock);
473     return -1;
474   }
475
476   memset(&sin, 0, sizeof(sin));
477   sin.sin_family = AF_INET;
478   sin.sin_port = htons(olsr_cnf->olsrport);
479
480   if(bufspace <= 0) {
481     sin.sin_addr.s_addr = ifp->int_addr.sin_addr.s_addr;
482   }
483
484   if (bind(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
485     perror("bind");
486     syslog(LOG_ERR, "bind: %m");
487     close(sock);
488     return -1;
489   }
490
491   on = fcntl(sock, F_GETFL);
492   if (on == -1) {
493     syslog(LOG_ERR, "fcntl (F_GETFL): %m\n");
494   } else {
495     if (fcntl(sock, F_SETFL, on | O_NONBLOCK) == -1) {
496       syslog(LOG_ERR, "fcntl O_NONBLOCK: %m\n");
497     }
498   }
499   return sock;
500 }
501
502 /**
503  *Creates a nonblocking IPv6 socket
504  *@param sin sockaddr_in6 struct. Used for bind(2).
505  *@return the FD of the socket or -1 on error.
506  */
507 int
508 getsocket6(int bufspace, struct interface *ifp)
509 {
510   struct sockaddr_in6 sin;
511   int on;
512   int sock = socket(AF_INET6, SOCK_DGRAM, 0);
513   if (sock < 0) {
514     perror("socket");
515     syslog(LOG_ERR, "socket: %m");
516     return (-1);
517   }
518 #ifdef IPV6_V6ONLY
519   on = 1;
520   if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0) {
521     perror("setsockopt(IPV6_V6ONLY)");
522     syslog(LOG_ERR, "setsockopt(IPV6_V6ONLY): %m");
523   }
524 #endif
525
526   //#ifdef SO_BROADCAST
527   /*
528      if (setsockopt(sock, SOL_SOCKET, SO_MULTICAST, &on, sizeof (on)) < 0)
529      {
530      perror("setsockopt");
531      syslog(LOG_ERR, "setsockopt SO_BROADCAST: %m");
532      close(sock);
533      return (-1);
534      }
535    */
536   //#endif
537
538 #ifdef SO_RCVBUF
539   if(bufspace > 0) {
540     for (on = bufspace;; on -= 1024) {
541       if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &on, sizeof(on)) == 0)
542         break;
543       if (on <= 8 * 1024) {
544         perror("setsockopt");
545         syslog(LOG_ERR, "setsockopt SO_RCVBUF: %m");
546         break;
547       }
548     }
549   }
550 #endif
551
552   if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) {
553     perror("SO_REUSEADDR failed");
554     close(sock);
555     return (-1);
556   }
557
558   /*
559    * WHEN USING KERNEL 2.6 THIS MUST HAPPEN PRIOR TO THE PORT BINDING!!!!
560    */
561
562   /* Bind to device */
563   if (bind_socket_to_device(sock, ifp->int_name) < 0) {
564     fprintf(stderr, "Could not bind socket to device... exiting!\n\n");
565     syslog(LOG_ERR, "Could not bind socket to device... exiting!\n\n");
566     close(sock);
567     return -1;
568   }
569
570   memset(&sin, 0, sizeof(sin));
571   sin.sin6_family = AF_INET6;
572   sin.sin6_port = htons(olsr_cnf->olsrport);
573   sin.sin6_scope_id = ifp->if_index;
574
575   if(bufspace <= 0) {
576     memcpy(&sin.sin6_addr, &ifp->int6_addr.sin6_addr, sizeof(struct in6_addr));
577   }
578
579   if (bind(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
580     struct ipaddr_str buf;
581     OLSR_PRINTF(1, "Error, cannot bind address %s to %s-socket: %s (%d)\n",
582         inet_ntop(sin.sin6_family, &sin.sin6_addr, buf.buf, sizeof(buf)),
583         bufspace <= 0 ? "transmit" : "receive",
584         strerror(errno), errno);
585     syslog(LOG_ERR, "bind: %m");
586     close(sock);
587     return (-1);
588   }
589
590   on = fcntl(sock, F_GETFL);
591   if (on == -1) {
592     syslog(LOG_ERR, "fcntl (F_GETFL): %m\n");
593   } else {
594     if (fcntl(sock, F_SETFL, on | O_NONBLOCK) == -1) {
595       syslog(LOG_ERR, "fcntl O_NONBLOCK: %m\n");
596     }
597   }
598   return sock;
599 }
600
601 int
602 join_mcast(struct interface *ifs, int sock)
603 {
604   /* See linux/in6.h */
605   struct ipaddr_str buf;
606   struct ipv6_mreq mcastreq;
607
608   mcastreq.ipv6mr_multiaddr = ifs->int6_multaddr.sin6_addr;
609   mcastreq.ipv6mr_interface = ifs->if_index;
610
611 #if !defined __FreeBSD__ && !defined __FreeBSD_kernel__ && !defined __MacOSX__ && !defined __NetBSD__
612   OLSR_PRINTF(3, "Interface %s joining multicast %s...", ifs->int_name, ip6_to_string(&buf, &ifs->int6_multaddr.sin6_addr));
613   /* Send multicast */
614   if (setsockopt(sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, (char *)&mcastreq, sizeof(struct ipv6_mreq)) < 0) {
615     perror("Join multicast");
616     return -1;
617   }
618 #else
619 #warning implement IPV6_ADD_MEMBERSHIP
620 #endif
621
622   /* Old libc fix */
623 #ifdef IPV6_JOIN_GROUP
624   /* Join receiver group */
625   if (setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, (char *)&mcastreq, sizeof(struct ipv6_mreq)) < 0)
626 #else
627   /* Join receiver group */
628   if (setsockopt(sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, (char *)&mcastreq, sizeof(struct ipv6_mreq)) < 0)
629 #endif
630   {
631     perror("Join multicast send");
632     return -1;
633   }
634
635   if (setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_IF, (char *)&mcastreq.ipv6mr_interface, sizeof(mcastreq.ipv6mr_interface)) < 0) {
636     perror("Set multicast if");
637     return -1;
638   }
639
640   OLSR_PRINTF(3, "OK\n");
641   return 0;
642 }
643
644 /*
645  *From net-tools lib/interface.c
646  *
647  */
648 int
649 get_ipv6_address(char *ifname, struct sockaddr_in6 *saddr6, struct olsr_ip_prefix *prefix)
650 {
651   char addr6[40], devname[IFNAMSIZ];
652   char addr6p[8][5];
653   int plen, scope, dad_status, if_idx;
654   FILE *f;
655   union olsr_ip_addr tmp_ip;
656
657   if ((f = fopen(PATH_PROCNET_IFINET6, "r")) != NULL) {
658     while (fscanf
659            (f, "%4s%4s%4s%4s%4s%4s%4s%4s %x %02x %02x %02x %20s\n", addr6p[0], addr6p[1], addr6p[2], addr6p[3], addr6p[4],
660             addr6p[5], addr6p[6], addr6p[7], &if_idx, &plen, &scope, &dad_status, devname) != EOF) {
661       if (!strcmp(devname, ifname)) {
662         bool isNetWide = false;
663         sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s", addr6p[0], addr6p[1], addr6p[2], addr6p[3], addr6p[4], addr6p[5], addr6p[6],
664                 addr6p[7]);
665         OLSR_PRINTF(5, "\tinet6 addr: %s\n", addr6);
666         OLSR_PRINTF(5, "\tScope: %d\n", scope);
667
668         inet_pton(AF_INET6, addr6, &tmp_ip.v6);
669
670         isNetWide = (scope != IPV6_ADDR_LOOPBACK) && (scope != IPV6_ADDR_LINKLOCAL) && (scope != IPV6_ADDR_SITELOCAL);
671
672         if ((prefix == NULL && isNetWide) || (prefix != NULL && ip_in_net(&tmp_ip, prefix))) {
673           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],
674                       addr6p[6], addr6p[7]);
675           memcpy(&saddr6->sin6_addr, &tmp_ip.v6, sizeof(struct in6_addr));
676           fclose(f);
677           return 1;
678         }
679       }
680     }
681     fclose(f);
682   }
683   return 0;
684 }
685
686 /**
687  * Wrapper for sendto(2)
688  */
689 ssize_t
690 olsr_sendto(int s, const void *buf, size_t len, int flags, const struct sockaddr * to, socklen_t tolen)
691 {
692   return sendto(s, buf, len, flags, to, tolen);
693 }
694
695 /**
696  * Wrapper for recvfrom(2)
697  */
698
699 ssize_t
700 olsr_recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr * from, socklen_t * fromlen)
701 {
702   return recvfrom(s, buf, len, flags, from, fromlen);
703 }
704
705 /**
706  * Wrapper for select(2)
707  */
708
709 int
710 olsr_select(int nfds, fd_set * readfds, fd_set * writefds, fd_set * exceptfds, struct timeval *timeout)
711 {
712   return select(nfds, readfds, writefds, exceptfds, timeout);
713 }
714
715 int
716 check_wireless_interface(char *ifname)
717 {
718   struct ifreq ifr;
719
720   memset(&ifr, 0, sizeof(ifr));
721   strscpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
722
723   return (ioctl(olsr_cnf->ioctl_s, SIOCGIWNAME, &ifr) >= 0) ? 1 : 0;
724 }
725
726 #if 0
727
728 #include <linux/sockios.h>
729 #include <linux/types.h>
730
731 /* This data structure is used for all the MII ioctl's */
732 struct mii_data {
733   __u16 phy_id;
734   __u16 reg_num;
735   __u16 val_in;
736   __u16 val_out;
737 };
738
739 /* Basic Mode Control Register */
740 #define MII_BMCR                0x00
741 #define  MII_BMCR_RESET         0x8000
742 #define  MII_BMCR_LOOPBACK      0x4000
743 #define  MII_BMCR_100MBIT       0x2000
744 #define  MII_BMCR_AN_ENA        0x1000
745 #define  MII_BMCR_ISOLATE       0x0400
746 #define  MII_BMCR_RESTART       0x0200
747 #define  MII_BMCR_DUPLEX        0x0100
748 #define  MII_BMCR_COLTEST       0x0080
749
750 /* Basic Mode Status Register */
751 #define MII_BMSR                0x01
752 #define  MII_BMSR_CAP_MASK      0xf800
753 #define  MII_BMSR_100BASET4     0x8000
754 #define  MII_BMSR_100BASETX_FD  0x4000
755 #define  MII_BMSR_100BASETX_HD  0x2000
756 #define  MII_BMSR_10BASET_FD    0x1000
757 #define  MII_BMSR_10BASET_HD    0x0800
758 #define  MII_BMSR_NO_PREAMBLE   0x0040
759 #define  MII_BMSR_AN_COMPLETE   0x0020
760 #define  MII_BMSR_REMOTE_FAULT  0x0010
761 #define  MII_BMSR_AN_ABLE       0x0008
762 #define  MII_BMSR_LINK_VALID    0x0004
763 #define  MII_BMSR_JABBER        0x0002
764 #define  MII_BMSR_EXT_CAP       0x0001
765
766 int
767 calculate_if_metric(char *ifname)
768 {
769   if (check_wireless_interface(ifname)) {
770     struct ifreq ifr;
771     strscpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
772
773     /* Get bit rate */
774     if (ioctl(olsr_cnf->ioctl_s, SIOCGIWRATE, &ifr) < 0) {
775       OLSR_PRINTF(1, "Not able to find rate for WLAN interface %s\n", ifname);
776       return WEIGHT_WLAN_11MB;
777     }
778
779     OLSR_PRINTF(1, "Bitrate %d\n", ifr.ifr_ifru.ifru_ivalue);
780
781     //WEIGHT_WLAN_LOW,          /* <11Mb WLAN     */
782     //WEIGHT_WLAN_11MB,         /* 11Mb 802.11b   */
783     //WEIGHT_WLAN_54MB,         /* 54Mb 802.11g   */
784     return WEIGHT_WLAN_LOW;
785   } else {
786     /* Ethernet */
787     /* Mii wizardry */
788     struct ifreq ifr;
789     struct mii_data *mii = (struct mii_data *)&ifr.ifr_data;
790     int bmcr;
791     memset(&ifr, 0, sizeof(ifr));
792     strscpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
793
794     if (ioctl(olsr_cnf->ioctl_s, SIOCGMIIPHY, &ifr) < 0) {
795       if (errno != ENODEV)
796         OLSR_PRINTF(1, "SIOCGMIIPHY on '%s' failed: %s\n", ifr.ifr_name, strerror(errno));
797       return WEIGHT_ETHERNET_DEFAULT;
798     }
799
800     mii->reg_num = MII_BMCR;
801     if (ioctl(olsr_cnf->ioctl_s, SIOCGMIIREG, &ifr) < 0) {
802       OLSR_PRINTF(1, "SIOCGMIIREG on %s failed: %s\n", ifr.ifr_name, strerror(errno));
803       return WEIGHT_ETHERNET_DEFAULT;
804     }
805     bmcr = mii->val_out;
806
807     OLSR_PRINTF(1, "%s: ", ifr.ifr_name);
808     OLSR_PRINTF(1, "%s Mbit, %s duplex\n", (bmcr & MII_BMCR_100MBIT) ? "100" : "10", (bmcr & MII_BMCR_DUPLEX) ? "full" : "half");
809
810     is_if_link_up(ifname);
811
812     if (mii->val_out & MII_BMCR_100MBIT)
813       return WEIGHT_ETHERNET_100MB;
814     else
815       return WEIGHT_ETHERNET_10MB;
816     //WEIGHT_ETHERNET_1GB,      /* Ethernet 1Gb   */
817
818   }
819 }
820
821 bool
822 is_if_link_up(char *ifname)
823 {
824   if (check_wireless_interface(ifname)) {
825     /* No link checking on wireless devices */
826     return true;
827   } else {
828     /* Mii wizardry */
829     struct ifreq ifr;
830     struct mii_data *mii = (struct mii_data *)&ifr.ifr_data;
831     int bmsr;
832     memset(&ifr, 0, sizeof(ifr));
833     strscpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
834
835     if (ioctl(olsr_cnf->ioctl_s, SIOCGMIIPHY, &ifr) < 0) {
836       if (errno != ENODEV)
837         OLSR_PRINTF(1, "SIOCGMIIPHY on '%s' failed: %s\n", ifr.ifr_name, strerror(errno));
838       return WEIGHT_ETHERNET_DEFAULT;
839     }
840     mii->reg_num = MII_BMSR;
841     if (ioctl(olsr_cnf->ioctl_s, SIOCGMIIREG, &ifr) < 0) {
842       OLSR_PRINTF(1, "SIOCGMIIREG on %s failed: %s\n", ifr.ifr_name, strerror(errno));
843       return WEIGHT_ETHERNET_DEFAULT;
844     }
845     bmsr = mii->val_out;
846
847     OLSR_PRINTF(1, "%s: ", ifr.ifr_name);
848     OLSR_PRINTF(1, "%s\n", (bmsr & MII_BMSR_LINK_VALID) ? "link ok " : "no link ");
849
850     return (bmsr & MII_BMSR_LINK_VALID);
851
852   }
853 }
854
855 #else
856 int
857 calculate_if_metric(char *ifname)
858 {
859   return check_wireless_interface(ifname);
860 }
861 #endif
862
863 bool olsr_if_isup(const char * dev)
864 {
865   struct ifreq ifr;
866
867   memset(&ifr, 0, sizeof(ifr));
868   strscpy(ifr.ifr_name, dev, IFNAMSIZ);
869
870   if (ioctl(olsr_cnf->ioctl_s, SIOCGIFFLAGS, &ifr) < 0) {
871     OLSR_PRINTF(1, "ioctl SIOCGIFFLAGS (get flags) error on device %s: %s (%d)\n",
872         dev, strerror(errno), errno);
873     return 1;
874   }
875   return (ifr.ifr_flags & IFF_UP) != 0;
876 }
877
878 int olsr_if_set_state(const char *dev, bool up) {
879   int oldflags;
880   struct ifreq ifr;
881
882   memset(&ifr, 0, sizeof(ifr));
883   strscpy(ifr.ifr_name, dev, IFNAMSIZ);
884
885   if (ioctl(olsr_cnf->ioctl_s, SIOCGIFFLAGS, &ifr) < 0) {
886     OLSR_PRINTF(1, "ioctl SIOCGIFFLAGS (get flags) error on device %s: %s (%d)\n",
887         dev, strerror(errno), errno);
888     return 1;
889   }
890
891   oldflags = ifr.ifr_flags;
892   if (up) {
893     ifr.ifr_flags |= IFF_UP;
894   }
895   else {
896     ifr.ifr_flags &= ~IFF_UP;
897   }
898
899   if (oldflags == ifr.ifr_flags) {
900     /* interface is already up/down */
901     return 0;
902   }
903
904   if (ioctl(olsr_cnf->ioctl_s, SIOCSIFFLAGS, &ifr) < 0) {
905     OLSR_PRINTF(1, "ioctl SIOCSIFFLAGS (set flags %s) error on device %s: %s (%d)\n",
906         up ? "up" : "down", dev, strerror(errno), errno);
907     return 1;
908   }
909   return 0;
910 }
911
912 /*
913  * Local Variables:
914  * c-basic-offset: 2
915  * indent-tabs-mode: nil
916  * End:
917  */