* replaced the bmf plugin with the most recent 1.3 from sf.net with the
[olsrd.git] / lib / bmf / src / Bmf.c
index 7cefe69..c5a3c40 100644 (file)
  * OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-/* $Id: Bmf.c,v 1.1 2006/05/03 08:59:04 kattemat Exp $ */
+/* -------------------------------------------------------------------------
+ * File       : Bmf.c
+ * Description: Multicast forwarding functions
+ * Created    : 29 Jun 2006
+ *
+ * $Id: Bmf.c,v 1.2 2007/02/10 17:05:55 bernd67 Exp $ 
+ * ------------------------------------------------------------------------- */
 
 #define _MULTI_THREADED
 
 #include <errno.h> /* errno */
 #include <assert.h> /* assert() */
 #include <linux/if_packet.h> /* struct sockaddr_ll, PACKET_MULTICAST */
-#include <pthread.h> /* pthread_create() */
-#include <signal.h> /* SIGINT */
+#include <pthread.h> /* pthread_t, pthread_create() */
+#include <signal.h> /* sigset_t, sigfillset(), sigdelset(), SIGINT */
+#include <netinet/ip.h> /* struct ip */
 
 /* OLSRD includes */
-#include "defs.h" /* olsr_cnf */
+#include "defs.h" /* olsr_cnf, OLSR_PRINTF */
 #include "olsr.h" /* olsr_printf */
 #include "scheduler.h" /* olsr_register_scheduler_event */
 #include "mid_set.h" /* mid_lookup_main_addr() */
 #include "mpr_selector_set.h" /* olsr_lookup_mprs_set() */
+#include "link_set.h" /* get_best_link_to_neighbor() */
 
 /* Plugin includes */
 #include "NetworkInterfaces.h" /* TBmfInterface, CreateBmfNetworkInterfaces(), CloseBmfNetworkInterfaces() */
 static pthread_t BmfThread;
 static int BmfThreadRunning = 0;
 
+/* -------------------------------------------------------------------------
+ * Function   : EncapsulateAndForwardPacket
+ * Description: Encapsulate a captured raw IP packet and forward it
+ * Input      : intf - the network interface on which to forward the packet
+ *              buffer - space for the encapsulation header, followed by
+ *                the captured packet
+ *              len - the number of octets in the encapsulation header plus
+ *                captured packet
+ * Output     : none
+ * Return     : none
+ * Data Used  : none
+ * ------------------------------------------------------------------------- */
+static void EncapsulateAndForwardPacket(struct TBmfInterface* intf, unsigned char* buffer, ssize_t len)
+{
+  unsigned char* ethPkt = buffer + ENCAP_HDR_LEN;
+  int nBytesWritten;
+  struct sockaddr_in encapDest;
+
+  /* Change encapsulated source MAC address to that of sending interface */
+  memcpy(ethPkt + IFHWADDRLEN, intf->macAddr, IFHWADDRLEN);
+
+  /* Destination address is local broadcast */
+  memset(&encapDest, 0, sizeof(encapDest));
+  encapDest.sin_family = AF_INET;
+  encapDest.sin_port = htons(BMF_ENCAP_PORT);
+  encapDest.sin_addr.s_addr = ((struct sockaddr_in*)&intf->olsrIntf->int_broadaddr)->sin_addr.s_addr;
+
+  nBytesWritten = sendto(
+    intf->encapsulatingSkfd,
+    buffer,
+    len,
+    MSG_DONTROUTE,
+    (struct sockaddr*) &encapDest,
+    sizeof(encapDest));                   
+  if (nBytesWritten != len)
+  {
+    olsr_printf(
+      1,
+      "%s: sendto() error forwarding pkt to \"%s\": %s\n",
+      PLUGIN_NAME,
+      intf->ifName,
+      strerror(errno));
+  }
+  else
+  {
+    OLSR_PRINTF(
+      9,
+      "%s: --> encapsulated and forwarded to \"%s\"\n",
+      PLUGIN_NAME_SHORT,
+      intf->ifName);
+  } /* if (nBytesWritten != len) */
+}
 
-static void BmfPacketCaptured(struct TBmfInterface* intf, unsigned char* buffer, ssize_t len)
+/* -------------------------------------------------------------------------
+ * Function   : BmfPacketCaptured
+ * Description: Handle a captured raw IP packet
+ * Input      : intf - the network interface on which the packet was captured
+ *              sllPkttype - the type of packet. Either PACKET_OUTGOING,
+ *                PACKET_BROADCAST or PACKET_MULTICAST.
+ *              buffer - space for the encapsulation header, followed by
+ *                the captured packet
+ *              len - the number of octets in the encapsulation header plus
+ *                captured packet
+ * Output     : none
+ * Return     : none
+ * Data Used  : BmfInterfaces
+ * Notes      : The packet is assumed to be captured on a socket of family
+ *              PF_PACKET and type SOCK_RAW.
+ * ------------------------------------------------------------------------- */
+static void BmfPacketCaptured(
+  struct TBmfInterface* intf,
+  unsigned char sllPkttype,
+  unsigned char* buffer,
+  ssize_t len)
 {
-  struct interface* ifFrom;
   unsigned char* srcMac;
   union olsr_ip_addr srcIp;
   union olsr_ip_addr destIp;
-  union olsr_ip_addr* originator;
-  struct sockaddr_in sin;
+  union olsr_ip_addr* origIp;
   struct TBmfInterface* nextFwIntf;
+  int isFromOlsrIntf;
+  int isFromOlsrNeighbor;
+  int iAmMpr;
+  unsigned char* ethPkt = buffer + ENCAP_HDR_LEN;
+  ssize_t ethPktLen = len - ENCAP_HDR_LEN;
+  struct ip* ipData;
+  u_int32_t crc32;
+  struct TEncapHeader* encapHdr;
 
   /* Only forward IPv4 packets */
   u_int16_t type;
-  memcpy(&type, buffer + ETH_TYPE_OFFSET, 2);
+  memcpy(&type, ethPkt + ETH_TYPE_OFFSET, 2);
   if (ntohs(type) != IPV4_TYPE)
   {
     return;
   }
 
-  /* Lookup the OLSR interface on which this packet is received */
-  ifFrom = intf->olsrIntf;
+  ipData = (struct ip*)(ethPkt + IP_HDR_OFFSET);
 
-  /* Only forward multicast or local broadcast packets */
-  COPY_IP(&destIp, buffer + IP_HDR_OFFSET + IPV4_OFFSET_DSTIP);
-  if (! IsMulticast(&destIp) && ! IsLocalBroadcast(&destIp, ifFrom))
+  /* Only forward multicast packets. Also forward local broadcast packets,
+   * if configured */
+  COPY_IP(&destIp, &ipData->ip_dst);
+  if (IsMulticast(&destIp) ||
+      (EnableLocalBroadcast != 0 && IsLocalBroadcast(&destIp, &intf->broadAddr)))
   {
-    return;
+    /* continue */
   }
-  
-  /* Discard OLSR packets (UDP port 698) and BMF encapsulated packets
-   * (UDP port 50505) */
-  if (IsOlsrOrBmfPacket(buffer, len))
+  else
   {
     return;
   }
 
-  /* Apply drop list for testing purposes. */
-  srcMac = buffer + IFHWADDRLEN;
-  if (IsInDropList(srcMac))
+  /* Discard OLSR packets (UDP port 698) and BMF encapsulated packets */
+  if (IsOlsrOrBmfPacket(intf, ethPkt, ethPktLen))
   {
     return;
   }
 
-  /* Lookup main address of source */
-       COPY_IP(&srcIp, buffer + IP_HDR_OFFSET + IPV4_OFFSET_SRCIP);
-  originator = mid_lookup_main_addr(&srcIp);
-  if (originator == NULL)
-  {
-    originator = &srcIp;
-  }
+  /* Check if this packet is captured on an OLSR-enabled interface */
+  isFromOlsrIntf = (intf->olsrIntf != NULL);
 
-  olsr_printf(
+  COPY_IP(&srcIp, &ipData->ip_src);
+  OLSR_PRINTF(
     9,
-    "MC pkt to %s received from originator %s (%s) via \"%s\"\n",
-    olsr_ip_to_string(&destIp),
-    olsr_ip_to_string(originator),
+    "%s: %s pkt of %d bytes captured on %s interface \"%s\": %s->%s\n",
+    PLUGIN_NAME_SHORT,
+    sllPkttype == PACKET_OUTGOING ? "outgoing" : "incoming",
+    ethPktLen,
+    isFromOlsrIntf ? "OLSR" : "non-OLSR",
+    intf->ifName,
     olsr_ip_to_string(&srcIp),
-    intf->ifName);
+    olsr_ip_to_string(&destIp));
 
-  /* Check if I am MPR for that originator */
-  if (ifFrom != NULL && olsr_lookup_mprs_set(originator) == NULL)
+  /* Apply drop list for testing purposes. */
+  srcMac = ethPkt + IFHWADDRLEN;
+  if (IsInDropList(srcMac))
   {
-    olsr_printf(
+    OLSR_PRINTF(
       9,
-      "--> Discarding pkt: I am not selected as MPR by that originator\n");
+      "%s: --> discarding: source MAC (%.2x:%.2x:%.2x:%.2x:%.2x:%.2x) found in drop list\n",
+      PLUGIN_NAME_SHORT,
+      *srcMac, *(srcMac + 1), *(srcMac + 2), *(srcMac + 3), *(srcMac + 4), *(srcMac + 5));
     return;
   }
 
-  /* If this packet is captured on a non-OLSR interface, decrease
-   * the TTL and re-calculate the IP header checksum */
-  if (ifFrom == NULL)
+  /* Lookup main address of source in the MID table of OLSR */
+  origIp = mid_lookup_main_addr(&srcIp);
+  if (origIp == NULL)
   {
-    PacketDecreaseTtlAndUpdateHeaderChecksum(buffer);
+    origIp = &srcIp;
   }
 
-  /* If the TTL is <= 0, do not forward this packet */
-  if (GetIpTtl(buffer) <= 0)
+#ifdef DO_TTL_STUFF
+  /* If this packet is captured on a non-OLSR interface, decrease
+   * the TTL and re-calculate the IP header checksum. */
+  if (! isFromOlsrIntf)
+  {
+    DecreaseTtlAndUpdateHeaderChecksum(ethPkt);
+  } */
+
+  /* If the resulting TTL is <= 0, this packet life has ended, so do not forward it */
+  if (GetIpTtl(ethPkt) <= 0)
   {
+    OLSR_PRINTF(
+      9,
+      "%s: --> discarding: TTL=0\n",
+      PLUGIN_NAME_SHORT);
     return;
-  }
+  } */
+#endif
 
   /* Check if this packet was seen recently */
