* upgrade to olsr-bmf-1.5
authorBernd Petrovitsch <bernd@firmix.at>
Sat, 30 Jun 2007 20:07:47 +0000 (20:07 +0000)
committerBernd Petrovitsch <bernd@firmix.at>
Sat, 30 Jun 2007 20:07:47 +0000 (20:07 +0000)
13 files changed:
lib/bmf/Makefile
lib/bmf/README_BMF.txt
lib/bmf/src/Address.c
lib/bmf/src/Address.h
lib/bmf/src/Bmf.c
lib/bmf/src/Bmf.h
lib/bmf/src/NetworkInterfaces.c
lib/bmf/src/NetworkInterfaces.h
lib/bmf/src/Packet.c
lib/bmf/src/Packet.h
lib/bmf/src/PacketHistory.c
lib/bmf/src/PacketHistory.h
lib/bmf/src/olsrd_plugin.c

index d17a244..9c0f472 100644 (file)
@@ -34,7 +34,7 @@
 
 OLSRD_PLUGIN = true
 PLUGIN_NAME =  olsrd_bmf
-PLUGIN_VER =   1.4
+PLUGIN_VER =   1.5
 
 TOPDIR = ../..
 include $(TOPDIR)/Makefile.inc
index 6d1e377..d3ca257 100644 (file)
@@ -1,6 +1,6 @@
 BASIC MULTICAST FORWARDING PLUGIN FOR OLSRD
 by Erik Tromp (erik.tromp@nl.thalesgroup.com, erik_tromp@hotmail.com)
-Version 1.4
+Version 1.5
 
 1. Introduction
 ---------------
@@ -17,14 +17,14 @@ in the past 3-6 seconds are forwarded.
 2. How to build and install
 ---------------------------
 
-Download the olsr-bmf-v1.4.tar.gz file and save it into your OLSRD
+Download the olsr-bmf-v1.5.tar.gz file and save it into your OLSRD
 base install directory.
 
 Change directory (cd) to your OLSRD base install directory.
 
 At the command prompt, type:
 
-  tar -zxvf ./olsr-bmf-v1.4.tar.gz
+  tar -zxvf ./olsr-bmf-v1.5.tar.gz
 
 then type:
 
@@ -47,7 +47,7 @@ Set permissions, e.g.:
 To configure BMF in OLSR, you must edit the file /etc/olsrd.conf
 to load the BMF plugin. For example, add the following lines:
 
-  LoadPlugin "olsrd_bmf.so.1.4"
+  LoadPlugin "olsrd_bmf.so.1.5"
   {
     # No PlParam entries required for basic operation
   }
@@ -64,8 +64,8 @@ olsrd daemon by entering at the shell prompt:
 Look at the output; it should list the BMF plugin, e.g.:
 
   ---------- Plugin loader ----------
-  Library: olsrd_bmf.so.1.4
-  OLSRD Basic Multicast Forwarding plugin 1.4 (Mar 30 2007 14:30:57)
+  Library: olsrd_bmf.so.1.5
+  OLSRD Basic Multicast Forwarding plugin 1.5 (May 16 2007 14:30:57)
     (C) Thales Communications Huizen, Netherlands
     Erik Tromp (erik.tromp@nl.thalesgroup.com)
   Checking plugin interface version...  4 - OK
@@ -149,7 +149,8 @@ original packets are encapsulated into a new IP packet. Encapsulated
 packets are transported in UDP, port 50698. The source address of the
 encapsulation packet is set to the address of the forwarder instead of
 the originator. Of course, the payload of the encapsulation packet is
-the original IP packet.
+the original IP packet. For an exact specification of the encapsulation
+format, refer to paragraph 10 below.
 
 For local reception, each received encapsulated packets is unpacked
 and passed into a tuntap interface which is specially created for
@@ -189,16 +190,12 @@ the /etc/olsrd.conf file.
 The following gives an overview of all plugin parameters that can be
 configured:
 
-  LoadPlugin "olsrd_bmf.so.1.4"
+  LoadPlugin "olsrd_bmf.so.1.5"
   {
     # Specify the name of the BMF network interface.
     # Defaults to "bmf0".
     PlParam "BmfInterface" "mybmf0"
 
-    # Specify the type of the BMF network interface: either "tun" or
-    # "tap". Defaults to "tun".
-    PlParam "BmfInterfaceType" "tap"
-
     # Specify the IP address and mask for the BMF network interface.
     # By default, the IP address of the first OLSR interface is copied.
     # The default prefix length is 32.
@@ -334,7 +331,7 @@ want to forward multicast and local-broadcast IP packets, specify these
 interfaces one by one as "NonOlsrIf" parameters in the BMF plugin section
 of /etc/olsrd.conf. For example:
 
-  LoadPlugin "olsrd_bmf.so.1.4"
+  LoadPlugin "olsrd_bmf.so.1.5"
   {
     # Non-OLSR interfaces to participate in the multicast flooding
     PlParam     "NonOlsrIf"  "eth2"
@@ -392,7 +389,7 @@ Therefore, override the default IP address and prefix length of
 the BMF network interface, by editing the /etc/olsrd.conf file.
 For example:
 
-  LoadPlugin "olsrd_bmf.so.1.4"
+  LoadPlugin "olsrd_bmf.so.1.5"
   {
       PlParam "BmfInterfaceIp" "10.10.10.4/24"
   }
@@ -454,43 +451,7 @@ packets with their destination IP address in the range 224.0.0.0 -
 TTL is implicitly assumed to be 1).
 
 
-9. Testing in a lab environment
--------------------------------
-
-When using equipment like switches or hubs, usually all the hosts see each
-other. In an OLSR lab environment, we sometimes want to simulate the
-situation that some hosts in the network cannot directly see other hosts
-(as 1-hop neighbors) but only indirectly (as 2- or more-hop neighbors).
-To simulate that situation, the iptables tool is often used (see
-www.netfilter.org). For BMF, however, that is nog enough.
-
-For OLSR testing, setup iptables on each host to drop packets from
-all other hosts which are not direct (1-hop) neigbors. For example, to
-drop all packets from the hosts with MAC addresses 00:0C:29:51:32:88,
-00:0C:29:61:34:B7 and 00:0C:29:28:0E:CC, enter at the shell prompt:
-
-  iptables -A INPUT -m mac --mac-source 00:0C:29:51:32:88 -j DROP
-  iptables -A INPUT -m mac --mac-source 00:0C:29:61:34:B7 -j DROP
-  iptables -A INPUT -m mac --mac-source 00:0C:29:28:0E:CC -j DROP
-
-For BMF testing, edit the file /etc/olsrd.conf, and specify the MAC
-addresses of the hosts we do not want to see. (Even though packets from
-these hosts are dropped by iptables, they are still received on network
-interfaces if they are in promiscuous mode.) For example:
-
-  LoadPlugin "olsrd_bmf.so.1.4"
-  {
-    # Drop all packets received from the following MAC sources
-    PlParam     "DropMac"    "00:0C:29:51:32:88" # RemoteClient1
-    PlParam     "DropMac"    "00:0C:29:61:34:B7" # SimpleClient1
-    PlParam     "DropMac"    "00:0C:29:28:0E:CC" # SimpleClient2
-  }
-
-See also the notes in the 'packet' manpage ("Packet sockets are not
-subject to the input or output firewall chains").
-
-
-10. Common problems, FAQ
+9. Common problems, FAQ
 ------------------------
 
 ---------
@@ -561,9 +522,75 @@ the BMF network interface, either by specifying the interface name itself
 (e.g. "bmf0") or by specifying its IP address.
 
 
-11. Version history
+10. Version history
 -------------------
 
+16 May 2007: Version 1.5
+
+* Improved packet history list to take into account the full 32 bits
+  of the packet fingerprint.
+  Previous versions derived a 16-bits value from the 32-bits packet
+  fingerprint and used that 16-bits value to determine packet unicity. In
+  situations with high packet rates (e.g. multicast video), this leads to
+  packets being incorrectly seen as duplicates of other, previously received
+  packets.
+
+* New encapsulation format. In previous versions, a complete Ethernet
+  frame was encapsulated. This is unnecessary, and not very clean; e.g.
+  from packets coming in on non-Ethernet media such as PPP, the data in
+  the Ethernet header is bogus.
+  The new encapsulation format encapsulates only the IP packet. An
+  outer IP header [1], UDP header [2] and BMF Encapsulation Header are
+  inserted before the datagram's existing IP header, as follows:
+
+                                       +---------------------------+
+                                       |                           |
+                                       |      Outer IP Header      |
+                                       +---------------------------+
+                                       |                           |
+                                       |        UDP Header         |
+                                       +---------------------------+
+                                       |      BMF Encapsulation    |
+                                       |           Header          |
+   +---------------------------+       +---------------------------+
+   |                           |       |                           |
+   |         IP Header         |       |         IP Header         |
+   +---------------------------+ ====> +---------------------------+
+   |                           |       |                           |
+   |         IP Payload        |       |         IP Payload        |
+   |                           |       |                           |
+   |                           |       |                           |
+   +---------------------------+       +---------------------------+
+
+  The BMF encapsulation header has a typical type-length-value (TLV)
+  format:
+
+    0                   1                   2                   3
+    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   |     Type      |    Length     |            Reserved           |
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   |                       Packet fingerprint                      |
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+   Type                1
+
+   Length              6.  Length in bytes of this extension, not
+                       including the Type and Length bytes.
+
+   Reserved            Reserved for future use. MUST be set to 0 on
+                       sending, MUST be verified as 0 on receipt;
+                       otherwise the extension must be handled as not
+                       understood and silently skipped.
+
+   Packet fingerprint  32-bits unique fingerprint inserted by the
+                       encapsulator. MAY be used by the receiver to
+                       determine duplicate packet reception.
+
+  The new encapsulation format is incompatible with those of previous
+  BMF versions, implying that all network nodes need to be updated.
+
+
 31 Mar 2007: Version 1.4
 * Optimized the standard forwarding mechanism in such a way that
   retransmissions of packets are only done on those network interfaces
@@ -643,3 +670,12 @@ the BMF network interface, either by specifying the interface name itself
 27 Apr 2006: Version 1.0.1
 * First release.
 
+
+11. Normative References
+------------------------
+
+   [1]  Postel, J., "Internet Protocol", STD 5, RFC 791, September 1981.
+
+   [2]  Postel, J., "User Datagram Protocol", STD 6, RFC 768, August
+        1980.
+
index 6132818..1fe0f44 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * OLSR Basic Multicast Forwarding (BMF) plugin.
- * Copyright (c) 2005, 2006, Thales Communications, Huizen, The Netherlands.
+ * Copyright (c) 2005 - 2007, Thales Communications, Huizen, The Netherlands.
  * Written by Erik Tromp.
  * All rights reserved.
  *
@@ -128,8 +128,8 @@ int IsOlsrOrBmfPacket(unsigned char* ipPacket)
   }
 
   /* The total length must be at least large enough to store the UDP header */
-  ipHeaderLen = GetHeaderLength(ipPacket);
-  if (GetTotalLength(ipPacket) < ipHeaderLen + sizeof(struct udphdr))
+  ipHeaderLen = GetIpHeaderLength(ipPacket);
+  if (GetIpTotalLength(ipPacket) < ipHeaderLen + sizeof(struct udphdr))
   {
     /* Not long enough */
     return 0;
index 8c73573..1642283 100644 (file)
@@ -3,7 +3,7 @@
 
 /*
  * OLSR Basic Multicast Forwarding (BMF) plugin.
- * Copyright (c) 2005, 2006, Thales Communications, Huizen, The Netherlands.
+ * Copyright (c) 2005 - 2007, Thales Communications, Huizen, The Netherlands.
  * Written by Erik Tromp.
  * All rights reserved.
  *
index 2bf8ae6..103cda9 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * OLSR Basic Multicast Forwarding (BMF) plugin.
- * Copyright (c) 2005, 2006, Thales Communications, Huizen, The Netherlands.
+ * Copyright (c) 2005 - 2007, Thales Communications, Huizen, The Netherlands.
  * Written by Erik Tromp.
  * All rights reserved.
  *
@@ -48,6 +48,7 @@
 #include <stdarg.h> /* va_list, va_start, va_end */
 #include <errno.h> /* errno */
 #include <assert.h> /* assert() */
+#include <linux/if_ether.h> /* ETH_P_IP */
 #include <linux/if_packet.h> /* struct sockaddr_ll, PACKET_MULTICAST */
 #include <pthread.h> /* pthread_t, pthread_create() */
 #include <signal.h> /* sigset_t, sigfillset(), sigdelset(), SIGINT */
@@ -67,7 +68,6 @@
 #include "Address.h" /* IsMulticast() */
 #include "Packet.h" /* ETH_TYPE_OFFSET, IFHWADDRLEN etc. */
 #include "PacketHistory.h" /* InitPacketHistory() */
-#include "DropList.h" /* DropMac() */
 
 static pthread_t BmfThread;
 static int BmfThreadRunning = 0;
@@ -108,7 +108,7 @@ void BmfPError(char* format, ...)
 
     olsr_printf(1, "%s: %s\n", strDesc, strErr);
   }
-}
+} /* BmfPError */
 
 /* -------------------------------------------------------------------------
  * Function   : MainAddressOf
@@ -129,69 +129,14 @@ union olsr_ip_addr* MainAddressOf(union olsr_ip_addr* ip)
     result = ip;
   }
   return result;
-}
-
-/* -------------------------------------------------------------------------
- * Function   : ComposeEnapsulationDestination
- * Description: Compose a next destination for an encapsulated packet
- * Input      : intf - the network interface on which to forward the
- *                encapsulation packet
- *              src - the IP source of the encapsulated packet. Pass NULL if
- *                not applicable.
- *              forwardedBy - the IP address of the last host that forwarded
- *                the packet. Pass NULL if not applicable.
- *              forwardedTo - the IP address to which the last host has
- *                forwarded the packet. Pass NULL if not applicable.
- * Output     : nextDest - the composed next destination
- * Return     : 1 if a valid next destination could be composed, or 0 if not
- * Data Used  : BmfMechanism
- * ------------------------------------------------------------------------- */
-static int ComposeEnapsulationDestination(
-  struct TBmfInterface* intf,
-  union olsr_ip_addr* src,
-  union olsr_ip_addr* forwardedBy,
-  union olsr_ip_addr* forwardedTo,
-  struct sockaddr_in* nextDest)
-{
-  struct link_entry* bestNeighborLink;
-  int nPossibleNeighbors;
-
-  memset(nextDest, 0, sizeof(nextDest));
-  nextDest->sin_family = AF_INET;
-  nextDest->sin_port = htons(BMF_ENCAP_PORT);
-
-  bestNeighborLink = GetBestNeighbor(intf, src, forwardedBy, forwardedTo, &nPossibleNeighbors);
-
-  if (bestNeighborLink != NULL)
-  {
-    /* Depending on the how many neighbors there are, and on the BMF mechanism... */
-    if (nPossibleNeighbors == 1 || BmfMechanism == BM_UNICAST_PROMISCUOUS)
-    {
-      /* ...destination IP address is address of best neighbor... */
-      COPY_IP(&nextDest->sin_addr.s_addr, &bestNeighborLink->neighbor_iface_addr);
-    }
-    else
-    {
-      /* ...or destination IP address is local broadcast. */
-      COPY_IP(&nextDest->sin_addr.s_addr, &intf->broadAddr);
-    }
-  }
-  else
-  {
-    /* No (good enough) neighbor on the specified interface: don't forward
-     * the packet */
-    return 0;
-  }
-
-  return 1;
-}
+} /* MainAddressOf */
 
 /* -------------------------------------------------------------------------
  * Function   : EncapsulateAndForwardPacket
  * Description: Encapsulate a captured raw IP packet and forward it
  * Input      : intf - the network interface on which to forward the packet
  *              encapsulationUdpData - The encapsulation header, followed by
- *                the encapsulated Ethernet frame
+ *                the encapsulated IP packet
  * Output     : none
  * Return     : none
  * Data Used  : none
@@ -200,16 +145,22 @@ static void EncapsulateAndForwardPacket(
   struct TBmfInterface* intf,
   unsigned char* encapsulationUdpData)
 {
-  unsigned char* ethernetFrame = GetEthernetFrame(encapsulationUdpData);
-  int nBytesWritten;
-  struct sockaddr_in forwardTo; /* Next destination of encapsulation packet */
+  /* The packet */
   u_int16_t udpDataLen = GetEncapsulationUdpDataLength(encapsulationUdpData);
 
