dbe73290d29376f3e289843e0c9c45a86c8ca1f2
[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
49 #include <net/if.h>
50
51 #include <sys/ioctl.h>
52
53 #include <fcntl.h>
54 #include <string.h>
55 #include <stdio.h>
56 #include <syslog.h>
57 #include <unistd.h>
58
59 /* Redirect proc entry */
60 #define REDIRECT_PROC "/proc/sys/net/ipv4/conf/%s/send_redirects"
61
62 /* IP spoof proc entry */
63 #define SPOOF_PROC "/proc/sys/net/ipv4/conf/%s/rp_filter"
64
65 /*
66  *Wireless definitions for ioctl calls
67  *(from linux/wireless.h)
68  */
69 #define SIOCGIWNAME     0x8B01  /* get name == wireless protocol */
70 #define SIOCGIWRATE     0x8B21  /* get default bit rate (bps) */
71
72 /* The original state of the IP forwarding proc entry */
73 static char orig_fwd_state;
74 static char orig_global_redirect_state;
75
76 /**
77  *Bind a socket to a device
78  *
79  *@param sock the socket to bind
80  *@param dev_name name of the device
81  *
82  *@return negative if error
83  */
84
85 int
86 bind_socket_to_device(int sock, char *dev_name)
87 {
88   /*
89    *Bind to device using the SO_BINDTODEVICE flag
90    */
91   OLSR_PRINTF(3, "Binding socket %d to device %s\n", sock, dev_name);
92   return setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, dev_name, strlen(dev_name) + 1);
93 }
94
95 /**
96  *Enable IP forwarding.
97  *Just writing "1" to the /proc/sys/net/ipv4/ip_forward
98  *if using IPv4 or /proc/sys/net/ipv6/conf/all/forwarding
99  *if using IPv6.
100  *Could probably drop the check for
101  *"0" here and write "1" anyways.
102  *
103  *@param version IP version.
104  *
105  *@return 1 on sucess 0 on failiure
106  */
107 int
108 enable_ip_forwarding(int version)
109 {
110   FILE *proc_fwd;
111   const char *const procfile = version == AF_INET ? "/proc/sys/net/ipv4/ip_forward" : "/proc/sys/net/ipv6/conf/all/forwarding";
112
113   if ((proc_fwd = fopen(procfile, "r")) == NULL) {
114     /* IPv4 */
115     if (version == AF_INET)
116       fprintf(stderr,
117               "WARNING! Could not open the %s file to check/enable IP forwarding!\nAre you using the procfile filesystem?\nDoes your system support IPv4?\nI will continue(in 3 sec) - but you should mannually ensure that IP forwarding is enabeled!\n\n",
118               procfile);
119     /* IPv6 */
120     else
121       fprintf(stderr,
122               "WARNING! Could not open the %s file to check/enable IP forwarding!\nAre you using the procfile filesystem?\nDoes your system support IPv6?\nI will continue(in 3 sec) - but you should mannually ensure that IP forwarding is enabeled!\n\n",
123               procfile);
124
125     sleep(3);
126     return 0;
127   }
128
129   orig_fwd_state = fgetc(proc_fwd);
130   fclose(proc_fwd);
131   if (orig_fwd_state == '1') {
132     OLSR_PRINTF(3, "\nIP forwarding is enabled on this system\n");
133   } else {
134     if ((proc_fwd = fopen(procfile, "w")) == NULL) {
135       fprintf(stderr, "Could not open %s for writing!\n", procfile);
136       fprintf(stderr, "I will continue(in 3 sec) - but you should mannually ensure that IP forwarding is enabeled!\n\n");
137       sleep(3);
138       return 0;
139     } else {
140       syslog(LOG_INFO, "Writing \"1\" to %s\n", procfile);
141       fputs("1", proc_fwd);
142     }
143     fclose(proc_fwd);
144   }
145   return 1;
146 }
147
148 int
149 disable_redirects_global(int version)
150 {
151   FILE *proc_redirect;
152   const char *const procfile = "/proc/sys/net/ipv4/conf/all/send_redirects";
153
154   if (version == AF_INET6)
155     return -1;
156
157   if ((proc_redirect = fopen(procfile, "r")) == NULL) {
158     fprintf(stderr,
159             "WARNING! Could not open the %s file to check/disable ICMP redirects!\nAre you using the procfile filesystem?\nDoes your system support IPv4?\nI will continue(in 3 sec) - but you should mannually ensure that ICMP redirects are disabled!\n\n",
160             procfile);
161
162     sleep(3);
163     return -1;
164   }
165   orig_global_redirect_state = fgetc(proc_redirect);
166   fclose(proc_redirect);
167
168   if (orig_global_redirect_state == '0')
169     return 0;
170
171   if ((proc_redirect = fopen(procfile, "w")) == NULL) {
172     fprintf(stderr, "Could not open %s for writing!\n", procfile);
173     fprintf(stderr, "I will continue(in 3 sec) - but you should mannually ensure that ICMP redirect is disabeled!\n\n");
174     sleep(3);
175     return 0;
176   }
177   syslog(LOG_INFO, "Writing \"0\" to %s", procfile);
178   fputs("0", proc_redirect);
179   fclose(proc_redirect);
180   return 1;
181 }
182
183 /**
184  *
185  *@return 1 on sucess 0 on failiure
186  */
187 int
188 disable_redirects(const char *if_name, struct interface *iface, int version)
189 {
190   FILE *proc_redirect;
191   char procfile[FILENAME_MAX];
192
193   if (version == AF_INET6)
194     return -1;
195
196   /* Generate the procfile name */
197   snprintf(procfile, sizeof(procfile), REDIRECT_PROC, if_name);
198
199   if ((proc_redirect = fopen(procfile, "r")) == NULL) {
200     fprintf(stderr,
201             "WARNING! Could not open the %s file to check/disable ICMP redirects!\nAre you using the procfile filesystem?\nDoes your system support IPv4?\nI will continue(in 3 sec) - but you should mannually ensure that ICMP redirects are disabled!\n\n",
202             procfile);
203     sleep(3);
204     return 0;
205   }
206   iface->nic_state.redirect = fgetc(proc_redirect);
207   fclose(proc_redirect);
208
209   if ((proc_redirect = fopen(procfile, "w")) == NULL) {
210     fprintf(stderr, "Could not open %s for writing!\n", procfile);
211     fprintf(stderr, "I will continue(in 3 sec) - but you should mannually ensure that ICMP redirect is disabeled!\n\n");
212     sleep(3);
213     return 0;
214   }
215   syslog(LOG_INFO, "Writing \"0\" to %s", procfile);
216   fputs("0", proc_redirect);
217   fclose(proc_redirect);
218   return 1;
219 }
220
221 /**
222  *
223  *@return 1 on sucess 0 on failiure
224  */
225 int
226 deactivate_spoof(const char *if_name, struct interface *iface, int version)
227 {
228   FILE *proc_spoof;
229   char procfile[FILENAME_MAX];
230
231   if (version == AF_INET6)
232     return -1;
233
234   /* Generate the procfile name */
235   sprintf(procfile, SPOOF_PROC, if_name);
236
237   if ((proc_spoof = fopen(procfile, "r")) == NULL) {
238     fprintf(stderr,
239             "WARNING! Could not open the %s file to check/disable the IP spoof filter!\nAre you using the procfile filesystem?\nDoes your system support IPv4?\nI will continue(in 3 sec) - but you should mannually ensure that IP spoof filtering is disabled!\n\n",
240             procfile);
241
242     sleep(3);
243     return 0;
244   }
245   iface->nic_state.spoof = fgetc(proc_spoof);
246   fclose(proc_spoof);
247
248   if ((proc_spoof = fopen(procfile, "w")) == NULL) {
249     fprintf(stderr, "Could not open %s for writing!\n", procfile);
250     fprintf(stderr, "I will continue(in 3 sec) - but you should mannually ensure that IP spoof filtering is disabeled!\n\n");
251     sleep(3);
252     return 0;
253   }
254   syslog(LOG_INFO, "Writing \"0\" to %s", procfile);
255   fputs("0", proc_spoof);
256   fclose(proc_spoof);
257   return 1;
258 }
259
260 /**
261  *Resets the spoof filter and ICMP redirect settings
262  */
263 int
264 restore_settings(int version)
265 {
266   struct interface *ifs;
267
268   OLSR_PRINTF(1, "Restoring network state\n");
269
270   /* Restore IP forwarding to "off" */
271   if (orig_fwd_state == '0') {
272     const char *const procfile = version == AF_INET ? "/proc/sys/net/ipv4/ip_forward" : "/proc/sys/net/ipv6/conf/all/forwarding";
273     FILE *proc_fd;
274
275     if ((proc_fd = fopen(procfile, "w")) == NULL) {
276       fprintf(stderr, "Could not open %s for writing!\nSettings not restored!\n", procfile);
277     } else {
278       syslog(LOG_INFO, "Resetting %s to %c\n", procfile, orig_fwd_state);
279       fputc(orig_fwd_state, proc_fd);
280       fclose(proc_fd);
281     }
282   }
283
284   /* Restore global ICMP redirect setting */
285   if (orig_global_redirect_state != '0') {
286     if (version == AF_INET) {
287       const char *const procfile = "/proc/sys/net/ipv4/conf/all/send_redirects";
288       FILE *proc_fd;
289
290       if ((proc_fd = fopen(procfile, "w")) == NULL) {
291         fprintf(stderr, "Could not open %s for writing!\nSettings not restored!\n", procfile);
292       } else {
293         syslog(LOG_INFO, "Resetting %s to %c\n", procfile, orig_global_redirect_state);
294         fputc(orig_global_redirect_state, proc_fd);
295         fclose(proc_fd);
296       }
297     }
298   }
299
300   if (version == AF_INET6)
301     return 0;
302
303   for (ifs = ifnet; ifs != NULL; ifs = ifs->int_next) {
304     char procfile[FILENAME_MAX];
305     FILE *proc_fd;
306     /* Discard host-emulation interfaces */
307     if (ifs->is_hcif)
308       continue;
309     /* ICMP redirects */
310
311     /* Generate the procfile name */
312     snprintf(procfile, sizeof(procfile), REDIRECT_PROC, ifs->int_name);
313
314     if ((proc_fd = fopen(procfile, "w")) == NULL)
315       fprintf(stderr, "Could not open %s for writing!\nSettings not restored!\n", procfile);
316     else {
317       syslog(LOG_INFO, "Resetting %s to %c\n", procfile, ifs->nic_state.redirect);
318
319       fputc(ifs->nic_state.redirect, proc_fd);
320       fclose(proc_fd);
321     }
322
323     /* Spoof filter */
324
325     /* Generate the procfile name */
326     sprintf(procfile, SPOOF_PROC, ifs->int_name);
327     if ((proc_fd = fopen(procfile, "w")) == NULL)
328       fprintf(stderr, "Could not open %s for writing!\nSettings not restored!\n", procfile);
329     else {
330       syslog(LOG_INFO, "Resetting %s to %c\n", procfile, ifs->nic_state.spoof);
331
332       fputc(ifs->nic_state.spoof, proc_fd);
333       fclose(proc_fd);
334     }
335   }
336   return 1;
337 }
338
339 /**
340  *Creates a blocking tcp socket for communication with switch daemon.
341  *@param sa sockaddr struct. Used for bind(2).
342  *@return the FD of the socket or -1 on error.
343  */
344 int
345 gethemusocket(struct sockaddr_in *pin)
346 {
347   int sock, on = 1;
348
349   OLSR_PRINTF(1, "       Connecting to switch daemon port 10150...");
350   if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
351     perror("hcsocket");
352     syslog(LOG_ERR, "hcsocket: %m");
353     return -1;
354   }
355
356   if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) {
357     perror("SO_REUSEADDR failed");
358     close(sock);
359     return -1;
360   }
361   /* connect to PORT on HOST */
362   if (connect(sock, (struct sockaddr *)pin, sizeof(*pin)) < 0) {
363     printf("FAILED\n");
364     fprintf(stderr, "Error connecting %d - %s\n", errno, strerror(errno));
365     printf("connection refused\n");
366     close(sock);
367     return -1;
368   }
369
370   printf("OK\n");
371
372   /* Keep TCP socket blocking */
373   return sock;
374 }
375
376 /**
377  *Creates a nonblocking broadcast socket.
378  *@param sa sockaddr struct. Used for bind(2).
379  *@return the FD of the socket or -1 on error.
380  */
381 int
382 getsocket(int bufspace, char *int_name)
383 {
384   struct sockaddr_in sin;
385   int on;
386   int sock = socket(AF_INET, SOCK_DGRAM, 0);
387   if (sock < 0) {
388     perror("socket");
389     syslog(LOG_ERR, "socket: %m");
390     return -1;
391   }
392
393   on = 1;
394 #ifdef SO_BROADCAST
395   if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)) < 0) {
396     perror("setsockopt");
397     syslog(LOG_ERR, "setsockopt SO_BROADCAST: %m");
398     close(sock);
399     return -1;
400   }
401 #endif
402
403   if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) {
404     perror("SO_REUSEADDR failed");
405     close(sock);
406     return -1;
407   }
408 #ifdef SO_RCVBUF
409   for (on = bufspace;; on -= 1024) {
410     if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &on, sizeof(on)) == 0)
411       break;
412     if (on <= 8 * 1024) {
413       perror("setsockopt");
414       syslog(LOG_ERR, "setsockopt SO_RCVBUF: %m");
415       break;
416     }
417   }
418 #endif
419
420   /*
421    * WHEN USING KERNEL 2.6 THIS MUST HAPPEN PRIOR TO THE PORT BINDING!!!!
422    */
423
424   /* Bind to device */
425   if (bind_socket_to_device(sock, int_name) < 0) {
426     fprintf(stderr, "Could not bind socket to device... exiting!\n\n");
427     syslog(LOG_ERR, "Could not bind socket to device... exiting!\n\n");
428     close(sock);
429     return -1;
430   }
431
432   memset(&sin, 0, sizeof(sin));
433   sin.sin_family = AF_INET;
434   sin.sin_port = htons(olsr_cnf->olsrport);
435   sin.sin_addr.s_addr = INADDR_ANY;
436   if (bind(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
437     perror("bind");
438     syslog(LOG_ERR, "bind: %m");
439     close(sock);
440     return -1;
441   }
442
443   on = fcntl(sock, F_GETFL);
444   if (on == -1) {
445     syslog(LOG_ERR, "fcntl (F_GETFL): %m\n");
446   } else {
447     if (fcntl(sock, F_SETFL, on | O_NONBLOCK) == -1) {
448       syslog(LOG_ERR, "fcntl O_NONBLOCK: %m\n");
449     }
450   }
451   return sock;
452 }
453
454 /**
455  *Creates a nonblocking IPv6 socket
456  *@param sin sockaddr_in6 struct. Used for bind(2).
457  *@return the FD of the socket or -1 on error.
458  */
459 int
460 getsocket6(int bufspace, char *int_name)
461 {
462   struct sockaddr_in6 sin;
463   int on;
464   int sock = socket(AF_INET6, SOCK_DGRAM, 0);
465   if (sock < 0) {
466     perror("socket");
467     syslog(LOG_ERR, "socket: %m");
468     return (-1);
469   }
470 #ifdef IPV6_V6ONLY
471   on = 1;
472   if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0) {
473     perror("setsockopt(IPV6_V6ONLY)");
474     syslog(LOG_ERR, "setsockopt(IPV6_V6ONLY): %m");
475   }
476 #endif
477
478   //#ifdef SO_BROADCAST
479   /*
480      if (setsockopt(sock, SOL_SOCKET, SO_MULTICAST, &on, sizeof (on)) < 0)
481      {
482      perror("setsockopt");
483      syslog(LOG_ERR, "setsockopt SO_BROADCAST: %m");
484      close(sock);
485      return (-1);
486      }
487    */
488   //#endif
489
490 #ifdef SO_RCVBUF
491   for (on = bufspace;; on -= 1024) {
492     if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &on, sizeof(on)) == 0)
493       break;
494     if (on <= 8 * 1024) {
495       perror("setsockopt");
496       syslog(LOG_ERR, "setsockopt SO_RCVBUF: %m");
497       break;
498     }
499   }
500 #endif
501
502   if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) {
503     perror("SO_REUSEADDR failed");
504     close(sock);
505     return (-1);
506   }
507
508   /*
509    * WHEN USING KERNEL 2.6 THIS MUST HAPPEN PRIOR TO THE PORT BINDING!!!!
510    */
511
512   /* Bind to device */
513   if (bind_socket_to_device(sock, int_name) < 0) {
514     fprintf(stderr, "Could not bind socket to device... exiting!\n\n");
515     syslog(LOG_ERR, "Could not bind socket to device... exiting!\n\n");
516     close(sock);
517     return -1;
518   }
519
520   memset(&sin, 0, sizeof(sin));
521   sin.sin6_family = AF_INET6;
522   sin.sin6_port = htons(olsr_cnf->olsrport);
523   //(addrsock6.sin6_addr).s_addr = IN6ADDR_ANY_INIT;
524   if (bind(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
525     perror("bind");
526     syslog(LOG_ERR, "bind: %m");
527     close(sock);
528     return (-1);
529   }
530
531   on = fcntl(sock, F_GETFL);
532   if (on == -1) {
533     syslog(LOG_ERR, "fcntl (F_GETFL): %m\n");
534   } else {
535     if (fcntl(sock, F_SETFL, on | O_NONBLOCK) == -1) {
536       syslog(LOG_ERR, "fcntl O_NONBLOCK: %m\n");
537     }
538   }
539   return sock;
540 }
541
542 int
543 join_mcast(struct interface *ifs, int sock)
544 {
545   /* See linux/in6.h */
546   struct ipaddr_str buf;
547   struct ipv6_mreq mcastreq;
548
549   mcastreq.ipv6mr_multiaddr = ifs->int6_multaddr.sin6_addr;
550   mcastreq.ipv6mr_interface = ifs->if_index;
551
552 #if !defined __FreeBSD__ && !defined __MacOSX__ && !defined __NetBSD__
553   OLSR_PRINTF(3, "Interface %s joining multicast %s...", ifs->int_name, ip6_to_string(&buf, &ifs->int6_multaddr.sin6_addr));
554   /* Send multicast */
555   if (setsockopt(sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, (char *)&mcastreq, sizeof(struct ipv6_mreq)) < 0) {
556     perror("Join multicast");
557     return -1;
558   }
559 #else
560 #warning implement IPV6_ADD_MEMBERSHIP
561 #endif
562
563   /* Old libc fix */
564 #ifdef IPV6_JOIN_GROUP
565   /* Join reciever group */
566   if (setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, (char *)&mcastreq, sizeof(struct ipv6_mreq)) < 0)
567 #else
568   /* Join reciever group */
569   if (setsockopt(sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, (char *)&mcastreq, sizeof(struct ipv6_mreq)) < 0)
570 #endif
571   {
572     perror("Join multicast send");
573     return -1;
574   }
575
576   if (setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_IF, (char *)&mcastreq.ipv6mr_interface, sizeof(mcastreq.ipv6mr_interface)) < 0) {
577     perror("Set multicast if");
578     return -1;
579   }
580
581   OLSR_PRINTF(3, "OK\n");
582   return 0;
583 }
584
585 /*
586  *From net-tools lib/interface.c
587  *
588  */
589 int
590 get_ipv6_address(char *ifname, struct sockaddr_in6 *saddr6, int scope_in)
591 {
592   char addr6[40], devname[IFNAMSIZ];
593   char addr6p[8][5];
594   int plen, scope, dad_status, if_idx;
595   FILE *f;
596   struct sockaddr_in6 tmp_sockaddr6;
597
598   if ((f = fopen(_PATH_PROCNET_IFINET6, "r")) != NULL) {
599     while (fscanf
600            (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],
601             addr6p[5], addr6p[6], addr6p[7], &if_idx, &plen, &scope, &dad_status, devname) != EOF) {
602       if (!strcmp(devname, ifname)) {
603         sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s", addr6p[0], addr6p[1], addr6p[2], addr6p[3], addr6p[4], addr6p[5], addr6p[6],
604                 addr6p[7]);
605         OLSR_PRINTF(5, "\tinet6 addr: %s\n", addr6);
606         OLSR_PRINTF(5, "\tScope: %d\n", scope);
607         if (scope == scope_in) {
608           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],
609                       addr6p[6], addr6p[7]);
610           inet_pton(AF_INET6, addr6, &tmp_sockaddr6);
611           memcpy(&saddr6->sin6_addr, &tmp_sockaddr6, 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 /*
800  * Local Variables:
801  * c-basic-offset: 2
802  * indent-tabs-mode: nil
803  * End:
804  */