-  if (CheckMarkRecentPacket(buffer, len))
+  crc32 = PacketCrc32(ethPkt, ethPktLen);
+  if (CheckAndMarkRecentPacket(Hash16(crc32)))
   {
-    olsr_printf(
+    OLSR_PRINTF(
       9,
-      "--> Discarding pkt: was a duplicate\n");
+      "%s: --> discarding: packet is duplicate\n",
+      PLUGIN_NAME_SHORT);
     return;
   }
 
-  /* Encapsulate and forward packet on all OLSR interfaces */
-  memset(&sin, 0, sizeof(sin));
-  sin.sin_family = AF_INET;
-  sin.sin_port = htons(BMF_ENCAP_PORT);
+  /* Compose encapsulation header */
+  encapHdr = (struct TEncapHeader*) buffer;
+  memset (encapHdr, 0, ENCAP_HDR_LEN);
+  encapHdr->crc32 = htonl(crc32);
+
+  /* Check if this packet is captured on an OLSR interface from an OLSR neighbor */
+  isFromOlsrNeighbor =
+    (isFromOlsrIntf /* The packet is captured on an OLSR interface... */
+    && get_best_link_to_neighbor(origIp) != NULL); /* ...from an OLSR neighbor */ 
+
+  /* Check with OLSR if I am MPR for that neighbor */
+  iAmMpr = olsr_lookup_mprs_set(origIp) != NULL;
 
