Bug 407 - OLSR is missing HNA support
authorLalith Suresh <suresh.lalith@gmail.com>
Wed, 17 Mar 2010 15:46:42 +0000
changeset 6140 12bb87242796
parent 6139 3202621a634c
child 6141 3adf94e68d82
Bug 407 - OLSR is missing HNA support
examples/routing/olsr-hna.cc
examples/routing/wscript
src/helper/olsr-helper.cc
src/helper/olsr-helper.h
src/routing/olsr/olsr-repositories.h
src/routing/olsr/olsr-routing-protocol.cc
src/routing/olsr/olsr-routing-protocol.h
src/routing/olsr/olsr-state.cc
src/routing/olsr/olsr-state.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/routing/olsr-hna.cc	Wed Mar 17 15:46:42 2010 +0000
@@ -0,0 +1,263 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+// 
+// This script, adapted from examples/wireless/wifi-simple-adhoc illustrates
+// the use of OLSR HNA.
+// 
+// Network Topology:
+//
+//             |------ OLSR ------|   |---- non-OLSR ----|
+//           A ))))            (((( B ------------------- C
+//           10.1.1.1     10.1.1.2   172.16.1.2     172.16.1.1
+//
+// Node A needs to send a UDP packet to node C. This can be done only after
+// A receives an HNA message from B, in which B announces 172.16.1.0/24
+// as an associated network.
+//
+// If no HNA message is generated by B, a will not be able to form a route to C.
+// This can be verified as follows:
+//
+// ./waf --run olsr-hna
+//
+// There are two ways to make a node to generate HNA messages.
+//
+// One way is to use olsr::RoutingProtocol::SetRoutingTableAssociation ()
+// to use which you may run:
+//
+// ./waf --run "olsr-hna --assocMethod1=1"
+//
+// The other way is to use olsr::RoutingProtocol::AddHostNetworkAssociation ()
+// to use which you may run:
+//
+// ./waf --run "olsr-hna --assocMethod2=1"
+//
+
+#include "ns3/core-module.h"
+#include "ns3/common-module.h"
+#include "ns3/node-module.h"
+#include "ns3/helper-module.h"
+#include "ns3/mobility-module.h"
+#include "ns3/contrib-module.h"
+#include "ns3/wifi-module.h"
+#include "ns3/ipv4-list-routing.h"
+#include "ns3/olsr-routing-protocol.h"
+
+#include <iostream>
+#include <fstream>
+#include <vector>
+#include <string>
+
+NS_LOG_COMPONENT_DEFINE ("OlsrHna");
+
+using namespace ns3;
+
+void ReceivePacket (Ptr<Socket> socket)
+{
+  NS_LOG_UNCOND ("Received one packet!");
+}
+
+static void GenerateTraffic (Ptr<Socket> socket, uint32_t pktSize, 
+                             uint32_t pktCount, Time pktInterval )
+{
+  if (pktCount > 0)
+    {
+      socket->Send (Create<Packet> (pktSize));
+      Simulator::Schedule (pktInterval, &GenerateTraffic, 
+                                      socket, pktSize,pktCount-1, pktInterval);
+    }
+  else
+    {
+      socket->Close ();
+    }
+}
+
+
+int main (int argc, char *argv[])
+{
+  std::string phyMode ("wifib-1mbs");
+  double rss = -80;  // -dBm
+  uint32_t packetSize = 1000; // bytes
+  uint32_t numPackets = 1;
+  double interval = 1.0; // seconds
+  bool verbose = false;
+  bool assocMethod1 = false;
+  bool assocMethod2 = false;
+
+  CommandLine cmd;
+
+  cmd.AddValue ("phyMode", "Wifi Phy mode", phyMode);
+  cmd.AddValue ("rss", "received signal strength", rss);
+  cmd.AddValue ("packetSize", "size of application packet sent", packetSize);
+  cmd.AddValue ("numPackets", "number of packets generated", numPackets);
+  cmd.AddValue ("interval", "interval (seconds) between packets", interval);
+  cmd.AddValue ("verbose", "turn on all WifiNetDevice log components", verbose);
+  cmd.AddValue ("assocMethod1", "Use SetRoutingTableAssociation () method", assocMethod1);
+  cmd.AddValue ("assocMethod2", "Use AddHostNetworkAssociation () method", assocMethod2);
+  
+  cmd.Parse (argc, argv);
+  // Convert to time object
+  Time interPacketInterval = Seconds (interval);
+
+  // disable fragmentation for frames below 2200 bytes
+  Config::SetDefault ("ns3::WifiRemoteStationManager::FragmentationThreshold", StringValue ("2200"));
+  // turn off RTS/CTS for frames below 2200 bytes
+  Config::SetDefault ("ns3::WifiRemoteStationManager::RtsCtsThreshold", StringValue ("2200"));
+  // Fix non-unicast data rate to be the same as that of unicast
+  Config::SetDefault ("ns3::WifiRemoteStationManager::NonUnicastMode", 
+                      StringValue (phyMode));
+
+  NodeContainer olsrNodes;
+  olsrNodes.Create (2);
+
+  NodeContainer csmaNodes;
+  csmaNodes.Create (1);
+
+  // The below set of helpers will help us to put together the wifi NICs we want
+  WifiHelper wifi;
+  if (verbose)
+    {
+      wifi.EnableLogComponents ();  // Turn on all Wifi logging
+    }
+  wifi.SetStandard (WIFI_PHY_STANDARD_80211b);
+
+  YansWifiPhyHelper wifiPhy =  YansWifiPhyHelper::Default ();
+  // This is one parameter that matters when using FixedRssLossModel
+  // set it to zero; otherwise, gain will be added
+  wifiPhy.Set ("RxGain", DoubleValue (0) ); 
+  // ns-3 supports RadioTap and Prism tracing extensions for 802.11b
+  wifiPhy.SetPcapDataLinkType (YansWifiPhyHelper::DLT_IEEE802_11_RADIO);
+
+  YansWifiChannelHelper wifiChannel ;
+  wifiChannel.SetPropagationDelay ("ns3::ConstantSpeedPropagationDelayModel");
+  // The below FixedRssLossModel will cause the rss to be fixed regardless
+  // of the distance between the two stations, and the transmit power
+  wifiChannel.AddPropagationLoss ("ns3::FixedRssLossModel","Rss",DoubleValue(rss));
+  wifiPhy.SetChannel (wifiChannel.Create ());
+
+  // Add a non-QoS upper mac, and disable rate control
+  NqosWifiMacHelper wifiMac = NqosWifiMacHelper::Default ();
+  wifi.SetRemoteStationManager ("ns3::ConstantRateWifiManager",
+                                "DataMode",StringValue(phyMode),
+                                   "ControlMode",StringValue(phyMode));
+  // Set it to adhoc mode
+  wifiMac.SetType ("ns3::AdhocWifiMac");
+  NetDeviceContainer devices = wifi.Install (wifiPhy, wifiMac, olsrNodes);
+
+  CsmaHelper csma;
+  csma.SetChannelAttribute ("DataRate", DataRateValue (DataRate (5000000)));
+  csma.SetChannelAttribute ("Delay", TimeValue (MilliSeconds (2)));
+  NetDeviceContainer csmaDevices = csma.Install (NodeContainer (csmaNodes.Get(0), olsrNodes.Get(1)));
+
+  // Note that with FixedRssLossModel, the positions below are not 
+  // used for received signal strength. 
+  MobilityHelper mobility;
+  Ptr<ListPositionAllocator> positionAlloc = CreateObject<ListPositionAllocator> ();
+  positionAlloc->Add (Vector (0.0, 0.0, 0.0));
+  positionAlloc->Add (Vector (5.0, 0.0, 0.0));
+  mobility.SetPositionAllocator (positionAlloc);
+  mobility.SetMobilityModel ("ns3::ConstantPositionMobilityModel");
+  mobility.Install (olsrNodes);
+
+  OlsrHelper olsr;
+
+  // Specify Node B's csma device as a non-OLSR device.
+  olsr.ExcludeInterface (olsrNodes.Get (1), 2);
+
+  Ipv4StaticRoutingHelper staticRouting;
+
+  Ipv4ListRoutingHelper list;
+  list.Add (staticRouting, 0);
+  list.Add (olsr, 10);
+
+  InternetStackHelper internet_olsr;
+  internet_olsr.SetRoutingHelper (list);
+  internet_olsr.Install (olsrNodes);
+
+  InternetStackHelper internet_csma;
+  internet_csma.Install (csmaNodes);
+
+  Ipv4AddressHelper ipv4;
+  NS_LOG_INFO ("Assign IP Addresses.");
+  ipv4.SetBase ("10.1.1.0", "255.255.255.0");
+  ipv4.Assign (devices);
+
+  ipv4.SetBase ("172.16.1.0", "255.255.255.0");
+  ipv4.Assign (csmaDevices);
+
+  TypeId tid = TypeId::LookupByName ("ns3::UdpSocketFactory");
+  Ptr<Socket> recvSink = Socket::CreateSocket (csmaNodes.Get(0), tid);
+  InetSocketAddress local = InetSocketAddress (Ipv4Address::GetAny (), 80);
+  recvSink->Bind (local);
+  recvSink->SetRecvCallback (MakeCallback (&ReceivePacket));
+
+  Ptr<Socket> source = Socket::CreateSocket (olsrNodes.Get (0), tid);
+  InetSocketAddress remote = InetSocketAddress (Ipv4Address ("172.16.1.1"), 80);
+  source->Connect (remote);
+
+  // Obtain olsr::RoutingProtocol instance of gateway node
+  // (namely, node B) and add the required association
+  Ptr<Ipv4> stack = olsrNodes.Get (1) -> GetObject<Ipv4> ();
+  Ptr<Ipv4RoutingProtocol> rp_Gw = (stack->GetRoutingProtocol ());
+  Ptr<Ipv4ListRouting> lrp_Gw = DynamicCast<Ipv4ListRouting> (rp_Gw);
+
+  Ptr<olsr::RoutingProtocol> olsrrp_Gw;
+
+  for (uint32_t i = 0; i < lrp_Gw->GetNRoutingProtocols ();  i++)
+    {
+      int16_t priority;
+      Ptr<Ipv4RoutingProtocol> temp = lrp_Gw->GetRoutingProtocol (i, priority);
+      if (DynamicCast<olsr::RoutingProtocol> (temp))
+        {
+          olsrrp_Gw = DynamicCast<olsr::RoutingProtocol> (temp);
+        }
+    }
+
+  // Create a special Ipv4StaticRouting instance for RoutingTableAssociation
+  // Even the Ipv4StaticRouting instance added to list may be used
+  Ptr<Ipv4StaticRouting> hnaEntries = Create<Ipv4StaticRouting> ();
+
+  if (assocMethod1)
+    {
+      // Add the required routes into the Ipv4StaticRouting Protocol instance
+      // and have the node generate HNA messages for all these routes
+      // which are associated with non-OLSR interfaces specified above.
+      hnaEntries->AddNetworkRouteTo (Ipv4Address ("172.16.1.0"), Ipv4Mask ("255.255.255.0"), uint32_t(2), uint32_t(1));
+      olsrrp_Gw->SetRoutingTableAssociation (hnaEntries);
+    }
+ 
+  if (assocMethod2)
+    {
+      // Specify the required associations directly.
+      olsrrp_Gw->AddHostNetworkAssociation (Ipv4Address ("172.16.1.0"), Ipv4Mask ("255.255.255.0"));
+    }
+
+  // Tracing
+  wifiPhy.EnablePcap ("olsr-hna", devices);
+  csma.EnablePcap ("olsr-hna", csmaDevices, false);
+
+  Simulator::ScheduleWithContext (source->GetNode ()->GetId (),
+                                  Seconds (15.0), &GenerateTraffic, 
+                                  source, packetSize, numPackets, interPacketInterval);
+
+  Simulator::Stop (Seconds (20.0));
+  Simulator::Run ();
+  Simulator::Destroy ();
+
+  return 0;
+}
--- a/examples/routing/wscript	Wed Mar 17 14:14:59 2010 +0000
+++ b/examples/routing/wscript	Wed Mar 17 15:46:42 2010 +0000
@@ -33,6 +33,10 @@
                                  ['point-to-point', 'internet-stack', 'olsr'])
     obj.source = 'simple-point-to-point-olsr.cc'
 
