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