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