-  /* Change encapsulated source MAC address to that of sending interface */
-  SetFrameSourceMac(ethernetFrame, intf->macAddr);
+  /* The next destination(s) */
+  struct TBestNeighbors bestNeighborLinks;
+  int nPossibleNeighbors;
+  struct sockaddr_in forwardTo; /* Next destination of encapsulation packet */
 
-  /* Compose destination of encapsulation packet */
-  if (ComposeEnapsulationDestination(intf, NULL, NULL, NULL, &forwardTo) == 0)
+  int nPacketsToSend;
+  int nBytesWritten;
+  int i;
+
+  /* Retrieve at most two best neigbors to forward the packet to */
+  bestNeighborLinks = GetBestTwoNeighbors(intf, NULL, NULL, NULL, &nPossibleNeighbors);
+
+  if (nPossibleNeighbors <= 0)
   {
     OLSR_PRINTF(
       8,
@@ -219,74 +170,100 @@ static void EncapsulateAndForwardPacket(
     return;
   }
 
-  nBytesWritten = sendto(
-    intf->encapsulatingSkfd,
-    encapsulationUdpData,
-    udpDataLen,
-    MSG_DONTROUTE,
-    (struct sockaddr*) &forwardTo,
-    sizeof(forwardTo));                   
-  if (nBytesWritten != udpDataLen)
+  /* Compose destination of encapsulation packet */
+
+  memset(&forwardTo, 0, sizeof(forwardTo));
+  forwardTo.sin_family = AF_INET;
+  forwardTo.sin_port = htons(BMF_ENCAP_PORT);
+
+  /* Start by filling in the local broadcast address */
+  COPY_IP(&forwardTo.sin_addr.s_addr, &intf->broadAddr);
+
+  /* - If the BMF mechanism is BM_UNICAST_PROMISCUOUS, always send just one
+   *   packet (to the best neighbor).
+   * - If the BMF mechanism is BM_BROADCAST,
+   *   - send one unicast packet if there is one possible neighbor,
+   *   - send two unicast packets if there are two possible neighbors, and
+   *   - only if there are more than two possible neighbors, then send an
+   *     (WLAN-air-expensive, less reliable) broadcast packet. */
+  if (BmfMechanism == BM_UNICAST_PROMISCUOUS || nPossibleNeighbors < 2)
   {
-    BmfPError("sendto() error forwarding pkt on \"%s\"", intf->ifName);
+    nPacketsToSend = 1;
   }
-  else
+  else /* BmfMechanism == BM_BROADCAST && nPossibleNeighbors >= 2 */
   {
-    /* Increase counter */
-    intf->nBmfPacketsTx++;
+    nPacketsToSend = 2;
+  }
 
-    OLSR_PRINTF(
-      8,
-      "%s: --> encapsulated and forwarded on \"%s\" to %s\n",
-      PLUGIN_NAME_SHORT,
-      intf->ifName,
-      inet_ntoa(forwardTo.sin_addr));
-  } /* if (nBytesWritten != udpDataLen) */
-}
+  for (i = 0; i < nPacketsToSend; i++)
+  {
+    if (BmfMechanism == BM_UNICAST_PROMISCUOUS || nPossibleNeighbors <= 2)
+    {
+      COPY_IP(&forwardTo.sin_addr.s_addr, &bestNeighborLinks.links[i]->neighbor_iface_addr);
+    }
+
+    /* Forward the BMF packet via the encapsulation socket */
+    nBytesWritten = sendto(
+      intf->encapsulatingSkfd,
+      encapsulationUdpData,
+      udpDataLen,
+      MSG_DONTROUTE,
+      (struct sockaddr*) &forwardTo,
+      sizeof(forwardTo));                   
+
+    /* Evaluate and display result */
+    if (nBytesWritten != udpDataLen)
+    {
+      BmfPError("sendto() error forwarding pkt on \"%s\"", intf->ifName);
+    }
+    else
+    {
+      /* Increase counter */
+      intf->nBmfPacketsTx++;
+
+      OLSR_PRINTF(
+        8,
+        "%s: --> encapsulated and forwarded on \"%s\" to %s\n",
+        PLUGIN_NAME_SHORT,
+        intf->ifName,
+        inet_ntoa(forwardTo.sin_addr));
+    } /* if (nBytesWritten != udpDataLen) */
+  } /* for */
+} /* EncapsulateAndForwardPacket */
 
 /* -------------------------------------------------------------------------
  * Function   : BmfPacketCaptured
- * Description: Handle a captured raw Ethernet frame
+ * Description: Handle a captured 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.
  *              encapsulationUdpData - space for the encapsulation header, followed by
- *                the captured Ethernet frame
+ *                the captured IP packet
  * Output     : none
  * Return     : none
  * Data Used  : BmfInterfaces
- * Notes      : The Ethernet frame is assumed to be captured on a socket of family
- *              PF_PACKET and type SOCK_RAW.
+ * Notes      : The IP packet is assumed to be captured on a socket of family
+ *              PF_PACKET and type SOCK_DGRAM (cooked).
  * ------------------------------------------------------------------------- */
 static void BmfPacketCaptured(
   struct TBmfInterface* intf,
   unsigned char sllPkttype,
   unsigned char* encapsulationUdpData)
 {
-  unsigned char* srcMac;
-  union olsr_ip_addr src; /* Source IP address in captured frame */
-  union olsr_ip_addr dst; /* Destination IP address in captured frame */
-  union olsr_ip_addr* origIp; /* Main OLSR address of source of captured frame */
+  union olsr_ip_addr src; /* Source IP address in captured packet */
+  union olsr_ip_addr dst; /* Destination IP address in captured packet */
+  union olsr_ip_addr* origIp; /* Main OLSR address of source of captured packet */
   struct TBmfInterface* walker;
   int isFromOlsrIntf;
   int isFromOlsrNeighbor;
   int iAmMpr;
-  unsigned char* ethernetFrame; /* The captured Ethernet frame... */
-  u_int16_t ethernetFrameLen; /* ...and its length */
-  struct ip* ipHeader; /* The IP header inside the captured Ethernet frame */
-  unsigned char* ipPacket; /* The IP packet inside the captured Ethernet frame */
+  unsigned char* ipPacket; /* The captured IP packet... */
+  u_int16_t ipPacketLen; /* ...and its length */
+  struct ip* ipHeader; /* The IP header inside the captured IP packet */
   u_int32_t crc32;
   struct TEncapHeader* encapHdr;
 
-  ethernetFrame = GetEthernetFrame(encapsulationUdpData);
-
-  /* Only forward IPv4 packets */
-  if (GetEtherType(ethernetFrame) != IPV4_TYPE)
-  {
-    return;
-  }
-
-  ipHeader = GetIpHeader(ethernetFrame);
+  ipHeader = GetIpHeader(encapsulationUdpData);
 
   COPY_IP(&dst, &ipHeader->ip_dst);
 
@@ -301,7 +278,7 @@ static void BmfPacketCaptured(
     return;
   }
 
-  ipPacket = GetIpPacket(ethernetFrame);
+  ipPacket = GetIpPacket(encapsulationUdpData);
 
   /* Don't forward fragments of IP packets. Also, don't forward OLSR packets (UDP
    * port 698) and BMF encapsulated packets */
@@ -316,8 +293,8 @@ static void BmfPacketCaptured(
   /* Check if the frame is captured on an OLSR-enabled interface */
   isFromOlsrIntf = (intf->olsrIntf != NULL);
 
-  /* Retrieve the length of the captured frame */
-  ethernetFrameLen = GetFrameLength(ethernetFrame);
+  /* Retrieve the length of the captured packet */
+  ipPacketLen = GetIpTotalLength(ipPacket);
 
   COPY_IP(&src, &ipHeader->ip_src);
   OLSR_PRINTF(
@@ -325,30 +302,20 @@ static void BmfPacketCaptured(
     "%s: %s pkt of %ld bytes captured on %s interface \"%s\": %s->%s\n",
     PLUGIN_NAME_SHORT,
     sllPkttype == PACKET_OUTGOING ? "outgoing" : "incoming",
-    (long)ethernetFrameLen,
+    (long)ipPacketLen,
     isFromOlsrIntf ? "OLSR" : "non-OLSR",
     intf->ifName,
     olsr_ip_to_string(&src),
     olsr_ip_to_string(&dst));
 
-  /* Apply drop list for testing purposes. */
-  srcMac = ethernetFrame + IFHWADDRLEN;
-  if (IsInDropList(srcMac))
-  {
-    OLSR_PRINTF(
-      8,
-      "%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;
-  }
-
   /* Lookup main address of source in the MID table of OLSR */
   origIp = MainAddressOf(&src);
 
+  /* Calculate packet fingerprint */
+  crc32 = PacketCrc32(ipPacket, ipPacketLen);
+
   /* Check if this packet was seen recently */
-  crc32 = PacketCrc32(ethernetFrame, ethernetFrameLen);
-  if (CheckAndMarkRecentPacket(Hash16(crc32)))
+  if (CheckAndMarkRecentPacket(crc32))
   {
     /* Increase counter */
     intf->nBmfPacketsRxDup++;
@@ -363,6 +330,9 @@ static void BmfPacketCaptured(
   /* Compose encapsulation header */
   encapHdr = (struct TEncapHeader*) encapsulationUdpData;
   memset (encapHdr, 0, ENCAP_HDR_LEN);
+  encapHdr->type = BMF_ENCAP_TYPE;
+  encapHdr->len = BMF_ENCAP_LEN;
+  encapHdr->reserved = 0;
   encapHdr->crc32 = htonl(crc32);
 
   /* Check if the frame is captured on an OLSR interface from an OLSR neighbor.
@@ -461,19 +431,37 @@ static void BmfPacketCaptured(
       /* Case 2: Forward from OLSR interface to non-OLSR interface */
 
       int nBytesWritten;
+      struct sockaddr_ll dest;
 
-      /* Change source MAC address to that of sending interface */
-      SetFrameSourceMac(ethernetFrame, walker->macAddr);
-
-      /* If the encapsulated Ethernet frame is an IP local broadcast packet,
+      /* If the encapsulated IP packet is a local broadcast packet,
        * update its destination address to match the subnet of the network
        * interface on which the packet is being sent. */
-      CheckAndUpdateLocalBroadcast(GetIpPacket(ethernetFrame), &walker->broadAddr);
+      CheckAndUpdateLocalBroadcast(ipPacket, &walker->broadAddr);
+
+      memset(&dest, 0, sizeof(dest));
+      dest.sll_family = AF_PACKET;
+      dest.sll_protocol = htons(ETH_P_IP);
+      dest.sll_ifindex = if_nametoindex(walker->ifName);
+      dest.sll_halen = IFHWADDRLEN;
+
+      /* 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(dest.sll_addr, 0xFF, IFHWADDRLEN);
 
-      nBytesWritten = write(walker->capturingSkfd, ethernetFrame, ethernetFrameLen);
-      if (nBytesWritten != ethernetFrameLen)
+      nBytesWritten = sendto(
+        walker->capturingSkfd,
+        ipPacket,
+        ipPacketLen,
+        0,
+        (struct sockaddr*) &dest,
+        sizeof(dest));
+      if (nBytesWritten != ipPacketLen)
       {
-        BmfPError("write() error forwarding pkt on \"%s\"", walker->ifName);
+        BmfPError("sendto() error forwarding pkt on \"%s\"", walker->ifName);
       }
       else
       {
@@ -509,19 +497,37 @@ static void BmfPacketCaptured(
       else
       {
         int nBytesWritten;
+        struct sockaddr_ll dest;
 
-        /* Change source MAC address to that of sending interface */
-        SetFrameSourceMac(ethernetFrame, walker->macAddr);
-
-        /* If the encapsulated Ethernet frame is an IP local broadcast packet,
+        /* If the encapsulated IP packet is a local broadcast packet,
          * update its destination address to match the subnet of the network
          * interface on which the packet is being sent. */
-        CheckAndUpdateLocalBroadcast(GetIpPacket(ethernetFrame), &walker->broadAddr);
+        CheckAndUpdateLocalBroadcast(ipPacket, &walker->broadAddr);
+
+        memset(&dest, 0, sizeof(dest));
+        dest.sll_family = AF_PACKET;
+        dest.sll_protocol = htons(ETH_P_IP);
+        dest.sll_ifindex = if_nametoindex(walker->ifName);
+        dest.sll_halen = IFHWADDRLEN;
+
+        /* 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(dest.sll_addr, 0xFF, IFHWADDRLEN);
 
-        nBytesWritten = write(walker->capturingSkfd, ethernetFrame, ethernetFrameLen);
-        if (nBytesWritten != ethernetFrameLen)
+        nBytesWritten = sendto(
+          walker->capturingSkfd,
+          ipPacket,
+          ipPacketLen,
+          0,
+          (struct sockaddr*) &dest,
+          sizeof(dest));
+        if (nBytesWritten != ipPacketLen)
         {
-          BmfPError("write() error forwarding pkt on \"%s\"", walker->ifName);
+          BmfPError("sendto() error forwarding pkt on \"%s\"", walker->ifName);
         }
         else
         {
@@ -537,7 +543,7 @@ static void BmfPacketCaptured(
       } /* if (intf == walker) */
     } /* if */
   } /* for */
-}
+} /* BmfPacketCaptured */
 
 /* -------------------------------------------------------------------------
  * Function   : BmfEncapsulationPacketReceived
@@ -550,7 +556,7 @@ static void BmfPacketCaptured(
  *                broadcast).
  *              encapsulationUdpData - the encapsulating IP UDP data, containting
  *                the BMF encapsulation header, followed by the encapsulated
- *                Ethernet frame
+ *                IP packet
  * Output     : none
  * Return     : none
  * Data Used  : BmfInterfaces
@@ -563,14 +569,14 @@ static void BmfEncapsulationPacketReceived(
 {
   int iAmMpr; /* True (1) if I am selected as MPR by 'forwardedBy' */
   struct sockaddr_in forwardTo; /* Next destination of encapsulation packet */
-  struct TBmfInterface* walker;
-  unsigned char* ethernetFrame; /* The encapsulated Ethernet packet */
-  u_int16_t ethernetFrameLen; /* Length of the encapsulated Ethernet packet */
-  struct ip* ipHeader; /* IP header inside the encapsulated Ethernet packet */
+  unsigned char* ipPacket; /* The encapsulated IP packet */
+  u_int16_t ipPacketLen; /* Length of the encapsulated IP packet */
+  struct ip* ipHeader; /* IP header inside the encapsulated IP packet */
   union olsr_ip_addr mcSrc; /* Original source of the encapsulated multicast packet */
   union olsr_ip_addr mcDst; /* Multicast destination of the encapsulated packet */
   struct TEncapHeader* encapsulationHdr;
   u_int16_t encapsulationUdpDataLen;
+  struct TBmfInterface* walker;
 
   /* Are we talking to ourselves? */
   if (if_ifwithaddr(forwardedBy) != NULL)
@@ -584,19 +590,14 @@ static void BmfEncapsulationPacketReceived(
     return;
   }
 
-  ethernetFrame = GetEthernetFrame(encapsulationUdpData);
-  ethernetFrameLen = GetFrameLength(ethernetFrame);
-
-  ipHeader = GetIpHeader(ethernetFrame);
+  /* Retrieve details about the encapsulated IP packet */
+  ipPacket = GetIpPacket(encapsulationUdpData);
+  ipPacketLen = GetIpTotalLength(ipPacket);
+  ipHeader = GetIpHeader(encapsulationUdpData);
 
   COPY_IP(&mcSrc, &ipHeader->ip_src);
   COPY_IP(&mcDst, &ipHeader->ip_dst);
 
-  /* Apply drop list? No, not needed: encapsulation packets are IP-routed,
-   * so filtering should be done by adding a rule to the iptables FORWARD
-   * chain, e.g.:
-   * iptables -A FORWARD -m mac --mac-source 00:0C:29:28:0E:CC -j DROP */
-
   /* Increase counter */
   intf->nBmfPacketsRx++;
 
@@ -605,7 +606,7 @@ static void BmfEncapsulationPacketReceived(
     8,
     "%s: encapsulated pkt of %ld bytes incoming on \"%s\": %s->%s, forwarded by %s to %s\n",
     PLUGIN_NAME_SHORT,
-    (long)ethernetFrameLen,
+    (long)ipPacketLen,
     intf->ifName,
     olsr_ip_to_string(&mcSrc),
     olsr_ip_to_string(&mcDst),
@@ -615,8 +616,20 @@ static void BmfEncapsulationPacketReceived(
   /* Get encapsulation header */
   encapsulationHdr = (struct TEncapHeader*) encapsulationUdpData;
 
+  /* Verify correct format of BMF encapsulation header */
+  if (encapsulationHdr->type != BMF_ENCAP_TYPE ||
+      encapsulationHdr->len != BMF_ENCAP_LEN ||
+      ntohs(encapsulationHdr->reserved != 0))
+  {
+    OLSR_PRINTF(
+      8,
+      "%s: --> discarding: format of BMF encapsulation header not recognized\n",
+      PLUGIN_NAME_SHORT);
+    return;
+  }
+
   /* Check if this packet was seen recently */
-  if (CheckAndMarkRecentPacket(Hash16(ntohl(encapsulationHdr->crc32))))
+  if (CheckAndMarkRecentPacket(ntohl(encapsulationHdr->crc32)))
   {
     /* Increase counter */
     intf->nBmfPacketsRxDup++;
@@ -630,31 +643,23 @@ static void BmfEncapsulationPacketReceived(
 
   if (EtherTunTapFd >= 0)
   {
-    /* Unpack the encapsulated Ethernet packet and send a copy to myself via
-     * the EtherTunTap interface */
+    /* Unpack the encapsulated IP packet and deliver it locally, by sending
+     * a copy into the local IP stack via the EtherTunTap interface */
 
     union olsr_ip_addr broadAddr;
     int nBytesToWrite, nBytesWritten;
     unsigned char* bufferToWrite;
 
-    /* If the encapsulated Ethernet frame is an IP local broadcast packet,
+    /* If the encapsulated IP packet is a local broadcast packet,
      * update its destination address to match the subnet of the EtherTunTap
      * interface */
     broadAddr.v4 = htonl(EtherTunTapIpBroadcast);
-    CheckAndUpdateLocalBroadcast(GetIpPacket(ethernetFrame), &broadAddr);
+    CheckAndUpdateLocalBroadcast(ipPacket, &broadAddr);
 
-    /* Start off by assuming a TAP device */
-    bufferToWrite = ethernetFrame;
-    nBytesToWrite = ethernetFrameLen;
-
-    /* If we're using the TUN device instead, we need to write an IP packet instead
-     * of an Ethernet packet */
-    if (TunOrTap == TT_TUN)
-    {
-      bufferToWrite += IP_HDR_OFFSET;
-      nBytesToWrite -= IP_HDR_OFFSET;
-    }
+    bufferToWrite = ipPacket;
+    nBytesToWrite = ipPacketLen;
 
+    /* Write the packet into the EtherTunTap interface for local delivery */
     nBytesWritten = write(EtherTunTapFd, bufferToWrite, nBytesToWrite);
     if (nBytesWritten != nBytesToWrite)
     {
@@ -668,56 +673,67 @@ static void BmfEncapsulationPacketReceived(
         PLUGIN_NAME_SHORT,
         EtherTunTapIfName);
     }
-  }
+  } /* if (EtherTunTapFd >= 0) */
 
   /* Check if I am MPR for the forwarder */
   /* TODO: olsr_lookup_mprs_set() is not thread-safe! */
   iAmMpr = (olsr_lookup_mprs_set(MainAddressOf(forwardedBy)) != NULL);
 
+  /* Compose destination address for next hop */
   memset(&forwardTo, 0, sizeof(forwardTo));
   forwardTo.sin_family = AF_INET;
   forwardTo.sin_port = htons(BMF_ENCAP_PORT);
 
+  /* Retrieve the number of bytes to be forwarded via the encapsulation socket */
   encapsulationUdpDataLen = GetEncapsulationUdpDataLength(encapsulationUdpData);
 
   /* Check with each network interface what needs to be done on it */
   for (walker = BmfInterfaces; walker != NULL; walker = walker->next)
   {
-    /* 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.
+    /* What to do with the packet on a non-OLSR interface? Unpack
+     * encapsulated packet, and forward it.
      *
-     * 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.
-     */
+     * What to do with the packet on an OLSR interface? Forward it only
+     * if the forwarding node has selected us as MPR (iAmMpr).
+     *
+     * Note that the packet is always coming in on an OLSR interface, because
+     * it is an encapsulated BMF packet. */
 
-    /* To a non-OLSR interface: unpack encapsulated packet and forward */
+    /* To a non-OLSR interface: unpack the encapsulated IP packet and forward it */
     if (walker->olsrIntf == NULL)
     {
       int nBytesWritten;
+      struct sockaddr_ll dest;
 
-      /* If the encapsulated Ethernet frame is an IP local broadcast packet,
+      /* If the encapsulated IP packet is a local broadcast packet,
        * update its destination address to match the subnet of the network
        * interface on which the packet is being sent. */
-      CheckAndUpdateLocalBroadcast(GetIpPacket(ethernetFrame), &walker->broadAddr);
+      CheckAndUpdateLocalBroadcast(ipPacket, &walker->broadAddr);
+
+      memset(&dest, 0, sizeof(dest));
+      dest.sll_family = AF_PACKET;
+      dest.sll_protocol = htons(ETH_P_IP);
+      dest.sll_ifindex = if_nametoindex(walker->ifName);
+      dest.sll_halen = IFHWADDRLEN;
+
+      /* 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(dest.sll_addr, 0xFF, IFHWADDRLEN);
 
-      nBytesWritten = write(walker->capturingSkfd, ethernetFrame, ethernetFrameLen);
-      if (nBytesWritten != ethernetFrameLen)
+      nBytesWritten = sendto(
+        walker->capturingSkfd,
+        ipPacket,
+        ipPacketLen,
+        0,
+        (struct sockaddr*) &dest,
+        sizeof(dest));
+      if (nBytesWritten != ipPacketLen)
       {
-        BmfPError("write() error forwarding unpacked encapsulated pkt on \"%s\"", walker->ifName);
+        BmfPError("sendto() error forwarding unpacked encapsulated pkt on \"%s\"", walker->ifName);
       }
       else
       {
@@ -732,18 +748,26 @@ static void BmfEncapsulationPacketReceived(
       }
     } /* if (walker->olsrIntf == NULL) */
 
-    /* To a OLSR interface: forward the packet if this node is selected as MPR by the forwarding node */
+    /* To an OLSR interface: forward the packet, but only if this node is
+     * selected as MPR by the forwarding node */
     else if (iAmMpr)
     {
+      struct TBestNeighbors bestNeighborLinks;
+      int nPossibleNeighbors;
       int nBytesWritten;
+      int nPacketsToSend;
+      int i;
+
+      /* Retrieve at most two best neigbors to forward the packet to */
+      bestNeighborLinks =
+        GetBestTwoNeighbors(
+          walker,
+          &mcSrc,
+          forwardedBy,
+          forwardedTo,
+          &nPossibleNeighbors);
 
-      /* Compose destination of encapsulation packet */
-      if (ComposeEnapsulationDestination(
-        walker,
-        &mcSrc,
-        forwardedBy,
-        forwardedTo,
-        &forwardTo) == 0)
+      if (nPossibleNeighbors <= 0)
       {
         OLSR_PRINTF(
           8,
@@ -754,54 +778,88 @@ static void BmfEncapsulationPacketReceived(
         continue; /* for */
       }
 
-      nBytesWritten = sendto(
-        walker->encapsulatingSkfd,
-        encapsulationUdpData,
-        encapsulationUdpDataLen,
-        MSG_DONTROUTE,
-        (struct sockaddr*) &forwardTo,
-        sizeof(forwardTo));                   
-
-      if (nBytesWritten != encapsulationUdpDataLen)
+      /* Compose destination of encapsulation packet.
+       * Start by filling in the local broadcast address. */
+      COPY_IP(&forwardTo.sin_addr.s_addr, &walker->broadAddr);
+
+      /* - If the BMF mechanism is BM_UNICAST_PROMISCUOUS, always send just one
+       *   packet (to the best neighbor). Other neighbors listen promiscuously.
+       * - If the BMF mechanism is BM_BROADCAST,
+       *   - send one unicast packet if there is one possible neighbor,
+       *   - send two unicast packets if there are two possible neighbors, and
+       *   - only if there are more than two possible neighbors, then send an
+       *     (WLAN-air-expensive, less reliable) broadcast packet. */
+      if (BmfMechanism == BM_UNICAST_PROMISCUOUS || nPossibleNeighbors < 2)
       {
-        BmfPError("sendto() error forwarding encapsulated pkt on \"%s\"", walker->ifName);
+        nPacketsToSend = 1;
       }
-      else
+      else /* BmfMechanism == BM_BROADCAST && nPossibleNeighbors >= 2 */
       {
-        /* Increase counter */
-        walker->nBmfPacketsTx++;
-
-        OLSR_PRINTF(
-          8,
-          "%s: --> forwarded on \"%s\" to %s\n",
-          PLUGIN_NAME_SHORT,
-          walker->ifName,
-          inet_ntoa(forwardTo.sin_addr));
+        nPacketsToSend = 2;
       }
+
+      for (i = 0; i < nPacketsToSend; i++)
+      {
+        if (BmfMechanism == BM_UNICAST_PROMISCUOUS || nPossibleNeighbors <= 2)
+        {
+          /* For unicast, overwrite the local broadcast address which was filled in
+           * above */
+          COPY_IP(&forwardTo.sin_addr.s_addr, &bestNeighborLinks.links[i]->neighbor_iface_addr);
+        }
+
+        /* Forward the BMF packet via the encapsulation socket */
+        nBytesWritten = sendto(
+          walker->encapsulatingSkfd,
+          encapsulationUdpData,
+          encapsulationUdpDataLen,
+          MSG_DONTROUTE,
+          (struct sockaddr*) &forwardTo,
+          sizeof(forwardTo));                   
+
+        /* Evaluate and display result */
+        if (nBytesWritten != encapsulationUdpDataLen)
+        {
+          BmfPError("sendto() error forwarding encapsulated pkt on \"%s\"", walker->ifName);
+        }
+        else
+        {
+          /* Increase counter */
+          walker->nBmfPacketsTx++;
+
+          OLSR_PRINTF(
+            8,
+            "%s: --> forwarded on \"%s\" to %s\n",
+            PLUGIN_NAME_SHORT,
+            walker->ifName,
+            inet_ntoa(forwardTo.sin_addr));
+        } /* if */
+      } /* for */
     }  /* else if (iAmMpr) */
+
     else /* walker->olsrIntf != NULL && !iAmMpr */
     {
-      /* 'walker' is an OLSR interface and I am not selected as MPR */
+      /* 'walker' is an OLSR interface, but I am not selected as MPR. In that
+       * case, don't forward. */
       OLSR_PRINTF(
         8,
         "%s: --> not forwarding on \"%s\": I am not selected as MPR by %s\n",
         PLUGIN_NAME_SHORT,
         walker->ifName,
         olsr_ip_to_string(forwardedBy));
-    }
+    } /* else */
   } /* for */
-}
+} /* BmfEncapsulationPacketReceived */
 
 /* -------------------------------------------------------------------------
  * Function   : BmfTunPacketCaptured
- * Description: Handle a Ethernet frame, captured outgoing on the tuntap interface
+ * Description: Handle an IP packet, captured outgoing on the tuntap interface
  * Input      : encapsulationUdpData - space for the encapsulation header, followed by
- *                the captured Ethernet frame
+ *                the captured outgoing IP 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.
+ *              PF_PACKET and type SOCK_DGRAM (cooked).
  * ------------------------------------------------------------------------- */
 static void BmfTunPacketCaptured(unsigned char* encapsulationUdpData)
 {
@@ -809,22 +867,15 @@ static void BmfTunPacketCaptured(unsigned char* encapsulationUdpData)
   union olsr_ip_addr dstIp;
   union olsr_ip_addr broadAddr;
   struct TBmfInterface* walker;
-  unsigned char* ethernetFrame;
-  u_int16_t ethernetFrameLen;
+  unsigned char* ipPacket;
+  u_int16_t ipPacketLen;
   struct ip* ipHeader;
   u_int32_t crc32;
   struct TEncapHeader* encapHdr;
 
-  ethernetFrame = GetEthernetFrame(encapsulationUdpData);
-  ethernetFrameLen = GetFrameLength(ethernetFrame);
-
-  /* Only forward IPv4 packets */
-  if (GetEtherType(ethernetFrame) != IPV4_TYPE)
-  {
-    return;
-  }
-
-  ipHeader = GetIpHeader(ethernetFrame);
+  ipPacket = GetIpPacket(encapsulationUdpData);
+  ipPacketLen = GetIpTotalLength(ipPacket);
+  ipHeader = GetIpHeader(encapsulationUdpData);
 
   /* Only forward multicast packets. If configured, also forward local broadcast packets */
   COPY_IP(&dstIp, &ipHeader->ip_dst);
@@ -844,14 +895,16 @@ static void BmfTunPacketCaptured(unsigned char* encapsulationUdpData)
     8,
     "%s: outgoing pkt of %ld bytes captured on tuntap interface \"%s\": %s->%s\n",
     PLUGIN_NAME_SHORT,
-    (long)ethernetFrameLen,
+    (long)ipPacketLen,
     EtherTunTapIfName,
     olsr_ip_to_string(&srcIp),
     olsr_ip_to_string(&dstIp));
 
+  /* Calculate packet fingerprint */
+  crc32 = PacketCrc32(ipPacket, ipPacketLen);
+
   /* Check if this packet was seen recently */
-  crc32 = PacketCrc32(ethernetFrame, ethernetFrameLen);
-  if (CheckAndMarkRecentPacket(Hash16(crc32)))
+  if (CheckAndMarkRecentPacket(crc32))
   {
     OLSR_PRINTF(
       8,
@@ -863,6 +916,9 @@ static void BmfTunPacketCaptured(unsigned char* encapsulationUdpData)
   /* Compose encapsulation header */
   encapHdr = (struct TEncapHeader*) encapsulationUdpData;
   memset (encapHdr, 0, ENCAP_HDR_LEN);
+  encapHdr->type = BMF_ENCAP_TYPE;
+  encapHdr->len = BMF_ENCAP_LEN;
+  encapHdr->reserved = 0;
   encapHdr->crc32 = htonl(crc32);
 
   /* Check with each network interface what needs to be done on it */
@@ -883,19 +939,37 @@ static void BmfTunPacketCaptured(unsigned char* encapsulationUdpData)
        * Answer 2 (better): Forward it. */
 
       int nBytesWritten;
+      struct sockaddr_ll dest;
 
-      /* Change source MAC address to that of sending interface */
-      SetFrameSourceMac(ethernetFrame, walker->macAddr);
-
-      /* If the encapsulated Ethernet frame is an IP local broadcast packet,
+      /* If the encapsulated IP packet is a local broadcast packet,
        * update its destination address to match the subnet of the network
        * interface on which the packet is being sent. */
-      CheckAndUpdateLocalBroadcast(GetIpPacket(ethernetFrame), &walker->broadAddr);
+      CheckAndUpdateLocalBroadcast(ipPacket, &walker->broadAddr);
+
+      memset(&dest, 0, sizeof(dest));
+      dest.sll_family = AF_PACKET;
+      dest.sll_protocol = htons(ETH_P_IP);
+      dest.sll_ifindex = if_nametoindex(walker->ifName);
+      dest.sll_halen = IFHWADDRLEN;
+
+      /* 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(dest.sll_addr, 0xFF, IFHWADDRLEN);
 
-      nBytesWritten = write(walker->capturingSkfd, ethernetFrame, ethernetFrameLen);
-      if (nBytesWritten != ethernetFrameLen)
+      nBytesWritten = sendto(
+        walker->capturingSkfd,
+        ipPacket,
+        ipPacketLen,
+        0,
+        (struct sockaddr*) &dest,
+        sizeof(dest));
+      if (nBytesWritten != ipPacketLen)
       {
-        BmfPError("write() error forwarding pkt on \"%s\"", walker->ifName);
+        BmfPError("sendto() error forwarding pkt on \"%s\"", walker->ifName);
       }
       else
       {
@@ -910,7 +984,7 @@ static void BmfTunPacketCaptured(unsigned char* encapsulationUdpData)
       } /* if */
     } /* if */
   } /* for */
-}
+} /* BmfTunPacketCaptured */
 
 /* -------------------------------------------------------------------------
  * Function   : DoBmf
@@ -959,7 +1033,7 @@ static void DoBmf(void)
         struct sockaddr_ll pktAddr;
         socklen_t addrLen = sizeof(pktAddr);
         int nBytes;
-        unsigned char* ethernetFrame;
+        unsigned char* ipPacket;
 
         /* A packet was captured. */
 
@@ -967,10 +1041,10 @@ static void DoBmf(void)
 
         /* Receive the captured Ethernet frame, leaving space for the BMF
          * encapsulation header */
-        ethernetFrame = GetEthernetFrame(rxBuffer);
+        ipPacket = GetIpPacket(rxBuffer);
         nBytes = recvfrom(
           skfd,
-          ethernetFrame,
+          ipPacket,
           BMF_BUFFER_SIZE - ENCAP_HDR_LEN,
           0,
           (struct sockaddr*)&pktAddr,
@@ -982,13 +1056,13 @@ static void DoBmf(void)
           continue; /* for */
         } /* if (nBytes < 0) */
 
-        /* Check if the number of received bytes is large enough for an Ethernet
-         * frame which contains at least a minimum-size IP header.
+        /* Check if the number of received bytes is large enough for an IP
+         * packet which contains at least a minimum-size IP header.
          * Note: There is an apparent bug in the packet socket implementation in
          * combination with VLAN interfaces. On a VLAN interface, the value returned
          * by 'recvfrom' may (but need not) be 4 (bytes) larger than the value
          * returned on a non-VLAN interface, for the same ethernet frame. */
-        if (nBytes < IP_HDR_OFFSET + (int)sizeof(struct ip))
+        if (nBytes < (int)sizeof(struct ip))
         {
           olsr_printf(
             1,
@@ -1047,8 +1121,13 @@ static void DoBmf(void)
           continue; /* for */
         } /* if (nBytes < 0) */
 
+        /* Check if the received packet is actually directed to another
+         * node on the LAN */
         if (pktAddr.sll_pkttype != PACKET_OTHERHOST)
         {
+          /* No, the packet is directed to this node. In that case it will
+           * be, or will already have been received, via the encapsulating
+           * socket. Discard it here. */
           continue; /* for */
         } /* if (pktAddr.sll_pkttype ...) */
 
@@ -1060,7 +1139,7 @@ static void DoBmf(void)
           continue; /* for */
         }
 
-        udpHeader = (struct udphdr*)(rxBuffer + GetHeaderLength(rxBuffer));
+        udpHeader = (struct udphdr*)(rxBuffer + GetIpHeaderLength(rxBuffer));
         destPort = ntohs(udpHeader->dest);
         if (destPort != BMF_ENCAP_PORT)
         {
@@ -1079,7 +1158,7 @@ static void DoBmf(void)
          * not) be 4 (bytes) larger than the value returned on a non-VLAN interface, for
          * the same ethernet frame. */
         minimumLength =
-          GetHeaderLength(rxBuffer) +
+          GetIpHeaderLength(rxBuffer) +
           sizeof(struct udphdr) +
           ENCAP_HDR_LEN +
           IP_HDR_OFFSET +
@@ -1102,7 +1181,7 @@ static void DoBmf(void)
           walker,
           &forwardedBy,
           &forwardedTo,
-          rxBuffer + GetHeaderLength(rxBuffer) + sizeof(struct udphdr));
+          rxBuffer + GetIpHeaderLength(rxBuffer) + sizeof(struct udphdr));
 
       } /* if (skfd >= 0 && (FD_ISSET...)) */
     } /* for */
