A Discrete-Event Network Simulator
API
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
arp-l3-protocol.cc
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 
27 #include "ipv4-l3-protocol.h"
28 #include "arp-l3-protocol.h"
29 #include "arp-header.h"
30 #include "arp-cache.h"
31 #include "ipv4-interface.h"
32 
33 NS_LOG_COMPONENT_DEFINE ("ArpL3Protocol");
34 
35 namespace ns3 {
36 
37 
38 NS_OBJECT_ENSURE_REGISTERED (ArpL3Protocol);
39 
40 TypeId
41 ArpL3Protocol::GetTypeId (void)
42 {
43  static TypeId tid = TypeId ("ns3::ArpL3Protocol")
44  .SetParent<Object> ()
45  .AddConstructor<ArpL3Protocol> ()
46  .AddAttribute ("CacheList",
47  "The list of ARP caches",
48  ObjectVectorValue (),
49  MakeObjectVectorAccessor (&ArpL3Protocol::m_cacheList),
50  MakeObjectVectorChecker<ArpCache> ())
51  .AddTraceSource ("Drop",
52  "Packet dropped because not enough room in pending queue for a specific cache entry.",
53  MakeTraceSourceAccessor (&ArpL3Protocol::m_dropTrace))
54  ;
55  return tid;
56 }
57 
58 ArpL3Protocol::ArpL3Protocol ()
59 {
60  NS_LOG_FUNCTION (this);
61 }
62 
63 ArpL3Protocol::~ArpL3Protocol ()
64 {
65  NS_LOG_FUNCTION (this);
66 }
67 
68 void
69 ArpL3Protocol::SetNode (Ptr<Node> node)
70 {
71  NS_LOG_FUNCTION (this << node);
72  m_node = node;
73 }
74 
75 /*
76  * This method is called by AddAgregate and completes the aggregation
77  * by setting the node in the ipv4 stack
78  */
79 void
81 {
82  NS_LOG_FUNCTION (this);
83  if (m_node == 0)
84  {
85  Ptr<Node>node = this->GetObject<Node> ();
86  //verify that it's a valid node and that
87  //the node was not set before
88  if (node != 0)
89  {
90  this->SetNode (node);
91  }
92  }
94 }
95 
96 void
98 {
99  NS_LOG_FUNCTION (this);
100  for (CacheList::iterator i = m_cacheList.begin (); i != m_cacheList.end (); ++i)
101  {
102  Ptr<ArpCache> cache = *i;
103  cache->Dispose ();
104  }
105  m_cacheList.clear ();
106  m_node = 0;
108 }
109 
111 ArpL3Protocol::CreateCache (Ptr<NetDevice> device, Ptr<Ipv4Interface> interface)
112 {
113  NS_LOG_FUNCTION (this << device << interface);
114  Ptr<Ipv4L3Protocol> ipv4 = m_node->GetObject<Ipv4L3Protocol> ();
115  Ptr<ArpCache> cache = CreateObject<ArpCache> ();
116  cache->SetDevice (device, interface);
117  NS_ASSERT (device->IsBroadcast ());
118  device->AddLinkChangeCallback (MakeCallback (&ArpCache::Flush, cache));
119  cache->SetArpRequestCallback (MakeCallback (&ArpL3Protocol::SendArpRequest, this));
120  m_cacheList.push_back (cache);
121  return cache;
122 }
123 
124 Ptr<ArpCache>
125 ArpL3Protocol::FindCache (Ptr<NetDevice> device)
126 {
127  NS_LOG_FUNCTION (this << device);
128  for (CacheList::const_iterator i = m_cacheList.begin (); i != m_cacheList.end (); i++)
129  {
130  if ((*i)->GetDevice () == device)
131  {
132  return *i;
133  }
134  }
135  NS_ASSERT (false);
136  // quiet compiler
137  return 0;
138 }
139 
140 void
141 ArpL3Protocol::Receive (Ptr<NetDevice> device, Ptr<const Packet> p, uint16_t protocol, const Address &from,
142  const Address &to, NetDevice::PacketType packetType)
143 {
144  NS_LOG_FUNCTION (this << device << p->GetSize () << protocol << from << to << packetType);
145 
146  Ptr<Packet> packet = p->Copy ();
147 
148  NS_LOG_LOGIC ("ARP: received packet of size "<< packet->GetSize ());
149 
150  Ptr<ArpCache> cache = FindCache (device);
151 
152  //
153  // If we're connected to a real world network, then some of the fields sizes
154  // in an ARP packet can vary in ways not seen in simulations. We need to be
155  // able to detect ARP packets with headers we don't recongnize and not process
156  // them instead of crashing. The ArpHeader will return 0 if it can't deal
157  // with the received header.
158  //
159  ArpHeader arp;
160  uint32_t size = packet->RemoveHeader (arp);
161  if (size == 0)
162  {
163  NS_LOG_LOGIC ("ARP: Cannot remove ARP header");
164  return;
165  }
166  NS_LOG_LOGIC ("ARP: received "<< (arp.IsRequest () ? "request" : "reply") <<
167  " node="<<m_node->GetId ()<<", got request from " <<
168  arp.GetSourceIpv4Address () << " for address " <<
169  arp.GetDestinationIpv4Address () << "; we have addresses: ");
170  for (uint32_t i = 0; i < cache->GetInterface ()->GetNAddresses (); i++)
171  {
172  NS_LOG_LOGIC (cache->GetInterface ()->GetAddress (i).GetLocal () << ", ");
173  }
174 
179  bool found = false;
180  for (uint32_t i = 0; i < cache->GetInterface ()->GetNAddresses (); i++)
181  {
182  if (arp.IsRequest () && arp.GetDestinationIpv4Address () ==
183  cache->GetInterface ()->GetAddress (i).GetLocal ())
184  {
185  found = true;
186  NS_LOG_LOGIC ("node="<<m_node->GetId () <<", got request from " <<
187  arp.GetSourceIpv4Address () << " -- send reply");
188  SendArpReply (cache, arp.GetDestinationIpv4Address (), arp.GetSourceIpv4Address (),
189  arp.GetSourceHardwareAddress ());
190  break;
191  }
192  else if (arp.IsReply () &&
193  arp.GetDestinationIpv4Address ().IsEqual (cache->GetInterface ()->GetAddress (i).GetLocal ()) &&
194  arp.GetDestinationHardwareAddress () == device->GetAddress ())
195  {
196  found = true;
197  Ipv4Address from = arp.GetSourceIpv4Address ();
198  ArpCache::Entry *entry = cache->Lookup (from);
199  if (entry != 0)
200  {
201  if (entry->IsWaitReply ())
202  {
203  NS_LOG_LOGIC ("node="<< m_node->GetId () <<
204  ", got reply from " << arp.GetSourceIpv4Address ()
205  << " for waiting entry -- flush");
206  Address from_mac = arp.GetSourceHardwareAddress ();
207  entry->MarkAlive (from_mac);
208  Ptr<Packet> pending = entry->DequeuePending ();
209  while (pending != 0)
210  {
211  cache->GetInterface ()->Send (pending,
212  arp.GetSourceIpv4Address ());
213  pending = entry->DequeuePending ();
214  }
215  }
216  else
217  {
218  // ignore this reply which might well be an attempt
219  // at poisening my arp cache.
220  NS_LOG_LOGIC ("node="<<m_node->GetId ()<<", got reply from " <<
221  arp.GetSourceIpv4Address () <<
222  " for non-waiting entry -- drop");
223  m_dropTrace (packet);
224  }
225  }
226  else
227  {
228  NS_LOG_LOGIC ("node="<<m_node->GetId ()<<", got reply for unknown entry -- drop");
229  m_dropTrace (packet);
230  }
231  break;
232  }
233  }
234  if (found == false)
235  {
236  NS_LOG_LOGIC ("node="<<m_node->GetId ()<<", got request from " <<
237  arp.GetSourceIpv4Address () << " for unknown address " <<
238  arp.GetDestinationIpv4Address () << " -- drop");
239  }
240 }
241 
242 bool
244  Ptr<NetDevice> device,
245  Ptr<ArpCache> cache,
246  Address *hardwareDestination)
247 {
248  NS_LOG_FUNCTION (this << packet << destination << device << cache << hardwareDestination);
249  ArpCache::Entry *entry = cache->Lookup (destination);
250  if (entry != 0)
251  {
252  if (entry->IsExpired ())
253  {
254  if (entry->IsDead ())
255  {
256  NS_LOG_LOGIC ("node="<<m_node->GetId ()<<
257  ", dead entry for " << destination << " expired -- send arp request");
258  entry->MarkWaitReply (packet);
259  SendArpRequest (cache, destination);
260  }
261  else if (entry->IsAlive ())
262  {
263  NS_LOG_LOGIC ("node="<<m_node->GetId ()<<
264  ", alive entry for " << destination << " expired -- send arp request");
265  entry->MarkWaitReply (packet);
266  SendArpRequest (cache, destination);
267  }
268  else if (entry->IsWaitReply ())
269  {
270  NS_FATAL_ERROR ("Test for possibly unreachable code-- please file a bug report, with a test case, if this is ever hit");
271  }
272  }
273  else
274  {
275  if (entry->IsDead ())
276  {
277  NS_LOG_LOGIC ("node="<<m_node->GetId ()<<
278  ", dead entry for " << destination << " valid -- drop");
279  m_dropTrace (packet);
280  }
281  else if (entry->IsAlive ())
282  {
283  NS_LOG_LOGIC ("node="<<m_node->GetId ()<<
284  ", alive entry for " << destination << " valid -- send");
285  Address destAddress = entry->GetMacAddress();
287  int bytes = packet->PeekPacketTag(bt);
288  if (!bytes && m_node->IsCognitiveRadio()) {
289  destAddress = destAddress + (RECEIVER_RADIO-CONTROL_RADIO); // go to RX MAC on receiver
290  }
291  *hardwareDestination = destAddress;
292  return true;
293  }
294  else if (entry->IsWaitReply ())
295  {
296  NS_LOG_LOGIC ("node="<<m_node->GetId ()<<
297  ", wait reply for " << destination << " valid -- drop previous");
298  if (!entry->UpdateWaitReply (packet))
299  {
300  m_dropTrace (packet);
301  }
302  }
303  }
304  }
305  else
306  {
307  // This is our first attempt to transmit data to this destination.
308  NS_LOG_LOGIC ("node="<<m_node->GetId ()<<
309  ", no entry for " << destination << " -- send arp request");
310  entry = cache->Add (destination);
311  entry->MarkWaitReply (packet);
312  SendArpRequest (cache, destination);
313  }
314  return false;
315 }
316 
317 void
318 ArpL3Protocol::SendArpRequest (Ptr<const ArpCache> cache, Ipv4Address to)
319 {
320  NS_LOG_FUNCTION (this << cache << to);
321  ArpHeader arp;
322  // need to pick a source address; use routing implementation to select
323  Ptr<Ipv4L3Protocol> ipv4 = m_node->GetObject<Ipv4L3Protocol> ();
324  Ptr<NetDevice> device = cache->GetDevice ();
325  NS_ASSERT (device != 0);
326  Ipv4Header header;
327  header.SetDestination (to);
328  Ptr<Packet> packet = Create<Packet> ();
329  Ipv4Address source = ipv4->SelectSourceAddress (device, to, Ipv4InterfaceAddress::GLOBAL);
330  NS_LOG_LOGIC ("ARP: sending request from node "<<m_node->GetId ()<<
331  " || src: " << device->GetAddress () << " / " << source <<
332  " || dst: " << device->GetBroadcast () << " / " << to);
333  arp.SetRequest (device->GetAddress (), source, device->GetBroadcast (), to);
334  packet->AddHeader (arp);
335  cache->GetDevice ()->Send (packet, device->GetBroadcast (), PROT_NUMBER);
336 }
337 
338 void
339 ArpL3Protocol::SendArpReply (Ptr<const ArpCache> cache, Ipv4Address myIp, Ipv4Address toIp, Address toMac)
340 {
341  NS_LOG_FUNCTION (this << cache << myIp << toIp << toMac);
342  ArpHeader arp;
343  NS_LOG_LOGIC ("ARP: sending reply from node "<<m_node->GetId ()<<
344  "|| src: " << cache->GetDevice ()->GetAddress () <<
345  " / " << myIp <<
346  " || dst: " << toMac << " / " << toIp);
347  arp.SetReply (cache->GetDevice ()->GetAddress (), myIp, toMac, toIp);
348  Ptr<Packet> packet = Create<Packet> ();
349  packet->AddHeader (arp);
350  cache->GetDevice ()->Send (packet, toMac, PROT_NUMBER);
351 }
352 
353 } // namespace ns3
void SetDevice(Ptr< NetDevice > device, Ptr< Ipv4Interface > interface)
Definition: arp-cache.cc:102
void Receive(Ptr< NetDevice > device, Ptr< const Packet > p, uint16_t protocol, const Address &from, const Address &to, NetDevice::PacketType packetType)
Receive a packet.
void SetDestination(Ipv4Address destination)
Definition: ipv4-header.cc:297
#define NS_LOG_FUNCTION(parameters)
Definition: log.h:311
ArpCache::Entry * Add(Ipv4Address to)
Add an Ipv4Address to this ARP cache.
Definition: arp-cache.cc:258
ArpCache::Entry * Lookup(Ipv4Address destination)
Do lookup in the ARP cache against an IP address.
Definition: arp-cache.cc:246
#define NS_ASSERT(condition)
Definition: assert.h:64
#define NS_LOG_COMPONENT_DEFINE(name)
Definition: log.h:122
uint32_t GetSize(void) const
Definition: packet.h:620
virtual void DoDispose(void)
Definition: object.cc:335
The packet header for an ARP packet.
Definition: arp-header.h:34
bool IsAlive(void)
Definition: arp-cache.cc:285
#define NS_FATAL_ERROR(msg)
fatal error handling
Definition: fatal-error.h:72
a polymophic address class
Definition: address.h:86
Packet header for IPv4.
Definition: ipv4-header.h:31
bool PeekPacketTag(Tag &tag) const
Definition: packet.cc:881
virtual void NotifyNewAggregate()
virtual void DoDispose(void)
void MarkWaitReply(Ptr< Packet > waiting)
Definition: arp-cache.cc:334
bool IsDead(void)
Definition: arp-cache.cc:279
Callback< R > MakeCallback(R(T::*memPtr)(void), OBJ objPtr)
Definition: callback.h:502
bool IsExpired(void) const
Definition: arp-cache.cc:382
#define NS_LOG_LOGIC(msg)
Definition: log.h:334
Address GetMacAddress(void) const
Definition: arp-cache.cc:346
virtual void NotifyNewAggregate(void)
Definition: object.cc:314
Ptr< Packet > Copy(void) const
Definition: packet.cc:131
Implement the Ipv4 layer.
bool IsEqual(const Ipv4Address &other) const
Comparison operation between two Ipv4Addresses.
Definition: ipv4-address.h:81
Ptr< const TraceSourceAccessor > MakeTraceSourceAccessor(T a)
void MarkAlive(Address macAddress)
Definition: arp-cache.cc:307
A record that that holds information about an ArpCache entry.
Definition: arp-cache.h:116
void Flush(void)
Clear the ArpCache of all entries.
Definition: arp-cache.cc:230
bool UpdateWaitReply(Ptr< Packet > waiting)
Definition: arp-cache.cc:318
Ipv4 addresses are stored in host order in this class.
Definition: ipv4-address.h:38
uint32_t GetId(void) const
Definition: node.cc:105
bool Lookup(Ptr< Packet > p, Ipv4Address destination, Ptr< NetDevice > device, Ptr< ArpCache > cache, Address *hardwareDestination)
Perform an ARP lookup.
bool IsWaitReply(void)
Definition: arp-cache.cc:291
Ptr< Packet > DequeuePending(void)
Definition: arp-cache.cc:395
Ptr< T > GetObject(void) const
Definition: object.h:332
void Dispose(void)
Definition: object.cc:204
void AddHeader(const Header &header)
Definition: packet.cc:270