Add link time optimization of available
[oonf.git] / src / os_linux / os_net_linux.c
1 /*
2  * os_net_linux.c
3  *
4  *  Created on: Oct 18, 2011
5  *      Author: rogge
6  */
7
8 #include <net/if.h>
9 #include <netinet/in.h>
10 #include <sys/ioctl.h>
11 #include <errno.h>
12 #include <ifaddrs.h>
13
14 #include "common/common_types.h"
15
16 #include "olsr_cfg.h"
17 #include "olsr_interface.h"
18 #include "olsr_logging.h"
19 #include "olsr.h"
20 #include "os_net.h"
21
22 static int _ioctl_v4, _ioctl_v6;
23
24 OLSR_SUBSYSTEM_STATE(_os_net_state);
25
26 /**
27  * Initialize os_net subsystem
28  * @return -1 if an error happened, 0 otherwise
29  */
30 int
31 os_net_init(void) {
32   if (olsr_subsystem_is_initialized(&_os_net_state))
33     return 0;
34
35   _ioctl_v4 = socket(AF_INET, SOCK_DGRAM, 0);
36   if (_ioctl_v4 == -1) {
37     OLSR_WARN(LOG_OS_NET, "Cannot open ipv4 ioctl socket: %s (%d)",
38         strerror(errno), errno);
39     return -1;
40   }
41
42   if (config_global.ipv6) {
43     _ioctl_v6 = socket(AF_INET6, SOCK_DGRAM, 0);
44     if (_ioctl_v6 == -1) {
45       OLSR_WARN(LOG_OS_NET, "Cannot open ipv6 ioctl socket: %s (%d)",
46           strerror(errno), errno);
47       close(_ioctl_v4);
48       return -1;
49     }
50   }
51   else {
52     _ioctl_v6 = -1;
53   }
54
55   olsr_subsystem_init(&_os_net_state);
56   return 0;
57 }
58
59 /**
60  * Cleanup os_net subsystem
61  */
62 void
63 os_net_cleanup(void) {
64   if (olsr_subsystem_cleanup(&_os_net_state))
65     return;
66
67   if (_ioctl_v4 != -1) {
68     close (_ioctl_v4);
69     _ioctl_v4 = -1;
70   }
71   if (_ioctl_v6 != -1) {
72     close (_ioctl_v6);
73     _ioctl_v6 = -1;
74   }
75 }
76
77 /**
78  * Updates the data of an interface.
79  * @param interf pointer to interface object.
80  * @param name name of interface
81  * @return -1 if an error happened, 0 otherwise
82  */
83 int
84 os_net_update_interface(struct olsr_interface_data *data,
85     const char *name) {
86   struct ifaddrs *ifaddr, *ifa;
87   union netaddr_socket *sock;
88   struct netaddr addr;
89   struct ifreq ifr;
90
91   memset(data, 0, sizeof(*data));
92
93   /* get interface index */
94   data->index = if_nametoindex(name);
95
96   if (data->index == 0) {
97     return 0;
98   }
99
100   if (getifaddrs(&ifaddr) == -1) {
101     OLSR_WARN(LOG_OS_NET, "Cannot get interface addresses: %s (%d)",
102         strerror(errno), errno);
103     return -1;
104   }
105
106   for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
107     if (strcmp(ifa->ifa_name, name) != 0) {
108       continue;
109     }
110
111     sock = (union netaddr_socket *)ifa->ifa_addr;
112
113     if (netaddr_from_socket(&addr, sock)) {
114       /* just ignore other interfaces */
115       continue;
116     }
117
118     if (addr.type == AF_INET) {
119       memcpy(&data->if_v4, &addr, sizeof(data->if_v4));
120     }
121     else if (addr.type == AF_INET6) {
122       if (IN6_IS_ADDR_LINKLOCAL(addr.addr)) {
123         memcpy(&data->linklocal_v6, &addr, sizeof(data->linklocal_v6));
124       }
125       else if (!(IN6_IS_ADDR_LOOPBACK(addr.addr)
126           || IN6_IS_ADDR_MULTICAST(addr.addr)
127           || IN6_IS_ADDR_UNSPECIFIED(addr.addr)
128           || IN6_IS_ADDR_V4COMPAT(addr.addr)
129           || IN6_IS_ADDR_V4MAPPED(addr.addr))) {
130         memcpy(&data->if_v6, &addr, sizeof(data->if_v6));
131       }
132     }
133   }
134
135   memset(&ifr, 0, sizeof(ifr));
136   strscpy(ifr.ifr_name, name, IFNAMSIZ);
137
138   if (ioctl(_ioctl_v4, SIOCGIFFLAGS, &ifr) < 0) {
139     OLSR_WARN(LOG_OS_NET,
140         "ioctl SIOCGIFFLAGS (get flags) error on device %s: %s (%d)\n",
141         name, strerror(errno), errno);
142     return -1;
143   }
144
145   if ((ifr.ifr_flags & (IFF_UP | IFF_RUNNING)) == (IFF_UP|IFF_RUNNING)) {
146     data->up = true;
147   }
148
149   return 0;
150 }