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