+    obj = bld.create_ns3_program('olsr-hna',
+                                 ['core', 'simulator', 'mobility', 'wifi'])
+    obj.source = 'olsr-hna.cc'
+
     obj = bld.create_ns3_program('nix-simple',
                                  ['point-to-point', 'internet-stack', 'nix-vector-routing'])
     obj.source = 'nix-simple.cc'
--- a/src/helper/olsr-helper.cc	Wed Mar 17 14:14:59 2010 +0000
+++ b/src/helper/olsr-helper.cc	Wed Mar 17 15:46:42 2010 +0000
@@ -33,6 +33,7 @@
 OlsrHelper::OlsrHelper (const OlsrHelper &o)
   : m_agentFactory (o.m_agentFactory)
 {
+  m_interfaceExclusions = o.m_interfaceExclusions;
 }
 
 OlsrHelper* 
@@ -41,10 +42,36 @@
   return new OlsrHelper (*this); 
 }
 
+void
+OlsrHelper::ExcludeInterface (Ptr<Node> node, uint32_t interface)
+{
+  std::map< Ptr<Node>, std::set<uint32_t> >::iterator it = m_interfaceExclusions.find (node);
+
+  if(it == m_interfaceExclusions.end ())
+    {
+      std::set<uint32_t> interfaces;
+      interfaces.insert (interface);
+    
+      m_interfaceExclusions.insert (std::make_pair (node, std::set<uint32_t> (interfaces) ));
+    }
+  else
+    {
+      it->second.insert (interface);
+    }
+}
+
 Ptr<Ipv4RoutingProtocol> 
 OlsrHelper::Create (Ptr<Node> node) const
 {
   Ptr<olsr::RoutingProtocol> agent = m_agentFactory.Create<olsr::RoutingProtocol> ();
+
+  std::map<Ptr<Node>, std::set<uint32_t> >::const_iterator it = m_interfaceExclusions.find (node);
+
+  if(it != m_interfaceExclusions.end ())
+    {
+      agent->SetInterfaceExclusions (it->second);
+    }
+
   node->AggregateObject (agent);
   return agent;
 }
