A Discrete-Event Network Simulator
API
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
arp-l3-protocol.cc
Go to the documentation of this file.
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 const uint16_t ArpL3Protocol::PROT_NUMBER = 0x0806;
38 
39 NS_OBJECT_ENSURE_REGISTERED (ArpL3Protocol);
40 
41 TypeId
43 {
44  static TypeId tid = TypeId ("ns3::ArpL3Protocol")
45  .SetParent<Object> ()
46  .AddConstructor<ArpL3Protocol> ()
47  .AddAttribute ("CacheList",
48  "The list of ARP caches",
51  MakeObjectVectorChecker<ArpCache> ())
52  .AddTraceSource ("Drop",
53  "Packet dropped because not enough room in pending queue for a specific cache entry.",
55  ;
56  return tid;
57 }
58 
60 {
61  NS_LOG_FUNCTION (this);
62 }
63 
65 {
66  NS_LOG_FUNCTION (this);
67 }
68 
69 void
71 {
72  NS_LOG_FUNCTION (this);
73  m_node = node;
74 }
75 
76 /*
77  * This method is called by AddAgregate and completes the aggregation
78  * by setting the node in the ipv4 stack
79  */
80 void
82 {
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 
112 {
113  NS_LOG_FUNCTION (this << device << interface);
115  Ptr<ArpCache> cache = CreateObject<ArpCache> ();
116  cache->SetDevice (device, interface);
117  NS_ASSERT (device->IsBroadcast ());
119  cache->SetArpRequestCallback (MakeCallback (&ArpL3Protocol::SendArpRequest, this));
120  m_cacheList.push_back (cache);
121  return cache;
122 }
123 
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");
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);
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  *hardwareDestination = entry->GetMacAddress ();
286  return true;
287  }
288  else if (entry->IsWaitReply ())
289  {
290  NS_LOG_LOGIC ("node="<<m_node->GetId ()<<
291  ", wait reply for " << destination << " valid -- drop previous");
292  if (!entry->UpdateWaitReply (packet))
293  {
294  m_dropTrace (packet);
295  }
296  }
297  }
298  }
299  else
300  {
301  // This is our first attempt to transmit data to this destination.
302  NS_LOG_LOGIC ("node="<<m_node->GetId ()<<
303  ", no entry for " << destination << " -- send arp request");
304  entry = cache->Add (destination);
305  entry->MarkWaitReply (packet);
306  SendArpRequest (cache, destination);
307  }
308  return false;
309 }
310 
311 void
313 {
314  NS_LOG_FUNCTION (this << cache << to);
315  ArpHeader arp;
316  // need to pick a source address; use routing implementation to select
318  Ptr<NetDevice> device = cache->GetDevice ();
319  NS_ASSERT (device != 0);
320  Ipv4Header header;
321  header.SetDestination (to);
322  Ptr<Packet> packet = Create<Packet> ();
323  Ipv4Address source = ipv4->SelectSourceAddress (device, to, Ipv4InterfaceAddress::GLOBAL);
324  NS_LOG_LOGIC ("ARP: sending request from node "<<m_node->GetId ()<<
325  " || src: " << device->GetAddress () << " / " << source <<
326  " || dst: " << device->GetBroadcast () << " / " << to);
327  arp.SetRequest (device->GetAddress (), source, device->GetBroadcast (), to);
328  packet->AddHeader (arp);
329  cache->GetDevice ()->Send (packet, device->GetBroadcast (), PROT_NUMBER);
330 }
331 
332 void
334 {
335  NS_LOG_FUNCTION (this << cache << toIp << toMac);
336  ArpHeader arp;
337  NS_LOG_LOGIC ("ARP: sending reply from node "<<m_node->GetId ()<<
338  "|| src: " << cache->GetDevice ()->GetAddress () <<
339  " / " << myIp <<
340  " || dst: " << toMac << " / " << toIp);
341  arp.SetReply (cache->GetDevice ()->GetAddress (), myIp, toMac, toIp);
342  Ptr<Packet> packet = Create<Packet> ();
343  packet->AddHeader (arp);
344  cache->GetDevice ()->Send (packet, toMac, PROT_NUMBER);
345 }
346 
347 } // namespace ns3