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