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