--- a/src/helper/olsr-helper.h	Wed Mar 17 14:14:59 2010 +0000
+++ b/src/helper/olsr-helper.h	Wed Mar 17 15:46:42 2010 +0000
@@ -24,6 +24,8 @@
 #include "ns3/node.h"
 #include "node-container.h"
 #include "ipv4-routing-helper.h"
+#include <map>
+#include <set>
 
 namespace ns3 {
 
@@ -57,6 +59,14 @@
    */
   OlsrHelper* Copy (void) const;
 
+ /**
+   * \param node the node for which an exception is to be defined
+   * \param interface an interface of node on which OLSR is not to be installed
+   *
+   * This method allows the user to specify an interface on which OLSR is not to be installed on
+   */
+  void ExcludeInterface (Ptr<Node> node, uint32_t interface);
+
   /**
    * \param node the node on which the routing protocol will run
    * \returns a newly-created routing protocol
@@ -72,6 +82,7 @@
    * This method controls the attributes of ns3::olsr::RoutingProtocol
    */
   void Set (std::string name, const AttributeValue &value);
+
 private:
   /**
    * \internal
@@ -80,6 +91,8 @@
    */
   OlsrHelper &operator = (const OlsrHelper &o);
   ObjectFactory m_agentFactory;
+
+  std::map< Ptr<Node>, std::set<uint32_t> > m_interfaceExclusions;
 };
 
 } // namespace ns3
--- a/src/routing/olsr/olsr-repositories.h	Wed Mar 17 14:14:59 2010 +0000
+++ b/src/routing/olsr/olsr-repositories.h	Wed Mar 17 15:46:42 2010 +0000
@@ -231,6 +231,61 @@
   return os;
 }
 
+/// Association
+struct Association
+{
+  Ipv4Address networkAddr;
+  Ipv4Mask netmask;
+};
+
+static inline bool
+operator == (const Association &a, const Association &b)
+{
+  return (a.networkAddr == b.networkAddr
+          && a.netmask == b.netmask);
+}
+
+static inline std::ostream&
+operator << (std::ostream &os, const Association &tuple)
+{
+  os << "Association(networkAddr=" << tuple.networkAddr
+     << ", netmask=" << tuple.netmask
+     << ")";
+  return os;
+}
+
+/// An Association Tuple
+struct AssociationTuple
+{
+  /// Main address of the gateway.
+  Ipv4Address gatewayAddr;
+  /// Network Address of network reachable through gatewayAddr
+  Ipv4Address networkAddr;
+  /// Netmask of network reachable through gatewayAddr
+  Ipv4Mask netmask;
+  /// Time at which this tuple expires and must be removed
+  Time expirationTime;
+};
+
+static inline bool
+operator == (const AssociationTuple &a, const AssociationTuple &b)
+{
+  return (a.gatewayAddr == b.gatewayAddr
+          && a.networkAddr == b.networkAddr
+          && a.netmask == b.netmask);
+}
+
+static inline std::ostream&
+operator << (std::ostream &os, const AssociationTuple &tuple)
+{
+  os << "AssociationTuple(gatewayAddr=" << tuple.gatewayAddr
+     << ", networkAddr=" << tuple.networkAddr
+     << ", netmask=" << tuple.netmask
+     << ", expirationTime=" << tuple.expirationTime
+     << ")";
+  return os;
+}
+
 
 typedef std::set<Ipv4Address> 			MprSet;	///< MPR Set type.
 typedef std::vector<MprSelectorTuple>		MprSelectorSet;	///< MPR Selector Set type.