@@ -1157,6 +1236,10 @@ static void DoBmf(void)
           continue; /* for */
         }
 
+        /* Unfortunately, the recvfrom call does not return the destination
+         * of the encapsulation packet (the destination may be either the
+         * my unicast or my local broadcast address). Therefore we fill in 'NULL'
+         * for the 'forwardedTo' parameter. */
         BmfEncapsulationPacketReceived(walker, &forwardedBy, NULL, rxBuffer);
 
       } /* if (skfd >= 0 && (FD_ISSET...)) */
@@ -1168,43 +1251,17 @@ static void DoBmf(void)
        * network interface */
 
       int nBytes;
-      unsigned char* ethernetFrame;
+      unsigned char* ipPacket;
       unsigned char* bufferToRead;
       size_t nBytesToRead;
 
       nFdBitsSet--;
 
       /* Receive the packet, leaving space for the BMF encapsulation header */
-      ethernetFrame = GetEthernetFrame(rxBuffer);
+      ipPacket = GetIpPacket(rxBuffer);
     
-      bufferToRead = ethernetFrame;
+      bufferToRead = ipPacket;
       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 a valid Ethernet header, for other BMF-nodes which may be
-         * 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(ethernetFrame, 0xFF, IFHWADDRLEN);
-
-        /* Source MAC address is not important. Set to all-zeros */
-        memset(ethernetFrame + IFHWADDRLEN, 0x00, IFHWADDRLEN);
-
-        /* Ethertype = 0800 = IP */
-        type = htons(0x0800);
-        memcpy(ethernetFrame + ETH_TYPE_OFFSET, &type, 2);
-      }
 
       nBytes = read(EtherTunTapFd, bufferToRead, nBytesToRead);
 
