Merge branch 'release-0.9.7'
[olsrd.git] / lib / pud / src / networkInterfaces.c
1 /*
2  * The olsr.org Optimized Link-State Routing daemon (olsrd)
3  *
4  * (c) by the OLSR project
5  *
6  * See our Git repository to find out who worked on this file
7  * and thus is a copyright holder on it.
8  *
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  *
15  * * Redistributions of source code must retain the above copyright
16  *   notice, this list of conditions and the following disclaimer.
17  * * Redistributions in binary form must reproduce the above copyright
18  *   notice, this list of conditions and the following disclaimer in
19  *   the documentation and/or other materials provided with the
20  *   distribution.
21  * * Neither the name of olsr.org, olsrd nor the names of its
22  *   contributors may be used to endorse or promote products derived
23  *   from this software without specific prior written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
28  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
29  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
30  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
31  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
32  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
33  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
35  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  * POSSIBILITY OF SUCH DAMAGE.
37  *
38  * Visit http://www.olsr.org for more information.
39  *
40  * If you find this software useful feel free to make a donation
41  * to the project. For more information see the website or contact
42  * the copyright holders.
43  *
44  */
45
46 #include "networkInterfaces.h"
47
48 /* Plugin includes */
49 #include "pud.h"
50 #include "configuration.h"
51 #include "netTools.h"
52
53 /* OLSRD includes */
54 #include "olsr.h"
55 #include "interfaces.h"
56
57 /* System includes */
58 #include <unistd.h>
59 #include <fcntl.h>
60
61 /*
62  * Main IP MAC address
63  */
64
65 /** the MAC address of the main IP address */
66 static unsigned char mac[PUD_NODEIDTYPE_MAC_BYTES] = { 0 };
67
68 /** true when the MAC address of the main IP address has been retrieved */
69 static bool macSet = false;
70
71 /**
72  * @return
73  * the MAC address of the main IP address
74  */
75 unsigned char * getMainIpMacAddress(void) {
76         if (!macSet) {
77                 struct ifreq ifr;
78                 unsigned char * macInIfr;
79
80                 struct interface_olsr *mainInterface = if_ifwithaddr(&olsr_cnf->main_addr);
81                 if (!mainInterface) {
82                         pudError(true, "Could not get the main interface");
83                         return NULL;
84                 }
85                 macInIfr = getHardwareAddress(mainInterface->int_name, olsr_cnf->ip_version, &ifr);
86                 if (!macInIfr) {
87                         pudError(true, "Could not get the MAC address of the main interface");
88                         return NULL;
89                 }
90                 memcpy(&mac[0], &macInIfr[0], PUD_NODEIDTYPE_MAC_BYTES);
91                 macSet = true;
92         }
93
94         return &mac[0];
95 }
96
97 /*
98  * TX interfaces
99  */
100
101 /** The list of network interface objects, sending our NMEA sentences */
102 static TRxTxNetworkInterface *txNetworkInterfacesListHead = NULL;
103
104 /** Pointer to the last network interface object, sending our NMEA sentences */
105 static TRxTxNetworkInterface *lastTxNetworkInterface = NULL;
106
107 /**
108  @return
109  The list of network interface objects, sending our NMEA sentences
110  */
111 TRxTxNetworkInterface *getTxNetworkInterfaces(void) {
112         return txNetworkInterfacesListHead;
113 }
114
115 /**
116  Create a transmit socket for a network interface
117
118  @param networkInterface
119  The network interface object. This function expects it to be filled with all
120  information, except for the socket descriptor.
121  @param txMcAddr
122  The transmit multicast address
123
124  @return
125  - the socket descriptor (>= 0)
126  - -1 if an error occurred
127  */
128 static int createTxSocket(TRxTxNetworkInterface * networkInterface, union olsr_sockaddr * txMcAddr) {
129         int ipFamilySetting;
130         int ipProtoSetting;
131         int ipMcLoopSetting;
132         int ipMcIfSetting;
133         int ipTtlSetting;
134         unsigned int ifIndex;
135
136         union olsr_sockaddr address;
137         void * addr;
138         size_t addrSize;
139
140         int txSocket = -1;
141
142         int mcLoopValue = 1;
143         int txTtl = getTxTtl();
144
145         assert(networkInterface != NULL);
146         assert(strncmp((char *) &networkInterface->name[0], "",
147                                         sizeof(networkInterface->name)) != 0);
148
149         memset(&address, 0, sizeof(address));
150         if (txMcAddr->in.sa_family == AF_INET) {
151                 struct ifreq ifr;
152                 struct in_addr * ifAddr = getIPv4Address(networkInterface->name, &ifr);
153                 if (!ifAddr) {
154                         pudError(true, "Could not get interface address of %s", networkInterface->name);
155                         goto bail;
156                 }
157
158                 assert(txMcAddr->in4.sin_addr.s_addr != INADDR_ANY);
159
160                 ipFamilySetting = AF_INET;
161                 ipProtoSetting = IPPROTO_IP;
162                 ipMcLoopSetting = IP_MULTICAST_LOOP;
163                 ipMcIfSetting = IP_MULTICAST_IF;
164                 ipTtlSetting = IP_MULTICAST_TTL;
165                 ifIndex = 0;
166
167                 address.in4.sin_family = ipFamilySetting;
168                 address.in4.sin_addr = *ifAddr;
169                 address.in4.sin_port = getTxMcPort();
170                 addr = &address.in4;
171                 addrSize = sizeof(struct sockaddr_in);
172         } else {
173                 assert(txMcAddr->in6.sin6_addr.s6_addr != in6addr_any.s6_addr);
174
175                 ipFamilySetting = AF_INET6;
176                 ipProtoSetting = IPPROTO_IPV6;
177                 ipMcLoopSetting = IPV6_MULTICAST_LOOP;
178                 ipMcIfSetting = IPV6_MULTICAST_IF;
179                 ipTtlSetting = IPV6_MULTICAST_HOPS;
180                 ifIndex = if_nametoindex(networkInterface->name);
181
182                 addr = &ifIndex;
183                 addrSize = sizeof(ifIndex);
184         }
185
186         /*  Create a datagram socket on which to transmit */
187         errno = 0;
188         txSocket = socket(ipFamilySetting, SOCK_DGRAM, 0);
189         if (txSocket < 0) {
190                 pudError(true, "Could not create a transmit socket for interface %s",
191                                 networkInterface->name);
192                 goto bail;
193         }
194
195         /* Bind the socket to the desired interface */
196         errno = 0;
197         if (setsockopt(txSocket, ipProtoSetting, ipMcIfSetting, addr, addrSize) < 0) {
198                 pudError(true, "Could not set the multicast interface on the"
199                         " transmit socket to interface %s", networkInterface->name);
200                 goto bail;
201         }
202
203         /* Disable multicast local loopback */
204         errno = 0;
205         if (setsockopt(txSocket, ipProtoSetting, ipMcLoopSetting, &mcLoopValue,
206                         sizeof(mcLoopValue)) < 0) {
207                 pudError(true, "Could not disable multicast loopback on the"
208                         " transmit socket for interface %s", networkInterface->name);
209                 goto bail;
210         }
211
212         /* Set the TTL on the socket */
213         errno = 0;
214         if (setsockopt(txSocket, ipProtoSetting, ipTtlSetting, &txTtl,
215                         sizeof(txTtl)) < 0) {
216                 pudError(true, "Could not set TTL on the transmit socket"
217                         " for interface %s", networkInterface->name);
218                 goto bail;
219         }
220
221         /* Set the no delay option on the socket */
222         errno = 0;
223         if (fcntl(txSocket, F_SETFL, O_NDELAY) < 0) {
224                 pudError(true, "Could not set the no delay option on the"
225                         " transmit socket for interface %s", networkInterface->name);
226                 goto bail;
227         }
228
229         return txSocket;
230
231         bail: if (txSocket >= 0) {
232                 close(txSocket);
233         }
234         return -1;
235 }
236
237 /**
238  Create a transmit interface and add it to the list of transmit network
239  interface objects
240
241  @param ifName
242  the network interface name
243  @param txMcAddr
244  the transmit multicast address
245
246  @return
247  - true on success
248  - false on failure
249  */
250 static bool createTxInterface(const char * ifName, union olsr_sockaddr * txMcAddr) {
251         int socketFd = -1;
252         TRxTxNetworkInterface * networkInterface = NULL;
253
254         if (ifName == NULL) {
255                 goto bail;
256         }
257
258         networkInterface = olsr_malloc(sizeof(TRxTxNetworkInterface),
259                         "TRxTxNetworkInterface (PUD)");
260         if (networkInterface == NULL) {
261                 goto bail;
262         }
263
264         memcpy(networkInterface->name, ifName, sizeof(networkInterface->name));
265         networkInterface->name[IFNAMSIZ] = '\0';
266         networkInterface->handler = NULL;
267         networkInterface->next = NULL;
268
269         /* networkInterface needs to be filled in when calling createTxSocket */
270         socketFd = createTxSocket(networkInterface, txMcAddr);
271         if (socketFd < 0) {
272                 goto bail;
273         }
274         networkInterface->socketFd = socketFd;
275
276         /* Add new object to the end of the global list. */
277         if (txNetworkInterfacesListHead == NULL) {
278                 txNetworkInterfacesListHead = networkInterface;
279                 lastTxNetworkInterface = networkInterface;
280         } else {
281                 lastTxNetworkInterface->next = networkInterface;
282                 lastTxNetworkInterface = networkInterface;
283         }
284
285         return true;
286
287         bail: if (networkInterface != NULL) {
288                 free(networkInterface);
289         }
290         return false;
291 }
292
293 /*
294  * Downlink interface
295  */
296
297 /** The socket fd, receiving downlinked messages */
298 static int downlinkSocketFd = -1;
299
300 /** the downlink handler function */
301 static socket_handler_func downlinkHandler = NULL;
302
303
304 /**
305  @return
306  The downlink socket fd. -1 when not valid.
307  */
308 int getDownlinkSocketFd(void) {
309         return downlinkSocketFd;
310 }
311
312 /**
313  Create an downlink socket
314
315  @param ipVersion
316  The IP version (AF_INET or AF_INET6) for the socket
317  @param rxSocketHandlerFunction
318  The socket handler function
319
320  @return
321  - the socket descriptor (>= 0)
322  - -1 if an error occurred
323  */
324 static int createDownlinkSocket(int ipVersion, socket_handler_func rxSocketHandlerFunction) {
325         union olsr_sockaddr address;
326         void * addr;
327         size_t addrSize;
328
329         int downlinkSocket = -1;
330
331         int socketReuseFlagValue = 1;
332
333         memset(&address, 0, sizeof(address));
334         if (ipVersion == AF_INET) {
335                 address.in4.sin_family = AF_INET;
336                 address.in4.sin_addr.s_addr = INADDR_ANY;
337                 address.in4.sin_port = getDownlinkPort();
338                 addr = &address.in4;
339                 addrSize = sizeof(struct sockaddr_in);
340         } else {
341                 address.in6.sin6_family = AF_INET6;
342                 address.in6.sin6_addr = in6addr_any;
343                 address.in6.sin6_port = getDownlinkPort();
344                 addr = &address.in6;
345                 addrSize = sizeof(struct sockaddr_in6);
346         }
347
348         /*  Create a datagram socket on which to receive */
349         errno = 0;
350         downlinkSocket = socket(ipVersion, SOCK_DGRAM, 0);
351         if (downlinkSocket < 0) {
352                 pudError(true, "Could not create the downlink socket");
353                 goto bail;
354         }
355
356         /* Enable SO_REUSEADDR to allow multiple applications to receive the same
357          * messages */
358         errno = 0;
359         if (setsockopt(downlinkSocket, SOL_SOCKET, SO_REUSEADDR, &socketReuseFlagValue,
360                         sizeof(socketReuseFlagValue)) < 0) {
361                 pudError(true, "Could not set REUSE option on the downlink socket");
362                 goto bail;
363         }
364
365         /* Bind to the proper port number with the IP address INADDR_ANY
366          * (INADDR_ANY is really required here, do not change it) */
367         errno = 0;
368         if (bind(downlinkSocket, addr, addrSize)) {
369                 pudError(true, "Could not bind downlink socket to port %d",
370                                 getDownlinkPort());
371                 goto bail;
372         }
373
374         add_olsr_socket(downlinkSocket, rxSocketHandlerFunction, NULL, NULL,
375                         SP_PR_READ);
376
377         downlinkHandler = rxSocketHandlerFunction;
378
379         return downlinkSocket;
380
381         bail: if (downlinkSocket >= 0) {
382                 close(downlinkSocket);
383         }
384         return -1;
385 }
386
387 /*
388  * Interface Functions
389  */
390
391 /**
392  Creates receive and transmit sockets and register the receive sockets with
393  the OLSR stack
394
395  @param rxSocketHandlerFunctionDownlink
396  The function to call upon reception of data on a downlink receive socket
397
398  @return
399  - true on success
400  - false on failure
401  */
402 bool createNetworkInterfaces(socket_handler_func rxSocketHandlerFunctionDownlink) {
403         union olsr_sockaddr * txMcAddr = getTxMcAddr();
404         unsigned int count = 0;
405
406         /* loop over all configured tx interfaces */
407         count = getTxNonOlsrInterfaceCount();
408         while (count--) {
409                 if (!createTxInterface((char *)getTxNonOlsrInterfaceName(count), txMcAddr)) {
410                         /* creating a transmit interface failed */
411                         return false;
412                 }
413         }
414
415         /* create uplink socket when needed */
416         if (isUplinkAddrSet()) {
417                 downlinkSocketFd = createDownlinkSocket(getUplinkAddr()->in.sa_family, rxSocketHandlerFunctionDownlink);
418                 if (downlinkSocketFd == -1) {
419                         return false;
420                 }
421         } else {
422                 downlinkSocketFd = -1;
423         }
424
425         return true;
426 }
427
428 /**
429  Close and cleanup the network interfaces in the given list
430
431  @param networkInterface
432  the list of network interface to close and clean up
433  */
434 static void closeInterfaces(TRxTxNetworkInterface * networkInterface) {
435         TRxTxNetworkInterface * nextNetworkInterface = networkInterface;
436         while (nextNetworkInterface != NULL) {
437                 TRxTxNetworkInterface * iteratedNetworkInterface = nextNetworkInterface;
438                 if (iteratedNetworkInterface->socketFd >= 0) {
439                         if (iteratedNetworkInterface->handler) {
440                                 remove_olsr_socket(iteratedNetworkInterface->socketFd,
441                                                 iteratedNetworkInterface->handler, NULL);
442                         }
443                         close(iteratedNetworkInterface->socketFd);
444                         iteratedNetworkInterface->socketFd = -1;
445                 }
446                 nextNetworkInterface = iteratedNetworkInterface->next;
447                 iteratedNetworkInterface->next = NULL;
448                 free(iteratedNetworkInterface);
449         }
450 }
451
452 /**
453  Close and cleanup all receive and transmit network interfaces
454  */
455 void closeNetworkInterfaces(void) {
456         if (txNetworkInterfacesListHead != NULL) {
457                 closeInterfaces(txNetworkInterfacesListHead);
458                 txNetworkInterfacesListHead = NULL;
459         }
460
461         if (downlinkSocketFd != -1 ) {
462                 if (downlinkHandler) {
463                         remove_olsr_socket (downlinkSocketFd, downlinkHandler, NULL);
464                         downlinkHandler = NULL;
465                 }
466                 close(downlinkSocketFd);
467                 downlinkSocketFd = -1;
468         }
469 }