1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2005 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 
21 #include "ns3/assert.h"
22 #include "ns3/abort.h"
23 #include "ns3/log.h"
24 #include "ns3/header.h"
25 #include "ipv4-header.h"
26 
27 namespace ns3 {
28 
29 NS_LOG_COMPONENT_DEFINE ("Ipv4Header");
30 
31 NS_OBJECT_ENSURE_REGISTERED (Ipv4Header);
32 
Ipv4Header()33 Ipv4Header::Ipv4Header ()
34   : m_calcChecksum (false),
35     m_payloadSize (0),
36     m_identification (0),
37     m_tos (0),
38     m_ttl (0),
39     m_protocol (0),
40     m_flags (0),
41     m_fragmentOffset (0),
42     m_checksum (0),
43     m_goodChecksum (true),
44     m_headerSize(5*4)
45 {
46 }
47 
48 void
EnableChecksum(void)49 Ipv4Header::EnableChecksum (void)
50 {
51   NS_LOG_FUNCTION (this);
52   m_calcChecksum = true;
53 }
54 
55 void
SetPayloadSize(uint16_t size)56 Ipv4Header::SetPayloadSize (uint16_t size)
57 {
58   NS_LOG_FUNCTION (this << size);
59   m_payloadSize = size;
60 }
61 uint16_t
GetPayloadSize(void) const62 Ipv4Header::GetPayloadSize (void) const
63 {
64   NS_LOG_FUNCTION (this);
65   return m_payloadSize;
66 }
67 
68 uint16_t
GetIdentification(void) const69 Ipv4Header::GetIdentification (void) const
70 {
71   NS_LOG_FUNCTION (this);
72   return m_identification;
73 }
74 void
SetIdentification(uint16_t identification)75 Ipv4Header::SetIdentification (uint16_t identification)
76 {
77   NS_LOG_FUNCTION (this << identification);
78   m_identification = identification;
79 }
80 
81 void
SetTos(uint8_t tos)82 Ipv4Header::SetTos (uint8_t tos)
83 {
84   NS_LOG_FUNCTION (this << static_cast<uint32_t> (tos));
85   m_tos = tos;
86 }
87 
88 void
SetDscp(DscpType dscp)89 Ipv4Header::SetDscp (DscpType dscp)
90 {
91   NS_LOG_FUNCTION (this << dscp);
92   m_tos &= 0x3; // Clear out the DSCP part, retain 2 bits of ECN
93   m_tos |= (dscp << 2);
94 }
95 
96 void
SetEcn(EcnType ecn)97 Ipv4Header::SetEcn (EcnType ecn)
98 {
99   NS_LOG_FUNCTION (this << ecn);
100   m_tos &= 0xFC; // Clear out the ECN part, retain 6 bits of DSCP
101   m_tos |= ecn;
102 }
103 
104 Ipv4Header::DscpType
GetDscp(void) const105 Ipv4Header::GetDscp (void) const
106 {
107   NS_LOG_FUNCTION (this);
108   // Extract only first 6 bits of TOS byte, i.e 0xFC
109   return DscpType ((m_tos & 0xFC) >> 2);
110 }
111 
112 std::string
DscpTypeToString(DscpType dscp) const113 Ipv4Header::DscpTypeToString (DscpType dscp) const
114 {
115   NS_LOG_FUNCTION (this << dscp);
116   switch (dscp)
117     {
118       case DscpDefault:
119         return "Default";
120       case DSCP_CS1:
121         return "CS1";
122       case DSCP_AF11:
123         return "AF11";
124       case DSCP_AF12:
125         return "AF12";
126       case DSCP_AF13:
127         return "AF13";
128       case DSCP_CS2:
129         return "CS2";
130       case DSCP_AF21:
131         return "AF21";
132       case DSCP_AF22:
133         return "AF22";
134       case DSCP_AF23:
135         return "AF23";
136       case DSCP_CS3:
137         return "CS3";
138       case DSCP_AF31:
139         return "AF31";
140       case DSCP_AF32:
141         return "AF32";
142       case DSCP_AF33:
143         return "AF33";
144       case DSCP_CS4:
145         return "CS4";
146       case DSCP_AF41:
147         return "AF41";
148       case DSCP_AF42:
149         return "AF42";
150       case DSCP_AF43:
151         return "AF43";
152       case DSCP_CS5:
153         return "CS5";
154       case DSCP_EF:
155         return "EF";
156       case DSCP_CS6:
157         return "CS6";
158       case DSCP_CS7:
159         return "CS7";
160       default:
161         return "Unrecognized DSCP";
162     };
163 }
164 
165 
166 Ipv4Header::EcnType
GetEcn(void) const167 Ipv4Header::GetEcn (void) const
168 {
169   NS_LOG_FUNCTION (this);
170   // Extract only last 2 bits of TOS byte, i.e 0x3
171   return EcnType (m_tos & 0x3);
172 }
173 
174 std::string
EcnTypeToString(EcnType ecn) const175 Ipv4Header::EcnTypeToString (EcnType ecn) const
176 {
177   NS_LOG_FUNCTION (this << ecn);
178   switch (ecn)
179     {
180       case ECN_NotECT:
181         return "Not-ECT";
182       case ECN_ECT1:
183         return "ECT (1)";
184       case ECN_ECT0:
185         return "ECT (0)";
186       case ECN_CE:
187         return "CE";
188       default:
189         return "Unknown ECN";
190     };
191 }
192 
193 uint8_t
GetTos(void) const194 Ipv4Header::GetTos (void) const
195 {
196   NS_LOG_FUNCTION (this);
197   return m_tos;
198 }
199 void
SetMoreFragments(void)200 Ipv4Header::SetMoreFragments (void)
201 {
202   NS_LOG_FUNCTION (this);
203   m_flags |= MORE_FRAGMENTS;
204 }
205 void
SetLastFragment(void)206 Ipv4Header::SetLastFragment (void)
207 {
208   NS_LOG_FUNCTION (this);
209   m_flags &= ~MORE_FRAGMENTS;
210 }
211 bool
IsLastFragment(void) const212 Ipv4Header::IsLastFragment (void) const
213 {
214   NS_LOG_FUNCTION (this);
215   return !(m_flags & MORE_FRAGMENTS);
216 }
217 
218 void
SetDontFragment(void)219 Ipv4Header::SetDontFragment (void)
220 {
221   NS_LOG_FUNCTION (this);
222   m_flags |= DONT_FRAGMENT;
223 }
224 void
SetMayFragment(void)225 Ipv4Header::SetMayFragment (void)
226 {
227   NS_LOG_FUNCTION (this);
228   m_flags &= ~DONT_FRAGMENT;
229 }
230 bool
IsDontFragment(void) const231 Ipv4Header::IsDontFragment (void) const
232 {
233   NS_LOG_FUNCTION (this);
234   return (m_flags & DONT_FRAGMENT);
235 }
236 
237 void
SetFragmentOffset(uint16_t offsetBytes)238 Ipv4Header::SetFragmentOffset (uint16_t offsetBytes)
239 {
240   NS_LOG_FUNCTION (this << offsetBytes);
241   // check if the user is trying to set an invalid offset
242   NS_ABORT_MSG_IF ((offsetBytes & 0x7), "offsetBytes must be multiple of 8 bytes");
243   m_fragmentOffset = offsetBytes;
244 }
245 uint16_t
GetFragmentOffset(void) const246 Ipv4Header::GetFragmentOffset (void) const
247 {
248   NS_LOG_FUNCTION (this);
249   // -fstrict-overflow sensitive, see bug 1868
250   if ( m_fragmentOffset + m_payloadSize > 65535 - 5*4 )
251     {
252       NS_LOG_WARN("Fragment will exceed the maximum packet size once reassembled");
253     }
254 
255   return m_fragmentOffset;
256 }
257 
258 void
SetTtl(uint8_t ttl)259 Ipv4Header::SetTtl (uint8_t ttl)
260 {
261   NS_LOG_FUNCTION (this << static_cast<uint32_t> (ttl));
262   m_ttl = ttl;
263 }
264 uint8_t
GetTtl(void) const265 Ipv4Header::GetTtl (void) const
266 {
267   NS_LOG_FUNCTION (this);
268   return m_ttl;
269 }
270 
271 uint8_t
GetProtocol(void) const272 Ipv4Header::GetProtocol (void) const
273 {
274   NS_LOG_FUNCTION (this);
275   return m_protocol;
276 }
277 void
SetProtocol(uint8_t protocol)278 Ipv4Header::SetProtocol (uint8_t protocol)
279 {
280   NS_LOG_FUNCTION (this << static_cast<uint32_t> (protocol));
281   m_protocol = protocol;
282 }
283 
284 void
SetSource(Ipv4Address source)285 Ipv4Header::SetSource (Ipv4Address source)
286 {
287   NS_LOG_FUNCTION (this << source);
288   m_source = source;
289 }
290 Ipv4Address
GetSource(void) const291 Ipv4Header::GetSource (void) const
292 {
293   NS_LOG_FUNCTION (this);
294   return m_source;
295 }
296 
297 void
SetDestination(Ipv4Address dst)298 Ipv4Header::SetDestination (Ipv4Address dst)
299 {
300   NS_LOG_FUNCTION (this << dst);
301   m_destination = dst;
302 }
303 Ipv4Address
GetDestination(void) const304 Ipv4Header::GetDestination (void) const
305 {
306   NS_LOG_FUNCTION (this);
307   return m_destination;
308 }
309 
310 
311 bool
IsChecksumOk(void) const312 Ipv4Header::IsChecksumOk (void) const
313 {
314   NS_LOG_FUNCTION (this);
315   return m_goodChecksum;
316 }
317 
318 TypeId
GetTypeId(void)319 Ipv4Header::GetTypeId (void)
320 {
321   static TypeId tid = TypeId ("ns3::Ipv4Header")
322     .SetParent<Header> ()
323     .SetGroupName ("Internet")
324     .AddConstructor<Ipv4Header> ()
325   ;
326   return tid;
327 }
328 TypeId
GetInstanceTypeId(void) const329 Ipv4Header::GetInstanceTypeId (void) const
330 {
331   NS_LOG_FUNCTION (this);
332   return GetTypeId ();
333 }
334 void
Print(std::ostream & os) const335 Ipv4Header::Print (std::ostream &os) const
336 {
337   NS_LOG_FUNCTION (this << &os);
338   // ipv4, right ?
339   std::string flags;
340   if (m_flags == 0)
341     {
342       flags = "none";
343     }
344   else if ((m_flags & MORE_FRAGMENTS) &&
345            (m_flags & DONT_FRAGMENT))
346     {
347       flags = "MF|DF";
348     }
349   else if (m_flags & DONT_FRAGMENT)
350     {
351       flags = "DF";
352     }
353   else if (m_flags & MORE_FRAGMENTS)
354     {
355       flags = "MF";
356     }
357   else
358     {
359       flags = "XX";
360     }
361   os << "tos 0x" << std::hex << m_tos << std::dec << " "
362      << "DSCP " << DscpTypeToString (GetDscp ()) << " "
363      << "ECN " << EcnTypeToString (GetEcn ()) << " "
364      << "ttl " << m_ttl << " "
365      << "id " << m_identification << " "
366      << "protocol " << m_protocol << " "
367      << "offset (bytes) " << m_fragmentOffset << " "
368      << "flags [" << flags << "] "
369      << "length: " << (m_payloadSize + 5 * 4)
370      << " "
371      << m_source << " > " << m_destination
372   ;
373 }
374 uint32_t
GetSerializedSize(void) const375 Ipv4Header::GetSerializedSize (void) const
376 {
377   NS_LOG_FUNCTION (this);
378   //return 5 * 4;
379 	return m_headerSize;
380 }
381 
382 void
Serialize(Buffer::Iterator start) const383 Ipv4Header::Serialize (Buffer::Iterator start) const
384 {
385   NS_LOG_FUNCTION (this << &start);
386   Buffer::Iterator i = start;
387 
388   uint8_t verIhl = (4 << 4) | (5);
389   i.WriteU8 (verIhl);
390   i.WriteU8 (m_tos);
391   i.WriteHtonU16 (m_payloadSize + 5*4);
392   i.WriteHtonU16 (m_identification);
393   uint32_t fragmentOffset = m_fragmentOffset / 8;
394   uint8_t flagsFrag = (fragmentOffset >> 8) & 0x1f;
395   if (m_flags & DONT_FRAGMENT)
396     {
397       flagsFrag |= (1<<6);
398     }
399   if (m_flags & MORE_FRAGMENTS)
400     {
401       flagsFrag |= (1<<5);
402     }
403   i.WriteU8 (flagsFrag);
404   uint8_t frag = fragmentOffset & 0xff;
405   i.WriteU8 (frag);
406   i.WriteU8 (m_ttl);
407   i.WriteU8 (m_protocol);
408   i.WriteHtonU16 (0);
409   i.WriteHtonU32 (m_source.Get ());
410   i.WriteHtonU32 (m_destination.Get ());
411 
412   if (m_calcChecksum)
413     {
414       i = start;
415       uint16_t checksum = i.CalculateIpChecksum (20);
416       NS_LOG_LOGIC ("checksum=" <<checksum);
417       i = start;
418       i.Next (10);
419       i.WriteU16 (checksum);
420     }
421 }
422 uint32_t
Deserialize(Buffer::Iterator start)423 Ipv4Header::Deserialize (Buffer::Iterator start)
424 {
425   NS_LOG_FUNCTION (this << &start);
426   Buffer::Iterator i = start;
427 
428   uint8_t verIhl = i.ReadU8 ();
429   uint8_t ihl = verIhl & 0x0f;
430   uint16_t headerSize = ihl * 4;
431 
432   if ((verIhl >> 4) != 4)
433     {
434       NS_LOG_WARN ("Trying to decode a non-IPv4 header, refusing to do it.");
435       return 0;
436     }
437 
438   m_tos = i.ReadU8 ();
439   uint16_t size = i.ReadNtohU16 ();
440   m_payloadSize = size - headerSize;
441   m_identification = i.ReadNtohU16 ();
442   uint8_t flags = i.ReadU8 ();
443   m_flags = 0;
444   if (flags & (1<<6))
445     {
446       m_flags |= DONT_FRAGMENT;
447     }
448   if (flags & (1<<5))
449     {
450       m_flags |= MORE_FRAGMENTS;
451     }
452   i.Prev ();
453   m_fragmentOffset = i.ReadU8 () & 0x1f;
454   m_fragmentOffset <<= 8;
455   m_fragmentOffset |= i.ReadU8 ();
456   m_fragmentOffset <<= 3;
457   m_ttl = i.ReadU8 ();
458   m_protocol = i.ReadU8 ();
459   m_checksum = i.ReadU16 ();
460   /* i.Next (2); // checksum */
461   m_source.Set (i.ReadNtohU32 ());
462   m_destination.Set (i.ReadNtohU32 ());
463   m_headerSize = headerSize;
464 
465   if (m_calcChecksum)
466     {
467       i = start;
468       uint16_t checksum = i.CalculateIpChecksum (headerSize);
469       NS_LOG_LOGIC ("checksum=" <<checksum);
470 
471       m_goodChecksum = (checksum == 0);
472     }
473   return GetSerializedSize ();
474 }
475 
476 } // namespace ns3
477