@@ -1214,13 +1271,9 @@ static void DoBmf(void)
       }
       else
       {
-        /* Check if the number of received bytes is large enough for an Ethernet
-         * frame which contains at least a minimum-size IP header */
-        if (TunOrTap == TT_TUN)
-        {
-          nBytes += IP_HDR_OFFSET;
-        }
-        if (nBytes < IP_HDR_OFFSET + (int)sizeof(struct ip))
+        /* Check if the number of received bytes is large enough for an IP
+         * packet which contains at least a minimum-size IP header */
+        if (nBytes < (int)sizeof(struct ip))
         {
           olsr_printf(
             1,
@@ -1235,11 +1288,11 @@ static void DoBmf(void)
 
           BmfTunPacketCaptured(rxBuffer);
 
-        } /* if (nBytes < IP_HDR_OFFSET... */
+        } /* if (nBytes < ... */
       } /* if (nBytes < 0) */
     } /* if (nFdBitsSet > 0 && ... */
   } /* while (nFdBitsSet > 0) */
-}
+} /* DoBmf */
 
 /* -------------------------------------------------------------------------
  * Function   : BmfSignalHandler
@@ -1252,7 +1305,7 @@ static void DoBmf(void)
 static void BmfSignalHandler(int signo __attribute__((unused)))
 {
   BmfThreadRunning = 0;
-}
+} /* BmfSignalHandler */
 
 /* -------------------------------------------------------------------------
  * Function   : BmfRun
@@ -1293,7 +1346,7 @@ static void* BmfRun(void* useless __attribute__((unused)))
   }
 
   return NULL;
-}
+} /* BmfRun */
 
 /* -------------------------------------------------------------------------
  * Function   : InterfaceChange
@@ -1338,8 +1391,9 @@ int InterfaceChange(struct interface* interf, int action)
       interf->int_name, action);
     break;
   }
+
   return 0;
-}
+} /* InterfaceChange */
 
 /* -------------------------------------------------------------------------
  * Function   : InitBmf
@@ -1376,7 +1430,7 @@ int InitBmf(struct interface* skipThisIntf)
   }
 
   return 1;
-}
+} /* InitBmf */
 
 /* -------------------------------------------------------------------------
  * Function   : CloseBmf
@@ -1384,7 +1438,7 @@ int InitBmf(struct interface* skipThisIntf)
  * Input      : none
  * Output     : none
  * Return     : none
- * Data Used  : BmfThreadRunning, BmfThread
+ * Data Used  : BmfThread
  * ------------------------------------------------------------------------- */
 void CloseBmf(void)
 {
@@ -1414,7 +1468,7 @@ void CloseBmf(void)
 
   /* Clean up after the BmfThread has been killed */
   CloseBmfNetworkInterfaces();
-}
+} /* CloseBmf */
 
 /* -------------------------------------------------------------------------
  * Function   : RegisterBmfParameter
@@ -1427,11 +1481,7 @@ void CloseBmf(void)
  * ------------------------------------------------------------------------- */
 int RegisterBmfParameter(char* key, char* value)
 {
-  if (strcmp(key, "DropMac") == 0)
-  {
-    return DropMac(value);
-  }
-  else if (strcmp(key, "NonOlsrIf") == 0)
+  if (strcmp(key, "NonOlsrIf") == 0)
   {
     return AddNonOlsrBmfIf(value);
   }
@@ -1443,10 +1493,6 @@ int RegisterBmfParameter(char* key, char* value)
   {
     return SetBmfInterfaceName(value);
   }
-  else if (strcmp(key, "BmfInterfaceType") == 0)
-  {
-    return SetBmfInterfaceType(value);
-  }
   else if (strcmp(key, "BmfInterfaceIp") == 0)
   {
     return SetBmfInterfaceIp(value);
@@ -1462,5 +1508,5 @@ int RegisterBmfParameter(char* key, char* value)
 
   /* Key not recognized */
   return 0;
-}
+} /* RegisterBmfParameter */
 
