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