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