index 5648eec..bf8749e 100644 (file)
@@ -3,7 +3,7 @@
 
 /*
  * OLSR Basic Multicast Forwarding (BMF) plugin.
- * Copyright (c) 2005, 2006, Thales Communications, Huizen, The Netherlands.
+ * Copyright (c) 2005 - 2007, Thales Communications, Huizen, The Netherlands.
  * Written by Erik Tromp.
  * All rights reserved.
  *
@@ -43,9 +43,9 @@
 /* BMF plugin data */
 #define PLUGIN_NAME "OLSRD Basic Multicast Forwarding (BMF) plugin"
 #define PLUGIN_NAME_SHORT "OLSRD BMF"
-#define PLUGIN_VERSION "1.4 (" __DATE__ " " __TIME__ ")"
+#define PLUGIN_VERSION "1.5 (" __DATE__ " " __TIME__ ")"
 #define PLUGIN_COPYRIGHT "  (C) Thales Communications Huizen, Netherlands"
-#define PLUGIN_AUTHOR "  Erik Tromp (erik.tromp@nl.thalesgroup.com)"
+#define PLUGIN_AUTHOR "  Erik Tromp (eriktromp@users.sourceforge.net)"
 #define MOD_DESC PLUGIN_NAME " " PLUGIN_VERSION "\n" PLUGIN_COPYRIGHT "\n" PLUGIN_AUTHOR
 
 /* UDP-Port on which multicast packets are encapsulated */
index 26c80c4..055a635 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * OLSR Basic Multicast Forwarding (BMF) plugin.
- * Copyright (c) 2005, 2006, Thales Communications, Huizen, The Netherlands.
+ * Copyright (c) 2005 - 2007, Thales Communications, Huizen, The Netherlands.
  * Written by Erik Tromp.
  * All rights reserved.
  *
@@ -50,7 +50,7 @@
 #include <assert.h> /* assert() */
 #include <net/if.h> /* socket(), ifreq, if_indextoname(), if_nametoindex() */
 #include <netinet/in.h> /* htons() */
-#include <linux/if_ether.h> /* ETH_P_ALL */
+#include <linux/if_ether.h> /* ETH_P_IP */
 #include <linux/if_packet.h> /* packet_mreq, PACKET_MR_PROMISC, PACKET_ADD_MEMBERSHIP */
 #include <linux/if_tun.h> /* IFF_TAP */
 #include <netinet/ip.h> /* struct ip */
@@ -87,12 +87,6 @@ int EtherTunTapFd = -1;
  * setting the plugin parameter "BmfInterface". */
 char EtherTunTapIfName[IFNAMSIZ] = "bmf0";
 
-/* If the plugin parameter "BmfInterfaceType" is set to "tap", an
- * EtherTap interface will be used, and this variable will be set to TT_TAP. If
- * "BmfInterfaceType" is set to "tun" or not set at all, an IP tunnel interface 
- * used, and this variable will be set to TT_TUN. */
-enum TTunOrTap TunOrTap = TT_TUN;
-
 /* The underlying mechanism to forward multicast packets. Either:
  * - BM_BROADCAST: BMF uses the IP local broadcast as destination address
  * - BM_UNICAST_PROMISCUOUS: BMF uses the IP address of the best neighbor as
@@ -136,33 +130,7 @@ int SetBmfInterfaceName(const char* ifname)
   strncpy(EtherTunTapIfName, ifname, IFNAMSIZ - 1);
   EtherTunTapIfName[IFNAMSIZ - 1] = '\0'; /* Ensures null termination */
   return 1;
-}
-
-/* -------------------------------------------------------------------------
- * Function   : SetBmfInterfaceType
- * Description: Overrule the default network interface type ("tun") of the
- *              EtherTunTap interface
- * Input      : iftype - network interface type, either "tun" or "tap"
- * Output     : none
- * Return     : fail (0) or success (1)
- * Data Used  : none
- * ------------------------------------------------------------------------- */
-int SetBmfInterfaceType(const char* iftype)
-{
-  if (strcmp(iftype, "tun") == 0)
-  {
-    TunOrTap = TT_TUN;
-    return 1;
-  }
-  else if (strcmp(iftype, "tap") == 0)
-  {
-    TunOrTap = TT_TAP;
-    return 1;
-  }
-
-  /* Value not recognized */
-  return 0;
-}
+} /* SetBmfInterfaceName */
 
 /* -------------------------------------------------------------------------
  * Function   : SetBmfInterfaceIp
@@ -223,7 +191,7 @@ int SetBmfInterfaceIp(const char* ip)
 
   /* Compose IP broadcast address in host byte order */
   EtherTunTapIpBroadcast = EtherTunTapIp;
-  for (i=prefixLen; i < IPV4_MAX_PREFIXLEN; i++)
+  for (i = prefixLen; i < IPV4_MAX_PREFIXLEN; i++)
   {
     EtherTunTapIpBroadcast |= (1 << (IPV4_MAX_PREFIXLEN - 1 - i));
   }
@@ -231,7 +199,7 @@ int SetBmfInterfaceIp(const char* ip)
   TunTapIpOverruled = 1;
 
   return 1;
-}
+} /* SetBmfInterfaceIp */
 
 /* -------------------------------------------------------------------------
  * Function   : SetCapturePacketsOnOlsrInterfaces
@@ -257,7 +225,7 @@ int SetCapturePacketsOnOlsrInterfaces(const char* enable)
 
   /* Value not recognized */
   return 0;
-}
+} /* SetCapturePacketsOnOlsrInterfaces */
 
 /* -------------------------------------------------------------------------
  * Function   : SetBmfMechanism
@@ -283,7 +251,7 @@ int SetBmfMechanism(const char* mechanism)
 
   /* Value not recognized */
   return 0;
-}
+} /* SetBmfMechanism */
 
 /* -------------------------------------------------------------------------
  * Function   : AddDescriptorToInputSet
@@ -304,7 +272,7 @@ static void AddDescriptorToInputSet(int skfd)
 
   /* Add descriptor to input set */
   FD_SET(skfd, &InputSet);
-}
+} /* AddDescriptorToInputSet */
 
 /* To save the state of the IP spoof filter for the EtherTunTap interface */
 static char EthTapSpoofState = '1';
@@ -366,7 +334,7 @@ int DeactivateSpoofFilter(void)
   fclose(procSpoof);
 
   return 1;
-}
+} /* DeactivateSpoofFilter */
 
 /* -------------------------------------------------------------------------
  * Function   : RestoreSpoofFilter
@@ -398,7 +366,7 @@ void RestoreSpoofFilter(void)
     fputc(EthTapSpoofState, procSpoof);
     fclose(procSpoof);
   }
-}
+} /* RestoreSpoofFilter */
 
 #ifndef USING_THALES_LINK_COST_ROUTING
 /* -------------------------------------------------------------------------
@@ -421,35 +389,41 @@ static float CalcEtx(float loss, float neigh_loss)
   {
     return 1.0 / (loss * neigh_loss);
   }
-}
+} /* CalcEtx */
 #endif /* USING_THALES_LINK_COST_ROUTING */
 
 /* -------------------------------------------------------------------------
- * Function   : GetBestNeighbor
- * Description: Get the best neighbor on an interface to send a BMF packet to
+ * Function   : GetBestTwoNeighbors
+ * Description: Find at most two best neighbors on a network interface to forward
+ *              a BMF packet to
  * Input      : intf - the network interface
  *              source - the source IP address of the BMF packet 
  *              forwardedBy - the IP address of the node that forwarded the BMF
  *                packet
  *              forwardedTo - the IP address of the node to which the BMF packet
- *                was directed 
+ *                was directed
  * Output     : nPossibleNeighbors - number of found possible neighbors
- * Return     : the best neighbor, or NULL if none found
+ * Return     : The list of the two best neighbors. If only one best neighbor is
+ *              found, the second list entry is NULL. If no neigbors are found,
+ *              the first and second list entries are both NULL.
  * Data Used  : none
  * ------------------------------------------------------------------------- */
