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