2 * OLSR Basic Multicast Forwarding (BMF) plugin.
3 * Copyright (c) 2005 - 2007, Thales Communications, Huizen, The Netherlands.
4 * Written by Erik Tromp.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
17 * * Neither the name of Thales, BMF nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
25 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
28 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
29 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
30 * OF THE POSSIBILITY OF SUCH DAMAGE.
33 /* -------------------------------------------------------------------------
35 * Description: Multicast forwarding functions
36 * Created : 29 Jun 2006
38 * ------------------------------------------------------------------------- */
40 #define _MULTI_THREADED
45 #include <stddef.h> /* NULL */
46 #include <sys/types.h> /* ssize_t */
47 #include <string.h> /* strerror() */
48 #include <stdarg.h> /* va_list, va_start, va_end */
49 #include <errno.h> /* errno */
50 #include <assert.h> /* assert() */
51 #include <linux/if_ether.h> /* ETH_P_IP */
52 #include <linux/if_packet.h> /* struct sockaddr_ll, PACKET_MULTICAST */
53 #include <pthread.h> /* pthread_t, pthread_create() */
54 #include <signal.h> /* sigset_t, sigfillset(), sigdelset(), SIGINT */
55 #include <netinet/ip.h> /* struct ip */
56 #include <netinet/udp.h> /* struct udphdr */
57 #include <unistd.h> /* close() */
60 #include "plugin_util.h" /* set_plugin_int */
61 #include "defs.h" /* olsr_cnf, OLSR_PRINTF */
63 #include "olsr.h" /* OLSR_PRINTF */
64 #include "mid_set.h" /* mid_lookup_main_addr() */
65 #include "mpr_selector_set.h" /* olsr_lookup_mprs_set() */
66 #include "link_set.h" /* get_best_link_to_neighbor() */
67 #include "net_olsr.h" /* ipequal */
68 #include "olsr_logging.h"
71 #include "NetworkInterfaces.h" /* TBmfInterface, CreateBmfNetworkInterfaces(), CloseBmfNetworkInterfaces() */
72 #include "Address.h" /* IsMulticast() */
73 #include "Packet.h" /* ENCAP_HDR_LEN, BMF_ENCAP_TYPE, BMF_ENCAP_LEN etc. */
74 #include "PacketHistory.h" /* InitPacketHistory() */
76 static pthread_t BmfThread;
77 static int BmfThreadRunning = 0;
79 /* unicast/broadcast fan out limit */
82 int BroadcastRetransmitCount = 1;
84 /* -------------------------------------------------------------------------
85 * Function : MainAddressOf
86 * Description: Lookup the main address of a node
87 * Input : ip - IP address of the node
89 * Return : The main IP address of the node
91 * ------------------------------------------------------------------------- */
92 union olsr_ip_addr* MainAddressOf(union olsr_ip_addr* ip)
94 union olsr_ip_addr* result;
96 /* TODO: mid_lookup_main_addr() is not thread-safe! */
97 result = olsr_lookup_main_addr_by_alias(ip);
103 } /* MainAddressOf */
105 /* -------------------------------------------------------------------------
106 * Function : EncapsulateAndForwardPacket
107 * Description: Encapsulate a captured raw IP packet and forward it
108 * Input : intf - the network interface on which to forward the packet
109 * encapsulationUdpData - The encapsulation header, followed by
110 * the encapsulated IP packet
114 * ------------------------------------------------------------------------- */
115 static void EncapsulateAndForwardPacket(
116 struct TBmfInterface* intf,
117 unsigned char* encapsulationUdpData)
120 u_int16_t udpDataLen = GetEncapsulationUdpDataLength(encapsulationUdpData);
122 /* The next destination(s) */
123 struct TBestNeighbors bestNeighborLinks;
124 struct link_entry* bestNeighbor;
126 int nPossibleNeighbors = 0;
127 struct sockaddr_in forwardTo; /* Next destination of encapsulation packet */
129 int sendUnicast; /* 0 = send broadcast; 1 = send unicast */
133 /* Find at most 'FanOutLimit' best neigbors to forward the packet to */
134 FindNeighbors(&bestNeighborLinks, &bestNeighbor, intf, NULL, NULL, NULL, &nPossibleNeighbors);
136 if (nPossibleNeighbors <= 0)
140 "BMF: not encap-forwarding on \"%s\": there is no neighbor that needs my retransmission\n",
145 /* Compose destination of encapsulation packet */
147 memset(&forwardTo, 0, sizeof(forwardTo));
148 forwardTo.sin_family = AF_INET;
149 forwardTo.sin_port = htons(BMF_ENCAP_PORT);
151 /* Start by filling in the local broadcast address. This may be overwritten later. */
152 forwardTo.sin_addr = intf->broadAddr.v4;
154 /* - If the BMF mechanism is BM_UNICAST_PROMISCUOUS, always send just one
155 * unicast packet (to the best neighbor).
156 * - But if the BMF mechanism is BM_BROADCAST,
157 * - send 'nPossibleNeighbors' unicast packets if there are up to
158 * 'FanOutLimit' possible neighbors,
159 * - if there are more than 'FanOutLimit' possible neighbors, then
160 * send a (WLAN-air-expensive, less reliable) broadcast packet. */
161 if (BmfMechanism == BM_UNICAST_PROMISCUOUS)
163 /* One unicast packet to the best neighbor */
166 bestNeighborLinks.links[0] = bestNeighbor;
168 else /* BmfMechanism == BM_BROADCAST */
170 if (nPossibleNeighbors <= FanOutLimit)
172 /* 'nPossibleNeighbors' unicast packets */
173 nPacketsToSend = nPossibleNeighbors;
176 else /* nPossibleNeighbors > FanOutLimit */
178 /* One broadcast packet, possibly retransmitted as specified in the
179 * 'BroadcastRetransmitCount' plugin parameter */
180 nPacketsToSend = BroadcastRetransmitCount;
185 for (i = 0; i < nPacketsToSend; i++)
189 if (sendUnicast == 1)
191 /* For unicast, overwrite the local broadcast address which was filled in above */
192 forwardTo.sin_addr = bestNeighborLinks.links[i]->neighbor_iface_addr.v4;
195 /* Forward the BMF packet via the encapsulation socket */
196 nBytesWritten = sendto(
197 intf->encapsulatingSkfd,
198 encapsulationUdpData,
201 (struct sockaddr*) &forwardTo,
204 /* Evaluate and display result */
205 if (nBytesWritten != udpDataLen)
207 OLSR_WARN(LOG_PLUGINS, "BMF: sendto() error forwarding pkt on \"%s\"", intf->ifName);
211 /* Increase counter */
212 intf->nBmfPacketsTx++;
216 "BMF: encapsulated and forwarded on \"%s\" to %s\n",
218 inet_ntoa(forwardTo.sin_addr));
219 } /* if (nBytesWritten != udpDataLen) */
221 } /* EncapsulateAndForwardPacket */
223 /* -------------------------------------------------------------------------
224 * Function : BmfPacketCaptured
225 * Description: Handle a captured IP packet
226 * Input : intf - the network interface on which the packet was captured
227 * sllPkttype - the type of packet. Either PACKET_OUTGOING,
228 * PACKET_BROADCAST or PACKET_MULTICAST.
229 * encapsulationUdpData - space for the encapsulation header, followed by
230 * the captured IP packet
233 * Data Used : BmfInterfaces
234 * Notes : The IP packet is assumed to be captured on a socket of family
235 * PF_PACKET and type SOCK_DGRAM (cooked).
236 * ------------------------------------------------------------------------- */
237 static void BmfPacketCaptured(
238 struct TBmfInterface* intf,
239 unsigned char sllPkttype,
240 unsigned char* encapsulationUdpData)
242 union olsr_ip_addr src; /* Source IP address in captured packet */
243 union olsr_ip_addr dst; /* Destination IP address in captured packet */
244 union olsr_ip_addr* origIp; /* Main OLSR address of source of captured packet */
245 struct TBmfInterface* walker;
247 int isFromOlsrNeighbor;
249 unsigned char* ipPacket; /* The captured IP packet... */
250 u_int16_t ipPacketLen; /* ...and its length */
251 struct ip* ipHeader; /* The IP header inside the captured IP packet */
253 struct TEncapHeader* encapHdr;
254 struct ipaddr_str srcBuf, dstBuf;
255 ipHeader = GetIpHeader(encapsulationUdpData);
257 dst.v4 = ipHeader->ip_dst;
259 /* Only forward multicast packets. If configured, also forward local broadcast packets */
260 if (IsMulticast(&dst) ||
261 (EnableLocalBroadcast != 0 && olsr_ipcmp(&dst, &intf->broadAddr) == 0))
270 ipPacket = GetIpPacket(encapsulationUdpData);
272 /* Don't forward fragments of IP packets: there is no way to distinguish fragments
273 * of BMF encapsulation packets from other fragments.
274 * Well yes, there is the IP-ID, which can be kept in a list to relate a fragment
275 * to earlier sent BMF packets, but... sometimes the second fragment comes in earlier
276 * than the first fragment, so that the list is not yet up to date and the second
277 * fragment is not recognized as a BMF packet.
278 * Also, don't forward OLSR packets (UDP port 698) and BMF encapsulated packets */
279 if (IsIpFragment(ipPacket) || IsOlsrOrBmfPacket(ipPacket))
284 /* Increase counter */
285 intf->nBmfPacketsRx++;
287 /* Check if the frame is captured on an OLSR-enabled interface */
288 isFromOlsrIntf = (intf->olsrIntf != NULL);
290 /* Retrieve the length of the captured packet */
291 ipPacketLen = GetIpTotalLength(ipPacket);
293 src.v4 = ipHeader->ip_src;
297 "BMF: %s pkt of %ld bytes captured on %s interface \"%s\": %s->%s\n",
298 sllPkttype == PACKET_OUTGOING ? "outgoing" : "incoming",
300 isFromOlsrIntf ? "OLSR" : "non-OLSR",
302 olsr_ip_to_string(&srcBuf, &src),
303 olsr_ip_to_string(&dstBuf, &dst));
305 /* Lookup main address of source in the MID table of OLSR */
306 origIp = MainAddressOf(&src);
308 /* Calculate packet fingerprint */
309 crc32 = PacketCrc32(ipPacket, ipPacketLen);
311 /* Check if this packet was seen recently */
312 if (CheckAndMarkRecentPacket(crc32))
314 /* Increase counter */
315 intf->nBmfPacketsRxDup++;
317 OLSR_DEBUG(LOG_PLUGINS, "BMF: discarding: packet is duplicate\n");
321 /* Compose encapsulation header */
322 encapHdr = (struct TEncapHeader*) encapsulationUdpData;
323 memset (encapHdr, 0, ENCAP_HDR_LEN);
324 encapHdr->type = BMF_ENCAP_TYPE;
325 encapHdr->len = BMF_ENCAP_LEN;
326 encapHdr->reserved = 0;
327 encapHdr->crc32 = htonl(crc32);
329 /* Check if the frame is captured on an OLSR interface from an OLSR neighbor.
330 * TODO1: get_best_link_to_neighbor() is not thread-safe.
331 * TODO2: get_best_link_to_neighbor() may be very CPU-expensive, a simpler call
332 * would do here (something like 'get_any_link_to_neighbor()'). */
334 (isFromOlsrIntf /* The frame is captured on an OLSR interface... */
335 && get_best_link_to_neighbor(origIp) != NULL); /* ...from an OLSR neighbor */
337 /* Check with OLSR if I am MPR for that neighbor */
338 /* TODO: olsr_lookup_mprs_set() is not thread-safe! */
339 iAmMpr = olsr_lookup_mprs_set(origIp) != NULL;
341 /* Check with each network interface what needs to be done on it */
342 for (walker = BmfInterfaces; walker != NULL; walker = walker->next)
344 /* Is the forwarding interface OLSR-enabled? */
345 int isToOlsrIntf = (walker->olsrIntf != NULL);
347 /* Depending on certain conditions, we decide whether or not to forward
348 * the packet, and if it is forwarded, in which form (encapsulated
349 * or not, TTL decreased or not). These conditions are:
350 * - is the packet is coming in on an OLSR interface or not? (isFromOlsrIntf)
351 * - is the packet going out on an OLSR interface or not? (isToOlsrIntf)
352 * - if the packet if coming in on an OLSR interface:
353 * - is the node that forwarded the packet my OLSR-neighbor? (isFromOlsrNeighbor)
354 * - has the node that forwarded the packet selected me as MPR? (iAmMpr)
356 * Based on these conditions, the following cases can be distinguished:
358 * - Case 1: Packet coming in on an OLSR interface. What to
359 * do with it on an OLSR interface?
361 * - Case 1.1: If the forwarding node is an OLSR neighbor that has *not*
362 * selected me as MPR: don't forward the packet.
363 * - Case 1.2: If the forwarding node is an OLSR neighbor that has selected
364 * me as MPR: encapsulate and forward the packet.
365 * - Case 1.3: If the forwarding node is not an OLSR neighbor: encapsulate
366 * and forward the packet.
367 * NOTE: Case 1.3 is a special case. In the perfect world, we expect to
368 * see only OLSR-neighbors on OLSR-enabled interfaces. Sometimes, however,
369 * ignorant users will connect a host not running OLSR, to a LAN in
370 * which there are hosts running OLSR. Of course these ignorant users,
371 * expecting magic, want to see their multicast packets being forwarded
372 * through the network.
374 * - Case 2: Packet coming in on an OLSR interface. What to do with it on a
375 * non-OLSR interface?
376 * Answer: Forward it.
378 * - Case 3: Packet coming in on a non-OLSR interface. What to
379 * do with it on an OLSR interface?
380 * Answer: Encapsulate and forward it.
382 * - Case 4: Packet coming in on non-OLSR interface. What to do with it on a
383 * non-OLSR interface?
384 * Answer 1: nothing. Multicast routing between non-OLSR interfaces
385 * is to be done by other protocols (e.g. PIM, DVMRP).
386 * Answer 2 (better): Forward it.
389 if (isFromOlsrIntf && isToOlsrIntf)
391 /* Case 1: Forward from an OLSR interface to an OLSR interface */
393 if (isFromOlsrNeighbor && !iAmMpr)
397 struct ipaddr_str buf;
400 "BMF: not encap-forwarding on \"%s\": I am not selected as MPR by neighbor %s\n",
402 olsr_ip_to_string(&buf, &src));
405 else if (sllPkttype == PACKET_OUTGOING && intf == walker)
409 "BMF: not encap-forwarding on \"%s\": pkt was captured on that interface\n",
414 /* Case 1.2 and 1.3 */
415 EncapsulateAndForwardPacket(walker, encapsulationUdpData);
417 } /* if (isFromOlsrIntf && isToOlsrIntf) */
419 else if (isFromOlsrIntf && !isToOlsrIntf)
421 /* Case 2: Forward from OLSR interface to non-OLSR interface */
424 struct sockaddr_ll dest;
426 /* If the encapsulated IP packet is a local broadcast packet,
427 * update its destination address to match the subnet of the network
428 * interface on which the packet is being sent. */
429 CheckAndUpdateLocalBroadcast(ipPacket, &walker->broadAddr);
431 memset(&dest, 0, sizeof(dest));
432 dest.sll_family = AF_PACKET;
433 dest.sll_protocol = htons(ETH_P_IP);
434 dest.sll_ifindex = if_nametoindex(walker->ifName);
435 dest.sll_halen = IFHWADDRLEN;
437 /* Use all-ones as destination MAC address. When the IP destination is
438 * a multicast address, the destination MAC address should normally also
439 * be a multicast address. E.g., when the destination IP is 224.0.0.1,
440 * the destination MAC should be 01:00:5e:00:00:01. However, it does not
441 * seem to matter when the destination MAC address is set to all-ones
443 memset(dest.sll_addr, 0xFF, IFHWADDRLEN);
445 nBytesWritten = sendto(
446 walker->capturingSkfd,
450 (struct sockaddr*) &dest,
452 if (nBytesWritten != ipPacketLen)
454 OLSR_WARN(LOG_PLUGINS, "BMF: sendto() error forwarding pkt on \"%s\"", walker->ifName);
458 /* Increase counter */
459 walker->nBmfPacketsTx++;
461 OLSR_WARN(LOG_PLUGINS, "BMF: forwarded on \"%s\"\n", walker->ifName);
463 } /* else if (isFromOlsrIntf && !isToOlsrIntf) */
465 else if (!isFromOlsrIntf && isToOlsrIntf)
467 /* Case 3: Forward from a non-OLSR interface to an OLSR interface.
468 * Encapsulate and forward packet. */
470 EncapsulateAndForwardPacket(walker, encapsulationUdpData);
471 } /* else if (!isFromOlsrIntf && isToOlsrIntf) */
475 /* Case 4: Forward from non-OLSR interface to non-OLSR interface. */
477 /* Don't forward on interface on which packet was received */
482 "not forwarding on \"%s\": pkt was captured on that interface\n",
489 struct sockaddr_ll dest;
491 /* If the encapsulated IP packet is a local broadcast packet,
492 * update its destination address to match the subnet of the network
493 * interface on which the packet is being sent. */
494 CheckAndUpdateLocalBroadcast(ipPacket, &walker->broadAddr);
496 memset(&dest, 0, sizeof(dest));
497 dest.sll_family = AF_PACKET;
498 dest.sll_protocol = htons(ETH_P_IP);
499 dest.sll_ifindex = if_nametoindex(walker->ifName);
500 dest.sll_halen = IFHWADDRLEN;
502 /* Use all-ones as destination MAC address. When the IP destination is
503 * a multicast address, the destination MAC address should normally also
504 * be a multicast address. E.g., when the destination IP is 224.0.0.1,
505 * the destination MAC should be 01:00:5e:00:00:01. However, it does not
506 * seem to matter when the destination MAC address is set to all-ones
508 memset(dest.sll_addr, 0xFF, IFHWADDRLEN);
510 nBytesWritten = sendto(
511 walker->capturingSkfd,
515 (struct sockaddr*) &dest,
517 if (nBytesWritten != ipPacketLen)
519 OLSR_WARN(LOG_PLUGINS, "BMF: sendto() error forwarding pkt on \"%s\"", walker->ifName);
523 /* Increase counter */
524 walker->nBmfPacketsTx++;
528 "BMF: forwarded from non-OLSR on non-OLSR \"%s\"\n",
531 } /* if (intf == walker) */
534 } /* BmfPacketCaptured */
536 /* -------------------------------------------------------------------------
537 * Function : BmfEncapsulationPacketReceived
538 * Description: Handle a received BMF-encapsulation packet
539 * Input : intf - the network interface on which the packet was received
540 * forwardedBy - the IP node that forwarded the packet to me
541 * forwardedTo - the destination IP address of the encapsulation
542 * packet, in case the packet was received promiscuously.
543 * Pass NULL if the packet is received normally (unicast or
545 * encapsulationUdpData - the encapsulating IP UDP data, containting
546 * the BMF encapsulation header, followed by the encapsulated
550 * Data Used : BmfInterfaces
551 * ------------------------------------------------------------------------- */
552 static void BmfEncapsulationPacketReceived(
553 struct TBmfInterface* intf,
554 union olsr_ip_addr* forwardedBy,
555 union olsr_ip_addr* forwardedTo,
556 unsigned char* encapsulationUdpData)
558 int iAmMpr; /* True (1) if I am selected as MPR by 'forwardedBy' */
559 struct sockaddr_in forwardTo; /* Next destination of encapsulation packet */
560 unsigned char* ipPacket; /* The encapsulated IP packet */
561 u_int16_t ipPacketLen; /* Length of the encapsulated IP packet */
562 struct ip* ipHeader; /* IP header inside the encapsulated IP packet */
563 union olsr_ip_addr mcSrc; /* Original source of the encapsulated multicast packet */
564 union olsr_ip_addr mcDst; /* Multicast destination of the encapsulated packet */
565 struct TEncapHeader* encapsulationHdr;
566 u_int16_t encapsulationUdpDataLen;
567 struct TBmfInterface* walker;
568 struct ipaddr_str mcSrcBuf, mcDstBuf, forwardedByBuf, forwardedToBuf;
569 /* Are we talking to ourselves? */
570 if (if_ifwithaddr(forwardedBy) != NULL)
575 /* Discard encapsulated packets received on a non-OLSR interface */
576 if (intf->olsrIntf == NULL)
581 /* Retrieve details about the encapsulated IP packet */
582 ipPacket = GetIpPacket(encapsulationUdpData);
583 ipPacketLen = GetIpTotalLength(ipPacket);
584 ipHeader = GetIpHeader(encapsulationUdpData);
586 mcSrc.v4 = ipHeader->ip_src;
587 mcDst.v4 = ipHeader->ip_dst;
589 /* Increase counter */
590 intf->nBmfPacketsRx++;
594 "BMF: encapsulated pkt of %ld bytes incoming on \"%s\": %s->%s, forwarded by %s to %s\n",
597 olsr_ip_to_string(&mcSrcBuf, &mcSrc),
598 olsr_ip_to_string(&mcDstBuf, &mcDst),
599 olsr_ip_to_string(&forwardedByBuf, forwardedBy),
600 forwardedTo != NULL ? olsr_ip_to_string(&forwardedToBuf, forwardedTo) : "me");
602 /* Get encapsulation header */
603 encapsulationHdr = (struct TEncapHeader*) encapsulationUdpData;
605 /* Verify correct format of BMF encapsulation header */
606 if (encapsulationHdr->type != BMF_ENCAP_TYPE ||
607 encapsulationHdr->len != BMF_ENCAP_LEN ||
608 ntohs(encapsulationHdr->reserved != 0))
612 "%s: --> discarding: format of BMF encapsulation header not recognized\n",
617 /* Check if this packet was seen recently */
618 if (CheckAndMarkRecentPacket(ntohl(encapsulationHdr->crc32)))
620 /* Increase counter */
621 intf->nBmfPacketsRxDup++;
623 OLSR_DEBUG(LOG_PLUGINS, "BMF: discarding: packet is duplicate\n");
627 if (EtherTunTapFd >= 0)
629 /* Unpack the encapsulated IP packet and deliver it locally, by sending
630 * a copy into the local IP stack via the EtherTunTap interface */
632 union olsr_ip_addr broadAddr;
633 int nBytesToWrite, nBytesWritten;
634 unsigned char* bufferToWrite;
636 /* If the encapsulated IP packet is a local broadcast packet,
637 * update its destination address to match the subnet of the EtherTunTap
639 broadAddr.v4.s_addr = htonl(EtherTunTapIpBroadcast);
640 CheckAndUpdateLocalBroadcast(ipPacket, &broadAddr);
642 bufferToWrite = ipPacket;
643 nBytesToWrite = ipPacketLen;
645 /* Write the packet into the EtherTunTap interface for local delivery */
646 nBytesWritten = write(EtherTunTapFd, bufferToWrite, nBytesToWrite);
647 if (nBytesWritten != nBytesToWrite)
649 OLSR_WARN(LOG_PLUGINS, "BMF: write() error forwarding encapsulated pkt on \"%s\"", EtherTunTapIfName);
653 OLSR_DEBUG(LOG_PLUGINS, "BMF: unpacked and delivered locally on \"%s\"\n", EtherTunTapIfName);
655 } /* if (EtherTunTapFd >= 0) */
657 /* Check if I am MPR for the forwarder */
658 /* TODO: olsr_lookup_mprs_set() is not thread-safe! */
659 iAmMpr = (olsr_lookup_mprs_set(MainAddressOf(forwardedBy)) != NULL);
661 /* Compose destination address for next hop */
662 memset(&forwardTo, 0, sizeof(forwardTo));
663 forwardTo.sin_family = AF_INET;
664 forwardTo.sin_port = htons(BMF_ENCAP_PORT);
666 /* Retrieve the number of bytes to be forwarded via the encapsulation socket */
667 encapsulationUdpDataLen = GetEncapsulationUdpDataLength(encapsulationUdpData);
669 /* Check with each network interface what needs to be done on it */
670 for (walker = BmfInterfaces; walker != NULL; walker = walker->next)
672 /* What to do with the packet on a non-OLSR interface? Unpack
673 * encapsulated packet, and forward it.
675 * What to do with the packet on an OLSR interface? Forward it only
676 * if the forwarding node has selected us as MPR (iAmMpr).
678 * Note that the packet is always coming in on an OLSR interface, because
679 * it is an encapsulated BMF packet. */
681 /* To a non-OLSR interface: unpack the encapsulated IP packet and forward it */
682 if (walker->olsrIntf == NULL)
685 struct sockaddr_ll dest;
687 /* If the encapsulated IP packet is a local broadcast packet,
688 * update its destination address to match the subnet of the network
689 * interface on which the packet is being sent. */
690 CheckAndUpdateLocalBroadcast(ipPacket, &walker->broadAddr);
692 memset(&dest, 0, sizeof(dest));
693 dest.sll_family = AF_PACKET;
694 dest.sll_protocol = htons(ETH_P_IP);
695 dest.sll_ifindex = if_nametoindex(walker->ifName);
696 dest.sll_halen = IFHWADDRLEN;
698 /* Use all-ones as destination MAC address. When the IP destination is
699 * a multicast address, the destination MAC address should normally also
700 * be a multicast address. E.g., when the destination IP is 224.0.0.1,
701 * the destination MAC should be 01:00:5e:00:00:01. However, it does not
702 * seem to matter when the destination MAC address is set to all-ones
704 memset(dest.sll_addr, 0xFF, IFHWADDRLEN);
706 nBytesWritten = sendto(
707 walker->capturingSkfd,
711 (struct sockaddr*) &dest,
713 if (nBytesWritten != ipPacketLen)
715 OLSR_WARN(LOG_PLUGINS, "BMF: sendto() error forwarding unpacked encapsulated pkt on \"%s\"", walker->ifName);
719 /* Increase counter */
720 walker->nBmfPacketsTx++;
724 "unpacked and forwarded on \"%s\"\n",
727 } /* if (walker->olsrIntf == NULL) */
729 /* To an OLSR interface: forward the packet, but only if this node is
730 * selected as MPR by the forwarding node */
733 struct TBestNeighbors bestNeighborLinks;
734 struct link_entry* bestNeighbor;
735 int nPossibleNeighbors;
737 int sendUnicast; /* 0 = send broadcast; 1 = send unicast */
740 /* Retrieve at most two best neigbors to forward the packet to */
748 &nPossibleNeighbors);
750 if (nPossibleNeighbors <= 0)
754 "not forwarding on \"%s\": there is no neighbor that needs my retransmission\n",
760 /* Compose destination of encapsulation packet.
761 * Start by filling in the local broadcast address. This may be overwritten later. */
762 forwardTo.sin_addr = walker->broadAddr.v4;
764 /* - If the BMF mechanism is BM_UNICAST_PROMISCUOUS, always send just one
765 * unicast packet (to the best neighbor).
766 * - But if the BMF mechanism is BM_BROADCAST,
767 * - send 'nPossibleNeighbors' unicast packets if there are up to
768 * 'FanOutLimit' possible neighbors,
769 * - if there are more than 'FanOutLimit' possible neighbors, then
770 * send a (WLAN-air-expensive, less reliable) broadcast packet. */
771 if (BmfMechanism == BM_UNICAST_PROMISCUOUS)
773 /* One unicast packet to the best neighbor */
776 bestNeighborLinks.links[0] = bestNeighbor;
778 else /* BmfMechanism == BM_BROADCAST */
780 if (nPossibleNeighbors <= FanOutLimit)
782 /* 'nPossibleNeighbors' unicast packets */
783 nPacketsToSend = nPossibleNeighbors;
786 else /* nPossibleNeighbors > FanOutLimit */
788 /* One broadcast packet, possibly retransmitted as specified in the
789 * 'BroadcastRetransmitCount' plugin parameter */
790 nPacketsToSend = BroadcastRetransmitCount;
795 for (i = 0; i < nPacketsToSend; i++)
801 /* For unicast, overwrite the local broadcast address which was filled in above */
802 forwardTo.sin_addr = bestNeighborLinks.links[i]->neighbor_iface_addr.v4;
805 /* Forward the BMF packet via the encapsulation socket */
806 nBytesWritten = sendto(
807 walker->encapsulatingSkfd,
808 encapsulationUdpData,
809 encapsulationUdpDataLen,
811 (struct sockaddr*) &forwardTo,
814 /* Evaluate and display result */
815 if (nBytesWritten != encapsulationUdpDataLen)
817 OLSR_WARN(LOG_PLUGINS, "sendto() error forwarding encapsulated pkt on \"%s\"", walker->ifName);
821 /* Increase counter */
822 walker->nBmfPacketsTx++;
826 "forwarded on \"%s\" to %s\n",
828 inet_ntoa(forwardTo.sin_addr));
831 } /* else if (iAmMpr) */
833 else /* walker->olsrIntf != NULL && !iAmMpr */
835 struct ipaddr_str buf;
836 /* 'walker' is an OLSR interface, but I am not selected as MPR. In that
837 * case, don't forward. */
840 "not forwarding on \"%s\": I am not selected as MPR by %s\n",
842 olsr_ip_to_string(&buf, forwardedBy));
845 } /* BmfEncapsulationPacketReceived */
847 /* -------------------------------------------------------------------------
848 * Function : BmfTunPacketCaptured
849 * Description: Handle an IP packet, captured outgoing on the tuntap interface
850 * Input : encapsulationUdpData - space for the encapsulation header, followed by
851 * the captured outgoing IP packet
855 * Notes : The packet is assumed to be captured on a socket of family
856 * PF_PACKET and type SOCK_DGRAM (cooked).
857 * ------------------------------------------------------------------------- */
858 static void BmfTunPacketCaptured(unsigned char* encapsulationUdpData)
860 union olsr_ip_addr srcIp;
861 union olsr_ip_addr dstIp;
862 union olsr_ip_addr broadAddr;
863 struct TBmfInterface* walker;
864 unsigned char* ipPacket;
865 u_int16_t ipPacketLen;
868 struct TEncapHeader* encapHdr;
869 struct ipaddr_str srcIpBuf, dstIpBuf;
870 ipPacket = GetIpPacket(encapsulationUdpData);
871 ipPacketLen = GetIpTotalLength(ipPacket);
872 ipHeader = GetIpHeader(encapsulationUdpData);
874 dstIp.v4 = ipHeader->ip_dst;
875 broadAddr.v4.s_addr = htonl(EtherTunTapIpBroadcast);
877 /* Only forward multicast packets. If configured, also forward local broadcast packets */
878 if (IsMulticast(&dstIp) ||
879 (EnableLocalBroadcast != 0 && olsr_ipcmp(&dstIp, &broadAddr) == 0))
888 srcIp.v4 = ipHeader->ip_src;
892 "outgoing pkt of %ld bytes captured on tuntap interface \"%s\": %s->%s\n",
895 olsr_ip_to_string(&srcIpBuf, &srcIp),
896 olsr_ip_to_string(&dstIpBuf, &dstIp));
898 /* Calculate packet fingerprint */
899 crc32 = PacketCrc32(ipPacket, ipPacketLen);
901 /* Check if this packet was seen recently */
902 if (CheckAndMarkRecentPacket(crc32))
904 OLSR_DEBUG(LOG_PLUGINS, "discarding: packet is duplicate\n");
908 /* Compose encapsulation header */
909 encapHdr = (struct TEncapHeader*) encapsulationUdpData;
910 memset (encapHdr, 0, ENCAP_HDR_LEN);
911 encapHdr->type = BMF_ENCAP_TYPE;
912 encapHdr->len = BMF_ENCAP_LEN;
913 encapHdr->reserved = 0;
914 encapHdr->crc32 = htonl(crc32);
916 /* Check with each network interface what needs to be done on it */
917 for (walker = BmfInterfaces; walker != NULL; walker = walker->next)
919 /* Is the forwarding interface OLSR-enabled? */
920 if (walker->olsrIntf != NULL)
922 /* On an OLSR interface: encapsulate and forward packet. */
924 EncapsulateAndForwardPacket(walker, encapsulationUdpData);
928 /* On a non-OLSR interface: what to do?
929 * Answer 1: nothing. Multicast routing between non-OLSR interfaces
930 * is to be done by other protocols (e.g. PIM, DVMRP).
931 * Answer 2 (better): Forward it. */
934 struct sockaddr_ll dest;
936 /* If the encapsulated IP packet is a local broadcast packet,
937 * update its destination address to match the subnet of the network
938 * interface on which the packet is being sent. */
939 CheckAndUpdateLocalBroadcast(ipPacket, &walker->broadAddr);
941 memset(&dest, 0, sizeof(dest));
942 dest.sll_family = AF_PACKET;
943 dest.sll_protocol = htons(ETH_P_IP);
944 dest.sll_ifindex = if_nametoindex(walker->ifName);
945 dest.sll_halen = IFHWADDRLEN;
947 /* Use all-ones as destination MAC address. When the IP destination is
948 * a multicast address, the destination MAC address should normally also
949 * be a multicast address. E.g., when the destination IP is 224.0.0.1,
950 * the destination MAC should be 01:00:5e:00:00:01. However, it does not
951 * seem to matter when the destination MAC address is set to all-ones
953 memset(dest.sll_addr, 0xFF, IFHWADDRLEN);
955 nBytesWritten = sendto(
956 walker->capturingSkfd,
960 (struct sockaddr*) &dest,
962 if (nBytesWritten != ipPacketLen)
964 OLSR_WARN(LOG_PLUGINS, "sendto() error forwarding pkt on \"%s\"", walker->ifName);
968 /* Increase counter */
969 walker->nBmfPacketsTx++;
973 "forwarded from non-OLSR to non-OLSR \"%s\"\n",
978 } /* BmfTunPacketCaptured */
980 /* -------------------------------------------------------------------------
982 * Description: Wait (blocking) for IP packets, then call the handler for each
987 * Data Used : BmfInterfaces
988 * ------------------------------------------------------------------------- */
989 static void DoBmf(void)
992 unsigned char rxBuffer[BMF_BUFFER_SIZE];
995 assert(HighestSkfd >= 0);
997 /* Make a local copy of the set of file descriptors that select() can
998 * modify to indicate which descriptors actually changed status */
1001 /* Wait (blocking) for packets received on any of the sockets.
1002 * NOTE: don't use a timeout (last parameter). It causes a high system CPU load! */
1003 nFdBitsSet = select(HighestSkfd + 1, &rxFdSet, NULL, NULL, NULL);
1008 OLSR_WARN(LOG_PLUGINS, "select() error");
1013 while (nFdBitsSet > 0)
1015 struct TBmfInterface* walker;
1017 /* Check if a packet was received on the capturing socket (if any)
1018 * of each network interface */
1019 for (walker = BmfInterfaces; walker != NULL; walker = walker->next)
1021 int skfd = walker->capturingSkfd;
1022 if (skfd >= 0 && (FD_ISSET(skfd, &rxFdSet)))
1024 struct sockaddr_ll pktAddr;
1025 socklen_t addrLen = sizeof(pktAddr);
1027 unsigned char* ipPacket;
1029 /* A packet was captured. */
1033 /* Receive the captured Ethernet frame, leaving space for the BMF
1034 * encapsulation header */
1035 ipPacket = GetIpPacket(rxBuffer);
1039 BMF_BUFFER_SIZE - ENCAP_HDR_LEN,
1041 (struct sockaddr*)&pktAddr,
1045 OLSR_WARN(LOG_PLUGINS, "recvfrom() error on \"%s\"", walker->ifName);
1048 } /* if (nBytes < 0) */
1050 /* Check if the number of received bytes is large enough for an IP
1051 * packet which contains at least a minimum-size IP header.
1052 * Note: There is an apparent bug in the packet socket implementation in
1053 * combination with VLAN interfaces. On a VLAN interface, the value returned
1054 * by 'recvfrom' may (but need not) be 4 (bytes) larger than the value
1055 * returned on a non-VLAN interface, for the same ethernet frame. */
1056 if (nBytes < (int)sizeof(struct ip))
1060 "captured frame too short (%d bytes) on \"%s\"\n",
1067 if (pktAddr.sll_pkttype == PACKET_OUTGOING ||
1068 pktAddr.sll_pkttype == PACKET_MULTICAST ||
1069 pktAddr.sll_pkttype == PACKET_BROADCAST)
1071 /* A multicast or broadcast packet was captured */
1073 BmfPacketCaptured(walker, pktAddr.sll_pkttype, rxBuffer);
1075 } /* if (pktAddr.sll_pkttype == ...) */
1076 } /* if (skfd >= 0 && (FD_ISSET...)) */
1079 /* Check if a BMF encapsulation packet was received on the listening
1080 * socket (if any) of each network interface */
1081 for (walker = BmfInterfaces; walker != NULL; walker = walker->next)
1083 int skfd = walker->listeningSkfd;
1084 if (skfd >= 0 && (FD_ISSET(skfd, &rxFdSet)))
1086 struct sockaddr_ll pktAddr;
1087 socklen_t addrLen = sizeof(pktAddr);
1090 struct ip* ipHeader;
1091 struct udphdr* udpHeader;
1093 union olsr_ip_addr forwardedBy;
1094 union olsr_ip_addr forwardedTo;
1096 /* Heard a BMF packet */
1105 (struct sockaddr*)&pktAddr,
1109 OLSR_WARN(LOG_PLUGINS, "recvfrom() error on \"%s\"", walker->ifName);
1112 } /* if (nBytes < 0) */
1114 /* Check if the received packet is actually directed to another
1115 * node on the LAN */
1116 if (pktAddr.sll_pkttype != PACKET_OTHERHOST)
1118 /* No, the packet is directed to this node. In that case it will
1119 * be, or will already have been received, via the encapsulating
1120 * socket. Discard it here. */
1122 } /* if (pktAddr.sll_pkttype ...) */
1124 /* Check if the received packet is UDP - BMF port */
1125 ipHeader = (struct ip*)rxBuffer;
1126 if (ipHeader->ip_p != SOL_UDP)
1132 udpHeader = (struct udphdr*)(rxBuffer + GetIpHeaderLength(rxBuffer));
1133 destPort = ntohs(udpHeader->dest);
1134 if (destPort != BMF_ENCAP_PORT)
1140 /* Check if the number of received bytes is large enough for a minimal BMF
1141 * encapsulation packet, at least:
1142 * - the IP header of the encapsulation IP packet
1143 * - the UDP header of the encapsulation IP packet
1144 * - the encapsulation header
1145 * - a minimum IP header inside the encapsulated packet
1146 * Note: on a VLAN interface, the value returned by 'recvfrom' may (but need
1147 * not) be 4 (bytes) larger than the value returned on a non-VLAN interface, for
1148 * the same ethernet frame. */
1150 GetIpHeaderLength(rxBuffer) +
1151 sizeof(struct udphdr) +
1154 if (nBytes < minimumLength)
1158 "captured a too short encapsulation packet (%d bytes) on \"%s\"\n",
1165 forwardedBy.v4 = ipHeader->ip_src;
1166 forwardedTo.v4 = ipHeader->ip_dst;
1167 BmfEncapsulationPacketReceived(
1171 rxBuffer + GetIpHeaderLength(rxBuffer) + sizeof(struct udphdr));
1173 } /* if (skfd >= 0 && (FD_ISSET...)) */
1176 /* Check if a packet was received on the encapsulating socket (if any)
1177 * of each network interface */
1178 for (walker = BmfInterfaces; walker != NULL; walker = walker->next)
1180 int skfd = walker->encapsulatingSkfd;
1181 if (skfd >= 0 && (FD_ISSET(skfd, &rxFdSet)))
1183 struct sockaddr_in from;
1184 socklen_t fromLen = sizeof(from);
1187 union olsr_ip_addr forwardedBy;
1189 /* An encapsulated packet was received */
1198 (struct sockaddr*)&from,
1202 OLSR_WARN(LOG_PLUGINS, "recvfrom() error on \"%s\"", walker->ifName);
1205 } /* if (nBytes < 0) */
1207 forwardedBy.v4 = from.sin_addr;
1209 /* Check if the number of received bytes is large enough for a minimal BMF
1210 * encapsulation packet, at least:
1211 * - the encapsulation header
1212 * - a minimum IP header inside the encapsulated packet */
1216 if (nBytes < minimumLength)
1218 struct ipaddr_str buf;
1221 "received a too short encapsulation packet (%d bytes) from %s on \"%s\"\n",
1223 olsr_ip_to_string(&buf, &forwardedBy),
1229 /* Unfortunately, the recvfrom call does not return the destination
1230 * of the encapsulation packet (the destination may be either the
1231 * my unicast or my local broadcast address). Therefore we fill in 'NULL'
1232 * for the 'forwardedTo' parameter. */
1233 BmfEncapsulationPacketReceived(walker, &forwardedBy, NULL, rxBuffer);
1235 } /* if (skfd >= 0 && (FD_ISSET...)) */
1238 if (nFdBitsSet > 0 && FD_ISSET(EtherTunTapFd, &rxFdSet))
1240 /* Check if an application has sent a packet out via the tuntap
1241 * network interface */
1244 unsigned char* ipPacket;
1245 unsigned char* bufferToRead;
1246 size_t nBytesToRead;
1250 /* Receive the packet, leaving space for the BMF encapsulation header */
1251 ipPacket = GetIpPacket(rxBuffer);
1253 bufferToRead = ipPacket;
1254 nBytesToRead = BMF_BUFFER_SIZE - ENCAP_HDR_LEN;
1256 nBytes = read(EtherTunTapFd, bufferToRead, nBytesToRead);
1260 OLSR_WARN(LOG_PLUGINS, "recvfrom() error on \"%s\"", EtherTunTapIfName);
1264 /* Check if the number of received bytes is large enough for an IP
1265 * packet which contains at least a minimum-size IP header */
1266 if (nBytes < (int)sizeof(struct ip))
1270 "captured packet too short (%d bytes) on \"%s\"\n",
1276 /* An outbound packet was captured */
1278 BmfTunPacketCaptured(rxBuffer);
1280 } /* if (nBytes < ... */
1281 } /* if (nBytes < 0) */
1282 } /* if (nFdBitsSet > 0 && ... */
1283 } /* while (nFdBitsSet > 0) */
1286 /* -------------------------------------------------------------------------
1287 * Function : BmfSignalHandler
1288 * Description: Signal handler function
1289 * Input : signo - signal being handled
1292 * Data Used : BmfThreadRunning
1293 * ------------------------------------------------------------------------- */
1294 static void BmfSignalHandler(int signo __attribute__((unused)))
1296 BmfThreadRunning = 0;
1297 } /* BmfSignalHandler */
1299 /* -------------------------------------------------------------------------
1301 * Description: Receiver thread function
1302 * Input : useless - not used
1305 * Data Used : BmfThreadRunning
1306 * Notes : Another thread can gracefully stop this thread by sending
1308 * ------------------------------------------------------------------------- */
1309 static void* BmfRun(void* useless __attribute__((unused)))
1311 /* Mask all signals except SIGALRM */
1312 sigset_t blockedSigs;
1313 sigfillset(&blockedSigs);
1314 sigdelset(&blockedSigs, SIGALRM);
1315 if (pthread_sigmask(SIG_BLOCK, &blockedSigs, NULL) != 0)
1317 OLSR_WARN(LOG_PLUGINS, "pthread_sigmask() error");
1320 /* Set up the signal handler for the process: use SIGALRM to terminate
1321 * the BMF thread. Only if a signal handler is specified, does a blocking
1322 * system call return with errno set to EINTR; if a signal hander is not
1323 * specified, any system call in which the thread may be waiting will not
1324 * return. Note that the BMF thread is usually blocked in the select()
1325 * function (see DoBmf()). */
1326 if (signal(SIGALRM, BmfSignalHandler) == SIG_ERR)
1328 OLSR_WARN(LOG_PLUGINS, "signal() error");
1331 /* Call the thread function until flagged to exit */
1332 while (BmfThreadRunning != 0)
1340 /* -------------------------------------------------------------------------
1341 * Function : InterfaceChange
1342 * Description: Callback function passed to OLSRD for it to call whenever a
1343 * network interface has been added, removed or updated
1344 * Input : interf - the network interface to deal with
1345 * action - indicates if the specified network interface was
1346 * added, removed or updated.
1350 * ------------------------------------------------------------------------- */
1351 int InterfaceChange(struct interface* interf, int action)
1355 case (IFCHG_IF_ADD):
1356 AddInterface(interf);
1357 OLSR_DEBUG(LOG_PLUGINS, "interface %s added\n", interf->int_name);
1360 case (IFCHG_IF_REMOVE):
1361 /* We cannot just remove the interface, because the receive-thread is likely
1362 * to be waiting in select(...) for packets coming in via the interface.
1363 * Therefore we first close BMF (CloseBmf()), interrupting and kiling the
1364 * receive-thread so that it is safe to remove this (and all other)
1365 * interfaces. After that, BMF is re-started (InitBmf(interf)). */
1368 OLSR_DEBUG(LOG_PLUGINS, "interface %s removed\n", interf->int_name);
1371 case (IFCHG_IF_UPDATE):
1372 OLSR_DEBUG(LOG_PLUGINS, "interface %s updated\n", interf->int_name);
1378 "interface %s: error - unknown action (%d)\n",
1379 interf->int_name, action);
1384 } /* InterfaceChange */
1387 /* -------------------------------------------------------------------------
1388 * Function : SetFanOutLimit
1389 * Description: Overrule the default fan out limit value (2)
1390 * Input : value - fan out limit value (1...MAX_UNICAST_NEIGHBORS)
1394 * Return : success (0) or fail (1)
1395 * Data Used : FanOutLimit
1396 * ------------------------------------------------------------------------- */
1399 void* data __attribute__((unused)),
1400 set_plugin_parameter_addon addon __attribute__((unused)))
1402 if (set_plugin_int(value, &FanOutLimit, addon) == 0)
1404 /* Extra check if within range */
1405 if (FanOutLimit >= 1 && FanOutLimit <= MAX_UNICAST_NEIGHBORS)
1413 /* -------------------------------------------------------------------------
1414 * Function : InitBmf
1415 * Description: Initialize the BMF plugin
1416 * Input : skipThisIntf - specifies which network interface should not
1417 * be enabled for BMF. Pass NULL if not applicable.
1419 * Return : fail (0) or success (1)
1420 * Data Used : BmfThreadRunning, BmfThread
1421 * ------------------------------------------------------------------------- */
1422 int InitBmf(struct interface* skipThisIntf)
1424 CreateBmfNetworkInterfaces(skipThisIntf);
1426 /* Start running the multicast packet processing thread */
1427 BmfThreadRunning = 1;
1428 if (pthread_create(&BmfThread, NULL, BmfRun, NULL) != 0)
1430 OLSR_WARN(LOG_PLUGINS, "pthread_create() error");
1434 if (EtherTunTapFd >= 0)
1436 /* Deactivate IP spoof filter for EtherTunTap interface */
1437 DeactivateSpoofFilter();
1439 /* If the BMF network interface has a sensible IP address, it is a good idea
1440 * to route all multicast traffic through that interface */
1441 if (EtherTunTapIp != ETHERTUNTAPDEFAULTIP)
1443 AddMulticastRoute();
1450 /* -------------------------------------------------------------------------
1451 * Function : CloseBmf
1452 * Description: Close the BMF plugin and clean up
1456 * Data Used : BmfThread
1457 * ------------------------------------------------------------------------- */
1460 if (EtherTunTapFd >= 0)
1462 /* If there is a multicast route, try to delete it first */
1463 DeleteMulticastRoute();
1465 /* Restore IP spoof filter for EtherTunTap interface */
1466 RestoreSpoofFilter();
1469 if (BmfThreadRunning)
1471 /* Signal BmfThread to exit */
1472 /* Strangely enough, all running threads receive the SIGALRM signal. But only the
1473 * BMF thread is affected by this signal, having specified a handler for this
1474 * signal in its thread entry function BmfRun(...). */
1475 if (pthread_kill(BmfThread, SIGALRM) != 0)
1477 OLSR_WARN(LOG_PLUGINS, "pthread_kill() error");
1480 /* Wait for BmfThread to acknowledge */
1481 if (pthread_join(BmfThread, NULL) != 0)
1483 OLSR_WARN(LOG_PLUGINS, "pthread_join() error");
1487 /* Clean up after the BmfThread has been killed */
1488 CloseBmfNetworkInterfaces();
1495 * indent-tabs-mode: nil