Remove Olsrd host emulation code
[olsrd.git] / src / linux / net.c
1
2 /*
3  * The olsr.org Optimized Link-State Routing daemon(olsrd)
4  * Copyright (c) 2004-2009, the olsr.org team - see HISTORY file
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 /*
44  * Linux spesific code
45  */
46
47 #include "../net_os.h"
48 #include "../ipcalc.h"
49 #include "../common/string.h"
50 #include "../olsr_protocol.h"
51 #include "../misc.h"
52 #include "../olsr_logging.h"
53 #include "../olsr.h"
54
55 #include <net/if.h>
56
57 #include <sys/ioctl.h>
58
59 #include <fcntl.h>
60 #include <string.h>
61 #include <stdio.h>
62 #include <syslog.h>
63 #include <errno.h>
64 #include <unistd.h>
65 #include <assert.h>
66
67 /* Redirect proc entry */
68 #define REDIRECT_PROC "/proc/sys/net/ipv4/conf/%s/send_redirects"
69
70 /* IP spoof proc entry */
71 #define SPOOF_PROC "/proc/sys/net/ipv4/conf/%s/rp_filter"
72
73 /*
74  *Wireless definitions for ioctl calls
75  *(from linux/wireless.h)
76  */
77 #define SIOCGIWNAME     0x8B01  /* get name == wireless protocol */
78 #define SIOCGIWRATE     0x8B21  /* get default bit rate (bps) */
79
80 /* The original state of the IP forwarding proc entry */
81 static char orig_fwd_state;
82 static char orig_global_redirect_state;
83
84 /**
85  *Bind a socket to a device
86  *
87  *@param sock the socket to bind
88  *@param dev_name name of the device
89  *
90  *@return negative if error
91  */
92
93 static int
94 bind_socket_to_device(int sock, char *dev_name)
95 {
96   /*
97    *Bind to device using the SO_BINDTODEVICE flag
98    */
99   OLSR_DEBUG(LOG_NETWORKING, "Binding socket %d to device %s\n", sock, dev_name);
100   return setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, dev_name, strlen(dev_name) + 1);
101 }
102
103
104 /**
105  *Enable IP forwarding.
106  *Just writing "1" to the /proc/sys/net/ipv4/ip_forward
107  *if using IPv4 or /proc/sys/net/ipv6/conf/all/forwarding
108  *if using IPv6.
109  *Could probably drop the check for
110  *"0" here and write "1" anyways.
111  *
112  *@param version IP version.
113  *
114  *@return 1 on sucess 0 on failiure
115  */
116 int
117 enable_ip_forwarding(int version)
118 {
119   const char *const procfile = version == AF_INET ? "/proc/sys/net/ipv4/ip_forward" : "/proc/sys/net/ipv6/conf/all/forwarding";
120   FILE *proc_fwd = fopen(procfile, "r");
121
122   if (proc_fwd == NULL) {
123     OLSR_WARN(LOG_NETWORKING,
124               "WARNING! Could not open the %s file to check/enable IP forwarding!\n"
125               "Are you using the procfile filesystem?\nDoes your system support IPv%d?\n"
126               "I will continue(in 3 sec) - but you should manually ensure that IP forwarding is enabled!\n\n",
127               procfile, version == AF_INET ? 4 : 6);
128     sleep(3);
129     return 0;
130   }
131   orig_fwd_state = fgetc(proc_fwd);
132   fclose(proc_fwd);
133
134   if (orig_fwd_state == '1') {
135     OLSR_INFO(LOG_NETWORKING, "\nIP forwarding is enabled on this system\n");
136   } else {
137     proc_fwd = fopen(procfile, "w");
138     if (proc_fwd == NULL) {
139       OLSR_WARN(LOG_NETWORKING, "Could not open %s for writing!\n"
140                 "I will continue(in 3 sec) - but you should manually ensure that IP forwarding is enabeled!\n\n", procfile);
141       sleep(3);
142       return 0;
143     }
144     fputs("1", proc_fwd);
145     fclose(proc_fwd);
146   }
147   return 1;
148 }
149
150 int
151 disable_redirects_global(int version)
152 {
153   FILE *proc_redirect;
154   const char *const procfile = "/proc/sys/net/ipv4/conf/all/send_redirects";
155
156   if (version == AF_INET6) {
157     return -1;
158   }
159   proc_redirect = fopen(procfile, "r");
160   if (proc_redirect == NULL) {
161     OLSR_WARN(LOG_NETWORKING,
162               "WARNING! Could not open the %s file to check/disable ICMP redirects!\n"
163               "Are you using the procfile filesystem?\n"
164               "Does your system support IPv4?\n"
165               "I will continue(in 3 sec) - but you should manually ensure that ICMP redirects are disabled!\n\n", procfile);
166     sleep(3);
167     return -1;
168   }
169   orig_global_redirect_state = fgetc(proc_redirect);
170   fclose(proc_redirect);
171
172   if (orig_global_redirect_state == '0') {
173     return 0;
174   }
175   proc_redirect = fopen(procfile, "w");
176   if (proc_redirect == NULL) {
177     OLSR_WARN(LOG_NETWORKING, "Could not open %s for writing!\n"
178               "I will continue(in 3 sec) - but you should manually ensure that ICMP redirect is disabled!\n\n", procfile);
179     sleep(3);
180     return 0;
181   }
182   fputs("0", proc_redirect);
183   fclose(proc_redirect);
184   return 1;
185 }
186
187 /**
188  *
189  *@return 1 on sucess 0 on failiure
190  */
191 int
192 disable_redirects(const char *if_name, struct interface *iface, int version)
193 {
194   FILE *proc_redirect;
195   char procfile[FILENAME_MAX];
196
197   if (version == AF_INET6) {
198     return -1;
199   }
200
201   /* Generate the procfile name */
202   snprintf(procfile, sizeof(procfile), REDIRECT_PROC, if_name);
203
204   proc_redirect = fopen(procfile, "r");
205   if (proc_redirect == NULL) {
206     OLSR_WARN(LOG_NETWORKING,
207               "WARNING! Could not open the %s file to check/disable ICMP redirects!\n"
208               "Are you using the procfile filesystem?\n"
209               "Does your system support IPv4?\n"
210               "I will continue(in 3 sec) - but you should manually ensure that ICMP redirects are disabled!\n\n", procfile);
211     sleep(3);
212     return 0;
213   }
214   iface->nic_state.redirect = fgetc(proc_redirect);
215   fclose(proc_redirect);
216
217   proc_redirect = fopen(procfile, "w");
218   if (proc_redirect == NULL) {
219     OLSR_WARN(LOG_NETWORKING, "Could not open %s for writing!\n"
220               "I will continue(in 3 sec) - but you should manually ensure that ICMP redirect is disabled!\n\n", procfile);
221     sleep(3);
222     return 0;
223   }
224   fputs("0", proc_redirect);
225   fclose(proc_redirect);
226   return 1;
227 }
228
229 /**
230  *
231  *@return 1 on sucess 0 on failiure
232  */
233 int
234 deactivate_spoof(const char *if_name, struct interface *iface, int version)
235 {
236   FILE *proc_spoof;
237   char procfile[FILENAME_MAX];
238
239   if (version == AF_INET6) {
240     return -1;
241   }
242
243   /* Generate the procfile name */
244   sprintf(procfile, SPOOF_PROC, if_name);
245
246   proc_spoof = fopen(procfile, "r");
247   if (proc_spoof == NULL) {
248     OLSR_WARN(LOG_NETWORKING,
249               "WARNING! Could not open the %s file to check/disable the IP spoof filter!\n"
250               "Are you using the procfile filesystem?\n"
251               "Does your system support IPv4?\n"
252               "I will continue(in 3 sec) - but you should manually ensure that IP spoof filtering is disabled!\n\n", procfile);
253     sleep(3);
254     return 0;
255   }
256   iface->nic_state.spoof = fgetc(proc_spoof);
257   fclose(proc_spoof);
258
259   proc_spoof = fopen(procfile, "w");
260   if (proc_spoof == NULL) {
261     OLSR_WARN(LOG_NETWORKING, "Could not open %s for writing!\n"
262               "I will continue(in 3 sec) - but you should manually ensure that IP spoof filtering is disabled!\n\n", procfile);
263     sleep(3);
264     return 0;
265   }
266   fputs("0", proc_spoof);
267   fclose(proc_spoof);
268   return 1;
269 }
270
271 /**
272  *Resets the spoof filter and ICMP redirect settings
273  */
274 int
275 restore_settings(int version)
276 {
277   struct interface *ifs;
278
279   OLSR_INFO(LOG_NETWORKING, "Restoring network state\n");
280
281   /* Restore IP forwarding to "off" */
282   if (orig_fwd_state == '0') {
283     const char *const procfile = version == AF_INET ? "/proc/sys/net/ipv4/ip_forward" : "/proc/sys/net/ipv6/conf/all/forwarding";
284     FILE *proc_fd = fopen(procfile, "w");
285
286     if (proc_fd == NULL) {
287       OLSR_WARN(LOG_NETWORKING, "Could not open %s for writing!\nSettings not restored!\n", procfile);
288     } else {
289       fputc(orig_fwd_state, proc_fd);
290       fclose(proc_fd);
291     }
292   }
293
294   /* Restore global ICMP redirect setting */
295   if (orig_global_redirect_state != '0') {
296     if (version == AF_INET) {
297       const char *const procfile = "/proc/sys/net/ipv4/conf/all/send_redirects";
298       FILE *proc_fd = fopen(procfile, "w");
299
300       if (proc_fd == NULL) {
301         OLSR_WARN(LOG_NETWORKING, "Could not open %s for writing!\nSettings not restored!\n", procfile);
302       } else {
303         fputc(orig_global_redirect_state, proc_fd);
304         fclose(proc_fd);
305       }
306     }
307   }
308
309   if (version == AF_INET6) {
310     return 0;
311   }
312
313   OLSR_FOR_ALL_INTERFACES(ifs) {
314     char procfile[FILENAME_MAX];
315     FILE *proc_fd;
316     /* ICMP redirects */
317
318     /* Generate the procfile name */
319     snprintf(procfile, sizeof(procfile), REDIRECT_PROC, ifs->int_name);
320     proc_fd = fopen(procfile, "w");
321     if (proc_fd == NULL) {
322       OLSR_WARN(LOG_NETWORKING, "Could not open %s for writing!\nSettings not restored!\n", procfile);
323     } else {
324       fputc(ifs->nic_state.redirect, proc_fd);
325       fclose(proc_fd);
326     }
327
328     /* Spoof filter */
329
330     /* Generate the procfile name */
331     sprintf(procfile, SPOOF_PROC, ifs->int_name);
332     proc_fd = fopen(procfile, "w");
333     if (proc_fd == NULL) {
334       OLSR_WARN(LOG_NETWORKING, "Could not open %s for writing!\nSettings not restored!\n", procfile);
335     } else {
336       fputc(ifs->nic_state.spoof, proc_fd);
337       fclose(proc_fd);
338     }
339   }
340   OLSR_FOR_ALL_INTERFACES_END(ifs);
341
342   return 1;
343 }
344
345 /**
346  *Creates a nonblocking broadcast socket.
347  *@param sa sockaddr struct. Used for bind(2).
348  *@return the FD of the socket or -1 on error.
349  */
350 int
351 getsocket(int bufspace, char *int_name)
352 {
353   struct sockaddr_in sin4;
354   int on;
355   int sock = socket(AF_INET, SOCK_DGRAM, 0);
356   if (sock < 0) {
357     OLSR_ERROR(LOG_NETWORKING, "Cannot open socket for OLSR PDUs (%s)\n", strerror(errno));
358     olsr_exit(EXIT_FAILURE);
359   }
360
361   on = 1;
362 #ifdef SO_BROADCAST
363   if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)) < 0) {
364     OLSR_ERROR(LOG_NETWORKING, "Cannot set socket for OLSR PDUs to broadcast mode (%s)\n", strerror(errno));
365     close(sock);
366     olsr_exit(EXIT_FAILURE);
367   }
368 #endif
369
370   if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) {
371     OLSR_ERROR(LOG_NETWORKING, "Cannot reuse address for OLSR PDUs (%s)\n", strerror(errno));
372     close(sock);
373     olsr_exit(EXIT_FAILURE);
374   }
375 #ifdef SO_RCVBUF
376   for (on = bufspace;; on -= 1024) {
377     if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &on, sizeof(on)) == 0) {
378       OLSR_DEBUG(LOG_NETWORKING, "Set socket buffer space to %d\n", on);
379       break;
380     }
381     if (on <= 8 * 1024) {
382       OLSR_WARN(LOG_NETWORKING, "Could not set a socket buffer space for OLSR PDUs (%s)\n", strerror(errno));
383       break;
384     }
385   }
386 #endif
387
388   /*
389    * WHEN USING KERNEL 2.6 THIS MUST HAPPEN PRIOR TO THE PORT BINDING!!!!
390    */
391
392   /* Bind to device */
393   if (bind_socket_to_device(sock, int_name) < 0) {
394     OLSR_ERROR(LOG_NETWORKING, "Could not bind socket for OLSR PDUs to device (%s)\n", strerror(errno));
395     close(sock);
396     olsr_exit(EXIT_FAILURE);
397   }
398
399   memset(&sin4, 0, sizeof(sin4));
400   sin4.sin_family = AF_INET;
401   sin4.sin_port = htons(olsr_cnf->olsr_port);
402   assert(sin4.sin_addr.s_addr == INADDR_ANY);
403   if (bind(sock, (struct sockaddr *)&sin4, sizeof(sin4)) < 0) {
404     OLSR_ERROR(LOG_NETWORKING, "Coult not bind socket for OLSR PDUs to port (%s)\n", strerror(errno));
405     close(sock);
406     olsr_exit(EXIT_FAILURE);
407   }
408
409   set_nonblocking(sock);
410   return sock;
411 }
412
413
414 /**
415  *Creates a nonblocking IPv6 socket
416  *@param sin sockaddr_in6 struct. Used for bind(2).
417  *@return the FD of the socket or -1 on error.
418  */
419 int
420 getsocket6(int bufspace, char *int_name)
421 {
422   struct sockaddr_in6 sin6;
423   int on;
424   int sock = socket(AF_INET6, SOCK_DGRAM, 0);
425   if (sock < 0) {
426     OLSR_ERROR(LOG_NETWORKING, "Cannot open socket for OLSR PDUs (%s)\n", strerror(errno));
427     olsr_exit(EXIT_FAILURE);
428   }
429 #ifdef IPV6_V6ONLY
430   on = 1;
431   if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0) {
432     OLSR_WARN(LOG_NETWORKING, "Cannot set socket for OLSR PDUs to ipv6 only (%s)\n", strerror(errno));
433   }
434 #endif
435
436
437   //#ifdef SO_BROADCAST
438   /*
439      if (setsockopt(sock, SOL_SOCKET, SO_MULTICAST, &on, sizeof(on)) < 0)
440      {
441      perror("setsockopt");
442      syslog(LOG_ERR, "setsockopt SO_BROADCAST: %m");
443      close(sock);
444      return (-1);
445      }
446    */
447   //#endif
448
449 #ifdef SO_RCVBUF
450   for (on = bufspace;; on -= 1024) {
451     if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &on, sizeof(on)) == 0) {
452       OLSR_DEBUG(LOG_NETWORKING, "Set socket buffer space to %d\n", on);
453       break;
454     }
455     if (on <= 8 * 1024) {
456       OLSR_WARN(LOG_NETWORKING, "Could not set a socket buffer space for OLSR PDUs (%s)\n", strerror(errno));
457       break;
458     }
459   }
460 #endif
461
462   on = 1;
463   if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) {
464     OLSR_ERROR(LOG_NETWORKING, "Cannot reuse address for socket for OLSR PDUs (%s)\n", strerror(errno));
465     close(sock);
466     olsr_exit(EXIT_FAILURE);
467   }
468
469   /*
470    * we are abusing "on" here. The value is 1 which is our intended
471    * hop limit value.
472    */
473   if (setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &on, sizeof(on)) < 0) {
474     OLSR_ERROR(LOG_NETWORKING, "Cannot set multicast hops to 1 for socket for OLSR PDUs (%s)\n", strerror(errno));
475     close(sock);
476     olsr_exit(EXIT_FAILURE);
477   }
478
479
480   /*
481    * WHEN USING KERNEL 2.6 THIS MUST HAPPEN PRIOR TO THE PORT BINDING!!!!
482    */
483
484   /* Bind to device */
485   if (bind_socket_to_device(sock, int_name) < 0) {
486     OLSR_ERROR(LOG_NETWORKING, "Cannot bind socket for OLSR PDUs to interface %s (%s)\n", int_name, strerror(errno));
487     close(sock);
488     olsr_exit(EXIT_FAILURE);
489   }
490
491   memset(&sin6, 0, sizeof(sin6));
492   sin6.sin6_family = AF_INET6;
493   sin6.sin6_port = htons(olsr_cnf->olsr_port);
494   assert(0 == memcmp(&sin6.sin6_addr, &in6addr_any, sizeof(sin6.sin6_addr)));   /* == IN6ADDR_ANY_INIT */
495   if (bind(sock, (struct sockaddr *)&sin6, sizeof(sin6)) < 0) {
496     OLSR_ERROR(LOG_NETWORKING, "Cannot bind socket for OLSR PDUs (%s)\n", strerror(errno));
497     close(sock);
498     olsr_exit(EXIT_FAILURE);
499   }
500
501   set_nonblocking(sock);
502   return sock;
503 }
504
505 int
506 join_mcast(struct interface *ifs, int sock)
507 {
508   /* See linux/in6.h */
509 #if !defined REMOVE_LOG_INFO
510   struct ipaddr_str buf;
511 #endif
512   struct ipv6_mreq mcastreq;
513
514   mcastreq.ipv6mr_multiaddr = ifs->int6_multaddr.sin6_addr;
515   mcastreq.ipv6mr_interface = ifs->if_index;
516
517   OLSR_INFO(LOG_NETWORKING, "Interface %s joining multicast %s\n", ifs->int_name,
518             ip6_to_string(&buf, &ifs->int6_multaddr.sin6_addr));
519   /* Send multicast */
520   if (setsockopt(sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, (char *)&mcastreq, sizeof(struct ipv6_mreq))
521       < 0) {
522     OLSR_WARN(LOG_NETWORKING, "Cannot join multicast group (%s)\n", strerror(errno));
523     return -1;
524   }
525 #if 0
526   /* Old libc fix */
527 #ifdef IPV6_JOIN_GROUP
528   /* Join reciever group */
529   if (setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, (char *)&mcastreq, sizeof(struct ipv6_mreq))
530       < 0)
531 #else
532   /* Join reciever group */
533   if (setsockopt(sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, (char *)&mcastreq, sizeof(struct ipv6_mreq))
534       < 0)
535 #endif
536   {
537     perror("Join multicast send");
538     return -1;
539   }
540 #endif
541   if (setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_IF, (char *)&mcastreq.ipv6mr_interface, sizeof(mcastreq.ipv6mr_interface))
542       < 0) {
543     OLSR_WARN(LOG_NETWORKING, "Cannot set multicast interface (%s)\n", strerror(errno));
544     return -1;
545   }
546
547   return 0;
548 }
549
550 /*
551  *From net-tools lib/interface.c
552  *
553  */
554 int
555 get_ipv6_address(char *ifname, struct sockaddr_in6 *saddr6, int addrtype6)
556 {
557   int rv = 0;
558   FILE *f = fopen(_PATH_PROCNET_IFINET6, "r");
559   if (f != NULL) {
560     char devname[IFNAMSIZ];
561     char addr6p[8][5];
562     int plen, scope, dad_status, if_idx;
563     bool found = false;
564     while (fscanf(f, "%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %20s\n",
565                   addr6p[0], addr6p[1], addr6p[2], addr6p[3],
566                   addr6p[4], addr6p[5], addr6p[6], addr6p[7], &if_idx, &plen, &scope, &dad_status, devname) != EOF) {
567       if (strcmp(devname, ifname) == 0) {
568         char addr6[40];
569         sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s",
570                 addr6p[0], addr6p[1], addr6p[2], addr6p[3], addr6p[4], addr6p[5], addr6p[6], addr6p[7]);
571
572         if (addrtype6 == OLSR_IP6T_SITELOCAL && scope == IPV6_ADDR_SITELOCAL)
573           found = true;
574         else if (addrtype6 == OLSR_IP6T_UNIQUELOCAL && scope == IPV6_ADDR_GLOBAL)
575           found = true;
576         else if (addrtype6 == OLSR_IP6T_GLOBAL && scope == IPV6_ADDR_GLOBAL)
577           found = true;
578
579         if (found) {
580           found = false;
581           if (addr6p[0][0] == 'F' || addr6p[0][0] == 'f') {
582             if (addr6p[0][1] == 'C' || addr6p[0][1] == 'c' || addr6p[0][1] == 'D' || addr6p[0][1] == 'd')
583               found = true;
584           }
585           if (addrtype6 == OLSR_IP6T_SITELOCAL)
586             found = true;
587           else if (addrtype6 == OLSR_IP6T_UNIQUELOCAL && found)
588             found = true;
589           else if (addrtype6 == OLSR_IP6T_GLOBAL && !found)
590             found = true;
591           else
592             found = false;
593         }
594
595         if (found) {
596           inet_pton(AF_INET6, addr6, &saddr6->sin6_addr);
597           rv = 1;
598           break;
599         }
600       }
601     }
602     fclose(f);
603   }
604   return rv;
605 }
606
607
608 /**
609  * Wrapper for sendto(2)
610  */
611 ssize_t
612 olsr_sendto(int s, const void *buf, size_t len, int flags, const struct sockaddr * to, socklen_t tolen)
613 {
614   return sendto(s, buf, len, flags, to, tolen);
615 }
616
617 /**
618  * Wrapper for recvfrom(2)
619  */
620
621 ssize_t
622 olsr_recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr * from, socklen_t * fromlen)
623 {
624   return recvfrom(s, buf, len, flags, from, fromlen);
625 }
626
627 /**
628  * Wrapper for select(2)
629  */
630
631 int
632 olsr_select(int nfds, fd_set * readfds, fd_set * writefds, fd_set * exceptfds, struct timeval *timeout)
633 {
634   return select(nfds, readfds, writefds, exceptfds, timeout);
635 }
636
637 int
638 check_wireless_interface(char *ifname)
639 {
640   struct ifreq ifr;
641
642   memset(&ifr, 0, sizeof(ifr));
643   strscpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
644
645   return (ioctl(olsr_cnf->ioctl_s, SIOCGIWNAME, &ifr) >= 0) ? 1 : 0;
646 }
647
648 #if 0
649
650 #include <linux/sockios.h>
651 #include <linux/types.h>
652
653 /* This data structure is used for all the MII ioctl's */
654 struct mii_data {
655   __u16 phy_id;
656   __u16 reg_num;
657   __u16 val_in;
658   __u16 val_out;
659 };
660
661
662 /* Basic Mode Control Register */
663 #define MII_BMCR                0x00
664 #define  MII_BMCR_RESET         0x8000
665 #define  MII_BMCR_LOOPBACK      0x4000
666 #define  MII_BMCR_100MBIT       0x2000
667 #define  MII_BMCR_AN_ENA        0x1000
668 #define  MII_BMCR_ISOLATE       0x0400
669 #define  MII_BMCR_RESTART       0x0200
670 #define  MII_BMCR_DUPLEX        0x0100
671 #define  MII_BMCR_COLTEST       0x0080
672
673 /* Basic Mode Status Register */
674 #define MII_BMSR                0x01
675 #define  MII_BMSR_CAP_MASK      0xf800
676 #define  MII_BMSR_100BASET4     0x8000
677 #define  MII_BMSR_100BASETX_FD  0x4000
678 #define  MII_BMSR_100BASETX_HD  0x2000
679 #define  MII_BMSR_10BASET_FD    0x1000
680 #define  MII_BMSR_10BASET_HD    0x0800
681 #define  MII_BMSR_NO_PREAMBLE   0x0040
682 #define  MII_BMSR_AN_COMPLETE   0x0020
683 #define  MII_BMSR_REMOTE_FAULT  0x0010
684 #define  MII_BMSR_AN_ABLE       0x0008
685 #define  MII_BMSR_LINK_VALID    0x0004
686 #define  MII_BMSR_JABBER        0x0002
687 #define  MII_BMSR_EXT_CAP       0x0001
688
689 int
690 calculate_if_metric(char *ifname)
691 {
692   if (check_wireless_interface(ifname)) {
693     struct ifreq ifr;
694     strscpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
695
696     /* Get bit rate */
697     if (ioctl(olsr_cnf->ioctl_s, SIOCGIWRATE, &ifr) < 0) {
698       OLSR_PRINTF(1, "Not able to find rate for WLAN interface %s\n", ifname);
699       return WEIGHT_WLAN_11MB;
700     }
701
702     OLSR_PRINTF(1, "Bitrate %d\n", ifr.ifr_ifru.ifru_ivalue);
703
704     //WEIGHT_WLAN_LOW,          /* <11Mb WLAN     */
705     //WEIGHT_WLAN_11MB,         /* 11Mb 802.11b   */
706     //WEIGHT_WLAN_54MB,         /* 54Mb 802.11g   */
707     return WEIGHT_WLAN_LOW;
708   } else {
709     /* Ethernet */
710     /* Mii wizardry */
711     struct ifreq ifr;
712     struct mii_data *mii = (struct mii_data *)&ifr.ifr_data;
713     int bmcr;
714     memset(&ifr, 0, sizeof(ifr));
715     strscpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
716
717     if (ioctl(olsr_cnf->ioctl_s, SIOCGMIIPHY, &ifr) < 0) {
718       if (errno != ENODEV)
719         OLSR_PRINTF(1, "SIOCGMIIPHY on '%s' failed: %s\n", ifr.ifr_name, strerror(errno));
720       return WEIGHT_ETHERNET_DEFAULT;
721     }
722
723     mii->reg_num = MII_BMCR;
724     if (ioctl(olsr_cnf->ioctl_s, SIOCGMIIREG, &ifr) < 0) {
725       OLSR_PRINTF(1, "SIOCGMIIREG on %s failed: %s\n", ifr.ifr_name, strerror(errno));
726       return WEIGHT_ETHERNET_DEFAULT;
727     }
728     bmcr = mii->val_out;
729
730
731     OLSR_PRINTF(1, "%s: ", ifr.ifr_name);
732     OLSR_PRINTF(1, "%s Mbit, %s duplex\n", (bmcr & MII_BMCR_100MBIT) ? "100" : "10", (bmcr & MII_BMCR_DUPLEX) ? "full" : "half");
733
734     is_if_link_up(ifname);
735
736     if (mii->val_out & MII_BMCR_100MBIT)
737       return WEIGHT_ETHERNET_100MB;
738     else
739       return WEIGHT_ETHERNET_10MB;
740     //WEIGHT_ETHERNET_1GB,      /* Ethernet 1Gb   */
741
742   }
743 }
744
745
746 bool
747 is_if_link_up(char *ifname)
748 {
749   if (check_wireless_interface(ifname)) {
750     /* No link checking on wireless devices */
751     return true;
752   } else {
753     /* Mii wizardry */
754     struct ifreq ifr;
755     struct mii_data *mii = (struct mii_data *)&ifr.ifr_data;
756     int bmsr;
757     memset(&ifr, 0, sizeof(ifr));
758     strscpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
759
760     if (ioctl(olsr_cnf->ioctl_s, SIOCGMIIPHY, &ifr) < 0) {
761       if (errno != ENODEV)
762         OLSR_PRINTF(1, "SIOCGMIIPHY on '%s' failed: %s\n", ifr.ifr_name, strerror(errno));
763       return WEIGHT_ETHERNET_DEFAULT;
764     }
765     mii->reg_num = MII_BMSR;
766     if (ioctl(olsr_cnf->ioctl_s, SIOCGMIIREG, &ifr) < 0) {
767       OLSR_PRINTF(1, "SIOCGMIIREG on %s failed: %s\n", ifr.ifr_name, strerror(errno));
768       return WEIGHT_ETHERNET_DEFAULT;
769     }
770     bmsr = mii->val_out;
771
772     OLSR_PRINTF(1, "%s: ", ifr.ifr_name);
773     OLSR_PRINTF(1, "%s\n", (bmsr & MII_BMSR_LINK_VALID) ? "link ok " : "no link ");
774
775     return (bmsr & MII_BMSR_LINK_VALID);
776
777   }
778 }
779
780 #else
781 int
782 calculate_if_metric(char *ifname)
783 {
784   return check_wireless_interface(ifname);
785 }
786 #endif
787
788 /*
789  * Local Variables:
790  * c-basic-offset: 2
791  * indent-tabs-mode: nil
792  * End:
793  */