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