4b192f292586edd900346247b3a355eb6bd0c417
[oonf.git] / src-api / core / os_linux / os_net_linux.c
1
2 /*
3  * The olsr.org Optimized Link-State Routing daemon(olsrd)
4  * Copyright (c) 2004-2013, 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 #include <net/if.h>
43 #include <netinet/in.h>
44 #include <sys/ioctl.h>
45 #include <errno.h>
46
47 #include "common/common_types.h"
48
49 #include "core/olsr_interface.h"
50 #include "core/olsr_logging.h"
51 #include "core/olsr_subsystem.h"
52 #include "core/os_net.h"
53
54 /* prototypes */
55 static int _init(void);
56 static void _cleanup(void);
57
58 /* global ioctl sockets for ipv4 and ipv6 */
59 static int _ioctl_v4, _ioctl_v6;
60
61 /* subsystem definition */
62 struct oonf_subsystem oonf_os_net_subsystem = {
63   .init = _init,
64   .cleanup = _cleanup,
65 };
66
67 /**
68  * Initialize os_net subsystem
69  * @return -1 if an error happened, 0 otherwise
70  */
71 static int
72 _init(void) {
73   _ioctl_v4 = socket(AF_INET, SOCK_DGRAM, 0);
74   if (_ioctl_v4 == -1) {
75     OLSR_WARN(LOG_OS_NET, "Cannot open ipv4 ioctl socket: %s (%d)",
76         strerror(errno), errno);
77     return -1;
78   }
79
80   _ioctl_v6 = socket(AF_INET6, SOCK_DGRAM, 0);
81   if (_ioctl_v6 == -1) {
82     OLSR_WARN(LOG_OS_NET, "Cannot open ipv6 ioctl socket: %s (%d)",
83         strerror(errno), errno);
84
85     /* do not stop here, system might just not support IPv6 */
86   }
87
88   return 0;
89 }
90
91 /**
92  * Cleanup os_net subsystem
93  */
94 static void
95 _cleanup(void) {
96   close (_ioctl_v4);
97   if (_ioctl_v6 != -1) {
98     close (_ioctl_v6);
99   }
100 }
101
102 /**
103  * Receive data from a socket.
104  * @param fd filedescriptor
105  * @param buf buffer for incoming data
106  * @param length length of buffer
107  * @param source pointer to netaddr socket object to store source of packet
108  * @param interf limit received data to certain interface
109  *   (only used if socket cannot be bound to interface)
110  * @return same as recvfrom()
111  */
112 int
113 os_recvfrom(int fd, void *buf, size_t length, union netaddr_socket *source,
114     struct olsr_interface_data *interf __attribute__((unused))) {
115   socklen_t len = sizeof(*source);
116   return recvfrom(fd, buf, length, 0, &source->std, &len);
117 }
118
119 /**
120  * Updates the data of an interface.
121  * The interface data object will be completely overwritten
122  * @param ifdata pointer to an interface data object
123  * @param name name of interface
124  * @return -1 if an error happened, 0 otherwise
125  */
126 int
127 os_net_update_interface(struct olsr_interface_data *ifdata,
128     const char *name) {
129   struct ifreq ifr;
130   struct ifaddrs *ifaddrs;
131   struct ifaddrs *ifa;
132   size_t addrcount;
133   union netaddr_socket *sock;
134   struct netaddr *addr;
135
136   /* cleanup data structure */
137   if (ifdata->addresses) {
138     free(ifdata->addresses);
139   }
140
141   memset(ifdata, 0, sizeof(*ifdata));
142   strscpy(ifdata->name, name, sizeof(ifdata->name));
143
144   /* get interface index */
145   ifdata->index = if_nametoindex(name);
146   if (ifdata->index == 0) {
147     /* interface is not there at the moment */
148     return 0;
149   }
150
151   memset(&ifr, 0, sizeof(ifr));
152   strscpy(ifr.ifr_name, ifdata->name, IF_NAMESIZE);
153
154   if (ioctl(_ioctl_v4, SIOCGIFFLAGS, &ifr) < 0) {
155     OLSR_WARN(LOG_OS_NET,
156         "ioctl SIOCGIFFLAGS (get flags) error on device %s: %s (%d)\n",
157         ifdata->name, strerror(errno), errno);
158     return -1;
159   }
160
161   if ((ifr.ifr_flags & (IFF_UP | IFF_RUNNING)) == (IFF_UP|IFF_RUNNING)) {
162     ifdata->up = true;
163   }
164
165   memset(&ifr, 0, sizeof(ifr));
166   strscpy(ifr.ifr_name, ifdata->name, IF_NAMESIZE);
167
168   if (ioctl(_ioctl_v4, SIOCGIFHWADDR, &ifr) < 0) {
169     OLSR_WARN(LOG_OS_NET,
170         "ioctl SIOCGIFHWADDR (get flags) error on device %s: %s (%d)\n",
171         ifdata->name, strerror(errno), errno);
172     return -1;
173   }
174
175   netaddr_from_binary(&ifdata->mac, ifr.ifr_hwaddr.sa_data, 6, AF_MAC48);
176
177   /* get ip addresses */
178   ifaddrs = NULL;
179   addrcount = 0;
180
181   if (getifaddrs(&ifaddrs)) {
182     OLSR_WARN(LOG_OS_NET,
183         "getifaddrs() failed: %s (%d)", strerror(errno), errno);
184     return -1;
185   }
186
187   for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) {
188     if (strcmp(ifdata->name, ifa->ifa_name) == 0 &&
189         (ifa->ifa_addr->sa_family == AF_INET || ifa->ifa_addr->sa_family == AF_INET6)) {
190       addrcount++;
191     }
192   }
193
194   ifdata->addresses = calloc(addrcount, sizeof(struct netaddr));
195   if (ifdata->addresses == NULL) {
196     OLSR_WARN(LOG_OS_NET,
197         "Cannot allocate memory for interface %s with %"PRINTF_SIZE_T_SPECIFIER" prefixes",
198         ifdata->name, addrcount);
199     freeifaddrs(ifaddrs);
200     return -1;
201   }
202
203   for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) {
204     if (strcmp(ifdata->name, ifa->ifa_name) == 0 &&
205         (ifa->ifa_addr->sa_family == AF_INET || ifa->ifa_addr->sa_family == AF_INET6)) {
206       sock = (union netaddr_socket *)ifa->ifa_addr;
207       addr = &ifdata->addresses[ifdata->addrcount];
208
209       if (netaddr_from_socket(&ifdata->addresses[ifdata->addrcount], sock) == 0) {
210         ifdata->addrcount++;
211
212         if (netaddr_get_address_family(addr) == AF_INET) {
213           if (!(netaddr_is_in_subnet(&NETADDR_IPV4_LOOPBACK, addr)
214               || netaddr_is_in_subnet(&NETADDR_IPV4_MULTICAST, addr))) {
215             ifdata->if_v4 = addr;
216           }
217         }
218         else if (netaddr_get_address_family(addr) == AF_INET6) {
219           if (netaddr_is_in_subnet(&NETADDR_IPV6_LINKLOCAL, addr)) {
220             ifdata->linklocal_v6_ptr = addr;
221           }
222           else if (!(netaddr_cmp(&NETADDR_IPV6_LOOPBACK, addr) == 0
223               || netaddr_is_in_subnet(&NETADDR_IPV6_MULTICAST, addr)
224               || netaddr_is_in_subnet(&NETADDR_IPV6_IPV4COMPATIBLE, addr)
225               || netaddr_is_in_subnet(&NETADDR_IPV6_IPV4MAPPED, addr))) {
226             ifdata->if_v6 = addr;
227           }
228         }
229       }
230     }
231   }
232
233   freeifaddrs(ifaddrs);
234   return 0;
235 }