@@ -240,6 +295,8 @@
 typedef std::vector<TopologyTuple>		TopologySet;	///< Topology Set type.
 typedef std::vector<DuplicateTuple>		DuplicateSet;	///< Duplicate Set type.
 typedef std::vector<IfaceAssocTuple>		IfaceAssocSet; ///< Interface Association Set type.
+typedef std::vector<AssociationTuple>		AssociationSet; ///< Association Set type.
+typedef std::vector<Association>		Associations; ///< Association Set type.
 
 
 }}; // namespace ns3, olsr
--- a/src/routing/olsr/olsr-routing-protocol.cc	Wed Mar 17 14:14:59 2010 +0000
+++ b/src/routing/olsr/olsr-routing-protocol.cc	Wed Mar 17 15:46:42 2010 +0000
@@ -41,6 +41,7 @@
 #include "ns3/random-variable.h"
 #include "ns3/inet-socket-address.h"
 #include "ns3/ipv4-routing-protocol.h"
+#include "ns3/ipv4-routing-table-entry.h"
 #include "ns3/ipv4-route.h"
 #include "ns3/boolean.h"
 #include "ns3/uinteger.h"
@@ -79,7 +80,8 @@
 #define OLSR_DUP_HOLD_TIME	Seconds (30)
 /// MID holding time.
 #define OLSR_MID_HOLD_TIME	(Scalar (3) * m_midInterval)
-
+/// HNA holding time.
+#define OLSR_HNA_HOLD_TIME  (Scalar (3) * m_hnaInterval)
 
 /********** Link types **********/
 
@@ -165,6 +167,10 @@
                    TimeValue (Seconds (5)),
                    MakeTimeAccessor (&RoutingProtocol::m_midInterval),
                    MakeTimeChecker ())
+    .AddAttribute ("HnaInterval", "HNA messages emission interval.  Normally it is equal to TcInterval.",
+                   TimeValue (Seconds (5)),
+                   MakeTimeAccessor (&RoutingProtocol::m_hnaInterval),
+                   MakeTimeChecker ())
     .AddAttribute ("Willingness", "Willingness of a node to carry and forward traffic for other nodes.",
                    EnumValue (OLSR_WILL_DEFAULT),
                    MakeEnumAccessor (&RoutingProtocol::m_willingness),
@@ -185,12 +191,16 @@
 
 
 RoutingProtocol::RoutingProtocol ()
-  : m_ipv4 (0),
+  : m_routingTableAssociation (0),
+    m_ipv4 (0),
     m_helloTimer (Timer::CANCEL_ON_DESTROY),
     m_tcTimer (Timer::CANCEL_ON_DESTROY),
     m_midTimer (Timer::CANCEL_ON_DESTROY),
+    m_hnaTimer (Timer::CANCEL_ON_DESTROY),    
     m_queuedMessagesTimer (Timer::CANCEL_ON_DESTROY)
-{}
+{
+  m_hnaRoutingTable = Create<Ipv4StaticRouting> ();
+}
 
 RoutingProtocol::~RoutingProtocol ()
 {}
@@ -204,6 +214,7 @@
   m_helloTimer.SetFunction (&RoutingProtocol::HelloTimerExpire, this);
   m_tcTimer.SetFunction (&RoutingProtocol::TcTimerExpire, this);
   m_midTimer.SetFunction (&RoutingProtocol::MidTimerExpire, this);
+  m_hnaTimer.SetFunction (&RoutingProtocol::HnaTimerExpire, this);
   m_queuedMessagesTimer.SetFunction (&RoutingProtocol::SendQueuedMessages, this);
 
   m_packetSequenceNumber = OLSR_MAX_SEQ_NUM;
@@ -213,11 +224,15 @@
   m_linkTupleTimerFirstTime = true;
 
   m_ipv4 = ipv4;
+  
+  m_hnaRoutingTable->SetIpv4 (ipv4);
 }
 
 void RoutingProtocol::DoDispose ()
 {
   m_ipv4 = 0;
+  m_hnaRoutingTable = 0;
+  m_routingTableAssociation = 0;
 
   for (std::map< Ptr<Socket>, Ipv4InterfaceAddress >::iterator iter = m_socketAddresses.begin ();
        iter != m_socketAddresses.end (); iter++)
@@ -251,6 +266,8 @@
   NS_LOG_DEBUG ("Starting OLSR on node " << m_mainAddress);
 
   Ipv4Address loopback ("127.0.0.1");
+
+  bool canRunOlsr = false;
   for (uint32_t i = 0; i < m_ipv4->GetNInterfaces (); i++)
     {
       Ipv4Address addr = m_ipv4->GetAddress (i, 0).GetLocal ();
@@ -269,6 +286,9 @@
           NS_ASSERT (GetMainAddress (addr) == m_mainAddress);
         }
 
+      if(m_interfaceExclusions.find (i) != m_interfaceExclusions.end ())
+        continue;
+
       // Create a socket to listen only on this interface
       Ptr<Socket> socket = Socket::CreateSocket (GetObject<Node> (), 
         UdpSocketFactory::GetTypeId()); 
@@ -279,13 +299,19 @@
         }
       socket->Connect (InetSocketAddress (Ipv4Address (0xffffffff), OLSR_PORT_NUMBER));
       m_socketAddresses[socket] = m_ipv4->GetAddress (i, 0);
+
+      canRunOlsr = true;
     }
 
-  HelloTimerExpire ();
-  TcTimerExpire ();
-  MidTimerExpire ();
+  if(canRunOlsr)
+   {
+      HelloTimerExpire ();
+      TcTimerExpire ();
+      MidTimerExpire ();
+      HnaTimerExpire ();      
 
-  NS_LOG_DEBUG ("OLSR on node " << m_mainAddress << " started");
+      NS_LOG_DEBUG ("OLSR on node " << m_mainAddress << " started");
+   }
 }
 
 void RoutingProtocol::SetMainInterface (uint32_t interface)
