blob: 3f3181a6e2a0fddf16a82c880c1cbc39a1266fa9 [file] [log] [blame]
Jonathan Hui4f9945c2016-05-10 20:48:47 -07001/*
Jonathan Hui44350172016-09-13 15:57:11 -07002 * Copyright (c) 2016, The OpenThread Authors.
Marcin K Szczodrak99870fa2016-05-12 22:39:11 -07003 * All rights reserved.
Jonathan Hui4f9945c2016-05-10 20:48:47 -07004 *
Marcin K Szczodrak99870fa2016-05-12 22:39:11 -07005 * 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.
Jonathan Hui4f9945c2016-05-10 20:48:47 -070015 *
Marcin K Szczodrak99870fa2016-05-12 22:39:11 -070016 * 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.
Jonathan Hui4f9945c2016-05-10 20:48:47 -070027 */
28
29/**
30 * @file
31 * This file implements 6LoWPAN header compression.
32 */
33
34#include <common/code_utils.hpp>
35#include <common/debug.hpp>
36#include <common/encoding.hpp>
37#include <net/ip6.hpp>
38#include <net/udp6.hpp>
39#include <thread/lowpan.hpp>
40#include <thread/network_data_leader.hpp>
41#include <thread/thread_netif.hpp>
42
43using Thread::Encoding::BigEndian::HostSwap16;
44
45namespace Thread {
46namespace Lowpan {
47
48Lowpan::Lowpan(ThreadNetif &aThreadNetif):
49 mNetworkData(aThreadNetif.GetNetworkDataLeader())
50{
51}
52
53ThreadError Lowpan::CopyContext(const Context &aContext, Ip6::Address &aAddress)
54{
55 memcpy(&aAddress, aContext.mPrefix, aContext.mPrefixLength / CHAR_BIT);
56
57 for (int i = (aContext.mPrefixLength & ~7); i < aContext.mPrefixLength; i++)
58 {
Jonathan Hui4369a312016-06-21 13:04:51 -070059 aAddress.mFields.m8[i / CHAR_BIT] &= ~(0x80 >> (i % CHAR_BIT));
60 aAddress.mFields.m8[i / CHAR_BIT] |= aContext.mPrefix[i / CHAR_BIT] & (0x80 >> (i % CHAR_BIT));
Jonathan Hui4f9945c2016-05-10 20:48:47 -070061 }
62
63 return kThreadError_None;
64}
65
66ThreadError Lowpan::ComputeIid(const Mac::Address &aMacAddr, const Context &aContext, Ip6::Address &aIpAddress)
67{
68 switch (aMacAddr.mLength)
69 {
70 case 2:
Jonathan Hui4369a312016-06-21 13:04:51 -070071 aIpAddress.mFields.m16[4] = HostSwap16(0x0000);
72 aIpAddress.mFields.m16[5] = HostSwap16(0x00ff);
73 aIpAddress.mFields.m16[6] = HostSwap16(0xfe00);
74 aIpAddress.mFields.m16[7] = HostSwap16(aMacAddr.mShortAddress);
Jonathan Hui4f9945c2016-05-10 20:48:47 -070075 break;
76
77 case Ip6::Address::kInterfaceIdentifierSize:
78 aIpAddress.SetIid(aMacAddr.mExtAddress);
79 break;
80
81 default:
82 assert(false);
83 }
84
85 if (aContext.mPrefixLength > 64)
86 {
87 for (int i = (aContext.mPrefixLength & ~7); i < aContext.mPrefixLength; i++)
88 {
Jonathan Hui4369a312016-06-21 13:04:51 -070089 aIpAddress.mFields.m8[i / CHAR_BIT] &= ~(0x80 >> (i % CHAR_BIT));
90 aIpAddress.mFields.m8[i / CHAR_BIT] |= aContext.mPrefix[i / CHAR_BIT] & (0x80 >> (i % CHAR_BIT));
Jonathan Hui4f9945c2016-05-10 20:48:47 -070091 }
92 }
93
94 return kThreadError_None;
95}
96
97int Lowpan::CompressSourceIid(const Mac::Address &aMacAddr, const Ip6::Address &aIpAddr, const Context &aContext,
98 uint16_t &aHcCtl, uint8_t *aBuf)
99{
100 uint8_t *cur = aBuf;
101 Ip6::Address ipaddr;
102 Mac::Address tmp;
103
104 ComputeIid(aMacAddr, aContext, ipaddr);
105
106 if (memcmp(ipaddr.GetIid(), aIpAddr.GetIid(), Ip6::Address::kInterfaceIdentifierSize) == 0)
107 {
108 aHcCtl |= kHcSrcAddrMode3;
109 }
110 else
111 {
112 tmp.mLength = sizeof(tmp.mShortAddress);
Jonathan Hui4369a312016-06-21 13:04:51 -0700113 tmp.mShortAddress = HostSwap16(aIpAddr.mFields.m16[7]);
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700114 ComputeIid(tmp, aContext, ipaddr);
115
116 if (memcmp(ipaddr.GetIid(), aIpAddr.GetIid(), Ip6::Address::kInterfaceIdentifierSize) == 0)
117 {
118 aHcCtl |= kHcSrcAddrMode2;
Jonathan Hui4369a312016-06-21 13:04:51 -0700119 cur[0] = aIpAddr.mFields.m8[14];
120 cur[1] = aIpAddr.mFields.m8[15];
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700121 cur += 2;
122 }
123 else
124 {
125 aHcCtl |= kHcSrcAddrMode1;
126 memcpy(cur, aIpAddr.GetIid(), Ip6::Address::kInterfaceIdentifierSize);
127 cur += Ip6::Address::kInterfaceIdentifierSize;
128 }
129 }
130
Jonathan Hui4050c682016-08-10 11:52:22 -0700131 return static_cast<int>(cur - aBuf);
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700132}
133
134int Lowpan::CompressDestinationIid(const Mac::Address &aMacAddr, const Ip6::Address &aIpAddr, const Context &aContext,
135 uint16_t &aHcCtl, uint8_t *aBuf)
136{
137 uint8_t *cur = aBuf;
138 Ip6::Address ipaddr;
139 Mac::Address tmp;
140
141 ComputeIid(aMacAddr, aContext, ipaddr);
142
143 if (memcmp(ipaddr.GetIid(), aIpAddr.GetIid(), Ip6::Address::kInterfaceIdentifierSize) == 0)
144 {
145 aHcCtl |= kHcDstAddrMode3;
146 }
147 else
148 {
149 tmp.mLength = sizeof(tmp.mShortAddress);
Jonathan Hui4369a312016-06-21 13:04:51 -0700150 tmp.mShortAddress = HostSwap16(aIpAddr.mFields.m16[7]);
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700151 ComputeIid(tmp, aContext, ipaddr);
152
153 if (memcmp(ipaddr.GetIid(), aIpAddr.GetIid(), Ip6::Address::kInterfaceIdentifierSize) == 0)
154 {
155 aHcCtl |= kHcDstAddrMode2;
Jonathan Hui4369a312016-06-21 13:04:51 -0700156 cur[0] = aIpAddr.mFields.m8[14];
157 cur[1] = aIpAddr.mFields.m8[15];
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700158 cur += 2;
159 }
160 else
161 {
162 aHcCtl |= kHcDstAddrMode1;
163 memcpy(cur, aIpAddr.GetIid(), Ip6::Address::kInterfaceIdentifierSize);
164 cur += Ip6::Address::kInterfaceIdentifierSize;
165 }
166 }
167
Jonathan Hui4050c682016-08-10 11:52:22 -0700168 return static_cast<int>(cur - aBuf);
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700169}
170
171int Lowpan::CompressMulticast(const Ip6::Address &aIpAddr, uint16_t &aHcCtl, uint8_t *aBuf)
172{
173 uint8_t *cur = aBuf;
174
175 aHcCtl |= kHcMulticast;
176
177 for (unsigned int i = 2; i < sizeof(Ip6::Address); i++)
178 {
Jonathan Hui4369a312016-06-21 13:04:51 -0700179 if (aIpAddr.mFields.m8[i])
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700180 {
Jonathan Hui4369a312016-06-21 13:04:51 -0700181 if (aIpAddr.mFields.m8[1] == 0x02 && i >= 15)
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700182 {
183 aHcCtl |= kHcDstAddrMode3;
Jonathan Hui4369a312016-06-21 13:04:51 -0700184 cur[0] = aIpAddr.mFields.m8[15];
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700185 cur++;
186 }
187 else if (i >= 13)
188 {
189 aHcCtl |= kHcDstAddrMode2;
Jonathan Hui4369a312016-06-21 13:04:51 -0700190 cur[0] = aIpAddr.mFields.m8[1];
191 memcpy(cur + 1, aIpAddr.mFields.m8 + 13, 3);
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700192 cur += 4;
193 }
194 else if (i >= 9)
195 {
196 aHcCtl |= kHcDstAddrMode1;
Jonathan Hui4369a312016-06-21 13:04:51 -0700197 cur[0] = aIpAddr.mFields.m8[1];
198 memcpy(cur + 1, aIpAddr.mFields.m8 + 11, 5);
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700199 cur += 6;
200 }
201 else
202 {
Jonathan Hui4369a312016-06-21 13:04:51 -0700203 memcpy(cur, aIpAddr.mFields.m8, sizeof(Ip6::Address));
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700204 cur += sizeof(Ip6::Address);
205 }
206
207 break;
208 }
209 }
210
Jonathan Hui4050c682016-08-10 11:52:22 -0700211 return static_cast<int>(cur - aBuf);
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700212}
213
214int Lowpan::Compress(Message &aMessage, const Mac::Address &aMacSource, const Mac::Address &aMacDest, uint8_t *aBuf)
215{
216 uint8_t *cur = aBuf;
217 uint16_t hcCtl = 0;
218 Ip6::Header ip6Header;
219 uint8_t *ip6HeaderBytes = reinterpret_cast<uint8_t *>(&ip6Header);
220 Context srcContext, dstContext;
221 bool srcContextValid = true, dstContextValid = true;
222 uint8_t nextHeader;
223
224 aMessage.Read(0, sizeof(ip6Header), &ip6Header);
225
226 if (mNetworkData.GetContext(ip6Header.GetSource(), srcContext) != kThreadError_None)
227 {
228 mNetworkData.GetContext(0, srcContext);
229 srcContextValid = false;
230 }
231
232 if (mNetworkData.GetContext(ip6Header.GetDestination(), dstContext) != kThreadError_None)
233 {
234 mNetworkData.GetContext(0, dstContext);
235 dstContextValid = false;
236 }
237
238 hcCtl = kHcDispatch;
239
240 // Lowpan HC Control Bits
241 cur += 2;
242
243 // Context Identifier
244 if (srcContext.mContextId != 0 || dstContext.mContextId != 0)
245 {
246 hcCtl |= kHcContextId;
Jonathan Hui4050c682016-08-10 11:52:22 -0700247 cur[0] = ((srcContext.mContextId << 4) | dstContext.mContextId) & 0xff;
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700248 cur++;
249 }
250
251 // Traffic Class
252 if (((ip6HeaderBytes[0] & 0x0f) == 0) && ((ip6HeaderBytes[1] & 0xf0) == 0))
253 {
254 hcCtl |= kHcTrafficClass;
255 }
256
257 // Flow Label
258 if (((ip6HeaderBytes[1] & 0x0f) == 0) && ((ip6HeaderBytes[2]) == 0) && ((ip6HeaderBytes[3]) == 0))
259 {
260 hcCtl |= kHcFlowLabel;
261 }
262
263 if ((hcCtl & kHcTrafficFlowMask) != kHcTrafficFlow)
264 {
Jonathan Hui4050c682016-08-10 11:52:22 -0700265 cur[0] = ((ip6HeaderBytes[1] >> 4) << 6) & 0xff;
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700266
267 if ((hcCtl & kHcTrafficClass) == 0)
268 {
269 cur[0] |= ((ip6HeaderBytes[0] & 0x0f) << 2) | (ip6HeaderBytes[1] >> 6);
270 cur++;
271 }
272
273 if ((hcCtl & kHcFlowLabel) == 0)
274 {
275 cur[0] |= ip6HeaderBytes[1] & 0x0f;
276 cur[1] = ip6HeaderBytes[2];
277 cur[2] = ip6HeaderBytes[3];
278 cur += 3;
279 }
280 }
281
282 // Next Header
283 switch (ip6Header.GetNextHeader())
284 {
285 case Ip6::kProtoHopOpts:
286 case Ip6::kProtoUdp:
287 hcCtl |= kHcNextHeader;
288 break;
289
290 default:
Nick Banksae545bb2016-09-13 09:25:22 -0700291 cur[0] = static_cast<uint8_t>(ip6Header.GetNextHeader());
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700292 cur++;
293 break;
294 }
295
296 // Hop Limit
297 switch (ip6Header.GetHopLimit())
298 {
299 case 1:
300 hcCtl |= kHcHopLimit1;
301 break;
302
303 case 64:
304 hcCtl |= kHcHopLimit64;
305 break;
306
307 case 255:
308 hcCtl |= kHcHopLimit255;
309 break;
310
311 default:
312 cur[0] = ip6Header.GetHopLimit();
313 cur++;
314 break;
315 }
316
317 // Source Address
318 if (ip6Header.GetSource().IsUnspecified())
319 {
320 hcCtl |= kHcSrcAddrContext;
321 }
322 else if (ip6Header.GetSource().IsLinkLocal())
323 {
324 cur += CompressSourceIid(aMacSource, ip6Header.GetSource(), srcContext, hcCtl, cur);
325 }
326 else if (srcContextValid)
327 {
328 hcCtl |= kHcSrcAddrContext;
329 cur += CompressSourceIid(aMacSource, ip6Header.GetSource(), srcContext, hcCtl, cur);
330 }
331 else
332 {
Jonathan Hui4369a312016-06-21 13:04:51 -0700333 memcpy(cur, ip6Header.GetSource().mFields.m8, sizeof(ip6Header.GetSource()));
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700334 cur += sizeof(Ip6::Address);
335 }
336
337 // Destination Address
338 if (ip6Header.GetDestination().IsMulticast())
339 {
340 cur += CompressMulticast(ip6Header.GetDestination(), hcCtl, cur);
341 }
342 else if (ip6Header.GetDestination().IsLinkLocal())
343 {
344 cur += CompressDestinationIid(aMacDest, ip6Header.GetDestination(), dstContext, hcCtl, cur);
345 }
346 else if (dstContextValid)
347 {
348 hcCtl |= kHcDstAddrContext;
349 cur += CompressDestinationIid(aMacDest, ip6Header.GetDestination(), dstContext, hcCtl, cur);
350 }
351 else
352 {
353 memcpy(cur, &ip6Header.GetDestination(), sizeof(ip6Header.GetDestination()));
354 cur += sizeof(Ip6::Address);
355 }
356
357 aBuf[0] = hcCtl >> 8;
Jonathan Hui4050c682016-08-10 11:52:22 -0700358 aBuf[1] = hcCtl & 0xff;
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700359 aMessage.SetOffset(sizeof(ip6Header));
360
Nick Banksae545bb2016-09-13 09:25:22 -0700361 nextHeader = static_cast<uint8_t>(ip6Header.GetNextHeader());
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700362
363 while (1)
364 {
365 switch (nextHeader)
366 {
367 case Ip6::kProtoHopOpts:
368 cur += CompressExtensionHeader(aMessage, cur, nextHeader);
369 break;
370
371 case Ip6::kProtoUdp:
372 cur += CompressUdp(aMessage, cur);
373 ExitNow();
374
375 default:
376 ExitNow();
377 }
378 }
379
380exit:
Jonathan Hui4050c682016-08-10 11:52:22 -0700381 return static_cast<int>(cur - aBuf);
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700382}
383
384int Lowpan::CompressExtensionHeader(Message &aMessage, uint8_t *aBuf, uint8_t &aNextHeader)
385{
386 Ip6::ExtensionHeader extHeader;
387 uint8_t *cur = aBuf;
388 uint8_t len;
389
390 aMessage.Read(aMessage.GetOffset(), sizeof(extHeader), &extHeader);
391 aMessage.MoveOffset(sizeof(extHeader));
392
393 cur[0] = kExtHdrDispatch | kExtHdrEidHbh;
Nick Banksae545bb2016-09-13 09:25:22 -0700394 aNextHeader = static_cast<uint8_t>(extHeader.GetNextHeader());
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700395
396 switch (extHeader.GetNextHeader())
397 {
398 case Ip6::kProtoUdp:
399 cur[0] |= kExtHdrNextHeader;
400 break;
401
402 default:
403 cur++;
Nick Banksae545bb2016-09-13 09:25:22 -0700404 cur[0] = static_cast<uint8_t>(extHeader.GetNextHeader());
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700405 break;
406 }
407
408 cur++;
409
410 len = (extHeader.GetLength() + 1) * 8 - sizeof(extHeader);
411 cur[0] = len;
412 cur++;
413
414 aMessage.Read(aMessage.GetOffset(), len, cur);
415 aMessage.MoveOffset(len);
416 cur += len;
417
Jonathan Hui4050c682016-08-10 11:52:22 -0700418 return static_cast<int>(cur - aBuf);
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700419}
420
421int Lowpan::CompressUdp(Message &aMessage, uint8_t *aBuf)
422{
423 Ip6::UdpHeader udpHeader;
424 uint8_t *cur = aBuf;
Jonathan Hui6d48a7b2016-07-17 22:43:42 -0700425 uint8_t *udpCtl = cur;
426 uint16_t source;
427 uint16_t destination;
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700428
429 aMessage.Read(aMessage.GetOffset(), sizeof(udpHeader), &udpHeader);
Jonathan Hui6d48a7b2016-07-17 22:43:42 -0700430 source = udpHeader.GetSourcePort();
431 destination = udpHeader.GetDestinationPort();
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700432
433 cur[0] = kUdpDispatch;
434 cur++;
435
Jonathan Hui6d48a7b2016-07-17 22:43:42 -0700436 if ((source & 0xfff0) == 0xf0b0 && (destination & 0xfff0) == 0xf0b0)
437 {
438 *udpCtl |= 3;
Jonathan Hui4050c682016-08-10 11:52:22 -0700439 *cur++ = (((source & 0xf) << 4) | (destination & 0xf)) & 0xff;
Jonathan Hui6d48a7b2016-07-17 22:43:42 -0700440 }
441 else if ((source & 0xff00) == 0xf000)
442 {
443 *udpCtl |= 2;
Jonathan Hui4050c682016-08-10 11:52:22 -0700444 *cur++ = source & 0xff;
Jonathan Hui6d48a7b2016-07-17 22:43:42 -0700445 *cur++ = destination >> 8;
Jonathan Hui4050c682016-08-10 11:52:22 -0700446 *cur++ = destination & 0xff;
Jonathan Hui6d48a7b2016-07-17 22:43:42 -0700447 }
448 else if ((destination & 0xff00) == 0xf000)
449 {
450 *udpCtl |= 1;
451 *cur++ = source >> 8;
Jonathan Hui4050c682016-08-10 11:52:22 -0700452 *cur++ = source & 0xff;
453 *cur++ = destination & 0xff;
Jonathan Hui6d48a7b2016-07-17 22:43:42 -0700454 }
455 else
456 {
457 memcpy(cur, &udpHeader, Ip6::UdpHeader::GetLengthOffset());
458 cur += Ip6::UdpHeader::GetLengthOffset();
459 }
460
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700461 memcpy(cur, reinterpret_cast<uint8_t *>(&udpHeader) + Ip6::UdpHeader::GetChecksumOffset(), 2);
462 cur += 2;
463
464 aMessage.MoveOffset(sizeof(udpHeader));
465
Jonathan Hui4050c682016-08-10 11:52:22 -0700466 return static_cast<int>(cur - aBuf);
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700467}
468
469ThreadError Lowpan::DispatchToNextHeader(uint8_t aDispatch, Ip6::IpProto &aNextHeader)
470{
471 ThreadError error = kThreadError_None;
472
473 if ((aDispatch & kExtHdrDispatchMask) == kExtHdrDispatch)
474 {
475 switch (aDispatch & kExtHdrEidMask)
476 {
477 case kExtHdrEidHbh:
478 aNextHeader = Ip6::kProtoHopOpts;
479 ExitNow();
480
481 case kExtHdrEidRouting:
482 aNextHeader = Ip6::kProtoRouting;
483 ExitNow();
484
485 case kExtHdrEidFragment:
486 aNextHeader = Ip6::kProtoFragment;
487 ExitNow();
488
489 case kExtHdrEidDst:
490 aNextHeader = Ip6::kProtoDstOpts;
491 ExitNow();
492
493 case kExtHdrEidIp6:
494 aNextHeader = Ip6::kProtoIp6;
495 ExitNow();
496 }
497 }
498 else if ((aDispatch & kUdpDispatchMask) == kUdpDispatch)
499 {
500 aNextHeader = Ip6::kProtoUdp;
501 ExitNow();
502 }
503
504 error = kThreadError_Parse;
505
506exit:
507 return error;
508}
509
510int Lowpan::DecompressBaseHeader(Ip6::Header &ip6Header, const Mac::Address &aMacSource, const Mac::Address &aMacDest,
511 const uint8_t *aBuf)
512{
513 ThreadError error = kThreadError_None;
514 const uint8_t *cur = aBuf;
515 uint16_t hcCtl;
516 Context srcContext, dstContext;
517 bool srcContextValid = true, dstContextValid = true;
518 Ip6::IpProto nextHeader;
519 uint8_t *bytes;
520
Jonathan Hui4050c682016-08-10 11:52:22 -0700521 hcCtl = static_cast<uint16_t>((cur[0] << 8) | cur[1]);
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700522 cur += 2;
523
524 // check Dispatch bits
525 VerifyOrExit((hcCtl & kHcDispatchMask) == kHcDispatch, error = kThreadError_Parse);
526
527 // Context Identifier
528 srcContext.mPrefixLength = 0;
529 dstContext.mPrefixLength = 0;
530
531 if ((hcCtl & kHcContextId) != 0)
532 {
533 if (mNetworkData.GetContext(cur[0] >> 4, srcContext) != kThreadError_None)
534 {
535 srcContextValid = false;
536 }
537
538 if (mNetworkData.GetContext(cur[0] & 0xf, dstContext) != kThreadError_None)
539 {
540 dstContextValid = false;
541 }
542
543 cur++;
544 }
545 else
546 {
547 mNetworkData.GetContext(0, srcContext);
548 mNetworkData.GetContext(0, dstContext);
549 }
550
551 memset(&ip6Header, 0, sizeof(ip6Header));
552 ip6Header.Init();
553
554 // Traffic Class and Flow Label
555 if ((hcCtl & kHcTrafficFlowMask) != kHcTrafficFlow)
556 {
557 bytes = reinterpret_cast<uint8_t *>(&ip6Header);
558 bytes[1] |= (cur[0] & 0xc0) >> 2;
559
560 if ((hcCtl & kHcTrafficClass) == 0)
561 {
562 bytes[0] |= (cur[0] >> 2) & 0x0f;
563 bytes[1] |= (cur[0] << 6) & 0xc0;
564 cur++;
565 }
566
567 if ((hcCtl & kHcFlowLabel) == 0)
568 {
569 bytes[1] |= cur[0] & 0x0f;
570 bytes[2] |= cur[1];
571 bytes[3] |= cur[2];
572 cur += 3;
573 }
574 }
575
576 // Next Header
577 if ((hcCtl & kHcNextHeader) == 0)
578 {
579 ip6Header.SetNextHeader(static_cast<Ip6::IpProto>(cur[0]));
580 cur++;
581 }
582
583 // Hop Limit
584 switch (hcCtl & kHcHopLimitMask)
585 {
586 case kHcHopLimit1:
587 ip6Header.SetHopLimit(1);
588 break;
589
590 case kHcHopLimit64:
591 ip6Header.SetHopLimit(64);
592 break;
593
594 case kHcHopLimit255:
595 ip6Header.SetHopLimit(255);
596 break;
597
598 default:
599 ip6Header.SetHopLimit(cur[0]);
600 cur++;
601 break;
602 }
603
604 // Source Address
605 switch (hcCtl & kHcSrcAddrModeMask)
606 {
607 case kHcSrcAddrMode0:
608 if ((hcCtl & kHcSrcAddrContext) == 0)
609 {
610 memcpy(&ip6Header.GetSource(), cur, sizeof(ip6Header.GetSource()));
611 cur += sizeof(Ip6::Address);
612 }
613
614 break;
615
616 case kHcSrcAddrMode1:
617 ip6Header.GetSource().SetIid(cur);
618 cur += Ip6::Address::kInterfaceIdentifierSize;
619 break;
620
621 case kHcSrcAddrMode2:
Jonathan Hui4369a312016-06-21 13:04:51 -0700622 ip6Header.GetSource().mFields.m8[11] = 0xff;
623 ip6Header.GetSource().mFields.m8[12] = 0xfe;
624 memcpy(ip6Header.GetSource().mFields.m8 + 14, cur, 2);
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700625 cur += 2;
626 break;
627
628 case kHcSrcAddrMode3:
629 ComputeIid(aMacSource, srcContext, ip6Header.GetSource());
630 break;
631 }
632
633 if ((hcCtl & kHcSrcAddrContext) == 0)
634 {
635 if ((hcCtl & kHcSrcAddrModeMask) != 0)
636 {
Jonathan Hui4369a312016-06-21 13:04:51 -0700637 ip6Header.GetSource().mFields.m16[0] = HostSwap16(0xfe80);
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700638 }
639 }
640 else
641 {
642 VerifyOrExit(srcContextValid, error = kThreadError_Parse);
643 CopyContext(srcContext, ip6Header.GetSource());
644 }
645
646 if ((hcCtl & kHcMulticast) == 0)
647 {
648 // Unicast Destination Address
649
650 switch (hcCtl & kHcDstAddrModeMask)
651 {
652 case kHcDstAddrMode0:
653 memcpy(&ip6Header.GetDestination(), cur, sizeof(ip6Header.GetDestination()));
654 cur += sizeof(Ip6::Address);
655 break;
656
657 case kHcDstAddrMode1:
658 ip6Header.GetDestination().SetIid(cur);
659 cur += Ip6::Address::kInterfaceIdentifierSize;
660 break;
661
662 case kHcDstAddrMode2:
Jonathan Hui4369a312016-06-21 13:04:51 -0700663 ip6Header.GetDestination().mFields.m8[11] = 0xff;
664 ip6Header.GetDestination().mFields.m8[12] = 0xfe;
665 memcpy(ip6Header.GetDestination().mFields.m8 + 14, cur, 2);
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700666 cur += 2;
667 break;
668
669 case kHcDstAddrMode3:
670 ComputeIid(aMacDest, dstContext, ip6Header.GetDestination());
671 break;
672 }
673
674 if ((hcCtl & kHcDstAddrContext) == 0)
675 {
676 if ((hcCtl & kHcDstAddrModeMask) != 0)
677 {
Jonathan Hui4369a312016-06-21 13:04:51 -0700678 ip6Header.GetDestination().mFields.m16[0] = HostSwap16(0xfe80);
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700679 }
680 }
681 else
682 {
683 VerifyOrExit(dstContextValid, error = kThreadError_Parse);
684 CopyContext(dstContext, ip6Header.GetDestination());
685 }
686 }
687 else
688 {
689 // Multicast Destination Address
690
Jonathan Hui4369a312016-06-21 13:04:51 -0700691 ip6Header.GetDestination().mFields.m8[0] = 0xff;
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700692
693 if ((hcCtl & kHcDstAddrContext) == 0)
694 {
695 switch (hcCtl & kHcDstAddrModeMask)
696 {
697 case kHcDstAddrMode0:
Jonathan Hui4369a312016-06-21 13:04:51 -0700698 memcpy(ip6Header.GetDestination().mFields.m8, cur, sizeof(Ip6::Address));
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700699 cur += sizeof(Ip6::Address);
700 break;
701
702 case kHcDstAddrMode1:
Jonathan Hui4369a312016-06-21 13:04:51 -0700703 ip6Header.GetDestination().mFields.m8[1] = cur[0];
704 memcpy(ip6Header.GetDestination().mFields.m8 + 11, cur + 1, 5);
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700705 cur += 6;
706 break;
707
708 case kHcDstAddrMode2:
Jonathan Hui4369a312016-06-21 13:04:51 -0700709 ip6Header.GetDestination().mFields.m8[1] = cur[0];
710 memcpy(ip6Header.GetDestination().mFields.m8 + 13, cur + 1, 3);
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700711 cur += 4;
712 break;
713
714 case kHcDstAddrMode3:
Jonathan Hui4369a312016-06-21 13:04:51 -0700715 ip6Header.GetDestination().mFields.m8[1] = 0x02;
716 ip6Header.GetDestination().mFields.m8[15] = cur[0];
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700717 cur++;
718 break;
719 }
720 }
721 else
722 {
723 switch (hcCtl & kHcDstAddrModeMask)
724 {
725 case 0:
726 VerifyOrExit(dstContextValid, error = kThreadError_Parse);
Jonathan Hui4369a312016-06-21 13:04:51 -0700727 ip6Header.GetDestination().mFields.m8[1] = cur[0];
728 ip6Header.GetDestination().mFields.m8[2] = cur[1];
729 ip6Header.GetDestination().mFields.m8[3] = dstContext.mPrefixLength;
730 memcpy(ip6Header.GetDestination().mFields.m8 + 4, dstContext.mPrefix, 8);
731 memcpy(ip6Header.GetDestination().mFields.m8 + 12, cur + 2, 4);
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700732 cur += 6;
733 break;
734
735 default:
736 ExitNow(error = kThreadError_Parse);
737 }
738 }
739 }
740
741 if ((hcCtl & kHcNextHeader) != 0)
742 {
743 SuccessOrExit(error = DispatchToNextHeader(cur[0], nextHeader));
744 ip6Header.SetNextHeader(nextHeader);
745 }
746
747exit:
Jonathan Hui4050c682016-08-10 11:52:22 -0700748 return (error == kThreadError_None) ? static_cast<int>(cur - aBuf) : -1;
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700749}
750
751int Lowpan::DecompressExtensionHeader(Message &aMessage, const uint8_t *aBuf, uint16_t aBufLength)
752{
753 const uint8_t *cur = aBuf;
754 uint8_t hdr[2];
755 uint8_t len;
756 Ip6::IpProto nextHeader;
757 int rval = -1;
758 uint8_t ctl = cur[0];
759
760 cur++;
761
762 // next header
763 if (ctl & kExtHdrNextHeader)
764 {
765 len = cur[0];
766 cur++;
767
768 SuccessOrExit(DispatchToNextHeader(cur[len], nextHeader));
769 hdr[0] = static_cast<uint8_t>(nextHeader);
770 }
771 else
772 {
773 hdr[0] = cur[0];
774 cur++;
775
776 len = cur[0];
777 cur++;
778 }
779
780 // length
781 hdr[1] = BitVectorBytes(sizeof(hdr) + len) - 1;
782
783 SuccessOrExit(aMessage.Append(hdr, sizeof(hdr)));
784 aMessage.MoveOffset(sizeof(hdr));
785
786 // payload
787 SuccessOrExit(aMessage.Append(cur, len));
788 aMessage.MoveOffset(len);
789 cur += len;
790
Jonathan Hui4050c682016-08-10 11:52:22 -0700791 rval = static_cast<int>(cur - aBuf);
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700792
793exit:
Marcin K Szczodrak318fe4b2016-07-25 21:19:07 -0700794 (void)aBufLength;
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700795 return rval;
796}
797
798int Lowpan::DecompressUdpHeader(Message &aMessage, const uint8_t *aBuf, uint16_t aBufLength, uint16_t aDatagramLength)
799{
800 ThreadError error = kThreadError_None;
801 const uint8_t *cur = aBuf;
802 Ip6::UdpHeader udpHeader;
803 uint8_t udpCtl = cur[0];
804
805 cur++;
806
807 memset(&udpHeader, 0, sizeof(udpHeader));
808
809 // source and dest ports
810 switch (udpCtl & kUdpPortMask)
811 {
812 case 0:
Jonathan Hui4050c682016-08-10 11:52:22 -0700813 udpHeader.SetSourcePort(static_cast<uint16_t>((cur[0] << 8) | cur[1]));
814 udpHeader.SetDestinationPort(static_cast<uint16_t>((cur[2] << 8) | cur[3]));
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700815 cur += 4;
816 break;
817
818 case 1:
Jonathan Hui4050c682016-08-10 11:52:22 -0700819 udpHeader.SetSourcePort(static_cast<uint16_t>((cur[0] << 8) | cur[1]));
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700820 udpHeader.SetDestinationPort(0xf000 | cur[2]);
821 cur += 3;
822 break;
823
824 case 2:
825 udpHeader.SetSourcePort(0xf000 | cur[0]);
Jonathan Hui4050c682016-08-10 11:52:22 -0700826 udpHeader.SetDestinationPort(static_cast<uint16_t>((cur[1] << 8) | cur[2]));
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700827 cur += 3;
828 break;
829
830 case 3:
Jonathan Hui6d48a7b2016-07-17 22:43:42 -0700831 udpHeader.SetSourcePort(0xf0b0 | (cur[0] >> 4));
832 udpHeader.SetDestinationPort(0xf0b0 | (cur[0] & 0xf));
833 cur += 1;
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700834 break;
835 }
836
837 // checksum
838 if ((udpCtl & kUdpChecksum) != 0)
839 {
840 ExitNow(error = kThreadError_Parse);
841 }
842 else
843 {
Jonathan Hui4050c682016-08-10 11:52:22 -0700844 udpHeader.SetChecksum(static_cast<uint16_t>((cur[0] << 8) | cur[1]));
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700845 cur += 2;
846 }
847
848 // length
849 if (aDatagramLength == 0)
850 {
Jonathan Hui4050c682016-08-10 11:52:22 -0700851 udpHeader.SetLength(sizeof(udpHeader) + static_cast<uint16_t>(aBufLength - (cur - aBuf)));
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700852 }
853 else
854 {
855 udpHeader.SetLength(aDatagramLength - aMessage.GetOffset());
856 }
857
858 aMessage.Append(&udpHeader, sizeof(udpHeader));
859 aMessage.MoveOffset(sizeof(udpHeader));
860
861exit:
862
863 if (error != kThreadError_None)
864 {
865 return -1;
866 }
867
Jonathan Hui4050c682016-08-10 11:52:22 -0700868 return static_cast<int>(cur - aBuf);
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700869}
870
871int Lowpan::Decompress(Message &aMessage, const Mac::Address &aMacSource, const Mac::Address &aMacDest,
872 const uint8_t *aBuf, uint16_t aBufLen, uint16_t aDatagramLength)
873{
874 ThreadError error = kThreadError_None;
875 Ip6::Header ip6Header;
876 const uint8_t *cur = aBuf;
877 bool compressed;
Jonathan Hui4050c682016-08-10 11:52:22 -0700878 uint16_t remaining;
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700879 int rval;
880
881 compressed = (((static_cast<uint16_t>(cur[0]) << 8) | cur[1]) & kHcNextHeader) != 0;
882
883 VerifyOrExit((rval = DecompressBaseHeader(ip6Header, aMacSource, aMacDest, aBuf)) >= 0, ;);
884 cur += rval;
885
886 SuccessOrExit(error = aMessage.Append(&ip6Header, sizeof(ip6Header)));
887 SuccessOrExit(error = aMessage.SetOffset(sizeof(ip6Header)));
888
889 while (compressed)
890 {
Jonathan Hui4050c682016-08-10 11:52:22 -0700891 remaining = aBufLen - static_cast<uint16_t>(cur - aBuf);
892
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700893 if ((cur[0] & kExtHdrDispatchMask) == kExtHdrDispatch)
894 {
895 compressed = (cur[0] & kExtHdrNextHeader) != 0;
Jonathan Hui4050c682016-08-10 11:52:22 -0700896 VerifyOrExit((rval = DecompressExtensionHeader(aMessage, cur, remaining)) >= 0,
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700897 error = kThreadError_Parse);
898 }
899 else if ((cur[0] & kUdpDispatchMask) == kUdpDispatch)
900 {
901 compressed = false;
Jonathan Hui4050c682016-08-10 11:52:22 -0700902 VerifyOrExit((rval = DecompressUdpHeader(aMessage, cur, remaining, aDatagramLength)) >= 0,
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700903 error = kThreadError_Parse);
904 }
905 else
906 {
907 ExitNow(error = kThreadError_Parse);
908 }
909
910 cur += rval;
911 }
912
913exit:
914
915 if (error != kThreadError_None)
916 {
917 return -1;
918 }
919
Jonathan Hui4050c682016-08-10 11:52:22 -0700920 return static_cast<int>(cur - aBuf);
Jonathan Hui4f9945c2016-05-10 20:48:47 -0700921}
922
923} // namespace Lowpan
924} // namespace Thread