+  /* Check with each interface what needs to be done on it */
   nextFwIntf = BmfInterfaces;
   while (nextFwIntf != NULL)
   {
+    int isToOlsrIntf;
+
     struct TBmfInterface* fwIntf = nextFwIntf;
     nextFwIntf = fwIntf->next;
 
-    if (fwIntf->olsrIntf != NULL)
+    /* Is the forwarding interface OLSR-enabled? */
+    isToOlsrIntf = (fwIntf->olsrIntf != NULL);
+
+    /* Depending on certain conditions, we decide whether or not to forward
+     * the packet, and if it is forwarded, in which form (encapsulated
+     * or not, TTL decreased or not). These conditions are:
+     * - is the packet is coming in on an OLSR interface or not? (isFromOlsrIntf)
+     * - is the packet going out on an OLSR interface or not? (isToOlsrIntf)
+     * - if the packet if coming in on an OLSR interface:
+     *   - is the node that forwarded the packet my OLSR-neighbor? (isFromOlsrNeighbor)
+     *   - has the node that forwarded the packet selected me as MPR? (iAmMpr)
+     *
+     * Based on these conditions, the following cases can be distinguished:
+     *
+     * - Case 1: Packet coming in on an OLSR interface. What to
+     *   do with it on an OLSR interface?
+     *   Answer:
+     *   - Case 1.1: If the forwarding node is an OLSR neighbor that has *not*
+     *     selected me as MPR: don't forward the packet.
+     *   - Case 1.2: If the forwarding node is an OLSR neighbor that has selected
+     *     me as MPR: encapsulate and forward the packet.
+     *   - Case 1.3: If the forwarding node is not an OLSR neighbor: encapsulate
+     *     and forward the packet.
+     *     NOTE: Case 1.3 is a special case. In the perfect world, we expect to
+     *     see only OLSR-neighbors on OLSR-enabled interfaces. Sometimes, however,
+     *     ignorant users will connect a host not running OLSR, to a LAN in
+     *     which there are hosts running OLSR. Of course these ignorant users,
+     *     expecting magic, want to see their multicast packets being forwarded
+     *     through the network.
+     *
+     * - Case 2: Packet coming in on an OLSR interface. What to do with it on a
+     *   non-OLSR interface?
+     *   Answer: [Decrease the packet's TTL and] forward it.
+     *
+     * - Case 3: Packet coming in on a non-OLSR interface. What to
+     *   do with it on an OLSR interface?
+     *   Answer: [Decrease the packet's TTL, then] encapsulate and forward it.
+     *
+     * - Case 4: Packet coming in on non-OLSR interface. What to do with it on a
+     *   non-OLSR interface?
+     *   Answer 1: nothing. Multicast routing between non-OLSR interfaces
+     *   is to be done by other protocols (e.g. PIM, DVMRP).
+     *   Answer 2 (better): [Decrease the packet's TTL, then] forward it.
+     */
+
+    if (isFromOlsrIntf && isToOlsrIntf)
     {
-      int nBytesWritten;
+      /* Case 1: Forward from an OLSR interface to an OLSR interface */
 
-      /* Change source MAC address to that of myself */
-      memcpy(buffer + IFHWADDRLEN, fwIntf->macAddr, IFHWADDRLEN);
-
-      /* Destination address is local broadcast */
-      sin.sin_addr.s_addr = ((struct sockaddr_in*)&fwIntf->olsrIntf->int_broadaddr)->sin_addr.s_addr;
+      if (isFromOlsrNeighbor && !iAmMpr)
+      {
+        /* Case 1.1 */
+        {
+          OLSR_PRINTF(
+            9,
+            "%s: --> not encap-forwarding to \"%s\": I am not selected as MPR by neighbor %s\n",
+            PLUGIN_NAME_SHORT,
+            fwIntf->ifName,
+            olsr_ip_to_string(&srcIp));
+        }    
+      }
+      else if (sllPkttype == PACKET_OUTGOING && intf == fwIntf)
+      {
+        OLSR_PRINTF(
+          9,
+          "%s: --> not encap-forwarding to \"%s\": pkt was captured on that interface\n",
+          PLUGIN_NAME_SHORT,
+          fwIntf->ifName);
+      }
+      else
+      {
+        /* Case 1.2 and 1.3 */
+        EncapsulateAndForwardPacket(fwIntf, buffer, len);
+      }
+    } /* if (isFromOlsrIntf && isToOlsrIntf) */
 
-      nBytesWritten = sendto(
-        fwIntf->encapsulatingSkfd,
-        buffer,
-        len,
-        MSG_DONTROUTE,
-        (struct sockaddr*) &sin,
-        sizeof(sin));                   
+    else if (isFromOlsrIntf && !isToOlsrIntf)
+    {
+      /* Case 2: Forward from OLSR interface to non-OLSR interface.
+       * [Decrease TTL and] forward */
 
-      if (nBytesWritten != len)
+#ifdef DO_TTL_STUFF
+      /* If the TTL is to become 0, do not forward this packet */
+      if (GetIpTtl(ethPkt) <= 1)
       {
-        olsr_printf(
-          1,
-          "%s: sendto() error forwarding MC pkt for %s to \"%s\": %s\n",
-          PLUGIN_NAME,
-          olsr_ip_to_string(&destIp),
-          fwIntf->olsrIntf->int_name,
-          strerror(errno));
+        OLSR_PRINTF(
+          9,
+          "%s: --> not forwarding to \"%s\": TTL=0\n",
+          PLUGIN_NAME_SHORT,
+          fwIntf->ifName);
       }
       else
       {
-        olsr_printf(
+        struct TSaveTtl sttl;
+#endif
+        int nBytesWritten;
+
+        /* Change source MAC address to that of sending interface */
+        memcpy(ethPkt + IFHWADDRLEN, fwIntf->macAddr, IFHWADDRLEN);
+
+        /* If the destination address is not a multicast address, it is assumed to be
+         * a local broadcast packet. Update the destination address to match the subnet
+         * of the network interface on which the packet is being sent. */
+        CheckAndUpdateLocalBroadcast(ethPkt, &fwIntf->broadAddr);
+
+#ifdef DO_TTL_STUFF
+        /* Save IP header checksum and the TTL-value of the packet */ 
+        SaveTtlAndChecksum(ethPkt, &sttl);
+
+        /* Decrease the TTL by 1 before writing */
+        DecreaseTtlAndUpdateHeaderChecksum(ethPkt);
+#endif
+
+        nBytesWritten = write(fwIntf->capturingSkfd, ethPkt, ethPktLen);
+        if (nBytesWritten != ethPktLen)
+        {
+          olsr_printf(
+            1,
+            "%s: write() error forwarding pkt for %s to \"%s\": %s\n",
+            PLUGIN_NAME,
+            olsr_ip_to_string(&destIp),
+            fwIntf->ifName,
+            strerror(errno));
+        }
+        else
+        {
+          OLSR_PRINTF(
+            9,
+            "%s: --> forwarded to \"%s\"\n",
+            PLUGIN_NAME_SHORT,
+            fwIntf->ifName);
+        }
+
+#ifdef DO_TTL_STUFF
+        /* Restore the IP header checksum and the TTL-value of the packet */
+        RestoreTtlAndChecksum(ethPkt, &sttl);
+
+      } /* if (GetIpTtl(ethPkt) <= 1) */
+#endif
+    } /* else if (isFromOlsrIntf && !isToOlsrIntf) */
+
+    else if (!isFromOlsrIntf && isToOlsrIntf)
+    {
+      /* Case 3: Forward from a non-OLSR interface to an OLSR interface.
+       * Encapsulate and forward packet.
+       * Note that packets from non-OLSR interfaces already had their TTL decreased. */
+
+      EncapsulateAndForwardPacket(fwIntf, buffer, len);
+    } /* else if (!isFromOlsrIntf && isToOlsrIntf) */
+
+    else
+    {
+      /* Case 4: Forward from non-OLSR interface to non-OLSR interface.
+       * Note that packets from non-OLSR interfaces already had their TTL decreased. */
+
+      /* Don't forward on interface on which packet was received */
+      if (intf == fwIntf)
+      {
+        OLSR_PRINTF(
           9,
-          "Successfully encapsulated one MC pkt for %s to \"%s\"\n",
-          olsr_ip_to_string(&destIp),
-          fwIntf->olsrIntf->int_name);
-      } /* if (nBytesWritten != len) */
-    } /* if (fwIntf->olsrIntf != NULL) */
+          "%s: --> not forwarding to \"%s\": pkt was captured on that interface\n",
+          PLUGIN_NAME_SHORT,
+          fwIntf->ifName);
+      }
+
+#ifdef DO_TTL_STUFF
+      /* If the TTL is <= 0, do not forward this packet */
+      else if (GetIpTtl(ethPkt) <= 0)
+      {
+        OLSR_PRINTF(
+          9,
+          "%s: --> not forwarding to \"%s\": TTL=0\n",
+          PLUGIN_NAME_SHORT,
+          fwIntf->ifName);
+      }
+#endif
+      else
+      {
+        int nBytesWritten;
+
+        /* Change source MAC address to that of sending interface */
+        memcpy(ethPkt + IFHWADDRLEN, fwIntf->macAddr, IFHWADDRLEN);
+
+        /* If the destination address is not a multicast address, it is assumed to be
+         * a local broadcast packet. Update the destination address to match the subnet
+         * of the network interface on which the packet is being sent. */
+        CheckAndUpdateLocalBroadcast(ethPkt, &fwIntf->broadAddr);
+
+        nBytesWritten = write(fwIntf->capturingSkfd, ethPkt, ethPktLen);
+        if (nBytesWritten != ethPktLen)
+        {
+          olsr_printf(
+            1,
+            "%s: write() error forwarding pkt for %s to \"%s\": %s\n",
+            PLUGIN_NAME,
+            olsr_ip_to_string(&destIp),
+            fwIntf->ifName,
+            strerror(errno));
+        }
+        else
+        {
+          OLSR_PRINTF(
+            9,
+            "%s: --> forwarded from non-OLSR to non-OLSR \"%s\"\n",
+            PLUGIN_NAME_SHORT,
+            fwIntf->ifName);
+        }
+      } /* if (intf == fwIntf) */
+    }
   } /* while (nextFwIntf != NULL) */
 }
 
