Massive refactoring of topology handling.
[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;
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) {
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   OLSR_FOR_ALL_LINK_ENTRIES_END(walker);
559
560   /* Display the result of the neighbor search */
561   if (*nPossibleNeighbors == 0) {
562     OLSR_DEBUG(LOG_PLUGINS, "No suitable neighbor found to forward to on \"%s\"\n", intf->ifName);
563   } else {
564 #if !defined REMOVE_LOG_DEBUG
565     struct ipaddr_str buf;
566 #endif
567     OLSR_DEBUG(LOG_PLUGINS,
568                "%d neighbors found on \"%s\"; best neighbor to forward to: %s\n",
569                *nPossibleNeighbors, intf->ifName, olsr_ip_to_string(&buf, &(*bestNeighbor)->neighbor_iface_addr));
570   }                             /* if */
571
572 }                               /* FindNeighbors */
573
574 /* -------------------------------------------------------------------------
575  * Function   : CreateCaptureSocket
576  * Description: Create socket for promiscuously capturing multicast IP traffic
577  * Input      : ifname - network interface (e.g. "eth0")
578  * Output     : none
579  * Return     : the socket descriptor ( >= 0), or -1 if an error occurred
580  * Data Used  : none
581  * Notes      : The socket is a cooked IP packet socket, bound to the specified
582  *              network interface
583  * ------------------------------------------------------------------------- */
584 static int
585 CreateCaptureSocket(const char *ifName)
586 {
587   int ifIndex = if_nametoindex(ifName);
588   struct packet_mreq mreq;
589   struct ifreq req;
590   struct sockaddr_ll bindTo;
591
592   /* Open cooked IP packet socket */
593   int skfd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP));
594   if (skfd < 0) {
595     OLSR_WARN(LOG_PLUGINS, "socket(PF_PACKET) error");
596     return -1;
597   }
598
599   /* Set interface to promiscuous mode */
600   memset(&mreq, 0, sizeof(struct packet_mreq));
601   mreq.mr_ifindex = ifIndex;
602   mreq.mr_type = PACKET_MR_PROMISC;
603   if (setsockopt(skfd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) {
604     OLSR_WARN(LOG_PLUGINS, "setsockopt(PACKET_MR_PROMISC) error");
605     close(skfd);
606     return -1;
607   }
608
609   /* Get hardware (MAC) address */
610   memset(&req, 0, sizeof(struct ifreq));
611   strncpy(req.ifr_name, ifName, IFNAMSIZ - 1);
612   req.ifr_name[IFNAMSIZ - 1] = '\0';    /* Ensures null termination */
613   if (ioctl(skfd, SIOCGIFHWADDR, &req) < 0) {
614     OLSR_WARN(LOG_PLUGINS, "error retrieving MAC address");
615     close(skfd);
616     return -1;
617   }
618
619   /* Bind the socket to the specified interface */
620   memset(&bindTo, 0, sizeof(bindTo));
621   bindTo.sll_family = AF_PACKET;
622   bindTo.sll_protocol = htons(ETH_P_IP);
623   bindTo.sll_ifindex = ifIndex;
624   memcpy(bindTo.sll_addr, req.ifr_hwaddr.sa_data, IFHWADDRLEN);
625   bindTo.sll_halen = IFHWADDRLEN;
626
627   if (bind(skfd, (struct sockaddr *)&bindTo, sizeof(bindTo)) < 0) {
628     OLSR_WARN(LOG_PLUGINS, "bind() error");
629     close(skfd);
630     return -1;
631   }
632
633   /* Set socket to blocking operation */
634   if (fcntl(skfd, F_SETFL, fcntl(skfd, F_GETFL, 0) & ~O_NONBLOCK) < 0) {
635     OLSR_WARN(LOG_PLUGINS, "fcntl() error");
636     close(skfd);
637     return -1;
638   }
639
640   AddDescriptorToInputSet(skfd);
641
642   return skfd;
643 }                               /* CreateCaptureSocket */
644
645 /* -------------------------------------------------------------------------
646  * Function   : CreateListeningSocket
647  * Description: Create socket for promiscuously listening to BMF packets.
648  *              Used only when 'BmfMechanism' is BM_UNICAST_PROMISCUOUS
649  * Input      : ifname - network interface (e.g. "eth0")
650  * Output     : none
651  * Return     : the socket descriptor ( >= 0), or -1 if an error occurred
652  * Data Used  : none
653  * Notes      : The socket is a cooked IP packet socket, bound to the specified
654  *              network interface
655  * ------------------------------------------------------------------------- */
656 static int
657 CreateListeningSocket(const char *ifName)
658 {
659   int ifIndex = if_nametoindex(ifName);
660   struct packet_mreq mreq;
661   struct ifreq req;
662   struct sockaddr_ll bindTo;
663
664   /* Open cooked IP packet socket */
665   int skfd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP));
666   if (skfd < 0) {
667     OLSR_WARN(LOG_PLUGINS, "socket(PF_PACKET) error");
668     return -1;
669   }
670
671   /* Set interface to promiscuous mode */
672   memset(&mreq, 0, sizeof(struct packet_mreq));
673   mreq.mr_ifindex = ifIndex;
674   mreq.mr_type = PACKET_MR_PROMISC;
675   if (setsockopt(skfd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) {
676     OLSR_WARN(LOG_PLUGINS, "setsockopt(PACKET_MR_PROMISC) error");
677     close(skfd);
678     return -1;
679   }
680
681   /* Get hardware (MAC) address */
682   memset(&req, 0, sizeof(struct ifreq));
683   strncpy(req.ifr_name, ifName, IFNAMSIZ - 1);
684   req.ifr_name[IFNAMSIZ - 1] = '\0';    /* Ensures null termination */
685   if (ioctl(skfd, SIOCGIFHWADDR, &req) < 0) {
686     OLSR_WARN(LOG_PLUGINS, "error retrieving MAC address");
687     close(skfd);
688     return -1;
689   }
690
691   /* Bind the socket to the specified interface */
692   memset(&bindTo, 0, sizeof(bindTo));
693   bindTo.sll_family = AF_PACKET;
694   bindTo.sll_protocol = htons(ETH_P_IP);
695   bindTo.sll_ifindex = ifIndex;
696   memcpy(bindTo.sll_addr, req.ifr_hwaddr.sa_data, IFHWADDRLEN);
697   bindTo.sll_halen = IFHWADDRLEN;
698
699   if (bind(skfd, (struct sockaddr *)&bindTo, sizeof(bindTo)) < 0) {
700     OLSR_WARN(LOG_PLUGINS, "bind() error");
701     close(skfd);
702     return -1;
703   }
704
705   /* Set socket to blocking operation */
706   if (fcntl(skfd, F_SETFL, fcntl(skfd, F_GETFL, 0) & ~O_NONBLOCK) < 0) {
707     OLSR_WARN(LOG_PLUGINS, "fcntl() error");
708     close(skfd);
709     return -1;
710   }
711
712   AddDescriptorToInputSet(skfd);
713
714   return skfd;
715 }                               /* CreateListeningSocket */
716
717 /* -------------------------------------------------------------------------
718  * Function   : CreateEncapsulateSocket
719  * Description: Create a socket for sending and receiving encapsulated
720  *              multicast packets
721  * Input      : ifname - network interface (e.g. "eth0")
722  * Output     : none
723  * Return     : the socket descriptor ( >= 0), or -1 if an error occurred
724  * Data Used  : none
725  * Notes      : The socket is an UDP (datagram) over IP socket, bound to the
726  *              specified network interface
727  * ------------------------------------------------------------------------- */
728 static int
729 CreateEncapsulateSocket(const char *ifName)
730 {
731   int on = 1;
732   struct sockaddr_in bindTo;
733
734   /* Open UDP-IP socket */
735   int skfd = socket(PF_INET, SOCK_DGRAM, 0);
736   if (skfd < 0) {
737     OLSR_WARN(LOG_PLUGINS, "socket(PF_INET) error");
738     return -1;
739   }
740
741   /* Enable sending to broadcast addresses */
742   if (setsockopt(skfd, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)) < 0) {
743     OLSR_WARN(LOG_PLUGINS, "setsockopt(SO_BROADCAST) error");
744     close(skfd);
745     return -1;
746   }
747
748   /* Bind to the specific network interfaces indicated by ifName. */
749   /* When using Kernel 2.6 this must happer prior to the port binding! */
750   if (setsockopt(skfd, SOL_SOCKET, SO_BINDTODEVICE, ifName, strlen(ifName) + 1) < 0) {
751     OLSR_WARN(LOG_PLUGINS, "setsockopt(SO_BINDTODEVICE) error");
752     close(skfd);
753     return -1;
754   }
755
756   /* Bind to BMF port */
757   memset(&bindTo, 0, sizeof(bindTo));
758   bindTo.sin_family = AF_INET;
759   bindTo.sin_port = htons(BMF_ENCAP_PORT);
760   bindTo.sin_addr.s_addr = htonl(INADDR_ANY);
761
762   if (bind(skfd, (struct sockaddr *)&bindTo, sizeof(bindTo)) < 0) {
763     OLSR_WARN(LOG_PLUGINS, "bind() error");
764     close(skfd);
765     return -1;
766   }
767
768   /* Set socket to blocking operation */
769   if (fcntl(skfd, F_SETFL, fcntl(skfd, F_GETFL, 0) & ~O_NONBLOCK) < 0) {
770     OLSR_WARN(LOG_PLUGINS, "fcntl() error");
771     close(skfd);
772     return -1;
773   }
774
775   AddDescriptorToInputSet(skfd);
776
777   return skfd;
778 }                               /* CreateEncapsulateSocket */
779
780 /* -------------------------------------------------------------------------
781  * Function   : CreateLocalEtherTunTap
782  * Description: Creates and brings up an EtherTunTap interface
783  * Input      : none
784  * Output     : none
785  * Return     : the socket file descriptor (>= 0), or -1 in case of failure
786  * Data Used  : EtherTunTapIfName - name used for the tuntap interface (e.g.
787  *                "bmf0")
788  *              EtherTunTapIp
789  *              EtherTunTapIpMask
790  *              EtherTunTapIpBroadcast
791  *              BmfInterfaces
792  * Note       : Order dependency: call this function only if BmfInterfaces
793  *              is filled with a list of network interfaces.
794  * ------------------------------------------------------------------------- */
795 static int
796 CreateLocalEtherTunTap(void)
797 {
798   static const char deviceName[] = "/dev/net/tun";
799   struct ifreq ifreq;
800   int etfd;
801   int ioctlSkfd;
802   int ioctlres;
803
804   etfd = open(deviceName, O_RDWR | O_NONBLOCK);
805   if (etfd < 0) {
806     OLSR_WARN(LOG_PLUGINS, "error opening %s", deviceName);
807     return -1;
808   }
809
810   memset(&ifreq, 0, sizeof(ifreq));
811   strncpy(ifreq.ifr_name, EtherTunTapIfName, IFNAMSIZ - 1);
812   ifreq.ifr_name[IFNAMSIZ - 1] = '\0';  /* Ensures null termination */
813
814   /* Specify the IFF_TUN flag for IP packets.
815    * Specify IFF_NO_PI for not receiving extra meta packet information. */
816   ifreq.ifr_flags = IFF_TUN;
817   ifreq.ifr_flags |= IFF_NO_PI;
818
819   if (ioctl(etfd, TUNSETIFF, (void *)&ifreq) < 0) {
820     OLSR_WARN(LOG_PLUGINS, "ioctl(TUNSETIFF) error on %s", deviceName);
821     close(etfd);
822     return -1;
823   }
824
825   memset(&ifreq, 0, sizeof(ifreq));
826   strncpy(ifreq.ifr_name, EtherTunTapIfName, IFNAMSIZ - 1);
827   ifreq.ifr_name[IFNAMSIZ - 1] = '\0';  /* Ensures null termination */
828   ifreq.ifr_addr.sa_family = AF_INET;
829
830   ioctlSkfd = socket(PF_INET, SOCK_DGRAM, 0);
831   if (ioctlSkfd < 0) {
832     OLSR_WARN(LOG_PLUGINS, "socket(PF_INET) error on %s", deviceName);
833     close(etfd);
834     return -1;
835   }
836
837   /* Give the EtherTunTap interface an IP address.
838    * The default IP address is the address of the first OLSR interface;
839    * the default netmask is 255.255.255.255 . Having an all-ones netmask prevents
840    * automatic entry of the BMF network interface in the routing table. */
841   if (EtherTunTapIp == ETHERTUNTAPIPNOTSET) {
842     struct TBmfInterface *nextBmfIf = BmfInterfaces;
843     while (nextBmfIf != NULL) {
844       struct TBmfInterface *bmfIf = nextBmfIf;
845       nextBmfIf = bmfIf->next;
846
847       if (bmfIf->olsrIntf != NULL) {
848         EtherTunTapIp = ntohl(bmfIf->intAddr.v4.s_addr);
849         EtherTunTapIpBroadcast = EtherTunTapIp;
850       }
851     }
852   }
853
854   if (EtherTunTapIp == ETHERTUNTAPIPNOTSET) {
855     /* No IP address configured for BMF network interface, and no OLSR interface found to
856      * copy IP address from. Fall back to default: 10.255.255.253 . */
857     EtherTunTapIp = ETHERTUNTAPDEFAULTIP;
858   }
859
860   ((struct sockaddr_in *)(ARM_NOWARN_ALIGN)&ifreq.ifr_addr)->sin_addr.s_addr = htonl(EtherTunTapIp);
861   ioctlres = ioctl(ioctlSkfd, SIOCSIFADDR, &ifreq);
862   if (ioctlres >= 0) {
863     /* Set net mask */
864     ((struct sockaddr_in *)(ARM_NOWARN_ALIGN)&ifreq.ifr_netmask)->sin_addr.s_addr = htonl(EtherTunTapIpMask);
865     ioctlres = ioctl(ioctlSkfd, SIOCSIFNETMASK, &ifreq);
866     if (ioctlres >= 0) {
867       /* Set broadcast IP */
868       ((struct sockaddr_in *)(ARM_NOWARN_ALIGN)&ifreq.ifr_broadaddr)->sin_addr.s_addr = htonl(EtherTunTapIpBroadcast);
869       ioctlres = ioctl(ioctlSkfd, SIOCSIFBRDADDR, &ifreq);
870       if (ioctlres >= 0) {
871         /* Bring EtherTunTap interface up (if not already) */
872         ioctlres = ioctl(ioctlSkfd, SIOCGIFFLAGS, &ifreq);
873         if (ioctlres >= 0) {
874           ifreq.ifr_flags |= (IFF_UP | IFF_RUNNING | IFF_BROADCAST);
875           ioctlres = ioctl(ioctlSkfd, SIOCSIFFLAGS, &ifreq);
876         }
877       }
878     }
879   }
880
881   if (ioctlres < 0) {
882     /* Any of the above ioctl() calls failed */
883     OLSR_WARN(LOG_PLUGINS, "error bringing up EtherTunTap interface \"%s\"", EtherTunTapIfName);
884
885     close(etfd);
886     close(ioctlSkfd);
887     return -1;
888   }
889
890   /* if (ioctlres < 0) */
891   /* Set the multicast flag on the interface */
892   memset(&ifreq, 0, sizeof(ifreq));
893   strncpy(ifreq.ifr_name, EtherTunTapIfName, IFNAMSIZ - 1);
894   ifreq.ifr_name[IFNAMSIZ - 1] = '\0';  /* Ensures null termination */
895
896   ioctlres = ioctl(ioctlSkfd, SIOCGIFFLAGS, &ifreq);
897   if (ioctlres >= 0) {
898     ifreq.ifr_flags |= IFF_MULTICAST;
899     ioctlres = ioctl(ioctlSkfd, SIOCSIFFLAGS, &ifreq);
900   }
901   if (ioctlres < 0) {
902     /* Any of the two above ioctl() calls failed */
903     OLSR_WARN(LOG_PLUGINS, "error setting multicast flag on EtherTunTap interface \"%s\"", EtherTunTapIfName);
904
905     /* Continue anyway */
906   }
907
908   /* Use ioctl to make the tuntap persistent. Otherwise it will disappear
909    * when this program exits. That is not desirable, since a multicast
910    * daemon (e.g. mrouted) may be using the tuntap interface. */
911   if (ioctl(etfd, TUNSETPERSIST, (void *)&ifreq) < 0) {
912     OLSR_WARN(LOG_PLUGINS, "error making EtherTunTap interface \"%s\" persistent", EtherTunTapIfName);
913
914     /* Continue anyway */
915   }
916
917   OLSR_DEBUG(LOG_PLUGINS, "opened 1 socket on \"%s\"\n", EtherTunTapIfName);
918
919   AddDescriptorToInputSet(etfd);
920
921   /* If the user configured a specific IP address for the BMF network interface,
922    * help the user and advertise the IP address of the BMF network interface
923    * on the OLSR network via HNA */
924   if (TunTapIpOverruled != 0) {
925     union olsr_ip_addr temp_net;
926
927     temp_net.v4.s_addr = htonl(EtherTunTapIp);
928     ip_prefix_list_add(&olsr_cnf->hna_entries, &temp_net, 32);
929   }
930
931   close(ioctlSkfd);
932
933   return etfd;
934 }                               /* CreateLocalEtherTunTap */
935
936 /* -------------------------------------------------------------------------
937  * Function   : CreateInterface
938  * Description: Create a new TBmfInterface object and adds it to the global
939  *              BmfInterfaces list
940  * Input      : ifName - name of the network interface (e.g. "eth0")
941  *            : olsrIntf - OLSR interface object of the network interface, or
942  *                NULL if the network interface is not OLSR-enabled
943  * Output     : none
944  * Return     : the number of opened sockets
945  * Data Used  : BmfInterfaces, LastBmfInterface
946  * ------------------------------------------------------------------------- */
947 static int
948 CreateInterface(const char *ifName, struct interface *olsrIntf)
949 {
950   int capturingSkfd = -1;
951   int encapsulatingSkfd = -1;
952   int listeningSkfd = -1;
953   int ioctlSkfd;
954   struct ifreq ifr;
955   int nOpened = 0;
956   struct TBmfInterface *newIf = malloc(sizeof(struct TBmfInterface));
957
958   assert(ifName != NULL);
959
960   if (newIf == NULL) {
961     return 0;
962   }
963
964   if (olsrIntf != NULL) {
965     /* On OLSR-enabled interfaces, create socket for encapsulating and forwarding
966      * multicast packets */
967     encapsulatingSkfd = CreateEncapsulateSocket(ifName);
968     if (encapsulatingSkfd < 0) {
969       free(newIf);
970       return 0;
971     }
972     nOpened++;
973   }
974
975   /* Create socket for capturing and sending of multicast packets on
976    * non-OLSR interfaces, and on OLSR-interfaces if configured. */
977   if ((olsrIntf == NULL) || (CapturePacketsOnOlsrInterfaces != 0)) {
978     capturingSkfd = CreateCaptureSocket(ifName);
979     if (capturingSkfd < 0) {
980       close(encapsulatingSkfd);
981       free(newIf);
982       return 0;
983     }
984
985     nOpened++;
986   }
987
988   /* Create promiscuous mode listening interface if BMF uses IP unicast
989    * as underlying forwarding mechanism */
990   if (BmfMechanism == BM_UNICAST_PROMISCUOUS) {
991     listeningSkfd = CreateListeningSocket(ifName);
992     if (listeningSkfd < 0) {
993       close(listeningSkfd);
994       close(encapsulatingSkfd); /* no problem if 'encapsulatingSkfd' is -1 */
995       free(newIf);
996       return 0;
997     }
998
999     nOpened++;
1000   }
1001
1002   /* For ioctl operations on the network interface, use either capturingSkfd
1003    * or encapsulatingSkfd, whichever is available */
1004   ioctlSkfd = (capturingSkfd >= 0) ? capturingSkfd : encapsulatingSkfd;
1005
1006   /* Retrieve the MAC address of the interface. */
1007   memset(&ifr, 0, sizeof(struct ifreq));
1008   strncpy(ifr.ifr_name, ifName, IFNAMSIZ - 1);
1009   ifr.ifr_name[IFNAMSIZ - 1] = '\0';    /* Ensures null termination */
1010   if (ioctl(ioctlSkfd, SIOCGIFHWADDR, &ifr) < 0) {
1011     OLSR_WARN(LOG_PLUGINS, "ioctl(SIOCGIFHWADDR) error for interface \"%s\"", ifName);
1012     close(capturingSkfd);
1013     close(encapsulatingSkfd);
1014     free(newIf);
1015     return 0;
1016   }
1017
1018   /* Copy data into TBmfInterface object */
1019   newIf->capturingSkfd = capturingSkfd;
1020   newIf->encapsulatingSkfd = encapsulatingSkfd;
1021   newIf->listeningSkfd = listeningSkfd;
1022   memcpy(newIf->macAddr, ifr.ifr_hwaddr.sa_data, IFHWADDRLEN);
1023   memcpy(newIf->ifName, ifName, IFNAMSIZ);
1024   newIf->olsrIntf = olsrIntf;
1025   if (olsrIntf != NULL) {
1026     /* For an OLSR-interface, copy the interface address and broadcast
1027      * address from the OLSR interface object. Downcast to correct sockaddr
1028      * subtype. */
1029     newIf->intAddr.v4 = olsrIntf->int_addr.sin_addr;
1030     newIf->broadAddr.v4 = olsrIntf->int_broadaddr.sin_addr;
1031   } else {
1032     /* For a non-OLSR interface, retrieve the IP address ourselves */
1033     memset(&ifr, 0, sizeof(struct ifreq));
1034     strncpy(ifr.ifr_name, ifName, IFNAMSIZ - 1);
1035     ifr.ifr_name[IFNAMSIZ - 1] = '\0';  /* Ensures null termination */
1036     if (ioctl(ioctlSkfd, SIOCGIFADDR, &ifr) < 0) {
1037       OLSR_WARN(LOG_PLUGINS, "ioctl(SIOCGIFADDR) error for interface \"%s\"", ifName);
1038
1039       newIf->intAddr.v4.s_addr = inet_addr("0.0.0.0");
1040     } else {
1041       /* Downcast to correct sockaddr subtype */
1042       newIf->intAddr.v4 = ((struct sockaddr_in *)(ARM_NOWARN_ALIGN)&ifr.ifr_addr)->sin_addr;
1043     }
1044
1045     /* For a non-OLSR interface, retrieve the IP broadcast address ourselves */
1046     memset(&ifr, 0, sizeof(struct ifreq));
1047     strncpy(ifr.ifr_name, ifName, IFNAMSIZ - 1);
1048     ifr.ifr_name[IFNAMSIZ - 1] = '\0';  /* Ensures null termination */
1049     if (ioctl(ioctlSkfd, SIOCGIFBRDADDR, &ifr) < 0) {
1050       OLSR_WARN(LOG_PLUGINS, "ioctl(SIOCGIFBRDADDR) error for interface \"%s\"", ifName);
1051
1052       newIf->broadAddr.v4.s_addr = inet_addr("0.0.0.0");
1053     } else {
1054       /* Downcast to correct sockaddr subtype */
1055       newIf->broadAddr.v4 = ((struct sockaddr_in *)(ARM_NOWARN_ALIGN)&ifr.ifr_broadaddr)->sin_addr;
1056     }
1057   }
1058
1059   /* Initialize fragment history table */
1060   memset(&newIf->fragmentHistory, 0, sizeof(newIf->fragmentHistory));
1061   newIf->nextFragmentHistoryEntry = 0;
1062
1063   /* Reset counters */
1064   newIf->nBmfPacketsRx = 0;
1065   newIf->nBmfPacketsRxDup = 0;
1066   newIf->nBmfPacketsTx = 0;
1067
1068   /* Add new TBmfInterface object to global list. OLSR interfaces are
1069    * added at the front of the list, non-OLSR interfaces at the back. */
1070   if (BmfInterfaces == NULL) {
1071     /* First TBmfInterface object in list */
1072     BmfInterfaces = newIf;
1073     LastBmfInterface = newIf;
1074   } else if (olsrIntf != NULL) {
1075     /* Add new TBmfInterface object at front of list */
1076     newIf->next = BmfInterfaces;
1077     BmfInterfaces = newIf;
1078   } else {
1079     /* Add new TBmfInterface object at back of list */
1080     newIf->next = NULL;
1081     LastBmfInterface->next = newIf;
1082     LastBmfInterface = newIf;
1083   }
1084
1085   OLSR_DEBUG(LOG_PLUGINS,
1086              "opened %d socket%s on %s interface \"%s\"\n",
1087              nOpened, nOpened == 1 ? "" : "s", olsrIntf != NULL ? "OLSR" : "non-OLSR", ifName);
1088
1089   return nOpened;
1090 }                               /* CreateInterface */
1091
1092 /* -------------------------------------------------------------------------
1093  * Function   : CreateBmfNetworkInterfaces
1094  * Description: Create a list of TBmfInterface objects, one for each network
1095  *              interface on which BMF runs
1096  * Input      : skipThisIntf - network interface to skip, if seen
1097  * Output     : none
1098  * Return     : fail (-1) or success (0)
1099  * Data Used  : none
1100  * ------------------------------------------------------------------------- */
1101 int
1102 CreateBmfNetworkInterfaces(struct interface *skipThisIntf)
1103 {
1104   int skfd;
1105   struct ifconf ifc;
1106   int numreqs = 30;
1107   struct ifreq *ifr;
1108   int n;
1109   int nOpenedSockets = 0;
1110
1111   /* Clear input descriptor set */
1112   FD_ZERO(&InputSet);
1113
1114   skfd = socket(PF_INET, SOCK_DGRAM, 0);
1115   if (skfd < 0) {
1116     OLSR_WARN(LOG_PLUGINS, "no inet socket available to retrieve interface list");
1117     return -1;
1118   }
1119
1120   /* Retrieve the network interface configuration list */
1121   ifc.ifc_buf = NULL;
1122   for (;;) {
1123     ifc.ifc_len = sizeof(struct ifreq) * numreqs;
1124     ifc.ifc_buf = realloc(ifc.ifc_buf, ifc.ifc_len);
1125
1126     if (ioctl(skfd, SIOCGIFCONF, &ifc) < 0) {
1127       OLSR_WARN(LOG_PLUGINS, "ioctl(SIOCGIFCONF) error");
1128
1129       close(skfd);
1130       free(ifc.ifc_buf);
1131       return -1;
1132     }
1133     if ((unsigned)ifc.ifc_len == sizeof(struct ifreq) * numreqs) {
1134       /* Assume it overflowed; double the space and try again */
1135       numreqs *= 2;
1136       assert(numreqs < 1024);
1137       continue;                 /* for (;;) */
1138     }
1139     break;                      /* for (;;) */
1140   }                             /* for (;;) */
1141
1142   close(skfd);
1143
1144   /* For each item in the interface configuration list... */
1145   ifr = ifc.ifc_req;
1146   for (n = ifc.ifc_len / sizeof(struct ifreq); --n >= 0; ifr++) {
1147     struct interface *olsrIntf;
1148     union olsr_ip_addr ipAddr;
1149
1150     /* Skip the BMF network interface itself */
1151     if (strncmp(ifr->ifr_name, EtherTunTapIfName, IFNAMSIZ) == 0) {
1152       continue;                 /* for (n = ...) */
1153     }
1154
1155     /* ...find the OLSR interface structure, if any */
1156     ipAddr.v4 = ((struct sockaddr_in *)(ARM_NOWARN_ALIGN)&ifr->ifr_addr)->sin_addr;
1157     olsrIntf = if_ifwithaddr(&ipAddr);
1158
1159     if (skipThisIntf != NULL && olsrIntf == skipThisIntf) {
1160       continue;                 /* for (n = ...) */
1161     }
1162
1163     if (olsrIntf == NULL && !IsNonOlsrBmfIf(ifr->ifr_name)) {
1164       /* Interface is neither OLSR interface, nor specified as non-OLSR BMF
1165        * interface in the BMF plugin parameter list */
1166       continue;                 /* for (n = ...) */
1167     }
1168
1169     nOpenedSockets += CreateInterface(ifr->ifr_name, olsrIntf);
1170
1171   }                             /* for (n = ...) */
1172
1173   free(ifc.ifc_buf);
1174
1175   /* Create the BMF network interface */
1176   EtherTunTapFd = CreateLocalEtherTunTap();
1177   if (EtherTunTapFd >= 0) {
1178     nOpenedSockets++;
1179   }
1180
1181   if (BmfInterfaces == NULL) {
1182     OLSR_WARN(LOG_PLUGINS, "could not initialize any network interface\n");
1183   } else {
1184     OLSR_WARN(LOG_PLUGINS, "opened %d sockets\n", nOpenedSockets);
1185   }
1186   return 0;
1187 }                               /* CreateBmfNetworkInterfaces */
1188
1189 /* -------------------------------------------------------------------------
1190  * Function   : AddInterface
1191  * Description: Add an OLSR-enabled network interface to the list of BMF-enabled
1192  *              network interfaces
1193  * Input      : newIntf - network interface to add
1194  * Output     : none
1195  * Return     : none
1196  * Data Used  : none
1197  * ------------------------------------------------------------------------- */
1198 void
1199 AddInterface(struct interface *newIntf)
1200 {
1201   int nOpened;
1202
1203   assert(newIntf != NULL);
1204
1205   nOpened = CreateInterface(newIntf->int_name, newIntf);
1206
1207   OLSR_DEBUG(LOG_PLUGINS, "opened %d sockets\n", nOpened);
1208 }                               /* AddInterface */
1209
1210 /* -------------------------------------------------------------------------
1211  * Function   : CloseBmfNetworkInterfaces
1212  * Description: Closes every socket on each network interface used by BMF
1213  * Input      : none
1214  * Output     : none
1215  * Return     : none
1216  * Data Used  : none
1217  * Notes      : Closes
1218  *              - the local EtherTunTap interface (e.g. "tun0" or "tap0")
1219  *              - for each BMF-enabled interface, the socket used for
1220  *                capturing multicast packets
1221  *              - for each OLSR-enabled interface, the socket used for
1222  *                encapsulating packets
1223  *              Also restores the network state to the situation before BMF
1224  *              was started.
1225  * ------------------------------------------------------------------------- */
1226 void
1227 CloseBmfNetworkInterfaces(void)
1228 {
1229   int nClosed = 0;
1230   u_int32_t totalOlsrBmfPacketsRx = 0;
1231   u_int32_t totalOlsrBmfPacketsRxDup = 0;
1232   u_int32_t totalOlsrBmfPacketsTx = 0;
1233   u_int32_t totalNonOlsrBmfPacketsRx = 0;
1234   u_int32_t totalNonOlsrBmfPacketsRxDup = 0;
1235   u_int32_t totalNonOlsrBmfPacketsTx = 0;
1236
1237   /* Close all opened sockets */
1238   struct TBmfInterface *nextBmfIf = BmfInterfaces;
1239   while (nextBmfIf != NULL) {
1240     struct TBmfInterface *bmfIf = nextBmfIf;
1241     nextBmfIf = bmfIf->next;
1242
1243     if (bmfIf->capturingSkfd >= 0) {
1244       close(bmfIf->capturingSkfd);
1245       nClosed++;
1246     }
1247     if (bmfIf->encapsulatingSkfd >= 0) {
1248       close(bmfIf->encapsulatingSkfd);
1249       nClosed++;
1250     }
1251
1252     OLSR_DEBUG(LOG_PLUGINS,
1253                "%s interface \"%s\": RX pkts %u (%u dups); TX pkts %u\n",
1254                bmfIf->olsrIntf != NULL ? "OLSR" : "non-OLSR",
1255                bmfIf->ifName, bmfIf->nBmfPacketsRx, bmfIf->nBmfPacketsRxDup, bmfIf->nBmfPacketsTx);
1256
1257     OLSR_DEBUG(LOG_PLUGINS, "closed %s interface \"%s\"\n", bmfIf->olsrIntf != NULL ? "OLSR" : "non-OLSR", bmfIf->ifName);
1258
1259     /* Add totals */
1260     if (bmfIf->olsrIntf != NULL) {
1261       totalOlsrBmfPacketsRx += bmfIf->nBmfPacketsRx;
1262       totalOlsrBmfPacketsRxDup += bmfIf->nBmfPacketsRxDup;
1263       totalOlsrBmfPacketsTx += bmfIf->nBmfPacketsTx;
1264     } else {
1265       totalNonOlsrBmfPacketsRx += bmfIf->nBmfPacketsRx;
1266       totalNonOlsrBmfPacketsRxDup += bmfIf->nBmfPacketsRxDup;
1267       totalNonOlsrBmfPacketsTx += bmfIf->nBmfPacketsTx;
1268     }
1269
1270     free(bmfIf);
1271   }                             /* while */
1272
1273   if (EtherTunTapFd >= 0) {
1274     close(EtherTunTapFd);
1275     nClosed++;
1276
1277     OLSR_DEBUG(LOG_PLUGINS, "closed \"%s\"\n", EtherTunTapIfName);
1278   }
1279
1280   BmfInterfaces = NULL;
1281
1282   OLSR_DEBUG(LOG_PLUGINS, "closed %d sockets\n", nClosed);
1283
1284   OLSR_DEBUG(LOG_PLUGINS,
1285              "Total all OLSR interfaces    : RX pkts %u (%u dups); TX pkts %u\n",
1286              totalOlsrBmfPacketsRx, totalOlsrBmfPacketsRxDup, totalOlsrBmfPacketsTx);
1287   OLSR_DEBUG(LOG_PLUGINS,
1288              "Total all non-OLSR interfaces: RX pkts %u (%u dups); TX pkts %u\n",
1289              totalNonOlsrBmfPacketsRx, totalNonOlsrBmfPacketsRxDup, totalNonOlsrBmfPacketsTx);
1290 }                               /* CloseBmfNetworkInterfaces */
1291
1292 #define MAX_NON_OLSR_IFS 32
1293 static char NonOlsrIfNames[MAX_NON_OLSR_IFS][IFNAMSIZ];
1294 static int nNonOlsrIfs = 0;
1295
1296 /* -------------------------------------------------------------------------
1297  * Function   : AddNonOlsrBmfIf
1298  * Description: Add an non-OLSR enabled network interface to the list of BMF-enabled
1299  *              network interfaces
1300  * Input      : ifName - network interface (e.g. "eth0")
1301  *              data - not used
1302  *              addon - not used
1303  * Output     : none
1304  * Return     : success (0) or fail (1)
1305  * Data Used  : NonOlsrIfNames
1306  * ------------------------------------------------------------------------- */
1307 int
1308 AddNonOlsrBmfIf(const char *ifName, void *data __attribute__ ((unused)), set_plugin_parameter_addon addon __attribute__ ((unused)))
1309 {
1310   assert(ifName != NULL);
1311
1312   if (nNonOlsrIfs >= MAX_NON_OLSR_IFS) {
1313     OLSR_WARN(LOG_PLUGINS, "too many non-OLSR interfaces specified, maximum is %d\n", MAX_NON_OLSR_IFS);
1314     return 1;
1315   }
1316
1317   strncpy(NonOlsrIfNames[nNonOlsrIfs], ifName, IFNAMSIZ - 1);
1318   NonOlsrIfNames[nNonOlsrIfs][IFNAMSIZ - 1] = '\0';     /* Ensures null termination */
1319   nNonOlsrIfs++;
1320   return 0;
1321 }                               /* AddNonOlsrBmfIf */
1322
1323 /* -------------------------------------------------------------------------
1324  * Function   : IsNonOlsrBmfIf
1325  * Description: Checks if a network interface is OLSR-enabled
1326  * Input      : ifName - network interface (e.g. "eth0")
1327  * Output     : none
1328  * Return     : true (1) or false (0)
1329  * Data Used  : NonOlsrIfNames
1330  * ------------------------------------------------------------------------- */
1331 int
1332 IsNonOlsrBmfIf(const char *ifName)
1333 {
1334   int i;
1335
1336   assert(ifName != NULL);
1337
1338   for (i = 0; i < nNonOlsrIfs; i++) {
1339     if (strncmp(NonOlsrIfNames[i], ifName, IFNAMSIZ) == 0)
1340       return 1;
1341   }
1342   return 0;
1343 }                               /* IsNonOlsrBmfIf */
1344
1345 /* -------------------------------------------------------------------------
1346  * Function   : CheckAndUpdateLocalBroadcast
1347  * Description: For an IP packet, check if the destination address is not a
1348  *              multicast address. If it is not, the packet is assumed to be
1349  *              a local broadcast packet. In that case, set the destination
1350  *              address of the IP packet to the passed broadcast address.
1351  * Input      : ipPacket - the IP packet
1352  *              broadAddr - the broadcast address to fill in
1353  * Output     : none
1354  * Return     : none
1355  * Data Used  : none
1356  * Notes      : See also RFC1141
1357  * ------------------------------------------------------------------------- */
1358 void
1359 CheckAndUpdateLocalBroadcast(unsigned char *ipPacket, union olsr_ip_addr *broadAddr)
1360 {
1361   struct iphdr *iph;
1362   union olsr_ip_addr destIp;
1363
1364   assert(ipPacket != NULL && broadAddr != NULL);
1365
1366   iph = (struct iphdr *)(ARM_NOWARN_ALIGN)ipPacket;
1367   destIp.v4.s_addr = iph->daddr;
1368   if (!IsMulticast(&destIp)) {
1369     u_int32_t origDaddr, newDaddr;
1370     u_int32_t check;
1371
1372     origDaddr = ntohl(iph->daddr);
1373
1374     iph->daddr = broadAddr->v4.s_addr;
1375     newDaddr = ntohl(iph->daddr);
1376
1377     /* Re-calculate IP header checksum for new destination */
1378     check = ntohs(iph->check);
1379
1380     check = ~(~check - ((origDaddr >> 16) & 0xFFFF) + ((newDaddr >> 16) & 0xFFFF));
1381     check = ~(~check - (origDaddr & 0xFFFF) + (newDaddr & 0xFFFF));
1382
1383     /* Add carry */
1384     check = check + (check >> 16);
1385
1386     iph->check = htons(check);
1387
1388     if (iph->protocol == SOL_UDP) {
1389       /* Re-calculate UDP/IP checksum for new destination */
1390
1391       int ipHeaderLen = GetIpHeaderLength(ipPacket);
1392       struct udphdr *udph = (struct udphdr *)(ARM_NOWARN_ALIGN)(ipPacket + ipHeaderLen);
1393
1394       /* RFC 1624, Eq. 3: HC' = ~(~HC - m + m') */
1395
1396       check = ntohs(udph->check);
1397
1398       check = ~(~check - ((origDaddr >> 16) & 0xFFFF) + ((newDaddr >> 16) & 0xFFFF));
1399       check = ~(~check - (origDaddr & 0xFFFF) + (newDaddr & 0xFFFF));
1400
1401       /* Add carry */
1402       check = check + (check >> 16);
1403
1404       udph->check = htons(check);
1405     }                           /* if */
1406   }                             /* if */
1407 }                               /* CheckAndUpdateLocalBroadcast */
1408
1409 /* -------------------------------------------------------------------------
1410  * Function   : AddMulticastRoute
1411  * Description: Insert a route to all multicast addresses in the kernel
1412  *              routing table. The route will be via the BMF network interface.
1413  * Input      : none
1414  * Output     : none
1415  * Return     : none
1416  * Data Used  : none
1417  * ------------------------------------------------------------------------- */
1418 void
1419 AddMulticastRoute(void)
1420 {
1421   struct rtentry kernel_route;
1422   int ioctlSkfd = socket(PF_INET, SOCK_DGRAM, 0);
1423   if (ioctlSkfd < 0) {
1424     OLSR_WARN(LOG_PLUGINS, "socket(PF_INET) error");
1425     return;
1426   }
1427
1428   memset(&kernel_route, 0, sizeof(struct rtentry));
1429
1430   ((struct sockaddr_in *)(ARM_NOWARN_ALIGN)&kernel_route.rt_dst)->sin_family = AF_INET;
1431   ((struct sockaddr_in *)(ARM_NOWARN_ALIGN)&kernel_route.rt_gateway)->sin_family = AF_INET;
1432   ((struct sockaddr_in *)(ARM_NOWARN_ALIGN)&kernel_route.rt_genmask)->sin_family = AF_INET;
1433
1434   /* 224.0.0.0/4 */
1435   ((struct sockaddr_in *)(ARM_NOWARN_ALIGN)&kernel_route.rt_dst)->sin_addr.s_addr = htonl(0xE0000000);
1436   ((struct sockaddr_in *)(ARM_NOWARN_ALIGN)&kernel_route.rt_genmask)->sin_addr.s_addr = htonl(0xF0000000);
1437
1438   kernel_route.rt_metric = 0;
1439   kernel_route.rt_flags = RTF_UP;
1440
1441   kernel_route.rt_dev = EtherTunTapIfName;
1442
1443   if (ioctl(ioctlSkfd, SIOCADDRT, &kernel_route) < 0) {
1444     OLSR_WARN(LOG_PLUGINS, "error setting multicast route via EtherTunTap interface \"%s\"", EtherTunTapIfName);
1445
1446     /* Continue anyway */
1447   }
1448   close(ioctlSkfd);
1449 }                               /* AddMulticastRoute */
1450
1451 /* -------------------------------------------------------------------------
1452  * Function   : DeleteMulticastRoute
1453  * Description: Delete the route to all multicast addresses from the kernel
1454  *              routing table
1455  * Input      : none
1456  * Output     : none
1457  * Return     : none
1458  * Data Used  : none
1459  * ------------------------------------------------------------------------- */
1460 void
1461 DeleteMulticastRoute(void)
1462 {
1463   if (EtherTunTapIp != ETHERTUNTAPDEFAULTIP) {
1464     struct rtentry kernel_route;
1465     int ioctlSkfd = socket(PF_INET, SOCK_DGRAM, 0);
1466     if (ioctlSkfd < 0) {
1467       OLSR_WARN(LOG_PLUGINS, "socket(PF_INET) error");
1468       return;
1469     }
1470
1471     memset(&kernel_route, 0, sizeof(struct rtentry));
1472
1473     ((struct sockaddr_in *)(ARM_NOWARN_ALIGN)&kernel_route.rt_dst)->sin_family = AF_INET;
1474     ((struct sockaddr_in *)(ARM_NOWARN_ALIGN)&kernel_route.rt_gateway)->sin_family = AF_INET;
1475     ((struct sockaddr_in *)(ARM_NOWARN_ALIGN)&kernel_route.rt_genmask)->sin_family = AF_INET;
1476
1477     /* 224.0.0.0/4 */
1478     ((struct sockaddr_in *)(ARM_NOWARN_ALIGN)&kernel_route.rt_dst)->sin_addr.s_addr = htonl(0xE0000000);
1479     ((struct sockaddr_in *)(ARM_NOWARN_ALIGN)&kernel_route.rt_genmask)->sin_addr.s_addr = htonl(0xF0000000);
1480
1481     kernel_route.rt_metric = 0;
1482     kernel_route.rt_flags = RTF_UP;
1483
1484     kernel_route.rt_dev = EtherTunTapIfName;
1485
1486     if (ioctl(ioctlSkfd, SIOCDELRT, &kernel_route) < 0) {
1487       OLSR_WARN(LOG_PLUGINS, "error deleting multicast route via EtherTunTap interface \"%s\"", EtherTunTapIfName);
1488
1489       /* Continue anyway */
1490     }
1491     close(ioctlSkfd);
1492   }                             /* if */
1493 }                               /* DeleteMulticastRoute */
1494
1495 /*
1496  * Local Variables:
1497  * c-basic-offset: 2
1498  * indent-tabs-mode: nil
1499  * End:
1500  */