-struct link_entry* GetBestNeighbor(
+struct TBestNeighbors GetBestTwoNeighbors(
   struct TBmfInterface* intf,
   union olsr_ip_addr* source,
   union olsr_ip_addr* forwardedBy,
   union olsr_ip_addr* forwardedTo,
   int* nPossibleNeighbors)
 {
+  struct TBestNeighbors result;
+  result.links[0] = NULL;
+  result.links[1] = NULL;
+
   /* handle the non-LQ case */
 
   if (olsr_cnf->lq_level == 0)
   {
     struct link_entry* walker;
-    struct link_entry* bestLink = NULL;
     *nPossibleNeighbors = 0;
 
     /* TODO: get_link_set() is not thread-safe! */
@@ -513,34 +487,18 @@ struct link_entry* GetBestNeighbor(
 
       *nPossibleNeighbors += 1;
 
-      /* Remember the first found link */
-      if (bestLink == NULL)
+      /* In the non-LQ case, it is not possible to select neigbors
+       * by quality or cost. So just remember the first two found links. */
+      if (result.links[0] == NULL)
       {
-        bestLink = walker;
+        result.links[0] = walker;
       }
-
+      else if (result.links[1] == NULL)
+      {
+        result.links[1] = walker;
+      } /* if */
     } /* for */
 
-    if (bestLink == NULL)
-    {
-      OLSR_PRINTF(
-        9,
-        "%s: ----> No suitable neighbor found to forward to on \"%s\"\n",
-        PLUGIN_NAME_SHORT,
-        intf->ifName);
-    }
-    else
-    {
-      OLSR_PRINTF(
-        9,
-        "%s: ----> Best %sneighbor to forward to on \"%s\" is %s\n",
-        PLUGIN_NAME_SHORT,
-        *nPossibleNeighbors == 1 ? "(and only) " : "",
-        intf->ifName,
-        olsr_ip_to_string(&bestLink->neighbor_iface_addr));
-    }
-
-    return bestLink;
   }
   /* handle the LQ case */
   else
@@ -548,9 +506,9 @@ struct link_entry* GetBestNeighbor(
 #ifdef USING_THALES_LINK_COST_ROUTING
 
     struct link_entry* walker;
-    struct link_entry* bestLink = NULL;
     float previousLinkCost = INFINITE_COST;
     float bestLinkCost = INFINITE_COST;
+    float oneButBestLinkCost = INFINITE_COST;
     *nPossibleNeighbors = 0;
 
     if (forwardedBy != NULL)
@@ -709,41 +667,26 @@ struct link_entry* GetBestNeighbor(
 
       *nPossibleNeighbors += 1;
 
-      /* Remember the best link. If all are very bad, remember none. */
+      /* Remember the best two links. If all are very bad, remember none. */
       if (walker->link_cost < bestLinkCost)
       {
-        bestLink = walker;
+        result.links[1] = result.links[0];
+        result.links[0] = walker;
         bestLinkCost = walker->link_cost;
-           }
+      }
+      else if (walker->link_cost < oneButBestLinkCost)
+      {
+        result.links[1] = walker;
+        oneButBestLinkCost = walker->link_cost;
+      } /* if */
     } /* for */
 
-    if (bestLink == NULL)
-    {
-      OLSR_PRINTF(
-        9,
-        "%s: ----> No suitable neighbor found to forward to on \"%s\"\n",
-        PLUGIN_NAME_SHORT,
-        intf->ifName);
-    }
-    else
-    {
-      OLSR_PRINTF(
-        9,
-        "%s: ----> Best %sneighbor to forward to on \"%s\" is %s\n",
-        PLUGIN_NAME_SHORT,
-        *nPossibleNeighbors == 1 ? "(and only) " : "",
-        intf->ifName,
-        olsr_ip_to_string(&bestLink->neighbor_iface_addr));
-    }
-
-    return bestLink;
-
 #else /* USING_THALES_LINK_COST_ROUTING */
         
     struct link_entry* walker;
-    struct link_entry* bestLink = NULL;
     float previousLinkEtx = INFINITE_ETX;
     float bestEtx = INFINITE_ETX; 
+    float oneButBestEtx = INFINITE_ETX; 
     *nPossibleNeighbors = 0;
 
     if (forwardedBy != NULL)
@@ -919,40 +862,60 @@ struct link_entry* GetBestNeighbor(
 
       *nPossibleNeighbors += 1;
 
-      /* Remember the best link. If all are very bad, remember none. */
+      /* Remember the best two links. If all are very bad, remember none. */
       if (currEtx < bestEtx)
       {
-        bestLink = walker;
+        result.links[1] = result.links[0];
+        result.links[0] = walker;
         bestEtx = currEtx;
       }
-
+      else if (currEtx < oneButBestEtx)
+      {
+        result.links[1] = walker;
+        oneButBestEtx = currEtx;
+      } /* if */
     } /* for */
 
-    if (bestLink == NULL)
-    {
-      OLSR_PRINTF(
-        9,
-        "%s: ----> No suitable neighbor found to forward to on \"%s\"\n",
-        PLUGIN_NAME_SHORT,
-        intf->ifName);
-    }
-    else
+#endif /* USING_THALES_LINK_COST_ROUTING */
+
+  } /* if */
+
+  /* Display the result of the neighbor search */
+  if (result.links[0] == NULL)
+  {
+    OLSR_PRINTF(
+      9,
+      "%s: ----> No suitable neighbor found to forward to on \"%s\"\n",
+      PLUGIN_NAME_SHORT,
+      intf->ifName);
+  }
+  else
+  {
+    OLSR_PRINTF(
+      9,
+      "%s: ----> Best neighbor%s to forward to on \"%s\": ",
+      PLUGIN_NAME_SHORT,
+      *nPossibleNeighbors == 1 ? "" : "s",
+      intf->ifName);
+
+    OLSR_PRINTF(
+      9,
+      "%s",
+      olsr_ip_to_string(&result.links[0]->neighbor_iface_addr));
+
+    if (result.links[1] != NULL)
     {
       OLSR_PRINTF(
         9,
-        "%s: ----> Best %sneighbor to forward to on \"%s\" is %s\n",
-        PLUGIN_NAME_SHORT,
-        *nPossibleNeighbors == 1 ? "(and only) " : "",
-        intf->ifName,
-        olsr_ip_to_string(&bestLink->neighbor_iface_addr));
-    }
-
-    return bestLink;
-
-#endif /* USING_THALES_LINK_COST_ROUTING */
+        ", %s",
+        olsr_ip_to_string(&result.links[1]->neighbor_iface_addr));
+    } /* if */
 
+    OLSR_PRINTF(9, "\n");
   } /* if */
-} /* GetBestNeighbor */
+
+  return result;
+} /* GetBestTwoNeighbors */
 
 /* -------------------------------------------------------------------------
  * Function   : CreateCaptureSocket
@@ -961,7 +924,7 @@ struct link_entry* GetBestNeighbor(
  * Output     : none
  * Return     : the socket descriptor ( >= 0), or -1 if an error occurred
  * Data Used  : none
- * Notes      : The socket is a raw packet socket, bound to the specified
+ * Notes      : The socket is a cooked IP packet socket, bound to the specified
  *              network interface
  * ------------------------------------------------------------------------- */
 static int CreateCaptureSocket(const char* ifName)
@@ -971,8 +934,8 @@ static int CreateCaptureSocket(const char* ifName)
   struct ifreq req;
   struct sockaddr_ll bindTo;
 
-  /* Open raw packet socket */
-  int skfd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
+  /* Open cooked IP packet socket */
+  int skfd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP));
   if (skfd < 0)
   {
     BmfPError("socket(PF_PACKET) error");
@@ -1004,7 +967,7 @@ static int CreateCaptureSocket(const char* ifName)
   /* Bind the socket to the specified interface */
   memset(&bindTo, 0, sizeof(bindTo));
   bindTo.sll_family = AF_PACKET;
-  bindTo.sll_protocol = htons(ETH_P_ALL);
+  bindTo.sll_protocol = htons(ETH_P_IP);
   bindTo.sll_ifindex = ifIndex;
   memcpy(bindTo.sll_addr, req.ifr_hwaddr.sa_data, IFHWADDRLEN);
   bindTo.sll_halen = IFHWADDRLEN;
@@ -1027,17 +990,17 @@ static int CreateCaptureSocket(const char* ifName)
   AddDescriptorToInputSet(skfd);
 
   return skfd;
-}
+} /* CreateCaptureSocket */
 
 /* -------------------------------------------------------------------------
  * Function   : CreateListeningSocket
  * Description: Create socket for promiscuously listening to BMF packets.
- *              Used when 'BmfMechanism' is BM_UNICAST_PROMISCUOUS
+ *              Used only when 'BmfMechanism' is BM_UNICAST_PROMISCUOUS
  * Input      : ifname - network interface (e.g. "eth0")
  * Output     : none
  * Return     : the socket descriptor ( >= 0), or -1 if an error occurred
  * Data Used  : none
- * Notes      : The socket is an UDP (datagram) packet socket, bound to the specified
+ * Notes      : The socket is a cooked IP packet socket, bound to the specified
  *              network interface
  * ------------------------------------------------------------------------- */
 static int CreateListeningSocket(const char* ifName)
@@ -1047,8 +1010,8 @@ static int CreateListeningSocket(const char* ifName)
   struct ifreq req;
   struct sockaddr_ll bindTo;
 
-  /* Open UDP packet socket */
-  int skfd = socket(PF_PACKET, SOCK_DGRAM, 0);
+  /* Open cooked IP packet socket */
+  int skfd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP));
   if (skfd < 0)
   {
     BmfPError("socket(PF_PACKET) error");
@@ -1076,11 +1039,11 @@ static int CreateListeningSocket(const char* ifName)
     close(skfd);
     return -1;
   }
-   
+
   /* Bind the socket to the specified interface */
   memset(&bindTo, 0, sizeof(bindTo));
   bindTo.sll_family = AF_PACKET;
-  bindTo.sll_protocol = htons(ETH_P_ALL);
+  bindTo.sll_protocol = htons(ETH_P_IP);
   bindTo.sll_ifindex = ifIndex;
   memcpy(bindTo.sll_addr, req.ifr_hwaddr.sa_data, IFHWADDRLEN);
   bindTo.sll_halen = IFHWADDRLEN;
@@ -1103,7 +1066,7 @@ static int CreateListeningSocket(const char* ifName)
   AddDescriptorToInputSet(skfd);
 
   return skfd;
-}
+} /* CreateListeningSocket */
 
 /* -------------------------------------------------------------------------
  * Function   : CreateEncapsulateSocket
@@ -1170,7 +1133,7 @@ static int CreateEncapsulateSocket(const char* ifName)
   AddDescriptorToInputSet(skfd);
 
   return skfd;
-}
+} /* CreateEncapsulateSocket */
 
 /* -------------------------------------------------------------------------
  * Function   : CreateLocalEtherTunTap
@@ -1206,16 +1169,9 @@ static int CreateLocalEtherTunTap(void)
   strncpy(ifreq.ifr_name, EtherTunTapIfName, IFNAMSIZ - 1);
   ifreq.ifr_name[IFNAMSIZ - 1] = '\0'; /* Ensures null termination */
 
-  /* Specify either the IFF_TAP flag for Ethernet frames, or the IFF_TUN flag for IP.
+  /* Specify the IFF_TUN flag for IP packets.
    * Specify IFF_NO_PI for not receiving extra meta packet information. */
-  if (TunOrTap == TT_TUN)
-  {
-    ifreq.ifr_flags = IFF_TUN;
-  }
-  else
-  {
-    ifreq.ifr_flags = IFF_TAP;
-  }
+  ifreq.ifr_flags = IFF_TUN;
   ifreq.ifr_flags |= IFF_NO_PI;
 
   if (ioctl(etfd, TUNSETIFF, (void *)&ifreq) < 0)
@@ -1349,7 +1305,7 @@ static int CreateLocalEtherTunTap(void)
   close(ioctlSkfd);
 
   return etfd;
-}
+} /* CreateLocalEtherTunTap */
 
 /* -------------------------------------------------------------------------
  * Function   : CreateInterface
@@ -1533,7 +1489,7 @@ static int CreateInterface(
     ifName);
 
   return nOpened;
-}
+} /* CreateInterface */
 
 /* -------------------------------------------------------------------------
  * Function   : CreateBmfNetworkInterfaces
@@ -1641,7 +1597,7 @@ int CreateBmfNetworkInterfaces(struct interface* skipThisIntf)
     olsr_printf(1, "%s: opened %d sockets\n", PLUGIN_NAME, nOpenedSockets);
   }
   return 0;
-}
+} /* CreateBmfNetworkInterfaces */
 
 /* -------------------------------------------------------------------------
  * Function   : AddInterface
@@ -1661,12 +1617,12 @@ void AddInterface(struct interface* newIntf)
   nOpened = CreateInterface(newIntf->int_name, newIntf);
 
   olsr_printf(1, "%s: opened %d sockets\n", PLUGIN_NAME, nOpened);
-}
+} /* AddInterface */
 
 /* -------------------------------------------------------------------------
  * Function   : CloseBmfNetworkInterfaces
  * Description: Closes every socket on each network interface used by BMF
- * Input      : newIntf - network interface to add
+ * Input      : none
  * Output     : none
  * Return     : none
  * Data Used  : none
@@ -1767,7 +1723,7 @@ void CloseBmfNetworkInterfaces(void)
     totalNonOlsrBmfPacketsRx,
     totalNonOlsrBmfPacketsRxDup,
     totalNonOlsrBmfPacketsTx);
-}
+} /* CloseBmfNetworkInterfaces */
 
 #define MAX_NON_OLSR_IFS 32
 static char NonOlsrIfNames[MAX_NON_OLSR_IFS][IFNAMSIZ];
@@ -1800,7 +1756,7 @@ int AddNonOlsrBmfIf(const char* ifName)
   NonOlsrIfNames[nNonOlsrIfs][IFNAMSIZ - 1] = '\0'; /* Ensures null termination */
   nNonOlsrIfs++;
   return 1;
-}
+} /* AddNonOlsrBmfIf */
 
 /* -------------------------------------------------------------------------
  * Function   : IsNonOlsrBmfIf
@@ -1821,7 +1777,7 @@ int IsNonOlsrBmfIf(const char* ifName)
     if (strncmp(NonOlsrIfNames[i], ifName, IFNAMSIZ) == 0) return 1;
   }
   return 0;
-}
+} /* IsNonOlsrBmfIf */
 
 /* -------------------------------------------------------------------------
  * Function   : CheckAndUpdateLocalBroadcast
@@ -1870,7 +1826,7 @@ void CheckAndUpdateLocalBroadcast(unsigned char* ipPacket, union olsr_ip_addr* b
     {
       /* Re-calculate UDP/IP checksum for new destination */
 
-      int ipHeaderLen = GetHeaderLength(ipPacket);
+      int ipHeaderLen = GetIpHeaderLength(ipPacket);
       struct udphdr* udph = (struct udphdr*) (ipPacket + ipHeaderLen);
 
       /* RFC 1624, Eq. 3: HC' = ~(~HC - m + m') */
@@ -1884,9 +1840,9 @@ void CheckAndUpdateLocalBroadcast(unsigned char* ipPacket, union olsr_ip_addr* b
       check = check + (check >> 16);
 
       udph->check = htons(check);
-     }
-  }
-}
+     } /* if */
+  } /* if */
+} /* CheckAndUpdateLocalBroadcast */
 
 /* -------------------------------------------------------------------------
  * Function   : AddMulticastRoute
@@ -1929,7 +1885,7 @@ void AddMulticastRoute(void)
     /* Continue anyway */
   }
   close(ioctlSkfd);
-}
+} /* AddMulticastRoute */
 
 /* -------------------------------------------------------------------------
  * Function   : DeleteMulticastRoute
@@ -1974,5 +1930,5 @@ void DeleteMulticastRoute(void)
       /* Continue anyway */
     }
     close(ioctlSkfd);