+/* -------------------------------------------------------------------------
+ * Function   : BmfEncapsulatedPacketReceived
+ * Description: Handle a received BMF-encapsulated IP packet
+ * Input      : intf - the network interface on which the packet was received
+ *              fromIp - the IP node that forwarded the packet to us
+ *              buffer - the received encapsulated packet
+ *              len - the number of octets in the received encapsulated packet
+ * Output     : none
+ * Return     : none
+ * Data Used  : BmfInterfaces
+ * Notes      : The packet is assumed to be received on a socket of family
+ *              PF_INET and type SOCK_DGRAM (UDP).
+ * ------------------------------------------------------------------------- */
 static void BmfEncapsulatedPacketReceived(
   struct TBmfInterface* intf, 
-  struct in_addr srcIp,
+  union olsr_ip_addr* fromIp,
   unsigned char* buffer,
   ssize_t len)
 {
-  union olsr_ip_addr fromAddr;
-  struct interface* ifFrom;
   union olsr_ip_addr* forwarder;
   int nBytesToWrite;
   unsigned char* bufferToWrite;
   int nBytesWritten;
   int iAmMpr;
-  struct sockaddr_in sin;
+  struct sockaddr_in encapDest;
   struct TBmfInterface* nextFwIntf;
-
-  COPY_IP(&fromAddr, &srcIp.s_addr);
+  struct ip* ipData;
+  unsigned char* ethPkt;
+  ssize_t ethPktLen;
+  struct TEncapHeader* encapHdr;
 
   /* Are we talking to ourselves? */
-  if (if_ifwithaddr(&fromAddr) != NULL)
+  if (if_ifwithaddr(fromIp) != NULL)
   {
     return;
   }
 
-  /* Lookup the OLSR interface on which this packet is received */
-  ifFrom = intf->olsrIntf;
-
   /* Encapsulated packet received on non-OLSR interface? Then discard */
-  if (ifFrom == NULL)
+  if (intf->olsrIntf == NULL)
   {
     return;
   }
@@ -242,74 +535,86 @@ static void BmfEncapsulatedPacketReceived(
    * chain, e.g.:
    * iptables -A FORWARD -m mac --mac-source 00:0C:29:28:0E:CC -j DROP */
 
-  /* Lookup main address of forwarding node */
-  forwarder = mid_lookup_main_addr(&fromAddr);
-  if (forwarder == NULL)
-  {
-    forwarder = &fromAddr;
-    olsr_printf(
-      9,
-      "Encapsulated MC pkt received; forwarder to me by %s on \"%s\"\n",
-      olsr_ip_to_string(forwarder),
-      intf->ifName);
-  }
-  else
-  {
-    olsr_printf(
-      9,
-      "Encapsulated MC pkt received; forwarder to me by %s (thru %s) on \"%s\"\n",
-      olsr_ip_to_string(forwarder),
-      olsr_ip_to_string(&fromAddr),
-      intf->ifName);
-  }
+  ethPkt = buffer + ENCAP_HDR_LEN;
+  ethPktLen = len - ENCAP_HDR_LEN;
+
+  ipData = (struct ip*) (ethPkt + IP_HDR_OFFSET);
+
+  OLSR_PRINTF(
+    9,
+    "%s: encapsulated pkt of %d bytes incoming on \"%s\": %s->",
+    PLUGIN_NAME_SHORT,
+    ethPktLen,
+    intf->ifName,
+    inet_ntoa(ipData->ip_src));
+  OLSR_PRINTF(
+    9,
+    "%s, forwarded by %s\n",
+    inet_ntoa(ipData->ip_dst), /* not possible to call inet_ntoa twice in same printf */
+    olsr_ip_to_string(fromIp));
+
+  /* Get encapsulation header */
+  encapHdr = (struct TEncapHeader*) buffer;
 
   /* Check if this packet was seen recently */
-  if (CheckMarkRecentPacket(buffer, len))
+  if (CheckAndMarkRecentPacket(Hash16(ntohl(encapHdr->crc32))))
   {
-    olsr_printf(
+    OLSR_PRINTF(
       9,
-      "--> Discarding encapsulated pkt: was a duplicate\n");
+      "%s: --> discarding: packet is duplicate\n",
+      PLUGIN_NAME_SHORT);
     return;
   }
 
-  /* Unpack encapsulated packet and send a copy to myself via the EtherTunTap device */
-  nBytesToWrite = len;
-  bufferToWrite = buffer;
-  if (TunOrTap == TT_TUN)
-  {
-    nBytesToWrite -= IP_HDR_OFFSET;
-    bufferToWrite += IP_HDR_OFFSET;
-  }
-  nBytesWritten = write(EtherTunTapFd, bufferToWrite, nBytesToWrite);
-  if (nBytesWritten != nBytesToWrite)
+  if (EtherTunTapFd >= 0)
   {
-    olsr_printf(
-      1,
-      "%s: write() error sending encapsulated MC pkt to \"%s\": %s\n",
-      PLUGIN_NAME,
-      EtherTunTapIfName,
-      strerror(errno));
+    struct sockaddr broadAddr;
+
+    /* Unpack encapsulated packet and send a copy to myself via the EtherTunTap interface */
+    bufferToWrite = ethPkt;
+    nBytesToWrite = ethPktLen;
+    if (TunOrTap == TT_TUN)
+    {
+      bufferToWrite += IP_HDR_OFFSET;
+      nBytesToWrite -= IP_HDR_OFFSET;
+    }
+
+    ((struct sockaddr_in*)&broadAddr)->sin_addr.s_addr = htonl(EtherTunTapIpBroadcast);
+    CheckAndUpdateLocalBroadcast(ethPkt, &broadAddr);
+
+    nBytesWritten = write(EtherTunTapFd, bufferToWrite, nBytesToWrite);
+    if (nBytesWritten != nBytesToWrite)
+    {
+      olsr_printf(
+        1,
+        "%s: write() error forwarding encapsulated pkt to \"%s\": %s\n",
+        PLUGIN_NAME,
+        EtherTunTapIfName,
+        strerror(errno));
+    }
+    else
+    {
+      OLSR_PRINTF(
+        9,
+        "%s: --> unpacked and forwarded to \"%s\"\n",
+        PLUGIN_NAME_SHORT,
+        EtherTunTapIfName);
+    }
   }
-  else
+
+  /* Lookup main address of forwarding node */
+  forwarder = mid_lookup_main_addr(fromIp);
+  if (forwarder == NULL)
   {
-    olsr_printf(
-      9,
-      "Successfully unpacked and sent encapsulated MC pkt to \"%s\"\n",
-      EtherTunTapIfName);
+    forwarder = fromIp;
   }
 
   /* Check if I am MPR for the forwarder */
   iAmMpr = (olsr_lookup_mprs_set(forwarder) != NULL);
-  if (! iAmMpr)
-  {
-    olsr_printf(
-      9,
-      "--> Not forwarding encapsulated pkt: I am not selected as MPR by that forwarder\n");
-  }
 
-  memset(&sin, 0, sizeof(sin));
-  sin.sin_family = AF_INET;
-  sin.sin_port = htons(BMF_ENCAP_PORT);
+  memset(&encapDest, 0, sizeof(encapDest));
+  encapDest.sin_family = AF_INET;
+  encapDest.sin_port = htons(BMF_ENCAP_PORT);
 
   nextFwIntf = BmfInterfaces;
   while (nextFwIntf != NULL)
@@ -317,123 +622,310 @@ static void BmfEncapsulatedPacketReceived(
     struct TBmfInterface* fwIntf = nextFwIntf;
     nextFwIntf = fwIntf->next;
 
-    /* On non-OLSR interfaces: unpack encapsulated packet, decrease TTL
-     * and send */
+    /* Depending on certain conditions, decide whether or not to forward
+     * the packet, and if it is forwarded, in which form (encapsulated
+     * or not). These conditions are:
+     * - is the packet going out on an OLSR interface or not? (isToOlsrIntf)
+     * - is this node selected as MPR by the node that forwarded the packet,
+     *   or not? (iAmMpr)
+     * Note that the packet is always coming in on an OLSR interface, because
+     * it is an encapsulated BMF packet.
+     *
+     * Based on these conditions, 3 cases can be distinguished:
+     * - Case 1: What to do with the packet on a non-OLSR interface?
+     *   Answer: unpack encapsulated packet, [decrease its TTL and] forward it.
+     * - Case 2: The forwarding node has selected us as MPR. What to
+     *   do with the packet on an OLSR interface?
+     *   Answer: Forward it.
+     * - Case 3: The forwarding node has not selected us as MPR. What to
+     *   do with the packet on an OLSR interface?
+     *   Answer: nothing. Nodes not selected as MPR must not participate in
+     *   the flooding.
+     */
+
+    /* Forward from OLSR interface to non-OLSR interface: unpack encapsulated
+     * packet, [decrease TTL] and forward */
     if (fwIntf->olsrIntf == NULL)
     {
-      struct TSaveTtl sttl;
-
-      /* Change source MAC address to that of sending interface */
-      memcpy(buffer + IFHWADDRLEN, fwIntf->macAddr, IFHWADDRLEN);
-
-      /* Save IP header checksum and the TTL-value of the packet, then 
-       * decrease the TTL by 1 before writing */
-      SaveTtlAndChecksum(buffer, &sttl);
-      PacketDecreaseTtlAndUpdateHeaderChecksum(buffer);
-
-      /* If the TTL is <= 0, do not forward this packet */
-      if (GetIpTtl(buffer) <= 0)
-      {
-        return;
-      }
-
-      nBytesWritten = write(fwIntf->capturingSkfd, buffer, len);
-      if (nBytesWritten != len)
+#ifdef DO_TTL_STUFF
+      /* If the TTL is to become 0, do not forward this packet */
+      if (GetIpTtl(ethPkt) <= 1)
       {
-        olsr_printf(
-          1,
-          "%s: write() error sending unpacked encapsulated MC pkt to \"%s\": %s\n",
-          PLUGIN_NAME,
-          fwIntf->ifName,
-          strerror(errno));
-      }
-      else
-      {
-        olsr_printf(
+        OLSR_PRINTF(
           9,
-          "Successfully unpacked and sent one encapsulated MC pkt to \"%s\"\n",
+          "%s: --> not forwarding on \"%s\": TTL=0\n",
+          PLUGIN_NAME_SHORT,
           fwIntf->ifName);
       }
+      else
+      {
+        struct TSaveTtl sttl;
+#endif
+
+        /* If the destination address is not a multicast address, it is assumed to be
+         * a local broadcast packet. Update the destination address to match the subnet
+         * of the network interface on which the packet is being sent. */
+        CheckAndUpdateLocalBroadcast(ethPkt, &fwIntf->broadAddr);
+
+#ifdef DO_TTL_STUFF
+        /* Save IP header checksum and the TTL-value of the packet, then 
+         * decrease the TTL by 1 before writing */
+        SaveTtlAndChecksum(ethPkt, &sttl);
+
+        /* Decrease the TTL by 1 before writing */
+        DecreaseTtlAndUpdateHeaderChecksum(ethPkt);
+#endif
+
+        nBytesWritten = write(fwIntf->capturingSkfd, ethPkt, ethPktLen);
+        if (nBytesWritten != ethPktLen)
+        {
+          olsr_printf(
+            1,
+            "%s: write() error forwarding unpacked encapsulated pkt to \"%s\": %s\n",
+            PLUGIN_NAME,
+            fwIntf->ifName,
+            strerror(errno));
+        }
+        else
+        {
+          OLSR_PRINTF(
+            9,
+            "%s: --> unpacked and forwarded to \"%s\"\n",
+            PLUGIN_NAME_SHORT,
+            fwIntf->ifName);
+        }
+
+#ifdef DO_TTL_STUFF
+        /* Restore the IP header checksum and the TTL-value of the packet */
+        RestoreTtlAndChecksum(ethPkt, &sttl);
 
-      /* Restore the IP header checksum and the TTL-value of the packet */
-      RestoreTtlAndChecksum(buffer, &sttl);
+      } /* if (GetIpTtl(ethPkt) <= 1) */
+#endif
     } /* if (fwIntf->olsrIntf == NULL) */
 
-    /* On OLSR interfaces, forward the packet if this node is selected as MPR by the 
-     * forwarding node */
+    /* Forward from OLSR interface to OLSR interface: forward the packet if this
+     * node is selected as MPR by the forwarding node */
     else if (iAmMpr)
     {
       /* Change source MAC address to that of sending interface */
       memcpy(buffer + IFHWADDRLEN, fwIntf->macAddr, IFHWADDRLEN);
 
       /* Destination address is local broadcast */
-      sin.sin_addr.s_addr = ((struct sockaddr_in*)&fwIntf->olsrIntf->int_broadaddr)->sin_addr.s_addr;
+      encapDest.sin_addr.s_addr = ((struct sockaddr_in*)&fwIntf->olsrIntf->int_broadaddr)->sin_addr.s_addr;
 
       nBytesWritten = sendto(
         fwIntf->encapsulatingSkfd,
         buffer,
         len,
         MSG_DONTROUTE,
-        (struct sockaddr*) &sin,
-        sizeof(sin));                   
+        (struct sockaddr*) &encapDest,
+        sizeof(encapDest));                   
 
       if (nBytesWritten != len)
       {
         olsr_printf(
           1,
-          "%s: sendto() error forwarding encapsulated MC pkt to \"%s\": %s\n",
+          "%s: sendto() error forwarding encapsulated pkt via \"%s\": %s\n",
           PLUGIN_NAME,
-          fwIntf->olsrIntf->int_name,
+          fwIntf->ifName,
           strerror(errno));
       }
       else
       {
-        olsr_printf(
+        OLSR_PRINTF(
           9,
-          "Successfully forwarded one encapsulated MC pkt to \"%s\"\n",
-          fwIntf->olsrIntf->int_name);
+          "%s: --> forwarded to \"%s\"\n",
+          PLUGIN_NAME_SHORT,
+          fwIntf->ifName);
       }
-    } /* else if (iAmMpr) */
+    }  /* else if (iAmMpr) */
+    else /* fwIntf->olsrIntf != NULL && !iAmMpr */
+    {
+      /* fwIntf is an OLSR interface and I am not selected as MPR */
+      OLSR_PRINTF(
+        9,
+        "%s: --> not forwarding to \"%s\": I am not selected as MPR by %s\n",
+        PLUGIN_NAME_SHORT,
+        fwIntf->ifName,
+        olsr_ip_to_string(fromIp));
+    }
   } /* while (nextFwIntf != NULL) */
 }
 
