1 /*
2 * Copyright (c) 2016, The OpenThread Authors.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. Neither the name of the copyright holder nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 /**
30 * @file
31 * This file implements 6LoWPAN header compression.
32 */
33
34 #include "lowpan.hpp"
35
36 #include "common/code_utils.hpp"
37 #include "common/debug.hpp"
38 #include "common/encoding.hpp"
39 #include "common/locator_getters.hpp"
40 #include "common/numeric_limits.hpp"
41 #include "instance/instance.hpp"
42 #include "net/ip6.hpp"
43 #include "net/udp6.hpp"
44 #include "thread/network_data_leader.hpp"
45 #include "thread/thread_netif.hpp"
46
47 namespace ot {
48 namespace Lowpan {
49
Lowpan(Instance & aInstance)50 Lowpan::Lowpan(Instance &aInstance)
51 : InstanceLocator(aInstance)
52 {
53 }
54
FindContextForId(uint8_t aContextId,Context & aContext) const55 void Lowpan::FindContextForId(uint8_t aContextId, Context &aContext) const
56 {
57 if (Get<NetworkData::Leader>().GetContext(aContextId, aContext) != kErrorNone)
58 {
59 aContext.Clear();
60 }
61 }
62
FindContextToCompressAddress(const Ip6::Address & aIp6Address,Context & aContext) const63 void Lowpan::FindContextToCompressAddress(const Ip6::Address &aIp6Address, Context &aContext) const
64 {
65 Error error = Get<NetworkData::Leader>().GetContext(aIp6Address, aContext);
66
67 if ((error != kErrorNone) || !aContext.mCompressFlag)
68 {
69 aContext.Clear();
70 }
71 }
72
ComputeIid(const Mac::Address & aMacAddr,const Context & aContext,Ip6::InterfaceIdentifier & aIid)73 Error Lowpan::ComputeIid(const Mac::Address &aMacAddr, const Context &aContext, Ip6::InterfaceIdentifier &aIid)
74 {
75 Error error = kErrorNone;
76
77 switch (aMacAddr.GetType())
78 {
79 case Mac::Address::kTypeShort:
80 aIid.SetToLocator(aMacAddr.GetShort());
81 break;
82
83 case Mac::Address::kTypeExtended:
84 aIid.SetFromExtAddress(aMacAddr.GetExtended());
85 break;
86
87 default:
88 ExitNow(error = kErrorParse);
89 }
90
91 aIid.ApplyPrefix(aContext.mPrefix);
92
93 exit:
94 return error;
95 }
96
CompressSourceIid(const Mac::Address & aMacAddr,const Ip6::Address & aIpAddr,const Context & aContext,uint16_t & aHcCtl,FrameBuilder & aFrameBuilder)97 Error Lowpan::CompressSourceIid(const Mac::Address &aMacAddr,
98 const Ip6::Address &aIpAddr,
99 const Context &aContext,
100 uint16_t &aHcCtl,
101 FrameBuilder &aFrameBuilder)
102 {
103 Error error = kErrorNone;
104 Ip6::InterfaceIdentifier iid;
105
106 IgnoreError(ComputeIid(aMacAddr, aContext, iid));
107
108 if (iid == aIpAddr.GetIid())
109 {
110 aHcCtl |= kHcSrcAddrMode3;
111 }
112 else if (aIpAddr.GetIid().IsLocator())
113 {
114 aHcCtl |= kHcSrcAddrMode2;
115 error = aFrameBuilder.AppendBigEndianUint16(aIpAddr.GetIid().GetLocator());
116 }
117 else
118 {
119 aHcCtl |= kHcSrcAddrMode1;
120 error = aFrameBuilder.Append(aIpAddr.GetIid());
121 }
122
123 return error;
124 }
125
CompressDestinationIid(const Mac::Address & aMacAddr,const Ip6::Address & aIpAddr,const Context & aContext,uint16_t & aHcCtl,FrameBuilder & aFrameBuilder)126 Error Lowpan::CompressDestinationIid(const Mac::Address &aMacAddr,
127 const Ip6::Address &aIpAddr,
128 const Context &aContext,
129 uint16_t &aHcCtl,
130 FrameBuilder &aFrameBuilder)
131 {
132 Error error = kErrorNone;
133 Ip6::InterfaceIdentifier iid;
134
135 IgnoreError(ComputeIid(aMacAddr, aContext, iid));
136
137 if (iid == aIpAddr.GetIid())
138 {
139 aHcCtl |= kHcDstAddrMode3;
140 }
141 else if (aIpAddr.GetIid().IsLocator())
142 {
143 aHcCtl |= kHcDstAddrMode2;
144 error = aFrameBuilder.AppendBigEndianUint16(aIpAddr.GetIid().GetLocator());
145 }
146 else
147 {
148 aHcCtl |= kHcDstAddrMode1;
149 error = aFrameBuilder.Append(aIpAddr.GetIid());
150 }
151
152 return error;
153 }
154
CompressMulticast(const Ip6::Address & aIpAddr,uint16_t & aHcCtl,FrameBuilder & aFrameBuilder)155 Error Lowpan::CompressMulticast(const Ip6::Address &aIpAddr, uint16_t &aHcCtl, FrameBuilder &aFrameBuilder)
156 {
157 Error error = kErrorNone;
158 Context multicastContext;
159
160 aHcCtl |= kHcMulticast;
161
162 for (unsigned int i = 2; i < sizeof(Ip6::Address); i++)
163 {
164 if (aIpAddr.mFields.m8[i])
165 {
166 // Check if multicast address can be compressed to 8-bits (ff02::00xx)
167 if (aIpAddr.mFields.m8[1] == 0x02 && i >= 15)
168 {
169 aHcCtl |= kHcDstAddrMode3;
170 SuccessOrExit(error = aFrameBuilder.AppendUint8(aIpAddr.mFields.m8[15]));
171 }
172 // Check if multicast address can be compressed to 32-bits (ffxx::00xx:xxxx)
173 else if (i >= 13)
174 {
175 aHcCtl |= kHcDstAddrMode2;
176 SuccessOrExit(error = aFrameBuilder.AppendUint8(aIpAddr.mFields.m8[1]));
177 SuccessOrExit(error = aFrameBuilder.AppendBytes(aIpAddr.mFields.m8 + 13, 3));
178 }
179 // Check if multicast address can be compressed to 48-bits (ffxx::00xx:xxxx:xxxx)
180 else if (i >= 11)
181 {
182 aHcCtl |= kHcDstAddrMode1;
183 SuccessOrExit(error = aFrameBuilder.AppendUint8(aIpAddr.mFields.m8[1]));
184 SuccessOrExit(error = aFrameBuilder.AppendBytes(aIpAddr.mFields.m8 + 11, 5));
185 }
186 else
187 {
188 // Check if multicast address can be compressed using Context ID 0 (mesh local prefix)
189 FindContextForId(0, multicastContext);
190
191 if (multicastContext.mPrefix.GetLength() == aIpAddr.mFields.m8[3] &&
192 memcmp(multicastContext.mPrefix.GetBytes(), aIpAddr.mFields.m8 + 4, 8) == 0)
193 {
194 aHcCtl |= kHcDstAddrContext | kHcDstAddrMode0;
195 SuccessOrExit(error = aFrameBuilder.AppendBytes(aIpAddr.mFields.m8 + 1, 2));
196 SuccessOrExit(error = aFrameBuilder.AppendBytes(aIpAddr.mFields.m8 + 12, 4));
197 }
198 else
199 {
200 SuccessOrExit(error = aFrameBuilder.Append(aIpAddr));
201 }
202 }
203
204 break;
205 }
206 }
207
208 exit:
209 return error;
210 }
211
Compress(Message & aMessage,const Mac::Addresses & aMacAddrs,FrameBuilder & aFrameBuilder)212 Error Lowpan::Compress(Message &aMessage, const Mac::Addresses &aMacAddrs, FrameBuilder &aFrameBuilder)
213 {
214 Error error = kErrorNone;
215 uint8_t headerDepth = 0xff;
216
217 while (headerDepth > 0)
218 {
219 FrameBuilder frameBuilder = aFrameBuilder;
220
221 error = Compress(aMessage, aMacAddrs, aFrameBuilder, headerDepth);
222
223 // We exit if `Compress()` is successful. Otherwise we reset
224 // the `aFrameBuidler` to its earlier state (remove all
225 // appended content from the failed `Compress()` call) and
226 // try again with a different `headerDepth`.
227
228 VerifyOrExit(error != kErrorNone);
229 aFrameBuilder = frameBuilder;
230 }
231
232 exit:
233 return error;
234 }
235
Compress(Message & aMessage,const Mac::Addresses & aMacAddrs,FrameBuilder & aFrameBuilder,uint8_t & aHeaderDepth)236 Error Lowpan::Compress(Message &aMessage,
237 const Mac::Addresses &aMacAddrs,
238 FrameBuilder &aFrameBuilder,
239 uint8_t &aHeaderDepth)
240 {
241 Error error = kErrorNone;
242 uint16_t startOffset = aMessage.GetOffset();
243 uint16_t hcCtl = kHcDispatch;
244 uint16_t hcCtlOffset = 0;
245 Ip6::Header ip6Header;
246 uint8_t *ip6HeaderBytes = reinterpret_cast<uint8_t *>(&ip6Header);
247 Context srcContext, dstContext;
248 uint8_t nextHeader;
249 uint8_t ecn;
250 uint8_t dscp;
251 uint8_t headerDepth = 0;
252 uint8_t headerMaxDepth = aHeaderDepth;
253
254 SuccessOrExit(error = aMessage.Read(aMessage.GetOffset(), ip6Header));
255
256 FindContextToCompressAddress(ip6Header.GetSource(), srcContext);
257 FindContextToCompressAddress(ip6Header.GetDestination(), dstContext);
258
259 // Lowpan HC Control Bits
260 hcCtlOffset = aFrameBuilder.GetLength();
261 SuccessOrExit(error = aFrameBuilder.AppendBigEndianUint16(hcCtl));
262
263 // Context Identifier
264 if (srcContext.mContextId != 0 || dstContext.mContextId != 0)
265 {
266 hcCtl |= kHcContextId;
267 SuccessOrExit(error = aFrameBuilder.AppendUint8(((srcContext.mContextId << 4) | dstContext.mContextId) & 0xff));
268 }
269
270 dscp = ((ip6HeaderBytes[0] << 2) & 0x3c) | (ip6HeaderBytes[1] >> 6);
271 ecn = (ip6HeaderBytes[1] << 2) & 0xc0;
272
273 // Flow Label
274 if (((ip6HeaderBytes[1] & 0x0f) == 0) && ((ip6HeaderBytes[2]) == 0) && ((ip6HeaderBytes[3]) == 0))
275 {
276 if (dscp == 0 && ecn == 0)
277 {
278 // Elide Flow Label and Traffic Class.
279 hcCtl |= kHcTrafficClass | kHcFlowLabel;
280 }
281 else
282 {
283 // Elide Flow Label and carry Traffic Class in-line.
284 hcCtl |= kHcFlowLabel;
285
286 SuccessOrExit(error = aFrameBuilder.AppendUint8(ecn | dscp));
287 }
288 }
289 else if (dscp == 0)
290 {
291 // Carry Flow Label and ECN only with 2-bit padding.
292 hcCtl |= kHcTrafficClass;
293
294 SuccessOrExit(error = aFrameBuilder.AppendUint8(ecn | (ip6HeaderBytes[1] & 0x0f)));
295 SuccessOrExit(error = aFrameBuilder.AppendBytes(ip6HeaderBytes + 2, 2));
296 }
297 else
298 {
299 // Carry Flow Label and Traffic Class in-line.
300 SuccessOrExit(error = aFrameBuilder.AppendUint8(ecn | dscp));
301 SuccessOrExit(error = aFrameBuilder.AppendUint8(ip6HeaderBytes[1] & 0x0f));
302 SuccessOrExit(error = aFrameBuilder.AppendBytes(ip6HeaderBytes + 2, 2));
303 }
304
305 // Next Header
306 switch (ip6Header.GetNextHeader())
307 {
308 case Ip6::kProtoHopOpts:
309 case Ip6::kProtoUdp:
310 case Ip6::kProtoIp6:
311 if (headerDepth + 1 < headerMaxDepth)
312 {
313 hcCtl |= kHcNextHeader;
314 break;
315 }
316 OT_FALL_THROUGH;
317
318 default:
319 SuccessOrExit(error = aFrameBuilder.AppendUint8(static_cast<uint8_t>(ip6Header.GetNextHeader())));
320 break;
321 }
322
323 // Hop Limit
324 switch (ip6Header.GetHopLimit())
325 {
326 case 1:
327 hcCtl |= kHcHopLimit1;
328 break;
329
330 case 64:
331 hcCtl |= kHcHopLimit64;
332 break;
333
334 case 255:
335 hcCtl |= kHcHopLimit255;
336 break;
337
338 default:
339 SuccessOrExit(error = aFrameBuilder.AppendUint8(ip6Header.GetHopLimit()));
340 break;
341 }
342
343 // Source Address
344 if (ip6Header.GetSource().IsUnspecified())
345 {
346 hcCtl |= kHcSrcAddrContext;
347 }
348 else if (ip6Header.GetSource().IsLinkLocal())
349 {
350 SuccessOrExit(
351 error = CompressSourceIid(aMacAddrs.mSource, ip6Header.GetSource(), srcContext, hcCtl, aFrameBuilder));
352 }
353 else if (srcContext.mIsValid)
354 {
355 hcCtl |= kHcSrcAddrContext;
356 SuccessOrExit(
357 error = CompressSourceIid(aMacAddrs.mSource, ip6Header.GetSource(), srcContext, hcCtl, aFrameBuilder));
358 }
359 else
360 {
361 SuccessOrExit(error = aFrameBuilder.Append(ip6Header.GetSource()));
362 }
363
364 // Destination Address
365 if (ip6Header.GetDestination().IsMulticast())
366 {
367 SuccessOrExit(error = CompressMulticast(ip6Header.GetDestination(), hcCtl, aFrameBuilder));
368 }
369 else if (ip6Header.GetDestination().IsLinkLocal())
370 {
371 SuccessOrExit(error = CompressDestinationIid(aMacAddrs.mDestination, ip6Header.GetDestination(), dstContext,
372 hcCtl, aFrameBuilder));
373 }
374 else if (dstContext.mIsValid)
375 {
376 hcCtl |= kHcDstAddrContext;
377 SuccessOrExit(error = CompressDestinationIid(aMacAddrs.mDestination, ip6Header.GetDestination(), dstContext,
378 hcCtl, aFrameBuilder));
379 }
380 else
381 {
382 SuccessOrExit(error = aFrameBuilder.Append(ip6Header.GetDestination()));
383 }
384
385 headerDepth++;
386
387 aMessage.MoveOffset(sizeof(ip6Header));
388
389 nextHeader = static_cast<uint8_t>(ip6Header.GetNextHeader());
390
391 while (headerDepth < headerMaxDepth)
392 {
393 switch (nextHeader)
394 {
395 case Ip6::kProtoHopOpts:
396 SuccessOrExit(error = CompressExtensionHeader(aMessage, aFrameBuilder, nextHeader));
397 break;
398
399 case Ip6::kProtoUdp:
400 error = CompressUdp(aMessage, aFrameBuilder);
401 ExitNow();
402
403 case Ip6::kProtoIp6:
404 // For IP-in-IP the NH bit of the LOWPAN_NHC encoding MUST be set to zero.
405 SuccessOrExit(error = aFrameBuilder.AppendUint8(kExtHdrDispatch | kExtHdrEidIp6));
406
407 error = Compress(aMessage, aMacAddrs, aFrameBuilder);
408
409 OT_FALL_THROUGH;
410
411 default:
412 ExitNow();
413 }
414
415 headerDepth++;
416 }
417
418 exit:
419 aHeaderDepth = headerDepth;
420
421 if (error == kErrorNone)
422 {
423 aFrameBuilder.Write<uint16_t>(hcCtlOffset, BigEndian::HostSwap16(hcCtl));
424 }
425 else
426 {
427 aMessage.SetOffset(startOffset);
428 }
429
430 return error;
431 }
432
CompressExtensionHeader(Message & aMessage,FrameBuilder & aFrameBuilder,uint8_t & aNextHeader)433 Error Lowpan::CompressExtensionHeader(Message &aMessage, FrameBuilder &aFrameBuilder, uint8_t &aNextHeader)
434 {
435 Error error = kErrorNone;
436 uint16_t startOffset = aMessage.GetOffset();
437 Ip6::ExtensionHeader extHeader;
438 uint16_t len;
439 uint16_t padLength = 0;
440 uint8_t tmpByte;
441
442 SuccessOrExit(error = aMessage.Read(aMessage.GetOffset(), extHeader));
443 aMessage.MoveOffset(sizeof(extHeader));
444
445 tmpByte = kExtHdrDispatch | kExtHdrEidHbh;
446
447 switch (extHeader.GetNextHeader())
448 {
449 case Ip6::kProtoUdp:
450 case Ip6::kProtoIp6:
451 tmpByte |= kExtHdrNextHeader;
452 break;
453
454 default:
455 SuccessOrExit(error = aFrameBuilder.AppendUint8(tmpByte));
456 tmpByte = static_cast<uint8_t>(extHeader.GetNextHeader());
457 break;
458 }
459
460 SuccessOrExit(error = aFrameBuilder.AppendUint8(tmpByte));
461
462 len = extHeader.GetSize() - sizeof(extHeader);
463
464 // RFC 6282 does not support compressing large extension headers
465 VerifyOrExit(len <= kExtHdrMaxLength, error = kErrorFailed);
466
467 // RFC 6282 says: "IPv6 Hop-by-Hop and Destination Options Headers may use a trailing
468 // Pad1 or PadN to achieve 8-octet alignment. When there is a single trailing Pad1 or PadN
469 // option of 7 octets or less and the containing header is a multiple of 8 octets, the trailing
470 // Pad1 or PadN option MAY be elided by the compressor."
471 if (aNextHeader == Ip6::kProtoHopOpts || aNextHeader == Ip6::kProtoDstOpts)
472 {
473 uint16_t offset = aMessage.GetOffset();
474 uint16_t endOffset = offset + len;
475 bool hasOption = false;
476 Ip6::Option option;
477
478 for (; offset < endOffset; offset += option.GetSize())
479 {
480 SuccessOrExit(error = option.ParseFrom(aMessage, offset, endOffset));
481 hasOption = true;
482 }
483
484 // Check if the last option can be compressed.
485 if (hasOption && option.IsPadding())
486 {
487 padLength = option.GetSize();
488 len -= padLength;
489 }
490 }
491
492 VerifyOrExit(aMessage.GetOffset() + len + padLength <= aMessage.GetLength(), error = kErrorParse);
493
494 aNextHeader = static_cast<uint8_t>(extHeader.GetNextHeader());
495
496 SuccessOrExit(error = aFrameBuilder.AppendUint8(static_cast<uint8_t>(len)));
497 SuccessOrExit(error = aFrameBuilder.AppendBytesFromMessage(aMessage, aMessage.GetOffset(), len));
498 aMessage.MoveOffset(len + padLength);
499
500 exit:
501 if (error != kErrorNone)
502 {
503 aMessage.SetOffset(startOffset);
504 }
505
506 return error;
507 }
508
CompressUdp(Message & aMessage,FrameBuilder & aFrameBuilder)509 Error Lowpan::CompressUdp(Message &aMessage, FrameBuilder &aFrameBuilder)
510 {
511 Error error = kErrorNone;
512 uint16_t startOffset = aMessage.GetOffset();
513 Ip6::Udp::Header udpHeader;
514 uint16_t source;
515 uint16_t destination;
516
517 SuccessOrExit(error = aMessage.Read(aMessage.GetOffset(), udpHeader));
518
519 source = udpHeader.GetSourcePort();
520 destination = udpHeader.GetDestinationPort();
521
522 if ((source & 0xfff0) == 0xf0b0 && (destination & 0xfff0) == 0xf0b0)
523 {
524 SuccessOrExit(error = aFrameBuilder.AppendUint8(kUdpDispatch | 3));
525 SuccessOrExit(error = aFrameBuilder.AppendUint8((((source & 0xf) << 4) | (destination & 0xf)) & 0xff));
526 }
527 else if ((source & 0xff00) == 0xf000)
528 {
529 SuccessOrExit(error = aFrameBuilder.AppendUint8(kUdpDispatch | 2));
530 SuccessOrExit(error = aFrameBuilder.AppendUint8(source & 0xff));
531 SuccessOrExit(error = aFrameBuilder.AppendBigEndianUint16(destination));
532 }
533 else if ((destination & 0xff00) == 0xf000)
534 {
535 SuccessOrExit(error = aFrameBuilder.AppendUint8(kUdpDispatch | 1));
536 SuccessOrExit(error = aFrameBuilder.AppendBigEndianUint16(source));
537 SuccessOrExit(error = aFrameBuilder.AppendUint8(destination & 0xff));
538 }
539 else
540 {
541 SuccessOrExit(error = aFrameBuilder.AppendUint8(kUdpDispatch));
542 SuccessOrExit(error = aFrameBuilder.AppendBytes(&udpHeader, Ip6::Udp::Header::kLengthFieldOffset));
543 }
544
545 SuccessOrExit(error = aFrameBuilder.AppendBigEndianUint16(udpHeader.GetChecksum()));
546
547 aMessage.MoveOffset(sizeof(udpHeader));
548
549 exit:
550 if (error != kErrorNone)
551 {
552 aMessage.SetOffset(startOffset);
553 }
554
555 return error;
556 }
557
DispatchToNextHeader(uint8_t aDispatch,uint8_t & aNextHeader)558 Error Lowpan::DispatchToNextHeader(uint8_t aDispatch, uint8_t &aNextHeader)
559 {
560 Error error = kErrorNone;
561
562 if ((aDispatch & kExtHdrDispatchMask) == kExtHdrDispatch)
563 {
564 switch (aDispatch & kExtHdrEidMask)
565 {
566 case kExtHdrEidHbh:
567 aNextHeader = Ip6::kProtoHopOpts;
568 ExitNow();
569
570 case kExtHdrEidRouting:
571 aNextHeader = Ip6::kProtoRouting;
572 ExitNow();
573
574 case kExtHdrEidFragment:
575 aNextHeader = Ip6::kProtoFragment;
576 ExitNow();
577
578 case kExtHdrEidDst:
579 aNextHeader = Ip6::kProtoDstOpts;
580 ExitNow();
581
582 case kExtHdrEidIp6:
583 aNextHeader = Ip6::kProtoIp6;
584 ExitNow();
585 }
586 }
587 else if ((aDispatch & kUdpDispatchMask) == kUdpDispatch)
588 {
589 aNextHeader = Ip6::kProtoUdp;
590 ExitNow();
591 }
592
593 error = kErrorParse;
594
595 exit:
596 return error;
597 }
598
DecompressBaseHeader(Ip6::Header & aIp6Header,bool & aCompressedNextHeader,const Mac::Addresses & aMacAddrs,FrameData & aFrameData)599 Error Lowpan::DecompressBaseHeader(Ip6::Header &aIp6Header,
600 bool &aCompressedNextHeader,
601 const Mac::Addresses &aMacAddrs,
602 FrameData &aFrameData)
603 {
604 Error error = kErrorParse;
605 uint16_t hcCtl;
606 uint8_t byte;
607 uint8_t srcContextId = 0;
608 uint8_t dstContextId = 0;
609 Context srcContext;
610 Context dstContext;
611 uint8_t nextHeader;
612
613 SuccessOrExit(aFrameData.ReadBigEndianUint16(hcCtl));
614
615 // check Dispatch bits
616 VerifyOrExit((hcCtl & kHcDispatchMask) == kHcDispatch);
617
618 // Context Identifier
619 if ((hcCtl & kHcContextId) != 0)
620 {
621 SuccessOrExit(aFrameData.ReadUint8(byte));
622
623 srcContextId = (byte >> 4);
624 dstContextId = (byte & 0xf);
625 }
626
627 FindContextForId(srcContextId, srcContext);
628 FindContextForId(dstContextId, dstContext);
629
630 aIp6Header.Clear();
631 aIp6Header.InitVersionTrafficClassFlow();
632
633 // Traffic Class and Flow Label
634 if ((hcCtl & kHcTrafficFlowMask) != kHcTrafficFlow)
635 {
636 uint8_t *ip6HeaderBytes = reinterpret_cast<uint8_t *>(&aIp6Header);
637
638 VerifyOrExit(aFrameData.GetLength() > 0);
639
640 ip6HeaderBytes[1] |= (aFrameData.GetBytes()[0] & 0xc0) >> 2;
641
642 if ((hcCtl & kHcTrafficClass) == 0)
643 {
644 IgnoreError(aFrameData.ReadUint8(byte));
645 ip6HeaderBytes[0] |= (byte >> 2) & 0x0f;
646 ip6HeaderBytes[1] |= (byte << 6) & 0xc0;
647 }
648
649 if ((hcCtl & kHcFlowLabel) == 0)
650 {
651 VerifyOrExit(aFrameData.GetLength() >= 3);
652 ip6HeaderBytes[1] |= aFrameData.GetBytes()[0] & 0x0f;
653 ip6HeaderBytes[2] |= aFrameData.GetBytes()[1];
654 ip6HeaderBytes[3] |= aFrameData.GetBytes()[2];
655 aFrameData.SkipOver(3);
656 }
657 }
658
659 // Next Header
660 if ((hcCtl & kHcNextHeader) == 0)
661 {
662 SuccessOrExit(aFrameData.ReadUint8(byte));
663
664 aIp6Header.SetNextHeader(byte);
665 aCompressedNextHeader = false;
666 }
667 else
668 {
669 aCompressedNextHeader = true;
670 }
671
672 // Hop Limit
673 switch (hcCtl & kHcHopLimitMask)
674 {
675 case kHcHopLimit1:
676 aIp6Header.SetHopLimit(1);
677 break;
678
679 case kHcHopLimit64:
680 aIp6Header.SetHopLimit(64);
681 break;
682
683 case kHcHopLimit255:
684 aIp6Header.SetHopLimit(255);
685 break;
686
687 default:
688 SuccessOrExit(aFrameData.ReadUint8(byte));
689 aIp6Header.SetHopLimit(byte);
690 break;
691 }
692
693 // Source Address
694 switch (hcCtl & kHcSrcAddrModeMask)
695 {
696 case kHcSrcAddrMode0:
697 if ((hcCtl & kHcSrcAddrContext) == 0)
698 {
699 SuccessOrExit(aFrameData.Read(aIp6Header.GetSource()));
700 }
701
702 break;
703
704 case kHcSrcAddrMode1:
705 SuccessOrExit(aFrameData.Read(aIp6Header.GetSource().GetIid()));
706 break;
707
708 case kHcSrcAddrMode2:
709 aIp6Header.GetSource().mFields.m8[11] = 0xff;
710 aIp6Header.GetSource().mFields.m8[12] = 0xfe;
711 SuccessOrExit(aFrameData.ReadBytes(aIp6Header.GetSource().mFields.m8 + 14, 2));
712 break;
713
714 case kHcSrcAddrMode3:
715 IgnoreError(ComputeIid(aMacAddrs.mSource, srcContext, aIp6Header.GetSource().GetIid()));
716 break;
717 }
718
719 if ((hcCtl & kHcSrcAddrModeMask) != kHcSrcAddrMode0)
720 {
721 if ((hcCtl & kHcSrcAddrContext) == 0)
722 {
723 aIp6Header.GetSource().mFields.m16[0] = BigEndian::HostSwap16(0xfe80);
724 }
725 else
726 {
727 VerifyOrExit(srcContext.mIsValid);
728 aIp6Header.GetSource().SetPrefix(srcContext.mPrefix);
729 }
730 }
731
732 if ((hcCtl & kHcMulticast) == 0)
733 {
734 // Unicast Destination Address
735
736 switch (hcCtl & kHcDstAddrModeMask)
737 {
738 case kHcDstAddrMode0:
739 VerifyOrExit((hcCtl & kHcDstAddrContext) == 0);
740 SuccessOrExit(aFrameData.Read(aIp6Header.GetDestination()));
741 break;
742
743 case kHcDstAddrMode1:
744 SuccessOrExit(aFrameData.Read(aIp6Header.GetDestination().GetIid()));
745 break;
746
747 case kHcDstAddrMode2:
748 aIp6Header.GetDestination().mFields.m8[11] = 0xff;
749 aIp6Header.GetDestination().mFields.m8[12] = 0xfe;
750 SuccessOrExit(aFrameData.ReadBytes(aIp6Header.GetDestination().mFields.m8 + 14, 2));
751 break;
752
753 case kHcDstAddrMode3:
754 SuccessOrExit(ComputeIid(aMacAddrs.mDestination, dstContext, aIp6Header.GetDestination().GetIid()));
755 break;
756 }
757
758 if ((hcCtl & kHcDstAddrContext) == 0)
759 {
760 if ((hcCtl & kHcDstAddrModeMask) != 0)
761 {
762 aIp6Header.GetDestination().mFields.m16[0] = BigEndian::HostSwap16(0xfe80);
763 }
764 }
765 else
766 {
767 VerifyOrExit(dstContext.mIsValid);
768 aIp6Header.GetDestination().SetPrefix(dstContext.mPrefix);
769 }
770 }
771 else
772 {
773 // Multicast Destination Address
774
775 aIp6Header.GetDestination().mFields.m8[0] = 0xff;
776
777 if ((hcCtl & kHcDstAddrContext) == 0)
778 {
779 switch (hcCtl & kHcDstAddrModeMask)
780 {
781 case kHcDstAddrMode0:
782 SuccessOrExit(aFrameData.Read(aIp6Header.GetDestination()));
783 break;
784
785 case kHcDstAddrMode1:
786 SuccessOrExit(aFrameData.ReadUint8(aIp6Header.GetDestination().mFields.m8[1]));
787 SuccessOrExit(aFrameData.ReadBytes(aIp6Header.GetDestination().mFields.m8 + 11, 5));
788 break;
789
790 case kHcDstAddrMode2:
791 SuccessOrExit(aFrameData.ReadUint8(aIp6Header.GetDestination().mFields.m8[1]));
792 SuccessOrExit(aFrameData.ReadBytes(aIp6Header.GetDestination().mFields.m8 + 13, 3));
793 break;
794
795 case kHcDstAddrMode3:
796 aIp6Header.GetDestination().mFields.m8[1] = 0x02;
797 SuccessOrExit(aFrameData.ReadUint8(aIp6Header.GetDestination().mFields.m8[15]));
798 break;
799 }
800 }
801 else
802 {
803 switch (hcCtl & kHcDstAddrModeMask)
804 {
805 case 0:
806 VerifyOrExit(dstContext.mIsValid);
807 SuccessOrExit(aFrameData.ReadBytes(aIp6Header.GetDestination().mFields.m8 + 1, 2));
808 aIp6Header.GetDestination().mFields.m8[3] = dstContext.mPrefix.GetLength();
809 memcpy(aIp6Header.GetDestination().mFields.m8 + 4, dstContext.mPrefix.GetBytes(), 8);
810 SuccessOrExit(aFrameData.ReadBytes(aIp6Header.GetDestination().mFields.m8 + 12, 4));
811 break;
812
813 default:
814 ExitNow();
815 }
816 }
817 }
818
819 if ((hcCtl & kHcNextHeader) != 0)
820 {
821 VerifyOrExit(aFrameData.GetLength() > 0);
822 SuccessOrExit(DispatchToNextHeader(*aFrameData.GetBytes(), nextHeader));
823 aIp6Header.SetNextHeader(nextHeader);
824 }
825
826 error = kErrorNone;
827
828 exit:
829 return error;
830 }
831
DecompressExtensionHeader(Message & aMessage,FrameData & aFrameData)832 Error Lowpan::DecompressExtensionHeader(Message &aMessage, FrameData &aFrameData)
833 {
834 Error error = kErrorParse;
835 uint8_t hdr[2];
836 uint8_t len;
837 uint8_t ctl;
838 Ip6::PadOption padOption;
839
840 SuccessOrExit(aFrameData.ReadUint8(ctl));
841
842 // next header
843 if (ctl & kExtHdrNextHeader)
844 {
845 SuccessOrExit(aFrameData.ReadUint8(len));
846
847 VerifyOrExit(aFrameData.CanRead(len + 1));
848 SuccessOrExit(DispatchToNextHeader(aFrameData.GetBytes()[len], hdr[0]));
849 }
850 else
851 {
852 SuccessOrExit(aFrameData.ReadUint8(hdr[0]));
853 SuccessOrExit(aFrameData.ReadUint8(len));
854
855 VerifyOrExit(aFrameData.CanRead(len));
856 }
857
858 // length
859 hdr[1] = BytesForBitSize(sizeof(hdr) + len) - 1;
860
861 SuccessOrExit(aMessage.AppendBytes(hdr, sizeof(hdr)));
862 aMessage.MoveOffset(sizeof(hdr));
863
864 // payload
865 SuccessOrExit(aMessage.AppendBytes(aFrameData.GetBytes(), len));
866 aMessage.MoveOffset(len);
867 aFrameData.SkipOver(len);
868
869 // The RFC6282 says: "The trailing Pad1 or PadN option MAY be elided by the compressor.
870 // A decompressor MUST ensure that the containing header is padded out to a multiple of 8 octets
871 // in length, using a Pad1 or PadN option if necessary."
872
873 if (padOption.InitToPadHeaderWithSize(len + sizeof(hdr)) == kErrorNone)
874 {
875 SuccessOrExit(aMessage.AppendBytes(&padOption, padOption.GetSize()));
876 aMessage.MoveOffset(padOption.GetSize());
877 }
878
879 error = kErrorNone;
880
881 exit:
882 return error;
883 }
884
DecompressUdpHeader(Ip6::Udp::Header & aUdpHeader,FrameData & aFrameData)885 Error Lowpan::DecompressUdpHeader(Ip6::Udp::Header &aUdpHeader, FrameData &aFrameData)
886 {
887 Error error = kErrorParse;
888 uint8_t udpCtl;
889 uint8_t byte;
890 uint16_t srcPort = 0;
891 uint16_t dstPort = 0;
892
893 SuccessOrExit(aFrameData.ReadUint8(udpCtl));
894
895 VerifyOrExit((udpCtl & kUdpDispatchMask) == kUdpDispatch);
896
897 aUdpHeader.Clear();
898
899 switch (udpCtl & kUdpPortMask)
900 {
901 case 0:
902 SuccessOrExit(aFrameData.ReadBigEndianUint16(srcPort));
903 SuccessOrExit(aFrameData.ReadBigEndianUint16(dstPort));
904 break;
905
906 case 1:
907 SuccessOrExit(aFrameData.ReadBigEndianUint16(srcPort));
908 SuccessOrExit(aFrameData.ReadUint8(byte));
909 dstPort = (0xf000 | byte);
910 break;
911
912 case 2:
913 SuccessOrExit(aFrameData.ReadUint8(byte));
914 srcPort = (0xf000 | byte);
915 SuccessOrExit(aFrameData.ReadBigEndianUint16(dstPort));
916 break;
917
918 case 3:
919 SuccessOrExit(aFrameData.ReadUint8(byte));
920 srcPort = (0xf0b0 | (byte >> 4));
921 dstPort = (0xf0b0 | (byte & 0xf));
922 break;
923 }
924
925 aUdpHeader.SetSourcePort(srcPort);
926 aUdpHeader.SetDestinationPort(dstPort);
927
928 if ((udpCtl & kUdpChecksum) != 0)
929 {
930 ExitNow();
931 }
932 else
933 {
934 uint16_t checksum;
935
936 SuccessOrExit(aFrameData.ReadBigEndianUint16(checksum));
937 aUdpHeader.SetChecksum(checksum);
938 }
939
940 error = kErrorNone;
941
942 exit:
943 return error;
944 }
945
DecompressUdpHeader(Message & aMessage,FrameData & aFrameData,uint16_t aDatagramLength)946 Error Lowpan::DecompressUdpHeader(Message &aMessage, FrameData &aFrameData, uint16_t aDatagramLength)
947 {
948 Error error;
949 Ip6::Udp::Header udpHeader;
950
951 SuccessOrExit(error = DecompressUdpHeader(udpHeader, aFrameData));
952
953 // length
954 if (aDatagramLength == 0)
955 {
956 udpHeader.SetLength(sizeof(udpHeader) + aFrameData.GetLength());
957 }
958 else
959 {
960 udpHeader.SetLength(aDatagramLength - aMessage.GetOffset());
961 }
962
963 SuccessOrExit(error = aMessage.Append(udpHeader));
964 aMessage.MoveOffset(sizeof(udpHeader));
965
966 exit:
967 return error;
968 }
969
Decompress(Message & aMessage,const Mac::Addresses & aMacAddrs,FrameData & aFrameData,uint16_t aDatagramLength)970 Error Lowpan::Decompress(Message &aMessage,
971 const Mac::Addresses &aMacAddrs,
972 FrameData &aFrameData,
973 uint16_t aDatagramLength)
974 {
975 Error error = kErrorParse;
976 Ip6::Header ip6Header;
977 bool compressed;
978 uint16_t ip6PayloadLength;
979 uint16_t currentOffset = aMessage.GetOffset();
980
981 SuccessOrExit(DecompressBaseHeader(ip6Header, compressed, aMacAddrs, aFrameData));
982
983 SuccessOrExit(aMessage.Append(ip6Header));
984 aMessage.MoveOffset(sizeof(ip6Header));
985
986 while (compressed)
987 {
988 uint8_t byte;
989
990 VerifyOrExit(aFrameData.GetLength() > 0);
991 byte = *aFrameData.GetBytes();
992
993 if ((byte & kExtHdrDispatchMask) == kExtHdrDispatch)
994 {
995 if ((byte & kExtHdrEidMask) == kExtHdrEidIp6)
996 {
997 compressed = false;
998
999 aFrameData.SkipOver(sizeof(uint8_t));
1000
1001 SuccessOrExit(Decompress(aMessage, aMacAddrs, aFrameData, aDatagramLength));
1002 }
1003 else
1004 {
1005 compressed = (byte & kExtHdrNextHeader) != 0;
1006 SuccessOrExit(DecompressExtensionHeader(aMessage, aFrameData));
1007 }
1008 }
1009 else if ((byte & kUdpDispatchMask) == kUdpDispatch)
1010 {
1011 compressed = false;
1012 SuccessOrExit(DecompressUdpHeader(aMessage, aFrameData, aDatagramLength));
1013 }
1014 else
1015 {
1016 ExitNow();
1017 }
1018 }
1019
1020 if (aDatagramLength)
1021 {
1022 ip6PayloadLength = BigEndian::HostSwap16(aDatagramLength - currentOffset - sizeof(Ip6::Header));
1023 }
1024 else
1025 {
1026 ip6PayloadLength =
1027 BigEndian::HostSwap16(aMessage.GetOffset() - currentOffset - sizeof(Ip6::Header) + aFrameData.GetLength());
1028 }
1029
1030 aMessage.Write(currentOffset + Ip6::Header::kPayloadLengthFieldOffset, ip6PayloadLength);
1031
1032 error = kErrorNone;
1033
1034 exit:
1035 return error;
1036 }
1037
DecompressEcn(const Message & aMessage,uint16_t aOffset) const1038 Ip6::Ecn Lowpan::DecompressEcn(const Message &aMessage, uint16_t aOffset) const
1039 {
1040 Ip6::Ecn ecn = Ip6::kEcnNotCapable;
1041 uint16_t hcCtl;
1042 uint8_t byte;
1043
1044 SuccessOrExit(aMessage.Read(aOffset, hcCtl));
1045 hcCtl = BigEndian::HostSwap16(hcCtl);
1046
1047 VerifyOrExit((hcCtl & kHcDispatchMask) == kHcDispatch);
1048 aOffset += sizeof(uint16_t);
1049
1050 if ((hcCtl & kHcTrafficFlowMask) == kHcTrafficFlow)
1051 {
1052 // ECN is elided and is zero (`kEcnNotCapable`).
1053 ExitNow();
1054 }
1055
1056 // When ECN is not elided, it is always included as the
1057 // first two bits of the next byte.
1058 SuccessOrExit(aMessage.Read(aOffset, byte));
1059 ecn = static_cast<Ip6::Ecn>((byte & kEcnMask) >> kEcnOffset);
1060
1061 exit:
1062 return ecn;
1063 }
1064
MarkCompressedEcn(Message & aMessage,uint16_t aOffset)1065 void Lowpan::MarkCompressedEcn(Message &aMessage, uint16_t aOffset)
1066 {
1067 uint8_t byte;
1068
1069 aOffset += sizeof(uint16_t);
1070 IgnoreError(aMessage.Read(aOffset, byte));
1071
1072 byte &= ~kEcnMask;
1073 byte |= static_cast<uint8_t>(Ip6::kEcnMarked << kEcnOffset);
1074
1075 aMessage.Write(aOffset, byte);
1076 }
1077
1078 //---------------------------------------------------------------------------------------------------------------------
1079 // MeshHeader
1080
Init(uint16_t aSource,uint16_t aDestination,uint8_t aHopsLeft)1081 void MeshHeader::Init(uint16_t aSource, uint16_t aDestination, uint8_t aHopsLeft)
1082 {
1083 mSource = aSource;
1084 mDestination = aDestination;
1085 mHopsLeft = aHopsLeft;
1086 }
1087
IsMeshHeader(const FrameData & aFrameData)1088 bool MeshHeader::IsMeshHeader(const FrameData &aFrameData)
1089 {
1090 return (aFrameData.GetLength() >= kMinHeaderLength) && ((*aFrameData.GetBytes() & kDispatchMask) == kDispatch);
1091 }
1092
ParseFrom(FrameData & aFrameData)1093 Error MeshHeader::ParseFrom(FrameData &aFrameData)
1094 {
1095 Error error;
1096 uint16_t headerLength;
1097
1098 SuccessOrExit(error = ParseFrom(aFrameData.GetBytes(), aFrameData.GetLength(), headerLength));
1099 aFrameData.SkipOver(headerLength);
1100
1101 exit:
1102 return error;
1103 }
1104
ParseFrom(const uint8_t * aFrame,uint16_t aFrameLength,uint16_t & aHeaderLength)1105 Error MeshHeader::ParseFrom(const uint8_t *aFrame, uint16_t aFrameLength, uint16_t &aHeaderLength)
1106 {
1107 Error error = kErrorParse;
1108 uint8_t dispatch;
1109
1110 VerifyOrExit(aFrameLength >= kMinHeaderLength);
1111 dispatch = *aFrame++;
1112
1113 VerifyOrExit((dispatch & (kDispatchMask | kSourceShort | kDestShort)) == (kDispatch | kSourceShort | kDestShort));
1114
1115 mHopsLeft = (dispatch & kHopsLeftMask);
1116
1117 if (mHopsLeft == kDeepHopsLeft)
1118 {
1119 VerifyOrExit(aFrameLength >= kDeepHopsHeaderLength);
1120 mHopsLeft = *aFrame++;
1121 aHeaderLength = kDeepHopsHeaderLength;
1122 }
1123 else
1124 {
1125 aHeaderLength = kMinHeaderLength;
1126 }
1127
1128 mSource = BigEndian::ReadUint16(aFrame);
1129 mDestination = BigEndian::ReadUint16(aFrame + 2);
1130
1131 error = kErrorNone;
1132
1133 exit:
1134 return error;
1135 }
1136
ParseFrom(const Message & aMessage)1137 Error MeshHeader::ParseFrom(const Message &aMessage)
1138 {
1139 uint16_t headerLength;
1140
1141 return ParseFrom(aMessage, headerLength);
1142 }
1143
ParseFrom(const Message & aMessage,uint16_t & aHeaderLength)1144 Error MeshHeader::ParseFrom(const Message &aMessage, uint16_t &aHeaderLength)
1145 {
1146 uint8_t frame[kDeepHopsHeaderLength];
1147 uint16_t frameLength;
1148
1149 frameLength = aMessage.ReadBytes(/* aOffset */ 0, frame, sizeof(frame));
1150
1151 return ParseFrom(frame, frameLength, aHeaderLength);
1152 }
1153
GetHeaderLength(void) const1154 uint16_t MeshHeader::GetHeaderLength(void) const
1155 {
1156 return (mHopsLeft >= kDeepHopsLeft) ? kDeepHopsHeaderLength : kMinHeaderLength;
1157 }
1158
DecrementHopsLeft(void)1159 void MeshHeader::DecrementHopsLeft(void)
1160 {
1161 if (mHopsLeft > 0)
1162 {
1163 mHopsLeft--;
1164 }
1165 }
1166
AppendTo(FrameBuilder & aFrameBuilder) const1167 Error MeshHeader::AppendTo(FrameBuilder &aFrameBuilder) const
1168 {
1169 Error error;
1170 uint8_t dispatch = (kDispatch | kSourceShort | kDestShort);
1171
1172 if (mHopsLeft < kDeepHopsLeft)
1173 {
1174 SuccessOrExit(error = aFrameBuilder.AppendUint8(dispatch | mHopsLeft));
1175 }
1176 else
1177 {
1178 SuccessOrExit(error = aFrameBuilder.AppendUint8(dispatch | kDeepHopsLeft));
1179 SuccessOrExit(error = aFrameBuilder.AppendUint8(mHopsLeft));
1180 }
1181
1182 SuccessOrExit(error = aFrameBuilder.AppendBigEndianUint16(mSource));
1183 SuccessOrExit(error = aFrameBuilder.AppendBigEndianUint16(mDestination));
1184
1185 exit:
1186 return error;
1187 }
1188
AppendTo(Message & aMessage) const1189 Error MeshHeader::AppendTo(Message &aMessage) const
1190 {
1191 uint8_t frame[kDeepHopsHeaderLength];
1192 FrameBuilder frameBuilder;
1193
1194 frameBuilder.Init(frame, sizeof(frame));
1195
1196 IgnoreError(AppendTo(frameBuilder));
1197
1198 return aMessage.AppendBytes(frameBuilder.GetBytes(), frameBuilder.GetLength());
1199 }
1200
1201 //---------------------------------------------------------------------------------------------------------------------
1202 // FragmentHeader
1203
IsFragmentHeader(const FrameData & aFrameData)1204 bool FragmentHeader::IsFragmentHeader(const FrameData &aFrameData)
1205 {
1206 return IsFragmentHeader(aFrameData.GetBytes(), aFrameData.GetLength());
1207 }
1208
IsFragmentHeader(const uint8_t * aFrame,uint16_t aFrameLength)1209 bool FragmentHeader::IsFragmentHeader(const uint8_t *aFrame, uint16_t aFrameLength)
1210 {
1211 return (aFrameLength >= sizeof(FirstFrag)) && ((*aFrame & kDispatchMask) == kDispatch);
1212 }
1213
ParseFrom(FrameData & aFrameData)1214 Error FragmentHeader::ParseFrom(FrameData &aFrameData)
1215 {
1216 Error error;
1217 uint16_t headerLength;
1218
1219 SuccessOrExit(error = ParseFrom(aFrameData.GetBytes(), aFrameData.GetLength(), headerLength));
1220 aFrameData.SkipOver(headerLength);
1221
1222 exit:
1223 return error;
1224 }
1225
ParseFrom(const uint8_t * aFrame,uint16_t aFrameLength,uint16_t & aHeaderLength)1226 Error FragmentHeader::ParseFrom(const uint8_t *aFrame, uint16_t aFrameLength, uint16_t &aHeaderLength)
1227 {
1228 Error error = kErrorParse;
1229
1230 VerifyOrExit(IsFragmentHeader(aFrame, aFrameLength));
1231
1232 mSize = BigEndian::ReadUint16(aFrame + kSizeIndex) & kSizeMask;
1233 mTag = BigEndian::ReadUint16(aFrame + kTagIndex);
1234
1235 if ((*aFrame & kOffsetFlag) == kOffsetFlag)
1236 {
1237 VerifyOrExit(aFrameLength >= sizeof(NextFrag));
1238 mOffset = aFrame[kOffsetIndex] * 8;
1239 aHeaderLength = sizeof(NextFrag);
1240 }
1241 else
1242 {
1243 mOffset = 0;
1244 aHeaderLength = sizeof(FirstFrag);
1245 }
1246
1247 error = kErrorNone;
1248
1249 exit:
1250 return error;
1251 }
1252
ParseFrom(const Message & aMessage,uint16_t aOffset,uint16_t & aHeaderLength)1253 Error FragmentHeader::ParseFrom(const Message &aMessage, uint16_t aOffset, uint16_t &aHeaderLength)
1254 {
1255 uint8_t frame[sizeof(NextFrag)];
1256 uint16_t frameLength;
1257
1258 frameLength = aMessage.ReadBytes(aOffset, frame, sizeof(frame));
1259
1260 return ParseFrom(frame, frameLength, aHeaderLength);
1261 }
1262
1263 } // namespace Lowpan
1264 } // namespace ot
1265