@@ -293,6 +319,10 @@
   m_mainAddress = m_ipv4->GetAddress (interface, 0).GetLocal ();
 }
 
+void RoutingProtocol::SetInterfaceExclusions (std::set<uint32_t> exceptions)
+{
+  m_interfaceExclusions = exceptions;
+}
 
 //
 // \brief Processes an incoming %OLSR packet following RFC 3626 specification.
@@ -397,6 +427,12 @@
                             <<  " received MID message of size " << messageHeader.GetSerializedSize ());
               ProcessMid (messageHeader, senderIfaceAddr);
               break;
+            case olsr::MessageHeader::HNA_MESSAGE:
+              NS_LOG_DEBUG (Simulator::Now ().GetSeconds ()
+                            << "s OLSR node " << m_mainAddress
+                            <<  " received HNA message of size " << messageHeader.GetSerializedSize ());
+              ProcessHna (messageHeader, senderIfaceAddr);
+              break; 
 
             default:
               NS_LOG_DEBUG ("OLSR message type " <<
@@ -1039,6 +1075,53 @@
         }
     }
 
+  // 5. For each tuple in the association set,
+  //    If there is no entry in the routing table with:
+  //        R_dest_addr     == A_network_addr/A_netmask
+  //   then a new routing entry is created.
+  const AssociationSet &associationSet = m_state.GetAssociationSet ();
+  for (AssociationSet::const_iterator it = associationSet.begin ();
+       it != associationSet.end (); it++)
+    {
+      AssociationTuple const &tuple = *it;
+      RoutingTableEntry gatewayEntry;
+      
+      bool gatewayEntryExists = Lookup (tuple.gatewayAddr, gatewayEntry);
+      bool addRoute = false;
+      
+      uint32_t routeIndex = 0;
+      
+      for (routeIndex = 0; routeIndex < m_hnaRoutingTable->GetNRoutes (); routeIndex++)
+        {
+          Ipv4RoutingTableEntry route = m_hnaRoutingTable->GetRoute (routeIndex);
+          if (route.GetDestNetwork () == tuple.networkAddr &&
+              route.GetDestNetworkMask () == tuple.netmask)
+            {
+              break;
+            }
+        }
+    
+      if (routeIndex == m_hnaRoutingTable->GetNRoutes ())
+        {
+          addRoute = true;
+        }
+      else if(gatewayEntryExists && m_hnaRoutingTable->GetMetric (routeIndex) > gatewayEntry.distance)
+        {
+          m_hnaRoutingTable->RemoveRoute(routeIndex);
+          addRoute = true;
+        }
+        
+      if(addRoute && gatewayEntryExists)
+        {
+          m_hnaRoutingTable->AddNetworkRouteTo (tuple.networkAddr,
+                                                tuple.netmask,
+                                                gatewayEntry.nextAddr,
+                                                gatewayEntry.interface,
+                                                gatewayEntry.distance);
+                                             
+        }
+    }
+
   NS_LOG_DEBUG ("Node " << m_mainAddress << ": RoutingTableComputation end.");
   m_routingTableChanged (GetSize ());
 }
@@ -1280,6 +1363,67 @@
   NS_LOG_DEBUG ("Node " << m_mainAddress << " ProcessMid from " << senderIface << " -> END.");
 }
 
+///
+/// \brief Processes a HNA message following RFC 3626 specification.
+///
+/// The Host Network Association Set is updated (if needed) with the information
+/// of the received HNA message.
+///
+/// \param msg the %OLSR message which contains the HNA message.
+/// \param sender_iface the address of the interface where the message was sent from.
+///
+void
+RoutingProtocol::ProcessHna (const olsr::MessageHeader &msg,
+                       const Ipv4Address &senderIface)
+{
+
+  const olsr::MessageHeader::Hna &hna = msg.GetHna ();
+  Time now = Simulator::Now ();
+  
+  // 1. If the sender interface of this message is not in the symmetric
+  // 1-hop neighborhood of this node, the message MUST be discarded.
+  const LinkTuple *link_tuple = m_state.FindSymLinkTuple (senderIface, now);
+  if (link_tuple == NULL)
+    return;
+  
+  // 2. Otherwise, for each (network address, netmask) pair in the
+  // message:
+  
+  for (std::vector<olsr::MessageHeader::Hna::Association>::const_iterator it = hna.associations.begin();
+       it != hna.associations.end() ; it++)
+    {
+      AssociationTuple *tuple = m_state.FindAssociationTuple(msg.GetOriginatorAddress(),it->address,it->mask);
+  
+      // 2.1  if an entry in the association set already exists, where:
+      //          A_gateway_addr == originator address
+      //          A_network_addr == network address
+      //          A_netmask      == netmask
+      //      then the holding time for that tuple MUST be set to:
+      //          A_time         =  current time + validity time
+      if(tuple != NULL)
+        {
+          tuple->expirationTime = now + msg.GetVTime ();
+        }
+        
+      // 2.2 otherwise, a new tuple MUST be recorded with:
+      //          A_gateway_addr =  originator address
+      //          A_network_addr =  network address
+      //          A_netmask      =  netmask
+      //          A_time         =  current time + validity time
+      else
+        {
+          const AssociationTuple &assocTuple = (AssociationTuple){msg.GetOriginatorAddress(),it->address,it->mask,now + msg.GetVTime ()};
+          
+          AddAssociationTuple (assocTuple);
+          
+          //Schedule Association Tuple deletion
+          Simulator::Schedule (DELAY (assocTuple.expirationTime),
+                               &RoutingProtocol::AssociationTupleTimerExpire, this,
+                               assocTuple.gatewayAddr,assocTuple.networkAddr,assocTuple.netmask);
+        }
+        
+    }
+}
 
 ///
 /// \brief OLSR's default forwarding algorithm.