-static void DoBmf(void* useless)
+/* -------------------------------------------------------------------------
+ * Function   : BmfTunPacketCaptured
+ * Description: Handle a raw IP packet captured outgoing on the tuntap interface
+ * Input      : buffer - space for the encapsulation header, followed by
+ *                the captured packet
+ *              len - the number of octets in the encapsulation header plus
+ *                captured packet
+ * Output     : none
+ * Return     : none
+ * Data Used  : none
+ * Notes      : The packet is assumed to be captured on a socket of family
+ *              PF_PACKET and type SOCK_RAW.
+ * ------------------------------------------------------------------------- */
+static void BmfTunPacketCaptured(
+  unsigned char* buffer,
+  ssize_t len)
 {
-#define BUFFER_MAX 2048
-  struct TBmfInterface* intf;
-  int nFdBitsSet;
+  union olsr_ip_addr srcIp;
+  union olsr_ip_addr destIp;
+  struct TBmfInterface* nextFwIntf;
+  unsigned char* ethPkt = buffer + ENCAP_HDR_LEN;
+  ssize_t ethPktLen = len - ENCAP_HDR_LEN;
+  struct ip* ipData;
+  u_int32_t crc32;
+  struct TEncapHeader* encapHdr;
+  struct sockaddr broadAddr;
+  u_int16_t type;
+
+  /* Only forward IPv4 packets */
+  memcpy(&type, ethPkt + ETH_TYPE_OFFSET, 2);
+  if (ntohs(type) != IPV4_TYPE)
+  {
+    return;
+  }
 
-  /* Compose set of socket file descriptors. 
-   * Keep the highest descriptor seen. */
-  int highestSkfd = -1;
-  fd_set input_set;
-  FD_ZERO(&input_set);
+  ipData = (struct ip*)(ethPkt + IP_HDR_OFFSET);
 
-  intf = BmfInterfaces;
-  while (intf != NULL)
+  /* Only forward multicast packets, or local broadcast packets if specified */
+  COPY_IP(&destIp, &ipData->ip_dst);
+  ((struct sockaddr_in*)&broadAddr)->sin_addr.s_addr = htonl(EtherTunTapIpBroadcast);
+  if (IsMulticast(&destIp) ||
+      (EnableLocalBroadcast != 0 && IsLocalBroadcast(&destIp, &broadAddr)))
   {
-    FD_SET(intf->capturingSkfd, &input_set);
-    if (intf->capturingSkfd > highestSkfd)
+    /* continue */
+  }
+  else
+  {
+    return;
+  }
+
+  COPY_IP(&srcIp, &ipData->ip_src);
+  OLSR_PRINTF(
+    9,
+    "%s: outgoing pkt of %d bytes captured on tuntap interface \"%s\": %s->%s\n",
+    PLUGIN_NAME_SHORT,
+    ethPktLen,
+    EtherTunTapIfName,
+    olsr_ip_to_string(&srcIp),
+    olsr_ip_to_string(&destIp));
+
+  /* Check if this packet was seen recently */
+  crc32 = PacketCrc32(ethPkt, ethPktLen);
+  if (CheckAndMarkRecentPacket(Hash16(crc32)))
+  {
+    OLSR_PRINTF(
+      9,
+      "%s: --> discarding: packet is duplicate\n",
+      PLUGIN_NAME_SHORT);
+    return;
+  }
+
+  /* Compose encapsulation header */
+  encapHdr = (struct TEncapHeader*) buffer;
+  memset (encapHdr, 0, ENCAP_HDR_LEN);
+  encapHdr->crc32 = htonl(crc32);
+
+  /* Check with each interface what needs to be done on it */
+  nextFwIntf = BmfInterfaces;
+  while (nextFwIntf != NULL)
+  {
+    int isToOlsrIntf;
+
+    struct TBmfInterface* fwIntf = nextFwIntf;
+    nextFwIntf = fwIntf->next;
+
+    /* Is the forwarding interface OLSR-enabled? */
+    isToOlsrIntf = (fwIntf->olsrIntf != NULL);
+
+    /* Depending on certain conditions, we decide whether or not to forward
+     * the packet, and if it is forwarded, in which form (encapsulated
+     * or not). These conditions are:
+     * - is the packet going out on an OLSR interface or not? (isToOlsrIntf)
+     *
+     * Based on these conditions, the following cases can be distinguished:
+     *
+     * - Case 1: What to do with a packet for an OLSR interface?
+     *   Answer: Encapsulate and forward it.
+     *
+     * - Case 2: What to do with a packet for a non-OLSR interface?
+     *   Answer 1: nothing. Multicast routing between non-OLSR interfaces
+     *   is to be done by other protocols (e.g. PIM, DVMRP).
+     *   Answer 2 (better): Forward it.
+     */
+
+    if (isToOlsrIntf)
     {
-      highestSkfd = intf->capturingSkfd;
-    }
+      /* Case 1: Forward to an OLSR interface.
+       * Encapsulate and forward packet. */
 
-    if (intf->encapsulatingSkfd >= 0)
+      EncapsulateAndForwardPacket(fwIntf, buffer, len);
+    }
+    else
     {
-      FD_SET(intf->encapsulatingSkfd, &input_set);
-      if (intf->encapsulatingSkfd > highestSkfd)
+      /* Case 2: Forward to a non-OLSR interface. */
+
+      int nBytesWritten;
+
+      /* Change source MAC address to that of sending interface */
+      memcpy(ethPkt + IFHWADDRLEN, fwIntf->macAddr, IFHWADDRLEN);
+
+      /* If the destination address is not a multicast address, it is assumed to be
+       * a local broadcast packet. Update the destination address to match the subnet
+       * of the network interface on which the packet is being sent. */
+      CheckAndUpdateLocalBroadcast(ethPkt, &fwIntf->broadAddr);
+
+      nBytesWritten = write(fwIntf->capturingSkfd, ethPkt, ethPktLen);
+      if (nBytesWritten != ethPktLen)
       {
-        highestSkfd = intf->encapsulatingSkfd;
+        olsr_printf(
+          1,
+          "%s: write() error forwarding pkt for %s to \"%s\": %s\n",
+          PLUGIN_NAME,
+          olsr_ip_to_string(&destIp),
+          fwIntf->ifName,
+          strerror(errno));
       }
-    }
+      else
+      {
+        OLSR_PRINTF(
+          9,
+          "%s: --> forwarded from non-OLSR to non-OLSR \"%s\"\n",
+          PLUGIN_NAME_SHORT,
+          fwIntf->ifName);
+      }
+    } /* if (isToOlsrIntf) */
+  } /* while (nextFwIntf != NULL) */
+}
 
