PUD: make all variables static
[olsrd.git] / lib / pud / src / networkInterfaces.c
1 #include "networkInterfaces.h"
2
3 /* Plugin includes */
4 #include "pud.h"
5 #include "configuration.h"
6 #include "netTools.h"
7
8 /* OLSRD includes */
9 #include "cfgparser/olsrd_conf.h"
10 #include "olsr.h"
11
12 /* System includes */
13 #include <assert.h>
14 #include <stddef.h>
15 #include <string.h>
16 #include <sys/socket.h>
17 #include <errno.h>
18 #include <unistd.h>
19 #include <netinet/in.h>
20 #include <stdlib.h>
21 #include <fcntl.h>
22 #include <ifaddrs.h>
23
24 /*
25  * RX interfaces
26  */
27
28 /** The list of network interface objects, receiving GPS NMEA sentences */
29 static TRxTxNetworkInterface *rxNetworkInterfacesListHead = NULL;
30
31 /** Pointer to the last network interface object, receiving GPS NMEA sentences */
32 static TRxTxNetworkInterface *lastRxNetworkInterface = NULL;
33
34 /**
35  @return
36  The list of network interface objects, receiving GPS NMEA sentences
37  */
38 TRxTxNetworkInterface *getRxNetworkInterfaces(void) {
39         return rxNetworkInterfacesListHead;
40 }
41
42 /**
43  Create a receive socket for a network interface
44
45  @param networkInterface
46  The network interface object. This function expects it to be filled with all
47  information, except for the socket descriptor.
48  @param rxSocketHandlerFunction
49  The function that handles reception of data on the network interface
50
51  @return
52  - the socket descriptor (>= 0)
53  - -1 if an error occurred
54  */
55 static int createRxSocket(TRxTxNetworkInterface * networkInterface,
56                 socket_handler_func rxSocketHandlerFunction) {
57         int ipFamilySetting;
58         int ipProtoSetting;
59         int ipMcLoopSetting;
60         int ipAddMembershipSetting;
61         int socketReuseFlagValue = 1;
62         int mcLoopValue = 1;
63         union olsr_sockaddr address;
64         int rxSocket = -1;
65
66         assert(networkInterface != NULL);
67         assert(rxSocketHandlerFunction != NULL);
68         assert(strncmp((char *) &networkInterface->name[0], "",
69                                         sizeof(networkInterface->name)) != 0);
70
71         memset(&address, 0, sizeof(address));
72         if (olsr_cnf->ip_version == AF_INET) {
73                 assert(networkInterface->ipAddress.in4.sin_addr.s_addr != INADDR_ANY);
74
75                 ipFamilySetting = AF_INET;
76                 ipProtoSetting = IPPROTO_IP;
77                 ipMcLoopSetting = IP_MULTICAST_LOOP;
78                 ipAddMembershipSetting = IP_ADD_MEMBERSHIP;
79
80                 address.in4.sin_family = ipFamilySetting;
81                 address.in4.sin_addr.s_addr = INADDR_ANY;
82                 address.in4.sin_port = getRxMcPort();
83         } else {
84                 assert(networkInterface->ipAddress.in6.sin6_addr.s6_addr != in6addr_any.s6_addr);
85
86                 ipFamilySetting = AF_INET6;
87                 ipProtoSetting = IPPROTO_IPV6;
88                 ipMcLoopSetting = IPV6_MULTICAST_LOOP;
89                 ipAddMembershipSetting = IPV6_ADD_MEMBERSHIP;
90
91                 address.in6.sin6_family = ipFamilySetting;
92                 address.in6.sin6_addr = in6addr_any;
93                 address.in6.sin6_port = getRxMcPort();
94         }
95
96         /* Create a datagram socket on which to receive. */
97         errno = 0;
98         rxSocket = socket(ipFamilySetting, SOCK_DGRAM, 0);
99         if (rxSocket < 0) {
100                 pudError(true, "Could not create a receive socket for interface %s",
101                                 networkInterface->name);
102                 goto bail;
103         }
104
105         /* Enable SO_REUSEADDR to allow multiple applications to receive the same
106          * multicast messages */
107         errno = 0;
108         if (setsockopt(rxSocket, SOL_SOCKET, SO_REUSEADDR, &socketReuseFlagValue,
109                         sizeof(socketReuseFlagValue)) < 0) {
110                 pudError(true, "Could not set the reuse flag on the receive socket for"
111                         " interface %s", networkInterface->name);
112                 goto bail;
113         }
114
115         /* Bind to the proper port number with the IP address INADDR_ANY
116          * (INADDR_ANY is really required here, do not change it) */
117         errno = 0;
118         if (bind(rxSocket, (struct sockaddr *) &address, sizeof(address)) < 0) {
119                 pudError(true, "Could not bind the receive socket for interface"
120                         " %s to port %u", networkInterface->name, ntohs(getRxMcPort()));
121                 goto bail;
122         }
123
124         /* Enable multicast local loopback */
125         errno = 0;
126         if (setsockopt(rxSocket, ipProtoSetting, ipMcLoopSetting, &mcLoopValue,
127                         sizeof(mcLoopValue)) < 0) {
128                 pudError(true, "Could not %s multicast loopback on the"
129                         " receive socket for interface %s", mcLoopValue ? "enable"
130                                 : "disable", networkInterface->name);
131                 goto bail;
132         }
133
134         /* Join the multicast group on the local interface. Note that this
135          * ADD_MEMBERSHIP option must be called for each local interface over
136          * which the multicast datagrams are to be received. */
137         if (ipFamilySetting == AF_INET) {
138                 struct ip_mreq mc_settings;
139                 (void) memset(&mc_settings, 0, sizeof(mc_settings));
140                 mc_settings.imr_multiaddr = getRxMcAddr()->in4.sin_addr;
141                 mc_settings.imr_interface = networkInterface->ipAddress.in4.sin_addr;
142                 errno = 0;
143                 if (setsockopt(rxSocket, ipProtoSetting, ipAddMembershipSetting,
144                                 &mc_settings, sizeof(mc_settings)) < 0) {
145                         pudError(true, "Could not subscribe interface %s to the configured"
146                                 " multicast group", networkInterface->name);
147                         goto bail;
148                 }
149         } else {
150                 struct ipv6_mreq mc6_settings;
151                 (void) memset(&mc6_settings, 0, sizeof(mc6_settings));
152                 mc6_settings.ipv6mr_multiaddr = getRxMcAddr()->in6.sin6_addr;
153                 mc6_settings.ipv6mr_interface = 0;
154                 errno = 0;
155                 if (setsockopt(rxSocket, ipProtoSetting, ipAddMembershipSetting,
156                                 &mc6_settings, sizeof(mc6_settings)) < 0) {
157                         pudError(true, "Could not subscribe interface %s to the configured"
158                                 " multicast group", networkInterface->name);
159                         goto bail;
160                 }
161         }
162
163         add_olsr_socket(rxSocket, rxSocketHandlerFunction, NULL, networkInterface,
164                         SP_PR_READ);
165
166         return rxSocket;
167
168         bail: if (rxSocket >= 0) {
169                 close(rxSocket);
170         }
171         return -1;
172
173 }
174
175 /**
176  Create a receive interface and add it to the list of receive network interface
177  objects
178
179  @param ifName
180  the network interface name
181  @param ipAddr
182  the IP address of the interface
183  @param rxSocketHandlerFunction
184  the function that handles reception of data on the network interface
185
186  @return
187  - true on success
188  - false on failure
189  */
190 static bool createRxInterface(const char * ifName, union olsr_sockaddr ipAddr,
191                 socket_handler_func rxSocketHandlerFunction) {
192         unsigned char * hwAddr;
193         int socketFd = -1;
194         TRxTxNetworkInterface * networkInterface = NULL;
195         struct ifreq ifReqHwAddr;
196
197         if (ifName == NULL) {
198                 goto bail;
199         }
200
201         hwAddr = getHardwareAddress(ifName, olsr_cnf->ip_version, &ifReqHwAddr);
202         if (hwAddr == NULL) {
203                 goto bail;
204         }
205
206         networkInterface = olsr_malloc(sizeof(TRxTxNetworkInterface),
207                         "TRxTxNetworkInterface (PUD)");
208         if (networkInterface == NULL) {
209                 goto bail;
210         }
211
212         memcpy(networkInterface->name, ifName, sizeof(networkInterface->name));
213         networkInterface->name[IFNAMSIZ] = '\0';
214         networkInterface->ipAddress = ipAddr;
215         memcpy(&networkInterface->hwAddress[0], hwAddr,
216                         sizeof(networkInterface->hwAddress));
217         networkInterface->next = NULL;
218
219         /* networkInterface needs to be filled in when calling createRxSocket */
220         socketFd = createRxSocket(networkInterface, rxSocketHandlerFunction);
221         if (socketFd < 0) {
222                 goto bail;
223         }
224         networkInterface->socketFd = socketFd;
225
226         /* Add new object to the end of the global list. */
227         if (rxNetworkInterfacesListHead == NULL) {
228                 rxNetworkInterfacesListHead = networkInterface;
229                 lastRxNetworkInterface = networkInterface;
230         } else {
231                 lastRxNetworkInterface->next = networkInterface;
232                 lastRxNetworkInterface = networkInterface;
233         }
234
235         return true;
236
237         bail: if (networkInterface != NULL) {
238                 free(networkInterface);
239         }
240         return false;
241
242 }
243
244 /*
245  * TX interfaces
246  */
247
248 /** The list of network interface objects, sending our NMEA sentences */
249 static TRxTxNetworkInterface *txNetworkInterfacesListHead = NULL;
250
251 /** Pointer to the last network interface object, sending our NMEA sentences */
252 static TRxTxNetworkInterface *lastTxNetworkInterface = NULL;
253
254 /**
255  @return
256  The list of network interface objects, sending our NMEA sentences
257  */
258 TRxTxNetworkInterface *getTxNetworkInterfaces(void) {
259         return txNetworkInterfacesListHead;
260 }
261
262 /**
263  Create a transmit socket for a network interface
264
265  @param networkInterface
266  The network interface object. This function expects it to be filled with all
267  information, except for the socket descriptor.
268
269  @return
270  - the socket descriptor (>= 0)
271  - -1 if an error occurred
272  */
273 static int createTxSocket(TRxTxNetworkInterface * networkInterface) {
274         int ipFamilySetting;
275         int ipProtoSetting;
276         int ipMcLoopSetting;
277         int ipMcIfSetting;
278         int mcLoopValue = 0;
279         unsigned char txTtl = getTxTtl();
280         union olsr_sockaddr address;
281         int txSocket = -1;
282
283         assert(networkInterface != NULL);
284         assert(strncmp((char *) &networkInterface->name[0], "",
285                                         sizeof(networkInterface->name)) != 0);
286
287         memset(&address, 0, sizeof(address));
288         if (olsr_cnf->ip_version == AF_INET) {
289                 assert(networkInterface->ipAddress.in4.sin_addr.s_addr != INADDR_ANY);
290
291                 ipFamilySetting = AF_INET;
292                 ipProtoSetting = IPPROTO_IP;
293                 ipMcLoopSetting = IP_MULTICAST_LOOP;
294                 ipMcIfSetting = IP_MULTICAST_IF;
295
296                 address.in4.sin_family = ipFamilySetting;
297                 address.in4.sin_addr = networkInterface->ipAddress.in4.sin_addr;
298                 address.in4.sin_port = getTxMcPort();
299         } else {
300                 assert(networkInterface->ipAddress.in6.sin6_addr.s6_addr != in6addr_any.s6_addr);
301
302                 ipFamilySetting = AF_INET6;
303                 ipProtoSetting = IPPROTO_IPV6;
304                 ipMcLoopSetting = IPV6_MULTICAST_LOOP;
305                 ipMcIfSetting = IPV6_MULTICAST_IF;
306
307                 address.in6.sin6_family = ipFamilySetting;
308                 address.in6.sin6_addr = networkInterface->ipAddress.in6.sin6_addr;
309                 address.in6.sin6_port = getTxMcPort();
310         }
311
312         /*  Create a datagram socket on which to transmit */
313         errno = 0;
314         txSocket = socket(ipFamilySetting, SOCK_DGRAM, 0);
315         if (txSocket < 0) {
316                 pudError(true, "Could not create a transmit socket for interface %s",
317                                 networkInterface->name);
318                 goto bail;
319         }
320
321         /* Bind the socket to the desired interface and port */
322         errno = 0;
323         if (setsockopt(txSocket, ipProtoSetting, ipMcIfSetting, &address,
324                         sizeof(address)) < 0) {
325                 pudError(true, "Could not set the multicast interface on the"
326                         " transmit socket to interface %s", networkInterface->name);
327                 goto bail;
328         }
329
330         /* Disable multicast local loopback */
331         errno = 0;
332         if (setsockopt(txSocket, ipProtoSetting, ipMcLoopSetting, &mcLoopValue,
333                         sizeof(mcLoopValue)) < 0) {
334                 pudError(true, "Could not %s multicast loopback on the"
335                         " transmit socket for interface %s", mcLoopValue ? "enable"
336                                 : "disable", networkInterface->name);
337                 goto bail;
338         }
339
340         /* Set the TTL on the socket */
341         errno = 0;
342         if (setsockopt(txSocket, ipProtoSetting, IP_MULTICAST_TTL, &txTtl,
343                         sizeof(txTtl)) < 0) {
344                 pudError(true, "Could not set TTL on the transmit socket"
345                         " for interface %s", networkInterface->name);
346                 goto bail;
347         }
348
349         /* Set the no delay option on the socket */
350         errno = 0;
351         if (fcntl(txSocket, F_SETFL, O_NDELAY) < 0) {
352                 pudError(true, "Could not set the no delay option on the"
353                         " transmit socket for interface %s", networkInterface->name);
354                 goto bail;
355         }
356
357         return txSocket;
358
359         bail: if (txSocket >= 0) {
360                 close(txSocket);
361         }
362         return -1;
363 }
364
365 /**
366  Create a transmit interface and add it to the list of transmit network
367  interface objects
368
369  @param ifName
370  the network interface name
371  @param ipAddr
372  the IP address of the interface
373
374  @return
375  - true on success
376  - false on failure
377  */
378 static bool createTxInterface(const char * ifName, union olsr_sockaddr ipAddr) {
379         unsigned char * hwAddr;
380         int socketFd = -1;
381         TRxTxNetworkInterface * networkInterface = NULL;
382         struct ifreq ifReqHwAddr;
383
384         if (ifName == NULL) {
385                 goto bail;
386         }
387
388         hwAddr = getHardwareAddress(ifName, olsr_cnf->ip_version, &ifReqHwAddr);
389         if (hwAddr == NULL) {
390                 goto bail;
391         }
392
393         networkInterface = olsr_malloc(sizeof(TRxTxNetworkInterface),
394                         "TRxTxNetworkInterface (PUD)");
395         if (networkInterface == NULL) {
396                 goto bail;
397         }
398
399         memcpy(networkInterface->name, ifName, sizeof(networkInterface->name));
400         networkInterface->name[IFNAMSIZ] = '\0';
401         networkInterface->ipAddress = ipAddr;
402         memcpy(&networkInterface->hwAddress[0], hwAddr,
403                         sizeof(networkInterface->hwAddress));
404         networkInterface->next = NULL;
405
406         /* networkInterface needs to be filled in when calling createTxSocket */
407         socketFd = createTxSocket(networkInterface);
408         if (socketFd < 0) {
409                 goto bail;
410         }
411         networkInterface->socketFd = socketFd;
412
413         /* Add new object to the end of the global list. */
414         if (txNetworkInterfacesListHead == NULL) {
415                 txNetworkInterfacesListHead = networkInterface;
416                 lastTxNetworkInterface = networkInterface;
417         } else {
418                 lastTxNetworkInterface->next = networkInterface;
419                 lastTxNetworkInterface = networkInterface;
420         }
421
422         return true;
423
424         bail: if (networkInterface != NULL) {
425                 free(networkInterface);
426         }
427         return false;
428 }
429
430 /*
431  * OLSR interfaces
432  */
433
434 /** The list of OLSR network interface objects */
435 static TOLSRNetworkInterface *olsrNetworkInterfacesListHead = NULL;
436
437 /** Pointer to the last OLSR network interface object */
438 static TOLSRNetworkInterface *lastOlsrNetworkInterface = NULL;
439
440 /**
441  Get the OLSR interface structure for a certain OLSR interface. Note that
442  pointer comparison is performed to compare the OLSR interfaces.
443
444  @param olsrIntf
445  a pointer to an OLSR interface
446
447  @return
448  - a pointer to the OLSR interface structure
449  - NULL when not found
450  */
451 TOLSRNetworkInterface * getOlsrNetworkInterface(struct interface *olsrIntf) {
452         TOLSRNetworkInterface * retval = olsrNetworkInterfacesListHead;
453
454         while ((retval->olsrIntf != olsrIntf) && (retval != NULL)) {
455                 retval = retval->next;
456         }
457
458         return retval;
459 }
460
461 /**
462  Create an OLSR interface and add it to the list of OLSR network interface
463  objects
464
465  @param olsrIntf
466  a pointer to the OLSR interface
467
468  @return
469  - true on success
470  - false on failure
471  */
472 static int createOlsrInterface(struct interface *olsrIntf) {
473         unsigned char * hwAddr;
474         struct ifreq ifReqHwAddr;
475         TOLSRNetworkInterface * networkInterface = NULL;
476
477         hwAddr = getHardwareAddress(olsrIntf->int_name, olsr_cnf->ip_version,
478                         &ifReqHwAddr);
479         if (hwAddr == NULL) {
480                 goto bail;
481         }
482
483         networkInterface = olsr_malloc(sizeof(TOLSRNetworkInterface),
484                         "TOLSRNetworkInterface (PUD)");
485         if (networkInterface == NULL) {
486                 goto bail;
487         }
488
489         networkInterface->olsrIntf = olsrIntf;
490         memcpy(&networkInterface->hwAddress[0], hwAddr,
491                         sizeof(networkInterface->hwAddress));
492         networkInterface->next = NULL;
493
494         /* Add new object to the end of the global list. */
495         if (olsrNetworkInterfacesListHead == NULL) {
496                 olsrNetworkInterfacesListHead = networkInterface;
497                 lastOlsrNetworkInterface = networkInterface;
498         } else {
499                 lastOlsrNetworkInterface->next = networkInterface;
500                 lastOlsrNetworkInterface = networkInterface;
501         }
502
503         return true;
504
505         bail: if (networkInterface != NULL) {
506                 free(networkInterface);
507         }
508         return false;
509 }
510
511 /*
512  * Interface Functions
513  */
514
515 /**
516  Creates receive and transmit sockets and register the receive sockets with
517  the OLSR stack
518
519  @param rxSocketHandlerFunction
520  The function to call upon reception of data on a receive socket
521
522  @return
523  - true on success
524  - false on failure
525  */
526 bool createNetworkInterfaces(socket_handler_func rxSocketHandlerFunction) {
527         int retval = false;
528         struct ifaddrs *ifAddrs = NULL;
529         struct ifaddrs *ifAddr = NULL;
530
531         errno = 0;
532         if (getifaddrs(&ifAddrs) != 0) {
533                 pudError(true, "Could not get list of interfaces and their addresses");
534                 return retval;
535         }
536
537         /* loop over all interfaces */
538         for (ifAddr = ifAddrs; ifAddr != NULL; ifAddr = ifAddr->ifa_next) {
539                 struct sockaddr * addr = ifAddr->ifa_addr;
540                 if (addr != NULL) {
541                         int addrFamily = addr->sa_family;
542                         if (addrFamily == olsr_cnf->ip_version) {
543                                 char * ifName = ifAddr->ifa_name;
544                                 union olsr_sockaddr ipAddr;
545
546                                 /* determine whether the iterated interface is an OLSR
547                                  * interface: returns NULL when the interface is not an
548                                  * OLSR interface */
549                                 struct interface *olsrIntf = if_ifwithname(ifName);
550                                 bool isOlsrIf = (olsrIntf != NULL);
551
552                                 /* determine whether the iterated interface is configured as a
553                                  * non-OLSR interface in the plugin parameter list */
554                                 bool isRxNonOlsrIf = isRxNonOlsrInterface(ifName);
555                                 bool isTxNonOlsrIf = isTxNonOlsrInterface(ifName);
556                                 bool isNonOlsrIf = isRxNonOlsrIf || isTxNonOlsrIf;
557
558                                 if (!isOlsrIf && !isNonOlsrIf) {
559                                         /* Interface is not an OLSR interface AND interface is not
560                                          * configured as non-OLSR interface: skip */
561                                         continue;
562                                 }
563
564                                 if (isOlsrIf && !createOlsrInterface(olsrIntf)) {
565                                         /* creating an OLSR interface failed */
566                                         goto end;
567                                 }
568
569                                 if (!isNonOlsrIf) {
570                                         /* interface is not configured as non-OLSR interface: skip */
571                                         continue;
572                                 }
573
574                                 if (addrFamily == AF_INET) {
575                                         memcpy(&ipAddr.in4, addr, sizeof(struct sockaddr_in));
576                                 } else {
577                                         memcpy(&ipAddr.in6, addr, sizeof(struct sockaddr_in6));
578                                 }
579
580                                 if (isRxNonOlsrIf && !createRxInterface(ifName, ipAddr,
581                                                 rxSocketHandlerFunction)) {
582                                         /* creating a receive interface failed */
583                                         goto end;
584                                 }
585
586                                 if (isTxNonOlsrIf && !createTxInterface(ifName, ipAddr)) {
587                                         /* creating a transmit interface failed */
588                                         goto end;
589                                 }
590                         }
591                 }
592         }
593
594         retval = true;
595
596         end: freeifaddrs(ifAddrs);
597         return retval;
598 }
599
600 /**
601  Cleanup the OLSR network interfaces in the given list
602
603  @param networkInterface
604  the list of network interface to close and clean up
605  */
606 static void cleanupOlsrInterfaces(TOLSRNetworkInterface * networkInterface) {
607         TOLSRNetworkInterface * nextNetworkInterface = networkInterface;
608         while (nextNetworkInterface != NULL) {
609                 TOLSRNetworkInterface * iteratedNetworkInterface = nextNetworkInterface;
610                 nextNetworkInterface = iteratedNetworkInterface->next;
611                 iteratedNetworkInterface->next = NULL;
612                 free(iteratedNetworkInterface);
613         }
614 }
615
616 /**
617  Close and cleanup the network interfaces in the given list
618
619  @param networkInterface
620  the list of network interface to close and clean up
621  */
622 static void closeInterfaces(TRxTxNetworkInterface * networkInterface) {
623         TRxTxNetworkInterface * nextNetworkInterface = networkInterface;
624         while (nextNetworkInterface != NULL) {
625                 TRxTxNetworkInterface * iteratedNetworkInterface = nextNetworkInterface;
626                 if (iteratedNetworkInterface->socketFd >= 0) {
627                         close(iteratedNetworkInterface->socketFd);
628                         iteratedNetworkInterface->socketFd = -1;
629                 }
630                 nextNetworkInterface = iteratedNetworkInterface->next;
631                 iteratedNetworkInterface->next = NULL;
632                 free(iteratedNetworkInterface);
633         }
634 }
635
636 /**
637  Close and cleanup all receive and transmit network interfaces
638  */
639 void closeNetworkInterfaces(void) {
640         if (rxNetworkInterfacesListHead != NULL) {
641                 closeInterfaces(rxNetworkInterfacesListHead);
642                 rxNetworkInterfacesListHead = NULL;
643         }
644
645         if (txNetworkInterfacesListHead != NULL) {
646                 closeInterfaces(txNetworkInterfacesListHead);
647                 txNetworkInterfacesListHead = NULL;
648         }
649
650         if (olsrNetworkInterfacesListHead != NULL) {
651                 cleanupOlsrInterfaces(olsrNetworkInterfacesListHead);
652                 olsrNetworkInterfacesListHead = NULL;
653         }
654 }