Update to new avl/list iteration macros
[olsrd.git] / lib / bmf / src / NetworkInterfaces.c
1
2 /*
3  * OLSR Basic Multicast Forwarding (BMF) plugin.
4  * Copyright (c) 2005 - 2007, Thales Communications, Huizen, The Netherlands.
5  * Written by Erik Tromp.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * * Redistributions of source code must retain the above copyright
13  *   notice, this list of conditions and the following disclaimer.
14  * * Redistributions in binary form must reproduce the above copyright
15  *   notice, this list of conditions and the following disclaimer in
16  *   the documentation and/or other materials provided with the
17  *   distribution.
18  * * Neither the name of Thales, BMF nor the names of its
19  *   contributors may be used to endorse or promote products derived
20  *   from this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
24  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25  * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
26  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
29  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
30  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
31  * OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33
34 /* -------------------------------------------------------------------------
35  * File       : NetworkInterfaces.c
36  * Description: Functions to open and close sockets
37  * Created    : 29 Jun 2006
38  *
39  * ------------------------------------------------------------------------- */
40
41 #include "NetworkInterfaces.h"
42
43 /* System includes */
44 #include <stddef.h>             /* NULL */
45 #include <syslog.h>             /* syslog() */
46 #include <string.h>             /* strerror(), strchr(), strcmp() */
47 #include <errno.h>              /* errno */
48 #include <unistd.h>             /* close() */
49 #include <sys/ioctl.h>          /* ioctl() */
50 #include <fcntl.h>              /* fcntl() */
51 #include <assert.h>             /* assert() */
52 #include <net/if.h>             /* socket(), ifreq, if_indextoname(), if_nametoindex() */
53 #include <netinet/in.h>         /* htons() */
54 #include <linux/if_ether.h>     /* ETH_P_IP */
55 #include <linux/if_packet.h>    /* packet_mreq, PACKET_MR_PROMISC, PACKET_ADD_MEMBERSHIP */
56 #include <linux/if_tun.h>       /* IFF_TAP */
57 #include <netinet/ip.h>         /* struct ip */
58 #include <netinet/udp.h>        /* SOL_UDP */
59 #include <stdlib.h>             /* atoi, malloc */
60
61 /* OLSRD includes */
62 #include "olsr.h"
63 #include "ipcalc.h"
64 #include "defs.h"               /* olsr_cnf */
65 #include "link_set.h"           /* get_link_set() */
66 #include "tc_set.h"             /* olsr_lookup_tc_entry(), olsr_lookup_tc_edge() */
67 #include "net_olsr.h"           /* ipequal */
68 #include "lq_plugin.h"
69 #include "olsr_ip_prefix_list.h"
70 #include "olsr_logging.h"
71
72 /* Plugin includes */
73 #include "Packet.h"             /* IFHWADDRLEN */
74 #include "Bmf.h"                /* PLUGIN_NAME, MainAddressOf() */
75 #include "Address.h"            /* IsMulticast() */
76
77 /* List of network interface objects used by BMF plugin */
78 struct TBmfInterface *BmfInterfaces = NULL;
79 struct TBmfInterface *LastBmfInterface = NULL;
80
81 /* Highest-numbered open socket file descriptor. To be used as first
82  * parameter in calls to select(...). */
83 int HighestSkfd = -1;
84
85 /* Set of socket file descriptors */
86 fd_set InputSet;
87
88 /* File descriptor of EtherTunTap interface */
89 int EtherTunTapFd = -1;
90
91 /* Network interface name of EtherTunTap interface. May be overruled by
92  * setting the plugin parameter "BmfInterface". */
93 char EtherTunTapIfName[IFNAMSIZ] = "bmf0";
94
95 /* The underlying mechanism to forward multicast packets. Either:
96  * - BM_BROADCAST: BMF uses the IP local broadcast as destination address
97  * - BM_UNICAST_PROMISCUOUS: BMF uses the IP address of the best neighbor as
98  *   destination address. The other neighbors listen promiscuously. */
99 enum TBmfMechanism BmfMechanism = BM_BROADCAST;
100
101 #define ETHERTUNTAPIPNOTSET 0
102
103 /* The IP address of the BMF network interface in host byte order.
104  * May be overruled by setting the plugin parameter "BmfInterfaceIp". */
105 u_int32_t EtherTunTapIp = ETHERTUNTAPIPNOTSET;
106
107 /* 255.255.255.255 in host byte order. May be overruled by
108  * setting the plugin parameter "BmfInterfaceIp". */
109 u_int32_t EtherTunTapIpMask = 0xFFFFFFFF;
110
111 /* The IP broadcast address of the BMF network interface in host byte order.
112  * May be overruled by setting the plugin parameter "BmfinterfaceIp". */
113 u_int32_t EtherTunTapIpBroadcast = ETHERTUNTAPIPNOTSET;
114
115 /* Whether or not the configuration has overruled the default IP
116  * configuration of the EtherTunTap interface */
117 int TunTapIpOverruled = 0;
118
119 /* Whether or not to capture packets on the OLSR-enabled
120  * interfaces (in promiscuous mode). May be overruled by setting the plugin
121  * parameter "CapturePacketsOnOlsrInterfaces" to "yes". */
122 int CapturePacketsOnOlsrInterfaces = 0;
123
124 /* -------------------------------------------------------------------------
125  * Function   : SetBmfInterfaceName
126  * Description: Overrule the default network interface name ("bmf0") of the
127  *              EtherTunTap interface
128  * Input      : ifname - network interface name (e.g. "mybmf0")
129  *              data - not used
130  *              addon - not used
131  * Output     : none
132  * Return     : success (0) or fail (1)
133  * Data Used  : EtherTunTapIfName
134  * ------------------------------------------------------------------------- */
135 int
136 SetBmfInterfaceName(const char *ifname,
137                     void *data __attribute__ ((unused)), set_plugin_parameter_addon addon __attribute__ ((unused)))
138 {
139   strncpy(EtherTunTapIfName, ifname, IFNAMSIZ - 1);
140   EtherTunTapIfName[IFNAMSIZ - 1] = '\0';       /* Ensures null termination */
141   return 0;
142 }                               /* SetBmfInterfaceName */
143
144 /* -------------------------------------------------------------------------
145  * Function   : SetBmfInterfaceIp
146  * Description: Overrule the default IP address and prefix length
147  *              ("10.255.255.253/30") of the EtherTunTap interface
148  * Input      : ip - IP address string, followed by '/' and prefix length
149  *              data - not used
150  *              addon - not used
151  * Output     : none
152  * Return     : success (0) or fail (1)
153  * Data Used  : EtherTunTapIp, EtherTunTapIpMask, EtherTunTapIpBroadcast,
154  *              TunTapIpOverruled
155  * ------------------------------------------------------------------------- */
156 int
157 SetBmfInterfaceIp(const char *ip, void *data __attribute__ ((unused)), set_plugin_parameter_addon addon __attribute__ ((unused)))
158 {
159 #define IPV4_MAX_ADDRLEN 16
160 #define IPV4_MAX_PREFIXLEN 32
161   char *slashAt;
162   char ipAddr[IPV4_MAX_ADDRLEN];
163   struct in_addr sinaddr;
164   int prefixLen;
165   int i;
166
167   /* Inspired by function str2prefix_ipv4 as found in Quagga source
168    * file lib/prefix.c */
169
170   /* Find slash inside string. */
171   slashAt = strchr(ip, '/');
172
173   /* String doesn't contain slash. */
174   if (slashAt == NULL || slashAt - ip >= IPV4_MAX_ADDRLEN) {
175     /* No prefix length specified, or IP address too long */
176     return 1;
177   }
178
179   strncpy(ipAddr, ip, slashAt - ip);
180   *(ipAddr + (slashAt - ip)) = '\0';
181   if (inet_aton(ipAddr, &sinaddr) == 0) {
182     /* Invalid address passed */
183     return 1;
184   }
185
186   EtherTunTapIp = ntohl(sinaddr.s_addr);
187
188   /* Get prefix length. */
189   prefixLen = atoi(++slashAt);
190   if (prefixLen <= 0 || prefixLen > IPV4_MAX_PREFIXLEN) {
191     return 1;
192   }
193
194   /* Compose IP subnet mask in host byte order */
195   EtherTunTapIpMask = 0;
196   for (i = 0; i < prefixLen; i++) {
197     EtherTunTapIpMask |= (1 << (IPV4_MAX_PREFIXLEN - 1 - i));
198   }
199
200   /* Compose IP broadcast address in host byte order */
201   EtherTunTapIpBroadcast = EtherTunTapIp;
202   for (i = prefixLen; i < IPV4_MAX_PREFIXLEN; i++) {
203     EtherTunTapIpBroadcast |= (1 << (IPV4_MAX_PREFIXLEN - 1 - i));
204   }
205
206   TunTapIpOverruled = 1;
207
208   return 0;
209 }                               /* SetBmfInterfaceIp */
210
211 /* -------------------------------------------------------------------------
212  * Function   : SetCapturePacketsOnOlsrInterfaces
213  * Description: Overrule the default setting, enabling or disabling the
214  *              capturing of packets on OLSR-enabled interfaces.
215  * Input      : enable - either "yes" or "no"
216  *              data - not used
217  *              addon - not used
218  * Output     : none
219  * Return     : success (0) or fail (1)
220  * Data Used  : none
221  * ------------------------------------------------------------------------- */
222 int
223 SetCapturePacketsOnOlsrInterfaces(const char *enable,
224                                   void *data __attribute__ ((unused)), set_plugin_parameter_addon addon __attribute__ ((unused)))
225 {
226   if (strcmp(enable, "yes") == 0) {
227     CapturePacketsOnOlsrInterfaces = 1;
228     return 0;
229   } else if (strcmp(enable, "no") == 0) {
230     CapturePacketsOnOlsrInterfaces = 0;
231     return 0;
232   }
233
234   /* Value not recognized */
235   return 1;
236 }                               /* SetCapturePacketsOnOlsrInterfaces */
237
238 /* -------------------------------------------------------------------------
239  * Function   : SetBmfMechanism
240  * Description: Overrule the default BMF mechanism to either BM_BROADCAST or
241  *              BM_UNICAST_PROMISCUOUS.
242  * Input      : mechanism - either "Broadcast" or "UnicastPromiscuous"
243  *              data - not used
244  *              addon - not used
245  * Output     : none
246  * Return     : success (0) or fail (1)
247  * Data Used  : none
248  * ------------------------------------------------------------------------- */
249 int
250 SetBmfMechanism(const char *mechanism,
251                 void *data __attribute__ ((unused)), set_plugin_parameter_addon addon __attribute__ ((unused)))
252 {
253   if (strcmp(mechanism, "Broadcast") == 0) {
254     BmfMechanism = BM_BROADCAST;
255     return 0;
256   } else if (strcmp(mechanism, "UnicastPromiscuous") == 0) {
257     BmfMechanism = BM_UNICAST_PROMISCUOUS;
258     return 0;
259   }
260
261   /* Value not recognized */
262   return 1;
263 }                               /* SetBmfMechanism */
264
265 /* -------------------------------------------------------------------------
266  * Function   : AddDescriptorToInputSet
267  * Description: Add a socket descriptor to the global set of socket file descriptors
268  * Input      : skfd - socket file descriptor
269  * Output     : none
270  * Return     : none
271  * Data Used  : HighestSkfd, InputSet
272  * Notes      : Keeps track of the highest-numbered descriptor
273  * ------------------------------------------------------------------------- */
274 static void
275 AddDescriptorToInputSet(int skfd)
276 {
277   /* Keep the highest-numbered descriptor */
278   if (skfd > HighestSkfd) {
279     HighestSkfd = skfd;
280   }
281
282   /* Add descriptor to input set */
283   FD_SET(skfd, &InputSet);
284 }                               /* AddDescriptorToInputSet */
285
286 /* To save the state of the IP spoof filter for the EtherTunTap interface */
287 static char EthTapSpoofState = '1';
288
289 /* -------------------------------------------------------------------------
290  * Function   : DeactivateSpoofFilter
291  * Description: Deactivates the Linux anti-spoofing filter for the tuntap
292  *              interface
293  * Input      : none
294  * Output     : none
295  * Return     : fail (0) or success (1)
296  * Data Used  : EtherTunTapIfName, EthTapSpoofState
297  * Notes      : Saves the current filter state for later restoring
298  * ------------------------------------------------------------------------- */
299 int
300 DeactivateSpoofFilter(void)
301 {
302   FILE *procSpoof;
303   char procFile[FILENAME_MAX];
304
305   /* Generate the procfile name */
306   sprintf(procFile, "/proc/sys/net/ipv4/conf/%s/rp_filter", EtherTunTapIfName);
307
308   /* Open procfile for reading */
309   procSpoof = fopen(procFile, "r");
310   if (procSpoof == NULL) {
311     OLSR_WARN(LOG_PLUGINS,
312               "WARNING! Could not open the %s file to check/disable the IP spoof filter!\n"
313               "Are you using the procfile filesystem?\n"
314               "Does your system support IPv4?\n"
315               "I will continue (in 3 sec) - but you should manually ensure that IP spoof\n" "filtering is disabled!\n\n", procFile);
316
317     sleep(3);
318     return 0;
319   }
320
321   EthTapSpoofState = fgetc(procSpoof);
322   fclose(procSpoof);
323
324   /* Open procfile for writing */
325   procSpoof = fopen(procFile, "w");
326   if (procSpoof == NULL) {
327     OLSR_WARN(LOG_PLUGINS, "Could not open %s for writing!\n"
328               "I will continue (in 3 sec) - but you should manually ensure that IP" " spoof filtering is disabled!\n\n", procFile);
329     sleep(3);
330     return 0;
331   }
332
333   fputs("0", procSpoof);
334
335   fclose(procSpoof);
336
337   return 1;
338 }                               /* DeactivateSpoofFilter */
339
340 /* -------------------------------------------------------------------------
341  * Function   : RestoreSpoofFilter
342  * Description: Restores the Linux anti-spoofing filter setting for the tuntap
343  *              interface
344  * Input      : none
345  * Output     : none
346  * Return     : none
347  * Data Used  : EtherTunTapIfName, EthTapSpoofState
348  * ------------------------------------------------------------------------- */
349 void
350 RestoreSpoofFilter(void)
351 {
352   FILE *procSpoof;
353   char procFile[FILENAME_MAX];
354
355   /* Generate the procfile name */
356   sprintf(procFile, "/proc/sys/net/ipv4/conf/%s/rp_filter", EtherTunTapIfName);
357
358   /* Open procfile for writing */
359   procSpoof = fopen(procFile, "w");
360   if (procSpoof == NULL) {
361     OLSR_WARN(LOG_PLUGINS, "Could not open %s for writing!\nSettings not restored!\n", procFile);
362   } else {
363     fputc(EthTapSpoofState, procSpoof);
364     fclose(procSpoof);
365   }
366 }                               /* RestoreSpoofFilter */
367
368 /* -------------------------------------------------------------------------
369  * Function   : FindNeighbors
370  * Description: Find the neighbors on a network interface to forward a BMF
371  *              packet to
372  * Input      : intf - the network interface
373  *              source - the source IP address of the BMF packet
374  *              forwardedBy - the IP address of the node that forwarded the BMF
375  *                packet
376  *              forwardedTo - the IP address of the node to which the BMF packet
377  *                was directed
378  * Output     : neighbors - list of (up to a number of 'FanOutLimit') neighbors.
379  *              bestNeighbor - the best neighbor (in terms of lowest cost or ETX
380  *                value)
381  *              nPossibleNeighbors - number of found possible neighbors
382  * Data Used  : FanOutLimit
383  * ------------------------------------------------------------------------- */
384 void
385 FindNeighbors(struct TBestNeighbors *neighbors,
386               struct link_entry **bestNeighbor,
387               struct TBmfInterface *intf,
388               union olsr_ip_addr *source, union olsr_ip_addr *forwardedBy, union olsr_ip_addr *forwardedTo, int *nPossibleNeighbors)
389 {
390   struct link_entry *walker, *iterator;
391   olsr_linkcost previousLinkEtx = LINK_COST_BROKEN;
392   olsr_linkcost bestEtx = LINK_COST_BROKEN;
393
394   int i;
395
396   /* Initialize */
397   *bestNeighbor = NULL;
398   for (i = 0; i < MAX_UNICAST_NEIGHBORS; i++) {
399     neighbors->links[i] = NULL;
400   }
401   *nPossibleNeighbors = 0;
402
403   if (forwardedBy != NULL) {
404     /* Retrieve the cost of the link from 'forwardedBy' to myself */
405     struct link_entry *bestLinkFromForwarder = get_best_link_to_neighbor_ip(forwardedBy);
406     if (bestLinkFromForwarder != NULL) {
407       previousLinkEtx = bestLinkFromForwarder->linkcost;
408     }
409   }
410
411   OLSR_FOR_ALL_LINK_ENTRIES(walker, iterator) {
412 #if !defined REMOVE_LOG_DEBUG
413     struct ipaddr_str buf;
414 #endif
415     union olsr_ip_addr *neighborMainIp;
416     struct link_entry *bestLinkToNeighbor;
417     struct tc_entry *tcLastHop;
418     float currEtx;
419
420     /* Consider only links from the specified interface */
421     if (olsr_ipcmp(&intf->intAddr, &walker->local_iface_addr) != 0) {
422       continue;                 /* for */
423     }
424
425     OLSR_DEBUG(LOG_PLUGINS,
426                "Considering forwarding pkt on \"%s\" to %s\n", intf->ifName, olsr_ip_to_string(&buf, &walker->neighbor_iface_addr));
427
428     neighborMainIp = MainAddressOf(&walker->neighbor_iface_addr);
429
430     /* Consider only neighbors with an IP address that differs from the
431      * passed IP addresses (if passed). Rely on short-circuit boolean evaluation. */
432     if (source != NULL && olsr_ipcmp(neighborMainIp, MainAddressOf(source)) == 0) {
433       OLSR_DEBUG(LOG_PLUGINS, "Not forwarding to %s: is source of pkt\n", olsr_ip_to_string(&buf, &walker->neighbor_iface_addr));
434
435       continue;                 /* for */
436     }
437
438     /* Rely on short-circuit boolean evaluation */
439     if (forwardedBy != NULL && olsr_ipcmp(neighborMainIp, MainAddressOf(forwardedBy)) == 0) {
440       OLSR_DEBUG(LOG_PLUGINS,
441                  "Not forwarding to %s: is the node that forwarded the pkt\n",
442                  olsr_ip_to_string(&buf, &walker->neighbor_iface_addr));
443
444       continue;                 /* for */
445     }
446
447     /* Rely on short-circuit boolean evaluation */
448     if (forwardedTo != NULL && olsr_ipcmp(neighborMainIp, MainAddressOf(forwardedTo)) == 0) {
449       OLSR_DEBUG(LOG_PLUGINS,
450                  "Not forwarding to %s: is the node to which the pkt was forwarded\n",
451                  olsr_ip_to_string(&buf, &walker->neighbor_iface_addr));
452
453       continue;                 /* for */
454     }
455
456     /* Found a candidate neighbor to direct our packet to */
457
458     /* Calculate the link quality (ETX) of the link to the found neighbor */
459     currEtx = walker->linkcost;
460
461     if (currEtx >= LINK_COST_BROKEN) {
462       OLSR_DEBUG(LOG_PLUGINS, "Not forwarding to %s: link is timing out\n", olsr_ip_to_string(&buf, &walker->neighbor_iface_addr));
463
464       continue;                 /* for */
465     }
466
467     /* Compare costs to check if the candidate neighbor is best reached via 'intf' */
468     OLSR_DEBUG(LOG_PLUGINS,
469                "Forwarding pkt to %s will cost ETX %5.2f\n", olsr_ip_to_string(&buf, &walker->neighbor_iface_addr), currEtx);
470
471     /*
472      * If the candidate neighbor is best reached via another interface, then skip
473      * the candidate neighbor; the candidate neighbor has been / will be selected via that
474      * other interface.
475      */
476     bestLinkToNeighbor = get_best_link_to_neighbor_ip(&walker->neighbor_iface_addr);
477
478     if (walker != bestLinkToNeighbor) {
479       if (bestLinkToNeighbor == NULL) {
480         OLSR_DEBUG(LOG_PLUGINS, "Not forwarding to %s: no link found\n", olsr_ip_to_string(&buf, &walker->neighbor_iface_addr));
481       } else {
482 #if !defined REMOVE_LOG_DEBUG
483         struct interface *bestIntf = if_ifwithaddr(&bestLinkToNeighbor->local_iface_addr);
484         char lqbuffer[LQTEXT_MAXLENGTH];
485 #endif
486         OLSR_DEBUG(LOG_PLUGINS,
487                    "Not forwarding to %s: \"%s\" gives a better link to this neighbor, costing %s\n",
488                    olsr_ip_to_string(&buf, &walker->neighbor_iface_addr),
489                    bestIntf->int_name,
490                    olsr_get_linkcost_text(bestLinkToNeighbor->linkcost, false, lqbuffer, sizeof(lqbuffer)));
491       }
492
493       continue;                 /* for */
494     }
495
496     if (forwardedBy != NULL) {
497 #if !defined REMOVE_LOG_DEBUG
498       struct ipaddr_str forwardedByBuf, niaBuf;
499       char lqbuffer[LQTEXT_MAXLENGTH];
500 #endif
501       OLSR_DEBUG(LOG_PLUGINS,
502                  "2-hop path from %s via me to %s will cost ETX %s\n",
503                  olsr_ip_to_string(&forwardedByBuf, forwardedBy),
504                  olsr_ip_to_string(&niaBuf, &walker->neighbor_iface_addr),
505                  olsr_get_linkcost_text(previousLinkEtx + currEtx, true, lqbuffer, sizeof(lqbuffer)));
506     }
507
508     /* Check the topology table whether the 'forwardedBy' node is itself a direct
509      * neighbor of the candidate neighbor, at a lower cost than the 2-hop route
510      * via myself. If so, we do not need to forward the BMF packet to the candidate
511      * neighbor, because the 'forwardedBy' node will forward the packet. */
512     if (forwardedBy != NULL) {
513       tcLastHop = olsr_lookup_tc_entry(MainAddressOf(forwardedBy));
514       if (tcLastHop != NULL) {
515         struct tc_edge_entry *tc_edge;
516
517         tc_edge = olsr_lookup_tc_edge(tcLastHop, MainAddressOf(&walker->neighbor_iface_addr));
518
519         /* We are not interested in dead-end edges. */
520         if (tc_edge) {
521           olsr_linkcost tcEtx = tc_edge->cost;
522
523           if (previousLinkEtx + currEtx > tcEtx) {
524 #if !defined REMOVE_LOG_DEBUG
525             struct ipaddr_str neighbor_iface_buf, forw_buf;
526             char lqbuffer[LQTEXT_MAXLENGTH];
527             olsr_ip_to_string(&neighbor_iface_buf, &walker->neighbor_iface_addr);
528 #endif
529             OLSR_DEBUG(LOG_PLUGINS,
530                        "Not forwarding to %s: I am not an MPR between %s and %s, direct link costs %s\n",
531                        neighbor_iface_buf.buf,
532                        olsr_ip_to_string(&forw_buf, forwardedBy),
533                        neighbor_iface_buf.buf,
534                        olsr_get_linkcost_text(tcEtx, false, lqbuffer, sizeof(lqbuffer)));
535
536             continue;           /* for */
537           }                     /* if */
538         }                       /* if */
539       }                         /* if */
540     }
541
542     /* if */
543     /* Remember the best neighbor. If all are very bad, remember none. */
544     if (currEtx < bestEtx) {
545       *bestNeighbor = walker;
546       bestEtx = currEtx;
547     }
548
549     /* Fill the list with up to 'FanOutLimit' neighbors. If there
550      * are more neighbors, broadcast is used instead of unicast. In that
551      * case we do not need the list of neighbors. */
552     if (*nPossibleNeighbors < FanOutLimit) {
553       neighbors->links[*nPossibleNeighbors] = walker;
554     }
555
556     *nPossibleNeighbors += 1;
557   }
558
559   /* Display the result of the neighbor search */
560   if (*nPossibleNeighbors == 0) {
561     OLSR_DEBUG(LOG_PLUGINS, "No suitable neighbor found to forward to on \"%s\"\n", intf->ifName);
562   } else {
563 #if !defined REMOVE_LOG_DEBUG
564     struct ipaddr_str buf;
565 #endif
566     OLSR_DEBUG(LOG_PLUGINS,
567                "%d neighbors found on \"%s\"; best neighbor to forward to: %s\n",
568                *nPossibleNeighbors, intf->ifName, olsr_ip_to_string(&buf, &(*bestNeighbor)->neighbor_iface_addr));
569   }                             /* if */
570
571 }                               /* FindNeighbors */
572
573 /* -------------------------------------------------------------------------
574  * Function   : CreateCaptureSocket
575  * Description: Create socket for promiscuously capturing multicast IP traffic
576  * Input      : ifname - network interface (e.g. "eth0")
577  * Output     : none
578  * Return     : the socket descriptor ( >= 0), or -1 if an error occurred
579  * Data Used  : none
580  * Notes      : The socket is a cooked IP packet socket, bound to the specified
581  *              network interface
582  * ------------------------------------------------------------------------- */
583 static int
584 CreateCaptureSocket(const char *ifName)
585 {
586   int ifIndex = if_nametoindex(ifName);
587   struct packet_mreq mreq;
588   struct ifreq req;
589   struct sockaddr_ll bindTo;
590
591   /* Open cooked IP packet socket */
592   int skfd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP));
593   if (skfd < 0) {
594     OLSR_WARN(LOG_PLUGINS, "socket(PF_PACKET) error");
595     return -1;
596   }
597
598   /* Set interface to promiscuous mode */
599   memset(&mreq, 0, sizeof(struct packet_mreq));
600   mreq.mr_ifindex = ifIndex;
601   mreq.mr_type = PACKET_MR_PROMISC;
602   if (setsockopt(skfd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) {
603     OLSR_WARN(LOG_PLUGINS, "setsockopt(PACKET_MR_PROMISC) error");
604     close(skfd);
605     return -1;
606   }
607
608   /* Get hardware (MAC) address */
609   memset(&req, 0, sizeof(struct ifreq));
610   strncpy(req.ifr_name, ifName, IFNAMSIZ - 1);
611   req.ifr_name[IFNAMSIZ - 1] = '\0';    /* Ensures null termination */
612   if (ioctl(skfd, SIOCGIFHWADDR, &req) < 0) {
613     OLSR_WARN(LOG_PLUGINS, "error retrieving MAC address");
614     close(skfd);
615     return -1;
616   }
617
618   /* Bind the socket to the specified interface */
619   memset(&bindTo, 0, sizeof(bindTo));
620   bindTo.sll_family = AF_PACKET;
621   bindTo.sll_protocol = htons(ETH_P_IP);
622   bindTo.sll_ifindex = ifIndex;
623   memcpy(bindTo.sll_addr, req.ifr_hwaddr.sa_data, IFHWADDRLEN);
624   bindTo.sll_halen = IFHWADDRLEN;
625
626   if (bind(skfd, (struct sockaddr *)&bindTo, sizeof(bindTo)) < 0) {
627     OLSR_WARN(LOG_PLUGINS, "bind() error");
628     close(skfd);
629     return -1;
630   }
631
632   /* Set socket to blocking operation */
633   if (fcntl(skfd, F_SETFL, fcntl(skfd, F_GETFL, 0) & ~O_NONBLOCK) < 0) {
634     OLSR_WARN(LOG_PLUGINS, "fcntl() error");
635     close(skfd);
636     return -1;
637   }
638
639   AddDescriptorToInputSet(skfd);
640
641   return skfd;
642 }                               /* CreateCaptureSocket */
643
644 /* -------------------------------------------------------------------------
645  * Function   : CreateListeningSocket
646  * Description: Create socket for promiscuously listening to BMF packets.
647  *              Used only when 'BmfMechanism' is BM_UNICAST_PROMISCUOUS
648  * Input      : ifname - network interface (e.g. "eth0")
649  * Output     : none
650  * Return     : the socket descriptor ( >= 0), or -1 if an error occurred
651  * Data Used  : none
652  * Notes      : The socket is a cooked IP packet socket, bound to the specified
653  *              network interface
654  * ------------------------------------------------------------------------- */
655 static int
656 CreateListeningSocket(const char *ifName)
657 {
658   int ifIndex = if_nametoindex(ifName);
659   struct packet_mreq mreq;
660   struct ifreq req;
661   struct sockaddr_ll bindTo;
662
663   /* Open cooked IP packet socket */
664   int skfd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP));
665   if (skfd < 0) {
666     OLSR_WARN(LOG_PLUGINS, "socket(PF_PACKET) error");
667     return -1;
668   }
669
670   /* Set interface to promiscuous mode */
671   memset(&mreq, 0, sizeof(struct packet_mreq));
672   mreq.mr_ifindex = ifIndex;
673   mreq.mr_type = PACKET_MR_PROMISC;
674   if (setsockopt(skfd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) {
675     OLSR_WARN(LOG_PLUGINS, "setsockopt(PACKET_MR_PROMISC) error");
676     close(skfd);
677     return -1;
678   }
679
680   /* Get hardware (MAC) address */
681   memset(&req, 0, sizeof(struct ifreq));
682   strncpy(req.ifr_name, ifName, IFNAMSIZ - 1);
683   req.ifr_name[IFNAMSIZ - 1] = '\0';    /* Ensures null termination */
684   if (ioctl(skfd, SIOCGIFHWADDR, &req) < 0) {
685     OLSR_WARN(LOG_PLUGINS, "error retrieving MAC address");
686     close(skfd);
687     return -1;
688   }
689
690   /* Bind the socket to the specified interface */
691   memset(&bindTo, 0, sizeof(bindTo));
692   bindTo.sll_family = AF_PACKET;
693   bindTo.sll_protocol = htons(ETH_P_IP);
694   bindTo.sll_ifindex = ifIndex;
695   memcpy(bindTo.sll_addr, req.ifr_hwaddr.sa_data, IFHWADDRLEN);
696   bindTo.sll_halen = IFHWADDRLEN;
697
698   if (bind(skfd, (struct sockaddr *)&bindTo, sizeof(bindTo)) < 0) {
699     OLSR_WARN(LOG_PLUGINS, "bind() error");
700     close(skfd);
701     return -1;
702   }
703
704   /* Set socket to blocking operation */
705   if (fcntl(skfd, F_SETFL, fcntl(skfd, F_GETFL, 0) & ~O_NONBLOCK) < 0) {
706     OLSR_WARN(LOG_PLUGINS, "fcntl() error");
707     close(skfd);
708     return -1;
709   }
710
711   AddDescriptorToInputSet(skfd);
712
713   return skfd;
714 }                               /* CreateListeningSocket */
715
716 /* -------------------------------------------------------------------------
717  * Function   : CreateEncapsulateSocket
718  * Description: Create a socket for sending and receiving encapsulated
719  *              multicast packets
720  * Input      : ifname - network interface (e.g. "eth0")
721  * Output     : none
722  * Return     : the socket descriptor ( >= 0), or -1 if an error occurred
723  * Data Used  : none
724  * Notes      : The socket is an UDP (datagram) over IP socket, bound to the
725  *              specified network interface
726  * ------------------------------------------------------------------------- */
727 static int
728 CreateEncapsulateSocket(const char *ifName)
729 {
730   int on = 1;
731   struct sockaddr_in bindTo;
732
733   /* Open UDP-IP socket */
734   int skfd = socket(PF_INET, SOCK_DGRAM, 0);
735   if (skfd < 0) {
736     OLSR_WARN(LOG_PLUGINS, "socket(PF_INET) error");
737     return -1;
738   }
739
740   /* Enable sending to broadcast addresses */
741   if (setsockopt(skfd, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)) < 0) {
742     OLSR_WARN(LOG_PLUGINS, "setsockopt(SO_BROADCAST) error");
743     close(skfd);
744     return -1;
745   }
746
747   /* Bind to the specific network interfaces indicated by ifName. */
748   /* When using Kernel 2.6 this must happer prior to the port binding! */
749   if (setsockopt(skfd, SOL_SOCKET, SO_BINDTODEVICE, ifName, strlen(ifName) + 1) < 0) {
750     OLSR_WARN(LOG_PLUGINS, "setsockopt(SO_BINDTODEVICE) error");
751     close(skfd);
752     return -1;
753   }
754
755   /* Bind to BMF port */
756   memset(&bindTo, 0, sizeof(bindTo));
757   bindTo.sin_family = AF_INET;
758   bindTo.sin_port = htons(BMF_ENCAP_PORT);
759   bindTo.sin_addr.s_addr = htonl(INADDR_ANY);
760
761   if (bind(skfd, (struct sockaddr *)&bindTo, sizeof(bindTo)) < 0) {
762     OLSR_WARN(LOG_PLUGINS, "bind() error");
763     close(skfd);
764     return -1;
765   }
766
767   /* Set socket to blocking operation */
768   if (fcntl(skfd, F_SETFL, fcntl(skfd, F_GETFL, 0) & ~O_NONBLOCK) < 0) {
769     OLSR_WARN(LOG_PLUGINS, "fcntl() error");
770     close(skfd);
771     return -1;
772   }
773
774   AddDescriptorToInputSet(skfd);
775
776   return skfd;
777 }                               /* CreateEncapsulateSocket */
778
779 /* -------------------------------------------------------------------------
780  * Function   : CreateLocalEtherTunTap
781  * Description: Creates and brings up an EtherTunTap interface
782  * Input      : none
783  * Output     : none
784  * Return     : the socket file descriptor (>= 0), or -1 in case of failure
785  * Data Used  : EtherTunTapIfName - name used for the tuntap interface (e.g.
786  *                "bmf0")
787  *              EtherTunTapIp
788  *              EtherTunTapIpMask
789  *              EtherTunTapIpBroadcast
790  *              BmfInterfaces
791  * Note       : Order dependency: call this function only if BmfInterfaces
792  *              is filled with a list of network interfaces.
793  * ------------------------------------------------------------------------- */
794 static int
795 CreateLocalEtherTunTap(void)
796 {
797   static const char deviceName[] = "/dev/net/tun";
798   struct ifreq ifreq;
799   int etfd;
800   int ioctlSkfd;
801   int ioctlres;
802
803   etfd = open(deviceName, O_RDWR | O_NONBLOCK);
804   if (etfd < 0) {
805     OLSR_WARN(LOG_PLUGINS, "error opening %s", deviceName);
806     return -1;
807   }
808
809   memset(&ifreq, 0, sizeof(ifreq));
810   strncpy(ifreq.ifr_name, EtherTunTapIfName, IFNAMSIZ - 1);
811   ifreq.ifr_name[IFNAMSIZ - 1] = '\0';  /* Ensures null termination */
812
813   /* Specify the IFF_TUN flag for IP packets.
814    * Specify IFF_NO_PI for not receiving extra meta packet information. */
815   ifreq.ifr_flags = IFF_TUN;
816   ifreq.ifr_flags |= IFF_NO_PI;
817
818   if (ioctl(etfd, TUNSETIFF, (void *)&ifreq) < 0) {
819     OLSR_WARN(LOG_PLUGINS, "ioctl(TUNSETIFF) error on %s", deviceName);
820     close(etfd);
821     return -1;
822   }
823
824   memset(&ifreq, 0, sizeof(ifreq));
825   strncpy(ifreq.ifr_name, EtherTunTapIfName, IFNAMSIZ - 1);
826   ifreq.ifr_name[IFNAMSIZ - 1] = '\0';  /* Ensures null termination */
827   ifreq.ifr_addr.sa_family = AF_INET;
828
829   ioctlSkfd = socket(PF_INET, SOCK_DGRAM, 0);
830   if (ioctlSkfd < 0) {
831     OLSR_WARN(LOG_PLUGINS, "socket(PF_INET) error on %s", deviceName);
832     close(etfd);
833     return -1;
834   }
835
836   /* Give the EtherTunTap interface an IP address.
837    * The default IP address is the address of the first OLSR interface;
838    * the default netmask is 255.255.255.255 . Having an all-ones netmask prevents
839    * automatic entry of the BMF network interface in the routing table. */
840   if (EtherTunTapIp == ETHERTUNTAPIPNOTSET) {
841     struct TBmfInterface *nextBmfIf = BmfInterfaces;
842     while (nextBmfIf != NULL) {
843       struct TBmfInterface *bmfIf = nextBmfIf;
844       nextBmfIf = bmfIf->next;
845
846       if (bmfIf->olsrIntf != NULL) {
847         EtherTunTapIp = ntohl(bmfIf->intAddr.v4.s_addr);
848         EtherTunTapIpBroadcast = EtherTunTapIp;
849       }
850     }
851   }
852
853   if (EtherTunTapIp == ETHERTUNTAPIPNOTSET) {
854     /* No IP address configured for BMF network interface, and no OLSR interface found to
855      * copy IP address from. Fall back to default: 10.255.255.253 . */
856     EtherTunTapIp = ETHERTUNTAPDEFAULTIP;
857   }
858
859   ((struct sockaddr_in *)(ARM_NOWARN_ALIGN(&ifreq.ifr_addr)))->sin_addr.s_addr = htonl(EtherTunTapIp);
860   ioctlres = ioctl(ioctlSkfd, SIOCSIFADDR, &ifreq);
861   if (ioctlres >= 0) {
862     /* Set net mask */
863     ((struct sockaddr_in *)(ARM_NOWARN_ALIGN(&ifreq.ifr_netmask)))->sin_addr.s_addr = htonl(EtherTunTapIpMask);
864     ioctlres = ioctl(ioctlSkfd, SIOCSIFNETMASK, &ifreq);
865     if (ioctlres >= 0) {
866       /* Set broadcast IP */
867       ((struct sockaddr_in *)(ARM_NOWARN_ALIGN(&ifreq.ifr_broadaddr)))->sin_addr.s_addr = htonl(EtherTunTapIpBroadcast);
868       ioctlres = ioctl(ioctlSkfd, SIOCSIFBRDADDR, &ifreq);
869       if (ioctlres >= 0) {
870         /* Bring EtherTunTap interface up (if not already) */
871         ioctlres = ioctl(ioctlSkfd, SIOCGIFFLAGS, &ifreq);
872         if (ioctlres >= 0) {
873           ifreq.ifr_flags |= (IFF_UP | IFF_RUNNING | IFF_BROADCAST);
874           ioctlres = ioctl(ioctlSkfd, SIOCSIFFLAGS, &ifreq);
875         }
876       }
877     }
878   }
879
880   if (ioctlres < 0) {
881     /* Any of the above ioctl() calls failed */
882     OLSR_WARN(LOG_PLUGINS, "error bringing up EtherTunTap interface \"%s\"", EtherTunTapIfName);
883
884     close(etfd);
885     close(ioctlSkfd);
886     return -1;
887   }
888
889   /* if (ioctlres < 0) */
890   /* Set the multicast flag on the interface */
891   memset(&ifreq, 0, sizeof(ifreq));
892   strncpy(ifreq.ifr_name, EtherTunTapIfName, IFNAMSIZ - 1);
893   ifreq.ifr_name[IFNAMSIZ - 1] = '\0';  /* Ensures null termination */
894
895   ioctlres = ioctl(ioctlSkfd, SIOCGIFFLAGS, &ifreq);
896   if (ioctlres >= 0) {
897     ifreq.ifr_flags |= IFF_MULTICAST;
898     ioctlres = ioctl(ioctlSkfd, SIOCSIFFLAGS, &ifreq);
899   }
900   if (ioctlres < 0) {
901     /* Any of the two above ioctl() calls failed */
902     OLSR_WARN(LOG_PLUGINS, "error setting multicast flag on EtherTunTap interface \"%s\"", EtherTunTapIfName);
903
904     /* Continue anyway */
905   }
906
907   /* Use ioctl to make the tuntap persistent. Otherwise it will disappear
908    * when this program exits. That is not desirable, since a multicast
909    * daemon (e.g. mrouted) may be using the tuntap interface. */
910   if (ioctl(etfd, TUNSETPERSIST, (void *)&ifreq) < 0) {
911     OLSR_WARN(LOG_PLUGINS, "error making EtherTunTap interface \"%s\" persistent", EtherTunTapIfName);
912
913     /* Continue anyway */
914   }
915
916   OLSR_DEBUG(LOG_PLUGINS, "opened 1 socket on \"%s\"\n", EtherTunTapIfName);
917
918   AddDescriptorToInputSet(etfd);
919
920   /* If the user configured a specific IP address for the BMF network interface,
921    * help the user and advertise the IP address of the BMF network interface
922    * on the OLSR network via HNA */
923   if (TunTapIpOverruled != 0) {
924     union olsr_ip_addr temp_net;
925
926     temp_net.v4.s_addr = htonl(EtherTunTapIp);
927     ip_prefix_list_add(&olsr_cnf->hna_entries, &temp_net, 32);
928   }
929
930   close(ioctlSkfd);
931
932   return etfd;
933 }                               /* CreateLocalEtherTunTap */
934
935 /* -------------------------------------------------------------------------
936  * Function   : CreateInterface
937  * Description: Create a new TBmfInterface object and adds it to the global
938  *              BmfInterfaces list
939  * Input      : ifName - name of the network interface (e.g. "eth0")
940  *            : olsrIntf - OLSR interface object of the network interface, or
941  *                NULL if the network interface is not OLSR-enabled
942  * Output     : none
943  * Return     : the number of opened sockets
944  * Data Used  : BmfInterfaces, LastBmfInterface
945  * ------------------------------------------------------------------------- */
946 static int
947 CreateInterface(const char *ifName, struct interface *olsrIntf)
948 {
949   int capturingSkfd = -1;
950   int encapsulatingSkfd = -1;
951   int listeningSkfd = -1;
952   int ioctlSkfd;
953   struct ifreq ifr;
954   int nOpened = 0;
955   struct TBmfInterface *newIf = malloc(sizeof(struct TBmfInterface));
956
957   assert(ifName != NULL);
958
959   if (newIf == NULL) {
960     return 0;
961   }
962
963   if (olsrIntf != NULL) {
964     /* On OLSR-enabled interfaces, create socket for encapsulating and forwarding
965      * multicast packets */
966     encapsulatingSkfd = CreateEncapsulateSocket(ifName);
967     if (encapsulatingSkfd < 0) {
968       free(newIf);
969       return 0;
970     }
971     nOpened++;
972   }
973
974   /* Create socket for capturing and sending of multicast packets on
975    * non-OLSR interfaces, and on OLSR-interfaces if configured. */
976   if ((olsrIntf == NULL) || (CapturePacketsOnOlsrInterfaces != 0)) {
977     capturingSkfd = CreateCaptureSocket(ifName);
978     if (capturingSkfd < 0) {
979       close(encapsulatingSkfd);
980       free(newIf);
981       return 0;
982     }
983
984     nOpened++;
985   }
986
987   /* Create promiscuous mode listening interface if BMF uses IP unicast
988    * as underlying forwarding mechanism */
989   if (BmfMechanism == BM_UNICAST_PROMISCUOUS) {
990     listeningSkfd = CreateListeningSocket(ifName);
991     if (listeningSkfd < 0) {
992       close(listeningSkfd);
993       close(encapsulatingSkfd); /* no problem if 'encapsulatingSkfd' is -1 */
994       free(newIf);
995       return 0;
996     }
997
998     nOpened++;
999   }
1000
1001   /* For ioctl operations on the network interface, use either capturingSkfd
1002    * or encapsulatingSkfd, whichever is available */
1003   ioctlSkfd = (capturingSkfd >= 0) ? capturingSkfd : encapsulatingSkfd;
1004
1005   /* Retrieve the MAC address of the interface. */
1006   memset(&ifr, 0, sizeof(struct ifreq));
1007   strncpy(ifr.ifr_name, ifName, IFNAMSIZ - 1);
1008   ifr.ifr_name[IFNAMSIZ - 1] = '\0';    /* Ensures null termination */
1009   if (ioctl(ioctlSkfd, SIOCGIFHWADDR, &ifr) < 0) {
1010     OLSR_WARN(LOG_PLUGINS, "ioctl(SIOCGIFHWADDR) error for interface \"%s\"", ifName);
1011     close(capturingSkfd);
1012     close(encapsulatingSkfd);
1013     free(newIf);
1014     return 0;
1015   }
1016
1017   /* Copy data into TBmfInterface object */
1018   newIf->capturingSkfd = capturingSkfd;
1019   newIf->encapsulatingSkfd = encapsulatingSkfd;
1020   newIf->listeningSkfd = listeningSkfd;
1021   memcpy(newIf->macAddr, ifr.ifr_hwaddr.sa_data, IFHWADDRLEN);
1022   memcpy(newIf->ifName, ifName, IFNAMSIZ);
1023   newIf->olsrIntf = olsrIntf;
1024   if (olsrIntf != NULL) {
1025     /* For an OLSR-interface, copy the interface address and broadcast
1026      * address from the OLSR interface object. Downcast to correct sockaddr
1027      * subtype. */
1028     newIf->intAddr.v4 = olsrIntf->int_src.v4.sin_addr;
1029     newIf->broadAddr.v4 = olsrIntf->int_multicast.v4.sin_addr;
1030   } else {
1031     /* For a non-OLSR interface, retrieve the IP address ourselves */
1032     memset(&ifr, 0, sizeof(struct ifreq));
1033     strncpy(ifr.ifr_name, ifName, IFNAMSIZ - 1);
1034     ifr.ifr_name[IFNAMSIZ - 1] = '\0';  /* Ensures null termination */
1035     if (ioctl(ioctlSkfd, SIOCGIFADDR, &ifr) < 0) {
1036       OLSR_WARN(LOG_PLUGINS, "ioctl(SIOCGIFADDR) error for interface \"%s\"", ifName);
1037
1038       newIf->intAddr.v4.s_addr = inet_addr("0.0.0.0");
1039     } else {
1040       /* Downcast to correct sockaddr subtype */
1041       newIf->intAddr.v4 = ((struct sockaddr_in *)(ARM_NOWARN_ALIGN(&ifr.ifr_addr)))->sin_addr;
1042     }
1043
1044     /* For a non-OLSR interface, retrieve the IP broadcast address ourselves */
1045     memset(&ifr, 0, sizeof(struct ifreq));
1046     strncpy(ifr.ifr_name, ifName, IFNAMSIZ - 1);
1047     ifr.ifr_name[IFNAMSIZ - 1] = '\0';  /* Ensures null termination */
1048     if (ioctl(ioctlSkfd, SIOCGIFBRDADDR, &ifr) < 0) {
1049       OLSR_WARN(LOG_PLUGINS, "ioctl(SIOCGIFBRDADDR) error for interface \"%s\"", ifName);
1050
1051       newIf->broadAddr.v4.s_addr = inet_addr("0.0.0.0");
1052     } else {
1053       /* Downcast to correct sockaddr subtype */
1054       newIf->broadAddr.v4 = ((struct sockaddr_in *)(ARM_NOWARN_ALIGN(&ifr.ifr_broadaddr)))->sin_addr;
1055     }
1056   }
1057
1058   /* Initialize fragment history table */
1059   memset(&newIf->fragmentHistory, 0, sizeof(newIf->fragmentHistory));
1060   newIf->nextFragmentHistoryEntry = 0;
1061
1062   /* Reset counters */
1063   newIf->nBmfPacketsRx = 0;
1064   newIf->nBmfPacketsRxDup = 0;
1065   newIf->nBmfPacketsTx = 0;
1066
1067   /* Add new TBmfInterface object to global list. OLSR interfaces are
1068    * added at the front of the list, non-OLSR interfaces at the back. */
1069   if (BmfInterfaces == NULL) {
1070     /* First TBmfInterface object in list */
1071     BmfInterfaces = newIf;
1072     LastBmfInterface = newIf;
1073   } else if (olsrIntf != NULL) {
1074     /* Add new TBmfInterface object at front of list */
1075     newIf->next = BmfInterfaces;
1076     BmfInterfaces = newIf;
1077   } else {
1078     /* Add new TBmfInterface object at back of list */
1079     newIf->next = NULL;
1080     LastBmfInterface->next = newIf;
1081     LastBmfInterface = newIf;
1082   }
1083
1084   OLSR_DEBUG(LOG_PLUGINS,
1085              "opened %d socket%s on %s interface \"%s\"\n",
1086              nOpened, nOpened == 1 ? "" : "s", olsrIntf != NULL ? "OLSR" : "non-OLSR", ifName);
1087
1088   return nOpened;
1089 }                               /* CreateInterface */
1090
1091 /* -------------------------------------------------------------------------
1092  * Function   : CreateBmfNetworkInterfaces
1093  * Description: Create a list of TBmfInterface objects, one for each network
1094  *              interface on which BMF runs
1095  * Input      : skipThisIntf - network interface to skip, if seen
1096  * Output     : none
1097  * Return     : fail (-1) or success (0)
1098  * Data Used  : none
1099  * ------------------------------------------------------------------------- */
1100 int
1101 CreateBmfNetworkInterfaces(struct interface *skipThisIntf)
1102 {
1103   int skfd;
1104   struct ifconf ifc;
1105   int numreqs = 30;
1106   struct ifreq *ifr;
1107   int n;
1108   int nOpenedSockets = 0;
1109
1110   /* Clear input descriptor set */
1111   FD_ZERO(&InputSet);
1112
1113   skfd = socket(PF_INET, SOCK_DGRAM, 0);
1114   if (skfd < 0) {
1115     OLSR_WARN(LOG_PLUGINS, "no inet socket available to retrieve interface list");
1116     return -1;
1117   }
1118
1119   /* Retrieve the network interface configuration list */
1120   ifc.ifc_buf = NULL;
1121   for (;;) {
1122     ifc.ifc_len = sizeof(struct ifreq) * numreqs;
1123     ifc.ifc_buf = realloc(ifc.ifc_buf, ifc.ifc_len);
1124
1125     if (ioctl(skfd, SIOCGIFCONF, &ifc) < 0) {
1126       OLSR_WARN(LOG_PLUGINS, "ioctl(SIOCGIFCONF) error");
1127
1128       close(skfd);
1129       free(ifc.ifc_buf);
1130       return -1;
1131     }
1132     if ((unsigned)ifc.ifc_len == sizeof(struct ifreq) * numreqs) {
1133       /* Assume it overflowed; double the space and try again */
1134       numreqs *= 2;
1135       assert(numreqs < 1024);
1136       continue;                 /* for (;;) */
1137     }
1138     break;                      /* for (;;) */
1139   }                             /* for (;;) */
1140
1141   close(skfd);
1142
1143   /* For each item in the interface configuration list... */
1144   ifr = ifc.ifc_req;
1145   for (n = ifc.ifc_len / sizeof(struct ifreq); --n >= 0; ifr++) {
1146     struct interface *olsrIntf;
1147     union olsr_ip_addr ipAddr;
1148
1149     /* Skip the BMF network interface itself */
1150     if (strncmp(ifr->ifr_name, EtherTunTapIfName, IFNAMSIZ) == 0) {
1151       continue;                 /* for (n = ...) */
1152     }
1153
1154     /* ...find the OLSR interface structure, if any */
1155     ipAddr.v4 = ((struct sockaddr_in *)(ARM_NOWARN_ALIGN(&ifr->ifr_addr)))->sin_addr;
1156     olsrIntf = if_ifwithaddr(&ipAddr);
1157
1158     if (skipThisIntf != NULL && olsrIntf == skipThisIntf) {
1159       continue;                 /* for (n = ...) */
1160     }
1161
1162     if (olsrIntf == NULL && !IsNonOlsrBmfIf(ifr->ifr_name)) {
1163       /* Interface is neither OLSR interface, nor specified as non-OLSR BMF
1164        * interface in the BMF plugin parameter list */
1165       continue;                 /* for (n = ...) */
1166     }
1167
1168     nOpenedSockets += CreateInterface(ifr->ifr_name, olsrIntf);
1169
1170   }                             /* for (n = ...) */
1171
1172   free(ifc.ifc_buf);
1173
1174   /* Create the BMF network interface */
1175   EtherTunTapFd = CreateLocalEtherTunTap();
1176   if (EtherTunTapFd >= 0) {
1177     nOpenedSockets++;
1178   }
1179
1180   if (BmfInterfaces == NULL) {
1181     OLSR_WARN(LOG_PLUGINS, "could not initialize any network interface\n");
1182   } else {
1183     OLSR_WARN(LOG_PLUGINS, "opened %d sockets\n", nOpenedSockets);
1184   }
1185   return 0;
1186 }                               /* CreateBmfNetworkInterfaces */
1187
1188 /* -------------------------------------------------------------------------
1189  * Function   : AddInterface
1190  * Description: Add an OLSR-enabled network interface to the list of BMF-enabled
1191  *              network interfaces
1192  * Input      : newIntf - network interface to add
1193  * Output     : none
1194  * Return     : none
1195  * Data Used  : none
1196  * ------------------------------------------------------------------------- */
1197 void
1198 AddInterface(struct interface *newIntf)
1199 {
1200   int nOpened;
1201
1202   assert(newIntf != NULL);
1203
1204   nOpened = CreateInterface(newIntf->int_name, newIntf);
1205
1206   OLSR_DEBUG(LOG_PLUGINS, "opened %d sockets\n", nOpened);
1207 }                               /* AddInterface */
1208
1209 /* -------------------------------------------------------------------------
1210  * Function   : CloseBmfNetworkInterfaces
1211  * Description: Closes every socket on each network interface used by BMF
1212  * Input      : none
1213  * Output     : none
1214  * Return     : none
1215  * Data Used  : none
1216  * Notes      : Closes
1217  *              - the local EtherTunTap interface (e.g. "tun0" or "tap0")
1218  *              - for each BMF-enabled interface, the socket used for
1219  *                capturing multicast packets
1220  *              - for each OLSR-enabled interface, the socket used for
1221  *                encapsulating packets
1222  *              Also restores the network state to the situation before BMF
1223  *              was started.
1224  * ------------------------------------------------------------------------- */
1225 void
1226 CloseBmfNetworkInterfaces(void)
1227 {
1228   int nClosed = 0;
1229   u_int32_t totalOlsrBmfPacketsRx = 0;
1230   u_int32_t totalOlsrBmfPacketsRxDup = 0;
1231   u_int32_t totalOlsrBmfPacketsTx = 0;
1232   u_int32_t totalNonOlsrBmfPacketsRx = 0;
1233   u_int32_t totalNonOlsrBmfPacketsRxDup = 0;
1234   u_int32_t totalNonOlsrBmfPacketsTx = 0;
1235
1236   /* Close all opened sockets */
1237   struct TBmfInterface *nextBmfIf = BmfInterfaces;
1238   while (nextBmfIf != NULL) {
1239     struct TBmfInterface *bmfIf = nextBmfIf;
1240     nextBmfIf = bmfIf->next;
1241
1242     if (bmfIf->capturingSkfd >= 0) {
1243       close(bmfIf->capturingSkfd);
1244       nClosed++;
1245     }
1246     if (bmfIf->encapsulatingSkfd >= 0) {
1247       close(bmfIf->encapsulatingSkfd);
1248       nClosed++;
1249     }
1250
1251     OLSR_DEBUG(LOG_PLUGINS,
1252                "%s interface \"%s\": RX pkts %u (%u dups); TX pkts %u\n",
1253                bmfIf->olsrIntf != NULL ? "OLSR" : "non-OLSR",
1254                bmfIf->ifName, bmfIf->nBmfPacketsRx, bmfIf->nBmfPacketsRxDup, bmfIf->nBmfPacketsTx);
1255
1256     OLSR_DEBUG(LOG_PLUGINS, "closed %s interface \"%s\"\n", bmfIf->olsrIntf != NULL ? "OLSR" : "non-OLSR", bmfIf->ifName);
1257
1258     /* Add totals */
1259     if (bmfIf->olsrIntf != NULL) {
1260       totalOlsrBmfPacketsRx += bmfIf->nBmfPacketsRx;
1261       totalOlsrBmfPacketsRxDup += bmfIf->nBmfPacketsRxDup;
1262       totalOlsrBmfPacketsTx += bmfIf->nBmfPacketsTx;
1263     } else {
1264       totalNonOlsrBmfPacketsRx += bmfIf->nBmfPacketsRx;
1265       totalNonOlsrBmfPacketsRxDup += bmfIf->nBmfPacketsRxDup;
1266       totalNonOlsrBmfPacketsTx += bmfIf->nBmfPacketsTx;
1267     }
1268
1269     free(bmfIf);
1270   }                             /* while */
1271
1272   if (EtherTunTapFd >= 0) {
1273     close(EtherTunTapFd);
1274     nClosed++;
1275
1276     OLSR_DEBUG(LOG_PLUGINS, "closed \"%s\"\n", EtherTunTapIfName);
1277   }
1278
1279   BmfInterfaces = NULL;
1280
1281   OLSR_DEBUG(LOG_PLUGINS, "closed %d sockets\n", nClosed);
1282
1283   OLSR_DEBUG(LOG_PLUGINS,
1284              "Total all OLSR interfaces    : RX pkts %u (%u dups); TX pkts %u\n",
1285              totalOlsrBmfPacketsRx, totalOlsrBmfPacketsRxDup, totalOlsrBmfPacketsTx);
1286   OLSR_DEBUG(LOG_PLUGINS,
1287              "Total all non-OLSR interfaces: RX pkts %u (%u dups); TX pkts %u\n",
1288              totalNonOlsrBmfPacketsRx, totalNonOlsrBmfPacketsRxDup, totalNonOlsrBmfPacketsTx);
1289 }                               /* CloseBmfNetworkInterfaces */
1290
1291 #define MAX_NON_OLSR_IFS 32
1292 static char NonOlsrIfNames[MAX_NON_OLSR_IFS][IFNAMSIZ];
1293 static int nNonOlsrIfs = 0;
1294
1295 /* -------------------------------------------------------------------------
1296  * Function   : AddNonOlsrBmfIf
1297  * Description: Add an non-OLSR enabled network interface to the list of BMF-enabled
1298  *              network interfaces
1299  * Input      : ifName - network interface (e.g. "eth0")
1300  *              data - not used
1301  *              addon - not used
1302  * Output     : none
1303  * Return     : success (0) or fail (1)
1304  * Data Used  : NonOlsrIfNames
1305  * ------------------------------------------------------------------------- */
1306 int
1307 AddNonOlsrBmfIf(const char *ifName, void *data __attribute__ ((unused)), set_plugin_parameter_addon addon __attribute__ ((unused)))
1308 {
1309   assert(ifName != NULL);
1310
1311   if (nNonOlsrIfs >= MAX_NON_OLSR_IFS) {
1312     OLSR_WARN(LOG_PLUGINS, "too many non-OLSR interfaces specified, maximum is %d\n", MAX_NON_OLSR_IFS);
1313     return 1;
1314   }
1315
1316   strncpy(NonOlsrIfNames[nNonOlsrIfs], ifName, IFNAMSIZ - 1);
1317   NonOlsrIfNames[nNonOlsrIfs][IFNAMSIZ - 1] = '\0';     /* Ensures null termination */
1318   nNonOlsrIfs++;
1319   return 0;
1320 }                               /* AddNonOlsrBmfIf */
1321
1322 /* -------------------------------------------------------------------------
1323  * Function   : IsNonOlsrBmfIf
1324  * Description: Checks if a network interface is OLSR-enabled
1325  * Input      : ifName - network interface (e.g. "eth0")
1326  * Output     : none
1327  * Return     : true (1) or false (0)
1328  * Data Used  : NonOlsrIfNames
1329  * ------------------------------------------------------------------------- */
1330 int
1331 IsNonOlsrBmfIf(const char *ifName)
1332 {
1333   int i;
1334
1335   assert(ifName != NULL);
1336
1337   for (i = 0; i < nNonOlsrIfs; i++) {
1338     if (strncmp(NonOlsrIfNames[i], ifName, IFNAMSIZ) == 0)
1339       return 1;
1340   }
1341   return 0;
1342 }                               /* IsNonOlsrBmfIf */
1343
1344 /* -------------------------------------------------------------------------
1345  * Function   : CheckAndUpdateLocalBroadcast
1346  * Description: For an IP packet, check if the destination address is not a
1347  *              multicast address. If it is not, the packet is assumed to be
1348  *              a local broadcast packet. In that case, set the destination
1349  *              address of the IP packet to the passed broadcast address.
1350  * Input      : ipPacket - the IP packet
1351  *              broadAddr - the broadcast address to fill in
1352  * Output     : none
1353  * Return     : none
1354  * Data Used  : none
1355  * Notes      : See also RFC1141
1356  * ------------------------------------------------------------------------- */
1357 void
1358 CheckAndUpdateLocalBroadcast(unsigned char *ipPacket, union olsr_ip_addr *broadAddr)
1359 {
1360   struct iphdr *iph;
1361   union olsr_ip_addr destIp;
1362
1363   assert(ipPacket != NULL && broadAddr != NULL);
1364
1365   iph = (struct iphdr *)(ARM_NOWARN_ALIGN(ipPacket));
1366   destIp.v4.s_addr = iph->daddr;
1367   if (!IsMulticast(&destIp)) {
1368     u_int32_t origDaddr, newDaddr;
1369     u_int32_t check;
1370
1371     origDaddr = ntohl(iph->daddr);
1372
1373     iph->daddr = broadAddr->v4.s_addr;
1374     newDaddr = ntohl(iph->daddr);
1375
1376     /* Re-calculate IP header checksum for new destination */
1377     check = ntohs(iph->check);
1378
1379     check = ~(~check - ((origDaddr >> 16) & 0xFFFF) + ((newDaddr >> 16) & 0xFFFF));
1380     check = ~(~check - (origDaddr & 0xFFFF) + (newDaddr & 0xFFFF));
1381
1382     /* Add carry */
1383     check = check + (check >> 16);
1384
1385     iph->check = htons(check);
1386
1387     if (iph->protocol == SOL_UDP) {
1388       /* Re-calculate UDP/IP checksum for new destination */
1389
1390       int ipHeaderLen = GetIpHeaderLength(ipPacket);
1391       struct udphdr *udph = (struct udphdr *)(ARM_NOWARN_ALIGN(ipPacket + ipHeaderLen));
1392
1393       /* RFC 1624, Eq. 3: HC' = ~(~HC - m + m') */
1394
1395       check = ntohs(udph->check);
1396
1397       check = ~(~check - ((origDaddr >> 16) & 0xFFFF) + ((newDaddr >> 16) & 0xFFFF));
1398       check = ~(~check - (origDaddr & 0xFFFF) + (newDaddr & 0xFFFF));
1399
1400       /* Add carry */
1401       check = check + (check >> 16);
1402
1403       udph->check = htons(check);
1404     }                           /* if */
1405   }                             /* if */
1406 }                               /* CheckAndUpdateLocalBroadcast */
1407
1408 /* -------------------------------------------------------------------------
1409  * Function   : AddMulticastRoute
1410  * Description: Insert a route to all multicast addresses in the kernel
1411  *              routing table. The route will be via the BMF network interface.
1412  * Input      : none
1413  * Output     : none
1414  * Return     : none
1415  * Data Used  : none
1416  * ------------------------------------------------------------------------- */
1417 void
1418 AddMulticastRoute(void)
1419 {
1420   struct rtentry kernel_route;
1421   int ioctlSkfd = socket(PF_INET, SOCK_DGRAM, 0);
1422   if (ioctlSkfd < 0) {
1423     OLSR_WARN(LOG_PLUGINS, "socket(PF_INET) error");
1424     return;
1425   }
1426
1427   memset(&kernel_route, 0, sizeof(struct rtentry));
1428
1429   ((struct sockaddr_in *)(ARM_NOWARN_ALIGN(&kernel_route.rt_dst)))->sin_family = AF_INET;
1430   ((struct sockaddr_in *)(ARM_NOWARN_ALIGN(&kernel_route.rt_gateway)))->sin_family = AF_INET;
1431   ((struct sockaddr_in *)(ARM_NOWARN_ALIGN(&kernel_route.rt_genmask)))->sin_family = AF_INET;
1432
1433   /* 224.0.0.0/4 */
1434   ((struct sockaddr_in *)(ARM_NOWARN_ALIGN(&kernel_route.rt_dst)))->sin_addr.s_addr = htonl(0xE0000000);
1435   ((struct sockaddr_in *)(ARM_NOWARN_ALIGN(&kernel_route.rt_genmask)))->sin_addr.s_addr = htonl(0xF0000000);
1436
1437   kernel_route.rt_metric = 0;
1438   kernel_route.rt_flags = RTF_UP;
1439
1440   kernel_route.rt_dev = EtherTunTapIfName;
1441
1442   if (ioctl(ioctlSkfd, SIOCADDRT, &kernel_route) < 0) {
1443     OLSR_WARN(LOG_PLUGINS, "error setting multicast route via EtherTunTap interface \"%s\"", EtherTunTapIfName);
1444
1445     /* Continue anyway */
1446   }
1447   close(ioctlSkfd);
1448 }                               /* AddMulticastRoute */
1449
1450 /* -------------------------------------------------------------------------
1451  * Function   : DeleteMulticastRoute
1452  * Description: Delete the route to all multicast addresses from the kernel
1453  *              routing table
1454  * Input      : none
1455  * Output     : none
1456  * Return     : none
1457  * Data Used  : none
1458  * ------------------------------------------------------------------------- */
1459 void
1460 DeleteMulticastRoute(void)
1461 {
1462   if (EtherTunTapIp != ETHERTUNTAPDEFAULTIP) {
1463     struct rtentry kernel_route;
1464     int ioctlSkfd = socket(PF_INET, SOCK_DGRAM, 0);
1465     if (ioctlSkfd < 0) {
1466       OLSR_WARN(LOG_PLUGINS, "socket(PF_INET) error");
1467       return;
1468     }
1469
1470     memset(&kernel_route, 0, sizeof(struct rtentry));
1471
1472     ((struct sockaddr_in *)(ARM_NOWARN_ALIGN(&kernel_route.rt_dst)))->sin_family = AF_INET;
1473     ((struct sockaddr_in *)(ARM_NOWARN_ALIGN(&kernel_route.rt_gateway)))->sin_family = AF_INET;
1474     ((struct sockaddr_in *)(ARM_NOWARN_ALIGN(&kernel_route.rt_genmask)))->sin_family = AF_INET;
1475
1476     /* 224.0.0.0/4 */
1477     ((struct sockaddr_in *)(ARM_NOWARN_ALIGN(&kernel_route.rt_dst)))->sin_addr.s_addr = htonl(0xE0000000);
1478     ((struct sockaddr_in *)(ARM_NOWARN_ALIGN(&kernel_route.rt_genmask)))->sin_addr.s_addr = htonl(0xF0000000);
1479
1480     kernel_route.rt_metric = 0;
1481     kernel_route.rt_flags = RTF_UP;
1482
1483     kernel_route.rt_dev = EtherTunTapIfName;
1484
1485     if (ioctl(ioctlSkfd, SIOCDELRT, &kernel_route) < 0) {
1486       OLSR_WARN(LOG_PLUGINS, "error deleting multicast route via EtherTunTap interface \"%s\"", EtherTunTapIfName);
1487
1488       /* Continue anyway */
1489     }
1490     close(ioctlSkfd);
1491   }                             /* if */
1492 }                               /* DeleteMulticastRoute */
1493
1494 /*
1495  * Local Variables:
1496  * c-basic-offset: 2
1497  * indent-tabs-mode: nil
1498  * End:
1499  */