-    intf = intf->next;    
-  }
+/* -------------------------------------------------------------------------
+ * Function   : DoBmf
+ * Description: Wait (blocking) for IP packets, then call the handler for each
+ *              received packet
+ * Input      : none
+ * Output     : none
+ * Return     : none
+ * Data Used  : BmfInterfaces
+ * ------------------------------------------------------------------------- */
+static void DoBmf(void)
+{
+  struct TBmfInterface* currIf;
+  int nFdBitsSet;
+  /*unsigned char* rxBuffer = malloc(BMF_BUFFER_SIZE);*/
+  unsigned char rxBuffer[BMF_BUFFER_SIZE];
+  fd_set rxFdSet;
+
+  assert(HighestSkfd >= 0/* && rxBuffer != NULL*/);
 
-  assert(highestSkfd >= 0);
+  /* Make a local copy of the set of file descriptors that select() can
+   * modify to indicate which descriptors actually changed status */
+  rxFdSet = InputSet;
 
-  /* Wait (blocking) for packets received on any of the sockets */
-  nFdBitsSet = select(highestSkfd + 1, &input_set, NULL, NULL, NULL);
+  /* Wait (blocking) for packets received on any of the sockets.
+   * NOTE: don't use a timeout (last parameter). It causes a high system CPU load! */
+  nFdBitsSet = select(HighestSkfd + 1, &rxFdSet, NULL, NULL, NULL);
   if (nFdBitsSet < 0)
   {
     if (errno != EINTR)
@@ -442,109 +934,277 @@ static void DoBmf(void* useless)
     }
     return;
   }