-  }
-}
+  } /* if */
+} /* DeleteMulticastRoute */
index 4cb9ef3..c586206 100644 (file)
@@ -3,7 +3,7 @@
 
 /*
  * OLSR Basic Multicast Forwarding (BMF) plugin.
- * Copyright (c) 2005, 2006, Thales Communications, Huizen, The Netherlands.
+ * Copyright (c) 2005 - 2007, Thales Communications, Huizen, The Netherlands.
  * Written by Erik Tromp.
  * All rights reserved.
  *
@@ -117,25 +117,28 @@ extern u_int32_t EtherTunTapIpBroadcast;
 
 extern int CapturePacketsOnOlsrInterfaces;
 
-enum TTunOrTap { TT_TUN = 0, TT_TAP };
-extern enum TTunOrTap TunOrTap;
-
 enum TBmfMechanism { BM_BROADCAST = 0, BM_UNICAST_PROMISCUOUS };
 extern enum TBmfMechanism BmfMechanism;
 
 int SetBmfInterfaceName(const char* ifname);
-int SetBmfInterfaceType(const char* iftype);
 int SetBmfInterfaceIp(const char* ip);
 int SetCapturePacketsOnOlsrInterfaces(const char* enable);
 int SetBmfMechanism(const char* mechanism);
 int DeactivateSpoofFilter(void);
 void RestoreSpoofFilter(void);
-struct link_entry* GetBestNeighbor(
+
+struct TBestNeighbors
+{
+  struct link_entry* links[2];
+};
+
+struct TBestNeighbors GetBestTwoNeighbors(
   struct TBmfInterface* intf,
   union olsr_ip_addr* source,
   union olsr_ip_addr* forwardedBy,
   union olsr_ip_addr* forwardedTo,
-  int* multipleNeighbors);
+  int* nPossibleNeighbors);
+
 int CreateBmfNetworkInterfaces(struct interface* skipThisIntf);
 void AddInterface(struct interface* newIntf);
 void CloseBmfNetworkInterfaces(void);
index f4f007b..cb302a6 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * OLSR Basic Multicast Forwarding (BMF) plugin.
- * Copyright (c) 2005, 2006, Thales Communications, Huizen, The Netherlands.
+ * Copyright (c) 2005 - 2007, Thales Communications, Huizen, The Netherlands.
  * Written by Erik Tromp.
  * All rights reserved.
  *
@@ -67,10 +67,10 @@ int IsIpFragment(unsigned char* ipPacket)
     return 1;
   }
   return 0;
-}
+} /* IsIpFragment */
 
 /* -------------------------------------------------------------------------
- * Function   : GetTotalLength
+ * Function   : GetIpTotalLength
  * Description: Retrieve the total length of the IP packet (in bytes) of
  *              an IP packet
  * Input      : ipPacket - the IP packet
@@ -78,7 +78,7 @@ int IsIpFragment(unsigned char* ipPacket)
  * Return     : IP packet length
  * Data Used  : none
  * ------------------------------------------------------------------------- */
-u_int16_t GetTotalLength(unsigned char* ipPacket)
+u_int16_t GetIpTotalLength(unsigned char* ipPacket)
 {
   struct iphdr* iph;
 
@@ -86,17 +86,17 @@ u_int16_t GetTotalLength(unsigned char* ipPacket)
 
   iph = (struct iphdr*) ipPacket;
   return ntohs(iph->tot_len);
-}
+} /* GetIpTotalLength */
 
 /* -------------------------------------------------------------------------
- * Function   : GetHeaderLength
+ * Function   : GetIpHeaderLength
  * Description: Retrieve the IP header length (in bytes) of an IP packet
  * Input      : ipPacket - the IP packet
  * Output     : none
  * Return     : IP header length
  * Data Used  : none
  * ------------------------------------------------------------------------- */
-unsigned int GetHeaderLength(unsigned char* ipPacket)
+unsigned int GetIpHeaderLength(unsigned char* ipPacket)
 {
   struct iphdr* iph;
 
@@ -104,7 +104,7 @@ unsigned int GetHeaderLength(unsigned char* ipPacket)
 
   iph = (struct iphdr*) ipPacket;
   return iph->ihl << 2;
-}
+} /* GetIpHeaderLength */
 
 /* -------------------------------------------------------------------------
  * Function   : GetTtl
@@ -123,7 +123,7 @@ u_int8_t GetTtl(unsigned char* ipPacket)
 
   iph = (struct iphdr*) ipPacket;
   return iph->ttl;
-}
+} /* GetTtl */
 
 /* -------------------------------------------------------------------------
  * Function   : SaveTtlAndChecksum
@@ -143,7 +143,7 @@ void SaveTtlAndChecksum(unsigned char* ipPacket, struct TSaveTtl* sttl)
   iph = (struct iphdr*) ipPacket;
   sttl->ttl = iph->ttl;
   sttl->check = ntohs(iph->check);
-}
+} /* SaveTtlAndChecksum */
 
 /* -------------------------------------------------------------------------
  * Function   : RestoreTtlAndChecksum
@@ -164,7 +164,7 @@ void RestoreTtlAndChecksum(unsigned char* ipPacket, struct TSaveTtl* sttl)
   iph = (struct iphdr*) ipPacket;
   iph->ttl = sttl->ttl;
   iph->check = htons(sttl->check);
-}
+} /* RestoreTtlAndChecksum */
 
 /* -------------------------------------------------------------------------
  * Function   : DecreaseTtlAndUpdateHeaderChecksum
@@ -188,100 +188,44 @@ void DecreaseTtlAndUpdateHeaderChecksum(unsigned char* ipPacket)
   iph->ttl--; /* decrement ttl */
   sum = ntohs(iph->check) + 0x100; /* increment checksum high byte */
   iph->check = htons(sum + (sum>>16)); /* add carry */
-}
-
-/* -------------------------------------------------------------------------
- * Function   : GetEtherType
- * Description: Retrieve the EtherType of an Ethernet frame
- * Input      : ethernetFrame - the Ethernet frame
- * Output     : none
- * Return     : EtherType
- * Data Used  : none
- * ------------------------------------------------------------------------- */
-u_int16_t GetEtherType(unsigned char* ethernetFrame)
-{
-  u_int16_t type;
-  memcpy(&type, ethernetFrame + ETH_TYPE_OFFSET, 2);
-  return ntohs(type);
-}
+} /* DecreaseTtlAndUpdateHeaderChecksum */
 
 /* -------------------------------------------------------------------------
  * Function   : GetIpHeader
- * Description: Retrieve the IP header from an Ethernet frame
- * Input      : ethernetFrame - the Ethernet frame
+ * Description: Retrieve the IP header from BMF encapsulation UDP data
+ * Input      : encapsulationUdpData - the encapsulation UDP data
  * Output     : none
  * Return     : IP header
  * Data Used  : none
  * ------------------------------------------------------------------------- */
-struct ip* GetIpHeader(unsigned char* ethernetFrame)
+struct ip* GetIpHeader(unsigned char* encapsulationUdpData)
 {
-  return (struct ip*)(ethernetFrame + IP_HDR_OFFSET);
-}
+  return (struct ip*)(encapsulationUdpData + ENCAP_HDR_LEN);
+} /* GetIpHeader */
 
 /* -------------------------------------------------------------------------
  * Function   : GetIpPacket
- * Description: Retrieve the IP packet from an Ethernet frame
- * Input      : ethernetFrame - the Ethernet frame
- * Output     : none
- * Return     : IP packet
- * Data Used  : none
- * ------------------------------------------------------------------------- */
-unsigned char* GetIpPacket(unsigned char* ethernetFrame)
-{
-  return ethernetFrame + IP_HDR_OFFSET;
-}
-
-/* -------------------------------------------------------------------------
- * Function   : GetFrameLength
- * Description: Return the Ethernet frame length of an Ethernet frame containing
- *              an IP packet
- * Input      : ethernetFrame - the Ethernet frame
- * Output     : none
- * Return     : The frame length
- * Data Used  : none
- * ------------------------------------------------------------------------- */
-u_int16_t GetFrameLength(unsigned char* ethernetFrame)
-{
-  return GetTotalLength(GetIpPacket(ethernetFrame)) + IP_HDR_OFFSET;
-}
-
-/* -------------------------------------------------------------------------
- * Function   : SetFrameSourceMac
- * Description: Set the source MAC address of an Ethernet frame
- * Input      : ethernetFrame - the Ethernet frame
-              : srcMac - the source MAC address
- * Output     : none
- * Return     : none
- * Data Used  : none
- * ------------------------------------------------------------------------- */
-void SetFrameSourceMac(unsigned char* ethernetFrame, unsigned char* srcMac)
-{
-  memcpy(ethernetFrame + IFHWADDRLEN, srcMac, IFHWADDRLEN);
-}
-
-/* -------------------------------------------------------------------------
- * Function   : GetEthernetFrame
- * Description: Retrieve the Ethernet frame from BMF encapsulation UDP data
+ * Description: Retrieve the IP packet from BMF encapsulation UDP data
  * Input      : encapsulationUdpData - the encapsulation UDP data
  * Output     : none
- * Return     : The Ethernet frame
+ * Return     : The IP packet
  * Data Used  : none
  * ------------------------------------------------------------------------- */
-unsigned char* GetEthernetFrame(unsigned char* encapsulationUdpData)
+unsigned char* GetIpPacket(unsigned char* encapsulationUdpData)
 {
   return encapsulationUdpData + ENCAP_HDR_LEN;
-}
+} /* GetIpPacket */
 
 /* -------------------------------------------------------------------------
  * Function   : GetEncapsulationUdpDataLength
  * Description: Return the length of BMF encapsulation UDP data
  * Input      : encapsulationUdpData - the encapsulation UDP data
  * Output     : none
- * Return     : The packet length
+ * Return     : The encapsulation data length
  * Data Used  : none
  * ------------------------------------------------------------------------- */
 u_int16_t GetEncapsulationUdpDataLength(unsigned char* encapsulationUdpData)
 {
-  return GetFrameLength(GetEthernetFrame(encapsulationUdpData)) + ENCAP_HDR_LEN;
-}
+  return GetIpTotalLength(GetIpPacket(encapsulationUdpData)) + ENCAP_HDR_LEN;
+} /* GetEncapsulationUdpDataLength */
 
index 24f5c83..1dee489 100644 (file)
@@ -3,7 +3,7 @@
 
 /*
  * OLSR Basic Multicast Forwarding (BMF) plugin.
- * Copyright (c) 2005, 2006, Thales Communications, Huizen, The Netherlands.
+ * Copyright (c) 2005 - 2007, Thales Communications, Huizen, The Netherlands.
  * Written by Erik Tromp.
  * All rights reserved.
  *
 #define IPV4_TYPE 0x0800
 
 /* BMF-encapsulated packets are Ethernet-IP-UDP packets, which start
- * with a 16-bytes BMF header (struct TEncapHeader), followed by the
+ * with a 8-bytes BMF header (struct TEncapHeader), followed by the
  * encapsulated Ethernet-IP packet itself */
 
 struct TEncapHeader
 {
+  /* Use a standard Type-Length-Value (TLV) element */
+  u_int8_t type;
+  u_int8_t len;
+  u_int16_t reserved; /* Always 0 */
   u_int32_t crc32;
-  u_int32_t futureExpansion1;
-  u_int32_t futureExpansion2;
-  u_int32_t futureExpansion3;
 } __attribute__((__packed__));
 
 #define        ENCAP_HDR_LEN ((int)sizeof(struct TEncapHeader))
+#define BMF_ENCAP_TYPE 1
+#define BMF_ENCAP_LEN 6
 
 struct TSaveTtl
 {
@@ -75,18 +78,14 @@ struct TSaveTtl
 } __attribute__((__packed__));
 
 int IsIpFragment(unsigned char* ipPacket);
-u_int16_t GetTotalLength(unsigned char* ipPacket);
-unsigned int GetHeaderLength(unsigned char* ipPacket);
+u_int16_t GetIpTotalLength(unsigned char* ipPacket);
+unsigned int GetIpHeaderLength(unsigned char* ipPacket);
 u_int8_t GetTtl(unsigned char* ipPacket);
 void SaveTtlAndChecksum(unsigned char* ipPacket, struct TSaveTtl* sttl);
 void RestoreTtlAndChecksum(unsigned char* ipPacket, struct TSaveTtl* sttl);
 void DecreaseTtlAndUpdateHeaderChecksum(unsigned char* ipPacket);
-u_int16_t GetEtherType(unsigned char* ethernetFrame);
-struct ip* GetIpHeader(unsigned char* ethernetFrame);
-unsigned char* GetIpPacket(unsigned char* ethernetFrame);
-u_int16_t GetFrameLength(unsigned char* ethernetFrame);
-void SetFrameSourceMac(unsigned char* ethernetFrame, unsigned char* srcMac);
-unsigned char* GetEthernetFrame(unsigned char* encapsulationUdpData);
+struct ip* GetIpHeader(unsigned char* encapsulationUdpData);
+unsigned char* GetIpPacket(unsigned char* encapsulationUdpData);
 u_int16_t GetEncapsulationUdpDataLength(unsigned char* encapsulationUdpData);
 
 #endif /* _BMF_PACKET_H */
index 45e1ef4..9400a75 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * OLSR Basic Multicast Forwarding (BMF) plugin.
- * Copyright (c) 2005, 2006, Thales Communications, Huizen, The Netherlands.
+ * Copyright (c) 2005 - 2007, Thales Communications, Huizen, The Netherlands.
  * Written by Erik Tromp.
  * All rights reserved.
  *
 #include <netinet/ip.h> /* struct iphdr */
 
 /* OLSRD includes */
