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