-    
-  if (nFdBitsSet == 0)
-  {
-    /* No packets waiting. This is unexpected; normally we would excpect select(...)
-     * to return only if at least one packet was received (so nFdBitsSet > 0), or
-     * if this thread received a signal (so nFdBitsSet < 0). */
-    return;
-  }
 
   while (nFdBitsSet > 0)
   {
-    intf = BmfInterfaces;
-    while (intf != NULL)
+    /* Check if a packet was received on the capturing socket (if any)
+     * of each network interface */
+    struct TBmfInterface* nextIf = BmfInterfaces;
+    while (nextIf != NULL)
     {
-      int skfd = intf->capturingSkfd;
-      if (FD_ISSET(skfd, &input_set))
+      int skfd;
+
+      currIf = nextIf;
+      nextIf = currIf->next;
+
+      skfd = currIf->capturingSkfd;
+      if (skfd >= 0 && (FD_ISSET(skfd, &rxFdSet)))
       {
-        unsigned char buffer[BUFFER_MAX];
         struct sockaddr_ll pktAddr;
-        socklen_t addrLen;
+        socklen_t addrLen = sizeof(pktAddr);
         int nBytes;
+        unsigned char* ethPkt;
 
-        /* A packet was captured */
+        /* A packet was captured. */
 
         nFdBitsSet--;
 
-        memset(&pktAddr, 0, sizeof(struct sockaddr_ll));
-        addrLen = sizeof(pktAddr);
-
-        nBytes = recvfrom(skfd, buffer, BUFFER_MAX, 0, (struct sockaddr*)&pktAddr, &addrLen);
+        /* Receive the packet, leaving space for the BMF encapsulation header */
+        ethPkt = rxBuffer + ENCAP_HDR_LEN;
+        nBytes = recvfrom(
+          skfd,
+          ethPkt,
+          BMF_BUFFER_SIZE - ENCAP_HDR_LEN,
+          0,
+          (struct sockaddr*)&pktAddr,
+          &addrLen);
         if (nBytes < 0)
         {
-          olsr_printf(1, "%s: recvfrom() error: %s\n", PLUGIN_NAME, strerror(errno));
+          olsr_printf(
+            1,
+            "%s: recvfrom() error on \"%s\": %s\n",
+            PLUGIN_NAME,
+            currIf->ifName,
+            strerror(errno));
         }
-
-        /* Don't let BMF crash by sending too short packets. IP packets are always
-         * at least 14 (Ethernet header) + 20 (IP header) = 34 bytes long. */
-        if (nBytes >= 34)
+        else if (nBytes < IP_HDR_OFFSET + (int)sizeof(struct iphdr))
+        {
+          olsr_printf(
+            1,
+            "%s: captured packet too short (%d bytes) on \"%s\"\n",
+            PLUGIN_NAME,
+            nBytes,
+            currIf->ifName);
+        }
+        else
         {
-          if (pktAddr.sll_pkttype == PACKET_OUTGOING)
+          /* Don't trust the number of bytes as returned from 'recvfrom':
+           * that number may be 4 bytes too large, in case the receiving
+           * network interface is a VLAN interface. */
+          nBytes = IP_HDR_OFFSET + GetIpPacketLength(ethPkt);
+
+          /* Don't let BMF crash by sending too short packets */
+          if (nBytes >= IP_HDR_OFFSET + GetIpHeaderLength(ethPkt))
           {
-            union olsr_ip_addr destIp;
-            COPY_IP(&destIp, buffer + IP_HDR_OFFSET + IPV4_OFFSET_DSTIP);
-            if (IsMulticast(&destIp) || IsLocalBroadcast(&destIp, intf->olsrIntf))
+            if (pktAddr.sll_pkttype == PACKET_OUTGOING ||
+                pktAddr.sll_pkttype == PACKET_MULTICAST ||
+                pktAddr.sll_pkttype == PACKET_BROADCAST)
             {
-              if (! IsOlsrOrBmfPacket(buffer, nBytes))
-              {
-                MarkRecentPacket(buffer, nBytes);
-              }
+              /* A multicast or broadcast packet was captured */
+              BmfPacketCaptured(currIf, pktAddr.sll_pkttype, rxBuffer, nBytes + ENCAP_HDR_LEN);
             }
           }
-          else if (pktAddr.sll_pkttype == PACKET_MULTICAST ||
-                   pktAddr.sll_pkttype == PACKET_BROADCAST)
+          else
           {
-            BmfPacketCaptured(intf, buffer, nBytes);
+            olsr_printf(
+              1,
+              "%s: captured packet too short (%d bytes) on \"%s\"\n",
+              PLUGIN_NAME,
+              nBytes,
+              currIf->ifName);
           }
-        } /* if (nBytes >= 34) */
-      } /* if (FD_ISSET...) */
+        } /* if (nBytes < 0) */
+      } /* if (skfd >= 0 && (FD_ISSET...)) */
+    } /* while (nextIf != NULL) */
+    
+    /* Check if a packet was received on the encapsulating socket (if any)
+     * of each network interface */
+    nextIf = BmfInterfaces;
+    while (nextIf != NULL)
+    {
+      int skfd;
+
+      currIf = nextIf;
+      nextIf = currIf->next;
 
-      skfd = intf->encapsulatingSkfd;
-      if (skfd >= 0 && (FD_ISSET(skfd, &input_set)))
+      skfd = currIf->encapsulatingSkfd;
+      if (skfd >= 0 && (FD_ISSET(skfd, &rxFdSet)))
       {
-        unsigned char buffer[BUFFER_MAX];
-        struct sockaddr_in addr;
-        socklen_t addrLen = sizeof(addr);
+        struct sockaddr_in from;
+        socklen_t fromLen = sizeof(from);
         int nBytes;
 
         /* An encapsulated packet was received */
 
         nFdBitsSet--;
 
-        memset(&addr, 0, sizeof(addr));
-
-        nBytes = recvfrom(skfd, buffer, BUFFER_MAX, 0, (struct sockaddr*)&addr, &addrLen);
+        nBytes = recvfrom(
+          skfd,
+          rxBuffer,
+          BMF_BUFFER_SIZE,
+          0,
+          (struct sockaddr*)&from,
+          &fromLen);
         if (nBytes < 0)
         {
-          olsr_printf(1, "%s: recvfrom() error: %s\n", PLUGIN_NAME, strerror(errno));
+          olsr_printf(
+            1,
+            "%s: recvfrom() error on \"%s\": %s\n",
+            PLUGIN_NAME,
+            currIf->ifName,
+            strerror(errno));
         }
-        if (nBytes > 0)
+        else
         {
-          BmfEncapsulatedPacketReceived(intf, addr.sin_addr, buffer, nBytes);
+          /* Don't let BMF crash by sending too short packets. */
+          if (nBytes >= IP_HDR_OFFSET + GetIpHeaderLength(rxBuffer))
+          {
+            union olsr_ip_addr srcIp;
+            COPY_IP(&srcIp, &from.sin_addr.s_addr);
+            BmfEncapsulatedPacketReceived(currIf, &srcIp, rxBuffer, nBytes);
+          }
+          else
+          {
+            olsr_printf(
+              1,
+              "%s: encapsulated packet too short (%d bytes) from %s on \"%s\"\n",
+              PLUGIN_NAME,
+              nBytes,
+              inet_ntoa(from.sin_addr),
+              currIf->ifName);
+          }
+        } /* if (nBytes < 0) */
+      } /* if (skfd >= 0 && (FD_ISSET...)) */
+    } /* while (nextIf != NULL) */
+
+    if (nFdBitsSet > 0 && FD_ISSET(EtherTunTapFd, &rxFdSet))
+    {
+      /* Check if an application has sent a packet to the tuntap
+       * network interface */
+
+      int nBytes;
+      unsigned char* ethPkt;
+      unsigned char* bufferToRead;
+      size_t nBytesToRead;
+
+      nFdBitsSet--;
+
+      /* Receive the packet, leaving space for the BMF encapsulation header */
+      ethPkt = rxBuffer + ENCAP_HDR_LEN;
+    
+      bufferToRead = ethPkt;
+      nBytesToRead = BMF_BUFFER_SIZE - ENCAP_HDR_LEN;
+      if (TunOrTap == TT_TUN)
+      {
+        u_int16_t type;
+
+        /* When using a tun-interface, also leave space for an Ethernet header */
+        bufferToRead += IP_HDR_OFFSET;
+        nBytesToRead -= IP_HDR_OFFSET;
+
+        /* Compose an Ethernet header, in case other BMF-nodes are receiving
+         * their BMF packets on a tap-interface. */
+
+        /* Use all-ones as destination MAC address. When the IP destination is
+         * a multicast address, the destination MAC address should normally also
+         * be a multicast address. E.g., when the destination IP is 224.0.0.1,
+         * the destination MAC should be 01:00:5e:00:00:01. However, it does not
+         * seem to matter when the destination MAC address is set to all-ones
+         * in that case. */
+        memset(ethPkt, 0xFF, IFHWADDRLEN);
+
+        /* Source MAC address is not important. Set to all-zeros */
+        memset(ethPkt + IFHWADDRLEN, 0x00, IFHWADDRLEN);
+
+        /* Ethertype = 0800 = IP */
+        type = htons(0x0800);
+        memcpy(ethPkt + ETH_TYPE_OFFSET, &type, 2);
+      }
+
+      nBytes = read(
+        EtherTunTapFd,
+        bufferToRead,
+        nBytesToRead);
+
+      if (nBytes < 0)
+      {
+        if (errno != EAGAIN)
+        {
+          olsr_printf(
+            1,
+            "%s: recvfrom() error on \"%s\": %s\n",
+            PLUGIN_NAME,
+            EtherTunTapIfName,
+            strerror(errno));
         }
-      } /* if (skfd >= 0 && (FD_ISSET...) */
+      }
+      else if (nBytes < (int)sizeof(struct iphdr))
+      {
+        olsr_printf(
+          1,
+          "%s: captured packet too short (%d bytes) on \"%s\"\n",
+          PLUGIN_NAME,
+          nBytes,
+          EtherTunTapIfName);
+      }
+      else
+      {
+        /* Don't trust the number of bytes as returned from 'recvfrom':
+         * that number may be 4 bytes too large, in case the receiving
+         * network interface is a VLAN interface. */
+        nBytes = IP_HDR_OFFSET + GetIpPacketLength(ethPkt);
 
-      intf = intf->next;    
-    } /* while (intf != NULL) */
+        /* Don't let BMF crash by sending too short packets */
+        if (nBytes >= IP_HDR_OFFSET + GetIpHeaderLength(ethPkt))
+        {
+          /* An outbound packet was captured */
+          BmfTunPacketCaptured(rxBuffer, nBytes + ENCAP_HDR_LEN);
+        }
+        else
+        {
+          olsr_printf(
+            1,
+            "%s: captured packet too short (%d bytes) on \"%s\"\n",
+            PLUGIN_NAME,
+            nBytes,
+            EtherTunTapIfName);
+        } /* if (nBytes >= IP_HDR_OFFSET... */
+      } /* if (nBytes < 0) */
+    } /* if (nFdBitsSet > 0 && ... */
   } /* while (nFdBitsSet > 0) */
+  /*free(rxBuffer);*/
 }
 