@@ -1447,7 +1591,7 @@
 RoutingProtocol::SendHello ()
 {
   NS_LOG_FUNCTION (this);
-  
+    
   olsr::MessageHeader msg;
   Time now = Simulator::Now ();
 
@@ -1569,6 +1713,7 @@
   
   olsr::MessageHeader::Tc &tc = msg.GetTc ();
   tc.ansn = m_ansn;
+      
   for (MprSelectorSet::const_iterator mprsel_tuple = m_state.GetMprSelectors ().begin();
        mprsel_tuple != m_state.GetMprSelectors ().end(); mprsel_tuple++)
     {
@@ -1622,6 +1767,94 @@
 }
 
 ///
+/// \brief Creates a new %OLSR HNA message which is buffered for being sent later on.
+///
+void
+RoutingProtocol::SendHna ()
+{
+
+  olsr::MessageHeader msg;
+
+  msg.SetVTime (OLSR_HNA_HOLD_TIME);
+  msg.SetOriginatorAddress (m_mainAddress);
+  msg.SetTimeToLive (255);
+  msg.SetHopCount (0);
+  msg.SetMessageSequenceNumber (GetMessageSequenceNumber ());
+  olsr::MessageHeader::Hna &hna = msg.GetHna ();
+  
+  std::vector<olsr::MessageHeader::Hna::Association>
+    &associations = hna.associations;
+      
+  if (m_routingTableAssociation != 0)
+    {
+      // Add (NetworkAddr, Netmask) entries from Associated Routing Table to HNA message.
+      for (uint32_t i = 0; i < m_routingTableAssociation->GetNRoutes (); i++)
+        {
+          Ipv4RoutingTableEntry route = m_routingTableAssociation->GetRoute (i);
+          
+          std::set<uint32_t>::const_iterator ci = m_interfaceExclusions.find (route.GetInterface ());
+                  
+          if (ci != m_interfaceExclusions.end ())
+            {
+              olsr::MessageHeader::Hna::Association assoc = {route.GetDestNetwork (), route.GetDestNetworkMask ()};
+              associations.push_back(assoc);
+            }
+        }
+    }
+    
+  int size = associations.size ();
+
+  // Add (NetworkAddr, Netmask) entries specified using AddHostNetworkAssociation () to HNA message.
+  for (Associations::const_iterator it = m_state.GetAssociations ().begin ();
+        it != m_state.GetAssociations ().end (); it++)
+    {
+      // Check if the entry has already been added from the Associated Routing Table
+      std::vector<olsr::MessageHeader::Hna::Association>::const_iterator ci = associations.begin ();
+      bool found = false;
+      for (int i = 0; i < size; i++)
+        {
+          if (it->networkAddr == ci->address && it->netmask == ci->mask)
+            {
+              found = true;
+              break;
+            }
+          ci++;
+        }
+      
+      if(!found)
+        {
+          olsr::MessageHeader::Hna::Association assoc = {it->networkAddr,it->netmask};
+          associations.push_back(assoc);
+        }
+    }
+    
+  if(associations.size () == 0)
+    return;
+  
+  QueueMessage (msg, JITTER);
+}
+
+///
+/// \brief Injects a (networkAddr, netmask) tuple for which the node
+///        can generate an HNA message for
+///
+void
+RoutingProtocol::AddHostNetworkAssociation (Ipv4Address networkAddr, Ipv4Mask netmask)
+{
+  m_state.InsertAssociation ((Association) {networkAddr, netmask});
+}
+
+///
+/// \brief Adds an Ipv4StaticRouting protocol Association
+///        can generate an HNA message for
+///
+void
+RoutingProtocol::SetRoutingTableAssociation (Ptr<Ipv4StaticRouting> routingTable)
+{
+  m_routingTableAssociation = routingTable;
+}
+
+///
 /// \brief	Updates Link Set according to a new received HELLO message (following RFC 3626
 ///		specification). Neighbor Set is also updated if needed.
 void
@@ -2301,6 +2534,29 @@
   m_state.EraseIfaceAssocTuple (tuple);
 }
 
+///
+/// \brief Adds a host network association tuple to the Association Set.
+///
+/// \param tuple the host network association tuple to be added.
+///
+void
+RoutingProtocol::AddAssociationTuple (const AssociationTuple &tuple)
+{
+  m_state.InsertAssociationTuple (tuple);
+}
+
+///
+/// \brief Removes a host network association tuple from the Association Set.
+///
+/// \param tuple the host network association tuple to be removed.
+///
+void
+RoutingProtocol::RemoveAssociationTuple (const AssociationTuple &tuple)
+{
+  m_state.EraseAssociationTuple (tuple);
+}
+
+
 
 uint16_t RoutingProtocol::GetPacketSequenceNumber ()
 {
@@ -2358,6 +2614,24 @@
 }
 
 ///
+/// \brief Sends an HNA message (if the node has associated hosts/networks) and reschedules the HNA timer.
+/// \param e The event which has expired.
+///
+void
+RoutingProtocol::HnaTimerExpire ()
+{
+  if (m_state.GetAssociations ().size () > 0 || m_routingTableAssociation !=0)
+    {
+      SendHna ();
+    }
+  else
+    {
+      NS_LOG_DEBUG ("Not sending any HNA, no associations to advertise.");
+    }
+  m_hnaTimer.Schedule (m_hnaInterval);
+}
+
+///
 /// \brief Removes tuple if expired. Else timer is rescheduled to expire at tuple.expirationTime.
 ///
 /// The task of actually removing the tuple is left to the OLSR agent.
@@ -2537,6 +2811,29 @@
     }
 }
 