+#include "defs.h" /* GET_TIMESTAMP, TIMED_OUT */
 #include "olsr.h" /* olsr_printf */
 
-/* NULLPlugin includes */
+/* Plugin includes */
 #include "Packet.h"
 
-static u_int32_t PacketHistory[HISTORY_TABLE_SIZE];
+static struct TDupEntry* PacketHistory[HISTORY_HASH_SIZE];
 
 #define CRC_UPTO_NBYTES 256
 
@@ -85,7 +86,7 @@ static u_int16_t CalcCrcCcitt(unsigned char* buffer, ssize_t len)
     crc ^= ((crc & 0xff) << 4) << 1;
   }
   return crc;
-}
+} /* CalcCrcCcitt */
 #endif
 
 /* -------------------------------------------------------------------------
@@ -120,8 +121,8 @@ static void GenerateCrc32Table(void)
       }
     }
     CrcTable[i] = crc;
-  }
-}
+  } /* for */
+} /* GenerateCrc32Table */
 
 /* -------------------------------------------------------------------------
  * Function   : CalcCrc32
@@ -142,32 +143,26 @@ static u_int32_t CalcCrc32(unsigned char* buffer, ssize_t len)
     crc = (crc >> 8) ^ CrcTable[j];
   }
   return crc ^ 0xffffffffUL;
-}
+} /* CalcCrc32 */
 
 /* -------------------------------------------------------------------------
  * Function   : PacketCrc32
- * Description: Calculates the CRC-32 value for an Ethernet frame
- * Input      : ethernetFrame - the Ethernet frame
- *              len - the number of octets in the Ethernet frame
+ * Description: Calculates the CRC-32 value for an IP packet
+ * Input      : ipPacket - the IP packet
+ *              len - the number of octets in the IP packet
  * Output     : none
- * Return     : 32-bits hash value
+ * Return     : 32-bits CRC value
  * Data Used  : none
- * Notes      : The source and destination MAC address are not taken into account
- *              in the CRC calculation.
  * ------------------------------------------------------------------------- */
-u_int32_t PacketCrc32(unsigned char* ethernetFrame, ssize_t len)
+u_int32_t PacketCrc32(unsigned char* ipPacket, ssize_t len)
 {
-  ssize_t nCrcBytes;
   struct TSaveTtl sttl;
   struct ip* ipHeader;
   u_int32_t result;
 
-  assert(ethernetFrame != NULL);
+  assert(ipPacket != NULL);
 
-  /* Start CRC calculation at ethertype; skip source and destination MAC 
-   * addresses, and ethertype.
-   *
-   * Also skip TTL: in a multi-homed OLSR-network, the same multicast packet
+  /* Skip TTL: in a multi-homed OLSR-network, the same multicast packet
    * may enter the network multiple times, each copy differing only in its
    * TTL value. BMF must not calculate a different CRC for packets that
    * differ only in TTL. Skip also the IP-header checksum, because it changes
@@ -176,30 +171,36 @@ u_int32_t PacketCrc32(unsigned char* ethernetFrame, ssize_t len)
    *
    * Clip number of bytes over which CRC is calculated to prevent
    * long packets from possibly claiming too much CPU resources. */
-  nCrcBytes = len - IP_HDR_OFFSET;
-  assert(nCrcBytes > 0);
-  if (nCrcBytes > CRC_UPTO_NBYTES)
+  assert(len > 0);
+  if (len > CRC_UPTO_NBYTES)
   {
-    nCrcBytes = CRC_UPTO_NBYTES;
+    len = CRC_UPTO_NBYTES;
   }
 
-  SaveTtlAndChecksum(GetIpPacket(ethernetFrame), &sttl);
+  SaveTtlAndChecksum(ipPacket, &sttl);
 
-  ipHeader = GetIpHeader(ethernetFrame);
+  ipHeader = (struct ip*)ipPacket;
   ipHeader->ip_ttl = 0xFF; /* fixed value of TTL for CRC-32 calculation */
   ipHeader->ip_sum = 0x5A5A; /* fixed value of IP header checksum for CRC-32 calculation */
 
-  result = CalcCrc32(ethernetFrame + IP_HDR_OFFSET, nCrcBytes);
+  result = CalcCrc32(ipPacket, len);
 
-  RestoreTtlAndChecksum(GetIpPacket(ethernetFrame), &sttl);
+  RestoreTtlAndChecksum(ipPacket, &sttl);
   return result;
-}
+} /* PacketCrc32 */
 
-/* Calculates a 16-bit hash value from a 32-bit hash value */
-u_int16_t Hash16(u_int32_t hash32)
+/* -------------------------------------------------------------------------
+ * Function   : Hash
+ * Description: Calculates a hash value from a 32-bit value
+ * Input      : from32 - 32-bit value
+ * Output     : none
+ * Return     : hash value
+ * Data Used  : none
+ * ------------------------------------------------------------------------- */
+u_int32_t Hash(u_int32_t from32)
 {
-  return ((hash32 >> 16) + hash32) & 0xFFFFU;
-}
+  return ((from32 >> N_HASH_BITS) + from32) & ((1 << N_HASH_BITS) - 1);
+} /* Hash */
 
 /* -------------------------------------------------------------------------
  * Function   : InitPacketHistory
@@ -211,63 +212,61 @@ u_int16_t Hash16(u_int32_t hash32)
  * ------------------------------------------------------------------------- */
 void InitPacketHistory(void)
 {
-  memset(PacketHistory, 0, sizeof(PacketHistory));
-  GenerateCrc32Table();
-}
-
-/* -------------------------------------------------------------------------
- * Function   : MarkRecentPacket
- * Description: Record the fact that this packet was seen recently
- * Input      : hash16
- * Output     : none
- * Return     : none
- * Data Used  : PacketHistory
- * ------------------------------------------------------------------------- */
-void MarkRecentPacket(u_int16_t hash16)
-{
-  u_int32_t index;
-  uint offset;
-
-  index = hash16 / NPACKETS_PER_ENTRY;
-  assert(index < HISTORY_TABLE_SIZE);
+  int i;
 
-  offset = (hash16 % NPACKETS_PER_ENTRY) * NBITS_PER_PACKET;
-  assert(offset <= NBITS_IN_UINT32 - NBITS_PER_PACKET);
+  GenerateCrc32Table();
 
-  /* Mark as "seen recently" */
-  PacketHistory[index] = PacketHistory[index] | (0x3u << offset);
-}
+  for(i = 0; i < HISTORY_HASH_SIZE; i++)
+  {
+    PacketHistory[i] = NULL;
+  }
+} /* InitPacketHistory */
 
 /* -------------------------------------------------------------------------
  * Function   : CheckAndMarkRecentPacket
  * Description: Check if this packet was seen recently, then record the fact
  *              that this packet was seen recently.
- * Input      : hash16
+ * Input      : crc32 - 32-bits crc value of the packet
  * Output     : none
  * Return     : not recently seen (0), recently seen (1)
  * Data Used  : PacketHistory
  * ------------------------------------------------------------------------- */
-int CheckAndMarkRecentPacket(u_int16_t hash16)
+int CheckAndMarkRecentPacket(u_int32_t crc32)
 {
   u_int32_t index;
-  uint offset;
-  u_int32_t bitMask;
-  int result;
+  struct TDupEntry* walker;
+  struct TDupEntry* newEntry;
 
-  index = hash16 / NPACKETS_PER_ENTRY;
-  assert(index < HISTORY_TABLE_SIZE);
+  index = Hash(crc32);
+  assert(index < HISTORY_HASH_SIZE);
 
-  offset =  (hash16 % NPACKETS_PER_ENTRY) * NBITS_PER_PACKET;
-  assert(offset <= NBITS_IN_UINT32 - NBITS_PER_PACKET);
+  for (walker = PacketHistory[index]; walker != NULL; walker = walker->next)
+  {
+    if (walker->crc32 == crc32)
+    {
+      /* Found duplicate entry */
 
-  bitMask = 0x1u << offset;
-  result = ((PacketHistory[index] & bitMask) == bitMask);
-  
-  /* Always mark as "seen recently" */
-  PacketHistory[index] = PacketHistory[index] | (0x3u << offset);
+      /* Always mark as "seen recently": refresh time-out */
+      walker->timeOut = GET_TIMESTAMP(HISTORY_HOLD_TIME);
 
-  return result;
-}
+      return 1;
+    } /* if */
+  } /* for */
+
+  /* No duplicate entry found: create one */
+  newEntry = malloc(sizeof(struct TDupEntry));
+  if (newEntry != NULL)
+  {
+    newEntry->crc32 = crc32;
+    newEntry->timeOut = GET_TIMESTAMP(HISTORY_HOLD_TIME);
+
+    /* Add new entry at the front of the list */
+    newEntry->next = PacketHistory[index];
+    PacketHistory[index] = newEntry;
+  }
+
+  return 0;
+} /* CheckAndMarkRecentPacket */
   
 /* -------------------------------------------------------------------------
  * Function   : PrunePacketHistory
@@ -280,33 +279,37 @@ int CheckAndMarkRecentPacket(u_int16_t hash16)
 void PrunePacketHistory(void* useless __attribute__((unused)))
 {
   uint i;
-  for (i = 0; i < HISTORY_TABLE_SIZE; i++)
+  for (i = 0; i < HISTORY_HASH_SIZE; i++)
   {
-    if (PacketHistory[i] > 0)
+    if (PacketHistory[i] != NULL)
     {
-      uint j;
-      for (j = 0; j < NPACKETS_PER_ENTRY; j++)
+      struct TDupEntry* nextEntry = PacketHistory[i];
+      struct TDupEntry* prevEntry = NULL;
+      while (nextEntry != NULL) 
       {
-        uint offset = j * NBITS_PER_PACKET;
-
-        u_int32_t bitMask = 0x3u << offset;
-        u_int32_t bitsSeenRecenty = 0x3u << offset;
-        u_int32_t bitsTimingOut = 0x1u << offset;
+        struct TDupEntry* entry = nextEntry;
+        nextEntry = entry->next;
 
-        /* 10 should never occur */
-        assert ((PacketHistory[i] & bitMask) != (0x2u << offset));
-        
-        if ((PacketHistory[i] & bitMask) == bitsSeenRecenty)
-        {
-          /* 11 -> 01 */
-          PacketHistory[i] &= ~bitMask | bitsTimingOut;
-        }
-        else if ((PacketHistory[i] & bitMask) == bitsTimingOut)
+        if (TIMED_OUT(entry->timeOut))
         {
-          /* 01 -> 00 */
-          PacketHistory[i] &= ~bitMask;
-        }
-      } /* for (j = ...) */
-    } /* if (PacketHistory[i] > 0) */
+          /* De-queue */
+          if (prevEntry != NULL)
+          {
+            prevEntry->next = entry->next;
+          }
+          else
+          {
+            PacketHistory[i] = entry->next;
+          } /* if */
+
+          /* De-allocate memory */
+          free(entry); 
+             }
+             else
+             {
+               prevEntry = entry;
+             } /* if */
+      } /* while */
+    } /* if (PacketHistory[i] != NULL) */
   } /* for (i = ...) */
-}
+} /* PrunePacketHistory */
index 99ffb85..229b299 100644 (file)
@@ -3,7 +3,7 @@
 
 /*
  * OLSR Basic Multicast Forwarding (BMF) plugin.
- * Copyright (c) 2005, 2006, Thales Communications, Huizen, The Netherlands.
+ * Copyright (c) 2005 - 2007, Thales Communications, Huizen, The Netherlands.
  * Written by Erik Tromp.
  * All rights reserved.
  *
  *
  * ------------------------------------------------------------------------- */
 
+/* System includes */
 #include <sys/types.h> /* ssize_t */
+#include <sys/times.h> /* clock_t */
 
-/* 2 bits per seen packet: 
- * 11 = "seen recently",
- * 01 = "timing out"
- * 00 = "not seen recently"
- * Note that 10 is unused */
-#define NBITS_PER_PACKET 2
-#define NBITS_IN_UINT16 (sizeof(u_int16_t) * 8)
-#define NBITS_IN_UINT32 (sizeof(u_int32_t) * 8)
-#define NPACKETS_PER_ENTRY (NBITS_IN_UINT32 / NBITS_PER_PACKET)
-#define HISTORY_TABLE_SIZE ((1 << NBITS_IN_UINT16) / NPACKETS_PER_ENTRY)
+#define N_HASH_BITS 12
+#define HISTORY_HASH_SIZE (1 << N_HASH_BITS)
+
+/* Time-out of duplicate entries, in milliseconds */
+#define HISTORY_HOLD_TIME 3000
+
+struct TDupEntry
+{
+  u_int32_t crc32;
+  clock_t timeOut;
+  struct TDupEntry* next;
+};
 
 void InitPacketHistory(void);
-u_int32_t PacketCrc32(unsigned char* ethPkt, ssize_t len);
-u_int16_t Hash16(u_int32_t hash32);
-void MarkRecentPacket(u_int16_t hash16);
-int CheckAndMarkRecentPacket(u_int16_t hash16);
+u_int32_t PacketCrc32(unsigned char* ipPkt, ssize_t len);
+u_int32_t Hash(u_int32_t from32);
+void MarkRecentPacket(u_int32_t crc32);
+int CheckAndMarkRecentPacket(u_int32_t crc32);
 void PrunePacketHistory(void*);
 
 #endif /* _BMF_PACKETHISTORY_H */
index 46cd894..c101f9b 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * OLSR Basic Multicast Forwarding (BMF) plugin.
- * Copyright (c) 2005, 2006, Thales Communications, Huizen, The Netherlands.
+ * Copyright (c) 2005 - 2007, Thales Communications, Huizen, The Netherlands.
  * Written by Erik Tromp.
  * All rights reserved.
  *