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