diff --git a/Scripts/install-build-manet-rank-sim.sh b/Scripts/install-build-manet-rank-sim.sh
new file mode 100644
index 0000000000000000000000000000000000000000..a3d0d2050bef73101a04376d4f8a8600604451c0
--- /dev/null
+++ b/Scripts/install-build-manet-rank-sim.sh
@@ -0,0 +1,54 @@
+#!/bin/bash
+
+# enable specific modules and a pre-built python environment.
+module load gcc/8.5.0
+module load cmake/3.25.2
+
+## clean, configure and build
+#!/bin/bash
+
+# Check if the argument is provided
+if [ -z "$1" ]; then
+  echo "Please provide an argument."
+  exit 1
+fi
+
+# Assign the argument to a variable
+input="$1"
+
+# Test the input and execute code accordingly
+if [ "$input" == "clean-debug" ]; then
+  	./ns3 clean
+	./ns3 configure --build-profile=debug --out=build/debug
+	./ns3 build
+	cp build/debug/scratch/manet-rank/MainExperiment/ns3.36.1-manet-routing-debug manet-rank/build/v1_dbg
+	cd manet-rank/build/ || exit
+	chmod +x v1_dbg
+
+elif [ "$input" == "clean-opt" ]; then
+  	./ns3 clean
+	./ns3 configure --build-profile=optimized --out=build/optimized
+	./ns3 build
+	cp build/optimized/scratch/manet-rank-scratch/MainExperiment/ns3.36.1-manet-routing-optimized manet-rank/build/v1_opt
+	cd manet-rank/build/ || exit
+	chmod +x v1_opt
+
+elif [ "$input" == "build-debug" ]; then
+	./ns3 build
+	cp build/debug/scratch/manet-rank-scratch/MainExperiment/ns3.36.1-manet-routing-debug manet-rank/build/v1_dbg
+	cd manet-rank/build/ || exit
+	chmod +x v1_dbg
+
+elif [ "$input" == "build-opt" ]; then
+	./ns3 build
+	cp build/optimized/scratch/manet-rank-scratch/MainExperiment/ns3.36.1-manet-routing-optimized manet-rank/build/v1_opt
+	cd manet-rank/build/ || exit
+	chmod +x v1_opt
+else
+  echo "Invalid argument. Please provide a valid option."
+  exit 1
+fi
+
+# Add any common code that needs to be executed after the conditionals here
+
+echo "Script execution complete."
\ No newline at end of file
diff --git a/build/hpc_template.slurm b/build/hpc_template.slurm
new file mode 100644
index 0000000000000000000000000000000000000000..e1a87a19e1a54ecd66154db953e01556bb79ab69
--- /dev/null
+++ b/build/hpc_template.slurm
@@ -0,0 +1,13 @@
+#!/bin/bash
+#SBATCH --nodes=1
+#SBATCH --ntasks=40
+#SBATCH --cpus-per-task=1
+#SBATCH --time=0:30:00
+
+module load conda/py3-latest
+module load gcc/8.5.0
+module load cmake/3.25.2
+
+source activate myenv
+export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/[USER]/ns3-sims/workspace/ns-allinone-3.36.1/ns-3.36.1/build/optimized/lib:
+
diff --git a/build/master_template.slurm b/build/master_template.slurm
new file mode 100644
index 0000000000000000000000000000000000000000..8ac961825bfbf372c8a59a92102e57ca0660985e
--- /dev/null
+++ b/build/master_template.slurm
@@ -0,0 +1,13 @@
+#!/bin/bash
+#SBATCH --nodes=1
+#SBATCH --ntasks=1
+#SBATCH --cpus-per-task=1
+#SBATCH --time=60:00:00
+
+module load conda/py3-latest
+module load gcc/8.5.0
+module load cmake/3.25.2
+
+source activate myenv
+export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/[USER]/ns3-sims/workspace/ns-allinone-3.36.1/ns-3.36.1/build/optimized/lib:
+
diff --git a/greyattack-module/CMakeLists.txt b/greyattack-module/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..740a86a6ab7cd9aeed89e4f242c287765e332772
--- /dev/null
+++ b/greyattack-module/CMakeLists.txt
@@ -0,0 +1,38 @@
+check_include_file_cxx(stdint.h HAVE_STDINT_H)
+if(HAVE_STDINT_H)
+    add_definitions(-DHAVE_STDINT_H)
+endif()
+
+set(examples_as_tests_sources)
+if(${ENABLE_EXAMPLES})
+    set(examples_as_tests_sources
+        #test/greyattack-aodv-examples-test-suite.cc
+        )
+endif()
+
+build_lib(
+    LIBNAME greyattack-aodv
+    SOURCE_FILES 	model/greyattack-aodv.cc
+    		 	model/greyattack-aodv-id-cache.cc
+        		model/greyattack-aodv-dpd.cc
+        		model/greyattack-aodv-rtable.cc
+		        model/greyattack-aodv-rqueue.cc
+        		model/greyattack-aodv-packet.cc
+        		model/greyattack-aodv-neighbor.cc
+        		model/greyattack-aodv-routing-protocol.cc
+                helper/greyattack-aodv-helper.cc
+    HEADER_FILES model/greyattack-aodv.h
+			    model/greyattack-aodv-id-cache.h
+        		model/greyattack-aodv-dpd.h
+			    model/greyattack-aodv-rtable.h
+        		model/greyattack-aodv-rqueue.h
+        		model/greyattack-aodv-packet.h
+		        model/greyattack-aodv-neighbor.h
+        		model/greyattack-aodv-routing-protocol.h
+		        helper/greyattack-aodv-helper.h
+    LIBRARIES_TO_LINK	${libinternet}
+			${libwifi}
+    TEST_SOURCES test/greyattack-aodv-test-suite.cc
+    		 test/greyattack-aodv-id-cache-test-suite.cc
+                 ${examples_as_tests_sources}
+)
\ No newline at end of file
diff --git a/greyattack-module/doc/greyattack-aodv.h b/greyattack-module/doc/greyattack-aodv.h
new file mode 100644
index 0000000000000000000000000000000000000000..b01c12f4874fc1d468d7856ff85a3fe7ded42e5e
--- /dev/null
+++ b/greyattack-module/doc/greyattack-aodv.h
@@ -0,0 +1,38 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2009 IITP RAS
+ *
+ * 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
+ *
+ * Based on 
+ *      NS-2 aodvKmeans model developed by the CMU/MONARCH group and optimized and
+ *      tuned by Samir Das and Mahesh Marina, University of Cincinnati;
+ * 
+ *      aodvKmeans-UU implementation by Erik Nordström of Uppsala University
+ *      http://core.it.uu.se/core/index.php/aodvKmeans-UU
+ *
+ * Authors: Elena Buchatskaia <borovkovaes@iitp.ru>
+ *          Pavel Boyko <boyko@iitp.ru>
+ */
+
+#ifndef greyattack_aodv_H
+#define greyattack_aodv_H
+
+/**
+ * \defgroup aodvKmeans aodvKmeans Routing
+ *
+ * This section documents the API of the ns-3 aodvKmeans module. For a generic functional description, please refer to the ns-3 manual.
+ */
+
+#endif /* greyattack_aodv_H */
diff --git a/greyattack-module/doc/greyattack-aodv.rst b/greyattack-module/doc/greyattack-aodv.rst
new file mode 100644
index 0000000000000000000000000000000000000000..837100bbab433409b8350e02f1af88993af7ef16
--- /dev/null
+++ b/greyattack-module/doc/greyattack-aodv.rst
@@ -0,0 +1,135 @@
+.. include:: replace.txt
+
+Ad Hoc On-Demand Distance Vector (aodvKmeans)
+---------------------------------------
+
+This model implements the base specification of the Ad Hoc On-Demand 
+Distance Vector (aodvKmeans) protocol. The implementation is based on 
+:rfc:`3561`.
+
+The model was written by Elena Buchatskaia and Pavel Boyko of ITTP RAS,
+and is based on the ns-2 aodvKmeans model developed by the CMU/MONARCH group
+and optimized and tuned by Samir Das and Mahesh Marina, University of
+Cincinnati, and also on the aodvKmeans-UU implementation by Erik Nordström of 
+Uppsala University.
+
+Model Description
+*****************
+
+The source code for the aodvKmeans model lives in the directory `src/aodvKmeans`.
+
+Design
+++++++
+
+Class ``ns3::aodvKmeans::RoutingProtocol`` implements all functionality of 
+service packet exchange and inherits from ``ns3::Ipv4RoutingProtocol``.
+The base class defines two virtual functions for packet routing and 
+forwarding.  The first one, ``ns3::aodvKmeans::RouteOutput``, is used for 
+locally originated packets, and the second one, ``ns3::aodvKmeans::RouteInput``,
+is used for forwarding and/or delivering received packets.
+
+Protocol operation depends on many adjustable parameters. Parameters for 
+this functionality are attributes of ``ns3::aodvKmeans::RoutingProtocol``. 
+Parameter default values are drawn from the RFC and allow the 
+enabling/disabling protocol features, such as broadcasting HELLO messages, 
+broadcasting data packets and so on.
+
+aodvKmeans discovers routes on demand.  Therefore, the aodvKmeans model buffers all 
+packets while a route request packet (RREQ) is disseminated. 
+A packet queue is implemented in aodvKmeans-rqueue.cc. A smart pointer to 
+the packet, ``ns3::Ipv4RoutingProtocol::ErrorCallback``,
+``ns3::Ipv4RoutingProtocol::UnicastForwardCallback``, and the IP header 
+are stored in this queue. The packet queue implements garbage collection 
+of old packets and a queue size limit.
+
+The routing table implementation supports garbage collection of 
+old entries and state machine, defined in the standard.
+It is implemented as a STL map container. The key is a destination IP address.
+
+Some elements of protocol operation aren't described in the RFC. These 
+elements generally concern cooperation of different OSI model layers.
+The model uses the following heuristics:
+
+* This aodvKmeans implementation can detect the presence of unidirectional 
+  links and avoid them if necessary.  If the node the model receives an
+  RREQ for is a neighbor, the cause may be a unidirectional link.
+  This heuristic is taken from aodvKmeans-UU implementation and can be disabled.
+* Protocol operation strongly depends on broken link detection mechanism. 
+  The model implements two such heuristics.  First, this implementation 
+  support HELLO messages. However HELLO messages are not a good way to 
+  perform neighbor sensing in a wireless environment (at least not over 
+  802.11). Therefore, one may experience bad performance when running over 
+  wireless.  There are several reasons for this: 1) HELLO messages are 
+  broadcasted. In 802.11, broadcasting is often done at a 
+  lower bit rate than unicasting, thus HELLO messages can travel further 
+  than unicast data. 2) HELLO messages are small, thus less prone to 
+  bit errors than data transmissions, and 3) Broadcast transmissions are 
+  not guaranteed to be bidirectional, unlike unicast transmissions.  
+  Second, we use layer 2 feedback when possible. Link are considered to be 
+  broken if frame transmission results in a transmission failure for all 
+  retries. This mechanism is meant for active links and works faster than
+  the first method.
+
+The layer 2 feedback implementation relies on the ``TxErrHeader`` trace source, 
+currently supported in AdhocWifiMac only.
+
+Scope and Limitations
++++++++++++++++++++++
+
+The model is for IPv4 only.  The following optional protocol optimizations 
+are not implemented:
+
+#. Local link repair.
+#. RREP, RREQ and HELLO message extensions.
+
+These techniques require direct access to IP header, which contradicts
+the assertion from the aodvKmeans RFC that aodvKmeans works over UDP.  This model uses
+UDP for simplicity, hindering the ability to implement certain protocol 
+optimizations. The model doesn't use low layer raw sockets because they 
+are not portable.
+
+Future Work
++++++++++++
+
+No announced plans.
+
+..
+  References
+  ++++++++++
+
+..
+  Usage
+  *****
+
+..
+  Examples
+  ++++++++
+
+..
+  Helpers
+  +++++++
+
+..
+  Attributes
+  ++++++++++
+
+..
+  Tracing
+  +++++++
+
+..
+  Logging
+  +++++++
+
+..
+  Caveats
+  +++++++
+
+..
+  Validation
+  **********
+  Unit tests
+  ++++++++++
+  Larger-scale performance tests
+  ++++++++++++++++++++++++++++++
+
diff --git a/greyattack-module/examples/greyattack-aodv.cc b/greyattack-module/examples/greyattack-aodv.cc
new file mode 100644
index 0000000000000000000000000000000000000000..e7f77a608d3f5760eef706540cbc55ae9761eda2
--- /dev/null
+++ b/greyattack-module/examples/greyattack-aodv.cc
@@ -0,0 +1,243 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2009 IITP RAS
+ *
+ * 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 is an example script for greyattack manet routing protocol. 
+ *
+ * Authors: Pavel Boyko <boyko@iitp.ru>
+ */
+
+#include <iostream>
+#include <cmath>
+#include "ns3/greydefense-aodv-module.h"
+#include "ns3/core-module.h"
+#include "ns3/network-module.h"
+#include "ns3/internet-module.h"
+#include "ns3/mobility-module.h"
+#include "ns3/point-to-point-module.h"
+#include "ns3/v4ping-helper.h"
+#include "ns3/yans-wifi-helper.h"
+
+using namespace ns3;
+
+/**
+ * \ingroup greyattack-examples
+ * \ingroup examples
+ * \brief Test script.
+ * 
+ * This script creates 1-dimensional grid topology and then ping last node from the first one:
+ * 
+ * [10.0.0.1] <-- step --> [10.0.0.2] <-- step --> [10.0.0.3] <-- step --> [10.0.0.4]
+ * 
+ * ping 10.0.0.4
+ *
+ * When 1/3 of simulation time has elapsed, one of the nodes is moved out of
+ * range, thereby breaking the topology.  By default, this will result in
+ * only 34 of 100 pings being received.  If the step size is reduced
+ * to cover the gap, then all pings can be received.
+ */
+class greyattackExample 
+{
+public:
+  greyattackExample ();
+  /**
+   * \brief Configure script parameters
+   * \param argc is the command line argument count
+   * \param argv is the command line arguments
+   * \return true on successful configuration
+  */
+  bool Configure (int argc, char **argv);
+  /// Run simulation
+  void Run ();
+  /**
+   * Report results
+   * \param os the output stream
+   */
+  void Report (std::ostream & os);
+
+private:
+
+  // parameters
+  /// Number of nodes
+  uint32_t size;
+  /// Distance between nodes, meters
+  double step;
+  /// Simulation time, seconds
+  double totalTime;
+  /// Write per-device PCAP traces if true
+  bool pcap;
+  /// Print routes if true
+  bool printRoutes;
+
+  // network
+  /// nodes used in the example
+  NodeContainer nodes;
+  /// devices used in the example
+  NetDeviceContainer devices;
+  /// interfaces used in the example
+  Ipv4InterfaceContainer interfaces;
+
+private:
+  /// Create the nodes
+  void CreateNodes ();
+  /// Create the devices
+  void CreateDevices ();
+  /// Create the network
+  void InstallInternetStack ();
+  /// Create the simulation applications
+  void InstallApplications ();
+};
+
+int main (int argc, char **argv)
+{
+  greyattackExample test;
+  if (!test.Configure (argc, argv))
+    NS_FATAL_ERROR ("Configuration failed. Aborted.");
+
+  test.Run ();
+  test.Report (std::cout);
+  return 0;
+}
+
+//-----------------------------------------------------------------------------
+greyattackExample::greyattackExample () :
+  size (10),
+  step (50),
+  totalTime (100),
+  pcap (false),
+  printRoutes (false)
+{
+}
+
+bool
+greyattackExample::Configure (int argc, char **argv)
+{
+  // Enable greyattack logs by default. Comment this if too noisy
+  // LogComponentEnable("greyattackRoutingProtocol", LOG_LEVEL_ALL);
+
+  SeedManager::SetSeed (12345);
+  CommandLine cmd (__FILE__);
+
+  cmd.AddValue ("pcap", "Write PCAP traces.", pcap);
+  cmd.AddValue ("printRoutes", "Print routing table dumps.", printRoutes);
+  cmd.AddValue ("size", "Number of nodes.", size);
+  cmd.AddValue ("time", "Simulation time, s.", totalTime);
+  cmd.AddValue ("step", "Grid step, m", step);
+
+  cmd.Parse (argc, argv);
+  return true;
+}
+
+void
+greyattackExample::Run ()
+{
+//  Config::SetDefault ("ns3::WifiRemoteStationManager::RtsCtsThreshold", UintegerValue (1)); // enable rts cts all the time.
+  CreateNodes ();
+  CreateDevices ();
+  InstallInternetStack ();
+  InstallApplications ();
+
+  std::cout << "Starting simulation for " << totalTime << " s ...\n";
+
+  Simulator::Stop (Seconds (totalTime));
+  Simulator::Run ();
+  Simulator::Destroy ();
+}
+
+void
+greyattackExample::Report (std::ostream &)
+{ 
+}
+
+void
+greyattackExample::CreateNodes ()
+{
+  std::cout << "Creating " << (unsigned)size << " nodes " << step << " m apart.\n";
+  nodes.Create (size);
+  // Name nodes
+  for (uint32_t i = 0; i < size; ++i)
+    {
+      std::ostringstream os;
+      os << "node-" << i;
+      Names::Add (os.str (), nodes.Get (i));
+    }
+  // Create static grid
+  MobilityHelper mobility;
+  mobility.SetPositionAllocator ("ns3::GridPositionAllocator",
+                                 "MinX", DoubleValue (0.0),
+                                 "MinY", DoubleValue (0.0),
+                                 "DeltaX", DoubleValue (step),
+                                 "DeltaY", DoubleValue (0),
+                                 "GridWidth", UintegerValue (size),
+                                 "LayoutType", StringValue ("RowFirst"));
+  mobility.SetMobilityModel ("ns3::ConstantPositionMobilityModel");
+  mobility.Install (nodes);
+}
+
+void
+greyattackExample::CreateDevices ()
+{
+  WifiMacHelper wifiMac;
+  wifiMac.SetType ("ns3::AdhocWifiMac"); 
+  YansWifiPhyHelper wifiPhy;
+  YansWifiChannelHelper wifiChannel = YansWifiChannelHelper::Default ();
+  wifiPhy.SetChannel (wifiChannel.Create ());
+  WifiHelper wifi;
+  
+  wifi.SetRemoteStationManager ("ns3::ConstantRateWifiManager", "DataMode", StringValue ("OfdmRate6Mbps"), "RtsCtsThreshold", UintegerValue (0));
+  devices = wifi.Install (wifiPhy, wifiMac, nodes); 
+
+  if (pcap)
+    {
+      wifiPhy.EnablePcapAll (std::string ("greyattack"));
+    }
+}
+
+void
+greyattackExample::InstallInternetStack ()
+{
+  greyattackHelper greyattack;
+  // you can configure greyattack attributes here using greyattack.Set(name, value)
+  InternetStackHelper stack;
+  stack.SetRoutingHelper (greyattack); // has effect on the next Install ()
+  stack.Install (nodes);
+  Ipv4AddressHelper address;
+  address.SetBase ("10.0.0.0", "255.0.0.0");
+  interfaces = address.Assign (devices);
+
+  if (printRoutes)
+    {
+      Ptr<OutputStreamWrapper> routingStream = Create<OutputStreamWrapper> ("greyattack.routes", std::ios::out);
+      greyattack.PrintRoutingTableAllAt (Seconds (8), routingStream);
+    }
+}
+
+void
+greyattackExample::InstallApplications ()
+{
+  V4PingHelper ping (interfaces.GetAddress (size - 1));
+  ping.SetAttribute ("Verbose", BooleanValue (true));
+
+  ApplicationContainer p = ping.Install (nodes.Get (0));
+  p.Start (Seconds (0));
+  p.Stop (Seconds (totalTime) - Seconds (0.001));
+
+  // move node away
+  Ptr<Node> node = nodes.Get (size/2);
+  Ptr<MobilityModel> mob = node->GetObject<MobilityModel> ();
+  Simulator::Schedule (Seconds (totalTime/3), &MobilityModel::SetPosition, mob, Vector (1e5, 1e5, 1e5));
+}
+
diff --git a/greyattack-module/examples/wscript b/greyattack-module/examples/wscript
new file mode 100644
index 0000000000000000000000000000000000000000..79178f75e97d65298419342f585972b16531f0ea
--- /dev/null
+++ b/greyattack-module/examples/wscript
@@ -0,0 +1,6 @@
+## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
+
+def build(bld):
+    obj = bld.create_ns3_program('greydefense-aodv',
+                                 ['wifi', 'internet', 'greydefense-aodv', 'internet-apps'])
+    obj.source = 'greydefense-aodv.cc'
diff --git a/greyattack-module/helper/greyattack-aodv-helper.cc b/greyattack-module/helper/greyattack-aodv-helper.cc
new file mode 100644
index 0000000000000000000000000000000000000000..7c929d2912b149a5bc5c6de77c62aa7375bf27ce
--- /dev/null
+++ b/greyattack-module/helper/greyattack-aodv-helper.cc
@@ -0,0 +1,96 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2009 IITP RAS
+ *
+ * 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
+ *
+ * Authors: Pavel Boyko <boyko@iitp.ru>, written after OlsrHelper by Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+#include "greyattack-aodv-helper.h"
+#include "ns3/greyattack-aodv-routing-protocol.h"
+#include "ns3/node-list.h"
+#include "ns3/names.h"
+#include "ns3/ptr.h"
+#include "ns3/ipv4-list-routing.h"
+
+namespace ns3
+{
+
+greyattackHelper::greyattackHelper() :
+  Ipv4RoutingHelper ()
+{
+  m_agentFactory.SetTypeId ("ns3::greyattack-aodv::RoutingProtocol");
+}
+
+greyattackHelper*
+greyattackHelper::Copy (void) const
+{
+  return new greyattackHelper (*this);
+}
+
+Ptr<Ipv4RoutingProtocol> 
+greyattackHelper::Create (Ptr<Node> node) const
+{
+  Ptr<greyattackAodv::RoutingProtocol> agent = m_agentFactory.Create<greyattackAodv::RoutingProtocol> ();
+  node->AggregateObject (agent);
+  return agent;
+}
+
+void 
+greyattackHelper::Set (std::string name, const AttributeValue &value)
+{
+  m_agentFactory.Set (name, value);
+}
+
+int64_t
+greyattackHelper::AssignStreams (NodeContainer c, int64_t stream)
+{
+  int64_t currentStream = stream;
+  Ptr<Node> node;
+  for (NodeContainer::Iterator i = c.Begin (); i != c.End (); ++i)
+    {
+      node = (*i);
+      Ptr<Ipv4> ipv4 = node->GetObject<Ipv4> ();
+      NS_ASSERT_MSG (ipv4, "Ipv4 not installed on node");
+      Ptr<Ipv4RoutingProtocol> proto = ipv4->GetRoutingProtocol ();
+      NS_ASSERT_MSG (proto, "Ipv4 routing not installed on node");
+      Ptr<greyattackAodv::RoutingProtocol> greyattack = DynamicCast<greyattackAodv::RoutingProtocol> (proto);
+      if (greyattack)
+        {
+          currentStream += greyattack->AssignStreams (currentStream);
+          continue;
+        }
+      // greyattack may also be in a list
+      Ptr<Ipv4ListRouting> list = DynamicCast<Ipv4ListRouting> (proto);
+      if (list)
+        {
+          int16_t priority;
+          Ptr<Ipv4RoutingProtocol> listProto;
+          Ptr<greyattackAodv::RoutingProtocol> listgreyattack;
+          for (uint32_t i = 0; i < list->GetNRoutingProtocols (); i++)
+            {
+              listProto = list->GetRoutingProtocol (i, priority);
+              listgreyattack = DynamicCast<greyattackAodv::RoutingProtocol> (listProto);
+              if (listgreyattack)
+                {
+                  currentStream += listgreyattack->AssignStreams (currentStream);
+                  break;
+                }
+            }
+        }
+    }
+  return (currentStream - stream);
+}
+
+}
diff --git a/greyattack-module/helper/greyattack-aodv-helper.h b/greyattack-module/helper/greyattack-aodv-helper.h
new file mode 100644
index 0000000000000000000000000000000000000000..e12f768a83c054550ea4e644e1fa696008f9a318
--- /dev/null
+++ b/greyattack-module/helper/greyattack-aodv-helper.h
@@ -0,0 +1,84 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2009 IITP RAS
+ *
+ * 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
+ *
+ * Authors: Pavel Boyko <boyko@iitp.ru>, written after OlsrHelper by Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+
+#ifndef greyattack_aodv_HELPER_H
+#define greyattack_aodv_HELPER_H
+
+#include "ns3/object-factory.h"
+#include "ns3/node.h"
+#include "ns3/node-container.h"
+#include "ns3/ipv4-routing-helper.h"
+
+namespace ns3 {
+/**
+ * \ingroup greyattack
+ * \brief Helper class that adds greyattack routing to nodes.
+ */
+class greyattackHelper : public Ipv4RoutingHelper
+{
+public:
+  greyattackHelper ();
+
+  /**
+   * \returns pointer to clone of this greyattackHelper
+   *
+   * \internal
+   * This method is mainly for internal use by the other helpers;
+   * clients are expected to free the dynamic memory allocated by this method
+   */
+  greyattackHelper* Copy (void) const;
+
+  /**
+   * \param node the node on which the routing protocol will run
+   * \returns a newly-created routing protocol
+   *
+   * This method will be called by ns3::InternetStackHelper::Install
+   *
+   * \todo support installing greyattack on the subset of all available IP interfaces
+   */
+  virtual Ptr<Ipv4RoutingProtocol> Create (Ptr<Node> node) const;
+  /**
+   * \param name the name of the attribute to set
+   * \param value the value of the attribute to set.
+   *
+   * This method controls the attributes of ns3::greyattack::RoutingProtocol
+   */
+  void Set (std::string name, const AttributeValue &value);
+  /**
+   * Assign a fixed random variable stream number to the random variables
+   * used by this model.  Return the number of streams (possibly zero) that
+   * have been assigned.  The Install() method of the InternetStackHelper
+   * should have previously been called by the user.
+   *
+   * \param stream first stream index to use
+   * \param c NodeContainer of the set of nodes for which greyattack
+   *          should be modified to use a fixed stream
+   * \return the number of stream indices assigned by this helper
+   */
+  int64_t AssignStreams (NodeContainer c, int64_t stream);
+
+private:
+  /** the factory to create greyattack routing object */
+  ObjectFactory m_agentFactory;
+};
+
+}
+
+#endif /* greyattack_HELPER_H */
diff --git a/greyattack-module/model/greyattack-aodv-dpd.cc b/greyattack-module/model/greyattack-aodv-dpd.cc
new file mode 100644
index 0000000000000000000000000000000000000000..744c480aef8f70bb156ba3cb69a9d5d11ec7099f
--- /dev/null
+++ b/greyattack-module/model/greyattack-aodv-dpd.cc
@@ -0,0 +1,48 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2009 IITP RAS
+ *
+ * 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
+ *
+ *
+ * Authors: Elena Buchatskaia <borovkovaes@iitp.ru>
+ *          Pavel Boyko <boyko@iitp.ru>
+ */
+
+#include "greyattack-aodv-dpd.h"
+
+namespace ns3 {
+namespace greyattackAodv {
+
+bool
+DuplicatePacketDetection::IsDuplicate  (Ptr<const Packet> p, const Ipv4Header & header)
+{
+  return m_idCache.IsDuplicate (header.GetSource (), p->GetUid () );
+}
+void
+DuplicatePacketDetection::SetLifetime (Time lifetime)
+{
+  m_idCache.SetLifetime (lifetime);
+}
+
+Time
+DuplicatePacketDetection::GetLifetime () const
+{
+  return m_idCache.GetLifeTime ();
+}
+
+
+}
+}
+
diff --git a/greyattack-module/model/greyattack-aodv-dpd.h b/greyattack-module/model/greyattack-aodv-dpd.h
new file mode 100644
index 0000000000000000000000000000000000000000..c57d59e239f85905d8f0e39111b895c9fbe01806
--- /dev/null
+++ b/greyattack-module/model/greyattack-aodv-dpd.h
@@ -0,0 +1,76 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2009 IITP RAS
+ *
+ * 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
+ *
+ *
+ * Authors: Elena Buchatskaia <borovkovaes@iitp.ru>
+ *          Pavel Boyko <boyko@iitp.ru>
+ */
+
+#ifndef greyattack_aodv_DPD_H
+#define greyattack_aodv_DPD_H
+
+#include "greyattack-aodv-id-cache.h"
+#include "ns3/nstime.h"
+#include "ns3/packet.h"
+#include "ns3/ipv4-header.h"
+
+namespace ns3 {
+namespace greyattackAodv {
+/**
+ * \ingroup greyattack-aodv
+ *
+ * \brief Helper class used to remember already seen packets and detect duplicates.
+ *
+ * Currently duplicate detection is based on unique packet ID given by Packet::GetUid ()
+ * This approach is known to be weak (ns3::Packet UID is an internal identifier and not intended for logical uniqueness in models) and should be changed.
+ */
+class DuplicatePacketDetection
+{
+public:
+  /**
+   * Constructor
+   * \param lifetime the lifetime for added entries
+   */
+  DuplicatePacketDetection (Time lifetime) : m_idCache (lifetime)
+  {
+  }
+  /**
+   * Check if the packet is a duplicate. If not, save information about this packet.
+   * \param p the packet to check
+   * \param header the IP header to check
+   * \returns true if duplicate
+   */
+  bool IsDuplicate (Ptr<const Packet> p, const Ipv4Header & header);
+  /**
+   * Set duplicate record lifetime
+   * \param lifetime the lifetime for duplicate records
+   */
+  void SetLifetime (Time lifetime);
+  /**
+   * Get duplicate record lifetime
+   * \returns the duplicate record lifetime
+   */
+  Time GetLifetime () const;
+private:
+  /// Impl
+  IdCache m_idCache;
+};
+
+}
+}
+
+#endif /* greyattack_aodv_DPD_H */
diff --git a/greyattack-module/model/greyattack-aodv-id-cache.cc b/greyattack-module/model/greyattack-aodv-id-cache.cc
new file mode 100644
index 0000000000000000000000000000000000000000..5e3d230b452857266ebc26c884519b8bef671136
--- /dev/null
+++ b/greyattack-module/model/greyattack-aodv-id-cache.cc
@@ -0,0 +1,62 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2009 IITP RAS
+ *
+ * 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
+ *
+ * Based on
+ *      NS-3
+ *
+ * Authors: Charles Hutchins
+ */
+#include "greyattack-aodv-id-cache.h"
+#include <algorithm>
+
+namespace ns3 {
+namespace greyattackAodv {
+bool
+IdCache::IsDuplicate (Ipv4Address addr, uint32_t id)
+{
+  Purge ();
+  for (std::vector<UniqueId>::const_iterator i = m_idCache.begin ();
+       i != m_idCache.end (); ++i)
+    {
+      if (i->m_context == addr && i->m_id == id)
+        {
+          return true;
+        }
+    }
+  struct UniqueId uniqueId =
+  {
+    addr, id, m_lifetime + Simulator::Now ()
+  };
+  m_idCache.push_back (uniqueId);
+  return false;
+}
+void
+IdCache::Purge ()
+{
+  m_idCache.erase (remove_if (m_idCache.begin (), m_idCache.end (),
+                              IsExpired ()), m_idCache.end ());
+}
+
+uint32_t
+IdCache::GetSize ()
+{
+  Purge ();
+  return m_idCache.size ();
+}
+
+}
+}
diff --git a/greyattack-module/model/greyattack-aodv-id-cache.h b/greyattack-module/model/greyattack-aodv-id-cache.h
new file mode 100644
index 0000000000000000000000000000000000000000..e85b6534ceaedfff34dc9aabb664a2116fcc5d1f
--- /dev/null
+++ b/greyattack-module/model/greyattack-aodv-id-cache.h
@@ -0,0 +1,113 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2009 IITP RAS
+ *
+ * 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
+ *
+ * Based on
+ *      NS-3 greyattack model developed by
+ *
+ * Authors: Charles Hutchins
+ */
+
+#ifndef greyattack_aodv_ID_CACHE_H
+#define greyattack_aodv_ID_CACHE_H
+
+#include "ns3/ipv4-address.h"
+#include "ns3/simulator.h"
+#include <vector>
+
+namespace ns3 {
+namespace greyattackAodv {
+/**
+ * \ingroup greyattack
+ *
+ * \brief Unique packets identification cache used for simple duplicate detection.
+ */
+class IdCache
+{
+public:
+  /**
+   * constructor
+   * \param lifetime the lifetime for added entries
+   */
+  IdCache (Time lifetime) : m_lifetime (lifetime)
+  {
+  }
+  /**
+   * Check that entry (addr, id) exists in cache. Add entry, if it doesn't exist.
+   * \param addr the IP address
+   * \param id the cache entry ID
+   * \returns true if the pair exists
+   */ 
+  bool IsDuplicate (Ipv4Address addr, uint32_t id);
+  /// Remove all expired entries
+  void Purge ();
+  /**
+   * \returns number of entries in cache
+   */
+  uint32_t GetSize ();
+  /**
+   * Set lifetime for future added entries.
+   * \param lifetime the lifetime for entries
+   */
+  void SetLifetime (Time lifetime)
+  {
+    m_lifetime = lifetime;
+  }
+  /**
+   * Return lifetime for existing entries in cache
+   * \returns thhe lifetime
+   */
+  Time GetLifeTime () const
+  {
+    return m_lifetime;
+  }
+private:
+  /// Unique packet ID
+  struct UniqueId
+  {
+    /// ID is supposed to be unique in single address context (e.g. sender address)
+    Ipv4Address m_context;
+    /// The id
+    uint32_t m_id;
+    /// When record will expire
+    Time m_expire;
+  };
+  /**
+   * \brief IsExpired structure
+   */
+  struct IsExpired
+  {
+    /**
+     * \brief Check if the entry is expired
+     *
+     * \param u UniqueId entry
+     * \return true if expired, false otherwise
+     */
+    bool operator() (const struct UniqueId & u) const
+    {
+      return (u.m_expire < Simulator::Now ());
+    }
+  };
+  /// Already seen IDs
+  std::vector<UniqueId> m_idCache;
+  /// Default lifetime for ID records
+  Time m_lifetime;
+};
+
+}  // namespace greyattack
+}  // namespace ns3
+
+#endif /* greyattack_aodv_ID_CACHE_H */
diff --git a/greyattack-module/model/greyattack-aodv-neighbor.cc b/greyattack-module/model/greyattack-aodv-neighbor.cc
new file mode 100644
index 0000000000000000000000000000000000000000..40cbd7787c91496abc40555ad33c62a0bd53bc59
--- /dev/null
+++ b/greyattack-module/model/greyattack-aodv-neighbor.cc
@@ -0,0 +1,198 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2009 IITP RAS
+ *
+ * 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
+ *
+ * Based on
+ *      NS-3 greyattack model
+ *
+ * Authors: Charles Hutchins
+ */
+
+#include <algorithm>
+#include "ns3/log.h"
+#include "ns3/wifi-mac-header.h"
+#include "greyattack-aodv-neighbor.h"
+
+namespace ns3 {
+
+NS_LOG_COMPONENT_DEFINE ("greyattack-aodv-Neighbors");
+
+namespace greyattackAodv {
+Neighbors::Neighbors (Time delay)
+  : m_ntimer (Timer::CANCEL_ON_DESTROY)
+{
+  m_ntimer.SetDelay (delay);
+  m_ntimer.SetFunction (&Neighbors::Purge, this);
+  m_txErrorCallback = MakeCallback (&Neighbors::ProcessTxError, this);
+}
+
+bool
+Neighbors::IsNeighbor (Ipv4Address addr)
+{
+  Purge ();
+  for (std::vector<Neighbor>::const_iterator i = m_nb.begin ();
+       i != m_nb.end (); ++i)
+    {
+      if (i->m_neighborAddress == addr)
+        {
+          return true;
+        }
+    }
+  return false;
+}
+
+Time
+Neighbors::GetExpireTime (Ipv4Address addr)
+{
+  Purge ();
+  for (std::vector<Neighbor>::const_iterator i = m_nb.begin (); i
+       != m_nb.end (); ++i)
+    {
+      if (i->m_neighborAddress == addr)
+        {
+          return (i->m_expireTime - Simulator::Now ());
+        }
+    }
+  return Seconds (0);
+}
+
+void
+Neighbors::Update (Ipv4Address addr, Time expire)
+{
+  for (std::vector<Neighbor>::iterator i = m_nb.begin (); i != m_nb.end (); ++i)
+    {
+      if (i->m_neighborAddress == addr)
+        {
+          i->m_expireTime
+            = std::max (expire + Simulator::Now (), i->m_expireTime);
+          if (i->m_hardwareAddress == Mac48Address ())
+            {
+              i->m_hardwareAddress = LookupMacAddress (i->m_neighborAddress);
+            }
+          return;
+        }
+    }
+
+  NS_LOG_LOGIC ("Open link to " << addr);
+  Neighbor neighbor (addr, LookupMacAddress (addr), expire + Simulator::Now ());
+  m_nb.push_back (neighbor);
+  Purge ();
+}
+
+
+
+
+
+
+
+/**
+ * \brief CloseNeighbor structure
+ */
+struct CloseNeighbor
+{
+  /**
+   * Check if the entry is expired
+   *
+   * \param nb Neighbors::Neighbor entry
+   * \return true if expired, false otherwise
+   */
+  bool operator() (const Neighbors::Neighbor & nb) const
+  {
+    return ((nb.m_expireTime < Simulator::Now ()) || nb.close);
+  }
+};
+
+void
+Neighbors::Purge ()
+{
+  if (m_nb.empty ())
+    {
+      return;
+    }
+
+  CloseNeighbor pred;
+  if (!m_handleLinkFailure.IsNull ())
+    {
+      for (std::vector<Neighbor>::iterator j = m_nb.begin (); j != m_nb.end (); ++j)
+        {
+          if (pred (*j))
+            {
+              NS_LOG_LOGIC ("Close link to " << j->m_neighborAddress);
+              m_handleLinkFailure (j->m_neighborAddress);
+            }
+        }
+    }
+  m_nb.erase (std::remove_if (m_nb.begin (), m_nb.end (), pred), m_nb.end ());
+  m_ntimer.Cancel ();
+  m_ntimer.Schedule ();
+}
+
+void
+Neighbors::ScheduleTimer ()
+{
+  m_ntimer.Cancel ();
+  m_ntimer.Schedule ();
+}
+
+void
+Neighbors::AddArpCache (Ptr<ArpCache> a)
+{
+  m_arp.push_back (a);
+}
+
+void
+Neighbors::DelArpCache (Ptr<ArpCache> a)
+{
+  m_arp.erase (std::remove (m_arp.begin (), m_arp.end (), a), m_arp.end ());
+}
+
+Mac48Address
+Neighbors::LookupMacAddress (Ipv4Address addr)
+{
+  Mac48Address hwaddr;
+  for (std::vector<Ptr<ArpCache> >::const_iterator i = m_arp.begin ();
+       i != m_arp.end (); ++i)
+    {
+      ArpCache::Entry * entry = (*i)->Lookup (addr);
+      if (entry != 0 && (entry->IsAlive () || entry->IsPermanent ()) && !entry->IsExpired ())
+        {
+          hwaddr = Mac48Address::ConvertFrom (entry->GetMacAddress ());
+          break;
+        }
+    }
+  return hwaddr;
+}
+
+
+
+void
+Neighbors::ProcessTxError (WifiMacHeader const & hdr)
+{
+  Mac48Address addr = hdr.GetAddr1 ();
+
+  for (std::vector<Neighbor>::iterator i = m_nb.begin (); i != m_nb.end (); ++i)
+    {
+      if (i->m_hardwareAddress == addr)
+        {
+          i->close = true;
+        }
+    }
+  Purge ();
+}
+
+}  // namespace greyattack-aodv
+}  // namespace ns3
+
diff --git a/greyattack-module/model/greyattack-aodv-neighbor.h b/greyattack-module/model/greyattack-aodv-neighbor.h
new file mode 100644
index 0000000000000000000000000000000000000000..086a79af274daaf9efe578e8f4d8f94ee200ced6
--- /dev/null
+++ b/greyattack-module/model/greyattack-aodv-neighbor.h
@@ -0,0 +1,184 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2009 IITP RAS
+ *
+ * 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
+ *
+ * Based on
+ *      NS-3 greyattack model developed by
+ *
+ * Authors: Charles Hutchins
+ */
+
+#ifndef greyattack_aodvNEIGHBOR_H
+#define greyattack_aodvNEIGHBOR_H
+
+#include <vector>
+#include "ns3/simulator.h"
+#include "ns3/timer.h"
+#include "ns3/ipv4-address.h"
+#include "ns3/callback.h"
+#include "ns3/arp-cache.h"
+
+namespace ns3 {
+
+class WifiMacHeader;
+
+namespace greyattackAodv {
+
+class RoutingProtocol;
+
+/**
+ * \ingroup greyattack-aodv
+ * \brief maintain list of active neighbors
+ */
+class Neighbors
+{
+public:
+  /**
+   * constructor
+   * \param delay the delay time for purging the list of neighbors
+   */
+  Neighbors (Time delay);
+  /// Neighbor description
+  struct Neighbor
+  {
+    /// Neighbor IPv4 address
+    Ipv4Address m_neighborAddress;
+    /// Neighbor MAC address
+    Mac48Address m_hardwareAddress;
+    /// Neighbor expire time
+    Time m_expireTime;
+    /// Neighbor close indicator
+    bool close;
+    /// cluster id of neighbour
+    
+    /**
+     * \brief Neighbor structure constructor
+     *
+     * \param ip Ipv4Address entry
+     * \param mac Mac48Address entry
+     * \param t Time expire time
+     */
+    Neighbor (Ipv4Address ip, Mac48Address mac, Time t)
+      : m_neighborAddress (ip),
+        m_hardwareAddress (mac),
+        m_expireTime (t),
+        close (false)
+        
+    {
+    }
+  };
+  /**
+   * Return expire time for neighbor node with address addr, if exists, else return 0.
+   * \param addr the IP address of the neighbor node
+   * \returns the expire time for the neighbor node
+   */
+  Time GetExpireTime (Ipv4Address addr);
+  
+  /**
+   * Check that node with address addr is neighbor
+   * \param addr the IP address to check
+   * \returns true if the node with IP address is a neighbor
+   */
+  bool IsNeighbor (Ipv4Address addr);
+  /**
+   * Update expire time for entry with address addr, if it exists, else add new entry
+   * \param addr the IP address to check
+   * \param expire the expire time for the address
+   */
+  void Update (Ipv4Address addr, Time expire);
+  /// Remove all expired entries
+  void Purge ();
+  /// Schedule m_ntimer.
+  void ScheduleTimer ();
+  /// Remove all entries
+  void Clear ()
+  {
+    m_nb.clear ();
+  }
+
+  /**
+   * Add ARP cache to be used to allow layer 2 notifications processing
+   * \param a pointer to the ARP cache to add
+   */
+  void AddArpCache (Ptr<ArpCache> a);
+  /**
+   * Don't use given ARP cache any more (interface is down)
+   * \param a pointer to the ARP cache to delete
+   */
+  void DelArpCache (Ptr<ArpCache> a);
+  /**
+   * Get callback to ProcessTxError
+   * \returns the callback function
+   */
+  Callback<void, WifiMacHeader const &> GetTxErrorCallback () const
+  {
+    return m_txErrorCallback;
+  }
+
+  /**
+   * Set link failure callback
+   * \param cb the callback function
+   */
+  void SetCallback (Callback<void, Ipv4Address> cb)
+  {
+    m_handleLinkFailure = cb;
+  }
+  /**
+   * Get link failure callback
+   * \returns the link failure callback
+   */
+  Callback<void, Ipv4Address> GetCallback () const
+  {
+    return m_handleLinkFailure;
+  }
+
+
+  
+  
+
+private:
+  /// link failure callback
+  Callback<void, Ipv4Address> m_handleLinkFailure;
+  /// TX error callback
+  Callback<void, WifiMacHeader const &> m_txErrorCallback;
+  /// Timer for neighbor's list. Schedule Purge().
+  Timer m_ntimer;
+  /// vector of entries
+  std::vector<Neighbor> m_nb;
+  /// list of ARP cached to be used for layer 2 notifications processing
+  std::vector<Ptr<ArpCache> > m_arp;
+
+  
+  /**
+   * Find MAC address by IP using list of ARP caches
+   * 
+   * \param addr the IP address to lookup
+   * \returns the MAC address for the IP address
+   */
+  Mac48Address LookupMacAddress (Ipv4Address addr);
+  /**
+   * Process layer 2 TX error notification
+   * \param hdr header of the packet
+   */
+  void ProcessTxError (WifiMacHeader const &hdr);
+
+
+};
+
+}  // namespace greyattack
+}  // namespace ns3
+
+#endif /* greyattack_aodvNEIGHBOR_H */
diff --git a/greyattack-module/model/greyattack-aodv-packet.cc b/greyattack-module/model/greyattack-aodv-packet.cc
new file mode 100644
index 0000000000000000000000000000000000000000..67ae91c789d9a4002a1bdb85d3b926148babffeb
--- /dev/null
+++ b/greyattack-module/model/greyattack-aodv-packet.cc
@@ -0,0 +1,693 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2009 IITP RAS
+ *
+ * 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
+ *
+ * Based on
+ *      NS-3 greyattack model developed by
+ *
+ *
+ * Authors: Charles Hutchins
+ */
+#include "greyattack-aodv-packet.h"
+#include "ns3/address-utils.h"
+#include "ns3/packet.h"
+
+namespace ns3 {
+namespace greyattackAodv {
+
+NS_OBJECT_ENSURE_REGISTERED (TypeHeader);
+
+TypeHeader::TypeHeader (MessageType t)
+  : m_type (t),
+    m_valid (true)
+{
+}
+
+TypeId
+TypeHeader::GetTypeId ()
+{
+  static TypeId tid = TypeId ("ns3::greyattack-aodv::TypeHeader")
+    .SetParent<Header> ()
+    .SetGroupName ("greyattack-aodv")
+    .AddConstructor<TypeHeader> ()
+  ;
+  return tid;
+}
+
+TypeId
+TypeHeader::GetInstanceTypeId () const
+{
+  return GetTypeId ();
+}
+
+uint32_t
+TypeHeader::GetSerializedSize () const
+{
+  return 1;
+}
+
+void
+TypeHeader::Serialize (Buffer::Iterator i) const
+{
+  i.WriteU8 ((uint8_t) m_type);
+}
+
+uint32_t
+TypeHeader::Deserialize (Buffer::Iterator start)
+{
+  Buffer::Iterator i = start;
+  uint8_t type = i.ReadU8 ();
+  m_valid = true;
+  switch (type)
+    {
+    case greyattackTYPE_RREQ:
+    case greyattackTYPE_RREP:
+    case greyattackTYPE_RERR:
+    case greyattackTYPE_RREP_ACK:
+      {
+        m_type = (MessageType) type;
+        break;
+      }
+    default:
+      m_valid = false;
+    }
+  uint32_t dist = i.GetDistanceFrom (start);
+  NS_ASSERT (dist == GetSerializedSize ());
+  return dist;
+}
+
+void
+TypeHeader::Print (std::ostream &os) const
+{
+  switch (m_type)
+    {
+    case greyattackTYPE_RREQ:
+      {
+        os << "RREQ";
+        break;
+      }
+    case greyattackTYPE_RREP:
+      {
+        os << "RREP";
+        break;
+      }
+    case greyattackTYPE_RERR:
+      {
+        os << "RERR";
+        break;
+      }
+    case greyattackTYPE_RREP_ACK:
+      {
+        os << "RREP_ACK";
+        break;
+      }
+    default:
+      os << "UNKNOWN_TYPE";
+    }
+}
+
+bool
+TypeHeader::operator== (TypeHeader const & o) const
+{
+  return (m_type == o.m_type && m_valid == o.m_valid);
+}
+
+std::ostream &
+operator<< (std::ostream & os, TypeHeader const & h)
+{
+  h.Print (os);
+  return os;
+}
+
+//-----------------------------------------------------------------------------
+// RREQ
+//-----------------------------------------------------------------------------
+RreqHeader::RreqHeader (uint8_t flags, uint8_t reserved, uint8_t hopCount, uint32_t requestID, Ipv4Address dst,
+                        uint32_t dstSeqNo, Ipv4Address origin, uint32_t originSeqNo)
+  : m_AER(0.0),
+    m_flags (flags),
+    m_reserved (reserved),
+    m_hopCount (hopCount),
+    m_requestID (requestID),
+    m_dst (dst),
+    m_dstSeqNo (dstSeqNo),
+    m_origin (origin),
+    m_originSeqNo (originSeqNo)
+{
+}
+
+NS_OBJECT_ENSURE_REGISTERED (RreqHeader);
+
+TypeId
+RreqHeader::GetTypeId ()
+{
+  static TypeId tid = TypeId ("ns3::greyattack-aodv::RreqHeader")
+    .SetParent<Header> ()
+    .SetGroupName ("greyattack-aodv")
+    .AddConstructor<RreqHeader> ()
+  ;
+  return tid;
+}
+
+TypeId
+RreqHeader::GetInstanceTypeId () const
+{
+  return GetTypeId ();
+}
+
+uint32_t
+RreqHeader::GetSerializedSize () const
+{
+  return 23+4;
+}
+
+void
+RreqHeader::Serialize (Buffer::Iterator i) const
+{
+  i.WriteU8 (m_flags);
+  i.WriteU8 (m_reserved);
+  i.WriteU8 (m_hopCount);
+  i.WriteHtonU32 (m_requestID);
+  WriteTo (i, m_dst);
+  i.WriteHtonU32 (m_dstSeqNo);
+  WriteTo (i, m_origin);
+  i.WriteHtonU32 (m_originSeqNo);
+
+  uint8_t mAER_arr[sizeof(float)];
+  memcpy(mAER_arr, &m_AER, sizeof(float));
+  for(uint32_t float_idx=0; float_idx<sizeof(float); float_idx++) i.WriteU8(mAER_arr[float_idx]);
+}
+
+uint32_t
+RreqHeader::Deserialize (Buffer::Iterator start)
+{
+  Buffer::Iterator i = start;
+  m_flags = i.ReadU8 ();
+  m_reserved = i.ReadU8 ();
+  m_hopCount = i.ReadU8 ();
+  m_requestID = i.ReadNtohU32 ();
+  ReadFrom (i, m_dst);
+  m_dstSeqNo = i.ReadNtohU32 ();
+  ReadFrom (i, m_origin);
+  m_originSeqNo = i.ReadNtohU32 ();
+
+  uint8_t mAER_arr[sizeof(float)];
+  for(uint32_t float_idx=0; float_idx<sizeof(float); float_idx++) mAER_arr[float_idx] = i.ReadU8();
+  memcpy(&m_AER, mAER_arr, sizeof(float));
+
+  uint32_t dist = i.GetDistanceFrom (start);
+  NS_ASSERT (dist == GetSerializedSize ());
+  return dist;
+}
+
+void
+RreqHeader::Print (std::ostream &os) const
+{
+  os << "RREQ ID " << m_requestID << " destination: ipv4 " << m_dst
+     << " sequence number " << m_dstSeqNo << " source: ipv4 "
+     << m_origin << " sequence number " << m_originSeqNo
+     << " flags:" << " Gratuitous RREP " << (*this).GetGratuitousRrep ()
+     << " Destination only " << (*this).GetDestinationOnly ()
+     << " Unknown sequence number " << (*this).GetUnknownSeqno ()
+     << " Hop count " <<  unsigned((*this).GetHopCount())
+     << "\n";
+}
+
+std::ostream &
+operator<< (std::ostream & os, RreqHeader const & h)
+{
+  h.Print (os);
+  return os;
+}
+
+void
+RreqHeader::SetGratuitousRrep (bool f)
+{
+  if (f)
+    {
+      m_flags |= (1 << 5);
+    }
+  else
+    {
+      m_flags &= ~(1 << 5);
+    }
+}
+
+bool
+RreqHeader::GetGratuitousRrep () const
+{
+  return (m_flags & (1 << 5));
+}
+
+void
+RreqHeader::SetDestinationOnly (bool f)
+{
+  if (f)
+    {
+      m_flags |= (1 << 4);
+    }
+  else
+    {
+      m_flags &= ~(1 << 4);
+    }
+}
+
+bool
+RreqHeader::GetDestinationOnly () const
+{
+  return (m_flags & (1 << 4));
+}
+
+void
+RreqHeader::SetUnknownSeqno (bool f)
+{
+  if (f)
+    {
+      m_flags |= (1 << 3);
+    }
+  else
+    {
+      m_flags &= ~(1 << 3);
+    }
+}
+
+bool
+RreqHeader::GetUnknownSeqno () const
+{
+  return (m_flags & (1 << 3));
+}
+
+bool
+RreqHeader::operator== (RreqHeader const & o) const
+{
+  return (m_flags == o.m_flags && m_reserved == o.m_reserved
+          && m_hopCount == o.m_hopCount && m_requestID == o.m_requestID
+          && m_dst == o.m_dst && m_dstSeqNo == o.m_dstSeqNo
+          && m_origin == o.m_origin && m_originSeqNo == o.m_originSeqNo);
+}
+
+//-----------------------------------------------------------------------------
+// RREP
+//-----------------------------------------------------------------------------
+
+RrepHeader::RrepHeader (uint8_t prefixSize, uint8_t hopCount, Ipv4Address dst,
+                        uint32_t dstSeqNo, Ipv4Address origin, Time lifeTime)
+  : m_flags (0),
+    m_prefixSize (prefixSize),
+    m_hopCount (hopCount),
+    m_dst (dst),
+    m_dstSeqNo (dstSeqNo),
+    m_origin (origin),
+    m_num_mass(0)
+{
+  m_lifeTime = uint32_t (lifeTime.GetMilliSeconds ());
+}
+
+NS_OBJECT_ENSURE_REGISTERED (RrepHeader);
+
+TypeId
+RrepHeader::GetTypeId ()
+{
+  static TypeId tid = TypeId ("ns3::greyattack-aodv::RrepHeader")
+    .SetParent<Header> ()
+    .SetGroupName ("greyattack-aodv")
+    .AddConstructor<RrepHeader> ()
+  ;
+  return tid;
+}
+
+TypeId
+RrepHeader::GetInstanceTypeId () const
+{
+  return GetTypeId ();
+}
+
+uint32_t
+RrepHeader::GetSerializedSize () const
+{
+  return 19+1;
+}
+
+void
+RrepHeader::Serialize (Buffer::Iterator i) const
+{
+  i.WriteU8 (m_flags);
+  i.WriteU8 (m_prefixSize);
+  i.WriteU8 (m_hopCount);
+  WriteTo (i, m_dst);
+  i.WriteHtonU32 (m_dstSeqNo);
+  WriteTo (i, m_origin);
+  i.WriteHtonU32 (m_lifeTime);
+  i.WriteU8(m_num_mass);
+}
+
+uint32_t
+RrepHeader::Deserialize (Buffer::Iterator start)
+{
+  Buffer::Iterator i = start;
+
+  m_flags = i.ReadU8 ();
+  m_prefixSize = i.ReadU8 (); 
+  m_hopCount = i.ReadU8 ();
+  ReadFrom (i, m_dst);
+  m_dstSeqNo = i.ReadNtohU32 ();
+  ReadFrom (i, m_origin);
+  m_lifeTime = i.ReadNtohU32 ();
+  m_num_mass = i.ReadU8();
+  m_num_mass = 0;
+
+  uint32_t dist = i.GetDistanceFrom (start);
+  NS_ASSERT (dist == GetSerializedSize ());
+  return dist;
+}
+
+void
+RrepHeader::Print (std::ostream &os) const
+{
+  os << "destination: ipv4 " << m_dst << " sequence number " << m_dstSeqNo;
+  if (m_prefixSize != 0)
+    {
+      os << " prefix size " << m_prefixSize;
+    }
+  os << " source ipv4 " << m_origin << " lifetime " << m_lifeTime
+     << " acknowledgment required flag " << (*this).GetAckRequired ();
+}
+
+void
+RrepHeader::SetLifeTime (Time t)
+{
+  m_lifeTime = t.GetMilliSeconds ();
+}
+
+Time
+RrepHeader::GetLifeTime () const
+{
+  Time t (MilliSeconds (m_lifeTime));
+  return t;
+}
+
+void
+RrepHeader::SetAckRequired (bool f)
+{
+  if (f)
+    {
+      m_flags |= (1 << 6);
+    }
+  else
+    {
+      m_flags &= ~(1 << 6);
+    }
+}
+
+bool
+RrepHeader::GetAckRequired () const
+{
+  return (m_flags & (1 << 6));
+}
+
+void
+RrepHeader::SetPrefixSize (uint8_t sz)
+{
+  m_prefixSize = sz;
+}
+
+uint8_t
+RrepHeader::GetPrefixSize () const
+{
+  return m_prefixSize;
+}
+
+bool
+RrepHeader::operator== (RrepHeader const & o) const
+{
+  return (m_flags == o.m_flags && m_prefixSize == o.m_prefixSize
+          && m_hopCount == o.m_hopCount && m_dst == o.m_dst && m_dstSeqNo == o.m_dstSeqNo
+          && m_origin == o.m_origin && m_lifeTime == o.m_lifeTime);
+}
+
+void
+RrepHeader::SetHello (Ipv4Address origin, uint32_t srcSeqNo, Time lifetime)
+{
+  m_flags = 0;
+  m_prefixSize = 0;
+  m_hopCount = 0;
+  m_dst = origin;
+  m_dstSeqNo = srcSeqNo;
+  m_origin = origin;
+  m_lifeTime = lifetime.GetMilliSeconds ();
+}
+
+std::ostream &
+operator<< (std::ostream & os, RrepHeader const & h)
+{
+  h.Print (os);
+  return os;
+}
+
+//-----------------------------------------------------------------------------
+// RREP-ACK
+//-----------------------------------------------------------------------------
+
+RrepAckHeader::RrepAckHeader ()
+  : m_reserved (0)
+{
+}
+
+NS_OBJECT_ENSURE_REGISTERED (RrepAckHeader);
+
+TypeId
+RrepAckHeader::GetTypeId ()
+{
+  static TypeId tid = TypeId ("ns3::greyattack-aodv::RrepAckHeader")
+    .SetParent<Header> ()
+    .SetGroupName ("greyattack-aodv")
+    .AddConstructor<RrepAckHeader> ()
+  ;
+  return tid;
+}
+
+TypeId
+RrepAckHeader::GetInstanceTypeId () const
+{
+  return GetTypeId ();
+}
+
+uint32_t
+RrepAckHeader::GetSerializedSize () const
+{
+  return 1;
+}
+
+void
+RrepAckHeader::Serialize (Buffer::Iterator i ) const
+{
+  i.WriteU8 (m_reserved);
+}
+
+uint32_t
+RrepAckHeader::Deserialize (Buffer::Iterator start )
+{
+  Buffer::Iterator i = start;
+  m_reserved = i.ReadU8 ();
+  uint32_t dist = i.GetDistanceFrom (start);
+  NS_ASSERT (dist == GetSerializedSize ());
+  return dist;
+}
+
+void
+RrepAckHeader::Print (std::ostream &os ) const
+{
+}
+
+bool
+RrepAckHeader::operator== (RrepAckHeader const & o ) const
+{
+  return m_reserved == o.m_reserved;
+}
+
+std::ostream &
+operator<< (std::ostream & os, RrepAckHeader const & h )
+{
+  h.Print (os);
+  return os;
+}
+
+//-----------------------------------------------------------------------------
+// RERR
+//-----------------------------------------------------------------------------
+RerrHeader::RerrHeader ()
+  : m_flag (0),
+    m_reserved (0)
+{
+}
+
+NS_OBJECT_ENSURE_REGISTERED (RerrHeader);
+
+TypeId
+RerrHeader::GetTypeId ()
+{
+  static TypeId tid = TypeId ("ns3::greyattack-aodv::RerrHeader")
+    .SetParent<Header> ()
+    .SetGroupName ("greyattack-aodv")
+    .AddConstructor<RerrHeader> ()
+  ;
+  return tid;
+}
+
+TypeId
+RerrHeader::GetInstanceTypeId () const
+{
+  return GetTypeId ();
+}
+
+uint32_t
+RerrHeader::GetSerializedSize () const
+{
+  return (3 + 8 * GetDestCount ());
+}
+
+void
+RerrHeader::Serialize (Buffer::Iterator i ) const
+{
+  i.WriteU8 (m_flag);
+  i.WriteU8 (m_reserved);
+  i.WriteU8 (GetDestCount ());
+  std::map<Ipv4Address, uint32_t>::const_iterator j;
+  for (j = m_unreachableDstSeqNo.begin (); j != m_unreachableDstSeqNo.end (); ++j)
+    {
+      WriteTo (i, (*j).first);
+      i.WriteHtonU32 ((*j).second);
+    }
+}
+
+uint32_t
+RerrHeader::Deserialize (Buffer::Iterator start )
+{
+  Buffer::Iterator i = start;
+  m_flag = i.ReadU8 ();
+  m_reserved = i.ReadU8 ();
+  uint8_t dest = i.ReadU8 ();
+  m_unreachableDstSeqNo.clear ();
+  Ipv4Address address;
+  uint32_t seqNo;
+  for (uint8_t k = 0; k < dest; ++k)
+    {
+      ReadFrom (i, address);
+      seqNo = i.ReadNtohU32 ();
+      m_unreachableDstSeqNo.insert (std::make_pair (address, seqNo));
+    }
+
+  uint32_t dist = i.GetDistanceFrom (start);
+  NS_ASSERT (dist == GetSerializedSize ());
+  return dist;
+}
+
+void
+RerrHeader::Print (std::ostream &os ) const
+{
+  os << "Unreachable destination (ipv4 address, seq. number):";
+  std::map<Ipv4Address, uint32_t>::const_iterator j;
+  for (j = m_unreachableDstSeqNo.begin (); j != m_unreachableDstSeqNo.end (); ++j)
+    {
+      os << (*j).first << ", " << (*j).second;
+    }
+  os << "No delete flag " << (*this).GetNoDelete ();
+}
+
+void
+RerrHeader::SetNoDelete (bool f )
+{
+  if (f)
+    {
+      m_flag |= (1 << 0);
+    }
+  else
+    {
+      m_flag &= ~(1 << 0);
+    }
+}
+
+bool
+RerrHeader::GetNoDelete () const
+{
+  return (m_flag & (1 << 0));
+}
+
+bool
+RerrHeader::AddUnDestination (Ipv4Address dst, uint32_t seqNo )
+{
+  if (m_unreachableDstSeqNo.find (dst) != m_unreachableDstSeqNo.end ())
+    {
+      return true;
+    }
+
+  NS_ASSERT (GetDestCount () < 255); // can't support more than 255 destinations in single RERR
+  m_unreachableDstSeqNo.insert (std::make_pair (dst, seqNo));
+  return true;
+}
+
+bool
+RerrHeader::RemoveUnDestination (std::pair<Ipv4Address, uint32_t> & un )
+{
+  if (m_unreachableDstSeqNo.empty ())
+    {
+      return false;
+    }
+  std::map<Ipv4Address, uint32_t>::iterator i = m_unreachableDstSeqNo.begin ();
+  un = *i;
+  m_unreachableDstSeqNo.erase (i);
+  return true;
+}
+
+void
+RerrHeader::Clear ()
+{
+  m_unreachableDstSeqNo.clear ();
+  m_flag = 0;
+  m_reserved = 0;
+}
+
+bool
+RerrHeader::operator== (RerrHeader const & o ) const
+{
+  if (m_flag != o.m_flag || m_reserved != o.m_reserved || GetDestCount () != o.GetDestCount ())
+    {
+      return false;
+    }
+
+  std::map<Ipv4Address, uint32_t>::const_iterator j = m_unreachableDstSeqNo.begin ();
+  std::map<Ipv4Address, uint32_t>::const_iterator k = o.m_unreachableDstSeqNo.begin ();
+  for (uint8_t i = 0; i < GetDestCount (); ++i)
+    {
+      if ((j->first != k->first) || (j->second != k->second))
+        {
+          return false;
+        }
+
+      j++;
+      k++;
+    }
+  return true;
+}
+
+std::ostream &
+operator<< (std::ostream & os, RerrHeader const & h )
+{
+  h.Print (os);
+  return os;
+}
+}
+}
diff --git a/greyattack-module/model/greyattack-aodv-packet.h b/greyattack-module/model/greyattack-aodv-packet.h
new file mode 100644
index 0000000000000000000000000000000000000000..037e8b30cf812aeec3001a0f0852e77cd94ac2e0
--- /dev/null
+++ b/greyattack-module/model/greyattack-aodv-packet.h
@@ -0,0 +1,632 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2009 IITP RAS
+ *
+ * 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
+ *
+ * Based on
+ *      NS-3 greyattack model developed by
+ *
+ * Authors: Charles Hutchins
+ */
+#ifndef greyattack_aodvPACKET_H
+#define greyattack_aodvPACKET_H
+
+#include <iostream>
+#include "ns3/header.h"
+#include "ns3/enum.h"
+#include "ns3/ipv4-address.h"
+#include <map>
+#include "ns3/nstime.h"
+
+namespace ns3 {
+namespace greyattackAodv {
+
+/**
+* \ingroup greyattack
+* \brief MessageType enumeration
+*/
+enum MessageType
+{
+  greyattackTYPE_RREQ  = 1,   //!< greyattackTYPE_RREQ
+  greyattackTYPE_RREP  = 2,   //!< greyattackTYPE_RREP
+  greyattackTYPE_RERR  = 3,   //!< greyattackTYPE_RERR
+  greyattackTYPE_RREP_ACK = 4 //!< greyattackTYPE_RREP_ACK
+};
+
+/**
+* \ingroup greyattack
+* \brief greyattack types
+*/
+class TypeHeader : public Header
+{
+public:
+  /**
+   * constructor
+   * \param t the greyattack RREQ type
+   */
+  TypeHeader (MessageType t = greyattackTYPE_RREQ);
+
+  /**
+   * \brief Get the type ID.
+   * \return the object TypeId
+   */
+  static TypeId GetTypeId ();
+  TypeId GetInstanceTypeId () const;
+  uint32_t GetSerializedSize () const;
+  void Serialize (Buffer::Iterator start) const;
+  uint32_t Deserialize (Buffer::Iterator start);
+  void Print (std::ostream &os) const;
+
+  /**
+   * \returns the type
+   */
+  MessageType Get () const
+  {
+    return m_type;
+  }
+  /**
+   * Check that type if valid
+   * \returns true if the type is valid
+   */
+  bool IsValid () const
+  {
+    return m_valid;
+  }
+  /**
+   * \brief Comparison operator
+   * \param o header to compare
+   * \return true if the headers are equal
+   */
+  bool operator== (TypeHeader const & o) const;
+private:
+  MessageType m_type; ///< type of the message
+  bool m_valid; ///< Indicates if the message is valid
+};
+
+/**
+  * \brief Stream output operator
+  * \param os output stream
+  * \return updated stream
+  */
+std::ostream & operator<< (std::ostream & os, TypeHeader const & h);
+
+/**
+* \ingroup greyattack
+* \brief   Route Request (RREQ) Message Format
+  \verbatim
+  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      |J|R|G|D|U|   Reserved          |   Hop Count   |
+  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+  |                            RREQ ID                            |
+  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+  |                    Destination IP Address                     |
+  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+  |                  Destination Sequence Number                  |
+  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+  |                    Originator IP Address                      |
+  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+  |                  Originator Sequence Number                   |
+  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+  \endverbatim
+*/
+class RreqHeader : public Header
+{
+public:
+  /**
+   * constructor
+   *
+   * \param flags the message flags (0)
+   * \param reserved the reserved bits (0)
+   * \param hopCount the hop count
+   * \param requestID the request ID
+   * \param dst the destination IP address
+   * \param dstSeqNo the destination sequence number
+   * \param origin the origin IP address
+   * \param originSeqNo the origin sequence number
+   */
+   RreqHeader (uint8_t flags = 0, uint8_t reserved = 0, uint8_t hopCount = 0,
+              uint32_t requestID = 0, Ipv4Address dst = Ipv4Address (),
+              uint32_t dstSeqNo = 0, Ipv4Address origin = Ipv4Address (),
+              uint32_t originSeqNo = 0);
+
+  /**
+   * \brief Get the type ID.
+   * \return the object TypeId
+   */
+  static TypeId GetTypeId ();
+  TypeId GetInstanceTypeId () const;
+  uint32_t GetSerializedSize () const;
+  void Serialize (Buffer::Iterator start) const;
+  uint32_t Deserialize (Buffer::Iterator start);
+  void Print (std::ostream &os) const;
+
+  // Fields
+  /**
+   * \brief Set the hop count
+   * \param count the hop count
+   */
+  void SetHopCount (uint8_t count)
+  {
+    m_hopCount = count;
+  }
+  /**
+   * \brief Get the hop count
+   * \return the hop count
+   */
+  uint8_t GetHopCount () const
+  {
+    return m_hopCount;
+  }
+  /**
+   * \brief Set the request ID
+   * \param id the request ID
+   */
+  void SetId (uint32_t id)
+  {
+    m_requestID = id;
+  }
+  /**
+   * \brief Get the request ID
+   * \return the request ID
+   */
+  uint32_t GetId () const
+  {
+    return m_requestID;
+  }
+  /**
+   * \brief Set the destination address
+   * \param a the destination address
+   */
+  void SetDst (Ipv4Address a)
+  {
+    m_dst = a;
+  }
+  /**
+   * \brief Get the destination address
+   * \return the destination address
+   */
+  Ipv4Address GetDst () const
+  {
+    return m_dst;
+  }
+  /**
+   * \brief Set the destination sequence number
+   * \param s the destination sequence number
+   */
+  void SetDstSeqno (uint32_t s)
+  {
+    m_dstSeqNo = s;
+  }
+  /**
+   * \brief Get the destination sequence number
+   * \return the destination sequence number
+   */
+  uint32_t GetDstSeqno () const
+  {
+    return m_dstSeqNo;
+  }
+  /**
+   * \brief Set the origin address
+   * \param a the origin address
+   */
+  void SetOrigin (Ipv4Address a)
+  {
+    m_origin = a;
+  }
+  /**
+   * \brief Get the origin address
+   * \return the origin address
+   */
+  Ipv4Address GetOrigin () const
+  {
+    return m_origin;
+  }
+  /**
+   * \brief Set the origin sequence number
+   * \param s the origin sequence number
+   */
+  void SetOriginSeqno (uint32_t s)
+  {
+    m_originSeqNo = s;
+  }
+  /**
+   * \brief Get the origin sequence number
+   * \return the origin sequence number
+   */
+  uint32_t GetOriginSeqno () const
+  {
+    return m_originSeqNo;
+  }
+
+  // Flags
+  /**
+   * \brief Set the gratuitous RREP flag
+   * \param f the gratuitous RREP flag
+   */
+  void SetGratuitousRrep (bool f);
+  /**
+   * \brief Get the gratuitous RREP flag
+   * \return the gratuitous RREP flag
+   */
+  bool GetGratuitousRrep () const;
+  /**
+   * \brief Set the Destination only flag
+   * \param f the Destination only flag
+   */
+  void SetDestinationOnly (bool f);
+  /**
+   * \brief Get the Destination only flag
+   * \return the Destination only flag
+   */
+  bool GetDestinationOnly () const;
+  /**
+   * \brief Set the unknown sequence number flag
+   * \param f the unknown sequence number flag
+   */
+  void SetUnknownSeqno (bool f);
+  /**
+   * \brief Get the unknown sequence number flag
+   * \return the unknown sequence number flag
+   */
+  bool GetUnknownSeqno () const;
+
+  /**
+   * \brief Comparison operator
+   * \param o RREQ header to compare
+   * \return true if the RREQ headers are equal
+   */
+  bool operator== (RreqHeader const & o) const;
+
+  float m_AER;
+
+private:
+  uint8_t        m_flags;          ///< |J|R|G|D|U| bit flags, see RFC
+  uint8_t        m_reserved;       ///< Not used (must be 0)
+  uint8_t        m_hopCount;       ///< Hop Count
+  uint32_t       m_requestID;      ///< RREQ ID
+  Ipv4Address    m_dst;            ///< Destination IP Address
+  uint32_t       m_dstSeqNo;       ///< Destination Sequence Number
+  Ipv4Address    m_origin;         ///< Originator IP Address
+  uint32_t       m_originSeqNo;    ///< Source Sequence Number
+};
+
+/**
+  * \brief Stream output operator
+  * \param os output stream
+  * \return updated stream
+  */
+std::ostream & operator<< (std::ostream & os, RreqHeader const &);
+
+/**
+* \ingroup greyattack
+* \brief Route Reply (RREP) Message Format
+  \verbatim
+  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      |R|A|    Reserved     |Prefix Sz|   Hop Count   |
+  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+  |                     Destination IP address                    |
+  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+  |                  Destination Sequence Number                  |
+  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+  |                    Originator IP address                      |
+  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+  |                           Lifetime                            |
+  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+  \endverbatim
+*/
+class RrepHeader : public Header
+{
+public:
+  /**
+   * constructor
+   *
+   * \param prefixSize the prefix size (0)
+   * \param hopCount the hop count (0)
+   * \param dst the destination IP address
+   * \param dstSeqNo the destination sequence number
+   * \param origin the origin IP address
+   * \param lifetime the lifetime
+   */
+  RrepHeader (uint8_t prefixSize = 0, uint8_t hopCount = 0, Ipv4Address dst =
+                Ipv4Address (), uint32_t dstSeqNo = 0, Ipv4Address origin =
+                Ipv4Address (), Time lifetime = MilliSeconds (0));
+  /**
+   * \brief Get the type ID.
+   * \return the object TypeId
+   */
+  static TypeId GetTypeId ();
+  TypeId GetInstanceTypeId () const;
+  uint32_t GetSerializedSize () const;
+  void Serialize (Buffer::Iterator start) const;
+  uint32_t Deserialize (Buffer::Iterator start);
+  void Print (std::ostream &os) const;
+
+  // Fields
+  /**
+   * \brief Set the hop count
+   * \param count the hop count
+   */
+  void SetHopCount (uint8_t count)
+  {
+    m_hopCount = count;
+  }
+  /**
+   * \brief Get the hop count
+   * \return the hop count
+   */
+  uint8_t GetHopCount () const
+  {
+    return m_hopCount;
+  }
+  /**
+   * \brief Set the destination address
+   * \param a the destination address
+   */
+  void SetDst (Ipv4Address a)
+  {
+    m_dst = a;
+  }
+  /**
+   * \brief Get the destination address
+   * \return the destination address
+   */
+  Ipv4Address GetDst () const
+  {
+    return m_dst;
+  }
+  /**
+   * \brief Set the destination sequence number
+   * \param s the destination sequence number
+   */
+  void SetDstSeqno (uint32_t s)
+  {
+    m_dstSeqNo = s;
+  }
+  /**
+   * \brief Get the destination sequence number
+   * \return the destination sequence number
+   */
+  uint32_t GetDstSeqno () const
+  {
+    return m_dstSeqNo;
+  }
+  /**
+   * \brief Set the origin address
+   * \param a the origin address
+   */
+  void SetOrigin (Ipv4Address a)
+  {
+    m_origin = a;
+  }
+  /**
+   * \brief Get the origin address
+   * \return the origin address
+   */
+  Ipv4Address GetOrigin () const
+  {
+    return m_origin;
+  }
+  /**
+   * \brief Set the lifetime
+   * \param t the lifetime
+   */
+  void SetLifeTime (Time t);
+  /**
+   * \brief Get the lifetime
+   * \return the lifetime
+   */
+  Time GetLifeTime () const;
+
+  // Flags
+  /**
+   * \brief Set the ack required flag
+   * \param f the ack required flag
+   */
+  void SetAckRequired (bool f);
+  /**
+   * \brief get the ack required flag
+   * \return the ack required flag
+   */
+  bool GetAckRequired () const;
+  /**
+   * \brief Set the prefix size
+   * \param sz the prefix size
+   */
+  void SetPrefixSize (uint8_t sz);
+  /**
+   * \brief Set the pefix size
+   * \return the prefix size
+   */
+  uint8_t GetPrefixSize () const;
+
+  /**
+   * Configure RREP to be a Hello message
+   *
+   * \param src the source IP address
+   * \param srcSeqNo the source sequence number
+   * \param lifetime the lifetime of the message
+   */
+  void SetHello (Ipv4Address src, uint32_t srcSeqNo, Time lifetime);
+
+  /**
+   * \brief Comparison operator
+   * \param o RREP header to compare
+   * \return true if the RREP headers are equal
+   */
+  bool operator== (RrepHeader const & o) const;
+private:
+  uint8_t       m_flags;            ///< A - acknowledgment required flag
+  uint8_t       m_prefixSize;       ///< Prefix Size
+  uint8_t       m_hopCount;         ///< Hop Count
+  Ipv4Address   m_dst;              ///< Destination IP Address
+  uint32_t      m_dstSeqNo;         ///< Destination Sequence Number
+  Ipv4Address   m_origin;           ///< Source IP Address
+  uint32_t      m_lifeTime;         ///< Lifetime (in milliseconds)
+  uint8_t       m_num_mass;         /// to the defense protocol compatible with this one
+};
+
+/**
+  * \brief Stream output operator
+  * \param os output stream
+  * \return updated stream
+  */
+std::ostream & operator<< (std::ostream & os, RrepHeader const &);
+
+/**
+* \ingroup greyattack
+* \brief Route Reply Acknowledgment (RREP-ACK) Message Format
+  \verbatim
+  0                   1
+  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+  |     Type      |   Reserved    |
+  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+  \endverbatim
+*/
+class RrepAckHeader : public Header
+{
+public:
+  /// constructor
+  RrepAckHeader ();
+
+  /**
+   * \brief Get the type ID.
+   * \return the object TypeId
+   */
+  static TypeId GetTypeId ();
+  TypeId GetInstanceTypeId () const;
+  uint32_t GetSerializedSize () const;
+  void Serialize (Buffer::Iterator start) const;
+  uint32_t Deserialize (Buffer::Iterator start);
+  void Print (std::ostream &os) const;
+
+  /**
+   * \brief Comparison operator
+   * \param o RREP header to compare
+   * \return true if the RREQ headers are equal
+   */
+  bool operator== (RrepAckHeader const & o) const;
+private:
+  uint8_t       m_reserved; ///< Not used (must be 0)
+};
+
+/**
+  * \brief Stream output operator
+  * \param os output stream
+  * \return updated stream
+  */
+std::ostream & operator<< (std::ostream & os, RrepAckHeader const &);
+
+
+/**
+* \ingroup greyattack
+* \brief Route Error (RERR) Message Format
+  \verbatim
+  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      |N|          Reserved           |   DestCount   |
+  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+  |            Unreachable Destination IP Address (1)             |
+  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+  |         Unreachable Destination Sequence Number (1)           |
+  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-|
+  |  Additional Unreachable Destination IP Addresses (if needed)  |
+  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+  |Additional Unreachable Destination Sequence Numbers (if needed)|
+  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+  \endverbatim
+*/
+class RerrHeader : public Header
+{
+public:
+  /// constructor
+  RerrHeader ();
+
+  /**
+   * \brief Get the type ID.
+   * \return the object TypeId
+   */
+  static TypeId GetTypeId ();
+  TypeId GetInstanceTypeId () const;
+  uint32_t GetSerializedSize () const;
+  void Serialize (Buffer::Iterator i) const;
+  uint32_t Deserialize (Buffer::Iterator start);
+  void Print (std::ostream &os) const;
+
+  // No delete flag
+  /**
+   * \brief Set the no delete flag
+   * \param f the no delete flag
+   */
+  void SetNoDelete (bool f);
+  /**
+   * \brief Get the no delete flag
+   * \return the no delete flag
+   */
+  bool GetNoDelete () const;
+
+  /**
+   * \brief Add unreachable node address and its sequence number in RERR header
+   * \param dst unreachable IPv4 address
+   * \param seqNo unreachable sequence number
+   * \return false if we already added maximum possible number of unreachable destinations
+   */
+  bool AddUnDestination (Ipv4Address dst, uint32_t seqNo);
+  /**
+   * \brief Delete pair (address + sequence number) from REER header, if the number of unreachable destinations > 0
+   * \param un unreachable pair (address + sequence number)
+   * \return true on success
+   */
+  bool RemoveUnDestination (std::pair<Ipv4Address, uint32_t> & un);
+  /// Clear header
+  void Clear ();
+  /**
+   * \returns number of unreachable destinations in RERR message
+   */
+  uint8_t GetDestCount () const
+  {
+    return (uint8_t)m_unreachableDstSeqNo.size ();
+  }
+
+  /**
+   * \brief Comparison operator
+   * \param o RERR header to compare
+   * \return true if the RERR headers are equal
+   */
+  bool operator== (RerrHeader const & o) const;
+private:
+  uint8_t m_flag;            ///< No delete flag
+  uint8_t m_reserved;        ///< Not used (must be 0)
+
+  /// List of Unreachable destination: IP addresses and sequence numbers
+  std::map<Ipv4Address, uint32_t> m_unreachableDstSeqNo;
+};
+
+/**
+  * \brief Stream output operator
+  * \param os output stream
+  * \return updated stream
+  */
+std::ostream & operator<< (std::ostream & os, RerrHeader const &);
+
+}  // namespace greyattack-aodv
+}  // namespace ns3
+
+#endif /* greyattack_aodvPACKET_H */
diff --git a/greyattack-module/model/greyattack-aodv-routing-protocol.cc b/greyattack-module/model/greyattack-aodv-routing-protocol.cc
new file mode 100644
index 0000000000000000000000000000000000000000..d1c87bdc31d8b75c7481e308e1d8d02d0a032f38
--- /dev/null
+++ b/greyattack-module/model/greyattack-aodv-routing-protocol.cc
@@ -0,0 +1,2301 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2009 IITP RAS
+ *
+ * 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
+ *
+ * Based on
+ *      NS-3 greyattack model developed by
+ *
+ * Authors: Charles Hutchins
+ */
+#define NS_LOG_APPEND_CONTEXT                                   \
+  if (m_ipv4) { std::clog << "[node " << m_ipv4->GetObject<Node> ()->GetId () << "] "; }
+
+#include "greyattack-aodv-routing-protocol.h"
+#include "ns3/log.h"
+#include "ns3/boolean.h"
+#include "ns3/random-variable-stream.h"
+#include "ns3/inet-socket-address.h"
+#include "ns3/trace-source-accessor.h"
+#include "ns3/udp-socket-factory.h"
+#include "ns3/udp-l4-protocol.h"
+#include "ns3/udp-header.h"
+#include "ns3/wifi-net-device.h"
+#include "ns3/adhoc-wifi-mac.h"
+#include "ns3/wifi-mac-queue-item.h"
+#include "ns3/string.h"
+#include "ns3/pointer.h"
+#include "ns3/double.h"
+#include <algorithm>
+#include <limits>
+
+namespace ns3 {
+
+NS_LOG_COMPONENT_DEFINE ("greyattack-aodvRoutingProtocol");
+
+namespace greyattackAodv {
+NS_OBJECT_ENSURE_REGISTERED (RoutingProtocol);
+
+/// UDP Port for greyattack control traffic
+const uint32_t RoutingProtocol::greyattack_PORT = 654;
+
+/**
+* \ingroup greyattack
+* \brief Tag used by greyattack implementation
+*/
+class DeferredRouteOutputTag : public Tag
+{
+
+public:
+  /**
+   * \brief Constructor
+   * \param o the output interface
+   */
+  DeferredRouteOutputTag (int32_t o = -1) : Tag (),
+                                            m_oif (o)
+  {
+  }
+
+  /**
+   * \brief Get the type ID.
+   * \return the object TypeId
+   */
+  static TypeId GetTypeId ()
+  {
+    static TypeId tid = TypeId ("ns3::greyattack-aodv::DeferredRouteOutputTag")
+      .SetParent<Tag> ()
+      .SetGroupName ("greyattack-aodv")
+      .AddConstructor<DeferredRouteOutputTag> ()
+    ;
+    return tid;
+  }
+
+  TypeId  GetInstanceTypeId () const
+  {
+    return GetTypeId ();
+  }
+
+  /**
+   * \brief Get the output interface
+   * \return the output interface
+   */
+  int32_t GetInterface () const
+  {
+    return m_oif;
+  }
+
+  /**
+   * \brief Set the output interface
+   * \param oif the output interface
+   */
+  void SetInterface (int32_t oif)
+  {
+    m_oif = oif;
+  }
+
+  uint32_t GetSerializedSize () const
+  {
+    return sizeof(int32_t);
+  }
+
+  void  Serialize (TagBuffer i) const
+  {
+    i.WriteU32 (m_oif);
+  }
+
+  void  Deserialize (TagBuffer i)
+  {
+    m_oif = i.ReadU32 ();
+  }
+
+  void  Print (std::ostream &os) const
+  {
+    os << "DeferredRouteOutputTag: output interface = " << m_oif;
+  }
+
+private:
+  /// Positive if output device is fixed in RouteOutput
+  int32_t m_oif;
+};
+
+NS_OBJECT_ENSURE_REGISTERED (DeferredRouteOutputTag);
+
+
+//-----------------------------------------------------------------------------
+RoutingProtocol::RoutingProtocol ()
+  : m_rreqRetries (2),
+    m_ttlStart (1),
+    m_ttlIncrement (2),
+    m_ttlThreshold (7),
+    m_timeoutBuffer (2),
+    m_rreqRateLimit (10),
+    m_rerrRateLimit (10),
+    m_activeRouteTimeout (Seconds (3)),
+    m_netDiameter (35),
+    m_nodeTraversalTime (MilliSeconds (40)),
+    m_netTraversalTime (Time ((2 * m_netDiameter) * m_nodeTraversalTime)),
+    m_pathDiscoveryTime ( Time (2 * m_netTraversalTime)),
+    m_myRouteTimeout (Time (2 * std::max (m_pathDiscoveryTime, m_activeRouteTimeout))),
+    m_helloInterval (Seconds (1)),
+    m_allowedHelloLoss (2),
+    m_deletePeriod (Time (5 * std::max (m_activeRouteTimeout, m_helloInterval))),
+    m_nextHopWait (m_nodeTraversalTime + MilliSeconds (10)),
+    m_blackListTimeout (Time (m_rreqRetries * m_netTraversalTime)),
+    m_maxQueueLen (64),
+    m_maxQueueTime (Seconds (30)),
+    m_destinationOnly (false),
+    m_gratuitousReply (true),
+    m_enableHello (false),
+    m_routingTable (m_deletePeriod),
+    m_queue (m_maxQueueLen, m_maxQueueTime),
+    m_requestId (0),
+    m_seqNo (0),
+    m_rreqIdCache (m_pathDiscoveryTime),
+    m_dpd (m_pathDiscoveryTime),
+    m_nb (m_helloInterval),
+    m_rreqCount (0),
+    m_rerrCount (0),
+    m_vPercentDrop(0.0),
+    m_vTConnection(0.0),
+    m_vTNeighbour(0),
+    m_htimer (Timer::CANCEL_ON_DESTROY),
+    m_rreqRateLimitTimer (Timer::CANCEL_ON_DESTROY),
+    m_rerrRateLimitTimer (Timer::CANCEL_ON_DESTROY),
+    m_lastBcastTime (Seconds (0))
+{
+  m_nb.SetCallback (MakeCallback (&RoutingProtocol::SendRerrWhenBreaksLinkToNextHop, this));
+  targetNodes = CreateObject<TargetNodes> ();
+}
+
+TypeId
+RoutingProtocol::GetTypeId (void)
+{
+  static TypeId tid = TypeId ("ns3::greyattack-aodv::RoutingProtocol")
+    .SetParent<Ipv4RoutingProtocol> ()
+    .SetGroupName ("greyattack-aodv")
+    .AddConstructor<RoutingProtocol> ()
+    .AddAttribute ("HelloInterval", "HELLO messages emission interval.",
+                   TimeValue (Seconds (1)),
+                   MakeTimeAccessor (&RoutingProtocol::m_helloInterval),
+                   MakeTimeChecker ())
+    .AddAttribute ("targetNodes", "A List of nodes that we wish to target, and their signal strength",
+                    PointerValue(),
+                    MakePointerAccessor(&RoutingProtocol::targetNodes),
+                    MakePointerChecker<TargetNodes>())
+    .AddAttribute ("NeighbourThresh", "The Number of Neighbour threshold nodes.",
+                 UintegerValue (0),
+                 MakeUintegerAccessor (&RoutingProtocol::m_vTNeighbour),
+                 MakeUintegerChecker<uint32_t> ())
+    .AddAttribute ("mStrat", "The Malicious Node Strategy.",
+                     UintegerValue (0),
+                     MakeUintegerAccessor (&RoutingProtocol::m_strat),
+                     MakeUintegerChecker<uint32_t> ())
+    .AddAttribute ("ConnectionStrengthThreshold",
+                   "If the connection strength to a node is greater than this value, then the packet will be dropped",
+                   DoubleValue(0.0), MakeDoubleAccessor(&RoutingProtocol::m_vTConnection),
+                   MakeDoubleChecker<double> ())
+    .AddAttribute ("TtlStart", "Initial TTL value for RREQ.",
+                   UintegerValue (1),
+                   MakeUintegerAccessor (&RoutingProtocol::m_ttlStart),
+                   MakeUintegerChecker<uint16_t> ())
+    .AddAttribute ("TtlIncrement", "TTL increment for each attempt using the expanding ring search for RREQ dissemination.",
+                   UintegerValue (2),
+                   MakeUintegerAccessor (&RoutingProtocol::m_ttlIncrement),
+                   MakeUintegerChecker<uint16_t> ())
+    .AddAttribute ("TtlThreshold", "Maximum TTL value for expanding ring search, TTL = NetDiameter is used beyond this value.",
+                   UintegerValue (7),
+                   MakeUintegerAccessor (&RoutingProtocol::m_ttlThreshold),
+                   MakeUintegerChecker<uint16_t> ())
+    .AddAttribute ("TimeoutBuffer", "Provide a buffer for the timeout.",
+                   UintegerValue (2),
+                   MakeUintegerAccessor (&RoutingProtocol::m_timeoutBuffer),
+                   MakeUintegerChecker<uint16_t> ())
+    .AddAttribute ("RreqRetries", "Maximum number of retransmissions of RREQ to discover a route",
+                   UintegerValue (2),
+                   MakeUintegerAccessor (&RoutingProtocol::m_rreqRetries),
+                   MakeUintegerChecker<uint32_t> ())
+    .AddAttribute ("RreqRateLimit", "Maximum number of RREQ per second.",
+                   UintegerValue (10),
+                   MakeUintegerAccessor (&RoutingProtocol::m_rreqRateLimit),
+                   MakeUintegerChecker<uint32_t> ())
+    .AddAttribute ("RerrRateLimit", "Maximum number of RERR per second.",
+                   UintegerValue (10),
+                   MakeUintegerAccessor (&RoutingProtocol::m_rerrRateLimit),
+                   MakeUintegerChecker<uint32_t> ())
+    .AddAttribute ("NodeTraversalTime", "Conservative estimate of the average one hop traversal time for packets and should include "
+                   "queuing delays, interrupt processing times and transfer times.",
+                   TimeValue (MilliSeconds (40)),
+                   MakeTimeAccessor (&RoutingProtocol::m_nodeTraversalTime),
+                   MakeTimeChecker ())
+    .AddAttribute ("NextHopWait", "Period of our waiting for the neighbour's RREP_ACK = 10 ms + NodeTraversalTime",
+                   TimeValue (MilliSeconds (50)),
+                   MakeTimeAccessor (&RoutingProtocol::m_nextHopWait),
+                   MakeTimeChecker ())
+    .AddAttribute ("ActiveRouteTimeout", "Period of time during which the route is considered to be valid",
+                   TimeValue (Seconds (3)),
+                   MakeTimeAccessor (&RoutingProtocol::m_activeRouteTimeout),
+                   MakeTimeChecker ())
+    .AddAttribute ("MyRouteTimeout", "Value of lifetime field in RREP generating by this node = 2 * max(ActiveRouteTimeout, PathDiscoveryTime)",
+                   TimeValue (Seconds (11.2)),
+                   MakeTimeAccessor (&RoutingProtocol::m_myRouteTimeout),
+                   MakeTimeChecker ())
+    .AddAttribute ("BlackListTimeout", "Time for which the node is put into the blacklist = RreqRetries * NetTraversalTime",
+                   TimeValue (Seconds (5.6)),
+                   MakeTimeAccessor (&RoutingProtocol::m_blackListTimeout),
+                   MakeTimeChecker ())
+    .AddAttribute ("DeletePeriod", "DeletePeriod is intended to provide an upper bound on the time for which an upstream node A "
+                   "can have a neighbor B as an active next hop for destination D, while B has invalidated the route to D."
+                   " = 5 * max (HelloInterval, ActiveRouteTimeout)",
+                   TimeValue (Seconds (15)),
+                   MakeTimeAccessor (&RoutingProtocol::m_deletePeriod),
+                   MakeTimeChecker ())
+    .AddAttribute ("NetDiameter", "Net diameter measures the maximum possible number of hops between two nodes in the network",
+                   UintegerValue (35),
+                   MakeUintegerAccessor (&RoutingProtocol::m_netDiameter),
+                   MakeUintegerChecker<uint32_t> ())
+    .AddAttribute ("NetTraversalTime", "Estimate of the average net traversal time = 2 * NodeTraversalTime * NetDiameter",
+                   TimeValue (Seconds (2.8)),
+                   MakeTimeAccessor (&RoutingProtocol::m_netTraversalTime),
+                   MakeTimeChecker ())
+    .AddAttribute ("PathDiscoveryTime", "Estimate of maximum time needed to find route in network = 2 * NetTraversalTime",
+                   TimeValue (Seconds (5.6)),
+                   MakeTimeAccessor (&RoutingProtocol::m_pathDiscoveryTime),
+                   MakeTimeChecker ())
+    .AddAttribute ("MaxQueueLen", "Maximum number of packets that we allow a routing protocol to buffer.",
+                   UintegerValue (64),
+                   MakeUintegerAccessor (&RoutingProtocol::SetMaxQueueLen,
+                                         &RoutingProtocol::GetMaxQueueLen),
+                   MakeUintegerChecker<uint32_t> ())
+    .AddAttribute ("MaxQueueTime", "Maximum time packets can be queued (in seconds)",
+                   TimeValue (Seconds (30)),
+                   MakeTimeAccessor (&RoutingProtocol::SetMaxQueueTime,
+                                     &RoutingProtocol::GetMaxQueueTime),
+                   MakeTimeChecker ())
+    .AddAttribute ("AllowedHelloLoss", "Number of hello messages which may be loss for valid link.",
+                   UintegerValue (2),
+                   MakeUintegerAccessor (&RoutingProtocol::m_allowedHelloLoss),
+                   MakeUintegerChecker<uint16_t> ())
+    .AddAttribute ("GratuitousReply", "Indicates whether a gratuitous RREP should be unicast to the node originated route discovery.",
+                   BooleanValue (true),
+                   MakeBooleanAccessor (&RoutingProtocol::SetGratuitousReplyFlag,
+                                        &RoutingProtocol::GetGratuitousReplyFlag),
+                   MakeBooleanChecker ())
+    .AddAttribute ("DestinationOnly", "Indicates only the destination may respond to this RREQ.",
+                   BooleanValue (false),
+                   MakeBooleanAccessor (&RoutingProtocol::SetDestinationOnlyFlag,
+                                        &RoutingProtocol::GetDestinationOnlyFlag),
+                   MakeBooleanChecker ())
+    .AddAttribute ("EnableHello", "Indicates whether a hello messages enable.",
+                   BooleanValue (true),
+                   MakeBooleanAccessor (&RoutingProtocol::SetHelloEnable,
+                                        &RoutingProtocol::GetHelloEnable),
+                   MakeBooleanChecker ())
+    .AddAttribute ("EnableBroadcast", "Indicates whether a broadcast data packets forwarding enable.",
+                   BooleanValue (true),
+                   MakeBooleanAccessor (&RoutingProtocol::SetBroadcastEnable,
+                                        &RoutingProtocol::GetBroadcastEnable),
+                   MakeBooleanChecker ())
+    .AddAttribute ("UniformRv",
+                   "Access to the underlying UniformRandomVariable",
+                   StringValue ("ns3::UniformRandomVariable"),
+                   MakePointerAccessor (&RoutingProtocol::m_uniformRandomVariable),
+                   MakePointerChecker<UniformRandomVariable> ())
+    .AddAttribute("PercentDrop",
+                  "The Number of Packets to drop",
+                  DoubleValue(0.0), MakeDoubleAccessor(&RoutingProtocol::m_vPercentDrop),
+                  MakeDoubleChecker<double> ())
+  ;
+  return tid;
+}
+
+void
+RoutingProtocol::SetMaxQueueLen (uint32_t len)
+{
+  m_maxQueueLen = len;
+  m_queue.SetMaxQueueLen (len);
+}
+void
+RoutingProtocol::SetMaxQueueTime (Time t)
+{
+  m_maxQueueTime = t;
+  m_queue.SetQueueTimeout (t);
+}
+
+RoutingProtocol::~RoutingProtocol ()
+{
+}
+
+void
+RoutingProtocol::DoDispose ()
+{
+  m_ipv4 = 0;
+  for (std::map<Ptr<Socket>, Ipv4InterfaceAddress>::iterator iter =
+         m_socketAddresses.begin (); iter != m_socketAddresses.end (); iter++)
+    {
+      iter->first->Close ();
+    }
+  m_socketAddresses.clear ();
+  for (std::map<Ptr<Socket>, Ipv4InterfaceAddress>::iterator iter =
+         m_socketSubnetBroadcastAddresses.begin (); iter != m_socketSubnetBroadcastAddresses.end (); iter++)
+    {
+      iter->first->Close ();
+    }
+  m_socketSubnetBroadcastAddresses.clear ();
+  Ipv4RoutingProtocol::DoDispose ();
+}
+
+void
+RoutingProtocol::PrintRoutingTable (Ptr<OutputStreamWrapper> stream, Time::Unit unit) const
+{
+  *stream->GetStream () << "Node: " << m_ipv4->GetObject<Node> ()->GetId ()
+                        << "; Time: " << Now ().As (unit)
+                        << ", Local time: " << m_ipv4->GetObject<Node> ()->GetLocalTime ().As (unit)
+                        << ", greyattack-aodv Routing table" << std::endl;
+
+  m_routingTable.Print (stream, unit);
+  *stream->GetStream () << std::endl;
+}
+
+int64_t
+RoutingProtocol::AssignStreams (int64_t stream)
+{
+  NS_LOG_FUNCTION (this << stream);
+  m_uniformRandomVariable->SetStream (stream);
+  return 1;
+}
+
+void
+RoutingProtocol::Start ()
+{
+  NS_LOG_FUNCTION (this);
+
+    //This seems to be a function which is called when the protocol starts operation
+    //by this time, we have sorted the strategies out, so lets turn it into an enum here:
+    strat = static_cast<AttackStratSelect>(m_strat);
+
+  if (m_enableHello)
+    {
+      m_nb.ScheduleTimer ();
+    }
+  m_rreqRateLimitTimer.SetFunction (&RoutingProtocol::RreqRateLimitTimerExpire,
+                                    this);
+  m_rreqRateLimitTimer.Schedule (Seconds (1));
+
+  m_rerrRateLimitTimer.SetFunction (&RoutingProtocol::RerrRateLimitTimerExpire,
+                                    this);
+  m_rerrRateLimitTimer.Schedule (Seconds (1));
+
+}
+
+Ptr<Ipv4Route>
+RoutingProtocol::RouteOutput (Ptr<Packet> p, const Ipv4Header &header,
+                              Ptr<NetDevice> oif, Socket::SocketErrno &sockerr)
+{
+  NS_LOG_FUNCTION (this << header << (oif ? oif->GetIfIndex () : 0));
+  if (!p)
+    {
+      NS_LOG_DEBUG ("Packet is == 0");
+      return LoopbackRoute (header, oif); // later
+    }
+  if (m_socketAddresses.empty ())
+    {
+      sockerr = Socket::ERROR_NOROUTETOHOST;
+      NS_LOG_LOGIC ("No greyattack-aodv interfaces");
+      Ptr<Ipv4Route> route;
+      return route;
+    }
+  sockerr = Socket::ERROR_NOTERROR;
+  Ptr<Ipv4Route> route;
+  Ipv4Address dst = header.GetDestination ();
+  RoutingTableEntry rt;
+  if (m_routingTable.LookupValidRoute (dst, rt))
+    {
+      route = rt.GetRoute ();
+      NS_ASSERT (route != 0);
+      NS_LOG_DEBUG ("Exist route to " << route->GetDestination () << " from interface " << route->GetSource ());
+      if (oif != 0 && route->GetOutputDevice () != oif)
+        {
+          NS_LOG_DEBUG ("Output device doesn't match. Dropped.");
+          sockerr = Socket::ERROR_NOROUTETOHOST;
+          return Ptr<Ipv4Route> ();
+        }
+      UpdateRouteLifeTime (dst, m_activeRouteTimeout);
+      UpdateRouteLifeTime (route->GetGateway (), m_activeRouteTimeout);
+      return route;
+    }
+
+  // Valid route not found, in this case we return loopback.
+  // Actual route request will be deferred until packet will be fully formed,
+  // routed to loopback, received from loopback and passed to RouteInput (see below)
+  uint32_t iif = (oif ? m_ipv4->GetInterfaceForDevice (oif) : -1);
+  DeferredRouteOutputTag tag (iif);
+  NS_LOG_DEBUG ("Valid Route not found");
+  if (!p->PeekPacketTag (tag))
+    {
+      p->AddPacketTag (tag);
+    }
+  return LoopbackRoute (header, oif);
+}
+
+void
+RoutingProtocol::DeferredRouteOutput (Ptr<const Packet> p, const Ipv4Header & header,
+                                      UnicastForwardCallback ucb, ErrorCallback ecb)
+{
+  NS_LOG_FUNCTION (this << p << header);
+  NS_ASSERT (p != 0 && p != Ptr<Packet> ());
+
+  QueueEntry newEntry (p, header, ucb, ecb);
+  bool result = m_queue.Enqueue (newEntry);
+  //std::cout << "my queue size = " << m_queue.GetSize()  << " after adding packet for " << header.GetDestination() << "\n";
+  if (result)
+    {
+      NS_LOG_LOGIC ("Add packet " << p->GetUid () << " to queue. Protocol " << (uint16_t) header.GetProtocol ());
+      RoutingTableEntry rt;
+      bool result = m_routingTable.LookupRoute (header.GetDestination (), rt);
+      if (!result || ((rt.GetFlag () != IN_SEARCH) && result))
+        {
+          NS_LOG_LOGIC ("Send new RREQ for outbound packet to " << header.GetDestination ());
+          SendRequest (header.GetDestination ());
+        }
+    }
+}
+
+bool
+RoutingProtocol::RouteInput (Ptr<const Packet> p, const Ipv4Header &header,
+                             Ptr<const NetDevice> idev, UnicastForwardCallback ucb,
+                             MulticastForwardCallback mcb, LocalDeliverCallback lcb, ErrorCallback ecb)
+{
+  NS_LOG_FUNCTION (this << p->GetUid () << header.GetDestination () << idev->GetAddress ());
+  if (m_socketAddresses.empty ())
+    {
+      NS_LOG_LOGIC ("No greyattack-aodv interfaces");
+      return false;
+    }
+  NS_ASSERT (m_ipv4 != 0);
+  NS_ASSERT (p != 0);
+  // Check if input device supports IP
+  NS_ASSERT (m_ipv4->GetInterfaceForDevice (idev) >= 0);
+  int32_t iif = m_ipv4->GetInterfaceForDevice (idev);
+
+  Ipv4Address dst = header.GetDestination ();
+  Ipv4Address origin = header.GetSource ();
+
+  // Deferred route request
+  if (idev == m_lo)
+    {
+      DeferredRouteOutputTag tag;
+      if (p->PeekPacketTag (tag))
+        {
+          DeferredRouteOutput (p, header, ucb, ecb);
+          return true;
+        }
+    }
+
+  // Duplicate of own packet
+  if (IsMyOwnAddress (origin))
+    {
+      return true;
+    }
+
+  // greyattack is not a multicast routing protocol
+  if (dst.IsMulticast ())
+    {
+      return false;
+    }
+
+  // Broadcast local delivery/forwarding
+  for (std::map<Ptr<Socket>, Ipv4InterfaceAddress>::const_iterator j =
+         m_socketAddresses.begin (); j != m_socketAddresses.end (); ++j)
+    {
+      Ipv4InterfaceAddress iface = j->second;
+      if (m_ipv4->GetInterfaceForAddress (iface.GetLocal ()) == iif)
+        {
+          if (dst == iface.GetBroadcast () || dst.IsBroadcast ())
+            {
+              if (m_dpd.IsDuplicate (p, header))
+                {
+                  NS_LOG_DEBUG ("Duplicated packet " << p->GetUid () << " from " << origin << ". Drop.");
+                  return true;
+                }
+              UpdateRouteLifeTime (origin, m_activeRouteTimeout);
+              Ptr<Packet> packet = p->Copy ();
+              if (lcb.IsNull () == false)
+                {
+                  NS_LOG_LOGIC ("Broadcast local delivery to " << iface.GetLocal ());
+                  lcb (p, header, iif);
+                  // Fall through to additional processing
+                }
+              else
+                {
+                  NS_LOG_ERROR ("Unable to deliver packet locally due to null callback " << p->GetUid () << " from " << origin);
+                  ecb (p, header, Socket::ERROR_NOROUTETOHOST);
+                }
+              if (!m_enableBroadcast)
+                {
+                  return true;
+                }
+              if (header.GetProtocol () == UdpL4Protocol::PROT_NUMBER)
+                {
+                  UdpHeader udpHeader;
+                  p->PeekHeader (udpHeader);
+                  if (udpHeader.GetDestinationPort () == greyattack_PORT)
+                    {
+                      // greyattack packets sent in broadcast are already managed
+                      return true;
+                    }
+                }
+              if (header.GetTtl () > 1)
+                {
+                  NS_LOG_LOGIC ("Forward broadcast. TTL " << (uint16_t) header.GetTtl ());
+                  RoutingTableEntry toBroadcast;
+                  if (m_routingTable.LookupRoute (dst, toBroadcast))
+                    {
+                      Ptr<Ipv4Route> route = toBroadcast.GetRoute ();
+                      ucb (route, packet, header);
+                    }
+                  else
+                    {
+                      NS_LOG_DEBUG ("No route to forward broadcast. Drop packet " << p->GetUid ());
+                    }
+                }
+              else
+                {
+                  NS_LOG_DEBUG ("TTL exceeded. Drop packet " << p->GetUid ());
+                }
+              return true;
+            }
+        }
+    }
+
+  // Unicast local delivery
+  if (m_ipv4->IsDestinationAddress (dst, iif))
+    {
+      UpdateRouteLifeTime (origin, m_activeRouteTimeout);
+      RoutingTableEntry toOrigin;
+      if (m_routingTable.LookupValidRoute (origin, toOrigin))
+        {
+          UpdateRouteLifeTime (toOrigin.GetNextHop (), m_activeRouteTimeout);
+          m_nb.Update (toOrigin.GetNextHop (), m_activeRouteTimeout);
+        }
+      if (lcb.IsNull () == false)
+        {
+          NS_LOG_LOGIC ("Unicast local delivery to " << dst);
+          lcb (p, header, iif);
+        }
+      else
+        {
+          NS_LOG_ERROR ("Unable to deliver packet locally due to null callback " << p->GetUid () << " from " << origin);
+          ecb (p, header, Socket::ERROR_NOROUTETOHOST);
+        }
+      return true;
+    }
+
+  // Check if input device supports IP forwarding
+  if (m_ipv4->IsForwarding (iif) == false)
+    {
+      NS_LOG_LOGIC ("Forwarding disabled for this interface");
+      ecb (p, header, Socket::ERROR_NOROUTETOHOST);
+      return true;
+    }
+
+  // Forwarding
+  return Forwarding (p, header, ucb, ecb);
+}
+
+bool
+RoutingProtocol::Forwarding (Ptr<const Packet> p, const Ipv4Header & header,
+                             UnicastForwardCallback ucb, ErrorCallback ecb)
+{
+  NS_LOG_FUNCTION (this);
+  Ipv4Address dst = header.GetDestination ();
+  Ipv4Address origin = header.GetSource ();
+  uint16_t packetID = header.GetIdentification();
+  m_routingTable.Purge ();
+  RoutingTableEntry toDst;
+  if (m_routingTable.LookupRoute (dst, toDst))
+    {
+      if (toDst.GetFlag () == VALID)
+        {
+          Ptr<Ipv4Route> route = toDst.GetRoute ();
+          NS_LOG_LOGIC (route->GetSource () << " forwarding to " << dst << " from " << origin << " packet " << p->GetUid ());
+
+          /*
+           *  Each time a route is used to forward a data packet, its Active Route
+           *  Lifetime field of the source, destination and the next hop on the
+           *  path to the destination is updated to be no less than the current
+           *  time plus ActiveRouteTimeout.
+           */
+          UpdateRouteLifeTime (origin, m_activeRouteTimeout);
+          UpdateRouteLifeTime (dst, m_activeRouteTimeout);
+          UpdateRouteLifeTime (route->GetGateway (), m_activeRouteTimeout);
+          /*
+           *  Since the route between each originator and destination pair is expected to be symmetric, the
+           *  Active Route Lifetime for the previous hop, along the reverse path back to the IP source, is also updated
+           *  to be no less than the current time plus ActiveRouteTimeout
+           */
+          RoutingTableEntry toOrigin;
+          m_routingTable.LookupRoute (origin, toOrigin);
+          UpdateRouteLifeTime (toOrigin.GetNextHop (), m_activeRouteTimeout);
+
+          m_nb.Update (route->GetGateway (), m_activeRouteTimeout);
+          m_nb.Update (toOrigin.GetNextHop (), m_activeRouteTimeout);
+
+          switch(strat)
+          {
+              case PACKET_DROP_PERC:{
+                  ////randomly drop packets a certain percent of the time - but otherwise act normally.
+                  NS_LOG_ERROR("Strategy PACKET_DROP_SELECT selected");
+
+                  Ptr<UniformRandomVariable> rng = CreateObject<UniformRandomVariable>();
+                  rng->SetAttribute ("Min", DoubleValue (0));
+                  rng->SetAttribute ("Max", DoubleValue (1));
+
+                  double randomDouble = rng->GetValue();
+                  if (randomDouble < m_vPercentDrop && p->GetSize() > 400) {
+                      NS_LOG_ERROR("[Attack - PACKET_DROP_PERC]: Dropped packet " << packetID << " where the next hop was "
+                                                                                  << toDst.GetNextHop());
+                      return false;
+                  }
+                  break;
+              }
+              case PACKET_DROP_CONNECTION:{
+                  //// drops packets when the connection to the next hop node is at or above a pre-set threshold value
+                  NS_LOG_ERROR("Strategy PACKET_DROP_CONNECTION selected");
+
+                  // Get the node number from destination address and the precursor nodes
+                  uint8_t buf[4];
+                  std::vector<Ipv4Address> precursors;
+                  double precur_connection_strength = 0.0;
+                  uint32_t precur_node = 999;
+
+                  toDst.GetNextHop().Serialize(buf);
+                  toDst.GetPrecursors (precursors);
+
+                  // get the node number of the target node
+                  uint32_t index = unsigned(buf[3]) - 1;
+
+                  // check if we have updated the connection_strength vector...
+                  if (!targetNodes->connection_strength.size())
+                      break;
+
+                  // get the node number of the precursor.
+                  for(auto i : precursors)
+                  {
+                        uint8_t precur_buf[4];
+                        i.Serialize(precur_buf);
+                        precur_node = unsigned(precur_buf[3]) - 1;
+
+                        // check if the precursor node is valid
+                        if (precur_node >= targetNodes->connection_strength.size())
+                            continue;
+
+                        if(targetNodes->connection_strength[precur_node])
+                        {
+                            precur_connection_strength = targetNodes->connection_strength[precur_node];
+                            break;
+                        }
+                  }
+
+                  if (targetNodes->connection_strength[index]
+                            && precur_connection_strength < m_vTConnection
+                            && p->GetSize() > 400) {
+                      //i.e. if we have a less than m_vTConnection connectivity to
+                      // our precursor... drop the packet.
+
+
+                      NS_LOG_ERROR("[Attack - PACKET_DROP_CONNECTION]: Dropped packet " << packetID
+                                                                                        << " where the next hop was "
+                                                                                        << toDst.GetNextHop()
+                                                                                        << " and the precursor was:"
+                                                                                        << precur_node
+                                                                                        << " with connection strength:"
+                                                                                        << precur_connection_strength);
+                      return false;
+                  }
+                  break;
+              }
+              case PACKET_DROP_NEIGHBOURS:{
+                  uint32_t neighbour_bad_con_count = 0;
+                  NS_LOG_ERROR("[Attack - PACKET_DROP_NEIGHBOUR] Selected");
+                  for (auto i: targetNodes->connection_strength)
+                  {
+                      if(i < 1.0) {
+                          neighbour_bad_con_count++;
+                      }
+                  }
+                  if (neighbour_bad_con_count >= m_vTNeighbour)
+                  {
+                      NS_LOG_ERROR("[Attack - PACKET_DROP_NEIGHBOUR] neighbour_bad_con_count is: " << neighbour_bad_con_count);
+                      return false;
+                  }
+                  else
+                      break;
+              }
+              case NO_A_OPERATION:{
+                  // Do Nothing
+                  NS_LOG_INFO("Strategy NO-OP selected");
+                  break;
+              }
+          }
+
+          if(p->GetSize() > 400)
+              NS_LOG_ERROR ("forwarding packet ID: " << packetID << " ttl: " << unsigned(header.GetTtl()) << " to " << dst
+                                                    << " from " << origin << " via " << toDst.GetNextHop());
+          ucb(route, p, header);
+          return true;
+        }
+      else
+        {
+          if (toDst.GetValidSeqNo ())
+            {
+              SendRerrWhenNoRouteToForward (dst, toDst.GetSeqNo (), origin);
+              NS_LOG_DEBUG ("Drop packet " << p->GetUid () << " because no route to forward it.");
+              NS_LOG_ERROR ("TTL is: " << unsigned(header.GetTtl()));
+              return false;
+            }
+        }
+    }
+  NS_LOG_LOGIC ("route not found to " << dst << ". Send RERR message.");
+  NS_LOG_DEBUG ("Drop packet " << p->GetUid () << " because no route to forward it.");
+  SendRerrWhenNoRouteToForward (dst, 0, origin);
+  return false;
+}
+
+void
+RoutingProtocol::SetIpv4 (Ptr<Ipv4> ipv4)
+{
+  NS_ASSERT (ipv4 != 0);
+  NS_ASSERT (m_ipv4 == 0);
+
+  m_ipv4 = ipv4;
+
+  // Create lo route. It is asserted that the only one interface up for now is loopback
+  NS_ASSERT (m_ipv4->GetNInterfaces () == 1 && m_ipv4->GetAddress (0, 0).GetLocal () == Ipv4Address ("127.0.0.1"));
+  m_lo = m_ipv4->GetNetDevice (0);
+  NS_ASSERT (m_lo != 0);
+  // Remember lo route
+  RoutingTableEntry rt (/*device=*/ m_lo, /*dst=*/ Ipv4Address::GetLoopback (), /*know seqno=*/ true, /*seqno=*/ 0,
+                                    /*iface=*/ Ipv4InterfaceAddress (Ipv4Address::GetLoopback (), Ipv4Mask ("255.0.0.0")),
+                                    /*hops=*/ 1, /*next hop=*/ Ipv4Address::GetLoopback (),
+                                    /*lifetime=*/ Simulator::GetMaximumSimulationTime ());
+  m_routingTable.AddRoute (rt);
+
+  Simulator::ScheduleNow (&RoutingProtocol::Start, this);
+}
+
+void
+RoutingProtocol::NotifyInterfaceUp (uint32_t i)
+{
+  NS_LOG_FUNCTION (this << m_ipv4->GetAddress (i, 0).GetLocal ());
+  Ptr<Ipv4L3Protocol> l3 = m_ipv4->GetObject<Ipv4L3Protocol> ();
+  if (l3->GetNAddresses (i) > 1)
+    {
+      NS_LOG_WARN ("greyattack does not work with more then one address per each interface.");
+    }
+  Ipv4InterfaceAddress iface = l3->GetAddress (i, 0);
+  if (iface.GetLocal () == Ipv4Address ("127.0.0.1"))
+    {
+      return;
+    }
+
+  // Create a socket to listen only on this interface
+  Ptr<Socket> socket = Socket::CreateSocket (GetObject<Node> (),
+                                             UdpSocketFactory::GetTypeId ());
+  NS_ASSERT (socket != 0);
+  socket->SetRecvCallback (MakeCallback (&RoutingProtocol::Recvgreyattack, this));
+  socket->BindToNetDevice (l3->GetNetDevice (i));
+  socket->Bind (InetSocketAddress (iface.GetLocal (), greyattack_PORT));
+  socket->SetAllowBroadcast (true);
+  socket->SetIpRecvTtl (true);
+  m_socketAddresses.insert (std::make_pair (socket, iface));
+
+  // create also a subnet broadcast socket
+  socket = Socket::CreateSocket (GetObject<Node> (),
+                                 UdpSocketFactory::GetTypeId ());
+  NS_ASSERT (socket != 0);
+  socket->SetRecvCallback (MakeCallback (&RoutingProtocol::Recvgreyattack, this));
+  socket->BindToNetDevice (l3->GetNetDevice (i));
+  socket->Bind (InetSocketAddress (iface.GetBroadcast (), greyattack_PORT));
+  socket->SetAllowBroadcast (true);
+  socket->SetIpRecvTtl (true);
+  m_socketSubnetBroadcastAddresses.insert (std::make_pair (socket, iface));
+
+  // Add local broadcast record to the routing table
+  Ptr<NetDevice> dev = m_ipv4->GetNetDevice (m_ipv4->GetInterfaceForAddress (iface.GetLocal ()));
+  RoutingTableEntry rt (/*device=*/ dev, /*dst=*/ iface.GetBroadcast (), /*know seqno=*/ true, /*seqno=*/ 0, /*iface=*/ iface,
+                                    /*hops=*/ 1, /*next hop=*/ iface.GetBroadcast (), /*lifetime=*/ Simulator::GetMaximumSimulationTime ());
+  m_routingTable.AddRoute (rt);
+
+  if (l3->GetInterface (i)->GetArpCache ())
+    {
+      m_nb.AddArpCache (l3->GetInterface (i)->GetArpCache ());
+    }
+
+  // Allow neighbor manager use this interface for layer 2 feedback if possible
+  Ptr<WifiNetDevice> wifi = dev->GetObject<WifiNetDevice> ();
+  if (wifi == 0)
+    {
+      return;
+    }
+  Ptr<WifiMac> mac = wifi->GetMac ();
+  if (mac == 0)
+    {
+      return;
+    }
+
+  mac->TraceConnectWithoutContext ("DroppedMpdu", MakeCallback (&RoutingProtocol::NotifyTxError, this));
+}
+
+void
+RoutingProtocol::NotifyTxError (WifiMacDropReason reason, Ptr<const WifiMacQueueItem> mpdu)
+{
+  m_nb.GetTxErrorCallback ()(mpdu->GetHeader ());
+}
+
+void
+RoutingProtocol::NotifyInterfaceDown (uint32_t i)
+{
+  NS_LOG_FUNCTION (this << m_ipv4->GetAddress (i, 0).GetLocal ());
+
+  // Disable layer 2 link state monitoring (if possible)
+  Ptr<Ipv4L3Protocol> l3 = m_ipv4->GetObject<Ipv4L3Protocol> ();
+  Ptr<NetDevice> dev = l3->GetNetDevice (i);
+  Ptr<WifiNetDevice> wifi = dev->GetObject<WifiNetDevice> ();
+  if (wifi != 0)
+    {
+      Ptr<WifiMac> mac = wifi->GetMac ()->GetObject<AdhocWifiMac> ();
+      if (mac != 0)
+        {
+          mac->TraceDisconnectWithoutContext ("DroppedMpdu",
+                                              MakeCallback (&RoutingProtocol::NotifyTxError, this));
+          m_nb.DelArpCache (l3->GetInterface (i)->GetArpCache ());
+        }
+    }
+
+  // Close socket
+  Ptr<Socket> socket = FindSocketWithInterfaceAddress (m_ipv4->GetAddress (i, 0));
+  NS_ASSERT (socket);
+  socket->Close ();
+  m_socketAddresses.erase (socket);
+
+  // Close socket
+  socket = FindSubnetBroadcastSocketWithInterfaceAddress (m_ipv4->GetAddress (i, 0));
+  NS_ASSERT (socket);
+  socket->Close ();
+  m_socketSubnetBroadcastAddresses.erase (socket);
+
+  if (m_socketAddresses.empty ())
+    {
+      NS_LOG_LOGIC ("No greyattack-aodv interfaces");
+      m_htimer.Cancel ();
+      m_nb.Clear ();
+      m_routingTable.Clear ();
+      return;
+    }
+  m_routingTable.DeleteAllRoutesFromInterface (m_ipv4->GetAddress (i, 0));
+}
+
+void
+RoutingProtocol::NotifyAddAddress (uint32_t i, Ipv4InterfaceAddress address)
+{
+  NS_LOG_FUNCTION (this << " interface " << i << " address " << address);
+  Ptr<Ipv4L3Protocol> l3 = m_ipv4->GetObject<Ipv4L3Protocol> ();
+  if (!l3->IsUp (i))
+    {
+      return;
+    }
+  if (l3->GetNAddresses (i) == 1)
+    {
+      Ipv4InterfaceAddress iface = l3->GetAddress (i, 0);
+      Ptr<Socket> socket = FindSocketWithInterfaceAddress (iface);
+      if (!socket)
+        {
+          if (iface.GetLocal () == Ipv4Address ("127.0.0.1"))
+            {
+              return;
+            }
+          // Create a socket to listen only on this interface
+          Ptr<Socket> socket = Socket::CreateSocket (GetObject<Node> (),
+                                                     UdpSocketFactory::GetTypeId ());
+          NS_ASSERT (socket != 0);
+          socket->SetRecvCallback (MakeCallback (&RoutingProtocol::Recvgreyattack,this));
+          socket->BindToNetDevice (l3->GetNetDevice (i));
+          socket->Bind (InetSocketAddress (iface.GetLocal (), greyattack_PORT));
+          socket->SetAllowBroadcast (true);
+          m_socketAddresses.insert (std::make_pair (socket, iface));
+
+          // create also a subnet directed broadcast socket
+          socket = Socket::CreateSocket (GetObject<Node> (),
+                                         UdpSocketFactory::GetTypeId ());
+          NS_ASSERT (socket != 0);
+          socket->SetRecvCallback (MakeCallback (&RoutingProtocol::Recvgreyattack, this));
+          socket->BindToNetDevice (l3->GetNetDevice (i));
+          socket->Bind (InetSocketAddress (iface.GetBroadcast (), greyattack_PORT));
+          socket->SetAllowBroadcast (true);
+          socket->SetIpRecvTtl (true);
+          m_socketSubnetBroadcastAddresses.insert (std::make_pair (socket, iface));
+
+          // Add local broadcast record to the routing table
+          Ptr<NetDevice> dev = m_ipv4->GetNetDevice (
+              m_ipv4->GetInterfaceForAddress (iface.GetLocal ()));
+          RoutingTableEntry rt (/*device=*/ dev, /*dst=*/ iface.GetBroadcast (), /*know seqno=*/ true,
+                                            /*seqno=*/ 0, /*iface=*/ iface, /*hops=*/ 1,
+                                            /*next hop=*/ iface.GetBroadcast (), /*lifetime=*/ Simulator::GetMaximumSimulationTime ());
+          m_routingTable.AddRoute (rt);
+        }
+    }
+  else
+    {
+      NS_LOG_LOGIC ("greyattack does not work with more then one address per each interface. Ignore added address");
+    }
+}
+
+void
+RoutingProtocol::NotifyRemoveAddress (uint32_t i, Ipv4InterfaceAddress address)
+{
+  NS_LOG_FUNCTION (this);
+  Ptr<Socket> socket = FindSocketWithInterfaceAddress (address);
+  if (socket)
+    {
+      m_routingTable.DeleteAllRoutesFromInterface (address);
+      socket->Close ();
+      m_socketAddresses.erase (socket);
+
+      Ptr<Socket> unicastSocket = FindSubnetBroadcastSocketWithInterfaceAddress (address);
+      if (unicastSocket)
+        {
+          unicastSocket->Close ();
+          m_socketAddresses.erase (unicastSocket);
+        }
+
+      Ptr<Ipv4L3Protocol> l3 = m_ipv4->GetObject<Ipv4L3Protocol> ();
+      if (l3->GetNAddresses (i))
+        {
+          Ipv4InterfaceAddress iface = l3->GetAddress (i, 0);
+          // Create a socket to listen only on this interface
+          Ptr<Socket> socket = Socket::CreateSocket (GetObject<Node> (),
+                                                     UdpSocketFactory::GetTypeId ());
+          NS_ASSERT (socket != 0);
+          socket->SetRecvCallback (MakeCallback (&RoutingProtocol::Recvgreyattack, this));
+          // Bind to any IP address so that broadcasts can be received
+          socket->BindToNetDevice (l3->GetNetDevice (i));
+          socket->Bind (InetSocketAddress (iface.GetLocal (), greyattack_PORT));
+          socket->SetAllowBroadcast (true);
+          socket->SetIpRecvTtl (true);
+          m_socketAddresses.insert (std::make_pair (socket, iface));
+
+          // create also a unicast socket
+          socket = Socket::CreateSocket (GetObject<Node> (),
+                                         UdpSocketFactory::GetTypeId ());
+          NS_ASSERT (socket != 0);
+          socket->SetRecvCallback (MakeCallback (&RoutingProtocol::Recvgreyattack, this));
+          socket->BindToNetDevice (l3->GetNetDevice (i));
+          socket->Bind (InetSocketAddress (iface.GetBroadcast (), greyattack_PORT));
+          socket->SetAllowBroadcast (true);
+          socket->SetIpRecvTtl (true);
+          m_socketSubnetBroadcastAddresses.insert (std::make_pair (socket, iface));
+
+          // Add local broadcast record to the routing table
+          Ptr<NetDevice> dev = m_ipv4->GetNetDevice (m_ipv4->GetInterfaceForAddress (iface.GetLocal ()));
+          RoutingTableEntry rt (/*device=*/ dev, /*dst=*/ iface.GetBroadcast (), /*know seqno=*/ true, /*seqno=*/ 0, /*iface=*/ iface,
+                                            /*hops=*/ 1, /*next hop=*/ iface.GetBroadcast (), /*lifetime=*/ Simulator::GetMaximumSimulationTime ());
+          m_routingTable.AddRoute (rt);
+        }
+      if (m_socketAddresses.empty ())
+        {
+          NS_LOG_LOGIC ("No greyattack-aodv interfaces");
+          m_htimer.Cancel ();
+          m_nb.Clear ();
+          m_routingTable.Clear ();
+          return;
+        }
+    }
+  else
+    {
+      NS_LOG_LOGIC ("Remove address not participating in greyattack operation");
+    }
+}
+
+bool
+RoutingProtocol::IsMyOwnAddress (Ipv4Address src)
+{
+  NS_LOG_FUNCTION (this << src);
+  for (std::map<Ptr<Socket>, Ipv4InterfaceAddress>::const_iterator j =
+         m_socketAddresses.begin (); j != m_socketAddresses.end (); ++j)
+    {
+      Ipv4InterfaceAddress iface = j->second;
+      if (src == iface.GetLocal ())
+        {
+          return true;
+        }
+    }
+  return false;
+}
+
+Ptr<Ipv4Route>
+RoutingProtocol::LoopbackRoute (const Ipv4Header & hdr, Ptr<NetDevice> oif) const
+{
+  NS_LOG_FUNCTION (this << hdr);
+  NS_ASSERT (m_lo != 0);
+  Ptr<Ipv4Route> rt = Create<Ipv4Route> ();
+  rt->SetDestination (hdr.GetDestination ());
+  //
+  // Source address selection here is tricky.  The loopback route is
+  // returned when greyattack does not have a route; this causes the packet
+  // to be looped back and handled (cached) in RouteInput() method
+  // while a route is found. However, connection-oriented protocols
+  // like TCP need to create an endpoint four-tuple (src, src port,
+  // dst, dst port) and create a pseudo-header for checksumming.  So,
+  // greyattack needs to guess correctly what the eventual source address
+  // will be.
+  //
+  // For single interface, single address nodes, this is not a problem.
+  // When there are possibly multiple outgoing interfaces, the policy
+  // implemented here is to pick the first available greyattack interface.
+  // If RouteOutput() caller specified an outgoing interface, that
+  // further constrains the selection of source address
+  //
+  std::map<Ptr<Socket>, Ipv4InterfaceAddress>::const_iterator j = m_socketAddresses.begin ();
+  if (oif)
+    {
+      // Iterate to find an address on the oif device
+      for (j = m_socketAddresses.begin (); j != m_socketAddresses.end (); ++j)
+        {
+          Ipv4Address addr = j->second.GetLocal ();
+          int32_t interface = m_ipv4->GetInterfaceForAddress (addr);
+          if (oif == m_ipv4->GetNetDevice (static_cast<uint32_t> (interface)))
+            {
+              rt->SetSource (addr);
+              break;
+            }
+        }
+    }
+  else
+    {
+      rt->SetSource (j->second.GetLocal ());
+    }
+  NS_ASSERT_MSG (rt->GetSource () != Ipv4Address (), "Valid greyattack-aodv source address not found");
+  rt->SetGateway (Ipv4Address ("127.0.0.1"));
+  rt->SetOutputDevice (m_lo);
+  return rt;
+}
+
+void
+RoutingProtocol::SendRequest (Ipv4Address dst)
+{
+  NS_LOG_FUNCTION ( this << dst);
+  // A node SHOULD NOT originate more than RREQ_RATELIMIT RREQ messages per second.
+  if (m_rreqCount == m_rreqRateLimit)
+    {
+      Simulator::Schedule (m_rreqRateLimitTimer.GetDelayLeft () + MicroSeconds (100),
+                           &RoutingProtocol::SendRequest, this, dst);
+      return;
+    }
+  else
+    {
+      m_rreqCount++;
+    }
+  // Create RREQ header
+  RreqHeader rreqHeader;
+  rreqHeader.SetDst (dst);
+
+    //set the AER in the header.
+  float currentAER = 0.0;
+  m_routingTable.GetAER(currentAER);
+  rreqHeader.m_AER = currentAER;
+  NS_LOG_ERROR("Sending a RREQ with AER Value: " << rreqHeader.m_AER);
+
+  RoutingTableEntry rt;
+  // Using the Hop field in Routing Table to manage the expanding ring search
+  uint16_t ttl = m_ttlStart;
+  if (m_routingTable.LookupRoute (dst, rt))
+    {
+      if (rt.GetFlag () != IN_SEARCH)
+        {
+          ttl = std::min<uint16_t> (rt.GetHop () + m_ttlIncrement, m_netDiameter);
+        }
+      else
+        {
+          ttl = rt.GetHop () + m_ttlIncrement;
+          if (ttl > m_ttlThreshold)
+            {
+              ttl = m_netDiameter;
+            }
+        }
+      if (ttl == m_netDiameter)
+        {
+          rt.IncrementRreqCnt ();
+
+        }
+      if (rt.GetValidSeqNo ())
+        {
+          rreqHeader.SetDstSeqno (rt.GetSeqNo ());
+        }
+      else
+        {
+          rreqHeader.SetUnknownSeqno (true);
+        }
+      rt.SetHop (ttl);
+      rt.SetFlag (IN_SEARCH);
+      rt.SetLifeTime (m_pathDiscoveryTime);
+      m_routingTable.Update (rt);
+    }
+  else
+    {
+      rreqHeader.SetUnknownSeqno (true);
+      Ptr<NetDevice> dev = 0;
+      RoutingTableEntry newEntry (/*device=*/ dev, /*dst=*/ dst, /*validSeqNo=*/ false, /*seqno=*/ 0,
+                                              /*iface=*/ Ipv4InterfaceAddress (),/*hop=*/ ttl,
+                                              /*nextHop=*/ Ipv4Address (), /*lifeTime=*/ m_pathDiscoveryTime);
+      // Check if TtlStart == NetDiameter
+      if (ttl == m_netDiameter)
+        {
+          newEntry.IncrementRreqCnt ();
+        }
+      newEntry.SetFlag (IN_SEARCH);
+      m_routingTable.AddRoute (newEntry);
+    }
+
+  if (m_gratuitousReply)
+    {
+      rreqHeader.SetGratuitousRrep (true);
+    }
+  if (m_destinationOnly)
+    {
+      rreqHeader.SetDestinationOnly (true);
+    }
+
+  m_seqNo++;
+  rreqHeader.SetOriginSeqno (m_seqNo);
+  m_requestId++;
+  rreqHeader.SetId (m_requestId);
+
+  //std::cout << "Sending...\n";
+  // Send RREQ as subnet directed broadcast from each interface used by greyattack
+  for (std::map<Ptr<Socket>, Ipv4InterfaceAddress>::const_iterator j =
+         m_socketAddresses.begin (); j != m_socketAddresses.end (); ++j)
+    {
+
+      
+      Ptr<Socket> socket = j->first;
+      Ipv4InterfaceAddress iface = j->second;
+
+      //std::cout << iface.GetLocal() << " --> " <<dst << "\n";
+      rreqHeader.SetOrigin (iface.GetLocal ());
+      m_rreqIdCache.IsDuplicate (iface.GetLocal (), m_requestId);
+
+      Ptr<Packet> packet = Create<Packet> ();
+      SocketIpTtlTag tag;
+      tag.SetTtl (ttl);
+      packet->AddPacketTag (tag);
+      packet->AddHeader (rreqHeader);
+      TypeHeader tHeader (greyattackTYPE_RREQ);
+      packet->AddHeader (tHeader);
+      // Send to all-hosts broadcast if on /32 addr, subnet-directed otherwise
+      Ipv4Address destination;
+      if (iface.GetMask () == Ipv4Mask::GetOnes ())
+        {
+          destination = Ipv4Address ("255.255.255.255");
+        }
+      else
+        {
+          destination = iface.GetBroadcast ();
+        }
+      NS_LOG_DEBUG ("Send RREQ with id " << rreqHeader.GetId () << " to socket");
+      m_lastBcastTime = Simulator::Now ();
+      Simulator::Schedule (Time (MilliSeconds (m_uniformRandomVariable->GetInteger (0, 10))), &RoutingProtocol::SendTo, this, socket, packet, destination);
+    }
+  ScheduleRreqRetry (dst);
+}
+
+void
+RoutingProtocol::SendTo (Ptr<Socket> socket, Ptr<Packet> packet, Ipv4Address destination)
+{
+  socket->SendTo (packet, 0, InetSocketAddress (destination, greyattack_PORT));
+
+}
+void
+RoutingProtocol::ScheduleRreqRetry (Ipv4Address dst)
+{
+  NS_LOG_FUNCTION (this << dst);
+  if (m_addressReqTimer.find (dst) == m_addressReqTimer.end ())
+    {
+      Timer timer (Timer::CANCEL_ON_DESTROY);
+      m_addressReqTimer[dst] = timer;
+    }
+  m_addressReqTimer[dst].SetFunction (&RoutingProtocol::RouteRequestTimerExpire, this);
+  m_addressReqTimer[dst].Cancel ();
+  m_addressReqTimer[dst].SetArguments (dst);
+  RoutingTableEntry rt;
+  m_routingTable.LookupRoute (dst, rt);
+  Time retry;
+  if (rt.GetHop () < m_netDiameter)
+    {
+      retry = 2 * m_nodeTraversalTime * (rt.GetHop () + m_timeoutBuffer);
+    }
+  else
+    {
+      NS_ABORT_MSG_UNLESS (rt.GetRreqCnt () > 0, "Unexpected value for GetRreqCount ()");
+      uint16_t backoffFactor = rt.GetRreqCnt () - 1;
+      NS_LOG_LOGIC ("Applying binary exponential backoff factor " << backoffFactor);
+      retry = m_netTraversalTime * (1 << backoffFactor);
+    }
+  m_addressReqTimer[dst].Schedule (retry);
+  NS_LOG_LOGIC ("Scheduled RREQ retry in " << retry.As (Time::S));
+}
+
+void
+RoutingProtocol::Recvgreyattack (Ptr<Socket> socket)
+{
+  NS_LOG_FUNCTION (this << socket);
+  Address sourceAddress;
+  Ptr<Packet> packet = socket->RecvFrom (sourceAddress);
+  InetSocketAddress inetSourceAddr = InetSocketAddress::ConvertFrom (sourceAddress);
+  Ipv4Address sender = inetSourceAddr.GetIpv4 ();
+  Ipv4Address receiver;
+
+  if (m_socketAddresses.find (socket) != m_socketAddresses.end ())
+    {
+      receiver = m_socketAddresses[socket].GetLocal ();
+    }
+  else if (m_socketSubnetBroadcastAddresses.find (socket) != m_socketSubnetBroadcastAddresses.end ())
+    {
+      receiver = m_socketSubnetBroadcastAddresses[socket].GetLocal ();
+    }
+  else
+    {
+      NS_ASSERT_MSG (false, "Received a packet from an unknown socket");
+    }
+  NS_LOG_DEBUG ("greyattack node " << this << " received a greyattack packet from " << sender << " to " << receiver);
+
+  UpdateRouteToNeighbor (sender, receiver);
+  TypeHeader tHeader (greyattackTYPE_RREQ);
+  packet->RemoveHeader (tHeader);
+  if (!tHeader.IsValid ())
+    {
+      NS_LOG_DEBUG ("greyattack message " << packet->GetUid () << " with unknown type received: " << tHeader.Get () << ". Drop");
+      return; // drop
+    }
+  switch (tHeader.Get ())
+    {
+    case greyattackTYPE_RREQ:
+      {
+        RecvRequest (packet, receiver, sender);
+        break;
+      }
+    case greyattackTYPE_RREP:
+      {
+        RecvReply (packet, receiver, sender);
+        break;
+      }
+    case greyattackTYPE_RERR:
+      {
+        RecvError (packet, sender);
+        break;
+      }
+    case greyattackTYPE_RREP_ACK:
+      {
+        RecvReplyAck (sender);
+        break;
+      }
+    }
+}
+
+bool
+RoutingProtocol::UpdateRouteLifeTime (Ipv4Address addr, Time lifetime)
+{
+  NS_LOG_FUNCTION (this << addr << lifetime);
+  RoutingTableEntry rt;
+  if (m_routingTable.LookupRoute (addr, rt))
+    {
+      if (rt.GetFlag () == VALID)
+        {
+          NS_LOG_DEBUG ("Updating VALID route");
+          rt.SetRreqCnt (0);
+          rt.SetLifeTime (std::max (lifetime, rt.GetLifeTime ()));
+          m_routingTable.Update (rt);
+          return true;
+        }
+    }
+  return false;
+}
+
+void
+RoutingProtocol::UpdateRouteToNeighbor (Ipv4Address sender, Ipv4Address receiver)
+{
+  NS_LOG_FUNCTION (this << "sender " << sender << " receiver " << receiver);
+  RoutingTableEntry toNeighbor;
+  if (!m_routingTable.LookupRoute (sender, toNeighbor))
+    {
+      Ptr<NetDevice> dev = m_ipv4->GetNetDevice (m_ipv4->GetInterfaceForAddress (receiver));
+      RoutingTableEntry newEntry (/*device=*/ dev, /*dst=*/ sender, /*know seqno=*/ false, /*seqno=*/ 0,
+                                              /*iface=*/ m_ipv4->GetAddress (m_ipv4->GetInterfaceForAddress (receiver), 0),
+                                              /*hops=*/ 1, /*next hop=*/ sender, /*lifetime=*/ m_activeRouteTimeout);
+      m_routingTable.AddRoute (newEntry);
+    }
+  else
+    {
+      Ptr<NetDevice> dev = m_ipv4->GetNetDevice (m_ipv4->GetInterfaceForAddress (receiver));
+      if (toNeighbor.GetValidSeqNo () && (toNeighbor.GetHop () == 1) && (toNeighbor.GetOutputDevice () == dev))
+        {
+          toNeighbor.SetLifeTime (std::max (m_activeRouteTimeout, toNeighbor.GetLifeTime ()));
+          
+        }
+      else
+        {
+          RoutingTableEntry newEntry (/*device=*/ dev, /*dst=*/ sender, /*know seqno=*/ false, /*seqno=*/ 0,
+                                                  /*iface=*/ m_ipv4->GetAddress (m_ipv4->GetInterfaceForAddress (receiver), 0),
+                                                  /*hops=*/ 1, /*next hop=*/ sender, /*lifetime=*/ std::max (m_activeRouteTimeout, toNeighbor.GetLifeTime ())
+                                                  );
+          m_routingTable.Update (newEntry);
+
+        }
+    }
+
+}
+
+void
+RoutingProtocol::RecvRequest (Ptr<Packet> p, Ipv4Address receiver, Ipv4Address src)
+{
+  NS_LOG_FUNCTION (this);
+  RreqHeader rreqHeader;
+  p->RemoveHeader (rreqHeader);
+
+  // store the AER information here.
+    NS_LOG_ERROR("RREQ recv which has AER value: " << rreqHeader.m_AER);
+
+  // A node ignores all RREQs received from any node in its blacklist
+  RoutingTableEntry toPrev;
+  if (m_routingTable.LookupRoute (src, toPrev))
+    {
+      if (toPrev.IsUnidirectional ())
+        {
+          NS_LOG_DEBUG ("Ignoring RREQ from node in blacklist");
+          return;
+        }
+    }
+
+  uint32_t id = rreqHeader.GetId ();
+  Ipv4Address origin = rreqHeader.GetOrigin ();
+  
+  
+  
+  /*
+   *  Node checks to determine whether it has received a RREQ with the same Originator IP Address and RREQ ID.
+   *  If such a RREQ has been received, the node silently discards the newly received RREQ.
+   */
+  if (m_rreqIdCache.IsDuplicate (origin, id))
+    {
+      NS_LOG_DEBUG ("Ignoring RREQ due to duplicate");
+      return;
+    }
+
+  // Increment RREQ hop count
+  uint8_t hop = rreqHeader.GetHopCount () + 1;
+  rreqHeader.SetHopCount (hop);
+  
+  
+
+  /*
+   *  When the reverse route is created or updated, the following actions on the route are also carried out:
+   *  1. the Originator Sequence Number from the RREQ is compared to the corresponding destination sequence number
+   *     in the route table entry and copied if greater than the existing value there
+   *  2. the valid sequence number field is set to true;
+   *  3. the next hop in the routing table becomes the node from which the  RREQ was received
+   *  4. the hop count is copied from the Hop Count in the RREQ message;
+   *  5. the Lifetime is set to be the maximum of (ExistingLifetime, MinimalLifetime), where
+   *     MinimalLifetime = current time + 2*NetTraversalTime - 2*HopCount*NodeTraversalTime
+   */
+  RoutingTableEntry toOrigin;
+  if (!m_routingTable.LookupRoute (origin, toOrigin))
+    {
+      Ptr<NetDevice> dev = m_ipv4->GetNetDevice (m_ipv4->GetInterfaceForAddress (receiver));
+      RoutingTableEntry newEntry (/*device=*/ dev, /*dst=*/ origin, /*validSeno=*/ true, /*seqNo=*/ rreqHeader.GetOriginSeqno (),
+                                              /*iface=*/ m_ipv4->GetAddress (m_ipv4->GetInterfaceForAddress (receiver), 0), /*hops=*/ hop,
+                                              /*nextHop*/ src, /*timeLife=*/ Time ((2 * m_netTraversalTime - 2 * hop * m_nodeTraversalTime)));
+      m_routingTable.AddRoute (newEntry);
+    }
+  else
+    {
+      if (toOrigin.GetValidSeqNo ())
+        {
+          if (int32_t (rreqHeader.GetOriginSeqno ()) - int32_t (toOrigin.GetSeqNo ()) > 0)
+            {
+              toOrigin.SetSeqNo (rreqHeader.GetOriginSeqno ());
+            }
+        }
+      else
+        {
+          toOrigin.SetSeqNo (rreqHeader.GetOriginSeqno ());
+        }
+      toOrigin.SetValidSeqNo (true);
+      toOrigin.SetNextHop (src);
+      toOrigin.SetOutputDevice (m_ipv4->GetNetDevice (m_ipv4->GetInterfaceForAddress (receiver)));
+      toOrigin.SetInterface (m_ipv4->GetAddress (m_ipv4->GetInterfaceForAddress (receiver), 0));
+      toOrigin.SetHop (hop);
+      toOrigin.SetLifeTime (std::max (Time (2 * m_netTraversalTime - 2 * hop * m_nodeTraversalTime),
+                                      toOrigin.GetLifeTime ()));
+      m_routingTable.Update (toOrigin);
+      //m_nb.Update (src, Time (AllowedHelloLoss * HelloInterval));
+    }
+
+
+  RoutingTableEntry toNeighbor;
+  if (!m_routingTable.LookupRoute (src, toNeighbor))
+    {
+      NS_LOG_DEBUG ("Neighbor:" << src << " not found in routing table. Creating an entry");
+      Ptr<NetDevice> dev = m_ipv4->GetNetDevice (m_ipv4->GetInterfaceForAddress (receiver));
+      RoutingTableEntry newEntry (dev, src, false, rreqHeader.GetOriginSeqno (),
+                                  m_ipv4->GetAddress (m_ipv4->GetInterfaceForAddress (receiver), 0),
+                                  1, src, m_activeRouteTimeout);
+      m_routingTable.AddRoute (newEntry);
+    }
+  else
+    {
+      toNeighbor.SetLifeTime (m_activeRouteTimeout);
+      toNeighbor.SetValidSeqNo (false);
+      toNeighbor.SetSeqNo (rreqHeader.GetOriginSeqno ());
+      toNeighbor.SetFlag (VALID);
+      toNeighbor.SetOutputDevice (m_ipv4->GetNetDevice (m_ipv4->GetInterfaceForAddress (receiver)));
+      toNeighbor.SetInterface (m_ipv4->GetAddress (m_ipv4->GetInterfaceForAddress (receiver), 0));
+      toNeighbor.SetHop (1);
+      toNeighbor.SetNextHop (src);
+      m_routingTable.Update (toNeighbor);
+    }
+  m_nb.Update (src, Time (m_allowedHelloLoss * m_helloInterval));
+
+  NS_LOG_LOGIC (receiver << " receive RREQ with hop count " << static_cast<uint32_t> (rreqHeader.GetHopCount ())
+                         << " ID " << rreqHeader.GetId ()
+                         << " to destination " << rreqHeader.GetDst ());
+
+  //  A node generates a RREP if either:
+  //  (i)  it is itself the destination,
+  if (IsMyOwnAddress (rreqHeader.GetDst ()))
+    {
+      m_routingTable.LookupRoute (origin, toOrigin);
+      NS_LOG_DEBUG ("Send reply since I am the destination");
+      SendReply (rreqHeader, toOrigin);
+      return;
+    }
+  /*
+   * (ii) or it has an active route to the destination, the destination sequence number in the node's existing route table entry for the destination
+   *      is valid and greater than or equal to the Destination Sequence Number of the RREQ, and the "destination only" flag is NOT set.
+   */
+  RoutingTableEntry toDst;
+  Ipv4Address dst = rreqHeader.GetDst ();
+  if (m_routingTable.LookupRoute (dst, toDst))
+    {
+      /*
+       * Drop RREQ, This node RREP will make a loop.
+       */
+      if (toDst.GetNextHop () == src)
+        {
+          NS_LOG_DEBUG ("Drop RREQ from " << src << ", dest next hop " << toDst.GetNextHop ());
+          return;
+        }
+      /*
+       * The Destination Sequence number for the requested destination is set to the maximum of the corresponding value
+       * received in the RREQ message, and the destination sequence value currently maintained by the node for the requested destination.
+       * However, the forwarding node MUST NOT modify its maintained value for the destination sequence number, even if the value
+       * received in the incoming RREQ is larger than the value currently maintained by the forwarding node.
+       */
+      if ((rreqHeader.GetUnknownSeqno () || (int32_t (toDst.GetSeqNo ()) - int32_t (rreqHeader.GetDstSeqno ()) >= 0))
+          && toDst.GetValidSeqNo () )
+        {
+          if (!rreqHeader.GetDestinationOnly () && toDst.GetFlag () == VALID)
+            {
+              m_routingTable.LookupRoute (origin, toOrigin);
+              SendReplyByIntermediateNode (toDst, toOrigin, rreqHeader.GetGratuitousRrep ());
+              return;
+            }
+          rreqHeader.SetDstSeqno (toDst.GetSeqNo ());
+          rreqHeader.SetUnknownSeqno (false);
+        }
+    }
+
+  SocketIpTtlTag tag;
+  p->RemovePacketTag (tag);
+  if (tag.GetTtl () < 2)
+    {
+      NS_LOG_DEBUG ("TTL exceeded. Drop RREQ origin " << src << " destination " << dst );
+      return;
+    }
+
+  for (std::map<Ptr<Socket>, Ipv4InterfaceAddress>::const_iterator j =
+         m_socketAddresses.begin (); j != m_socketAddresses.end (); ++j)
+    {
+      Ptr<Socket> socket = j->first;
+      Ipv4InterfaceAddress iface = j->second;
+      Ptr<Packet> packet = Create<Packet> ();
+      SocketIpTtlTag ttl;
+
+        // looks like this is where we forward the RREQ on to other destinations.
+        // lets modify the value so it represents our AER.
+        float currentAER = 0.0;
+        float oldAER = rreqHeader.m_AER;
+        m_routingTable.GetAER(currentAER);
+        rreqHeader.m_AER = currentAER;
+        NS_LOG_ERROR("Forwarding(?) a RREQ with AER Value: " << rreqHeader.m_AER
+                                                             << " Old Value: " << oldAER);
+
+      ttl.SetTtl (tag.GetTtl () - 1);
+      packet->AddPacketTag (ttl);
+      packet->AddHeader (rreqHeader);
+      TypeHeader tHeader (greyattackTYPE_RREQ);
+      packet->AddHeader (tHeader);
+      // Send to all-hosts broadcast if on /32 addr, subnet-directed otherwise
+      Ipv4Address destination;
+      if (iface.GetMask () == Ipv4Mask::GetOnes ())
+        {
+          destination = Ipv4Address ("255.255.255.255");
+        }
+      else
+        {
+          destination = iface.GetBroadcast ();
+        }
+      m_lastBcastTime = Simulator::Now ();
+      Simulator::Schedule (Time (MilliSeconds (m_uniformRandomVariable->GetInteger (0, 10))), &RoutingProtocol::SendTo, this, socket, packet, destination);
+
+    }
+}
+
+void
+RoutingProtocol::SendReply (RreqHeader const & rreqHeader, RoutingTableEntry const & toOrigin)
+{
+  NS_LOG_FUNCTION (this << toOrigin.GetDestination ());
+  /*
+   * Destination node MUST increment its own sequence number by one if the sequence number in the RREQ packet is equal to that
+   * incremented value. Otherwise, the destination does not change its sequence number before generating the  RREP message.
+   */
+  if (!rreqHeader.GetUnknownSeqno () && (rreqHeader.GetDstSeqno () == m_seqNo + 1))
+    {
+      m_seqNo++;
+    }
+  RrepHeader rrepHeader ( /*prefixSize=*/ 0, /*hops=*/ 0, /*dst=*/ rreqHeader.GetDst (),
+                                          /*dstSeqNo=*/ m_seqNo, /*origin=*/ toOrigin.GetDestination (), /*lifeTime=*/ m_myRouteTimeout);
+  Ptr<Packet> packet = Create<Packet> ();
+  SocketIpTtlTag tag;
+  tag.SetTtl (toOrigin.GetHop ());
+  packet->AddPacketTag (tag);
+  packet->AddHeader (rrepHeader);
+  TypeHeader tHeader (greyattackTYPE_RREP);
+  packet->AddHeader (tHeader);
+  Ptr<Socket> socket = FindSocketWithInterfaceAddress (toOrigin.GetInterface ());
+  NS_ASSERT (socket);
+  socket->SendTo (packet, 0, InetSocketAddress (toOrigin.GetNextHop (), greyattack_PORT));
+}
+
+void
+RoutingProtocol::SendReplyByIntermediateNode (RoutingTableEntry & toDst, RoutingTableEntry & toOrigin, bool gratRep)
+{
+  NS_LOG_FUNCTION (this);
+
+  
+
+  
+  RrepHeader rrepHeader (/*prefix size=*/ 0, /*hops=*/ toDst.GetHop (), /*dst=*/ toDst.GetDestination (), /*dst seqno=*/ toDst.GetSeqNo (),
+                                          /*origin=*/ toOrigin.GetDestination (), /*lifetime=*/ toDst.GetLifeTime ());
+  /* If the node we received a RREQ for is a neighbor we are
+   * probably facing a unidirectional link... Better request a RREP-ack
+   */
+  if (toDst.GetHop () == 1)
+    {
+      rrepHeader.SetAckRequired (true);
+      RoutingTableEntry toNextHop;
+      m_routingTable.LookupRoute (toOrigin.GetNextHop (), toNextHop);
+      toNextHop.m_ackTimer.SetFunction (&RoutingProtocol::AckTimerExpire, this);
+      toNextHop.m_ackTimer.SetArguments (toNextHop.GetDestination (), m_blackListTimeout);
+      toNextHop.m_ackTimer.SetDelay (m_nextHopWait);
+    }
+  toDst.InsertPrecursor (toOrigin.GetNextHop ());
+  toOrigin.InsertPrecursor (toDst.GetNextHop ());
+  m_routingTable.Update (toDst);
+  m_routingTable.Update (toOrigin);
+
+  Ptr<Packet> packet = Create<Packet> ();
+  SocketIpTtlTag tag;
+  tag.SetTtl (toOrigin.GetHop ());
+  packet->AddPacketTag (tag);
+  packet->AddHeader (rrepHeader);
+  TypeHeader tHeader (greyattackTYPE_RREP);
+  packet->AddHeader (tHeader);
+  Ptr<Socket> socket = FindSocketWithInterfaceAddress (toOrigin.GetInterface ());
+  NS_ASSERT (socket);
+  socket->SendTo (packet, 0, InetSocketAddress (toOrigin.GetNextHop (), greyattack_PORT));
+
+  // Generating gratuitous RREPs
+  if (gratRep)
+    {
+      RrepHeader gratRepHeader (/*prefix size=*/ 0, /*hops=*/ toOrigin.GetHop (), /*dst=*/ toOrigin.GetDestination (),
+                                                 /*dst seqno=*/ toOrigin.GetSeqNo (), /*origin=*/ toDst.GetDestination (),
+                                                 /*lifetime=*/ toOrigin.GetLifeTime ());
+      Ptr<Packet> packetToDst = Create<Packet> ();
+      SocketIpTtlTag gratTag;
+      gratTag.SetTtl (toDst.GetHop ());
+      packetToDst->AddPacketTag (gratTag);
+      packetToDst->AddHeader (gratRepHeader);
+      TypeHeader type (greyattackTYPE_RREP);
+      packetToDst->AddHeader (type);
+      Ptr<Socket> socket = FindSocketWithInterfaceAddress (toDst.GetInterface ());
+      NS_ASSERT (socket);
+      NS_LOG_LOGIC ("Send gratuitous RREP " << packet->GetUid ());
+      socket->SendTo (packetToDst, 0, InetSocketAddress (toDst.GetNextHop (), greyattack_PORT));
+    }
+}
+
+void
+RoutingProtocol::SendReplyAck (Ipv4Address neighbor)
+{
+  NS_LOG_FUNCTION (this << " to " << neighbor);
+  RrepAckHeader h;
+  TypeHeader typeHeader (greyattackTYPE_RREP_ACK);
+  Ptr<Packet> packet = Create<Packet> ();
+  SocketIpTtlTag tag;
+  tag.SetTtl (1);
+  packet->AddPacketTag (tag);
+  packet->AddHeader (h);
+  packet->AddHeader (typeHeader);
+  RoutingTableEntry toNeighbor;
+  m_routingTable.LookupRoute (neighbor, toNeighbor);
+  Ptr<Socket> socket = FindSocketWithInterfaceAddress (toNeighbor.GetInterface ());
+  NS_ASSERT (socket);
+  socket->SendTo (packet, 0, InetSocketAddress (neighbor, greyattack_PORT));
+}
+
+void
+RoutingProtocol::RecvReply (Ptr<Packet> p, Ipv4Address receiver, Ipv4Address sender)
+{
+  NS_LOG_FUNCTION (this << " src " << sender);
+  RrepHeader rrepHeader;
+  p->RemoveHeader (rrepHeader);
+  Ipv4Address dst = rrepHeader.GetDst ();
+  NS_LOG_LOGIC ("RREP destination " << dst << " RREP origin " << rrepHeader.GetOrigin ());
+
+  uint8_t hop = rrepHeader.GetHopCount () + 1;
+  rrepHeader.SetHopCount (hop);
+
+  // If RREP is Hello message
+  if (dst == rrepHeader.GetOrigin ())
+    {
+      ProcessHello (rrepHeader, receiver);
+      return;
+    }
+
+  /*
+   * If the route table entry to the destination is created or updated, then the following actions occur:
+   * -  the route is marked as active,
+   * -  the destination sequence number is marked as valid,
+   * -  the next hop in the route entry is assigned to be the node from which the RREP is received,
+   *    which is indicated by the source IP address field in the IP header,
+   * -  the hop count is set to the value of the hop count from RREP message + 1
+   * -  the expiry time is set to the current time plus the value of the Lifetime in the RREP message,
+   * -  and the destination sequence number is the Destination Sequence Number in the RREP message.
+   */
+  Ptr<NetDevice> dev = m_ipv4->GetNetDevice (m_ipv4->GetInterfaceForAddress (receiver));
+  RoutingTableEntry newEntry (/*device=*/ dev, /*dst=*/ dst, /*validSeqNo=*/ true, /*seqno=*/ rrepHeader.GetDstSeqno (),
+                                          /*iface=*/ m_ipv4->GetAddress (m_ipv4->GetInterfaceForAddress (receiver), 0),/*hop=*/ hop,
+                                          /*nextHop=*/ sender, /*lifeTime=*/ rrepHeader.GetLifeTime ());
+  RoutingTableEntry toDst;
+  if (m_routingTable.LookupRoute (dst, toDst))
+    {
+      /*
+       * The existing entry is updated only in the following circumstances:
+       * (i) the sequence number in the routing table is marked as invalid in route table entry.
+       */
+      if (!toDst.GetValidSeqNo ())
+        {
+          m_routingTable.Update (newEntry);
+        }
+      // (ii)the Destination Sequence Number in the RREP is greater than the node's copy of the destination sequence number and the known value is valid,
+      else if ((int32_t (rrepHeader.GetDstSeqno ()) - int32_t (toDst.GetSeqNo ())) > 0)
+        {
+          m_routingTable.Update (newEntry);
+        }
+      else
+        {
+          // (iii) the sequence numbers are the same, but the route is marked as inactive.
+          if ((rrepHeader.GetDstSeqno () == toDst.GetSeqNo ()) && (toDst.GetFlag () != VALID))
+            {
+              m_routingTable.Update (newEntry);
+            }
+          // (iv)  the sequence numbers are the same, and the New Hop Count is smaller than the hop count in route table entry.
+          else if ((rrepHeader.GetDstSeqno () == toDst.GetSeqNo ()) && (hop < toDst.GetHop ()))
+            {
+              m_routingTable.Update (newEntry);
+            }
+        }
+    }
+  else
+    {
+      // The forward route for this destination is created if it does not already exist.
+      NS_LOG_LOGIC ("add new route");
+      m_routingTable.AddRoute (newEntry);
+    }
+  // Acknowledge receipt of the RREP by sending a RREP-ACK message back
+  if (rrepHeader.GetAckRequired ())
+    {
+      SendReplyAck (sender);
+      rrepHeader.SetAckRequired (false);
+    }
+  NS_LOG_LOGIC ("receiver " << receiver << " origin " << rrepHeader.GetOrigin ());
+  if (IsMyOwnAddress (rrepHeader.GetOrigin ()))
+    {
+      if (toDst.GetFlag () == IN_SEARCH)
+        {
+          m_routingTable.Update (newEntry);
+          m_addressReqTimer[dst].Cancel ();
+          m_addressReqTimer.erase (dst);
+        }
+      m_routingTable.LookupRoute (dst, toDst);
+      SendPacketFromQueue (dst, toDst.GetRoute ());
+      return;
+    }
+
+  RoutingTableEntry toOrigin;
+  if (!m_routingTable.LookupRoute (rrepHeader.GetOrigin (), toOrigin) || toOrigin.GetFlag () == IN_SEARCH)
+    {
+      return; // Impossible! drop.
+    }
+  toOrigin.SetLifeTime (std::max (m_activeRouteTimeout, toOrigin.GetLifeTime ()));
+  m_routingTable.Update (toOrigin);
+
+  // Update information about precursors
+  if (m_routingTable.LookupValidRoute (rrepHeader.GetDst (), toDst))
+    {
+      toDst.InsertPrecursor (toOrigin.GetNextHop ());
+      m_routingTable.Update (toDst);
+
+      RoutingTableEntry toNextHopToDst;
+      m_routingTable.LookupRoute (toDst.GetNextHop (), toNextHopToDst);
+      toNextHopToDst.InsertPrecursor (toOrigin.GetNextHop ());
+      m_routingTable.Update (toNextHopToDst);
+
+      toOrigin.InsertPrecursor (toDst.GetNextHop ());
+      m_routingTable.Update (toOrigin);
+
+      RoutingTableEntry toNextHopToOrigin;
+      m_routingTable.LookupRoute (toOrigin.GetNextHop (), toNextHopToOrigin);
+      toNextHopToOrigin.InsertPrecursor (toDst.GetNextHop ());
+      m_routingTable.Update (toNextHopToOrigin);
+    }
+  SocketIpTtlTag tag;
+  p->RemovePacketTag (tag);
+  if (tag.GetTtl () < 2)
+    {
+      NS_LOG_DEBUG ("TTL exceeded. Drop RREP destination " << dst << " origin " << rrepHeader.GetOrigin ());
+      return;
+    }
+
+  
+  Ptr<Packet> packet = Create<Packet> ();
+  SocketIpTtlTag ttl;
+  ttl.SetTtl (tag.GetTtl () - 1);
+  packet->AddPacketTag (ttl);
+  packet->AddHeader (rrepHeader);
+  TypeHeader tHeader (greyattackTYPE_RREP);
+  packet->AddHeader (tHeader);
+  Ptr<Socket> socket = FindSocketWithInterfaceAddress (toOrigin.GetInterface ());
+  NS_ASSERT (socket);
+  socket->SendTo (packet, 0, InetSocketAddress (toOrigin.GetNextHop (), greyattack_PORT));
+}
+
+void
+RoutingProtocol::RecvReplyAck (Ipv4Address neighbor)
+{
+  NS_LOG_FUNCTION (this);
+  RoutingTableEntry rt;
+  if (m_routingTable.LookupRoute (neighbor, rt))
+    {
+      rt.m_ackTimer.Cancel ();
+      rt.SetFlag (VALID);
+      m_routingTable.Update (rt);
+    }
+}
+
+void
+RoutingProtocol::ProcessHello (RrepHeader const & rrepHeader, Ipv4Address receiver )
+{
+  NS_LOG_FUNCTION (this << "from " << rrepHeader.GetDst ());
+  /*
+   *  Whenever a node receives a Hello message from a neighbor, the node
+   * SHOULD make sure that it has an active route to the neighbor, and
+   * create one if necessary.
+   */
+  RoutingTableEntry toNeighbor;
+  if (!m_routingTable.LookupRoute (rrepHeader.GetDst (), toNeighbor))
+    {
+      Ptr<NetDevice> dev = m_ipv4->GetNetDevice (m_ipv4->GetInterfaceForAddress (receiver));
+      RoutingTableEntry newEntry (/*device=*/ dev, /*dst=*/ rrepHeader.GetDst (), /*validSeqNo=*/ true, /*seqno=*/ rrepHeader.GetDstSeqno (),
+                                              /*iface=*/ m_ipv4->GetAddress (m_ipv4->GetInterfaceForAddress (receiver), 0),
+                                              /*hop=*/ 1, /*nextHop=*/ rrepHeader.GetDst (), /*lifeTime=*/ rrepHeader.GetLifeTime ());
+      m_routingTable.AddRoute (newEntry);
+    }
+  else
+    {
+      toNeighbor.SetLifeTime (std::max (Time (m_allowedHelloLoss * m_helloInterval), toNeighbor.GetLifeTime ()));
+      toNeighbor.SetSeqNo (rrepHeader.GetDstSeqno ());
+      toNeighbor.SetValidSeqNo (true);
+      toNeighbor.SetFlag (VALID);
+      toNeighbor.SetOutputDevice (m_ipv4->GetNetDevice (m_ipv4->GetInterfaceForAddress (receiver)));
+      toNeighbor.SetInterface (m_ipv4->GetAddress (m_ipv4->GetInterfaceForAddress (receiver), 0));
+      toNeighbor.SetHop (1);
+      toNeighbor.SetNextHop (rrepHeader.GetDst ());
+      m_routingTable.Update (toNeighbor);
+    }
+  if (m_enableHello)
+    {
+      m_nb.Update (rrepHeader.GetDst (), Time (m_allowedHelloLoss * m_helloInterval));
+    }
+}
+
+void
+RoutingProtocol::RecvError (Ptr<Packet> p, Ipv4Address src )
+{
+  NS_LOG_FUNCTION (this << " from " << src);
+  RerrHeader rerrHeader;
+  p->RemoveHeader (rerrHeader);
+  std::map<Ipv4Address, uint32_t> dstWithNextHopSrc;
+  std::map<Ipv4Address, uint32_t> unreachable;
+  m_routingTable.GetListOfDestinationWithNextHop (src, dstWithNextHopSrc);
+  std::pair<Ipv4Address, uint32_t> un;
+  while (rerrHeader.RemoveUnDestination (un))
+    {
+      for (std::map<Ipv4Address, uint32_t>::const_iterator i =
+             dstWithNextHopSrc.begin (); i != dstWithNextHopSrc.end (); ++i)
+        {
+          if (i->first == un.first)
+            {
+              unreachable.insert (un);
+            }
+        }
+    }
+
+  std::vector<Ipv4Address> precursors;
+  for (std::map<Ipv4Address, uint32_t>::const_iterator i = unreachable.begin ();
+       i != unreachable.end (); )
+    {
+      if (!rerrHeader.AddUnDestination (i->first, i->second))
+        {
+          TypeHeader typeHeader (greyattackTYPE_RERR);
+          Ptr<Packet> packet = Create<Packet> ();
+          SocketIpTtlTag tag;
+          tag.SetTtl (1);
+          packet->AddPacketTag (tag);
+          packet->AddHeader (rerrHeader);
+          packet->AddHeader (typeHeader);
+          SendRerrMessage (packet, precursors);
+          rerrHeader.Clear ();
+        }
+      else
+        {
+          RoutingTableEntry toDst;
+          m_routingTable.LookupRoute (i->first, toDst);
+          toDst.GetPrecursors (precursors);
+          ++i;
+        }
+    }
+  if (rerrHeader.GetDestCount () != 0)
+    {
+      TypeHeader typeHeader (greyattackTYPE_RERR);
+      Ptr<Packet> packet = Create<Packet> ();
+      SocketIpTtlTag tag;
+      tag.SetTtl (1);
+      packet->AddPacketTag (tag);
+      packet->AddHeader (rerrHeader);
+      packet->AddHeader (typeHeader);
+      SendRerrMessage (packet, precursors);
+    }
+  m_routingTable.InvalidateRoutesWithDst (unreachable);
+}
+
+void
+RoutingProtocol::RouteRequestTimerExpire (Ipv4Address dst)
+{
+  NS_LOG_LOGIC (this);
+  RoutingTableEntry toDst;
+  if (m_routingTable.LookupValidRoute (dst, toDst))
+    {
+      SendPacketFromQueue (dst, toDst.GetRoute ());
+      NS_LOG_LOGIC ("route to " << dst << " found");
+      return;
+    }
+  /*
+   *  If a route discovery has been attempted RreqRetries times at the maximum TTL without
+   *  receiving any RREP, all data packets destined for the corresponding destination SHOULD be
+   *  dropped from the buffer and a Destination Unreachable message SHOULD be delivered to the application.
+   */
+  if (toDst.GetRreqCnt () == m_rreqRetries)
+    {
+      NS_LOG_LOGIC ("route discovery to " << dst << " has been attempted RreqRetries (" << m_rreqRetries << ") times with ttl " << m_netDiameter);
+      m_addressReqTimer.erase (dst);
+      m_routingTable.DeleteRoute (dst);
+      NS_LOG_DEBUG ("Route not found. Drop all packets with dst " << dst);
+      m_queue.DropPacketWithDst (dst);
+      return;
+    }
+
+  if (toDst.GetFlag () == IN_SEARCH)
+    {
+      NS_LOG_LOGIC ("Resend RREQ to " << dst << " previous ttl " << toDst.GetHop ());
+      SendRequest (dst);
+    }
+  else
+    {
+      NS_LOG_DEBUG ("Route down. Stop search. Drop packet with destination " << dst);
+      m_addressReqTimer.erase (dst);
+      m_routingTable.DeleteRoute (dst);
+      m_queue.DropPacketWithDst (dst);
+    }
+}
+
+void
+RoutingProtocol::HelloTimerExpire ()
+{
+  NS_LOG_FUNCTION (this);
+  Time offset = Time (Seconds (0));
+  if (m_lastBcastTime > Time (Seconds (0)))
+    {
+      offset = Simulator::Now () - m_lastBcastTime;
+      NS_LOG_DEBUG ("Hello deferred due to last bcast at:" << m_lastBcastTime);
+    }
+  else
+    {
+      SendHello ();
+    }
+  m_htimer.Cancel ();
+  Time diff = m_helloInterval - offset;
+  m_htimer.Schedule (std::max (Time (Seconds (0)), diff));
+  m_lastBcastTime = Time (Seconds (0));
+}
+
+void
+RoutingProtocol::RreqRateLimitTimerExpire ()
+{
+  NS_LOG_FUNCTION (this);
+  m_rreqCount = 0;
+  m_rreqRateLimitTimer.Schedule (Seconds (1));
+}
+
+void
+RoutingProtocol::RerrRateLimitTimerExpire ()
+{
+  NS_LOG_FUNCTION (this);
+  m_rerrCount = 0;
+  m_rerrRateLimitTimer.Schedule (Seconds (1));
+}
+
+void
+RoutingProtocol::AckTimerExpire (Ipv4Address neighbor, Time blacklistTimeout)
+{
+  NS_LOG_FUNCTION (this);
+  m_routingTable.MarkLinkAsUnidirectional (neighbor, blacklistTimeout);
+}
+
+void
+RoutingProtocol::SendHello ()
+{
+  NS_LOG_FUNCTION (this);
+  /* Broadcast a RREP with TTL = 1 with the RREP message fields set as follows:
+   *   Destination IP Address         The node's IP address.
+   *   Destination Sequence Number    The node's latest sequence number.
+   *   Hop Count                      0
+   *   Lifetime                       AllowedHelloLoss * HelloInterval
+   */
+  for (std::map<Ptr<Socket>, Ipv4InterfaceAddress>::const_iterator j = m_socketAddresses.begin (); j != m_socketAddresses.end (); ++j)
+    {
+      Ptr<Socket> socket = j->first;
+      Ipv4InterfaceAddress iface = j->second;
+      RrepHeader helloHeader (/*prefix size=*/ 0, /*hops=*/ 0, /*dst=*/ iface.GetLocal (), /*dst seqno=*/ m_seqNo,
+                                               /*origin=*/ iface.GetLocal (),/*lifetime=*/ Time (m_allowedHelloLoss * m_helloInterval));
+      Ptr<Packet> packet = Create<Packet> ();
+      SocketIpTtlTag tag;
+      tag.SetTtl (1);
+      packet->AddPacketTag (tag);
+      packet->AddHeader (helloHeader);
+      TypeHeader tHeader (greyattackTYPE_RREP);
+      packet->AddHeader (tHeader);
+      // Send to all-hosts broadcast if on /32 addr, subnet-directed otherwise
+      Ipv4Address destination;
+      if (iface.GetMask () == Ipv4Mask::GetOnes ())
+        {
+          destination = Ipv4Address ("255.255.255.255");
+        }
+      else
+        {
+          destination = iface.GetBroadcast ();
+        }
+      Time jitter = Time (MilliSeconds (m_uniformRandomVariable->GetInteger (0, 10)));
+      Simulator::Schedule (jitter, &RoutingProtocol::SendTo, this, socket, packet, destination);
+    }
+}
+
+void
+RoutingProtocol::SendPacketFromQueue (Ipv4Address dst, Ptr<Ipv4Route> route)
+{
+  NS_LOG_FUNCTION (this);
+  QueueEntry queueEntry;
+  while (m_queue.Dequeue (dst, queueEntry))
+    {
+      DeferredRouteOutputTag tag;
+      Ptr<Packet> p = ConstCast<Packet> (queueEntry.GetPacket ());
+      if (p->RemovePacketTag (tag)
+          && tag.GetInterface () != -1
+          && tag.GetInterface () != m_ipv4->GetInterfaceForDevice (route->GetOutputDevice ()))
+        {
+          NS_LOG_DEBUG ("Output device doesn't match. Dropped.");
+          return;
+        }
+      UnicastForwardCallback ucb = queueEntry.GetUnicastForwardCallback ();
+      Ipv4Header header = queueEntry.GetIpv4Header ();
+      header.SetSource (route->GetSource ());
+      header.SetTtl (header.GetTtl () + 1); // compensate extra TTL decrement by fake loopback routing
+      ucb (route, p, header);
+    }
+}
+
+void
+RoutingProtocol::SendRerrWhenBreaksLinkToNextHop (Ipv4Address nextHop)
+{
+  NS_LOG_FUNCTION (this << nextHop);
+  RerrHeader rerrHeader;
+  std::vector<Ipv4Address> precursors;
+  std::map<Ipv4Address, uint32_t> unreachable;
+
+  RoutingTableEntry toNextHop;
+  if (!m_routingTable.LookupRoute (nextHop, toNextHop))
+    {
+      return;
+    }
+  toNextHop.GetPrecursors (precursors);
+  rerrHeader.AddUnDestination (nextHop, toNextHop.GetSeqNo ());
+  m_routingTable.GetListOfDestinationWithNextHop (nextHop, unreachable);
+  for (std::map<Ipv4Address, uint32_t>::const_iterator i = unreachable.begin (); i
+       != unreachable.end (); )
+    {
+      if (!rerrHeader.AddUnDestination (i->first, i->second))
+        {
+          NS_LOG_LOGIC ("Send RERR message with maximum size.");
+          TypeHeader typeHeader (greyattackTYPE_RERR);
+          Ptr<Packet> packet = Create<Packet> ();
+          SocketIpTtlTag tag;
+          tag.SetTtl (1);
+          packet->AddPacketTag (tag);
+          packet->AddHeader (rerrHeader);
+          packet->AddHeader (typeHeader);
+          SendRerrMessage (packet, precursors);
+          rerrHeader.Clear ();
+        }
+      else
+        {
+          RoutingTableEntry toDst;
+          m_routingTable.LookupRoute (i->first, toDst);
+          toDst.GetPrecursors (precursors);
+          ++i;
+        }
+    }
+  if (rerrHeader.GetDestCount () != 0)
+    {
+      TypeHeader typeHeader (greyattackTYPE_RERR);
+      Ptr<Packet> packet = Create<Packet> ();
+      SocketIpTtlTag tag;
+      tag.SetTtl (1);
+      packet->AddPacketTag (tag);
+      packet->AddHeader (rerrHeader);
+      packet->AddHeader (typeHeader);
+      SendRerrMessage (packet, precursors);
+    }
+  unreachable.insert (std::make_pair (nextHop, toNextHop.GetSeqNo ()));
+  m_routingTable.InvalidateRoutesWithDst (unreachable);
+}
+
+void
+RoutingProtocol::SendRerrWhenNoRouteToForward (Ipv4Address dst,
+                                               uint32_t dstSeqNo, Ipv4Address origin)
+{
+  NS_LOG_FUNCTION (this);
+  // A node SHOULD NOT originate more than RERR_RATELIMIT RERR messages per second.
+  if (m_rerrCount == m_rerrRateLimit)
+    {
+      // Just make sure that the RerrRateLimit timer is running and will expire
+      NS_ASSERT (m_rerrRateLimitTimer.IsRunning ());
+      // discard the packet and return
+      NS_LOG_LOGIC ("RerrRateLimit reached at " << Simulator::Now ().As (Time::S) << " with timer delay left "
+                                                << m_rerrRateLimitTimer.GetDelayLeft ().As (Time::S)
+                                                << "; suppressing RERR");
+      return;
+    }
+  RerrHeader rerrHeader;
+  rerrHeader.AddUnDestination (dst, dstSeqNo);
+  RoutingTableEntry toOrigin;
+  Ptr<Packet> packet = Create<Packet> ();
+  SocketIpTtlTag tag;
+  tag.SetTtl (1);
+  packet->AddPacketTag (tag);
+  packet->AddHeader (rerrHeader);
+  packet->AddHeader (TypeHeader (greyattackTYPE_RERR));
+  if (m_routingTable.LookupValidRoute (origin, toOrigin))
+    {
+      Ptr<Socket> socket = FindSocketWithInterfaceAddress (
+          toOrigin.GetInterface ());
+      NS_ASSERT (socket);
+      NS_LOG_LOGIC ("Unicast RERR to the source of the data transmission");
+      socket->SendTo (packet, 0, InetSocketAddress (toOrigin.GetNextHop (), greyattack_PORT));
+    }
+  else
+    {
+      for (std::map<Ptr<Socket>, Ipv4InterfaceAddress>::const_iterator i =
+             m_socketAddresses.begin (); i != m_socketAddresses.end (); ++i)
+        {
+          Ptr<Socket> socket = i->first;
+          Ipv4InterfaceAddress iface = i->second;
+          NS_ASSERT (socket);
+          NS_LOG_LOGIC ("Broadcast RERR message from interface " << iface.GetLocal ());
+          // Send to all-hosts broadcast if on /32 addr, subnet-directed otherwise
+          Ipv4Address destination;
+          if (iface.GetMask () == Ipv4Mask::GetOnes ())
+            {
+              destination = Ipv4Address ("255.255.255.255");
+            }
+          else
+            {
+              destination = iface.GetBroadcast ();
+            }
+          socket->SendTo (packet->Copy (), 0, InetSocketAddress (destination, greyattack_PORT));
+        }
+    }
+}
+
+void
+RoutingProtocol::SendRerrMessage (Ptr<Packet> packet, std::vector<Ipv4Address> precursors)
+{
+  NS_LOG_FUNCTION (this);
+
+  if (precursors.empty ())
+    {
+      NS_LOG_LOGIC ("No precursors");
+      return;
+    }
+  // A node SHOULD NOT originate more than RERR_RATELIMIT RERR messages per second.
+  if (m_rerrCount == m_rerrRateLimit)
+    {
+      // Just make sure that the RerrRateLimit timer is running and will expire
+      NS_ASSERT (m_rerrRateLimitTimer.IsRunning ());
+      // discard the packet and return
+      NS_LOG_LOGIC ("RerrRateLimit reached at " << Simulator::Now ().As (Time::S) << " with timer delay left "
+                                                << m_rerrRateLimitTimer.GetDelayLeft ().As (Time::S)
+                                                << "; suppressing RERR");
+      return;
+    }
+  // If there is only one precursor, RERR SHOULD be unicast toward that precursor
+  if (precursors.size () == 1)
+    {
+      RoutingTableEntry toPrecursor;
+      if (m_routingTable.LookupValidRoute (precursors.front (), toPrecursor))
+        {
+          Ptr<Socket> socket = FindSocketWithInterfaceAddress (toPrecursor.GetInterface ());
+          NS_ASSERT (socket);
+          NS_LOG_LOGIC ("one precursor => unicast RERR to " << toPrecursor.GetDestination () << " from " << toPrecursor.GetInterface ().GetLocal ());
+          Simulator::Schedule (Time (MilliSeconds (m_uniformRandomVariable->GetInteger (0, 10))), &RoutingProtocol::SendTo, this, socket, packet, precursors.front ());
+          m_rerrCount++;
+        }
+      return;
+    }
+
+  //  Should only transmit RERR on those interfaces which have precursor nodes for the broken route
+  std::vector<Ipv4InterfaceAddress> ifaces;
+  RoutingTableEntry toPrecursor;
+  for (std::vector<Ipv4Address>::const_iterator i = precursors.begin (); i != precursors.end (); ++i)
+    {
+      if (m_routingTable.LookupValidRoute (*i, toPrecursor)
+          && std::find (ifaces.begin (), ifaces.end (), toPrecursor.GetInterface ()) == ifaces.end ())
+        {
+          ifaces.push_back (toPrecursor.GetInterface ());
+        }
+    }
+
+  for (std::vector<Ipv4InterfaceAddress>::const_iterator i = ifaces.begin (); i != ifaces.end (); ++i)
+    {
+      Ptr<Socket> socket = FindSocketWithInterfaceAddress (*i);
+      NS_ASSERT (socket);
+      NS_LOG_LOGIC ("Broadcast RERR message from interface " << i->GetLocal ());
+      // std::cout << "Broadcast RERR message from interface " << i->GetLocal () << std::endl;
+      // Send to all-hosts broadcast if on /32 addr, subnet-directed otherwise
+      Ptr<Packet> p = packet->Copy ();
+      Ipv4Address destination;
+      if (i->GetMask () == Ipv4Mask::GetOnes ())
+        {
+          destination = Ipv4Address ("255.255.255.255");
+        }
+      else
+        {
+          destination = i->GetBroadcast ();
+        }
+      Simulator::Schedule (Time (MilliSeconds (m_uniformRandomVariable->GetInteger (0, 10))), &RoutingProtocol::SendTo, this, socket, p, destination);
+    }
+}
+
+Ptr<Socket>
+RoutingProtocol::FindSocketWithInterfaceAddress (Ipv4InterfaceAddress addr ) const
+{
+  NS_LOG_FUNCTION (this << addr);
+  for (std::map<Ptr<Socket>, Ipv4InterfaceAddress>::const_iterator j =
+         m_socketAddresses.begin (); j != m_socketAddresses.end (); ++j)
+    {
+      Ptr<Socket> socket = j->first;
+      Ipv4InterfaceAddress iface = j->second;
+      if (iface == addr)
+        {
+          return socket;
+        }
+    }
+  Ptr<Socket> socket;
+  return socket;
+}
+
+Ptr<Socket>
+RoutingProtocol::FindSubnetBroadcastSocketWithInterfaceAddress (Ipv4InterfaceAddress addr ) const
+{
+  NS_LOG_FUNCTION (this << addr);
+  for (std::map<Ptr<Socket>, Ipv4InterfaceAddress>::const_iterator j =
+         m_socketSubnetBroadcastAddresses.begin (); j != m_socketSubnetBroadcastAddresses.end (); ++j)
+    {
+      Ptr<Socket> socket = j->first;
+      Ipv4InterfaceAddress iface = j->second;
+      if (iface == addr)
+        {
+          return socket;
+        }
+    }
+  Ptr<Socket> socket;
+  return socket;
+}
+
+void
+RoutingProtocol::DoInitialize (void)
+{
+  NS_LOG_FUNCTION (this);
+  uint32_t startTime;
+  if (m_enableHello)
+    {
+      m_htimer.SetFunction (&RoutingProtocol::HelloTimerExpire, this);
+      startTime = m_uniformRandomVariable->GetInteger (0, 100);
+      NS_LOG_DEBUG ("Starting at time " << startTime << "ms");
+      m_htimer.Schedule (MilliSeconds (startTime));
+    }
+  Ipv4RoutingProtocol::DoInitialize ();
+}
+
+} //namespace greyattack
+} //namespace ns3
diff --git a/greyattack-module/model/greyattack-aodv-routing-protocol.h b/greyattack-module/model/greyattack-aodv-routing-protocol.h
new file mode 100644
index 0000000000000000000000000000000000000000..0cf94db0eee693d963301eacc3541b4162da7e43
--- /dev/null
+++ b/greyattack-module/model/greyattack-aodv-routing-protocol.h
@@ -0,0 +1,489 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2009 IITP RAS
+ *
+ * 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
+ *
+ * Based on
+ *      NS-3 greyattack
+ *
+ * Authors: Charles Hutchins
+ */
+#ifndef greyattack_aodvROUTINGPROTOCOL_H
+#define greyattack_aodvROUTINGPROTOCOL_H
+
+#include "greyattack-aodv-rtable.h"
+#include "greyattack-aodv-rqueue.h"
+#include "greyattack-aodv-packet.h"
+#include "greyattack-aodv-neighbor.h"
+#include "greyattack-aodv-dpd.h"
+#include "ns3/node.h"
+#include "ns3/random-variable-stream.h"
+#include "ns3/output-stream-wrapper.h"
+#include "ns3/ipv4-routing-protocol.h"
+#include "ns3/ipv4-interface.h"
+#include "ns3/ipv4-l3-protocol.h"
+#include "ns3/mobility-module.h"
+#include <map>
+
+namespace ns3 {
+
+class WifiMacQueueItem;
+enum WifiMacDropReason : uint8_t;  // opaque enum declaration
+
+// Define a new class here:
+class TargetNodes : public Object
+{
+public:
+    std::vector<uint32_t> node;
+    std::vector<double> connection_strength;
+};
+
+// define a strategy enum here to distinguish between strategies:
+enum AttackStratSelect
+{
+    NO_A_OPERATION,
+    PACKET_DROP_PERC,
+    PACKET_DROP_CONNECTION,
+    PACKET_DROP_NEIGHBOURS
+};
+
+namespace greyattackAodv {
+/**
+ * \ingroup greyattack
+ *
+ * \brief greyattack routing protocol
+ */
+class RoutingProtocol : public Ipv4RoutingProtocol
+{
+public:
+  /**
+   * \brief Get the type ID.
+   * \return the object TypeId
+   */
+  static TypeId GetTypeId (void);
+  static const uint32_t greyattack_PORT;
+
+  /// constructor
+  RoutingProtocol ();
+  virtual ~RoutingProtocol ();
+  virtual void DoDispose ();
+
+  // Inherited from Ipv4RoutingProtocol
+  Ptr<Ipv4Route> RouteOutput (Ptr<Packet> p, const Ipv4Header &header, Ptr<NetDevice> oif, Socket::SocketErrno &sockerr);
+  bool RouteInput (Ptr<const Packet> p, const Ipv4Header &header, Ptr<const NetDevice> idev,
+                   UnicastForwardCallback ucb, MulticastForwardCallback mcb,
+                   LocalDeliverCallback lcb, ErrorCallback ecb);
+  virtual void NotifyInterfaceUp (uint32_t interface);
+  virtual void NotifyInterfaceDown (uint32_t interface);
+  virtual void NotifyAddAddress (uint32_t interface, Ipv4InterfaceAddress address);
+  virtual void NotifyRemoveAddress (uint32_t interface, Ipv4InterfaceAddress address);
+  virtual void SetIpv4 (Ptr<Ipv4> ipv4);
+  virtual void PrintRoutingTable (Ptr<OutputStreamWrapper> stream, Time::Unit unit = Time::S) const;
+
+  // Handle protocol parameters
+  /**
+   * Get maximum queue time
+   * \returns the maximum queue time
+   */
+  Time GetMaxQueueTime () const
+  {
+    return m_maxQueueTime;
+  }
+  /**
+   * Set the maximum queue time
+   * \param t the maximum queue time
+   */
+  void SetMaxQueueTime (Time t);
+  /**
+   * Get the maximum queue length
+   * \returns the maximum queue length
+   */
+  uint32_t GetMaxQueueLen () const
+  {
+    return m_maxQueueLen;
+  }
+  /**
+   * Set the maximum queue length
+   * \param len the maximum queue length
+   */
+  void SetMaxQueueLen (uint32_t len);
+  /**
+   * Get destination only flag
+   * \returns the destination only flag
+   */
+  bool GetDestinationOnlyFlag () const
+  {
+    return m_destinationOnly;
+  }
+  /**
+   * Set destination only flag
+   * \param f the destination only flag
+   */
+  void SetDestinationOnlyFlag (bool f)
+  {
+    m_destinationOnly = f;
+  }
+  /**
+   * Get gratuitous reply flag
+   * \returns the gratuitous reply flag
+   */
+  bool GetGratuitousReplyFlag () const
+  {
+    return m_gratuitousReply;
+  }
+  /**
+   * Set gratuitous reply flag
+   * \param f the gratuitous reply flag
+   */
+  void SetGratuitousReplyFlag (bool f)
+  {
+    m_gratuitousReply = f;
+  }
+  /**
+   * Set hello enable
+   * \param f the hello enable flag
+   */
+  void SetHelloEnable (bool f)
+  {
+    m_enableHello = f;
+  }
+  /**
+   * Get hello enable flag
+   * \returns the enable hello flag
+   */
+  bool GetHelloEnable () const
+  {
+    return m_enableHello;
+  }
+  /**
+   * Set broadcast enable flag
+   * \param f enable broadcast flag
+   */
+  void SetBroadcastEnable (bool f)
+  {
+    m_enableBroadcast = f;
+  }
+  /**
+   * Get broadcast enable flag
+   * \returns the broadcast enable flag
+   */
+  bool GetBroadcastEnable () const
+  {
+    return m_enableBroadcast;
+  }
+
+  /**
+   * Assign a fixed random variable stream number to the random variables
+   * used by this model.  Return the number of streams (possibly zero) that
+   * have been assigned.
+   *
+   * \param stream first stream index to use
+   * \return the number of stream indices assigned by this model
+   */
+  int64_t AssignStreams (int64_t stream);
+
+protected:
+  virtual void DoInitialize (void);
+private:
+  /**
+   * Notify that an MPDU was dropped.
+   *
+   * \param reason the reason why the MPDU was dropped
+   * \param mpdu the dropped MPDU
+   */
+  void NotifyTxError (WifiMacDropReason reason, Ptr<const WifiMacQueueItem> mpdu);
+
+  ////my variables for monitoring nodes
+  Ptr<TargetNodes> targetNodes;
+
+  //strategy
+  uint32_t m_strat;
+  AttackStratSelect strat;
+
+  // Protocol parameters.
+  uint32_t m_rreqRetries;             ///< Maximum number of retransmissions of RREQ with TTL = NetDiameter to discover a route
+  uint16_t m_ttlStart;                ///< Initial TTL value for RREQ.
+  uint16_t m_ttlIncrement;            ///< TTL increment for each attempt using the expanding ring search for RREQ dissemination.
+  uint16_t m_ttlThreshold;            ///< Maximum TTL value for expanding ring search, TTL = NetDiameter is used beyond this value.
+  uint16_t m_timeoutBuffer;           ///< Provide a buffer for the timeout.
+  uint16_t m_rreqRateLimit;           ///< Maximum number of RREQ per second.
+  uint16_t m_rerrRateLimit;           ///< Maximum number of REER per second.
+  Time m_activeRouteTimeout;          ///< Period of time during which the route is considered to be valid.
+  uint32_t m_netDiameter;             ///< Net diameter measures the maximum possible number of hops between two nodes in the network
+  /**
+   *  NodeTraversalTime is a conservative estimate of the average one hop traversal time for packets
+   *  and should include queuing delays, interrupt processing times and transfer times.
+   */
+  Time m_nodeTraversalTime;
+  Time m_netTraversalTime;             ///< Estimate of the average net traversal time.
+  Time m_pathDiscoveryTime;            ///< Estimate of maximum time needed to find route in network.
+  Time m_myRouteTimeout;               ///< Value of lifetime field in RREP generating by this node.
+  /**
+   * Every HelloInterval the node checks whether it has sent a broadcast  within the last HelloInterval.
+   * If it has not, it MAY broadcast a  Hello message
+   */
+  Time m_helloInterval;
+  uint32_t m_allowedHelloLoss;         ///< Number of hello messages which may be loss for valid link
+  /**
+   * DeletePeriod is intended to provide an upper bound on the time for which an upstream node A
+   * can have a neighbor B as an active next hop for destination D, while B has invalidated the route to D.
+   */
+  Time m_deletePeriod;
+  Time m_nextHopWait;                  ///< Period of our waiting for the neighbour's RREP_ACK
+  Time m_blackListTimeout;             ///< Time for which the node is put into the blacklist
+  uint32_t m_maxQueueLen;              ///< The maximum number of packets that we allow a routing protocol to buffer.
+  Time m_maxQueueTime;                 ///< The maximum period of time that a routing protocol is allowed to buffer a packet for.
+  bool m_destinationOnly;              ///< Indicates only the destination may respond to this RREQ.
+  bool m_gratuitousReply;              ///< Indicates whether a gratuitous RREP should be unicast to the node originated route discovery.
+  bool m_enableHello;                  ///< Indicates whether a hello messages enable
+  bool m_enableBroadcast;              ///< Indicates whether a a broadcast data packets forwarding enable
+  //\}
+
+  /// IP protocol
+  Ptr<Ipv4> m_ipv4;
+  /// Raw unicast socket per each IP interface, map socket -> iface address (IP + mask)
+  std::map< Ptr<Socket>, Ipv4InterfaceAddress > m_socketAddresses;
+  /// Raw subnet directed broadcast socket per each IP interface, map socket -> iface address (IP + mask)
+  std::map< Ptr<Socket>, Ipv4InterfaceAddress > m_socketSubnetBroadcastAddresses;
+  /// Loopback device used to defer RREQ until packet will be fully formed
+  Ptr<NetDevice> m_lo;
+
+  /// Routing table
+  RoutingTable m_routingTable;
+  /// A "drop-front" queue used by the routing layer to buffer packets to which it does not have a route.
+  RequestQueue m_queue;
+  /// Broadcast ID
+  uint32_t m_requestId;
+  /// Request sequence number
+  uint32_t m_seqNo;
+  /// Handle duplicated RREQ
+  IdCache m_rreqIdCache;
+  /// Handle duplicated broadcast/multicast packets
+  DuplicatePacketDetection m_dpd;
+  /// Handle neighbors
+  Neighbors m_nb;
+  /// Number of RREQs used for RREQ rate control
+  uint16_t m_rreqCount;
+  /// Number of RERRs used for RERR rate control
+  uint16_t m_rerrCount;
+
+  // My variables for the EGTA
+  double m_vPercentDrop;
+  double m_vTConnection;
+  uint32_t m_vTNeighbour;
+
+private:
+  /// Start protocol operation
+  void Start ();
+  /**
+   * Queue packet and send route request
+   *
+   * \param p the packet to route
+   * \param header the IP header
+   * \param ucb the UnicastForwardCallback function
+   * \param ecb the ErrorCallback function
+   */ 
+  void DeferredRouteOutput (Ptr<const Packet> p, const Ipv4Header & header, UnicastForwardCallback ucb, ErrorCallback ecb);
+  /**
+   * If route exists and is valid, forward packet.
+   *
+   * \param p the packet to route
+   * \param header the IP header
+   * \param ucb the UnicastForwardCallback function
+   * \param ecb the ErrorCallback function
+   * \returns true if forwarded
+   */ 
+  bool Forwarding (Ptr<const Packet> p, const Ipv4Header & header, UnicastForwardCallback ucb, ErrorCallback ecb);
+  /**
+   * Repeated attempts by a source node at route discovery for a single destination
+   * use the expanding ring search technique.
+   * \param dst the destination IP address
+   */
+  void ScheduleRreqRetry (Ipv4Address dst);
+  /**
+   * Set lifetime field in routing table entry to the maximum of existing lifetime and lt, if the entry exists
+   * \param addr - destination address
+   * \param lt - proposed time for lifetime field in routing table entry for destination with address addr.
+   * \return true if route to destination address addr exist
+   */
+  bool UpdateRouteLifeTime (Ipv4Address addr, Time lt);
+  /**
+   * Update neighbor record.
+   * \param receiver is supposed to be my interface
+   * \param sender is supposed to be IP address of my neighbor.
+   */
+  void UpdateRouteToNeighbor (Ipv4Address sender, Ipv4Address receiver);
+  /**
+   * Test whether the provided address is assigned to an interface on this node
+   * \param src the source IP address
+   * \returns true if the IP address is the node's IP address
+   */
+  bool IsMyOwnAddress (Ipv4Address src);
+  /**
+   * Find unicast socket with local interface address iface
+   *
+   * \param iface the interface
+   * \returns the socket associated with the interface
+   */
+  Ptr<Socket> FindSocketWithInterfaceAddress (Ipv4InterfaceAddress iface) const;
+  /**
+   * Find subnet directed broadcast socket with local interface address iface
+   *
+   * \param iface the interface
+   * \returns the socket associated with the interface
+   */
+  Ptr<Socket> FindSubnetBroadcastSocketWithInterfaceAddress (Ipv4InterfaceAddress iface) const;
+  /**
+   * Process hello message
+   * 
+   * \param rrepHeader RREP message header
+   * \param receiverIfaceAddr receiver interface IP address
+   */
+  void ProcessHello (RrepHeader const & rrepHeader, Ipv4Address receiverIfaceAddr);
+  /**
+   * Create loopback route for given header
+   *
+   * \param header the IP header
+   * \param oif the output interface net device
+   * \returns the route
+   */
+  Ptr<Ipv4Route> LoopbackRoute (const Ipv4Header & header, Ptr<NetDevice> oif) const;
+
+  ///\name Receive control packets
+  //\{
+  /**
+   * Receive and process control packet
+   * \param socket input socket
+   */
+  void Recvgreyattack (Ptr<Socket> socket);
+  /**
+   * Receive RREQ
+   * \param p packet
+   * \param receiver receiver address
+   * \param src sender address
+   */
+  void RecvRequest (Ptr<Packet> p, Ipv4Address receiver, Ipv4Address src);
+  /**
+   * Receive RREP
+   * \param p packet
+   * \param my destination address
+   * \param src sender address
+   */
+  void RecvReply (Ptr<Packet> p, Ipv4Address my, Ipv4Address src);
+  /**
+   * Receive RREP_ACK
+   * \param neighbor neighbor address
+   */
+  void RecvReplyAck (Ipv4Address neighbor);
+  /**
+   * Receive RERR
+   * \param p packet
+   * \param src sender address
+   */
+  /// Receive  from node with address src
+  void RecvError (Ptr<Packet> p, Ipv4Address src);
+  //\}
+
+  ///\name Send
+  //\{
+  /** Forward packet from route request queue
+   * \param dst destination address
+   * \param route route to use
+   */
+  void SendPacketFromQueue (Ipv4Address dst, Ptr<Ipv4Route> route);
+  /// Send hello
+  void SendHello ();
+  /** Send RREQ
+   * \param dst destination address
+   */
+  void SendRequest (Ipv4Address dst);
+  /** Send RREP
+   * \param rreqHeader route request header
+   * \param toOrigin routing table entry to originator
+   */
+  void SendReply (RreqHeader const & rreqHeader, RoutingTableEntry const & toOrigin);
+  /** Send RREP by intermediate node
+   * \param toDst routing table entry to destination
+   * \param toOrigin routing table entry to originator
+   * \param gratRep indicates whether a gratuitous RREP should be unicast to destination
+   */
+  void SendReplyByIntermediateNode (RoutingTableEntry & toDst, RoutingTableEntry & toOrigin, bool gratRep);
+  /** Send RREP_ACK
+   * \param neighbor neighbor address
+   */
+  void SendReplyAck (Ipv4Address neighbor);
+  /** Initiate RERR
+   * \param nextHop next hop address
+   */
+  void SendRerrWhenBreaksLinkToNextHop (Ipv4Address nextHop);
+  /** Forward RERR
+   * \param packet packet
+   * \param precursors list of addresses of the visited nodes
+   */
+  void SendRerrMessage (Ptr<Packet> packet,  std::vector<Ipv4Address> precursors);
+  /**
+   * Send RERR message when no route to forward input packet. Unicast if there is reverse route to originating node, broadcast otherwise.
+   * \param dst - destination node IP address
+   * \param dstSeqNo - destination node sequence number
+   * \param origin - originating node IP address
+   */
+  void SendRerrWhenNoRouteToForward (Ipv4Address dst, uint32_t dstSeqNo, Ipv4Address origin);
+  /// @}
+
+  /**
+   * Send packet to destination socket
+   * \param socket - destination node socket
+   * \param packet - packet to send
+   * \param destination - destination node IP address
+   */
+  void SendTo (Ptr<Socket> socket, Ptr<Packet> packet, Ipv4Address destination);
+
+  /// Hello timer
+  Timer m_htimer;
+  /// Schedule next send of hello message
+  void HelloTimerExpire ();
+  /// RREQ rate limit timer
+  Timer m_rreqRateLimitTimer;
+  /// Reset RREQ count and schedule RREQ rate limit timer with delay 1 sec.
+  void RreqRateLimitTimerExpire ();
+  /// RERR rate limit timer
+  Timer m_rerrRateLimitTimer;
+  /// Reset RERR count and schedule RERR rate limit timer with delay 1 sec.
+  void RerrRateLimitTimerExpire ();
+  /// Map IP address + RREQ timer.
+  std::map<Ipv4Address, Timer> m_addressReqTimer;
+  /**
+   * Handle route discovery process
+   * \param dst the destination IP address
+   */
+  void RouteRequestTimerExpire (Ipv4Address dst);
+  /**
+   * Mark link to neighbor node as unidirectional for blacklistTimeout
+   *
+   * \param neighbor the IP address of the neightbor node
+   * \param blacklistTimeout the black list timeout time
+   */
+  void AckTimerExpire (Ipv4Address neighbor, Time blacklistTimeout);
+
+  /// Provides uniform random variables.
+  Ptr<UniformRandomVariable> m_uniformRandomVariable;
+  /// Keep track of the last bcast time
+  Time m_lastBcastTime;
+};
+
+} //namespace greyattack
+} //namespace ns3
+
+#endif /* greyattackROUTINGPROTOCOL_H */
diff --git a/greyattack-module/model/greyattack-aodv-rqueue.cc b/greyattack-module/model/greyattack-aodv-rqueue.cc
new file mode 100644
index 0000000000000000000000000000000000000000..adf2a8c75ff8b56760f4659a09a7a86c72e1524e
--- /dev/null
+++ b/greyattack-module/model/greyattack-aodv-rqueue.cc
@@ -0,0 +1,160 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2009 IITP RAS
+ *
+ * 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
+ *
+ * Based on
+ *      NS-3 greyattack
+ *
+ * Authors: Charles Hutchins
+ */
+#include "greyattack-aodv-rqueue.h"
+#include <algorithm>
+#include <functional>
+#include "ns3/ipv4-route.h"
+#include "ns3/socket.h"
+#include "ns3/log.h"
+
+namespace ns3 {
+
+NS_LOG_COMPONENT_DEFINE ("greyattack-aodvRequestQueue");
+
+namespace greyattackAodv {
+uint32_t
+RequestQueue::GetSize ()
+{
+  Purge ();
+  return m_queue.size ();
+}
+
+bool
+RequestQueue::Enqueue (QueueEntry & entry)
+{
+  Purge ();
+  for (std::vector<QueueEntry>::const_iterator i = m_queue.begin (); i
+       != m_queue.end (); ++i)
+    {
+      if ((i->GetPacket ()->GetUid () == entry.GetPacket ()->GetUid ())
+          && (i->GetIpv4Header ().GetDestination ()
+              == entry.GetIpv4Header ().GetDestination ()))
+        {
+          return false;
+        }
+    }
+  entry.SetExpireTime (m_queueTimeout);
+  if (m_queue.size () == m_maxLen)
+    {
+      Drop (m_queue.front (), "Drop the most aged packet"); // Drop the most aged packet
+      m_queue.erase (m_queue.begin ());
+    }
+  m_queue.push_back (entry);
+  
+  return true;
+}
+
+void
+RequestQueue::DropPacketWithDst (Ipv4Address dst)
+{
+  NS_LOG_FUNCTION (this << dst);
+  Purge ();
+  for (std::vector<QueueEntry>::iterator i = m_queue.begin (); i
+       != m_queue.end (); ++i)
+    {
+      if (i->GetIpv4Header ().GetDestination () == dst)
+        {
+          Drop (*i, "DropPacketWithDst ");
+        }
+    }
+  auto new_end = std::remove_if (m_queue.begin (), m_queue.end (),
+                                 [&](const QueueEntry& en) { return en.GetIpv4Header ().GetDestination () == dst; });
+  m_queue.erase (new_end, m_queue.end ());
+}
+
+bool
+RequestQueue::Dequeue (Ipv4Address dst, QueueEntry & entry)
+{
+  Purge ();
+  for (std::vector<QueueEntry>::iterator i = m_queue.begin (); i != m_queue.end (); ++i)
+    {
+      if (i->GetIpv4Header ().GetDestination () == dst)
+        {
+          entry = *i;
+          m_queue.erase (i);
+          return true;
+        }
+    }
+  return false;
+}
+
+bool
+RequestQueue::Find (Ipv4Address dst)
+{
+  for (std::vector<QueueEntry>::const_iterator i = m_queue.begin (); i
+       != m_queue.end (); ++i)
+    {
+      if (i->GetIpv4Header ().GetDestination () == dst)
+        {
+          return true;
+        }
+    }
+  return false;
+}
+
+/**
+ * \brief IsExpired structure
+ */
+struct IsExpired
+{
+  
+  /**
+   * Check if the entry is expired
+   *
+   * \param e QueueEntry entry
+   * \return true if expired, false otherwise
+   */
+   bool
+  operator() (QueueEntry const & e) const
+  {
+    return (e.GetExpireTime () < Seconds (0));
+  }
+};
+
+void
+RequestQueue::Purge ()
+{
+  IsExpired pred;
+  for (std::vector<QueueEntry>::iterator i = m_queue.begin (); i
+       != m_queue.end (); ++i)
+    {
+      if (pred (*i))
+        {
+          Drop (*i, "Drop outdated packet ");
+        }
+    }
+  m_queue.erase (std::remove_if (m_queue.begin (), m_queue.end (), pred),
+                 m_queue.end ());
+}
+
+void
+RequestQueue::Drop (QueueEntry en, std::string reason)
+{
+  NS_LOG_LOGIC (reason << en.GetPacket ()->GetUid () << " " << en.GetIpv4Header ().GetDestination ());
+  en.GetErrorCallback () (en.GetPacket (), en.GetIpv4Header (),
+                          Socket::ERROR_NOROUTETOHOST);
+  return;
+}
+
+}  // namespace greyattack
+}  // namespace ns3
diff --git a/greyattack-module/model/greyattack-aodv-rqueue.h b/greyattack-module/model/greyattack-aodv-rqueue.h
new file mode 100644
index 0000000000000000000000000000000000000000..f63da33c3a36c66175baa6eaea012f18b2b0538c
--- /dev/null
+++ b/greyattack-module/model/greyattack-aodv-rqueue.h
@@ -0,0 +1,275 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2009 IITP RAS
+ *
+ * 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
+ *
+ * Based on
+ *      NS-3 greyattack
+ *
+ * Authors: Charles Hutchins
+ */
+#ifndef greyattack_aodv_RQUEUE_H
+#define greyattack_aodv_RQUEUE_H
+
+#include <vector>
+#include "ns3/ipv4-routing-protocol.h"
+#include "ns3/simulator.h"
+
+
+namespace ns3 {
+namespace greyattackAodv {
+
+/**
+ * \ingroup greyattack
+ * \brief greyattack Queue Entry
+ */
+class QueueEntry
+{
+public:
+  /// IPv4 routing unicast forward callback typedef
+  typedef Ipv4RoutingProtocol::UnicastForwardCallback UnicastForwardCallback;
+  /// IPv4 routing error callback typedef
+  typedef Ipv4RoutingProtocol::ErrorCallback ErrorCallback;
+  /**
+   * constructor
+   *
+   * \param pa the packet to add to the queue
+   * \param h the Ipv4Header
+   * \param ucb the UnicastForwardCallback function
+   * \param ecb the ErrorCallback function
+   * \param exp the expiration time
+   */
+  QueueEntry (Ptr<const Packet> pa = 0, Ipv4Header const & h = Ipv4Header (),
+              UnicastForwardCallback ucb = UnicastForwardCallback (),
+              ErrorCallback ecb = ErrorCallback (), Time exp = Simulator::Now ())
+    : m_packet (pa),
+      m_header (h),
+      m_ucb (ucb),
+      m_ecb (ecb),
+      m_expire (exp + Simulator::Now ())
+  {
+  }
+
+  /**
+   * \brief Compare queue entries
+   * \param o QueueEntry to compare
+   * \return true if equal
+   */
+  bool operator== (QueueEntry const & o) const
+  {
+    return ((m_packet == o.m_packet) && (m_header.GetDestination () == o.m_header.GetDestination ()) && (m_expire == o.m_expire));
+  }
+
+  // Fields
+  /**
+   * Get unicast forward callback
+   * \returns unicast callback
+   */
+  UnicastForwardCallback GetUnicastForwardCallback () const
+  {
+    return m_ucb;
+  }
+  /**
+   * Set unicast forward callback
+   * \param ucb The unicast callback
+   */
+  void SetUnicastForwardCallback (UnicastForwardCallback ucb)
+  {
+    m_ucb = ucb;
+  }
+  /**
+   * Get error callback
+   * \returns the error callback
+   */
+  ErrorCallback GetErrorCallback () const
+  {
+    return m_ecb;
+  }
+  /**
+   * Set error callback
+   * \param ecb The error callback
+   */
+  void SetErrorCallback (ErrorCallback ecb)
+  {
+    m_ecb = ecb;
+  }
+  /**
+   * Get packet from entry
+   * \returns the packet
+   */
+  Ptr<const Packet> GetPacket () const
+  {
+    return m_packet;
+  }
+  /**
+   * Set packet in entry
+   * \param p The packet
+   */
+  void SetPacket (Ptr<const Packet> p)
+  {
+    m_packet = p;
+  }
+  /**
+   * Get IPv4 header
+   * \returns the IPv4 header
+   */
+  Ipv4Header GetIpv4Header () const
+  {
+    return m_header;
+  }
+  /**
+   * Set IPv4 header
+   * \param h the IPv4 header
+   */
+  void SetIpv4Header (Ipv4Header h)
+  {
+    m_header = h;
+  }
+  /**
+   * Set expire time
+   * \param exp The expiration time
+   */
+  void SetExpireTime (Time exp)
+  {
+    m_expire = exp + Simulator::Now ();
+  }
+  /**
+   * Get expire time
+   * \returns the expiration time
+   */
+  Time GetExpireTime () const
+  {
+    return m_expire - Simulator::Now ();
+  }
+
+private:
+  /// Data packet
+  Ptr<const Packet> m_packet;
+  /// IP header
+  Ipv4Header m_header;
+  /// Unicast forward callback
+  UnicastForwardCallback m_ucb;
+  /// Error callback
+  ErrorCallback m_ecb;
+  /// Expire time for queue entry
+  Time m_expire;
+};
+/**
+ * \ingroup greyattack
+ * \brief greyattack route request queue
+ *
+ * Since greyattack is an on demand routing we queue requests while looking for route.
+ */
+class RequestQueue
+{
+public:
+  /**
+   * constructor
+   *
+   * \param maxLen the maximum length
+   * \param routeToQueueTimeout the route to queue timeout
+   */
+  RequestQueue (uint32_t maxLen, Time routeToQueueTimeout)
+    : m_maxLen (maxLen),
+      m_queueTimeout (routeToQueueTimeout)
+  {
+  }
+  /**
+   * Push entry in queue, if there is no entry with the same packet and destination address in queue.
+   * \param entry the queue entry
+   * \returns true if the entry is queued
+   */
+  bool Enqueue (QueueEntry & entry);
+  /**
+   * Return first found (the earliest) entry for given destination
+   * 
+   * \param dst the destination IP address
+   * \param entry the queue entry
+   * \returns true if the entry is dequeued
+   */
+  bool Dequeue (Ipv4Address dst, QueueEntry & entry);
+  /**
+   * Remove all packets with destination IP address dst
+   * \param dst the destination IP address
+   */
+  void DropPacketWithDst (Ipv4Address dst);
+  /**
+   * Finds whether a packet with destination dst exists in the queue
+   * 
+   * \param dst the destination IP address
+   * \returns true if an entry with the IP address is found
+   */
+  bool Find (Ipv4Address dst);
+  /**
+   * \returns the number of entries
+   */
+  uint32_t GetSize ();
+
+  // Fields
+  /**
+   * Get maximum queue length
+   * \returns the maximum queue length
+   */
+  uint32_t GetMaxQueueLen () const
+  {
+    return m_maxLen;
+  }
+  /**
+   * Set maximum queue length
+   * \param len The maximum queue length
+   */
+  void SetMaxQueueLen (uint32_t len)
+  {
+    m_maxLen = len;
+  }
+  /**
+   * Get queue timeout
+   * \returns the queue timeout
+   */
+  Time GetQueueTimeout () const
+  {
+    return m_queueTimeout;
+  }
+  /**
+   * Set queue timeout
+   * \param t The queue timeout
+   */
+  void SetQueueTimeout (Time t)
+  {
+    m_queueTimeout = t;
+  }
+
+private:
+  /// The queue
+  std::vector<QueueEntry> m_queue;
+  /// Remove all expired entries
+  void Purge ();
+  /**
+   * Notify that packet is dropped from queue by timeout
+   * \param en the queue entry to drop
+   * \param reason the reason to drop the entry
+   */
+  void Drop (QueueEntry en, std::string reason);
+  /// The maximum number of packets that we allow a routing protocol to buffer.
+  uint32_t m_maxLen;
+  /// The maximum period of time that a routing protocol is allowed to buffer a packet for, seconds.
+  Time m_queueTimeout;
+};
+
+
+}  // namespace greyattack
+}  // namespace ns3
+
+#endif /* greyattack_aodv_RQUEUE_H */
diff --git a/greyattack-module/model/greyattack-aodv-rtable.cc b/greyattack-module/model/greyattack-aodv-rtable.cc
new file mode 100644
index 0000000000000000000000000000000000000000..a254aa37fd39e1dae9f2419bc35ce7de3fab29df
--- /dev/null
+++ b/greyattack-module/model/greyattack-aodv-rtable.cc
@@ -0,0 +1,583 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2009 IITP RAS
+ *
+ * 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
+ *
+ * Based on
+ *      NS-3 greyattack
+ *
+ * Authors: Charles Hutchins
+ */
+
+#include "greyattack-aodv-rtable.h"
+#include <algorithm>
+#include <iomanip>
+#include "ns3/simulator.h"
+#include "ns3/log.h"
+
+namespace ns3 {
+
+NS_LOG_COMPONENT_DEFINE ("greyattack-aodvRoutingTable");
+
+namespace greyattackAodv {
+
+/*
+ The Routing Table
+ */
+
+RoutingTableEntry::RoutingTableEntry (Ptr<NetDevice> dev, Ipv4Address dst, bool vSeqNo, uint32_t seqNo,
+                                      Ipv4InterfaceAddress iface, uint16_t hops, Ipv4Address nextHop, Time lifetime)
+  : m_ackTimer (Timer::CANCEL_ON_DESTROY),
+    m_validSeqNo (vSeqNo),
+    m_seqNo (seqNo),
+    m_hops (hops),
+    m_lifeTime (lifetime + Simulator::Now ()),
+    m_iface (iface),
+    m_flag (VALID),
+    m_reqCount (0),
+    m_blackListState (false),
+    m_blackListTimeout (Simulator::Now ())
+{
+  m_ipv4Route = Create<Ipv4Route> ();
+  m_ipv4Route->SetDestination (dst);
+  m_ipv4Route->SetGateway (nextHop);
+  m_ipv4Route->SetSource (m_iface.GetLocal ());
+  m_ipv4Route->SetOutputDevice (dev);
+}
+
+RoutingTableEntry::~RoutingTableEntry ()
+{
+}
+
+bool
+RoutingTableEntry::InsertPrecursor (Ipv4Address id)
+{
+  NS_LOG_FUNCTION (this << id);
+  if (!LookupPrecursor (id))
+    {
+      m_precursorList.push_back (id);
+      return true;
+    }
+  else
+    {
+      return false;
+    }
+}
+
+bool
+RoutingTableEntry::LookupPrecursor (Ipv4Address id)
+{
+  NS_LOG_FUNCTION (this << id);
+  for (std::vector<Ipv4Address>::const_iterator i = m_precursorList.begin (); i
+       != m_precursorList.end (); ++i)
+    {
+      if (*i == id)
+        {
+          NS_LOG_LOGIC ("Precursor " << id << " found");
+          return true;
+        }
+    }
+  NS_LOG_LOGIC ("Precursor " << id << " not found");
+  return false;
+}
+
+bool
+RoutingTableEntry::DeletePrecursor (Ipv4Address id)
+{
+  NS_LOG_FUNCTION (this << id);
+  std::vector<Ipv4Address>::iterator i = std::remove (m_precursorList.begin (),
+                                                      m_precursorList.end (), id);
+  if (i == m_precursorList.end ())
+    {
+      NS_LOG_LOGIC ("Precursor " << id << " not found");
+      return false;
+    }
+  else
+    {
+      NS_LOG_LOGIC ("Precursor " << id << " found");
+      m_precursorList.erase (i, m_precursorList.end ());
+    }
+  return true;
+}
+
+void
+RoutingTableEntry::DeleteAllPrecursors ()
+{
+  NS_LOG_FUNCTION (this);
+  m_precursorList.clear ();
+}
+
+bool
+RoutingTableEntry::IsPrecursorListEmpty () const
+{
+  return m_precursorList.empty ();
+}
+
+void
+RoutingTableEntry::GetPrecursors (std::vector<Ipv4Address> & prec) const
+{
+  NS_LOG_FUNCTION (this);
+  if (IsPrecursorListEmpty ())
+    {
+      return;
+    }
+  for (std::vector<Ipv4Address>::const_iterator i = m_precursorList.begin (); i
+       != m_precursorList.end (); ++i)
+    {
+      bool result = true;
+      for (std::vector<Ipv4Address>::const_iterator j = prec.begin (); j
+           != prec.end (); ++j)
+        {
+          if (*j == *i)
+            {
+              result = false;
+            }
+        }
+      if (result)
+        {
+          prec.push_back (*i);
+        }
+    }
+}
+
+void
+RoutingTableEntry::Invalidate (Time badLinkLifetime)
+{
+  NS_LOG_FUNCTION (this << badLinkLifetime.As (Time::S));
+  if (m_flag == INVALID)
+    {
+      return;
+    }
+  m_flag = INVALID;
+  m_reqCount = 0;
+  m_lifeTime = badLinkLifetime + Simulator::Now ();
+}
+
+void
+RoutingTableEntry::Print (Ptr<OutputStreamWrapper> stream, Time::Unit unit /* = Time::S */) const
+{
+  std::ostream* os = stream->GetStream ();
+  // Copy the current ostream state
+  std::ios oldState (nullptr);
+  oldState.copyfmt (*os);
+
+  *os << std::resetiosflags (std::ios::adjustfield) << std::setiosflags (std::ios::left);
+
+  std::ostringstream dest, gw, iface, expire;
+  dest << m_ipv4Route->GetDestination ();
+  gw << m_ipv4Route->GetGateway ();
+  iface << m_iface.GetLocal ();
+  expire << std::setprecision (2) << (m_lifeTime - Simulator::Now ()).As (unit);
+  *os << std::setw (16) << dest.str();
+  *os << std::setw (16) << gw.str();
+  *os << std::setw (16) << iface.str();
+  *os << std::setw (16);
+  switch (m_flag)
+    {
+    case VALID:
+      {
+        *os << "UP";
+        break;
+      }
+    case INVALID:
+      {
+        *os << "DOWN";
+        break;
+      }
+    case IN_SEARCH:
+      {
+        *os << "IN_SEARCH";
+        break;
+      }
+    }
+
+  *os << std::setw (16) << expire.str();
+  *os << m_hops << std::endl;
+  // Restore the previous ostream state
+  (*os).copyfmt (oldState);
+}
+
+/*
+ The Routing Table
+ */
+
+RoutingTable::RoutingTable (Time t)
+    : m_badLinkLifetime (t),
+      m_StoreRoutesTimer (Timer::CANCEL_ON_DESTROY),
+      routePointer(0),
+      encounterRate(10),
+      routeStorageFull(false)
+{
+    m_StoreRoutesTimer.SetFunction (&RoutingTable::StoreRoutes, this);
+    m_StoreRoutesTimer.Schedule (Seconds (3));
+}
+
+void RoutingTable::StoreRoutes() {
+    NS_LOG_INFO("Routing Table Timer is Working!");
+    std::map<Ipv4Address, RoutingTableEntry> table = m_ipv4AddressEntry;
+    Purge (table);
+
+    if(!routeStorageFull) {
+        RouteStorage.push_back(table);
+        routePointer++;
+        if(routePointer == encounterRate) routeStorageFull = true;
+    }
+    else
+    {
+        RouteStorage[routePointer] = table;
+    }
+    routePointer = routePointer % encounterRate;
+    float myAER = 0.0;
+    int result = GetAER(myAER);
+
+    std::stringstream ss;
+    ss << "AER is: " << myAER << " result was: " << result;
+    NS_LOG_ERROR(ss.str());
+    m_StoreRoutesTimer.Schedule (Seconds (1));
+}
+
+int
+RoutingTable::GetAER(float &averageAER)
+{
+    // if we havent filled up the buffer yet, we can't calculate an AER value.
+    if(!routeStorageFull)
+        return 1;
+
+    std::map<Ipv4Address, RoutingTableEntry> tableEntryNow = RouteStorage[routePointer];
+    std::map<Ipv4Address, RoutingTableEntry> tableEntryPrev = RouteStorage[routePointer + 1];
+    std::vector<uint32_t> encountersNow;
+    std::vector<uint32_t> encountersPrev;
+
+    // Get the currently encountered node IDS
+    for(std::map<Ipv4Address, RoutingTableEntry>::const_iterator i =
+            tableEntryNow.begin (); i != tableEntryNow.end (); ++i){
+        uint8_t buf[4];
+        i->second.GetNextHop().Serialize(buf);
+        encountersNow.push_back (unsigned(buf[3]) - 1);
+    }
+
+    // Get the Previously encountered node IDs
+    for(std::map<Ipv4Address, RoutingTableEntry>::const_iterator i =
+            tableEntryPrev.begin (); i != tableEntryPrev.end (); ++i){
+        uint8_t buf[4];
+        i->second.GetNextHop().Serialize(buf);
+        encountersPrev.push_back (unsigned(buf[3]) - 1);
+    }
+
+    // make sure there are no duplicates within each encounter set:
+    std::set<uint32_t> s1( encountersNow.begin(), encountersNow.end() );
+    std::set<uint32_t> s2( encountersPrev.begin(), encountersPrev.end() );
+    encountersNow.assign( s1.begin(), s1.end() );
+    encountersPrev.assign( s2.begin(), s2.end() );
+
+    // Now find the intersect of the two list.
+    std::vector<uint32_t> intersected_set;
+
+    std::sort(encountersNow.begin(), encountersNow.end());
+    std::sort(encountersPrev.begin(), encountersPrev.end());
+
+    std::set_intersection(encountersNow.begin(),encountersNow.end(),
+                          encountersPrev.begin(),encountersPrev.end(),
+                          back_inserter(intersected_set));
+    uint32_t newEncounters = encountersNow.size() + encountersPrev.size() - (intersected_set.size()*2);
+    averageAER = (float)newEncounters / (float)encounterRate;
+
+    //fix AER to 1.0
+    averageAER = std::min(averageAER, (float)1.0);
+
+    return 0;
+}
+
+bool
+RoutingTable::LookupRoute (Ipv4Address id, RoutingTableEntry & rt)
+{
+  NS_LOG_FUNCTION (this << id);
+  Purge ();
+  if (m_ipv4AddressEntry.empty ())
+    {
+      NS_LOG_LOGIC ("Route to " << id << " not found; m_ipv4AddressEntry is empty");
+      return false;
+    }
+  std::map<Ipv4Address, RoutingTableEntry>::const_iterator i =
+    m_ipv4AddressEntry.find (id);
+  if (i == m_ipv4AddressEntry.end ())
+    {
+      NS_LOG_LOGIC ("Route to " << id << " not found");
+      return false;
+    }
+  rt = i->second;
+  NS_LOG_LOGIC ("Route to " << id << " found");
+  return true;
+}
+
+bool
+RoutingTable::LookupValidRoute (Ipv4Address id, RoutingTableEntry & rt)
+{
+  NS_LOG_FUNCTION (this << id);
+  if (!LookupRoute (id, rt))
+    {
+      NS_LOG_LOGIC ("Route to " << id << " not found");
+      return false;
+    }
+  NS_LOG_LOGIC ("Route to " << id << " flag is " << ((rt.GetFlag () == VALID) ? "valid" : "not valid"));
+  return (rt.GetFlag () == VALID);
+}
+
+bool
+RoutingTable::DeleteRoute (Ipv4Address dst)
+{
+  NS_LOG_FUNCTION (this << dst);
+  Purge ();
+  if (m_ipv4AddressEntry.erase (dst) != 0)
+    {
+      NS_LOG_LOGIC ("Route deletion to " << dst << " successful");
+      return true;
+    }
+  NS_LOG_LOGIC ("Route deletion to " << dst << " not successful");
+  return false;
+}
+
+bool
+RoutingTable::AddRoute (RoutingTableEntry & rt)
+{
+  NS_LOG_FUNCTION (this);
+  Purge ();
+  if (rt.GetFlag () != IN_SEARCH)
+    {
+      rt.SetRreqCnt (0);
+    }
+  std::pair<std::map<Ipv4Address, RoutingTableEntry>::iterator, bool> result =
+    m_ipv4AddressEntry.insert (std::make_pair (rt.GetDestination (), rt));
+  return result.second;
+}
+
+bool
+RoutingTable::Update (RoutingTableEntry & rt)
+{
+  NS_LOG_FUNCTION (this);
+  std::map<Ipv4Address, RoutingTableEntry>::iterator i =
+    m_ipv4AddressEntry.find (rt.GetDestination ());
+  if (i == m_ipv4AddressEntry.end ())
+    {
+      NS_LOG_LOGIC ("Route update to " << rt.GetDestination () << " fails; not found");
+      return false;
+    }
+  i->second = rt;
+  if (i->second.GetFlag () != IN_SEARCH)
+    {
+      NS_LOG_LOGIC ("Route update to " << rt.GetDestination () << " set RreqCnt to 0");
+      i->second.SetRreqCnt (0);
+    }
+  return true;
+}
+
+bool
+RoutingTable::SetEntryState (Ipv4Address id, RouteFlags state)
+{
+  NS_LOG_FUNCTION (this);
+  std::map<Ipv4Address, RoutingTableEntry>::iterator i =
+    m_ipv4AddressEntry.find (id);
+  if (i == m_ipv4AddressEntry.end ())
+    {
+      NS_LOG_LOGIC ("Route set entry state to " << id << " fails; not found");
+      return false;
+    }
+  i->second.SetFlag (state);
+  i->second.SetRreqCnt (0);
+  NS_LOG_LOGIC ("Route set entry state to " << id << ": new state is " << state);
+  return true;
+}
+
+void
+RoutingTable::GetListOfDestinationWithNextHop (Ipv4Address nextHop, std::map<Ipv4Address, uint32_t> & unreachable )
+{
+  NS_LOG_FUNCTION (this);
+  Purge ();
+  unreachable.clear ();
+  for (std::map<Ipv4Address, RoutingTableEntry>::const_iterator i =
+         m_ipv4AddressEntry.begin (); i != m_ipv4AddressEntry.end (); ++i)
+    {
+      if (i->second.GetNextHop () == nextHop)
+        {
+          NS_LOG_LOGIC ("Unreachable insert " << i->first << " " << i->second.GetSeqNo ());
+          unreachable.insert (std::make_pair (i->first, i->second.GetSeqNo ()));
+        }
+    }
+}
+
+void
+RoutingTable::InvalidateRoutesWithDst (const std::map<Ipv4Address, uint32_t> & unreachable)
+{
+  NS_LOG_FUNCTION (this);
+  Purge ();
+  for (std::map<Ipv4Address, RoutingTableEntry>::iterator i =
+         m_ipv4AddressEntry.begin (); i != m_ipv4AddressEntry.end (); ++i)
+    {
+      for (std::map<Ipv4Address, uint32_t>::const_iterator j =
+             unreachable.begin (); j != unreachable.end (); ++j)
+        {
+          if ((i->first == j->first) && (i->second.GetFlag () == VALID))
+            {
+              NS_LOG_LOGIC ("Invalidate route with destination address " << i->first);
+              i->second.Invalidate (m_badLinkLifetime);
+            }
+        }
+    }
+}
+
+void
+RoutingTable::DeleteAllRoutesFromInterface (Ipv4InterfaceAddress iface)
+{
+  NS_LOG_FUNCTION (this);
+  if (m_ipv4AddressEntry.empty ())
+    {
+      return;
+    }
+  for (std::map<Ipv4Address, RoutingTableEntry>::iterator i =
+         m_ipv4AddressEntry.begin (); i != m_ipv4AddressEntry.end (); )
+    {
+      if (i->second.GetInterface () == iface)
+        {
+          std::map<Ipv4Address, RoutingTableEntry>::iterator tmp = i;
+          ++i;
+          m_ipv4AddressEntry.erase (tmp);
+        }
+      else
+        {
+          ++i;
+        }
+    }
+}
+
+void
+RoutingTable::Purge ()
+{
+  NS_LOG_FUNCTION (this);
+  if (m_ipv4AddressEntry.empty ())
+    {
+      return;
+    }
+  for (std::map<Ipv4Address, RoutingTableEntry>::iterator i =
+         m_ipv4AddressEntry.begin (); i != m_ipv4AddressEntry.end (); )
+    {
+      if (i->second.GetLifeTime () < Seconds (0))
+        {
+          if (i->second.GetFlag () == INVALID)
+            {
+              std::map<Ipv4Address, RoutingTableEntry>::iterator tmp = i;
+              ++i;
+              m_ipv4AddressEntry.erase (tmp);
+            }
+          else if (i->second.GetFlag () == VALID)
+            {
+              NS_LOG_LOGIC ("Invalidate route with destination address " << i->first);
+              i->second.Invalidate (m_badLinkLifetime);
+              ++i;
+            }
+          else
+            {
+              ++i;
+            }
+        }
+      else
+        {
+          ++i;
+        }
+    }
+}
+
+void
+RoutingTable::Purge (std::map<Ipv4Address, RoutingTableEntry> &table) const
+{
+  NS_LOG_FUNCTION (this);
+  if (table.empty ())
+    {
+      return;
+    }
+  for (std::map<Ipv4Address, RoutingTableEntry>::iterator i =
+         table.begin (); i != table.end (); )
+    {
+      if (i->second.GetLifeTime () < Seconds (0))
+        {
+          if (i->second.GetFlag () == INVALID)
+            {
+              std::map<Ipv4Address, RoutingTableEntry>::iterator tmp = i;
+              ++i;
+              table.erase (tmp);
+            }
+          else if (i->second.GetFlag () == VALID)
+            {
+              NS_LOG_LOGIC ("Invalidate route with destination address " << i->first);
+              i->second.Invalidate (m_badLinkLifetime);
+              ++i;
+            }
+          else
+            {
+              ++i;
+            }
+        }
+      else
+        {
+          ++i;
+        }
+    }
+}
+
+bool
+RoutingTable::MarkLinkAsUnidirectional (Ipv4Address neighbor, Time blacklistTimeout)
+{
+  NS_LOG_FUNCTION (this << neighbor << blacklistTimeout.As (Time::S));
+  std::map<Ipv4Address, RoutingTableEntry>::iterator i =
+    m_ipv4AddressEntry.find (neighbor);
+  if (i == m_ipv4AddressEntry.end ())
+    {
+      NS_LOG_LOGIC ("Mark link unidirectional to  " << neighbor << " fails; not found");
+      return false;
+    }
+  i->second.SetUnidirectional (true);
+  i->second.SetBlacklistTimeout (blacklistTimeout);
+  i->second.SetRreqCnt (0);
+  NS_LOG_LOGIC ("Set link to " << neighbor << " to unidirectional");
+  return true;
+}
+
+void
+RoutingTable::Print (Ptr<OutputStreamWrapper> stream, Time::Unit unit /* = Time::S */) const
+{
+  std::map<Ipv4Address, RoutingTableEntry> table = m_ipv4AddressEntry;
+  Purge (table);
+  std::ostream* os = stream->GetStream ();
+  // Copy the current ostream state
+  std::ios oldState (nullptr);
+  oldState.copyfmt (*os);
+
+  *os << std::resetiosflags (std::ios::adjustfield) << std::setiosflags (std::ios::left);
+  *os << "\nAODV Routing table\n";
+  *os << std::setw (16) << "Destination";
+  *os << std::setw (16) << "Gateway";
+  *os << std::setw (16) << "Interface";
+  *os << std::setw (16) << "Flag";
+  *os << std::setw (16) << "Expire";
+  *os << "Hops" << std::endl;
+  for (std::map<Ipv4Address, RoutingTableEntry>::const_iterator i =
+         table.begin (); i != table.end (); ++i)
+    {
+      i->second.Print (stream, unit);
+    }
+  *stream->GetStream () << "\n";
+}
+
+}
+}
diff --git a/greyattack-module/model/greyattack-aodv-rtable.h b/greyattack-module/model/greyattack-aodv-rtable.h
new file mode 100644
index 0000000000000000000000000000000000000000..6dc1c3cc907018979625f86b65631c4819a8d567
--- /dev/null
+++ b/greyattack-module/model/greyattack-aodv-rtable.h
@@ -0,0 +1,527 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2009 IITP RAS
+ *
+ * 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
+ *
+ * Based on
+ *      NS-3 greyattack
+ *
+ * Authors: Charles Hutchins
+ */
+#ifndef greyattack_aodv_RTABLE_H
+#define greyattack_aodv_RTABLE_H
+
+#include <stdint.h>
+#include <cassert>
+#include <map>
+#include <sys/types.h>
+#include "ns3/ipv4.h"
+#include "ns3/ipv4-route.h"
+#include "ns3/timer.h"
+#include "ns3/net-device.h"
+#include "ns3/output-stream-wrapper.h"
+
+namespace ns3 {
+namespace greyattackAodv {
+
+/**
+ * \ingroup greyattack
+ * \brief Route record states
+ */
+enum RouteFlags
+{
+  VALID = 0,          //!< VALID
+  INVALID = 1,        //!< INVALID
+  IN_SEARCH = 2,      //!< IN_SEARCH
+};
+
+/**
+ * \ingroup greyattack
+ * \brief Routing table entry
+ */
+class RoutingTableEntry
+{
+public:
+  /**
+   * constructor
+   *
+   * \param dev the device
+   * \param dst the destination IP address
+   * \param vSeqNo verify sequence number flag
+   * \param seqNo the sequence number
+   * \param iface the interface
+   * \param hops the number of hops
+   * \param nextHop the IP address of the next hop
+   * \param lifetime the lifetime of the entry
+   * \param interaction the number of iteractions with this node
+   */
+  RoutingTableEntry (Ptr<NetDevice> dev = 0,Ipv4Address dst = Ipv4Address (), bool vSeqNo = false, uint32_t seqNo = 0,
+                     Ipv4InterfaceAddress iface = Ipv4InterfaceAddress (), uint16_t  hops = 0,
+                     Ipv4Address nextHop = Ipv4Address (), Time lifetime = Simulator::Now ());
+
+  ~RoutingTableEntry ();
+
+  ///\name Precursors management
+  //\{
+  /**
+   * Insert precursor in precursor list if it doesn't yet exist in the list
+   * \param id precursor address
+   * \return true on success
+   */
+  bool InsertPrecursor (Ipv4Address id);
+  /**
+   * Lookup precursor by address
+   * \param id precursor address
+   * \return true on success
+   */
+  bool LookupPrecursor (Ipv4Address id);
+  /**
+   * \brief Delete precursor
+   * \param id precursor address
+   * \return true on success
+   */
+  bool DeletePrecursor (Ipv4Address id);
+  /// Delete all precursors
+  void DeleteAllPrecursors ();
+  /**
+   * Check that precursor list is empty
+   * \return true if precursor list is empty
+   */
+  bool IsPrecursorListEmpty () const;
+  /**
+   * Inserts precursors in output parameter prec if they do not yet exist in vector
+   * \param prec vector of precursor addresses
+   */
+  void GetPrecursors (std::vector<Ipv4Address> & prec) const;
+  //\}
+
+  /**
+   * Mark entry as "down" (i.e. disable it)
+   * \param badLinkLifetime duration to keep entry marked as invalid
+   */
+  void Invalidate (Time badLinkLifetime);
+
+  // Fields
+  /**
+   * Get destination address function
+   * \returns the IPv4 destination address
+   */
+  Ipv4Address GetDestination () const
+  {
+    return m_ipv4Route->GetDestination ();
+  }
+  /**
+   * Get route function
+   * \returns The IPv4 route
+   */
+  Ptr<Ipv4Route> GetRoute () const
+  {
+    return m_ipv4Route;
+  }
+  /**
+   * Set route function
+   * \param r the IPv4 route
+   */
+  void SetRoute (Ptr<Ipv4Route> r)
+  {
+    m_ipv4Route = r;
+  }
+  /**
+   * Set next hop address
+   * \param nextHop the next hop IPv4 address
+   */
+  void SetNextHop (Ipv4Address nextHop)
+  {
+    m_ipv4Route->SetGateway (nextHop);
+  }
+  /**
+   * Get next hop address
+   * \returns the next hop address
+   */
+  Ipv4Address GetNextHop () const
+  {
+    return m_ipv4Route->GetGateway ();
+  }
+  /**
+   * Set output device
+   * \param dev The output device
+   */
+  void SetOutputDevice (Ptr<NetDevice> dev)
+  {
+    m_ipv4Route->SetOutputDevice (dev);
+  }
+  /**
+   * Get output device
+   * \returns the output device
+   */
+  Ptr<NetDevice> GetOutputDevice () const
+  {
+    return m_ipv4Route->GetOutputDevice ();
+  }
+  /**
+   * Get the Ipv4InterfaceAddress
+   * \returns the Ipv4InterfaceAddress
+   */
+  Ipv4InterfaceAddress GetInterface () const
+  {
+    return m_iface;
+  }
+  /**
+   * Set the Ipv4InterfaceAddress
+   * \param iface The Ipv4InterfaceAddress
+   */
+  void SetInterface (Ipv4InterfaceAddress iface)
+  {
+    m_iface = iface;
+  }
+  /**
+   * Set the valid sequence number
+   * \param s the sequence number
+   */
+  void SetValidSeqNo (bool s)
+  {
+    m_validSeqNo = s;
+  }
+  /**
+   * Get the valid sequence number
+   * \returns the valid sequence number
+   */
+  bool GetValidSeqNo () const
+  {
+    return m_validSeqNo;
+  }
+  /**
+   * Set the sequence number
+   * \param sn the sequence number
+   */
+  void SetSeqNo (uint32_t sn)
+  {
+    m_seqNo = sn;
+  }
+  /**
+   * Get the sequence number
+   * \returns the sequence number
+   */
+  uint32_t GetSeqNo () const
+  {
+    return m_seqNo;
+  }
+  /**
+   * Set the number of hops
+   * \param hop the number of hops
+   */
+  void SetHop (uint16_t hop)
+  {
+    m_hops = hop;
+  }
+  /**
+   * Get the number of hops
+   * \returns the number of hops
+   */
+  uint16_t GetHop () const
+  {
+    return m_hops;
+  }
+  /**
+   * Set the lifetime
+   * \param lt The lifetime
+   */
+  void SetLifeTime (Time lt)
+  {
+    m_lifeTime = lt + Simulator::Now ();
+  }
+  /**
+   * Get the lifetime
+   * \returns the lifetime
+   */
+  Time GetLifeTime () const
+  {
+    return m_lifeTime - Simulator::Now ();
+  }
+  /**
+   * Set the route flags
+   * \param flag the route flags
+   */
+  void SetFlag (RouteFlags flag)
+  {
+    m_flag = flag;
+  }
+  /**
+   * Get the route flags
+   * \returns the route flags
+   */
+  RouteFlags GetFlag () const
+  {
+    return m_flag;
+  }
+  /**
+   * Set the RREQ count
+   * \param n the RREQ count
+   */
+  void SetRreqCnt (uint8_t n)
+  {
+    m_reqCount = n;
+  }
+  /**
+   * Get the RREQ count
+   * \returns the RREQ count
+   */
+  uint8_t GetRreqCnt () const
+  {
+    return m_reqCount;
+  }
+  /**
+   * Increment the RREQ count
+   */
+  void IncrementRreqCnt ()
+  {
+    m_reqCount++;
+  }
+  /**
+   * Set the unidirectional flag
+   * \param u the uni directional flag
+   */
+  void SetUnidirectional (bool u)
+  {
+    m_blackListState = u;
+  }
+  /**
+   * Get the unidirectional flag
+   * \returns the unidirectional flag
+   */
+  bool IsUnidirectional () const
+  {
+    return m_blackListState;
+  }
+  /**
+   * Set the blacklist timeout
+   * \param t the blacklist timeout value
+   */
+  void SetBlacklistTimeout (Time t)
+  {
+    m_blackListTimeout = t;
+  }
+  /**
+   * Get the blacklist timeout value
+   * \returns the blacklist timeout value
+   */
+  Time GetBlacklistTimeout () const
+  {
+    return m_blackListTimeout;
+  }
+  /// RREP_ACK timer
+  Timer m_ackTimer;
+
+  /**
+   * \brief Compare destination address
+   * \param dst IP address to compare
+   * \return true if equal
+   */
+  bool operator== (Ipv4Address const  dst) const
+  {
+    return (m_ipv4Route->GetDestination () == dst);
+  }
+  /**
+   * Print packet to trace file
+   * \param stream The output stream
+   * \param unit The time unit to use (default Time::S)
+   */
+  void Print (Ptr<OutputStreamWrapper> stream, Time::Unit unit = Time::S) const;
+
+private:
+  /// Valid Destination Sequence Number flag
+  bool m_validSeqNo;
+  /// Destination Sequence Number, if m_validSeqNo = true
+  uint32_t m_seqNo;
+  /// Hop Count (number of hops needed to reach destination)
+  uint16_t m_hops;
+  /**
+  * \brief Expiration or deletion time of the route
+  *	Lifetime field in the routing table plays dual role:
+  *	for an active route it is the expiration time, and for an invalid route
+  *	it is the deletion time.
+  */
+  Time m_lifeTime;
+  /** Ip route, include
+   *   - destination address
+   *   - source address
+   *   - next hop address (gateway)
+   *   - output device
+   */
+  Ptr<Ipv4Route> m_ipv4Route;
+  /// Output interface address
+  Ipv4InterfaceAddress m_iface;
+  /// Routing flags: valid, invalid or in search
+  RouteFlags m_flag;
+
+  /// List of precursors
+  std::vector<Ipv4Address> m_precursorList;
+  /// When I can send another request
+  Time m_routeRequestTimout;
+  /// Number of route requests
+  uint8_t m_reqCount;
+  /// Indicate if this entry is in "blacklist"
+  bool m_blackListState;
+  /// Time for which the node is put into the blacklist
+  Time m_blackListTimeout;
+};
+
+/**
+ * \ingroup greyattack
+ * \brief The Routing table used by greyattack protocol
+ */
+class RoutingTable
+{
+public:
+  /**
+   * constructor
+   * \param t the routing table entry lifetime
+   */
+  RoutingTable (Time t);
+  ///\name Handle lifetime of invalid route
+  //\{
+  /**
+   * Get the lifetime of a bad link
+   *
+   * \return the lifetime of a bad link
+   */
+  Time GetBadLinkLifetime () const
+  {
+    return m_badLinkLifetime;
+  }
+  /**
+   * Set the lifetime of a bad link
+   *
+   * \param t the lifetime of a bad link
+   */
+  void SetBadLinkLifetime (Time t)
+  {
+    m_badLinkLifetime = t;
+  }
+  
+  
+  //\}
+  /**
+   * Add routing table entry if it doesn't yet exist in routing table
+   * \param r routing table entry
+   * \return true in success
+   */
+  bool AddRoute (RoutingTableEntry & r);
+  /**
+   * Delete routing table entry with destination address dst, if it exists.
+   * \param dst destination address
+   * \return true on success
+   */
+  bool DeleteRoute (Ipv4Address dst);
+  /**
+   * Lookup routing table entry with destination address dst
+   * \param dst destination address
+   * \param rt entry with destination address dst, if exists
+   * \return true on success
+   */
+  bool LookupRoute (Ipv4Address dst, RoutingTableEntry & rt);
+  /**
+   * Lookup route in VALID state
+   * \param dst destination address
+   * \param rt entry with destination address dst, if exists
+   * \return true on success
+   */
+  bool LookupValidRoute (Ipv4Address dst, RoutingTableEntry & rt);
+  /**
+   * Update routing table
+   * \param rt entry with destination address dst, if exists
+   * \return true on success
+   */
+  bool Update (RoutingTableEntry & rt);
+  /**
+   * Set routing table entry flags
+   * \param dst destination address
+   * \param state the routing flags
+   * \return true on success
+   */
+  bool SetEntryState (Ipv4Address dst, RouteFlags state);
+  /**
+   * Lookup routing entries with next hop Address dst and not empty list of precursors.
+   *
+   * \param nextHop the next hop IP address
+   * \param unreachable
+   */
+  void GetListOfDestinationWithNextHop (Ipv4Address nextHop, std::map<Ipv4Address, uint32_t> & unreachable);
+  /**
+   *   Update routing entries with this destination as follows:
+   *  1. The destination sequence number of this routing entry, if it
+   *     exists and is valid, is incremented.
+   *  2. The entry is invalidated by marking the route entry as invalid
+   *  3. The Lifetime field is updated to current time plus DELETE_PERIOD.
+   *  \param unreachable routes to invalidate
+   */
+  void InvalidateRoutesWithDst (std::map<Ipv4Address, uint32_t> const & unreachable);
+  /**
+   * Delete all route from interface with address iface
+   * \param iface the interface IP address
+   */
+  void DeleteAllRoutesFromInterface (Ipv4InterfaceAddress iface);
+  /// Delete all entries from routing table
+  void Clear ()
+  {
+    m_ipv4AddressEntry.clear ();
+  }
+  /// Delete all outdated entries and invalidate valid entry if Lifetime is expired
+  void Purge ();
+  /** Mark entry as unidirectional (e.g. add this neighbor to "blacklist" for blacklistTimeout period)
+   * \param neighbor - neighbor address link to which assumed to be unidirectional
+   * \param blacklistTimeout - time for which the neighboring node is put into the blacklist
+   * \return true on success
+   */
+  bool MarkLinkAsUnidirectional (Ipv4Address neighbor, Time blacklistTimeout);
+  /**
+   * Print routing table
+   * \param stream the output stream
+   * \param unit The time unit to use (default Time::S)
+   */
+  void Print (Ptr<OutputStreamWrapper> stream, Time::Unit unit = Time::S) const;
+
+    /**
+         *
+         * @param averageAER - the average encounter rate
+         * @return - 1 on error (such as the buffer is not big enough yet to caluclate a value) and 0 for success
+         */
+    int GetAER(float &averageAER);
+
+private:
+  /// The routing table
+  std::map<Ipv4Address, RoutingTableEntry> m_ipv4AddressEntry;
+  /// Deletion time for invalid routes
+  Time m_badLinkLifetime;
+    // Timer used to store the route table every second or so.
+    Timer m_StoreRoutesTimer;
+    // vector to store the routes
+    std::vector<std::map<Ipv4Address, RoutingTableEntry>> RouteStorage;
+    uint32_t routePointer;
+    uint32_t encounterRate;
+    bool routeStorageFull;
+  /**
+   * const version of Purge, for use by Print() method
+   * \param table the routing table entry to purge
+   */
+  void Purge (std::map<Ipv4Address, RoutingTableEntry> &table) const;
+
+    void StoreRoutes();
+};
+
+}  // namespace greyattack-aodv
+}  // namespace ns3
+
+#endif /* greyattack_aodv_RTABLE_H */
diff --git a/greyattack-module/model/greyattack-aodv.cc b/greyattack-module/model/greyattack-aodv.cc
new file mode 100644
index 0000000000000000000000000000000000000000..95b48aa32240da0162db0a4749a2ada215f41225
--- /dev/null
+++ b/greyattack-module/model/greyattack-aodv.cc
@@ -0,0 +1,14 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+
+#include "greyattack-aodv.h"
+
+namespace ns3 {
+
+/* ... */
+
+namespace greyattackAodv{
+
+}
+
+
+}
\ No newline at end of file
diff --git a/greyattack-module/model/greyattack-aodv.h b/greyattack-module/model/greyattack-aodv.h
new file mode 100644
index 0000000000000000000000000000000000000000..81238ce11940dbc87bb36cb21bb57241d99b1aae
--- /dev/null
+++ b/greyattack-module/model/greyattack-aodv.h
@@ -0,0 +1,11 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+#ifndef GREYATTACK_AODV_H
+#define GREYATTACK_AODV_H
+
+namespace ns3 {
+
+/* ... */
+
+}
+
+#endif /* GREYATTACK_AODV_H */
diff --git a/greyattack-module/test/examples-to-run.py b/greyattack-module/test/examples-to-run.py
new file mode 100644
index 0000000000000000000000000000000000000000..4ffeed82bfded5492ba11ddc901f60d13e33ae39
--- /dev/null
+++ b/greyattack-module/test/examples-to-run.py
@@ -0,0 +1,20 @@
+#! /usr/bin/env python3
+## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
+
+# A list of C++ examples to run in order to ensure that they remain
+# buildable and runnable over time.  Each tuple in the list contains
+#
+#     (example_name, do_run, do_valgrind_run).
+#
+# See test.py for more information.
+cpp_examples = [
+    ("aodvKmeans", "True", "True"),
+]
+
+# A list of Python examples to run in order to ensure that they remain
+# runnable over time.  Each tuple in the list contains
+#
+#     (example_name, do_run).
+#
+# See test.py for more information.
+python_examples = []
diff --git a/greyattack-module/test/greyattack-aodv-id-cache-test-suite.cc b/greyattack-module/test/greyattack-aodv-id-cache-test-suite.cc
new file mode 100644
index 0000000000000000000000000000000000000000..0e11ea4706abca972ca86bd3681794164be033c4
--- /dev/null
+++ b/greyattack-module/test/greyattack-aodv-id-cache-test-suite.cc
@@ -0,0 +1,119 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2009 IITP RAS
+ *
+ * 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
+ *
+ * Based on
+ *      NS-2 greyattack model developed by
+ *
+ * Authors: Charles Hutchins
+ */
+#include "ns3/greyattack-aodv-id-cache.h"
+#include "ns3/test.h"
+
+namespace ns3 {
+namespace greyattackAodv {
+
+/**
+ * \ingroup greyattack
+ * \defgroup greyattack-test greyattack module tests
+ */
+
+
+/**
+ * \ingroup greyattack-test
+ * \ingroup tests
+ *
+ * \brief Unit test for id cache
+ */
+class IdCacheTest : public TestCase
+{
+public:
+  IdCacheTest () : TestCase ("Id Cache"),
+                   cache (Seconds (10))
+  {
+  }
+  virtual void DoRun ();
+
+private:
+  /// Timeout test function #1
+  void CheckTimeout1 ();
+  /// Timeout test function #2
+  void CheckTimeout2 ();
+  /// Timeout test function #3
+  void CheckTimeout3 ();
+
+  /// ID cache
+  IdCache cache;
+};
+
+void
+IdCacheTest::DoRun ()
+{
+  NS_TEST_EXPECT_MSG_EQ (cache.GetLifeTime (), Seconds (10), "Lifetime");
+  NS_TEST_EXPECT_MSG_EQ (cache.IsDuplicate (Ipv4Address ("1.2.3.4"), 3), false, "Unknown ID & address");
+  NS_TEST_EXPECT_MSG_EQ (cache.IsDuplicate (Ipv4Address ("1.2.3.4"), 4), false, "Unknown ID");
+  NS_TEST_EXPECT_MSG_EQ (cache.IsDuplicate (Ipv4Address ("4.3.2.1"), 3), false, "Unknown address");
+  NS_TEST_EXPECT_MSG_EQ (cache.IsDuplicate (Ipv4Address ("1.2.3.4"), 3), true, "Known address & ID");
+  cache.SetLifetime (Seconds (15));
+  NS_TEST_EXPECT_MSG_EQ (cache.GetLifeTime (), Seconds (15), "New lifetime");
+  cache.IsDuplicate (Ipv4Address ("1.1.1.1"), 4);
+  cache.IsDuplicate (Ipv4Address ("1.1.1.1"), 4);
+  cache.IsDuplicate (Ipv4Address ("2.2.2.2"), 5);
+  cache.IsDuplicate (Ipv4Address ("3.3.3.3"), 6);
+  NS_TEST_EXPECT_MSG_EQ (cache.GetSize (), 6, "trivial");
+
+  Simulator::Schedule (Seconds (5), &IdCacheTest::CheckTimeout1, this);
+  Simulator::Schedule (Seconds (11), &IdCacheTest::CheckTimeout2, this);
+  Simulator::Schedule (Seconds (30), &IdCacheTest::CheckTimeout3, this);
+  Simulator::Run ();
+  Simulator::Destroy ();
+}
+
+void
+IdCacheTest::CheckTimeout1 ()
+{
+  NS_TEST_EXPECT_MSG_EQ (cache.GetSize (), 6, "Nothing expire");
+}
+
+void
+IdCacheTest::CheckTimeout2 ()
+{
+  NS_TEST_EXPECT_MSG_EQ (cache.GetSize (), 3, "3 records left");
+}
+
+void
+IdCacheTest::CheckTimeout3 ()
+{
+  NS_TEST_EXPECT_MSG_EQ (cache.GetSize (), 0, "All records expire");
+}
+
+/**
+ * \ingroup greyattack-test
+ * \ingroup tests
+ *
+ * \brief Id Cache Test Suite
+ */
+class IdCacheTestSuite : public TestSuite
+{
+public:
+  IdCacheTestSuite () : TestSuite ("greyattack-routing-id-cache", UNIT)
+  {
+    AddTestCase (new IdCacheTest, TestCase::QUICK);
+  }
+} g_idCacheTestSuite; ///< the test suite
+
+}  // namespace greyattack
+}  // namespace ns3
diff --git a/greyattack-module/test/greyattack-aodv-test-suite.cc b/greyattack-module/test/greyattack-aodv-test-suite.cc
new file mode 100644
index 0000000000000000000000000000000000000000..7c00c33233200efcdd0e135263fe80582e7bd821
--- /dev/null
+++ b/greyattack-module/test/greyattack-aodv-test-suite.cc
@@ -0,0 +1,669 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2009 IITP RAS
+ *
+ * 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
+ *
+ * Authors: Pavel Boyko <boyko@iitp.ru>
+ */
+#include "ns3/test.h"
+#include "ns3/greyattack-aodv-neighbor.h"
+#include "ns3/greyattack-aodv-packet.h"
+#include "ns3/greyattack-aodv-rqueue.h"
+#include "ns3/greyattack-aodv-rtable.h"
+#include "ns3/ipv4-route.h"
+
+namespace ns3 {
+namespace greyattackAodv {
+
+/**
+ * \ingroup greyattack-test
+ * \ingroup tests
+ *
+ * \brief Unit test for neighbors
+ */
+struct NeighborTest : public TestCase
+{
+  NeighborTest () : TestCase ("Neighbor"),
+                    neighbor (0)
+  {
+  }
+  virtual void DoRun ();
+  /**
+   * Handler test function
+   * \param addr the IPv4 address of the neighbor
+   */
+  void Handler (Ipv4Address addr);
+  /// Check timeout function 1
+  void CheckTimeout1 ();
+  /// Check timeout function 2
+  void CheckTimeout2 ();
+  /// Check timeout function 3
+  void CheckTimeout3 ();
+  /// The Neighbors
+  Neighbors * neighbor;
+};
+
+void
+NeighborTest::Handler (Ipv4Address addr)
+{
+}
+
+void
+NeighborTest::CheckTimeout1 ()
+{
+  NS_TEST_EXPECT_MSG_EQ (neighbor->IsNeighbor (Ipv4Address ("1.2.3.4")), true, "Neighbor exists");
+  NS_TEST_EXPECT_MSG_EQ (neighbor->IsNeighbor (Ipv4Address ("1.1.1.1")), true, "Neighbor exists");
+  NS_TEST_EXPECT_MSG_EQ (neighbor->IsNeighbor (Ipv4Address ("2.2.2.2")), true, "Neighbor exists");
+  NS_TEST_EXPECT_MSG_EQ (neighbor->IsNeighbor (Ipv4Address ("3.3.3.3")), true, "Neighbor exists");
+}
+void
+NeighborTest::CheckTimeout2 ()
+{
+  NS_TEST_EXPECT_MSG_EQ (neighbor->IsNeighbor (Ipv4Address ("1.2.3.4")), false, "Neighbor doesn't exist");
+  NS_TEST_EXPECT_MSG_EQ (neighbor->IsNeighbor (Ipv4Address ("1.1.1.1")), false, "Neighbor doesn't exist");
+  NS_TEST_EXPECT_MSG_EQ (neighbor->IsNeighbor (Ipv4Address ("2.2.2.2")), false, "Neighbor doesn't exist");
+  NS_TEST_EXPECT_MSG_EQ (neighbor->IsNeighbor (Ipv4Address ("3.3.3.3")), true, "Neighbor exists");
+}
+void
+NeighborTest::CheckTimeout3 ()
+{
+  NS_TEST_EXPECT_MSG_EQ (neighbor->IsNeighbor (Ipv4Address ("1.2.3.4")), false, "Neighbor doesn't exist");
+  NS_TEST_EXPECT_MSG_EQ (neighbor->IsNeighbor (Ipv4Address ("1.1.1.1")), false, "Neighbor doesn't exist");
+  NS_TEST_EXPECT_MSG_EQ (neighbor->IsNeighbor (Ipv4Address ("2.2.2.2")), false, "Neighbor doesn't exist");
+  NS_TEST_EXPECT_MSG_EQ (neighbor->IsNeighbor (Ipv4Address ("3.3.3.3")), false, "Neighbor doesn't exist");
+}
+
+void
+NeighborTest::DoRun ()
+{
+  Neighbors nb (Seconds (1));
+  neighbor = &nb;
+  neighbor->SetCallback (MakeCallback (&NeighborTest::Handler, this));
+  neighbor->Update (Ipv4Address ("1.2.3.4"), Seconds (1));
+  NS_TEST_EXPECT_MSG_EQ (neighbor->IsNeighbor (Ipv4Address ("1.2.3.4")), true, "Neighbor exists");
+  NS_TEST_EXPECT_MSG_EQ (neighbor->IsNeighbor (Ipv4Address ("4.3.2.1")), false, "Neighbor doesn't exist");
+  neighbor->Update (Ipv4Address ("1.2.3.4"), Seconds (10));
+  NS_TEST_EXPECT_MSG_EQ (neighbor->IsNeighbor (Ipv4Address ("1.2.3.4")), true, "Neighbor exists");
+  NS_TEST_EXPECT_MSG_EQ (neighbor->GetExpireTime (Ipv4Address ("1.2.3.4")), Seconds (10), "Known expire time");
+  NS_TEST_EXPECT_MSG_EQ (neighbor->GetExpireTime (Ipv4Address ("4.3.2.1")), Seconds (0), "Known expire time");
+  neighbor->Update (Ipv4Address ("1.1.1.1"), Seconds (5));
+  neighbor->Update (Ipv4Address ("2.2.2.2"), Seconds (10));
+  neighbor->Update (Ipv4Address ("3.3.3.3"), Seconds (20));
+
+  Simulator::Schedule (Seconds (2), &NeighborTest::CheckTimeout1, this);
+  Simulator::Schedule (Seconds (15), &NeighborTest::CheckTimeout2, this);
+  Simulator::Schedule (Seconds (30), &NeighborTest::CheckTimeout3, this);
+  Simulator::Run ();
+  Simulator::Destroy ();
+}
+
+/**
+ * \ingroup greyattack-test
+ * \ingroup tests
+ *
+ * \brief Type header test case
+ */
+struct TypeHeaderTest : public TestCase
+{
+  TypeHeaderTest () : TestCase ("greyattack TypeHeader")
+  {
+  }
+  virtual void DoRun ()
+  {
+    TypeHeader h (greyattackTYPE_RREQ);
+    NS_TEST_EXPECT_MSG_EQ (h.IsValid (), true, "Default header is valid");
+    NS_TEST_EXPECT_MSG_EQ (h.Get (), greyattackTYPE_RREQ, "Default header is RREQ");
+
+    Ptr<Packet> p = Create<Packet> ();
+    p->AddHeader (h);
+    TypeHeader h2 (greyattackTYPE_RREP);
+    uint32_t bytes = p->RemoveHeader (h2);
+    NS_TEST_EXPECT_MSG_EQ (bytes, 1, "Type header is 1 byte long");
+    NS_TEST_EXPECT_MSG_EQ (h, h2, "Round trip serialization works");
+  }
+};
+
+/**
+ * \ingroup greyattack-test
+ * \ingroup tests
+ *
+ * \brief Unit test for RREQ
+ */
+struct RreqHeaderTest : public TestCase
+{
+  RreqHeaderTest () : TestCase ("greyattack RREQ")
+  {
+  }
+  virtual void DoRun ()
+  {
+    RreqHeader h (/*flags*/ 0, /*reserved*/ 0, /*hopCount*/ 6, /*requestID*/ 1, /*dst*/ Ipv4Address ("1.2.3.4"),
+                            /*dstSeqNo*/ 40, /*origin*/ Ipv4Address ("4.3.2.1"), /*originSeqNo*/ 10);
+    NS_TEST_EXPECT_MSG_EQ (h.GetGratuitousRrep (), false, "trivial");
+    NS_TEST_EXPECT_MSG_EQ (h.GetDestinationOnly (), false, "trivial");
+    NS_TEST_EXPECT_MSG_EQ (h.GetHopCount (), 6, "trivial");
+    NS_TEST_EXPECT_MSG_EQ (h.GetId (), 1, "trivial");
+    NS_TEST_EXPECT_MSG_EQ (h.GetDst (), Ipv4Address ("1.2.3.4"), "trivial");
+    NS_TEST_EXPECT_MSG_EQ (h.GetDstSeqno (), 40, "trivial");
+    NS_TEST_EXPECT_MSG_EQ (h.GetOrigin (), Ipv4Address ("4.3.2.1"), "trivial");
+    NS_TEST_EXPECT_MSG_EQ (h.GetOriginSeqno (), 10, "trivial");
+
+    h.SetGratuitousRrep (true);
+    NS_TEST_EXPECT_MSG_EQ (h.GetGratuitousRrep (), true, "trivial");
+    h.SetDestinationOnly (true);
+    NS_TEST_EXPECT_MSG_EQ (h.GetDestinationOnly (), true, "trivial");
+    h.SetUnknownSeqno (true);
+    NS_TEST_EXPECT_MSG_EQ (h.GetUnknownSeqno (), true, "trivial");
+    h.SetDst (Ipv4Address ("1.1.1.1"));
+    NS_TEST_EXPECT_MSG_EQ (h.GetDst (), Ipv4Address ("1.1.1.1"), "trivial");
+    h.SetDstSeqno (5);
+    NS_TEST_EXPECT_MSG_EQ (h.GetDstSeqno (), 5, "trivial");
+    h.SetHopCount (7);
+    NS_TEST_EXPECT_MSG_EQ (h.GetHopCount (), 7, "trivial");
+    h.SetId (55);
+    NS_TEST_EXPECT_MSG_EQ (h.GetId (), 55, "trivial");
+    h.SetOrigin (Ipv4Address ("4.4.4.4"));
+    NS_TEST_EXPECT_MSG_EQ (h.GetOrigin (), Ipv4Address ("4.4.4.4"), "trivial");
+    h.SetOriginSeqno (23);
+    NS_TEST_EXPECT_MSG_EQ (h.GetOriginSeqno (), 23, "trivial");
+
+    Ptr<Packet> p = Create<Packet> ();
+    p->AddHeader (h);
+    RreqHeader h2;
+    uint32_t bytes = p->RemoveHeader (h2);
+    NS_TEST_EXPECT_MSG_EQ (bytes, 23, "RREP is 23 bytes long");
+    NS_TEST_EXPECT_MSG_EQ (h, h2, "Round trip serialization works");
+
+  }
+};
+
+/**
+ * \ingroup greyattack-test
+ * \ingroup tests
+ *
+ * \brief Unit test for RREP
+ */
+struct RrepHeaderTest : public TestCase
+{
+  RrepHeaderTest () : TestCase ("greyattack RREP")
+  {
+  }
+  virtual void DoRun ()
+  {
+    RrepHeader h (/*prefixSize*/ 0, /*hopCount*/ 12, /*dst*/ Ipv4Address ("1.2.3.4"), /*dstSeqNo*/ 2,
+                                 /*origin*/ Ipv4Address ("4.3.2.1"), /*lifetime*/ Seconds (3));
+    NS_TEST_EXPECT_MSG_EQ (h.GetPrefixSize (), 0, "trivial");
+    NS_TEST_EXPECT_MSG_EQ (h.GetHopCount (), 12, "trivial");
+    NS_TEST_EXPECT_MSG_EQ (h.GetDst (), Ipv4Address ("1.2.3.4"), "trivial");
+    NS_TEST_EXPECT_MSG_EQ (h.GetDstSeqno (), 2, "trivial");
+    NS_TEST_EXPECT_MSG_EQ (h.GetOrigin (), Ipv4Address ("4.3.2.1"), "trivial");
+    NS_TEST_EXPECT_MSG_EQ (h.GetLifeTime (), Seconds (3), "trivial");
+    h.SetDst (Ipv4Address ("1.1.1.1"));
+    NS_TEST_EXPECT_MSG_EQ (h.GetDst (), Ipv4Address ("1.1.1.1"), "trivial");
+    h.SetDstSeqno (123);
+    NS_TEST_EXPECT_MSG_EQ (h.GetDstSeqno (), 123, "trivial");
+    h.SetOrigin (Ipv4Address ("4.4.4.4"));
+    NS_TEST_EXPECT_MSG_EQ (h.GetOrigin (), Ipv4Address ("4.4.4.4"), "trivial");
+    h.SetLifeTime (MilliSeconds (1200));
+    NS_TEST_EXPECT_MSG_EQ (h.GetLifeTime (), MilliSeconds (1200), "trivial");
+    h.SetAckRequired (true);
+    NS_TEST_EXPECT_MSG_EQ (h.GetAckRequired (), true, "trivial");
+    h.SetAckRequired (false);
+    NS_TEST_EXPECT_MSG_EQ (h.GetAckRequired (), false, "trivial");
+    h.SetPrefixSize (2);
+    NS_TEST_EXPECT_MSG_EQ (h.GetPrefixSize (), 2, "trivial");
+    h.SetHopCount (15);
+    NS_TEST_EXPECT_MSG_EQ (h.GetHopCount (), 15, "trivial");
+
+    h.SetHello (Ipv4Address ("10.0.0.2"), 9, Seconds (15));
+    NS_TEST_EXPECT_MSG_EQ (h.GetDst (), h.GetOrigin (), "trivial");
+    NS_TEST_EXPECT_MSG_EQ (h.GetDstSeqno (), 9, "trivial");
+    NS_TEST_EXPECT_MSG_EQ (h.GetLifeTime (), Seconds (15), "trivial");
+
+    Ptr<Packet> p = Create<Packet> ();
+    p->AddHeader (h);
+    RrepHeader h2;
+    uint32_t bytes = p->RemoveHeader (h2);
+    NS_TEST_EXPECT_MSG_EQ (bytes, 19, "RREP is 19 bytes long");
+    NS_TEST_EXPECT_MSG_EQ (h, h2, "Round trip serialization works");
+  }
+};
+
+/**
+ * \ingroup greyattack-test
+ * \ingroup tests
+ *
+ * \brief Unit test for RREP-ACK
+ */
+struct RrepAckHeaderTest : public TestCase
+{
+  RrepAckHeaderTest () : TestCase ("greyattack RREP-ACK")
+  {
+  }
+  virtual void DoRun ()
+  {
+    RrepAckHeader h;
+    Ptr<Packet> p = Create<Packet> ();
+    p->AddHeader (h);
+    RrepAckHeader h2;
+    uint32_t bytes = p->RemoveHeader (h2);
+    NS_TEST_EXPECT_MSG_EQ (bytes, 1, "ACK is 1 byte long");
+    NS_TEST_EXPECT_MSG_EQ (h, h2, "Round trip serialization works");
+  }
+};
+
+/**
+ * \ingroup greyattack-test
+ * \ingroup tests
+ *
+ * \brief Unit test for RERR
+ */
+struct RerrHeaderTest : public TestCase
+{
+  RerrHeaderTest () : TestCase ("greyattack RERR")
+  {
+  }
+  virtual void DoRun ()
+  {
+    RerrHeader h;
+    h.SetNoDelete (true);
+    NS_TEST_EXPECT_MSG_EQ (h.GetNoDelete (), true, "trivial");
+    Ipv4Address dst = Ipv4Address ("1.2.3.4");
+    NS_TEST_EXPECT_MSG_EQ (h.AddUnDestination (dst, 12), true, "trivial");
+    NS_TEST_EXPECT_MSG_EQ (h.GetDestCount (), 1, "trivial");
+    NS_TEST_EXPECT_MSG_EQ (h.AddUnDestination (dst, 13), true, "trivial");
+    Ipv4Address dst2 = Ipv4Address ("4.3.2.1");
+    NS_TEST_EXPECT_MSG_EQ (h.AddUnDestination (dst2, 12), true, "trivial");
+    NS_TEST_EXPECT_MSG_EQ (h.GetDestCount (), 2, "trivial");
+
+    Ptr<Packet> p = Create<Packet> ();
+    p->AddHeader (h);
+    RerrHeader h2;
+    uint32_t bytes = p->RemoveHeader (h2);
+    NS_TEST_EXPECT_MSG_EQ (bytes, h.GetSerializedSize (), "(De)Serialized size match");
+    NS_TEST_EXPECT_MSG_EQ (h, h2, "Round trip serialization works");
+  }
+};
+
+/**
+ * \ingroup greyattack-test
+ * \ingroup tests
+ *
+ * \brief Unit test for greyattack routing table entry
+ */
+struct QueueEntryTest : public TestCase
+{
+  QueueEntryTest () : TestCase ("QueueEntry")
+  {
+  }
+  /**
+   * Unicast test function
+   * \param route the IPv4 route
+   * \param packet the packet
+   * \param header the IPv4 header
+   */
+  void Unicast (Ptr<Ipv4Route> route, Ptr<const Packet> packet, const Ipv4Header & header)
+  {
+  }
+  /**
+   * Error test function
+   * \param p The packet
+   * \param h The header
+   * \param e the socket error
+   */
+  void Error (Ptr<const Packet> p, const Ipv4Header & h, Socket::SocketErrno e)
+  {
+  }
+  /**
+   * Unicast 2 testfunction
+   * \param route The IPv4 route
+   * \param packet The packet
+   * \param header The header
+   */
+  void Unicast2 (Ptr<Ipv4Route> route, Ptr<const Packet> packet, const Ipv4Header & header)
+  {
+  }
+  /**
+   * Error2 test function
+   * \param p The packet
+   * \param h The header
+   * \param e the socket error
+   */
+  void Error2 (Ptr<const Packet> p, const Ipv4Header & h, Socket::SocketErrno e)
+  {
+  }
+  virtual void DoRun ()
+  {
+    Ptr<const Packet> packet = Create<Packet> ();
+    Ipv4Header h;
+    h.SetDestination (Ipv4Address ("1.2.3.4"));
+    h.SetSource (Ipv4Address ("4.3.2.1"));
+    Ipv4RoutingProtocol::UnicastForwardCallback ucb = MakeCallback (&QueueEntryTest::Unicast, this);
+    Ipv4RoutingProtocol::ErrorCallback ecb = MakeCallback (&QueueEntryTest::Error, this);
+    QueueEntry entry (packet, h, ucb, ecb, Seconds (1));
+    NS_TEST_EXPECT_MSG_EQ (h.GetDestination (),  entry.GetIpv4Header ().GetDestination (), "trivial");
+    NS_TEST_EXPECT_MSG_EQ (h.GetSource (),  entry.GetIpv4Header ().GetSource (), "trivial");
+    NS_TEST_EXPECT_MSG_EQ (ucb.IsEqual (entry.GetUnicastForwardCallback ()), true, "trivial");
+    NS_TEST_EXPECT_MSG_EQ (ecb.IsEqual (entry.GetErrorCallback ()), true, "trivial");
+    NS_TEST_EXPECT_MSG_EQ (entry.GetExpireTime (), Seconds (1), "trivial");
+    NS_TEST_EXPECT_MSG_EQ (entry.GetPacket (), packet, "trivial");
+    entry.SetExpireTime (Seconds (3));
+    NS_TEST_EXPECT_MSG_EQ (entry.GetExpireTime (), Seconds (3), "trivial");
+    Ipv4Header h2;
+    h2.SetDestination (Ipv4Address ("1.1.1.1"));
+    entry.SetIpv4Header (h2);
+    NS_TEST_EXPECT_MSG_EQ (entry.GetIpv4Header ().GetDestination (), Ipv4Address ("1.1.1.1"), "trivial");
+    Ipv4RoutingProtocol::UnicastForwardCallback ucb2 = MakeCallback (&QueueEntryTest::Unicast2, this);
+    Ipv4RoutingProtocol::ErrorCallback ecb2 = MakeCallback (&QueueEntryTest::Error2, this);
+    entry.SetErrorCallback (ecb2);
+    NS_TEST_EXPECT_MSG_EQ (ecb2.IsEqual (entry.GetErrorCallback ()), true, "trivial");
+    entry.SetUnicastForwardCallback (ucb2);
+    NS_TEST_EXPECT_MSG_EQ (ucb2.IsEqual (entry.GetUnicastForwardCallback ()), true, "trivial");
+  }
+};
+//-----------------------------------------------------------------------------
+/// Unit test for RequestQueue
+struct greyattackRqueueTest : public TestCase
+{
+  greyattackRqueueTest () : TestCase ("Rqueue"),
+                      q (64, Seconds (30))
+  {
+  }
+  virtual void DoRun ();
+  /**
+   * Unicast test function
+   * \param route the IPv4 route
+   * \param packet the packet
+   * \param header the IPv4 header
+   */
+  void Unicast (Ptr<Ipv4Route> route, Ptr<const Packet> packet, const Ipv4Header & header)
+  {
+  }
+  /**
+   * Error test function
+   * \param p The packet
+   * \param h The header
+   * \param e the socket error
+   */
+  void Error (Ptr<const Packet> p, const Ipv4Header & h, Socket::SocketErrno e)
+  {
+  }
+  /// Check size limit function
+  void CheckSizeLimit ();
+  /// Check timeout function
+  void CheckTimeout ();
+
+  /// Request queue
+  RequestQueue q;
+};
+
+void
+greyattackRqueueTest::DoRun ()
+{
+  NS_TEST_EXPECT_MSG_EQ (q.GetMaxQueueLen (), 64, "trivial");
+  q.SetMaxQueueLen (32);
+  NS_TEST_EXPECT_MSG_EQ (q.GetMaxQueueLen (), 32, "trivial");
+  NS_TEST_EXPECT_MSG_EQ (q.GetQueueTimeout (), Seconds (30), "trivial");
+  q.SetQueueTimeout (Seconds (10));
+  NS_TEST_EXPECT_MSG_EQ (q.GetQueueTimeout (), Seconds (10), "trivial");
+
+  Ptr<const Packet> packet = Create<Packet> ();
+  Ipv4Header h;
+  h.SetDestination (Ipv4Address ("1.2.3.4"));
+  h.SetSource (Ipv4Address ("4.3.2.1"));
+  Ipv4RoutingProtocol::UnicastForwardCallback ucb = MakeCallback (&greyattackRqueueTest::Unicast, this);
+  Ipv4RoutingProtocol::ErrorCallback ecb = MakeCallback (&greyattackRqueueTest::Error, this);
+  QueueEntry e1 (packet, h, ucb, ecb, Seconds (1));
+  q.Enqueue (e1);
+  q.Enqueue (e1);
+  q.Enqueue (e1);
+  NS_TEST_EXPECT_MSG_EQ (q.Find (Ipv4Address ("1.2.3.4")), true, "trivial");
+  NS_TEST_EXPECT_MSG_EQ (q.Find (Ipv4Address ("1.1.1.1")), false, "trivial");
+  NS_TEST_EXPECT_MSG_EQ (q.GetSize (), 1, "trivial");
+  q.DropPacketWithDst (Ipv4Address ("1.2.3.4"));
+  NS_TEST_EXPECT_MSG_EQ (q.Find (Ipv4Address ("1.2.3.4")), false, "trivial");
+  NS_TEST_EXPECT_MSG_EQ (q.GetSize (), 0, "trivial");
+
+  h.SetDestination (Ipv4Address ("2.2.2.2"));
+  QueueEntry e2 (packet, h, ucb, ecb, Seconds (1));
+  q.Enqueue (e1);
+  q.Enqueue (e2);
+  Ptr<Packet> packet2 = Create<Packet> ();
+  QueueEntry e3 (packet2, h, ucb, ecb, Seconds (1));
+  NS_TEST_EXPECT_MSG_EQ (q.Dequeue (Ipv4Address ("3.3.3.3"), e3), false, "trivial");
+  NS_TEST_EXPECT_MSG_EQ (q.Dequeue (Ipv4Address ("2.2.2.2"), e3), true, "trivial");
+  NS_TEST_EXPECT_MSG_EQ (q.Find (Ipv4Address ("2.2.2.2")), false, "trivial");
+  q.Enqueue (e2);
+  q.Enqueue (e3);
+  NS_TEST_EXPECT_MSG_EQ (q.GetSize (), 2, "trivial");
+  Ptr<Packet> packet4 = Create<Packet> ();
+  h.SetDestination (Ipv4Address ("1.2.3.4"));
+  QueueEntry e4 (packet4, h, ucb, ecb, Seconds (20));
+  q.Enqueue (e4);
+  NS_TEST_EXPECT_MSG_EQ (q.GetSize (), 3, "trivial");
+  q.DropPacketWithDst (Ipv4Address ("1.2.3.4"));
+  NS_TEST_EXPECT_MSG_EQ (q.GetSize (), 1, "trivial");
+
+  CheckSizeLimit ();
+
+  Ipv4Header header2;
+  Ipv4Address dst2 ("1.2.3.4");
+  header2.SetDestination (dst2);
+
+  Simulator::Schedule (q.GetQueueTimeout () + Seconds (1), &greyattackRqueueTest::CheckTimeout, this);
+
+  Simulator::Run ();
+  Simulator::Destroy ();
+}
+
+void
+greyattackRqueueTest::CheckSizeLimit ()
+{
+  Ptr<Packet> packet = Create<Packet> ();
+  Ipv4Header header;
+  Ipv4RoutingProtocol::UnicastForwardCallback ucb = MakeCallback (&greyattackRqueueTest::Unicast, this);
+  Ipv4RoutingProtocol::ErrorCallback ecb = MakeCallback (&greyattackRqueueTest::Error, this);
+  QueueEntry e1 (packet, header, ucb, ecb, Seconds (1));
+
+  for (uint32_t i = 0; i < q.GetMaxQueueLen (); ++i)
+    {
+      q.Enqueue (e1);
+    }
+  NS_TEST_EXPECT_MSG_EQ (q.GetSize (), 2, "trivial");
+
+  for (uint32_t i = 0; i < q.GetMaxQueueLen (); ++i)
+    {
+      q.Enqueue (e1);
+    }
+  NS_TEST_EXPECT_MSG_EQ (q.GetSize (), 2, "trivial");
+}
+
+void
+greyattackRqueueTest::CheckTimeout ()
+{
+  NS_TEST_EXPECT_MSG_EQ (q.GetSize (), 0, "Must be empty now");
+}
+
+/**
+ * \ingroup greyattack-test
+ * \ingroup tests
+ *
+ * \brief Unit test for greyattack routing table entry
+ */
+struct greyattackRtableEntryTest : public TestCase
+{
+  greyattackRtableEntryTest () : TestCase ("RtableEntry")
+  {
+  }
+  virtual void DoRun ()
+  {
+    Ptr<NetDevice> dev;
+    Ipv4InterfaceAddress iface;
+    RoutingTableEntry rt (/*output device*/ dev, /*dst*/ Ipv4Address ("1.2.3.4"), /*validSeqNo*/ true, /*seqNo*/ 10,
+                                            /*interface*/ iface, /*hop*/ 5, /*next hop*/ Ipv4Address ("3.3.3.3"), /*lifetime*/ Seconds (10));
+    NS_TEST_EXPECT_MSG_EQ (rt.GetOutputDevice (), dev, "trivial");
+    NS_TEST_EXPECT_MSG_EQ (rt.GetDestination (), Ipv4Address ("1.2.3.4"), "trivial");
+    NS_TEST_EXPECT_MSG_EQ (rt.GetValidSeqNo (), true, "trivial");
+    NS_TEST_EXPECT_MSG_EQ (rt.GetSeqNo (), 10, "trivial");
+    NS_TEST_EXPECT_MSG_EQ (rt.GetInterface (), iface, "trivial");
+    NS_TEST_EXPECT_MSG_EQ (rt.GetHop (), 5, "trivial");
+    NS_TEST_EXPECT_MSG_EQ (rt.GetNextHop (), Ipv4Address ("3.3.3.3"), "trivial");
+    NS_TEST_EXPECT_MSG_EQ (rt.GetLifeTime (), Seconds (10), "trivial");
+    NS_TEST_EXPECT_MSG_EQ (rt.GetFlag (), VALID, "trivial");
+    NS_TEST_EXPECT_MSG_EQ (rt.GetRreqCnt (), 0, "trivial");
+    NS_TEST_EXPECT_MSG_EQ (rt.IsPrecursorListEmpty (), true, "trivial");
+
+    Ptr<NetDevice> dev2;
+    Ipv4InterfaceAddress iface2;
+    rt.SetOutputDevice (dev2);
+    NS_TEST_EXPECT_MSG_EQ (rt.GetOutputDevice (), dev2, "trivial");
+    rt.SetInterface (iface2);
+    NS_TEST_EXPECT_MSG_EQ (rt.GetInterface (), iface2, "trivial");
+    rt.SetValidSeqNo (false);
+    NS_TEST_EXPECT_MSG_EQ (rt.GetValidSeqNo (), false, "trivial");
+    rt.SetFlag (INVALID);
+    NS_TEST_EXPECT_MSG_EQ (rt.GetFlag (), INVALID, "trivial");
+    rt.SetFlag (IN_SEARCH);
+    NS_TEST_EXPECT_MSG_EQ (rt.GetFlag (), IN_SEARCH, "trivial");
+    rt.SetHop (12);
+    NS_TEST_EXPECT_MSG_EQ (rt.GetHop (), 12, "trivial");
+    rt.SetLifeTime (Seconds (1));
+    NS_TEST_EXPECT_MSG_EQ (rt.GetLifeTime (), Seconds (1), "trivial");
+    rt.SetNextHop (Ipv4Address ("1.1.1.1"));
+    NS_TEST_EXPECT_MSG_EQ (rt.GetNextHop (), Ipv4Address ("1.1.1.1"), "trivial");
+    rt.SetUnidirectional (true);
+    NS_TEST_EXPECT_MSG_EQ (rt.IsUnidirectional (), true, "trivial");
+    rt.SetBlacklistTimeout (Seconds (7));
+    NS_TEST_EXPECT_MSG_EQ (rt.GetBlacklistTimeout (), Seconds (7), "trivial");
+    rt.SetRreqCnt (2);
+    NS_TEST_EXPECT_MSG_EQ (rt.GetRreqCnt (), 2, "trivial");
+    rt.IncrementRreqCnt ();
+    NS_TEST_EXPECT_MSG_EQ (rt.GetRreqCnt (), 3, "trivial");
+    rt.Invalidate (Seconds (13));
+    NS_TEST_EXPECT_MSG_EQ (rt.GetFlag (), INVALID, "trivial");
+    NS_TEST_EXPECT_MSG_EQ (rt.GetLifeTime (), Seconds (13), "trivial");
+    rt.SetLifeTime (MilliSeconds (100));
+    NS_TEST_EXPECT_MSG_EQ (rt.GetLifeTime (), MilliSeconds (100), "trivial");
+    Ptr<Ipv4Route> route = rt.GetRoute ();
+    NS_TEST_EXPECT_MSG_EQ (route->GetDestination (), Ipv4Address ("1.2.3.4"), "trivial");
+
+    NS_TEST_EXPECT_MSG_EQ (rt.InsertPrecursor (Ipv4Address ("10.0.0.1")), true, "trivial");
+    NS_TEST_EXPECT_MSG_EQ (rt.IsPrecursorListEmpty (), false, "trivial");
+    NS_TEST_EXPECT_MSG_EQ (rt.InsertPrecursor (Ipv4Address ("10.0.0.2")), true, "trivial");
+    NS_TEST_EXPECT_MSG_EQ (rt.InsertPrecursor (Ipv4Address ("10.0.0.2")), false, "trivial");
+    NS_TEST_EXPECT_MSG_EQ (rt.LookupPrecursor (Ipv4Address ("10.0.0.3")), false, "trivial");
+    NS_TEST_EXPECT_MSG_EQ (rt.LookupPrecursor (Ipv4Address ("10.0.0.1")), true, "trivial");
+    NS_TEST_EXPECT_MSG_EQ (rt.DeletePrecursor (Ipv4Address ("10.0.0.2")), true, "trivial");
+    NS_TEST_EXPECT_MSG_EQ (rt.LookupPrecursor (Ipv4Address ("10.0.0.2")), false, "trivial");
+    std::vector<Ipv4Address> prec;
+    rt.GetPrecursors (prec);
+    NS_TEST_EXPECT_MSG_EQ (prec.size (), 1, "trivial");
+    NS_TEST_EXPECT_MSG_EQ (rt.InsertPrecursor (Ipv4Address ("10.0.0.4")), true, "trivial");
+    NS_TEST_EXPECT_MSG_EQ (rt.DeletePrecursor (Ipv4Address ("10.0.0.5")), false, "trivial");
+    rt.GetPrecursors (prec);
+    NS_TEST_EXPECT_MSG_EQ (prec.size (), 2, "trivial");
+    rt.DeleteAllPrecursors ();
+    NS_TEST_EXPECT_MSG_EQ (rt.IsPrecursorListEmpty (), true, "trivial");
+    rt.GetPrecursors (prec);
+    NS_TEST_EXPECT_MSG_EQ (prec.size (), 2, "trivial");
+    Simulator::Destroy ();
+  }
+};
+
+/**
+ * \ingroup greyattack-test
+ * \ingroup tests
+ *
+ * \brief Unit test for greyattack routing table
+ */
+struct greyattackRtableTest : public TestCase
+{
+  greyattackRtableTest () : TestCase ("Rtable")
+  {
+  }
+  virtual void DoRun ()
+  {
+    RoutingTable rtable (Seconds (2));
+    NS_TEST_EXPECT_MSG_EQ (rtable.GetBadLinkLifetime (), Seconds (2), "trivial");
+    rtable.SetBadLinkLifetime (Seconds (1));
+    NS_TEST_EXPECT_MSG_EQ (rtable.GetBadLinkLifetime (), Seconds (1), "trivial");
+    Ptr<NetDevice> dev;
+    Ipv4InterfaceAddress iface;
+    RoutingTableEntry rt (/*output device*/ dev, /*dst*/ Ipv4Address ("1.2.3.4"), /*validSeqNo*/ true, /*seqNo*/ 10,
+                                            /*interface*/ iface, /*hop*/ 5, /*next hop*/ Ipv4Address ("1.1.1.1"), /*lifetime*/ Seconds (10));
+    NS_TEST_EXPECT_MSG_EQ (rtable.AddRoute (rt), true, "trivial");
+    NS_TEST_EXPECT_MSG_EQ (rtable.AddRoute (rt), false, "trivial");
+    RoutingTableEntry rt2 (/*output device*/ dev, /*dst*/ Ipv4Address ("4.3.2.1"), /*validSeqNo*/ false, /*seqNo*/ 0,
+                                             /*interface*/ iface, /*hop*/ 15, /*next hop*/ Ipv4Address ("1.1.1.1"), /*lifetime*/ Seconds (1));
+    NS_TEST_EXPECT_MSG_EQ (rtable.AddRoute (rt2), true, "trivial");
+    NS_TEST_EXPECT_MSG_EQ (rtable.LookupRoute (rt2.GetDestination (), rt), true, "trivial");
+    NS_TEST_EXPECT_MSG_EQ (rt2.GetDestination (), rt.GetDestination (), "trivial");
+    rt.SetHop (20);
+    rt.InsertPrecursor (Ipv4Address ("10.0.0.3"));
+    NS_TEST_EXPECT_MSG_EQ (rtable.Update (rt), true, "trivial");
+    RoutingTableEntry rt3;
+    NS_TEST_EXPECT_MSG_EQ (rtable.LookupRoute (Ipv4Address ("10.0.0.1"), rt), false, "trivial");
+    NS_TEST_EXPECT_MSG_EQ (rtable.Update (rt3), false, "trivial");
+    NS_TEST_EXPECT_MSG_EQ (rtable.SetEntryState (Ipv4Address ("10.0.0.1"), INVALID), false, "trivial");
+    NS_TEST_EXPECT_MSG_EQ (rtable.SetEntryState (Ipv4Address ("1.2.3.4"), IN_SEARCH), true, "trivial");
+    NS_TEST_EXPECT_MSG_EQ (rtable.DeleteRoute (Ipv4Address ("5.5.5.5")), false, "trivial");
+    RoutingTableEntry rt4 (/*output device*/ dev, /*dst*/ Ipv4Address ("5.5.5.5"), /*validSeqNo*/ false, /*seqNo*/ 0,
+                                             /*interface*/ iface, /*hop*/ 15, /*next hop*/ Ipv4Address ("1.1.1.1"), /*lifetime*/ Seconds (-10));
+    NS_TEST_EXPECT_MSG_EQ (rtable.AddRoute (rt4), true, "trivial");
+    NS_TEST_EXPECT_MSG_EQ (rtable.SetEntryState (Ipv4Address ("5.5.5.5"), INVALID), true, "trivial");
+    NS_TEST_EXPECT_MSG_EQ (rtable.LookupRoute (Ipv4Address ("5.5.5.5"), rt), false, "trivial");
+    NS_TEST_EXPECT_MSG_EQ (rtable.MarkLinkAsUnidirectional (Ipv4Address ("1.2.3.4"), Seconds (2)), true, "trivial");
+    NS_TEST_EXPECT_MSG_EQ (rtable.LookupRoute (Ipv4Address ("1.2.3.4"), rt), true, "trivial");
+    NS_TEST_EXPECT_MSG_EQ (rt.IsUnidirectional (), true, "trivial");
+    rt.SetLifeTime (Seconds (-5));
+    NS_TEST_EXPECT_MSG_EQ (rtable.Update (rt), true, "trivial");
+    std::map<Ipv4Address, uint32_t> unreachable;
+    rtable.GetListOfDestinationWithNextHop (Ipv4Address ("1.1.1.1"), unreachable);
+    NS_TEST_EXPECT_MSG_EQ (unreachable.size (), 2, "trivial");
+    unreachable.insert (std::make_pair (Ipv4Address ("4.3.2.1"), 3));
+    rtable.InvalidateRoutesWithDst (unreachable);
+    NS_TEST_EXPECT_MSG_EQ (rtable.LookupRoute (Ipv4Address ("4.3.2.1"), rt), true, "trivial");
+    NS_TEST_EXPECT_MSG_EQ (rt.GetFlag (), INVALID, "trivial");
+    NS_TEST_EXPECT_MSG_EQ (rtable.DeleteRoute (Ipv4Address ("1.2.3.4")), true, "trivial");
+    NS_TEST_EXPECT_MSG_EQ (rtable.DeleteRoute (Ipv4Address ("1.2.3.4")), false, "trivial");
+    Simulator::Destroy ();
+  }
+};
+
+/**
+ * \ingroup greyattack-test
+ * \ingroup tests
+ *
+ * \brief greyattack test suite
+ */
+class greyattackTestSuite : public TestSuite
+{
+public:
+  greyattackTestSuite () : TestSuite ("routing-greyattack", UNIT)
+  {
+    AddTestCase (new NeighborTest, TestCase::QUICK);
+    AddTestCase (new TypeHeaderTest, TestCase::QUICK);
+    AddTestCase (new RreqHeaderTest, TestCase::QUICK);
+    AddTestCase (new RrepHeaderTest, TestCase::QUICK);
+    AddTestCase (new RrepAckHeaderTest, TestCase::QUICK);
+    AddTestCase (new RerrHeaderTest, TestCase::QUICK);
+    AddTestCase (new QueueEntryTest, TestCase::QUICK);
+    AddTestCase (new greyattackRqueueTest, TestCase::QUICK);
+    AddTestCase (new greyattackRtableEntryTest, TestCase::QUICK);
+    AddTestCase (new greyattackRtableTest, TestCase::QUICK);
+  }
+} g_greyattackTestSuite; ///< the test suite
+
+}  // namespace greyattack
+}  // namespace ns3
diff --git a/greyattack-module/test/loopback.cc b/greyattack-module/test/loopback.cc
new file mode 100644
index 0000000000000000000000000000000000000000..a22c5ae500f4369c16f5e530b47dc970fb9a6b75
--- /dev/null
+++ b/greyattack-module/test/loopback.cc
@@ -0,0 +1,197 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2010 IITP RAS
+ *
+ * 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
+ *
+ * Authors: Pavel Boyko <boyko@iitp.ru>
+ */
+
+#include "ns3/test.h"
+#include "ns3/simulator.h"
+#include "ns3/socket-factory.h"
+#include "ns3/udp-socket-factory.h"
+#include "ns3/mobility-helper.h"
+#include "ns3/double.h"
+#include "ns3/uinteger.h"
+#include "ns3/string.h"
+#include "ns3/boolean.h"
+#include "ns3/yans-wifi-helper.h"
+#include "ns3/internet-stack-helper.h"
+#include "ns3/ipv4-address-helper.h"
+#include "ns3/abort.h"
+#include "ns3/udp-echo-helper.h"
+#include "ns3/mobility-model.h"
+#include "ns3/pcap-file.h"
+#include "ns3/greyattack-helper.h"
+#include "ns3/v4ping.h"
+#include "ns3/config.h"
+#include "ns3/constant-position-mobility-model.h"
+#include "ns3/names.h"
+#include <sstream>
+
+namespace ns3 {
+namespace greyattack {
+
+/**
+ * \ingroup greyattack
+ *
+ * \brief greyattack loopback UDP echo test case
+ */
+class LoopbackTestCase : public TestCase
+{
+  uint32_t m_count; //!< number of packet received;
+  Ptr<Socket> m_txSocket; //!< transmit socket;
+  Ptr<Socket> m_echoSocket; //!< echo socket;
+  Ptr<Socket> m_rxSocket; //!< receive socket;
+  uint16_t m_echoSendPort; //!< echo send port;
+  uint16_t m_echoReplyPort; //!< echo reply port;
+
+  /**
+   * Send data function
+   * \param socket The socket to send data
+   */
+  void SendData (Ptr<Socket> socket);
+  /**
+   * Receive packet function
+   * \param socket The socket to receive data
+   */
+  void ReceivePkt (Ptr<Socket> socket);
+  /**
+   * Echo data function
+   * \param socket The socket to echo data
+   */
+  void EchoData (Ptr<Socket> socket);
+
+public:
+  LoopbackTestCase ();
+  void DoRun ();
+};
+
+LoopbackTestCase::LoopbackTestCase ()
+  : TestCase ("UDP Echo 127.0.0.1 test"),
+    m_count (0)
+{
+  m_echoSendPort = 1233;
+  m_echoReplyPort = 1234;
+}
+
+void LoopbackTestCase::ReceivePkt (Ptr<Socket> socket)
+{
+  Ptr<Packet> receivedPacket = socket->Recv (std::numeric_limits<uint32_t>::max (), 0);
+
+  m_count++;
+}
+
+void
+LoopbackTestCase::EchoData (Ptr<Socket> socket)
+{
+  Address from;
+  Ptr<Packet> receivedPacket = socket->RecvFrom (std::numeric_limits<uint32_t>::max (), 0, from);
+
+  Ipv4Address src = InetSocketAddress::ConvertFrom (from).GetIpv4 ();
+  Address to = InetSocketAddress (src, m_echoReplyPort);
+
+  receivedPacket->RemoveAllPacketTags ();
+  receivedPacket->RemoveAllByteTags ();
+
+  socket->SendTo (receivedPacket, 0, to);
+}
+
+void
+LoopbackTestCase::SendData (Ptr<Socket> socket)
+{
+  Address realTo = InetSocketAddress (Ipv4Address::GetLoopback (), m_echoSendPort);
+  socket->SendTo (Create<Packet> (123), 0, realTo);
+
+  Simulator::ScheduleWithContext (socket->GetNode ()->GetId (), Seconds (1.0),
+                                  &LoopbackTestCase::SendData, this, socket);
+}
+
+void
+LoopbackTestCase::DoRun ()
+{
+  NodeContainer nodes;
+  nodes.Create (1);
+  Ptr<MobilityModel> m = CreateObject<ConstantPositionMobilityModel> ();
+  m->SetPosition (Vector (0, 0, 0));
+  nodes.Get (0)->AggregateObject (m);
+  // Setup WiFi
+  WifiMacHelper wifiMac;
+  wifiMac.SetType ("ns3::AdhocWifiMac");
+  YansWifiPhyHelper wifiPhy;
+  YansWifiChannelHelper wifiChannel = YansWifiChannelHelper::Default ();
+  wifiPhy.SetChannel (wifiChannel.Create ());
+  WifiHelper wifi;
+  wifi.SetRemoteStationManager ("ns3::ConstantRateWifiManager", "DataMode", StringValue ("OfdmRate6Mbps"), "RtsCtsThreshold", StringValue ("2200"));
+  NetDeviceContainer devices = wifi.Install (wifiPhy, wifiMac, nodes);
+
+  // Setup TCP/IP & greyattack
+  greyattackHelper greyattack; // Use default parameters here
+  InternetStackHelper internetStack;
+  internetStack.SetRoutingHelper (greyattack);
+  internetStack.Install (nodes);
+  Ipv4AddressHelper address;
+  address.SetBase ("10.1.1.0", "255.255.255.0");
+  Ipv4InterfaceContainer interfaces = address.Assign (devices);
+
+  // Setup echos
+  Ptr<SocketFactory> socketFactory = nodes.Get (0)->GetObject<UdpSocketFactory> ();
+  m_rxSocket = socketFactory->CreateSocket ();
+  m_rxSocket->Bind (InetSocketAddress (Ipv4Address::GetLoopback (), m_echoReplyPort));
+  m_rxSocket->SetRecvCallback (MakeCallback (&LoopbackTestCase::ReceivePkt, this));
+
+  m_echoSocket = socketFactory->CreateSocket ();
+  m_echoSocket->Bind (InetSocketAddress (Ipv4Address::GetLoopback (), m_echoSendPort));
+  m_echoSocket->SetRecvCallback (MakeCallback (&LoopbackTestCase::EchoData, this));
+
+  m_txSocket = socketFactory->CreateSocket ();
+
+  Simulator::ScheduleWithContext (m_txSocket->GetNode ()->GetId (), Seconds (1.0),
+                                  &LoopbackTestCase::SendData, this, m_txSocket);
+
+  // Run
+  Simulator::Stop (Seconds (5));
+  Simulator::Run ();
+
+  m_txSocket->Close ();
+  m_echoSocket->Close ();
+  m_rxSocket->Close ();
+
+  Simulator::Destroy ();
+
+  // Check that 4 packets delivered
+  NS_TEST_ASSERT_MSG_EQ (m_count, 4, "Exactly 4 echo replies must be delivered.");
+}
+
+/**
+ * \ingroup greyattack-test
+ * \ingroup tests
+ *
+ * \brief greyattack Loopback test suite
+ */
+class greyattackLoopbackTestSuite : public TestSuite
+{
+public:
+  greyattackLoopbackTestSuite () : TestSuite ("routing-greyattack-loopback", SYSTEM)
+  {
+    SetDataDir (NS_TEST_SOURCEDIR);
+    // UDP Echo loopback test case
+    AddTestCase (new LoopbackTestCase (), TestCase::QUICK);
+  }
+} g_greyattackLoopbackTestSuite; ///< the test suite
+
+
+}  // namespace greyattack
+}  // namespace ns3
diff --git a/greyattack-module/wscript b/greyattack-module/wscript
new file mode 100644
index 0000000000000000000000000000000000000000..188523542c07b2a9344ad4a1a2efe009758ebb60
--- /dev/null
+++ b/greyattack-module/wscript
@@ -0,0 +1,48 @@
+## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
+
+def build(bld):
+    module = bld.create_ns3_module('greydefense-aodv', ['internet', 'wifi'])
+    module.includes = '.'
+    module.source = [
+        'model/greydefense-aodv-id-cache.cc',
+        'model/greydefense-aodv-dpd.cc',
+        'model/greydefense-aodv-rtable.cc',
+        'model/greydefense-aodv-rqueue.cc',
+        'model/greydefense-aodv-packet.cc',
+        'model/greydefense-aodv-neighbor.cc',
+        'model/greydefense-aodv-routing-protocol.cc',
+        'helper/greydefense-aodv-helper.cc',
+        ]
+
+    greydefense-aodv_test = bld.create_ns3_module_test_library('greydefense-aodv')
+    greydefense-aodv_test.source = [
+        'test/greydefense-aodv-id-cache-test-suite.cc',
+        'test/greydefense-aodv-test-suite.cc',
+        'test/greydefense-aodv-regression.cc',
+        'test/bug-772.cc',
+        'test/loopback.cc',
+        ]
+
+    # Tests encapsulating example programs should be listed here
+    if (bld.env['ENABLE_EXAMPLES']):
+        greydefense-aodv_test.source.extend([
+        #   'test/greydefense-aodv-examples-test-suite.cc',
+            ])
+
+    headers = bld(features='ns3header')
+    headers.module = 'greydefense-aodv'
+    headers.source = [
+        'model/greydefense-aodv-id-cache.h',
+        'model/greydefense-aodv-dpd.h',
+        'model/greydefense-aodv-rtable.h',
+        'model/greydefense-aodv-rqueue.h',
+        'model/greydefense-aodv-packet.h',
+        'model/greydefense-aodv-neighbor.h',
+        'model/greydefense-aodv-routing-protocol.h',
+        'helper/greydefense-aodv-helper.h',
+        ]
+
+    if bld.env['ENABLE_EXAMPLES']:
+        bld.recurse('examples')
+
+    bld.ns3_python_bindings()
\ No newline at end of file
diff --git a/manet-rank-scratch/MainExperiment/debug.py b/manet-rank-scratch/MainExperiment/debug.py
new file mode 100644
index 0000000000000000000000000000000000000000..3f428e2379b705abd36847f6e625692fa6690178
--- /dev/null
+++ b/manet-rank-scratch/MainExperiment/debug.py
@@ -0,0 +1,197 @@
+import re
+from collections import defaultdict
+
+# Define data structures to store parsed information
+rejected_nodes_info = []
+forwarded_packets = []  # List of dictionaries to store packet forwarding details
+attack_info = []  # List to store attack information
+
+# Regular expressions for matching log file lines
+forward_pattern = re.compile(
+    r'\+(\d+\.\d+s) \[node (\d+)\] (?:eaer|greydefense)-aodvRoutingProtocol:Forwarding\(\): forwarding packet ID: (\d+) ttl: (\d+) to (\d+\.\d+\.\d+\.\d+) from (\d+\.\d+\.\d+\.\d+) via (\d+\.\d+\.\d+\.\d+)')
+send_pattern = re.compile(
+    r'\+(\d+\.\d+s) \[node (\d+)\] (?:eaer|greydefense)-aodvRoutingProtocol:(?:RouteOutput|SendPacketFromQueue)\(\): sending packet ID: (\d+) ttl: (\d+) to (\d+\.\d+\.\d+\.\d+) from (\d+\.\d+\.\d+\.\d+)(?: via (\d+\.\d+\.\d+\.\d+))?')
+attack_pattern = re.compile(r'\+(\d+\.\d+s) \[node (\d+)\] (?:eaer|greyattack)-aodvRoutingProtocol:Forwarding\(\): \[Attack - PACKET_DROP_PERC\]: Dropped packet (\d+) where the next hop was (\d+\.\d+\.\d+\.\d+)')
+rejected_node_pattern = re.compile(r'\+(\d+\.\d+s) \[node (\d+)\] (?:eaer|greydefense)-aodvRoutingProtocol:UpdateTrust\(\): \d+ Rejected: (\d+)')
+# Dictionary to store the last timestamp for each packet ID
+last_timestamps = {}
+# list to store the next available new packet ID for retransmissions
+new_packet_ids = set()
+
+# Read the log file and parse lines
+with open('network.log', 'r') as log_file:
+    for line in log_file:
+        # Check if the line matches the "Forwarding" pattern
+        forward_match = forward_pattern.match(line)
+        send_match = send_pattern.match(line)
+        attack_match = attack_pattern.match(line)
+        rejected_node_match = rejected_node_pattern.match(line)
+
+        if forward_match:
+            timestamp, source_node, packet_id, ttl, destination_ip, source_ip, forwarding_node = forward_match.groups()
+
+        elif send_match:
+            timestamp, source_node, packet_id, ttl, destination_ip, source_ip, forwarding_node = send_match.groups()
+
+        elif attack_match:
+            timestamp, node_id, packet_id, next_hop = attack_match.groups()
+            packet_id = int(packet_id)
+            new_packet_ids.add(packet_id)
+
+            already_counted = False
+            for attack in attack_info:
+                if attack['Packet ID'] == packet_id:
+                    already_counted = True
+            if not already_counted:
+                attack_info.append({
+                    'Timestamp': float(timestamp[:-1]),  # Remove 's' and convert to float
+                    'Node ID': node_id,
+                    'Packet ID': packet_id,
+                    'Next Hop': next_hop
+                })
+            else:
+                packet_id += 10000
+                already_counted = False
+                for attack in attack_info:
+                    if attack['Packet ID'] == packet_id:
+                        already_counted = True
+                if not already_counted:
+                    attack_info.append({
+                        'Timestamp': float(timestamp[:-1]),  # Remove 's' and convert to float
+                        'Node ID': node_id,
+                        'Packet ID': packet_id,
+                        'Next Hop': next_hop
+                    })
+                else:
+                    print("Something's gone wrong")
+            continue
+
+        elif rejected_node_match:
+            timestamp, node_id, rejected_node  = rejected_node_match.groups()
+            rejected_nodes_info.append({
+                'Timestamp': float(timestamp[:-1]),  # Remove 's' and convert to float
+                'Node ID': node_id,
+                'Rejected Node': rejected_node,
+            })
+            continue
+
+        else:
+            continue
+
+        packet_id = int(packet_id)  # Convert packet ID to an integer
+
+        # Remove 's' from the timestamp and convert to float
+        timestamp = float(timestamp[:-1])
+
+        last_timestamp = last_timestamps.get(packet_id, 0)
+        current_timestamp = timestamp
+
+        if current_timestamp - last_timestamp >= 10.0 and packet_id in new_packet_ids:
+            # This is packet has an ID which is previously been used, add 10000 to the packet ID to keep them unique
+            packet_id += 10000
+
+            forwarded_packets.append({
+                'Timestamp': timestamp,
+                'Source Node': source_node,
+                'Packet ID': packet_id,
+                'TTL': ttl,
+                'Source IP': source_ip,
+                'Destination IP': destination_ip,
+                'Forwarding Node': forwarding_node
+            })
+
+            # Add the packet_id to the list of IDs
+            if packet_id not in new_packet_ids:
+                new_packet_ids.add(packet_id)
+        else:
+            forwarded_packets.append({
+                'Timestamp': timestamp,
+                'Source Node': source_node,
+                'Packet ID': packet_id,
+                'TTL': ttl,
+                'Source IP': source_ip,
+                'Destination IP': destination_ip,
+                'Forwarding Node': forwarding_node
+            })
+
+            # Add the packet_id to the list of IDs
+            if packet_id not in new_packet_ids:
+                new_packet_ids.add(packet_id)
+
+        # Update the last timestamp for the packet ID
+        last_timestamps[packet_id] = current_timestamp
+
+# keep track of a few parameters
+packets_delivered = 0
+packets_attacked = 0
+packets_total = 0
+last_timestamp = 0.0
+
+new_packet_ids = sorted(new_packet_ids)
+
+for pktid in list(new_packet_ids):
+    pkts_unique_id = []
+    print_route = True
+
+    for pkt in forwarded_packets:
+        if pkt['Packet ID'] == pktid:
+            pkts_unique_id.append(pkt)
+
+    pkts_unique_id = sorted(pkts_unique_id, key=lambda x: x['Timestamp'])
+    rejected_nodes_info = sorted(rejected_nodes_info, key=lambda x: x['Timestamp'])
+
+    # Packets which have not been recorded as forwarded or sent. (This comes from originating node and a route has already been set up)
+    attack_without_forwarding = False
+    if not any(pkts_unique_id):
+        for attack in attack_info:
+            if attack['Packet ID'] == pktid:
+                attack_without_forwarding = True
+                attack_next_hop = attack['Next Hop']
+                attack_node = attack['Node ID']
+                packets_attacked+=1
+                packets_total+=1
+                break;
+
+    if attack_without_forwarding:
+        print('[' + attack_node + '] Packet ID: ' + str(pktid) + ' Attacked, Next Hop: ' + attack_next_hop)
+        continue
+
+    # we have all forwarding information for the route, now we need to print the route out
+    route_str = '[ID: ' + str(pktid) + '] Timestamp: ' + str(pkts_unique_id[0]['Timestamp']) + ' ' + pkts_unique_id[0]['Source IP']
+
+    num_printed_rejected_nodes = 0
+    for rejected_node in rejected_nodes_info:
+        if rejected_node['Timestamp'] < pkts_unique_id[0]['Timestamp']:
+            print('Node: ' + str(rejected_node['Node ID']) + ' Timestamp: ' + str(rejected_node['Timestamp']) + ' Node Rejected: ' + rejected_node['Rejected Node'])
+            num_printed_rejected_nodes += 1
+    for i in range(num_printed_rejected_nodes):
+        rejected_nodes_info.pop(0)
+
+    for pkt in pkts_unique_id:
+        # record the route
+        route_str += ' -> ' + pkt['Forwarding Node']
+
+        # check if the packet has reached its destination or not
+        if pkt['Destination IP'] == pkt['Forwarding Node']:
+            print_route = False
+            packets_delivered+=1
+            break
+
+    # check if the packet has been intercepted on the route and dropped by the attacker.
+    for attack in attack_info:
+        if attack['Packet ID'] == pktid:
+            print_route = False
+            packets_attacked+=1
+            break
+
+    # total number of packets seen.
+    packets_total+=1
+
+    # print the route.
+    if print_route:
+        print(route_str)
+
+print('packets total: ' + str(packets_total))
+print('packets delivered: ' + str((packets_delivered / packets_total)))
+print('packets attacked (dropped): ' + str((packets_attacked / packets_total)))
+print('packets unaccounted for: ' + str(1 - ((packets_attacked + packets_delivered) / packets_total)))
\ No newline at end of file