+/// \brief Removes tuple_ if expired. Else timer is rescheduled to expire at tuple_->time().
+/// \param e The event which has expired.
+///
+void
+RoutingProtocol::AssociationTupleTimerExpire (Ipv4Address gatewayAddr, Ipv4Address networkAddr, Ipv4Mask netmask)
+{
+  AssociationTuple *tuple = m_state.FindAssociationTuple (gatewayAddr, networkAddr, netmask);
+  if (tuple == NULL)
+    {
+      return;
+    }
+  if (tuple->expirationTime < Simulator::Now ())
+    {
+      RemoveAssociationTuple (*tuple);
+    }
+  else
+    {
+      m_events.Track (Simulator::Schedule (DELAY (tuple->expirationTime),
+                                           &RoutingProtocol::AssociationTupleTimerExpire,
+                                           this, gatewayAddr, networkAddr, netmask));
+    }
+}
+
 ///
 /// \brief Clears the routing table and frees the memory assigned to each one of its entries.
 ///
@@ -2612,6 +2909,8 @@
   NS_LOG_FUNCTION (this << " " << m_ipv4->GetObject<Node> ()->GetId() << " " << header.GetDestination () << " " << oif);
   Ptr<Ipv4Route> rtentry;
   RoutingTableEntry entry1, entry2;
+  bool found = false;
+  
   if (Lookup (header.GetDestination (), entry1) != 0)
     {
       bool foundSendEntry = FindSendEntry (entry1, entry2);
@@ -2654,10 +2953,23 @@
       NS_LOG_DEBUG ("Olsr node " << m_mainAddress 
                     << ": RouteOutput for dest=" << header.GetDestination ()
                     << " --> nextHop=" << entry2.nextAddr
-                    << " interface=" << entry2.interface);      NS_LOG_DEBUG ("Found route to " << rtentry->GetDestination () << " via nh " << rtentry->GetGateway () << " with source addr " << rtentry->GetSource () << " and output dev " << rtentry->GetOutputDevice());
+                    << " interface=" << entry2.interface);
+      NS_LOG_DEBUG ("Found route to " << rtentry->GetDestination () << " via nh " << rtentry->GetGateway () << " with source addr " << rtentry->GetSource () << " and output dev " << rtentry->GetOutputDevice());
+      found = true;
     }
   else
     { 
+      rtentry = m_hnaRoutingTable->RouteOutput (p, header, oif, sockerr);
+      
+      if (rtentry)
+        {
+          found = true;
+          NS_LOG_DEBUG ("Found route to " << rtentry->GetDestination () << " via nh " << rtentry->GetGateway () << " with source addr " << rtentry->GetSource () << " and output dev " << rtentry->GetOutputDevice());
+        }
+    }
+    
+  if (!found)
+    {
       NS_LOG_DEBUG ("Olsr node " << m_mainAddress 
                     << ": RouteOutput for dest=" << header.GetDestination ()
                     << " No route to host");
@@ -2729,18 +3041,30 @@
     }
   else
     {
+      if(m_hnaRoutingTable->RouteInput (p, header, idev, ucb, mcb, lcb, ecb))
+        {
+          return true;
+        }
+      else
+        {
+        
 #ifdef NS3_LOG_ENABLE
-      NS_LOG_DEBUG ("Olsr node " << m_mainAddress 
+          NS_LOG_DEBUG ("Olsr node " << m_mainAddress 
                     << ": RouteInput for dest=" << header.GetDestination ()
-                    << " --> NOT FOUND; ** Dumping routing table...");      for (std::map<Ipv4Address, RoutingTableEntry>::const_iterator iter = m_table.begin ();
-           iter != m_table.end (); iter++)
-        {           NS_LOG_DEBUG ("dest=" << iter->first << " --> next=" << iter->second.nextAddr                 
+                    << " --> NOT FOUND; ** Dumping routing table...");      
+                    
+          for (std::map<Ipv4Address, RoutingTableEntry>::const_iterator iter = m_table.begin ();
+             iter != m_table.end (); iter++)
+          { 
+            NS_LOG_DEBUG ("dest=" << iter->first << " --> next=" << iter->second.nextAddr                 
                         << " via interface " << iter->second.interface);
+          }
+      
+          NS_LOG_DEBUG ("** Routing table dump end.");
+#endif // NS3_LOG_ENABLE
+
+          return false;
         }
-      
-      NS_LOG_DEBUG ("** Routing table dump end.");
-#endif // NS3_LOG_ENABLE
-      return false;
     }
 }
 void 
--- a/src/routing/olsr/olsr-routing-protocol.h	Wed Mar 17 14:14:59 2010 +0000
+++ b/src/routing/olsr/olsr-routing-protocol.h	Wed Mar 17 15:46:42 2010 +0000
@@ -38,6 +38,7 @@
 #include "ns3/traced-callback.h"
 #include "ns3/ipv4.h"
 #include "ns3/ipv4-routing-protocol.h"
+#include "ns3/ipv4-static-routing.h"
 
 #include <vector>
 #include <map>
@@ -105,11 +106,30 @@
    **/
   std::vector<RoutingTableEntry> GetRoutingTableEntries () const;
 
+private:
+  std::set<uint32_t> m_interfaceExclusions;
+  Ptr<Ipv4StaticRouting> m_routingTableAssociation;
+
+public:
+  std::set<uint32_t> GetInterfaceExclusions () const
+    {
+      return m_interfaceExclusions;
+    }
+  void SetInterfaceExclusions (std::set<uint32_t> exceptions);
+
+  /// Inject Association to be sent in HNA message
+  void AddHostNetworkAssociation (Ipv4Address networkAddr, Ipv4Mask netmask);
+
+  /// Inject Associations from an Ipv4StaticRouting instance
+  void SetRoutingTableAssociation (Ptr<Ipv4StaticRouting> routingTable);
+
 protected:
   virtual void DoStart (void);
 private:
   std::map<Ipv4Address, RoutingTableEntry> m_table; ///< Data structure for the routing table.
 
+  Ptr<Ipv4StaticRouting> m_hnaRoutingTable;
+
   EventGarbageCollector m_events;
 
   /// Address of the routing agent.
@@ -128,6 +148,8 @@
   Time m_tcInterval;
   /// MID messages' emission interval.
   Time m_midInterval;
+  /// HNA messages' emission interval.
+  Time m_hnaInterval;
   /// Willingness for forwarding packets on behalf of other nodes.
   uint8_t m_willingness;
 	
@@ -189,6 +211,9 @@
   Timer m_midTimer;
   void MidTimerExpire ();
 
+  Timer m_hnaTimer;
+  void HnaTimerExpire ();
+
   void DupTupleTimerExpire (Ipv4Address address, uint16_t sequenceNumber);
   bool m_linkTupleTimerFirstTime;
   void LinkTupleTimerExpire (Ipv4Address neighborIfaceAddr);
@@ -196,6 +221,7 @@
   void MprSelTupleTimerExpire (Ipv4Address mainAddr);
   void TopologyTupleTimerExpire (Ipv4Address destAddr, Ipv4Address lastAddr);
   void IfaceAssocTupleTimerExpire (Ipv4Address ifaceAddr);
+  void AssociationTupleTimerExpire (Ipv4Address gatewayAddr, Ipv4Address networkAddr, Ipv4Mask netmask);
 
   void IncrementAnsn ();
 
@@ -212,6 +238,7 @@
   void SendHello ();
   void SendTc ();
   void SendMid ();
+  void SendHna ();
 
   void NeighborLoss (const LinkTuple &tuple);
   void AddDuplicateTuple (const DuplicateTuple &tuple);
@@ -229,6 +256,8 @@
   void RemoveTopologyTuple (const TopologyTuple &tuple);
   void AddIfaceAssocTuple (const IfaceAssocTuple &tuple);
   void RemoveIfaceAssocTuple (const IfaceAssocTuple &tuple);
+  void AddAssociationTuple (const AssociationTuple &tuple);
+  void RemoveAssociationTuple (const AssociationTuple &tuple);
 
   void ProcessHello (const olsr::MessageHeader &msg,
                      const Ipv4Address &receiverIface,
@@ -237,6 +266,8 @@
                   const Ipv4Address &senderIface);
   void ProcessMid (const olsr::MessageHeader &msg,
                    const Ipv4Address &senderIface);
+  void ProcessHna (const olsr::MessageHeader &msg,
+                   const Ipv4Address &senderIface);
 
   void LinkSensing (const olsr::MessageHeader &msg,
                     const olsr::MessageHeader::Hello &hello,
--- a/src/routing/olsr/olsr-state.cc	Wed Mar 17 14:14:59 2010 +0000
+++ b/src/routing/olsr/olsr-state.cc	Wed Mar 17 15:46:42 2010 +0000
@@ -487,4 +487,60 @@
   return retval;
 }
 
+/********** Host-Network Association Set Manipulation **********/
+
+AssociationTuple*
+OlsrState::FindAssociationTuple (const Ipv4Address &gatewayAddr, const Ipv4Address &networkAddr, const Ipv4Mask &netmask)
+{
+  for (AssociationSet::iterator it = m_associationSet.begin ();
+	it != m_associationSet.end (); it++)
+    {
+      if (it->gatewayAddr == gatewayAddr and it->networkAddr == networkAddr and it->netmask == netmask)
+        {
+          return &(*it);
+        }
+    }
+   return NULL;
+}
+
+void
+OlsrState::EraseAssociationTuple (const AssociationTuple &tuple)
+{
+  for (AssociationSet::iterator it = m_associationSet.begin ();
+       it != m_associationSet.end (); it++)
+    {
+      if (*it == tuple)
+        {
+          m_associationSet.erase (it);
+          break;
+        }
+    }
+}
+
+void
+OlsrState::InsertAssociationTuple (const AssociationTuple &tuple)
+{
+  m_associationSet.push_back (tuple);
+}
+
+void
+OlsrState::EraseAssociation (const Association &tuple)
+{
+  for (Associations::iterator it = m_associations.begin ();
+       it != m_associations.end (); it++)
+    {
+      if (*it == tuple)
+        {
+          m_associations.erase (it);
+          break;
+        }
+    }
+}
+
+void
+OlsrState::InsertAssociation (const Association &tuple)
+{
+  m_associations.push_back(tuple);
+}
+
 } // namespace ns3
