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/log.h" |
|
23 #include "ns3/header.h" |
|
24 #include "ipv4-header.h" |
|
25 |
|
26 NS_LOG_COMPONENT_DEFINE ("Ipv4Header"); |
|
27 |
|
28 namespace ns3 { |
|
29 |
|
30 NS_OBJECT_ENSURE_REGISTERED (Ipv4Header); |
|
31 |
|
32 bool Ipv4Header::m_calcChecksum = false; |
|
33 |
|
34 Ipv4Header::Ipv4Header () |
|
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_goodChecksum (true) |
|
43 {} |
|
44 |
|
45 void |
|
46 Ipv4Header::EnableChecksums (void) |
|
47 { |
|
48 m_calcChecksum = true; |
|
49 } |
|
50 |
|
51 void |
|
52 Ipv4Header::SetPayloadSize (uint16_t size) |
|
53 { |
|
54 m_payloadSize = size; |
|
55 } |
|
56 uint16_t |
|
57 Ipv4Header::GetPayloadSize (void) const |
|
58 { |
|
59 return m_payloadSize; |
|
60 } |
|
61 |
|
62 uint16_t |
|
63 Ipv4Header::GetIdentification (void) const |
|
64 { |
|
65 return m_identification; |
|
66 } |
|
67 void |
|
68 Ipv4Header::SetIdentification (uint16_t identification) |
|
69 { |
|
70 m_identification = identification; |
|
71 } |
|
72 |
|
73 |
|
74 |
|
75 void |
|
76 Ipv4Header::SetTos (uint8_t tos) |
|
77 { |
|
78 m_tos = tos; |
|
79 } |
|
80 uint8_t |
|
81 Ipv4Header::GetTos (void) const |
|
82 { |
|
83 return m_tos; |
|
84 } |
|
85 void |
|
86 Ipv4Header::SetMoreFragments (void) |
|
87 { |
|
88 m_flags |= MORE_FRAGMENTS; |
|
89 } |
|
90 void |
|
91 Ipv4Header::SetLastFragment (void) |
|
92 { |
|
93 m_flags &= ~MORE_FRAGMENTS; |
|
94 } |
|
95 bool |
|
96 Ipv4Header::IsLastFragment (void) const |
|
97 { |
|
98 return !(m_flags & MORE_FRAGMENTS); |
|
99 } |
|
100 |
|
101 void |
|
102 Ipv4Header::SetDontFragment (void) |
|
103 { |
|
104 m_flags |= DONT_FRAGMENT; |
|
105 } |
|
106 void |
|
107 Ipv4Header::SetMayFragment (void) |
|
108 { |
|
109 m_flags &= ~DONT_FRAGMENT; |
|
110 } |
|
111 bool |
|
112 Ipv4Header::IsDontFragment (void) const |
|
113 { |
|
114 return (m_flags & DONT_FRAGMENT); |
|
115 } |
|
116 |
|
117 void |
|
118 Ipv4Header::SetFragmentOffset (uint16_t offset) |
|
119 { |
|
120 NS_ASSERT (!(offset & (~0x3fff))); |
|
121 m_fragmentOffset = offset; |
|
122 } |
|
123 uint16_t |
|
124 Ipv4Header::GetFragmentOffset (void) const |
|
125 { |
|
126 NS_ASSERT (!(m_fragmentOffset & (~0x3fff))); |
|
127 return m_fragmentOffset; |
|
128 } |
|
129 |
|
130 void |
|
131 Ipv4Header::SetTtl (uint8_t ttl) |
|
132 { |
|
133 m_ttl = ttl; |
|
134 } |
|
135 uint8_t |
|
136 Ipv4Header::GetTtl (void) const |
|
137 { |
|
138 return m_ttl; |
|
139 } |
|
140 |
|
141 uint8_t |
|
142 Ipv4Header::GetProtocol (void) const |
|
143 { |
|
144 return m_protocol; |
|
145 } |
|
146 void |
|
147 Ipv4Header::SetProtocol (uint8_t protocol) |
|
148 { |
|
149 m_protocol = protocol; |
|
150 } |
|
151 |
|
152 void |
|
153 Ipv4Header::SetSource (Ipv4Address source) |
|
154 { |
|
155 m_source = source; |
|
156 } |
|
157 Ipv4Address |
|
158 Ipv4Header::GetSource (void) const |
|
159 { |
|
160 return m_source; |
|
161 } |
|
162 |
|
163 void |
|
164 Ipv4Header::SetDestination (Ipv4Address dst) |
|
165 { |
|
166 m_destination = dst; |
|
167 } |
|
168 Ipv4Address |
|
169 Ipv4Header::GetDestination (void) const |
|
170 { |
|
171 return m_destination; |
|
172 } |
|
173 |
|
174 |
|
175 bool |
|
176 Ipv4Header::IsChecksumOk (void) const |
|
177 { |
|
178 return m_goodChecksum; |
|
179 } |
|
180 |
|
181 |
|
182 TypeId |
|
183 Ipv4Header::GetTypeId (void) |
|
184 { |
|
185 static TypeId tid = TypeId ("ns3::Ipv4Header") |
|
186 .SetParent<Header> () |
|
187 .AddConstructor<Ipv4Header> () |
|
188 ; |
|
189 return tid; |
|
190 } |
|
191 TypeId |
|
192 Ipv4Header::GetInstanceTypeId (void) const |
|
193 { |
|
194 return GetTypeId (); |
|
195 } |
|
196 void |
|
197 Ipv4Header::Print (std::ostream &os) const |
|
198 { |
|
199 // ipv4, right ? |
|
200 std::string flags; |
|
201 if (m_flags == 0) |
|
202 { |
|
203 flags = "none"; |
|
204 } |
|
205 else if (m_flags & MORE_FRAGMENTS && |
|
206 m_flags & DONT_FRAGMENT) |
|
207 { |
|
208 flags = "MF|DF"; |
|
209 } |
|
210 else if (m_flags & DONT_FRAGMENT) |
|
211 { |
|
212 flags = "DF"; |
|
213 } |
|
214 else if (m_flags & MORE_FRAGMENTS) |
|
215 { |
|
216 flags = "MF"; |
|
217 } |
|
218 else |
|
219 { |
|
220 flags = "XX"; |
|
221 } |
|
222 os << "tos 0x" << std::hex << m_tos << std::dec << " " |
|
223 << "ttl " << m_ttl << " " |
|
224 << "id " << m_identification << " " |
|
225 << "offset " << m_fragmentOffset << " " |
|
226 << "flags [" << flags << "] " |
|
227 << "length: " << (m_payloadSize + 5 * 4) |
|
228 << " " |
|
229 << m_source << " > " << m_destination |
|
230 ; |
|
231 } |
|
232 uint32_t |
|
233 Ipv4Header::GetSerializedSize (void) const |
|
234 { |
|
235 return 5 * 4; |
|
236 } |
|
237 |
|
238 void |
|
239 Ipv4Header::Serialize (Buffer::Iterator start) const |
|
240 { |
|
241 Buffer::Iterator i = start; |
|
242 |
|
243 uint8_t verIhl = (4 << 4) | (5); |
|
244 i.WriteU8 (verIhl); |
|
245 i.WriteU8 (m_tos); |
|
246 i.WriteHtonU16 (m_payloadSize + 5*4); |
|
247 i.WriteHtonU16 (m_identification); |
|
248 uint32_t fragmentOffset = m_fragmentOffset / 8; |
|
249 uint8_t flagsFrag = (fragmentOffset >> 8) & 0x1f; |
|
250 if (m_flags & DONT_FRAGMENT) |
|
251 { |
|
252 flagsFrag |= (1<<6); |
|
253 } |
|
254 if (m_flags & MORE_FRAGMENTS) |
|
255 { |
|
256 flagsFrag |= (1<<5); |
|
257 } |
|
258 i.WriteU8 (flagsFrag); |
|
259 uint8_t frag = fragmentOffset & 0xff; |
|
260 i.WriteU8 (frag); |
|
261 i.WriteU8 (m_ttl); |
|
262 i.WriteU8 (m_protocol); |
|
263 i.WriteHtonU16 (0); |
|
264 i.WriteHtonU32 (m_source.GetHostOrder ()); |
|
265 i.WriteHtonU32 (m_destination.GetHostOrder ()); |
|
266 |
|
267 if (m_calcChecksum) |
|
268 { |
|
269 #if 0 |
|
270 // XXX we need to add Buffer::Iterator::PeekData method |
|
271 uint8_t *data = start.PeekData (); |
|
272 uint16_t checksum = UtilsChecksumCalculate (0, data, GetSize ()); |
|
273 checksum = UtilsChecksumComplete (checksum); |
|
274 NS_LOG_LOGIC ("checksum=" <<checksum); |
|
275 i = start; |
|
276 i.Next (10); |
|
277 i.WriteU16 (checksum); |
|
278 #endif |
|
279 } |
|
280 } |
|
281 uint32_t |
|
282 Ipv4Header::Deserialize (Buffer::Iterator start) |
|
283 { |
|
284 Buffer::Iterator i = start; |
|
285 uint8_t verIhl = i.ReadU8 (); |
|
286 uint8_t ihl = verIhl & 0x0f; |
|
287 uint16_t headerSize = ihl * 4; |
|
288 NS_ASSERT ((verIhl >> 4) == 4); |
|
289 m_tos = i.ReadU8 (); |
|
290 uint16_t size = i.ReadNtohU16 (); |
|
291 m_payloadSize = size - headerSize; |
|
292 m_identification = i.ReadNtohU16 (); |
|
293 uint8_t flags = i.ReadU8 (); |
|
294 m_flags = 0; |
|
295 if (flags & (1<<6)) |
|
296 { |
|
297 m_flags |= DONT_FRAGMENT; |
|
298 } |
|
299 if (flags & (1<<5)) |
|
300 { |
|
301 m_flags |= MORE_FRAGMENTS; |
|
302 } |
|
303 //XXXX I think we should clear some bits in fragmentOffset ! |
|
304 i.Prev (); |
|
305 m_fragmentOffset = i.ReadNtohU16 (); |
|
306 m_fragmentOffset *= 8; |
|
307 m_ttl = i.ReadU8 (); |
|
308 m_protocol = i.ReadU8 (); |
|
309 i.Next (2); // checksum |
|
310 m_source.SetHostOrder (i.ReadNtohU32 ()); |
|
311 m_destination.SetHostOrder (i.ReadNtohU32 ()); |
|
312 |
|
313 if (m_calcChecksum) |
|
314 { |
|
315 #if 0 |
|
316 uint8_t *data = start.PeekData (); |
|
317 uint16_t localChecksum = UtilsChecksumCalculate (0, data, headerSize); |
|
318 if (localChecksum == 0xffff) |
|
319 { |
|
320 m_goodChecksum = true; |
|
321 } |
|
322 else |
|
323 { |
|
324 m_goodChecksum = false; |
|
325 } |
|
326 #endif |
|
327 } |
|
328 return GetSerializedSize (); |
|
329 } |
|
330 |
|
331 }; // namespace ns3 |
|