src/internet-stack/arp-l3-protocol.cc
author Pavel Boyko <boyko@iitp.ru>
Thu Aug 06 10:23:12 2009 +0400 (2009-08-06)
changeset 4696 5ef92ccda11a
parent 4669 8aaa5e83939e
child 4764 e90e1ef585b0
child 5671 b1fce73037f8
permissions -rw-r--r--
Route lookup removed in ARP request (see bug 606)
     1 /* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
     2 /*
     3  * Copyright (c) 2006 INRIA
     4  *
     5  * This program is free software; you can redistribute it and/or modify
     6  * it under the terms of the GNU General Public License version 2 as
     7  * published by the Free Software Foundation;
     8  *
     9  * This program is distributed in the hope that it will be useful,
    10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    12  * GNU General Public License for more details.
    13  *
    14  * You should have received a copy of the GNU General Public License
    15  * along with this program; if not, write to the Free Software
    16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    17  *
    18  * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
    19  */
    20 #include "ns3/packet.h"
    21 #include "ns3/log.h"
    22 #include "ns3/node.h"
    23 #include "ns3/net-device.h"
    24 #include "ns3/object-vector.h"
    25 #include "ns3/trace-source-accessor.h"
    26 #include "ns3/ipv4-route.h"
    27 
    28 #include "ipv4-l3-protocol.h"
    29 #include "arp-l3-protocol.h"
    30 #include "arp-header.h"
    31 #include "arp-cache.h"
    32 #include "ipv4-interface.h"
    33 
    34 NS_LOG_COMPONENT_DEFINE ("ArpL3Protocol");
    35 
    36 namespace ns3 {
    37 
    38 const uint16_t ArpL3Protocol::PROT_NUMBER = 0x0806;
    39 
    40 NS_OBJECT_ENSURE_REGISTERED (ArpL3Protocol);
    41 
    42 TypeId 
    43 ArpL3Protocol::GetTypeId (void)
    44 {
    45   static TypeId tid = TypeId ("ns3::ArpL3Protocol")
    46     .SetParent<Object> ()
    47     .AddConstructor<ArpL3Protocol> ()
    48     .AddAttribute ("CacheList",
    49                    "The list of ARP caches",
    50                    ObjectVectorValue (),
    51                    MakeObjectVectorAccessor (&ArpL3Protocol::m_cacheList),
    52                    MakeObjectVectorChecker<ArpCache> ())
    53     .AddTraceSource ("Drop",
    54                      "Packet dropped because not enough room in pending queue for a specific cache entry.",
    55                      MakeTraceSourceAccessor (&ArpL3Protocol::m_dropTrace))
    56     ;
    57   return tid;
    58 }
    59 
    60 ArpL3Protocol::ArpL3Protocol ()
    61 {
    62   NS_LOG_FUNCTION (this);
    63 }
    64 
    65 ArpL3Protocol::~ArpL3Protocol ()
    66 {
    67   NS_LOG_FUNCTION (this);
    68 }
    69 
    70 void 
    71 ArpL3Protocol::SetNode (Ptr<Node> node)
    72 {
    73   NS_LOG_FUNCTION (this);
    74   m_node = node;
    75 }
    76 
    77 /*
    78  * This method is called by AddAgregate and completes the aggregation
    79  * by setting the node in the ipv4 stack
    80  */
    81 void
    82 ArpL3Protocol::NotifyNewAggregate ()
    83 {
    84   if (m_node == 0)
    85     {
    86       Ptr<Node>node = this->GetObject<Node> ();
    87       //verify that it's a valid node and that
    88       //the node was not set before
    89       if (node != 0)
    90         {
    91           this->SetNode (node);
    92         }
    93     }
    94   Object::NotifyNewAggregate ();
    95 }
    96 
    97 void 
    98 ArpL3Protocol::DoDispose (void)
    99 {
   100   NS_LOG_FUNCTION (this);
   101   for (CacheList::iterator i = m_cacheList.begin (); i != m_cacheList.end (); ++i)
   102     {
   103       Ptr<ArpCache> cache = *i;
   104       cache->Dispose ();
   105     }
   106   m_cacheList.clear ();
   107   m_node = 0;
   108   Object::DoDispose ();
   109 }
   110 
   111 Ptr<ArpCache> 
   112 ArpL3Protocol::CreateCache (Ptr<NetDevice> device, Ptr<Ipv4Interface> interface)
   113 {
   114   NS_LOG_FUNCTION (this << device << interface);
   115   Ptr<Ipv4L3Protocol> ipv4 = m_node->GetObject<Ipv4L3Protocol> ();
   116   Ptr<ArpCache> cache = CreateObject<ArpCache> ();
   117   cache->SetDevice (device, interface);
   118   NS_ASSERT (device->IsBroadcast ());
   119   device->SetLinkChangeCallback (MakeCallback (&ArpCache::Flush, cache));
   120   cache->SetArpRequestCallback (MakeCallback (&ArpL3Protocol::SendArpRequest, this));
   121   m_cacheList.push_back (cache);
   122   return cache;
   123 }
   124 
   125 Ptr<ArpCache>
   126 ArpL3Protocol::FindCache (Ptr<NetDevice> device)
   127 {
   128   NS_LOG_FUNCTION (this << device);
   129   for (CacheList::const_iterator i = m_cacheList.begin (); i != m_cacheList.end (); i++)
   130     {
   131       if ((*i)->GetDevice () == device)
   132 	{
   133 	  return *i;
   134 	}
   135     }
   136   NS_ASSERT (false);
   137   // quiet compiler
   138   return 0;
   139 }
   140 
   141 void 
   142 ArpL3Protocol::Receive(Ptr<NetDevice> device, Ptr<const Packet> p, uint16_t protocol, const Address &from,
   143                        const Address &to, NetDevice::PacketType packetType)
   144 {
   145   NS_LOG_FUNCTION (this << device << p->GetSize () << protocol << from << to << packetType);
   146 
   147   Ptr<Packet> packet = p->Copy ();
   148 
   149   NS_LOG_LOGIC ("ARP: received packet of size "<< packet->GetSize ());
   150 
   151   Ptr<ArpCache> cache = FindCache (device);
   152 
   153   // 
   154   // If we're connected to a real world network, then some of the fields sizes 
   155   // in an ARP packet can vary in ways not seen in simulations.  We need to be
   156   // able to detect ARP packets with headers we don't recongnize and not process
   157   // them instead of crashing.  The ArpHeader will return 0 if it can't deal
   158   // with the received header.
   159   //
   160   ArpHeader arp;
   161   uint32_t size = packet->RemoveHeader (arp);
   162   if (size == 0)
   163     {
   164       NS_LOG_LOGIC ("ARP: Cannot remove ARP header");
   165       return;
   166     }
   167   NS_LOG_LOGIC ("ARP: received "<< (arp.IsRequest ()? "request" : "reply") <<
   168             " node="<<m_node->GetId ()<<", got request from " <<
   169             arp.GetSourceIpv4Address () << " for address " <<
   170             arp.GetDestinationIpv4Address () << "; we have addresses: ");
   171   for (uint32_t i = 0; i < cache->GetInterface ()->GetNAddresses (); i++)
   172     {
   173       NS_LOG_LOGIC (cache->GetInterface ()->GetAddress (i).GetLocal () << ", ");
   174     }
   175 
   176   /**
   177    * Note: we do not update the ARP cache when we receive an ARP request
   178    * from an unknown node. See bug #107
   179    */
   180   bool found = false;
   181   for (uint32_t i = 0; i < cache->GetInterface ()->GetNAddresses (); i++)
   182     {
   183       if (arp.IsRequest () && arp.GetDestinationIpv4Address () == 
   184         cache->GetInterface ()->GetAddress (i).GetLocal ()) 
   185         {
   186           found = true;
   187           NS_LOG_LOGIC ("node="<<m_node->GetId () <<", got request from " << 
   188                 arp.GetSourceIpv4Address () << " -- send reply");
   189           SendArpReply (cache, arp.GetDestinationIpv4Address (), arp.GetSourceIpv4Address (),
   190                     arp.GetSourceHardwareAddress ());
   191           break;
   192         } 
   193       else if (arp.IsReply () && 
   194         arp.GetDestinationIpv4Address ().IsEqual (cache->GetInterface ()->GetAddress (i).GetLocal ()) &&
   195         arp.GetDestinationHardwareAddress () == device->GetAddress ()) 
   196         {
   197           found = true;
   198           Ipv4Address from = arp.GetSourceIpv4Address ();
   199           ArpCache::Entry *entry = cache->Lookup (from);
   200           if (entry != 0)
   201             {
   202               if (entry->IsWaitReply ()) 
   203                 {
   204                   NS_LOG_LOGIC ("node="<< m_node->GetId () << 
   205                     ", got reply from " << arp.GetSourceIpv4Address ()
   206                      << " for waiting entry -- flush");
   207                   Address from_mac = arp.GetSourceHardwareAddress ();
   208                   entry->MarkAlive (from_mac);
   209                   Ptr<Packet> pending = entry->DequeuePending();
   210                   while (pending != 0)
   211                     {
   212                       cache->GetInterface ()->Send (pending,
   213                                                 arp.GetSourceIpv4Address ());
   214                       pending = entry->DequeuePending();
   215                     }
   216                 } 
   217               else 
   218                 {
   219                   // ignore this reply which might well be an attempt 
   220                   // at poisening my arp cache.
   221                   NS_LOG_LOGIC("node="<<m_node->GetId ()<<", got reply from " << 
   222                         arp.GetSourceIpv4Address () << 
   223                         " for non-waiting entry -- drop");
   224                   m_dropTrace (packet);
   225                 }
   226             } 
   227           else 
   228             {
   229               NS_LOG_LOGIC ("node="<<m_node->GetId ()<<", got reply for unknown entry -- drop");
   230               m_dropTrace (packet);
   231             }
   232           break;
   233         }
   234     }
   235   if (found == false)
   236     {
   237       NS_LOG_LOGIC ("node="<<m_node->GetId ()<<", got request from " <<
   238                 arp.GetSourceIpv4Address () << " for unknown address " <<
   239                 arp.GetDestinationIpv4Address () << " -- drop");
   240     }
   241 }
   242 
   243 bool 
   244 ArpL3Protocol::Lookup (Ptr<Packet> packet, Ipv4Address destination, 
   245                        Ptr<NetDevice> device,
   246                        Ptr<ArpCache> cache,
   247                        Address *hardwareDestination)
   248 {
   249   NS_LOG_FUNCTION (this << packet << destination << device << cache);
   250   ArpCache::Entry *entry = cache->Lookup (destination);
   251   if (entry != 0)
   252     {
   253       if (entry->IsExpired ()) 
   254         {
   255           if (entry->IsDead ()) 
   256             {
   257               NS_LOG_LOGIC ("node="<<m_node->GetId ()<<
   258                         ", dead entry for " << destination << " expired -- send arp request");
   259               entry->MarkWaitReply (packet);
   260               SendArpRequest (cache, destination);
   261             } 
   262           else if (entry->IsAlive ()) 
   263             {
   264               NS_LOG_LOGIC ("node="<<m_node->GetId ()<<
   265                         ", alive entry for " << destination << " expired -- send arp request");
   266               entry->MarkWaitReply (packet);
   267               SendArpRequest (cache, destination);
   268             } 
   269           else if (entry->IsWaitReply ()) 
   270             {
   271               NS_FATAL_ERROR ("Test for possibly unreachable code-- please file a bug report, with a test case, if this is ever hit");
   272             }
   273         } 
   274       else 
   275         {
   276           if (entry->IsDead ()) 
   277             {
   278               NS_LOG_LOGIC ("node="<<m_node->GetId ()<<
   279                             ", dead entry for " << destination << " valid -- drop");
   280               m_dropTrace (packet);
   281             } 
   282           else if (entry->IsAlive ()) 
   283             {
   284               NS_LOG_LOGIC ("node="<<m_node->GetId ()<<
   285                             ", alive entry for " << destination << " valid -- send");
   286 	      *hardwareDestination = entry->GetMacAddress ();
   287               return true;
   288             } 
   289           else if (entry->IsWaitReply ()) 
   290             {
   291               NS_LOG_LOGIC ("node="<<m_node->GetId ()<<
   292                             ", wait reply for " << destination << " valid -- drop previous");
   293               if (!entry->UpdateWaitReply (packet))
   294                 {
   295                   m_dropTrace (packet);
   296                 }
   297             }
   298         }
   299     }
   300   else
   301     {
   302       // This is our first attempt to transmit data to this destination.
   303       NS_LOG_LOGIC ("node="<<m_node->GetId ()<<
   304                 ", no entry for " << destination << " -- send arp request");
   305       entry = cache->Add (destination);
   306       entry->MarkWaitReply (packet);
   307       SendArpRequest (cache, destination);
   308     }
   309   return false;
   310 }
   311 
   312 void
   313 ArpL3Protocol::SendArpRequest (Ptr<const ArpCache> cache, Ipv4Address to)
   314 {
   315   NS_LOG_FUNCTION (this << cache << to);
   316   ArpHeader arp;
   317   // need to pick a source address; use routing implementation to select
   318   Ptr<Ipv4L3Protocol> ipv4 = m_node->GetObject<Ipv4L3Protocol> ();
   319   int32_t interface = ipv4->GetInterfaceForDevice (cache->GetDevice ());
   320   NS_ASSERT (interface >= 0);
   321   Ipv4Header header;
   322   header.SetDestination (to);
   323   Socket::SocketErrno errno_;
   324   Ptr<Packet> packet = Create<Packet> ();
   325   Ptr<Ipv4Route> route = ipv4->GetRoutingProtocol ()->RouteOutput (packet, header, interface, errno_);
   326   NS_ASSERT (route != 0);
   327   NS_LOG_LOGIC ("ARP: sending request from node "<<m_node->GetId ()<<
   328             " || src: " << cache->GetDevice ()->GetAddress () <<
   329             " / " << route->GetSource () <<
   330             " || dst: " << cache->GetDevice ()->GetBroadcast () <<
   331             " / " << to);
   332   arp.SetRequest (cache->GetDevice ()->GetAddress (),
   333 		  route->GetSource (),
   334                   cache->GetDevice ()->GetBroadcast (),
   335                   to);
   336   packet->AddHeader (arp);
   337   cache->GetDevice ()->Send (packet, cache->GetDevice ()->GetBroadcast (), PROT_NUMBER);
   338 }
   339 
   340 void
   341 ArpL3Protocol::SendArpReply (Ptr<const ArpCache> cache, Ipv4Address myIp, Ipv4Address toIp, Address toMac)
   342 {
   343   NS_LOG_FUNCTION (this << cache << toIp << toMac);
   344   ArpHeader arp;
   345   NS_LOG_LOGIC ("ARP: sending reply from node "<<m_node->GetId ()<<
   346             "|| src: " << cache->GetDevice ()->GetAddress () << 
   347             " / " << myIp <<
   348             " || dst: " << toMac << " / " << toIp);
   349   arp.SetReply (cache->GetDevice ()->GetAddress (), myIp, toMac, toIp);
   350   Ptr<Packet> packet = Create<Packet> ();
   351   packet->AddHeader (arp);
   352   cache->GetDevice ()->Send (packet, toMac, PROT_NUMBER);
   353 }
   354 
   355 }//namespace ns3