--- a/src/routing/olsr/olsr-state.h	Wed Mar 17 14:14:59 2010 +0000
+++ b/src/routing/olsr/olsr-state.h	Wed Mar 17 15:46:42 2010 +0000
@@ -45,6 +45,8 @@
   MprSelectorSet m_mprSelectorSet;	///< MPR Selector Set (RFC 3626, section 4.3.4).
   DuplicateSet m_duplicateSet;	///< Duplicate Set (RFC 3626, section 3.4).
   IfaceAssocSet m_ifaceAssocSet;	///< Interface Association Set (RFC 3626, section 4.1).
+  AssociationSet m_associationSet; ///<	Association Set (RFC 3626, section12.2). Associations obtained from HNA messages generated by other nodes.
+  Associations m_associations;	///< The node's local Host Network Associations that will be advertised using HNA messages.
 
 public:
 
@@ -147,6 +149,25 @@
   void EraseIfaceAssocTuple (const IfaceAssocTuple &tuple);
   void InsertIfaceAssocTuple (const IfaceAssocTuple &tuple);
 
+  // Host-Network Association
+  const AssociationSet & GetAssociationSet () const  // Associations known to the node
+  {
+    return m_associationSet;
+  }
+
+  const Associations & GetAssociations () const  // Set of associations that the node has
+  {
+    return m_associations;
+  }
+
+  AssociationTuple* FindAssociationTuple (const Ipv4Address &gatewayAddr,\
+					  const Ipv4Address &networkAddr,\
+					  const Ipv4Mask &netmask);
+  void EraseAssociationTuple (const AssociationTuple &tuple);
+  void InsertAssociationTuple (const AssociationTuple &tuple);
+  void EraseAssociation (const Association &tuple);
+  void InsertAssociation (const Association &tuple);
+
   // Returns a vector of all interfaces of a given neighbor, with the
   // exception of the "main" one.
   std::vector<Ipv4Address>