+/* -------------------------------------------------------------------------
+ * Function   : BmfSignalHandler
+ * Description: Signal handler function
+ * Input      : signo - signal being handled
+ * Output     : none
+ * Return     : none
+ * Data Used  : BmfThreadRunning
+ * ------------------------------------------------------------------------- */
 static void BmfSignalHandler(int signo)
 {
-  /* Dummy handler function */
-  return;
+  BmfThreadRunning = 0;
 }
 
-/* Thread entry function. Another thread can gracefully stop this thread by writing a
- * '0' into global variable 'BmfThreadRunning' followed by sending a SIGALRM signal. */
+/* -------------------------------------------------------------------------
+ * Function   : BmfRun
+ * Description: Receiver thread function
+ * Input      : useless - not used
+ * Output     : none
+ * Return     : not used
+ * Data Used  : BmfThreadRunning
+ * Notes      : Another thread can gracefully stop this thread by sending
+ *              a SIGALRM signal.
+ * ------------------------------------------------------------------------- */
 static void* BmfRun(void* useless)
 {
+  /* Mask all signals except SIGALRM */
   sigset_t blockedSigs;
   sigfillset(&blockedSigs);
   sigdelset(&blockedSigs, SIGALRM);
-  if (pthread_sigmask(SIG_BLOCK, &blockedSigs, NULL) < 0)
+  if (pthread_sigmask(SIG_BLOCK, &blockedSigs, NULL) != 0)
   {
     olsr_printf(1, "%s: pthread_sigmask() error: %s\n", PLUGIN_NAME, strerror(errno));
   }
@@ -563,47 +1223,93 @@ static void* BmfRun(void* useless)
   /* Call the thread function until flagged to exit */
   while (BmfThreadRunning != 0)
   {
-    DoBmf(useless);
+    DoBmf();
   }
-  
+
   return NULL;
 }
 
-/* Initialize the BMF plugin */
-int InitBmf()
+/* -------------------------------------------------------------------------
+ * Function   : InterfaceChange
+ * Description: Callback function passed to OLSRD for it to call whenever a
+ *              network interface has been added, removed or updated
+ * Input      : interf - the network interface to deal with
+ *              action - indicates if the specified network interface was
+ *                added, removed or updated.
+ * Output     : none
+ * Return     : always 0
+ * Data Used  : none
+ * ------------------------------------------------------------------------- */
+int InterfaceChange(struct interface* interf, int action)
 {
-  /* Check validity */
-  if (olsr_cnf->ip_version != AF_INET)
+  switch (action)
   {
-    fprintf(stderr, PLUGIN_NAME ": This plugin only supports IPv4!\n");
-    return 0;
+  case (IFCHG_IF_ADD):
+    AddInterface(interf);
+    olsr_printf(1, "%s: interface %s added\n", PLUGIN_NAME, interf->int_name);
+    break;
+
+  case (IFCHG_IF_REMOVE):
+    /* We cannot just remove the interface, because the receive-thread is likely
+     * to be waiting in select(...) for packets coming in via the interface.
+     * Therefore we first close BMF (CloseBmf()), interrupting and kiling the
+     * receive-thread so that it is safe to remove this (and all other)
+     * interfaces. After that, BMF is re-started (InitBmf(interf)). */
+    CloseBmf();
+    InitBmf(interf);
+    olsr_printf(1, "%s: interface %s removed\n", PLUGIN_NAME, interf->int_name);
+    break;
+
+  case (IFCHG_IF_UPDATE):
+    olsr_printf(1, "%s: interface %s updated\n", PLUGIN_NAME, interf->int_name);
+    break;
+      
+  default:
+    olsr_printf(
+      1,
+      "%s: interface %s: error - unknown action (%d)\n",
+      PLUGIN_NAME,
+      interf->int_name, action);
+    break;
   }
+  return 0;
+}
 
-  /* Clear the packet history */
-  InitPacketHistory();
+/* -------------------------------------------------------------------------
+ * Function   : InitBmf
+ * Description: Initialize the BMF plugin
+ * Input      : skipThisIntf - specifies which network interface should not
+ *              be enabled for BMF. Pass NULL if not applicable.
+ * Output     : none
+ * Return     : fail (0) or success (1)
+ * Data Used  : BmfThreadRunning, BmfThread
+ * ------------------------------------------------------------------------- */
+int InitBmf(struct interface* skipThisIntf)
+{
+  CreateBmfNetworkInterfaces(skipThisIntf);
 
-  if (CreateBmfNetworkInterfaces() < 0)
+  /* Start running the multicast packet processing thread */
+  BmfThreadRunning = 1;
+  if (pthread_create(&BmfThread, NULL, BmfRun, NULL) != 0)
   {
-    fprintf(stderr, PLUGIN_NAME ": could not initialize network interfaces!\n");
+    olsr_printf(1, "%s: pthread_create error: %s\n", PLUGIN_NAME, strerror(errno));
     return 0;
   }
-  
-  /* Run the multicast packet processing thread */
-  BmfThreadRunning = 1;
-  pthread_create(&BmfThread, NULL, BmfRun, NULL);
-
-  /* Register the duplicate registration pruning process */
-  olsr_register_scheduler_event(&PrunePacketHistory, NULL, 3.0, 2.0, NULL);
-
   return 1;
 }
 
-/* Close the BMF plugin */
+/* -------------------------------------------------------------------------
+ * Function   : CloseBmf
+ * Description: Close the BMF plugin and clean up
+ * Input      : none
+ * Output     : none
+ * Return     : none
+ * Data Used  : BmfThreadRunning, BmfThread
+ * ------------------------------------------------------------------------- */
 void CloseBmf()
 {
   /* Signal BmfThread to exit */
-  BmfThreadRunning = 0;
-  if (pthread_kill(BmfThread, SIGALRM) < 0)
+  if (pthread_kill(BmfThread, SIGALRM) != 0)
   /* Strangely enough, all running threads receive the SIGALRM signal. But only the
    * BMF thread is affected by this signal, having specified a handler for this
    * signal in its thread entry function BmfRun(...). */
@@ -612,7 +1318,7 @@ void CloseBmf()
   }
 
   /* Wait for BmfThread to acknowledge */
-  if (pthread_join(BmfThread, NULL) < 0)
+  if (pthread_join(BmfThread, NULL) != 0)
   {
     olsr_printf(1, "%s: pthread_join() error: %s\n", PLUGIN_NAME, strerror(errno));
   }
@@ -621,9 +1327,18 @@ void CloseBmf()
   CloseBmfNetworkInterfaces();
 }
 
+/* -------------------------------------------------------------------------
+ * Function   : RegisterBmfParameter
+ * Description: Register a configuration parameter with the BMF process
+ * Input      : key - the parameter name, e.g. "DropMac" or "NonOlsrIf"
+ *              value - the parameter value
+ * Output     : none
+ * Return     : fatal error (<0), minor error (0) or success (>0)
+ * Data Used  : none
+ * ------------------------------------------------------------------------- */
 int RegisterBmfParameter(char* key, char* value)
 {
-  if (strcmp(key, "Drop") == 0)
+  if (strcmp(key, "DropMac") == 0)
   {
     return DropMac(value);
   }
@@ -631,6 +1346,27 @@ int RegisterBmfParameter(char* key, char* value)
   {
     return AddNonOlsrBmfIf(value);
   }
+  else if (strcmp(key, "DoLocalBroadcast") == 0)
+  {
+    return DoLocalBroadcast(value);
+  }
+  else if (strcmp(key, "BmfInterface") == 0)
+  {
+    return SetBmfInterfaceName(value);
+  }
+  else if (strcmp(key, "BmfInterfaceType") == 0)
+  {
+    return SetBmfInterfaceType(value);
+  }
+  else if (strcmp(key, "BmfInterfaceIp") == 0)
+  {
+    return SetBmfInterfaceIp(value);
+  }
+  else if (strcmp(key, "CapturePacketsOnOlsrInterfaces") == 0)
+  {
+    return SetCapturePacketsOnOlsrInterfaces(value);
+  }
 
+  /* Key not recognized */
   return 0;
 }