sixlowpan_hc06.c 46 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503
  1. /****************************************************************************
  2. * net/sixlowpan/sixlowpan_hc06.c
  3. * 6lowpan HC06 implementation (draft-ietf-6lowpan-hc-06, updated to RFC
  4. * 6282)
  5. *
  6. * Copyright (C) 2017, Gregory Nutt, all rights reserved
  7. * Author: Gregory Nutt <gnutt@nuttx.org>
  8. *
  9. * Derives from Contiki:
  10. *
  11. * Copyright (c) 2008, Swedish Institute of Computer Science.
  12. * All rights reserved.
  13. * Authors: Adam Dunkels <adam@sics.se>
  14. * Nicolas Tsiftes <nvt@sics.se>
  15. * Niclas Finne <nfi@sics.se>
  16. * Mathilde Durvy <mdurvy@cisco.com>
  17. * Julien Abeille <jabeille@cisco.com>
  18. * Joakim Eriksson <joakime@sics.se>
  19. * Joel Hoglund <joel@sics.se>
  20. *
  21. * Redistribution and use in source and binary forms, with or without
  22. * modification, are permitted provided that the following c/onditions
  23. * are met:
  24. *
  25. * 1. Redistributions of source code must retain the above copyright
  26. * notice, this list of conditions and the following disclaimer.
  27. * 2. Redistributions in binary form must reproduce the above copyright
  28. * notice, this list of conditions and the following disclaimer in the
  29. * documentation and/or other materials provided with the distribution.
  30. * 3. Neither the name of the Institute nor the names of its contributors
  31. * may be used to endorse or promote products derived from this software
  32. * without specific prior written permission.
  33. *
  34. * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
  35. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  36. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  37. * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
  38. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  39. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  40. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  41. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  42. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  43. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  44. * SUCH DAMAGE.
  45. *
  46. ****************************************************************************/
  47. /* FOR HC-06 COMPLIANCE TODO:
  48. *
  49. * -Add compression options to UDP, currently only supports
  50. * both ports compressed or both ports elided
  51. * -Verify TC/FL compression works
  52. * -Add multicast support for M=1 and DAC=1
  53. */
  54. /****************************************************************************
  55. * Included Files
  56. ****************************************************************************/
  57. #include <nuttx/config.h>
  58. #include <string.h>
  59. #include <debug.h>
  60. #include <nuttx/mm/iob.h>
  61. #include <nuttx/net/netdev.h>
  62. #include <nuttx/net/radiodev.h>
  63. #include <nuttx/net/ip.h>
  64. #include "sixlowpan/sixlowpan_internal.h"
  65. #ifdef CONFIG_NET_6LOWPAN_COMPRESSION_HC06
  66. /****************************************************************************
  67. * Pre-processor Definitions
  68. ****************************************************************************/
  69. /* Used in the encoding of address uncompress rules */
  70. #define UNCOMPRESS_POSTLEN_SHIFT 0
  71. #define UNCOMPRESS_POSTLEN_MASK (0x0f << UNCOMPRESS_POSTLEN_SHIFT)
  72. # define UNCOMPRESS_POSTLEN(n) (((n) & UNCOMPRESS_POSTLEN_MASK) >> UNCOMPRESS_POSTLEN_SHIFT)
  73. #define UNCOMPRESS_PREFLEN_SHIFT 4
  74. #define UNCOMPRESS_PREFLEN_MASK (0x0f << UNCOMPRESS_PREFLEN_SHIFT)
  75. # define UNCOMPRESS_PREFLEN(n) (((n) & UNCOMPRESS_PREFLEN_MASK) >> UNCOMPRESS_PREFLEN_SHIFT)
  76. #define UNCOMPRESS_MACBASED (1 << 8)
  77. #define UNCOMPRESS_ZEROPAD (1 << 9)
  78. /****************************************************************************
  79. * Private Types
  80. ****************************************************************************/
  81. /* An address context for IPHC address compression each context can have up
  82. * to 8 bytes
  83. */
  84. struct sixlowpan_addrcontext_s
  85. {
  86. uint8_t used; /* Possibly use as prefix-length */
  87. uint8_t number;
  88. uint8_t prefix[8];
  89. };
  90. /****************************************************************************
  91. * Private Data
  92. ****************************************************************************/
  93. /* HC06 specific variables **************************************************/
  94. /* Use of global variables simplifies the logic and is safe in the multi-
  95. * device environment because access is serialized via the network lock.
  96. *
  97. * But note that state may NOT be preserved from packet-to-packet.
  98. */
  99. #if CONFIG_NET_6LOWPAN_MAXADDRCONTEXT > 0
  100. /* Addresses contexts for IPHC. */
  101. static struct sixlowpan_addrcontext_s
  102. g_hc06_addrcontexts[CONFIG_NET_6LOWPAN_MAXADDRCONTEXT];
  103. #endif
  104. /* Pointer to the byte where to write next inline field. */
  105. static FAR uint8_t *g_hc06ptr;
  106. /* Constant Data ************************************************************/
  107. /* Uncompression of linklocal
  108. *
  109. * 0 -> 16 bytes from packet
  110. * 1 -> 2 bytes from prefix - 16 bytes from packet
  111. * 2 -> 2 bytes from prefix - 0000::00ff:fe00:XXXX and 2 bytes from packet
  112. * 3 -> 2 bytes from prefix - Infer 2 or 8 bytes from MAC address
  113. *
  114. * NOTE: ipaddr=the uncompress function does change 0xf to 0x100
  115. * NOTE: 0x00 ipaddr=no-autoconfig ipaddr=unspecified
  116. */
  117. static const uint16_t g_unc_llconf[] =
  118. {
  119. 0x000f, 0x0028, 0x0022, 0x0120
  120. };
  121. /* Uncompression of ctx-based
  122. *
  123. * 0 -> 0 bits from packet [unspecified / reserved]
  124. * 1 -> 8 bytes from prefix - Bunch of zeroes and 8 bytes from packet
  125. * 2 -> 8 bytes from prefix - 0000::00ff:fe00:XXXX and 2 bytes from packet
  126. * 3 -> 8 bytes from prefix - Infer 2 or 8 bytes from MAC address
  127. */
  128. static const uint16_t g_unc_ctxconf[] =
  129. {
  130. 0x0000, 0x0088, 0x0082, 0x0180
  131. };
  132. /* Uncompression of mx-based
  133. *
  134. * 0 -> 0 bits from prefix / 16 bytes inline
  135. * 1 -> 2 bytes from prefix / 5 bytes inline: ffxx::00xx:xxxx:xxxx
  136. * 2 -> 2 bytes from prefix / 3 bytes inline: ffxx::00xx:xxxx
  137. * 3 -> 2 bytes from prefix / 1 byte inline: ff02::00xx
  138. *
  139. * All other bits required zero padding.
  140. */
  141. static const uint16_t g_unc_mxconf[] =
  142. {
  143. 0x020f, 0x0225, 0x0223, 0x0221
  144. };
  145. /* Link local prefix */
  146. static const uint8_t g_llprefix[] =
  147. {
  148. 0xfe, 0x80
  149. };
  150. /* TTL uncompression values */
  151. static const uint8_t g_ttl_values[] =
  152. {
  153. 0, 1, 64, 255
  154. };
  155. /****************************************************************************
  156. * Private Functions
  157. ****************************************************************************/
  158. /****************************************************************************
  159. * Name: find_addrcontext_bynumber
  160. *
  161. * Description:
  162. * Find the address context with the given number.
  163. *
  164. ****************************************************************************/
  165. static FAR struct sixlowpan_addrcontext_s *
  166. find_addrcontext_bynumber(uint8_t number)
  167. {
  168. /* Remove code to avoid warnings and save flash if no address context is
  169. * used.
  170. */
  171. #if CONFIG_NET_6LOWPAN_MAXADDRCONTEXT > 0
  172. int i;
  173. for (i = 0; i < CONFIG_NET_6LOWPAN_MAXADDRCONTEXT; i++)
  174. {
  175. if ((g_hc06_addrcontexts[i].used == 1) &&
  176. g_hc06_addrcontexts[i].number == number)
  177. {
  178. return &g_hc06_addrcontexts[i];
  179. }
  180. }
  181. #endif /* CONFIG_NET_6LOWPAN_MAXADDRCONTEXT > 0 */
  182. return NULL;
  183. }
  184. /****************************************************************************
  185. * Name: find_addrcontext_byprefix
  186. *
  187. * Description:
  188. * Find the address context corresponding to the prefix ipaddr.
  189. *
  190. ****************************************************************************/
  191. static FAR struct sixlowpan_addrcontext_s *
  192. find_addrcontext_byprefix(FAR const net_ipv6addr_t ipaddr)
  193. {
  194. #if CONFIG_NET_6LOWPAN_MAXADDRCONTEXT > 0
  195. int i;
  196. /* Remove code to avoid warnings and save flash if no address context is used */
  197. for (i = 0; i < CONFIG_NET_6LOWPAN_MAXADDRCONTEXT; i++)
  198. {
  199. if ((g_hc06_addrcontexts[i].used == 1) &&
  200. net_ipv6addr_prefixcmp(&g_hc06_addrcontexts[i].prefix, ipaddr, 64))
  201. {
  202. ninfo("Context found for ipaddr=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x Context: %d\n",
  203. ntohs(ipaddr[0]), ntohs(ipaddr[1]), ntohs(ipaddr[2]), ntohs(ipaddr[3]),
  204. ntohs(ipaddr[4]), ntohs(ipaddr[5]), ntohs(ipaddr[6]), ntohs(ipaddr[7]),
  205. g_hc06_addrcontexts[i].number);
  206. return &g_hc06_addrcontexts[i];
  207. }
  208. }
  209. #endif /* CONFIG_NET_6LOWPAN_MAXADDRCONTEXT > 0 */
  210. return NULL;
  211. }
  212. /****************************************************************************
  213. * Name: compress_ipaddr, compress_tagaddr, and compress_laddr
  214. *
  215. * Description:
  216. * Uncompress addresses based on a prefix and a postfix with zeroes in
  217. * between. If the postfix is zero in length it will use the link address
  218. * to configure the IP address (autoconf style).
  219. *
  220. * prefpost takes a byte where the first nibble specify prefix count
  221. * and the second postfix count (NOTE: 15/0xf ipaddr=16 bytes copy).
  222. *
  223. * compress_tagaddr() accepts a remote, variable length, taged MAC address;
  224. * compress_laddr() accepts a local, fixed length MAC address.
  225. * compress_ipaddr() is simply the common logic that does not depend on
  226. * the size of the MAC address.
  227. *
  228. ****************************************************************************/
  229. static uint8_t compress_ipaddr(FAR const net_ipv6addr_t ipaddr, uint8_t bitpos)
  230. {
  231. if (SIXLOWPAN_IS_IID_16BIT_COMPRESSABLE(ipaddr))
  232. {
  233. /* Compress IID to 16 bits: xxxx:xxxx:xxxx:xxxx:0000:00ff:fe00:XXXX */
  234. #ifdef CONFIG_ENDIAN_BIG
  235. *g_hc06ptr++ = ipaddr[7] >> 8; /* Preserve big-endian, network order */
  236. *g_hc06ptr++ = ipaddr[7] & 0xff;
  237. #else
  238. *g_hc06ptr++ = ipaddr[7] & 0xff; /* Preserve big-endian, network order */
  239. *g_hc06ptr++ = ipaddr[7] >> 8;
  240. #endif
  241. return 2 << bitpos; /* 16-bits */
  242. }
  243. else
  244. {
  245. int i;
  246. /* Do not compress IID: xxxx:xxxx:xxxx:xxxx:IID:IID:IID:IID */
  247. for (i = 4; i < 8; i++)
  248. {
  249. #ifdef CONFIG_ENDIAN_BIG
  250. *g_hc06ptr++ = ipaddr[i] >> 8; /* Preserve big-endian, network order */
  251. *g_hc06ptr++ = ipaddr[i] & 0xff;
  252. #else
  253. *g_hc06ptr++ = ipaddr[i] & 0xff; /* Preserve big-endian, network order */
  254. *g_hc06ptr++ = ipaddr[i] >> 8;
  255. #endif
  256. }
  257. return 1 << bitpos; /* 64-bits */
  258. }
  259. }
  260. static uint8_t compress_tagaddr(FAR const net_ipv6addr_t ipaddr,
  261. FAR const struct netdev_varaddr_s *macaddr,
  262. uint8_t bitpos)
  263. {
  264. uint8_t tag;
  265. #ifdef CONFIG_DEBUG_NET_INFO
  266. ninfo("Compressing bitpos=%u addrlen=%u\n", bitpos, macaddr->nv_addrlen);
  267. ninfo(" ipaddr=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
  268. ntohs(ipaddr[0]), ntohs(ipaddr[1]), ntohs(ipaddr[2]), ntohs(ipaddr[3]),
  269. ntohs(ipaddr[4]), ntohs(ipaddr[5]), ntohs(ipaddr[6]), ntohs(ipaddr[7]));
  270. switch (macaddr->nv_addrlen)
  271. {
  272. case 1:
  273. ninfo(" addr=%02x\n", macaddr->nv_addr[0]);
  274. break;
  275. case 2:
  276. ninfo(" saddr=%02x:%02x\n",
  277. macaddr->nv_addr[0], macaddr->nv_addr[1]);
  278. break;
  279. case 8:
  280. ninfo(" eaddr=%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
  281. macaddr->nv_addr[0], macaddr->nv_addr[1],
  282. macaddr->nv_addr[2], macaddr->nv_addr[3],
  283. macaddr->nv_addr[4], macaddr->nv_addr[5],
  284. macaddr->nv_addr[6], macaddr->nv_addr[7]);
  285. break;
  286. default:
  287. nerr("ERROR: Unsupported addrlen %u\n", macaddr->nv_addrlen);
  288. break;
  289. }
  290. #endif
  291. if (sixlowpan_ismacbased(ipaddr, macaddr))
  292. {
  293. tag = (3 << bitpos); /* 0-bits */
  294. }
  295. else
  296. {
  297. tag = compress_ipaddr(ipaddr, bitpos);
  298. }
  299. ninfo("Tag=%02x\n", tag);
  300. return tag;
  301. }
  302. static uint8_t compress_laddr(FAR const net_ipv6addr_t srcipaddr,
  303. FAR const struct netdev_varaddr_s *macaddr,
  304. uint8_t bitpos)
  305. {
  306. uint8_t tag;
  307. #ifdef CONFIG_DEBUG_NET_INFO
  308. ninfo("Compressing bitpos=%u\n", bitpos);
  309. ninfo(" srcipaddr=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
  310. ntohs(srcipaddr[0]), ntohs(srcipaddr[1]), ntohs(srcipaddr[2]),
  311. ntohs(srcipaddr[3]), ntohs(srcipaddr[4]), ntohs(srcipaddr[5]),
  312. ntohs(srcipaddr[6]), ntohs(srcipaddr[7]));
  313. switch (macaddr->nv_addrlen)
  314. {
  315. case 1:
  316. ninfo(" addr=%02x\n", macaddr->nv_addr[0]);
  317. break;
  318. case 2:
  319. ninfo(" saddr=%02x:%02x\n",
  320. macaddr->nv_addr[0], macaddr->nv_addr[1]);
  321. break;
  322. case 8:
  323. ninfo(" eaddr=%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
  324. macaddr->nv_addr[0], macaddr->nv_addr[1], macaddr->nv_addr[2],
  325. macaddr->nv_addr[3], macaddr->nv_addr[4], macaddr->nv_addr[5],
  326. macaddr->nv_addr[6], macaddr->nv_addr[7]);
  327. break;
  328. default:
  329. ninfo(" Unsupported addrlen %u\n", macaddr->nv_addrlen);
  330. }
  331. #endif
  332. if (sixlowpan_ismacbased(srcipaddr, macaddr))
  333. {
  334. tag = (3 << bitpos); /* 0-bits */
  335. }
  336. else
  337. {
  338. tag = compress_ipaddr(srcipaddr, bitpos);
  339. }
  340. ninfo("Tag=%02x\n", tag);
  341. return tag;
  342. }
  343. /****************************************************************************
  344. * Name: uncompress_addr
  345. *
  346. * Description:
  347. * Uncompress addresses based on a prefix and a postfix with zeroes in
  348. * between. If the postfix is zero in length it will use the link address
  349. * to configure the IP address (autoconf style).
  350. *
  351. * prefpost takes a byte where the first nibble specify prefix count
  352. * and the second postfix count (NOTE: 15/0xf ipaddr=16 bytes copy).
  353. *
  354. ****************************************************************************/
  355. static void uncompress_addr(FAR const struct netdev_varaddr_s *addr,
  356. FAR const uint8_t *prefix, uint16_t prefpost,
  357. FAR net_ipv6addr_t ipaddr)
  358. {
  359. FAR const uint8_t *srcptr;
  360. bool usemac = (prefpost & UNCOMPRESS_MACBASED) != 0;
  361. uint8_t prefcount = UNCOMPRESS_PREFLEN(prefpost);
  362. uint8_t postcount = UNCOMPRESS_POSTLEN(prefpost);
  363. int destndx;
  364. int i;
  365. /* The value 16 is encoded as 0xf in the 4 bit-fields. */
  366. prefcount = prefcount == 15 ? 16 : prefcount;
  367. postcount = postcount == 15 ? 16 : postcount;
  368. /* Select the data source */
  369. srcptr = g_hc06ptr;
  370. if (usemac)
  371. {
  372. /* Select the source the address data */
  373. srcptr = addr->nv_addr;
  374. /* If the provided postcount is zero and we are taking data from the
  375. * MAC address, set postcount to the full address length.
  376. */
  377. if (postcount == 0)
  378. {
  379. postcount = addr->nv_addrlen;
  380. }
  381. }
  382. /* Copy any prefix */
  383. if (prefcount > 0)
  384. {
  385. memcpy(ipaddr, prefix, prefcount);
  386. }
  387. /* Clear bytes between int prefcount and postcount */
  388. if (prefcount + postcount < 16)
  389. {
  390. FAR uint8_t *destptr = (FAR uint8_t *)&ipaddr[0];
  391. memset(&destptr[prefcount], 0, 16 - (prefcount + postcount));
  392. }
  393. /* Copy the remaining data from the source */
  394. if (postcount > 0)
  395. {
  396. /* If there is space for the ...:00ff:fe00:... and if we were not
  397. * asked t specifically zero pad the address, then add these magic
  398. * bits to the decoded address.
  399. */
  400. if (postcount <= 2 && prefcount < 11 &&
  401. (prefpost & UNCOMPRESS_ZEROPAD) == 0)
  402. {
  403. /* 16 bit uncompression ipaddr=0000:00ff:fe00:xxxx */
  404. ipaddr[5] = HTONS(0x00ff);
  405. ipaddr[6] = HTONS(0xfe00);
  406. }
  407. /* Handle the even bytes in the address */
  408. /* If the postcount is even then take extra care with endian-ness */
  409. destndx = 8 - (postcount >> 1);
  410. /* Handle any odd byte first */
  411. if ((postcount & 1) != 0)
  412. {
  413. #ifdef CONFIG_ENDIAN_BIG
  414. /* Preserve big-endian, network order */
  415. ipaddr[destndx - 1] = (uint16_t)(*srcptr) << 8;
  416. #else
  417. /* Preserve big-endian, network order */
  418. ipaddr[destndx - 1] = (uint16_t)(*srcptr);
  419. #endif
  420. srcptr++;
  421. }
  422. for (i = destndx; i < 8; i++)
  423. {
  424. #ifdef CONFIG_ENDIAN_BIG
  425. /* Preserve big-endian, network order */
  426. ipaddr[i] = (uint16_t)srcptr[0] << 8 | (uint16_t)srcptr[1];
  427. #else
  428. /* Preserve big-endian, network order */
  429. ipaddr[i] = (uint16_t)srcptr[1] << 8 | (uint16_t)srcptr[0];
  430. #endif
  431. srcptr += 2;
  432. }
  433. /* If the IP is dervied from a MAC address big enough to include the U/L bit,
  434. * invert it.
  435. */
  436. if (usemac && postcount == 8)
  437. {
  438. ipaddr[4] ^= HTONS(0x0200);
  439. }
  440. /* If we took the data from packet, then update the packet pointer */
  441. if (!usemac)
  442. {
  443. g_hc06ptr += postcount;
  444. }
  445. }
  446. else if (prefcount > 0)
  447. {
  448. /* No IID based configuration if no prefix and no data ipaddr=unspec */
  449. nwarn("WARNING: No IID based configuration\n");
  450. }
  451. ninfo("Uncompressing %d + %d ipaddr=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
  452. prefcount, postcount,
  453. ntohs(ipaddr[0]), ntohs(ipaddr[1]), ntohs(ipaddr[2]), ntohs(ipaddr[3]),
  454. ntohs(ipaddr[4]), ntohs(ipaddr[5]), ntohs(ipaddr[6]), ntohs(ipaddr[7]));
  455. }
  456. /****************************************************************************
  457. * Public Functions
  458. ****************************************************************************/
  459. /****************************************************************************
  460. * Name: sixlowpan_hc06_initialize
  461. *
  462. * Description:
  463. * sixlowpan_hc06_initialize() is called during OS initialization at power-up
  464. * reset. It is called from the common sixlowpan_initialize() function.
  465. * sixlowpan_hc06_initialize() configures HC06 networking data structures.
  466. * It is called prior to platform-specific driver initialization so that
  467. * the 6LoWPAN networking subsystem is prepared to deal with network
  468. * driver initialization actions.
  469. *
  470. * Input Parameters:
  471. * None
  472. *
  473. * Returned Value:
  474. * None
  475. *
  476. ****************************************************************************/
  477. void sixlowpan_hc06_initialize(void)
  478. {
  479. #if CONFIG_NET_6LOWPAN_MAXADDRCONTEXT > 0
  480. #if CONFIG_NET_6LOWPAN_MAXADDRCONTEXT > 1
  481. int i;
  482. #endif
  483. /* Preinitialize any address contexts for better header compression
  484. * (Saves up to 13 bytes per 6lowpan packet).
  485. */
  486. g_hc06_addrcontexts[0].used = 1;
  487. g_hc06_addrcontexts[0].number = 0;
  488. g_hc06_addrcontexts[0].prefix[0] = CONFIG_NET_6LOWPAN_MAXADDRCONTEXT_PREFIX_0_0;
  489. g_hc06_addrcontexts[0].prefix[1] = CONFIG_NET_6LOWPAN_MAXADDRCONTEXT_PREFIX_0_1;
  490. g_hc06_addrcontexts[0].prefix[2] = CONFIG_NET_6LOWPAN_MAXADDRCONTEXT_PREFIX_0_2;
  491. g_hc06_addrcontexts[0].prefix[3] = CONFIG_NET_6LOWPAN_MAXADDRCONTEXT_PREFIX_0_3;
  492. g_hc06_addrcontexts[0].prefix[4] = CONFIG_NET_6LOWPAN_MAXADDRCONTEXT_PREFIX_0_4;
  493. g_hc06_addrcontexts[0].prefix[5] = CONFIG_NET_6LOWPAN_MAXADDRCONTEXT_PREFIX_0_5;
  494. g_hc06_addrcontexts[0].prefix[6] = CONFIG_NET_6LOWPAN_MAXADDRCONTEXT_PREFIX_0_6;
  495. g_hc06_addrcontexts[0].prefix[7] = CONFIG_NET_6LOWPAN_MAXADDRCONTEXT_PREFIX_0_7;
  496. #if CONFIG_NET_6LOWPAN_MAXADDRCONTEXT > 1
  497. for (i = 1; i < CONFIG_NET_6LOWPAN_MAXADDRCONTEXT; i++)
  498. {
  499. #ifdef CONFIG_NET_6LOWPAN_MAXADDRCONTEXT_PREINIT_1
  500. if (i == 1)
  501. {
  502. g_hc06_addrcontexts[1].used = 1;
  503. g_hc06_addrcontexts[1].number = 1;
  504. g_hc06_addrcontexts[1].prefix[0] = CONFIG_NET_6LOWPAN_MAXADDRCONTEXT_PREFIX_1_0;
  505. g_hc06_addrcontexts[1].prefix[1] = CONFIG_NET_6LOWPAN_MAXADDRCONTEXT_PREFIX_1_1;
  506. g_hc06_addrcontexts[1].prefix[2] = CONFIG_NET_6LOWPAN_MAXADDRCONTEXT_PREFIX_1_2;
  507. g_hc06_addrcontexts[1].prefix[3] = CONFIG_NET_6LOWPAN_MAXADDRCONTEXT_PREFIX_1_3;
  508. g_hc06_addrcontexts[1].prefix[4] = CONFIG_NET_6LOWPAN_MAXADDRCONTEXT_PREFIX_1_4;
  509. g_hc06_addrcontexts[1].prefix[5] = CONFIG_NET_6LOWPAN_MAXADDRCONTEXT_PREFIX_1_5;
  510. g_hc06_addrcontexts[1].prefix[6] = CONFIG_NET_6LOWPAN_MAXADDRCONTEXT_PREFIX_1_6;
  511. g_hc06_addrcontexts[1].prefix[7] = CONFIG_NET_6LOWPAN_MAXADDRCONTEXT_PREFIX_1_7;
  512. }
  513. else
  514. #ifdef CONFIG_NET_6LOWPAN_MAXADDRCONTEXT_PREINIT_2
  515. if (i == 2)
  516. {
  517. g_hc06_addrcontexts[2].used = 1;
  518. g_hc06_addrcontexts[2].number = 2;
  519. g_hc06_addrcontexts[2].prefix[0] = CONFIG_NET_6LOWPAN_MAXADDRCONTEXT_PREFIX_2_0;
  520. g_hc06_addrcontexts[2].prefix[1] = CONFIG_NET_6LOWPAN_MAXADDRCONTEXT_PREFIX_2_1;
  521. g_hc06_addrcontexts[2].prefix[2] = CONFIG_NET_6LOWPAN_MAXADDRCONTEXT_PREFIX_2_2;
  522. g_hc06_addrcontexts[2].prefix[3] = CONFIG_NET_6LOWPAN_MAXADDRCONTEXT_PREFIX_2_3;
  523. g_hc06_addrcontexts[2].prefix[4] = CONFIG_NET_6LOWPAN_MAXADDRCONTEXT_PREFIX_2_4;
  524. g_hc06_addrcontexts[2].prefix[5] = CONFIG_NET_6LOWPAN_MAXADDRCONTEXT_PREFIX_2_5;
  525. g_hc06_addrcontexts[2].prefix[6] = CONFIG_NET_6LOWPAN_MAXADDRCONTEXT_PREFIX_2_6;
  526. g_hc06_addrcontexts[2].prefix[7] = CONFIG_NET_6LOWPAN_MAXADDRCONTEXT_PREFIX_2_7;
  527. }
  528. else
  529. #endif /* SIXLOWPAN_CONF_ADDR_CONTEXT_2 */
  530. {
  531. g_hc06_addrcontexts[i].used = 0;
  532. }
  533. #else
  534. g_hc06_addrcontexts[i].used = 0;
  535. #endif /* SIXLOWPAN_CONF_ADDR_CONTEXT_1 */
  536. }
  537. #endif /* CONFIG_NET_6LOWPAN_MAXADDRCONTEXT > 1 */
  538. #endif /* CONFIG_NET_6LOWPAN_MAXADDRCONTEXT > 0 */
  539. }
  540. /****************************************************************************
  541. * Name: sixlowpan_compresshdr_hc06
  542. *
  543. * Description:
  544. * Compress IP/UDP header
  545. *
  546. * This function is called by the 6lowpan code to create a compressed
  547. * 6lowpan packet in the frame buffer from a full IPv6 packet.
  548. *
  549. * HC-06:
  550. *
  551. * Originally draft-ietf-6lowpan-hc, version 6:
  552. * http://tools.ietf.org/html/draft-ietf-6lowpan-hc-06,
  553. *
  554. * Updated to:
  555. *
  556. * RFC 6282:
  557. * https://tools.ietf.org/html/rfc6282
  558. *
  559. * NOTE: sixlowpan_compresshdr_hc06() does not support ISA100_UDP header
  560. * compression
  561. *
  562. * For LOWPAN_UDP compression, we either compress both ports or none.
  563. * General format with LOWPAN_UDP compression is
  564. * 1 2 3
  565. * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
  566. * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  567. * |0|1|1|TF |N|HLI|C|S|SAM|M|D|DAM| SCI | DCI | comp. IPv6 hdr|
  568. * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  569. * | compressed IPv6 fields ..... |
  570. * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  571. * | LOWPAN_UDP | non compressed UDP fields ... |
  572. * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  573. * | L4 data ... |
  574. * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  575. *
  576. * NOTE: The address context number 00 is reserved for the link local
  577. * prefix. For unicast addresses, if we cannot compress the prefix, we
  578. * neither compress the IID.
  579. *
  580. * Input Parameters:
  581. * radio - A reference to a radio network device instance
  582. * ipv6 - The IPv6 header to be compressed
  583. * destmac - L2 destination address, needed to compress the IP
  584. * destination field
  585. * fptr - Pointer to frame to be compressed.
  586. *
  587. * Returned Value:
  588. * On success the indications of the defines COMPRESS_HDR_* are returned.
  589. * A negated errno value is returned on failure.
  590. *
  591. ****************************************************************************/
  592. int sixlowpan_compresshdr_hc06(FAR struct radio_driver_s *radio,
  593. FAR const struct ipv6_hdr_s *ipv6,
  594. FAR const struct netdev_varaddr_s *destmac,
  595. FAR uint8_t *fptr)
  596. {
  597. FAR uint8_t *iphc = fptr + g_frame_hdrlen;
  598. FAR struct sixlowpan_addrcontext_s *saddrcontext;
  599. FAR struct sixlowpan_addrcontext_s *daddrcontext;
  600. uint8_t iphc0;
  601. uint8_t iphc1;
  602. uint8_t tmp;
  603. int ret = COMPRESS_HDR_INLINE;
  604. ninfo("fptr=%p g_frame_hdrlen=%u iphc=%p\n", fptr, g_frame_hdrlen, iphc);
  605. /* As we copy some bit-length fields, in the IPHC encoding bytes,
  606. * we sometimes use |=
  607. * If the field is 0, and the current bit value in memory is 1,
  608. * this does not work. We therefore reset the IPHC encoding here
  609. */
  610. iphc0 = SIXLOWPAN_DISPATCH_IPHC;
  611. iphc1 = 0;
  612. iphc[2] = 0; /* Might not be used - but needs to be cleared */
  613. /* Point to just after the two IPHC bytes we have committed to */
  614. g_hc06ptr = iphc + 2;
  615. /* Address handling needs to be made first since it might cause an extra
  616. * byte with [ SCI | DCI ]
  617. */
  618. /* Check if dest address context exists (for allocating third byte) */
  619. daddrcontext = find_addrcontext_byprefix(ipv6->destipaddr);
  620. saddrcontext = find_addrcontext_byprefix(ipv6->srcipaddr);
  621. if (daddrcontext != NULL || saddrcontext != NULL)
  622. {
  623. /* set address context flag and increase g_hc06ptr */
  624. ninfo("Compressing dest or src ipaddr. Setting CID\n");
  625. iphc1 |= SIXLOWPAN_IPHC_CID;
  626. g_hc06ptr++;
  627. }
  628. /* Traffic class, flow label
  629. *
  630. * If flow label is 0, compress it. If traffic class is 0, compress it
  631. * We have to process both in the same time as the offset of traffic class
  632. * depends on the presence of version and flow label
  633. */
  634. /* hc06 format of tc is ECN | DSCP , original is DSCP | ECN */
  635. tmp = (ipv6->vtc << 4) | (ipv6->tcf >> 4);
  636. tmp = ((tmp & 0x03) << 6) | (tmp >> 2);
  637. if (((ipv6->tcf & 0x0f) == 0) && (ipv6->flow == 0))
  638. {
  639. /* Flow label can be compressed */
  640. iphc0 |= SIXLOWPAN_IPHC_TC_10;
  641. if (((ipv6->vtc & 0x0f) == 0) && ((ipv6->tcf & 0xf0) == 0))
  642. {
  643. /* Compress (elide) all */
  644. iphc0 |= SIXLOWPAN_IPHC_TC_01;
  645. }
  646. else
  647. {
  648. /* Compress only the flow label */
  649. *g_hc06ptr = tmp;
  650. g_hc06ptr += 1;
  651. }
  652. }
  653. else
  654. {
  655. /* Flow label cannot be compressed */
  656. if (((ipv6->vtc & 0x0f) == 0) && ((ipv6->tcf & 0xf0) == 0))
  657. {
  658. /* Compress only traffic class */
  659. iphc0 |= SIXLOWPAN_IPHC_TC_01;
  660. *g_hc06ptr = (tmp & 0xc0) | (ipv6->tcf & 0x0f);
  661. memcpy(g_hc06ptr + 1, &ipv6->flow, 2);
  662. g_hc06ptr += 3;
  663. }
  664. else
  665. {
  666. /* Compress nothing */
  667. memcpy(g_hc06ptr, &ipv6->vtc, 4);
  668. /* But replace the top byte with the new ECN | DSCP format */
  669. *g_hc06ptr = tmp;
  670. g_hc06ptr += 4;
  671. }
  672. }
  673. /* Note that the payload length is always compressed */
  674. /* Next header. We compress it if UDP */
  675. #ifdef CONFIG_NET_UDP
  676. if (ipv6->proto == IP_PROTO_UDP)
  677. {
  678. iphc0 |= SIXLOWPAN_IPHC_NH;
  679. }
  680. #endif /* CONFIG_NET_UDP */
  681. if ((iphc0 & SIXLOWPAN_IPHC_NH) == 0)
  682. {
  683. *g_hc06ptr = ipv6->proto;
  684. g_hc06ptr += 1;
  685. }
  686. /* Hop limit
  687. *
  688. * if 1: compress, encoding is 01
  689. * if 64: compress, encoding is 10
  690. * if 255: compress, encoding is 11
  691. * else do not compress
  692. */
  693. switch (ipv6->ttl)
  694. {
  695. case 1:
  696. iphc0 |= SIXLOWPAN_IPHC_HLIM_1;
  697. break;
  698. case 64:
  699. iphc0 |= SIXLOWPAN_IPHC_HLIM_64;
  700. break;
  701. case 255:
  702. iphc0 |= SIXLOWPAN_IPHC_HLIM_255;
  703. break;
  704. default:
  705. *g_hc06ptr = ipv6->ttl;
  706. g_hc06ptr += 1;
  707. break;
  708. }
  709. /* Source address - cannot be multicast */
  710. if (net_is_addr_unspecified(ipv6->srcipaddr))
  711. {
  712. ninfo("Compressing unspecified srcipaddr. Setting SAC\n");
  713. iphc1 |= SIXLOWPAN_IPHC_SAC;
  714. iphc1 |= SIXLOWPAN_IPHC_SAM_128;
  715. }
  716. else if (saddrcontext != NULL)
  717. {
  718. /* Elide the prefix - indicate by CID and set address context + SAC */
  719. ninfo("Compressing src with address context. Setting SAC. Context: %d\n",
  720. saddrcontext->number);
  721. iphc1 |= SIXLOWPAN_IPHC_SAC;
  722. iphc[2] |= saddrcontext->number << 4;
  723. /* Compression compare with this nodes address (source) */
  724. iphc1 |= compress_laddr(ipv6->srcipaddr,
  725. &radio->r_dev.d_mac.radio,
  726. SIXLOWPAN_IPHC_SAM_BIT);
  727. }
  728. /* No address context found for the source address */
  729. else if (net_is_addr_linklocal(ipv6->srcipaddr) &&
  730. ipv6->srcipaddr[1] == 0 && ipv6->srcipaddr[2] == 0 &&
  731. ipv6->srcipaddr[3] == 0)
  732. {
  733. iphc1 |= compress_laddr(ipv6->srcipaddr,
  734. &radio->r_dev.d_mac.radio,
  735. SIXLOWPAN_IPHC_SAM_BIT);
  736. }
  737. else
  738. {
  739. /* Send the full source address ipaddr: SAC = 0, SAM = 00 */
  740. ninfo("Uncompressable srcipaddr=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
  741. ntohs(ipv6->srcipaddr[0]), ntohs(ipv6->srcipaddr[1]),
  742. ntohs(ipv6->srcipaddr[2]), ntohs(ipv6->srcipaddr[3]),
  743. ntohs(ipv6->srcipaddr[4]), ntohs(ipv6->srcipaddr[5]),
  744. ntohs(ipv6->srcipaddr[6]), ntohs(ipv6->srcipaddr[7]));
  745. iphc1 |= SIXLOWPAN_IPHC_SAM_128; /* 128-bits */
  746. memcpy(g_hc06ptr, ipv6->srcipaddr, 16);
  747. g_hc06ptr += 16;
  748. }
  749. /* Destination address */
  750. if (net_is_addr_mcast(ipv6->destipaddr))
  751. {
  752. /* Address is multicast, try to compress */
  753. iphc1 |= SIXLOWPAN_IPHC_M;
  754. if (SIXLOWPAN_IS_MCASTADDR_COMPRESSABLE8(ipv6->destipaddr))
  755. {
  756. iphc1 |= SIXLOWPAN_IPHC_MDAM_8;
  757. /* Use "last" byte ("last" meaning the LS byte in host order.
  758. * destipaddr is in big-endian network order).
  759. */
  760. #ifdef CONFIG_ENDIAN_BIG
  761. *g_hc06ptr = (ipv6->destipaddr[7] & 0xff);
  762. #else
  763. *g_hc06ptr = (ipv6->destipaddr[7] >> 8);
  764. #endif
  765. g_hc06ptr += 1;
  766. }
  767. else if (SIXLOWPAN_IS_MCASTADDR_COMPRESSABLE32(ipv6->destipaddr))
  768. {
  769. FAR uint8_t *iptr = (FAR uint8_t *)ipv6->destipaddr;
  770. iphc1 |= SIXLOWPAN_IPHC_MDAM_32;
  771. /* Second byte + the last three */
  772. *g_hc06ptr = iptr[1];
  773. memcpy(g_hc06ptr + 1, &iptr[13], 3);
  774. g_hc06ptr += 4;
  775. }
  776. else if (SIXLOWPAN_IS_MCASTADDR_COMPRESSABLE48(ipv6->destipaddr))
  777. {
  778. FAR uint8_t *iptr = (FAR uint8_t *)ipv6->destipaddr;
  779. iphc1 |= SIXLOWPAN_IPHC_MDAM_48;
  780. /* Second byte + the last five */
  781. *g_hc06ptr = iptr[1];
  782. memcpy(g_hc06ptr + 1, &iptr[11], 5);
  783. g_hc06ptr += 6;
  784. }
  785. else
  786. {
  787. iphc1 |= SIXLOWPAN_IPHC_MDAM_128;
  788. /* Full address */
  789. memcpy(g_hc06ptr, ipv6->destipaddr, 16);
  790. g_hc06ptr += 16;
  791. }
  792. }
  793. else
  794. {
  795. /* Address is unicast, try to compress */
  796. if (daddrcontext != NULL)
  797. {
  798. /* Elide the prefix */
  799. ninfo("Compressing dest with address context. Setting DAC. Context: %d\n",
  800. daddrcontext->number);
  801. iphc1 |= SIXLOWPAN_IPHC_DAC;
  802. iphc[2] |= daddrcontext->number;
  803. /* Compession compare with link adress (destination) */
  804. iphc1 |= compress_tagaddr(ipv6->destipaddr, destmac,
  805. SIXLOWPAN_IPHC_DAM_BIT);
  806. }
  807. /* No address context found for this address */
  808. else if (net_is_addr_linklocal(ipv6->destipaddr) &&
  809. ipv6->destipaddr[1] == 0 && ipv6->destipaddr[2] == 0 &&
  810. ipv6->destipaddr[3] == 0)
  811. {
  812. iphc1 |= compress_tagaddr(ipv6->destipaddr, destmac,
  813. SIXLOWPAN_IPHC_DAM_BIT);
  814. }
  815. /* Send the full address */
  816. else
  817. {
  818. iphc1 |= SIXLOWPAN_IPHC_DAM_128; /* 128-bits */
  819. memcpy(g_hc06ptr, ipv6->destipaddr, 16);
  820. g_hc06ptr += 16;
  821. }
  822. }
  823. g_uncomp_hdrlen = IPv6_HDRLEN;
  824. #ifdef CONFIG_NET_UDP
  825. /* UDP header compression */
  826. if (ipv6->proto == IP_PROTO_UDP)
  827. {
  828. /* The UDP header will follow the IPv6 header */
  829. FAR struct udp_hdr_s *udp =
  830. (FAR struct udp_hdr_s *)((FAR uint8_t *)ipv6 + IPv6_HDRLEN);
  831. ninfo("Uncompressed UDP ports: srcport=%04x destport=%04x\n",
  832. ntohs(udp->srcport), ntohs(udp->destport));
  833. /* Mask out the last 4 bits can be used as a mask */
  834. if (((ntohs(udp->srcport) & 0xfff0) == SIXLOWPAN_UDP_4_BIT_PORT_MIN) &&
  835. ((ntohs(udp->destport) & 0xfff0) == SIXLOWPAN_UDP_4_BIT_PORT_MIN))
  836. {
  837. /* We can compress 12 bits of both source and dest */
  838. *g_hc06ptr = SIXLOWPAN_NHC_UDP_CS_P_11;
  839. ninfo("Remove 12b of both source & dest with prefix 0xf0b*\n");
  840. *(g_hc06ptr + 1) =
  841. (uint8_t)((ntohs(udp->srcport) - SIXLOWPAN_UDP_4_BIT_PORT_MIN) << 4) +
  842. (uint8_t)((ntohs(udp->destport) - SIXLOWPAN_UDP_4_BIT_PORT_MIN));
  843. g_hc06ptr += 2;
  844. }
  845. else if ((ntohs(udp->destport) & 0xff00) ==
  846. SIXLOWPAN_UDP_8_BIT_PORT_MIN)
  847. {
  848. /* We can compress 8 bits of dest, leave source. */
  849. *g_hc06ptr = SIXLOWPAN_NHC_UDP_CS_P_01;
  850. ninfo("Leave source, remove 8 bits of dest with prefix 0xF0\n");
  851. memcpy(g_hc06ptr + 1, &udp->srcport, 2);
  852. *(g_hc06ptr + 3) =
  853. (uint8_t) ((ntohs(udp->destport) -
  854. SIXLOWPAN_UDP_8_BIT_PORT_MIN));
  855. g_hc06ptr += 4;
  856. }
  857. else if ((ntohs(udp->srcport) & 0xff00) ==
  858. SIXLOWPAN_UDP_8_BIT_PORT_MIN)
  859. {
  860. /* We can compress 8 bits of src, leave dest. Copy compressed port */
  861. *g_hc06ptr = SIXLOWPAN_NHC_UDP_CS_P_10;
  862. ninfo("Remove 8 bits of source with prefix 0xF0, leave dest. hch: %u\n",
  863. *g_hc06ptr);
  864. *(g_hc06ptr + 1) =
  865. (uint8_t)((ntohs(udp->srcport) - SIXLOWPAN_UDP_8_BIT_PORT_MIN));
  866. memcpy(g_hc06ptr + 2, &udp->destport, 2);
  867. g_hc06ptr += 4;
  868. }
  869. else
  870. {
  871. /* we cannot compress. Copy uncompressed ports, full checksum */
  872. *g_hc06ptr = SIXLOWPAN_NHC_UDP_CS_P_00;
  873. nwarn("WARNING: Cannot compress headers\n");
  874. memcpy(g_hc06ptr + 1, &udp->srcport, 4);
  875. g_hc06ptr += 5;
  876. }
  877. /* Always inline the checksum */
  878. memcpy(g_hc06ptr, &udp->udpchksum, 2);
  879. g_hc06ptr += 2;
  880. g_uncomp_hdrlen += UDP_HDRLEN;
  881. ret = COMPRESS_HDR_ELIDED;
  882. }
  883. #endif /* CONFIG_NET_UDP */
  884. /* Before the g_frame_hdrlen operation */
  885. iphc[0] = iphc0;
  886. iphc[1] = iphc1;
  887. g_frame_hdrlen = g_hc06ptr - fptr;
  888. ninfo("fptr=%p g_frame_hdrlen=%u iphc=%02x:%02x:%02x g_hc06ptr=%p\n",
  889. fptr, g_frame_hdrlen, iphc[0], iphc[1], iphc[2], g_hc06ptr);
  890. return ret;
  891. }
  892. /****************************************************************************
  893. * Name: sixlowpan_uncompresshdr_hc06
  894. *
  895. * Description:
  896. * Uncompress HC06 (i.e., IPHC and LOWPAN_UDP) headers and put them in
  897. * sixlowpan_buf
  898. *
  899. * This function is called by the input function when the dispatch is HC06.
  900. * We process the frame in the IOB buffer, uncompress the header fields,
  901. * and copy the result into the driver packet buffer. At the end of the
  902. * decompression, g_frame_hdrlen and g_uncompressed_hdrlen are set to the
  903. * appropriate values
  904. *
  905. * Input Parameters:
  906. * radio - Reference to a radio network driver state instance.
  907. * metadata - Obfuscated MAC metadata including node addressing
  908. * information.
  909. * iplen - Equal to 0 if the packet is not a fragment (IP length is
  910. * then inferred from the L2 length), non 0 if the packet is
  911. * a first fragment.
  912. * iob - Pointer to the IOB containing the received frame.
  913. * fptr - Pointer to frame to be compressed.
  914. * bptr - Output goes here. Normally this is a known offset into
  915. * d_buf, may be redirected to a "bitbucket" on the case of
  916. * FRAGN frames.
  917. *
  918. * Returned Value:
  919. * None
  920. *
  921. ****************************************************************************/
  922. void sixlowpan_uncompresshdr_hc06(FAR struct radio_driver_s *radio,
  923. FAR const void *metadata,
  924. uint16_t iplen, FAR struct iob_s *iob,
  925. FAR uint8_t *fptr, FAR uint8_t *bptr)
  926. {
  927. FAR struct ipv6_hdr_s *ipv6 = (FAR struct ipv6_hdr_s *)bptr;
  928. struct netdev_varaddr_s addr;
  929. FAR uint8_t *iphc;
  930. uint8_t iphc0;
  931. uint8_t iphc1;
  932. uint8_t tmp;
  933. int ret;
  934. /* iphc points to IPHC. At least two byte will be used for the encoding. */
  935. iphc = fptr + g_frame_hdrlen;
  936. iphc0 = iphc[0];
  937. iphc1 = iphc[1];
  938. /* g_hc96ptr points to just after the 2-byte minimum IPHC */
  939. g_hc06ptr = iphc + 2;
  940. ninfo("fptr=%p g_frame_hdrlen=%u iphc=%02x:%02x:%02x g_hc06ptr=%p\n",
  941. fptr, g_frame_hdrlen, iphc[0], iphc[1], iphc[2], g_hc06ptr);
  942. /* Another if the CID flag is set */
  943. if ((iphc1 & SIXLOWPAN_IPHC_CID) != 0)
  944. {
  945. ninfo("CID flag set. Increase header by one\n");
  946. g_hc06ptr++;
  947. }
  948. /* Traffic class and flow label */
  949. if ((iphc0 & SIXLOWPAN_IPHC_TC_10) == 0)
  950. {
  951. /* Flow label are carried inline */
  952. if ((iphc0 & SIXLOWPAN_IPHC_TC_01) == 0)
  953. {
  954. /* Traffic class is carried inline */
  955. memcpy(&ipv6->tcf, g_hc06ptr + 1, 3);
  956. tmp = *g_hc06ptr;
  957. g_hc06ptr += 4;
  958. /* hc06 format of tc is ECN | DSCP , original is DSCP | ECN */
  959. /* set version, pick highest DSCP bits and set in vtc */
  960. ipv6->vtc = 0x60 | ((tmp >> 2) & 0x0f);
  961. /* ECN rolled down two steps + lowest DSCP bits at top two bits */
  962. ipv6->tcf = ((tmp >> 2) & 0x30) | (tmp << 6) | (ipv6->tcf & 0x0f);
  963. }
  964. else
  965. {
  966. /* Traffic class is compressed (set version and no TC) */
  967. ipv6->vtc = 0x60;
  968. /* Highest flow label bits + ECN bits */
  969. ipv6->tcf = (*g_hc06ptr & 0x0f) | ((*g_hc06ptr >> 2) & 0x30);
  970. memcpy(&ipv6->flow, g_hc06ptr + 1, 2);
  971. g_hc06ptr += 3;
  972. }
  973. }
  974. else
  975. {
  976. /* Version is always 6! */
  977. /* Version and flow label are compressed */
  978. if ((iphc0 & SIXLOWPAN_IPHC_TC_01) == 0)
  979. {
  980. /* Traffic class is inline */
  981. ipv6->vtc = 0x60 | ((*g_hc06ptr >> 2) & 0x0f);
  982. ipv6->tcf = ((*g_hc06ptr << 6) & 0xC0) | ((*g_hc06ptr >> 2) & 0x30);
  983. ipv6->flow = 0;
  984. g_hc06ptr += 1;
  985. }
  986. else
  987. {
  988. /* Traffic class is compressed */
  989. ipv6->vtc = 0x60;
  990. ipv6->tcf = 0;
  991. ipv6->flow = 0;
  992. }
  993. }
  994. /* Next Header */
  995. if ((iphc0 & SIXLOWPAN_IPHC_NH) == 0)
  996. {
  997. /* Next header is carried inline */
  998. ipv6->proto = *g_hc06ptr;
  999. ninfo("Next header inline: %d\n", ipv6->proto);
  1000. g_hc06ptr += 1;
  1001. }
  1002. /* Hop limit */
  1003. if ((iphc0 & SIXLOWPAN_IPHC_HLIM_MASK) != SIXLOWPAN_IPHC_HLIM_INLINE)
  1004. {
  1005. ipv6->ttl = g_ttl_values[iphc0 & SIXLOWPAN_IPHC_HLIM_MASK];
  1006. }
  1007. else
  1008. {
  1009. ipv6->ttl = *g_hc06ptr;
  1010. g_hc06ptr += 1;
  1011. }
  1012. /* Put the source address compression mode SAM in the tmp var */
  1013. tmp = ((iphc1 & SIXLOWPAN_IPHC_SAM_MASK) >> SIXLOWPAN_IPHC_SAM_BIT) & 0x03;
  1014. /* Address context based compression */
  1015. ret = sixlowpan_extract_srcaddr(radio, metadata, &addr);
  1016. if (ret < 0)
  1017. {
  1018. nerr("ERROR: sixlowpan_extract_srcaddr failed: %d\n", ret);
  1019. return;
  1020. }
  1021. if ((iphc1 & SIXLOWPAN_IPHC_SAC) != 0)
  1022. {
  1023. FAR struct sixlowpan_addrcontext_s *addrcontext;
  1024. uint8_t sci = (iphc1 & SIXLOWPAN_IPHC_CID) ? iphc[2] >> 4 : 0;
  1025. /* Source address - check address context != NULL only if SAM bits are != 0 */
  1026. if (tmp != 0)
  1027. {
  1028. addrcontext = find_addrcontext_bynumber(sci);
  1029. if (addrcontext == NULL)
  1030. {
  1031. nerr("ERROR: Address context not found\n");
  1032. return;
  1033. }
  1034. }
  1035. /* If tmp == 0 we do not have a address context and therefore no prefix */
  1036. /* REVISIT: Source address may not be the same size as the destination
  1037. * address.
  1038. */
  1039. uncompress_addr(&addr,
  1040. tmp != 0 ? addrcontext->prefix : NULL,
  1041. g_unc_ctxconf[tmp], ipv6->srcipaddr);
  1042. }
  1043. else
  1044. {
  1045. /* No compression and link local */
  1046. /* REVISIT: Source address may not be the same size as the destination
  1047. * address.
  1048. */
  1049. uncompress_addr(&addr, g_llprefix, g_unc_llconf[tmp],
  1050. ipv6->srcipaddr);
  1051. }
  1052. /* Destination address */
  1053. /* Put the destination address compression mode into tmp */
  1054. tmp = ((iphc1 & SIXLOWPAN_IPHC_DAM_MASK) >> SIXLOWPAN_IPHC_DAM_BIT) & 0x03;
  1055. /* Multicast compression */
  1056. ret = sixlowpan_extract_destaddr(radio, metadata, &addr);
  1057. if (ret < 0)
  1058. {
  1059. nerr("ERROR: sixlowpan_extract_srcaddr failed: %d\n", ret);
  1060. return;
  1061. }
  1062. if ((iphc1 & SIXLOWPAN_IPHC_M) != 0)
  1063. {
  1064. /* Address context based multicast compression */
  1065. if ((iphc1 & SIXLOWPAN_IPHC_DAC) != 0)
  1066. {
  1067. /* TODO: implement this */
  1068. }
  1069. else
  1070. {
  1071. /* Non-address context based multicast compression
  1072. *
  1073. * DAM 00: 128 bits
  1074. * DAM 01: 48 bits ffxx::00xx:xxxx:xxxx
  1075. * DAM 10: 32 bits ffxx::00xx:xxxx
  1076. * DAM 11: 8 bits ff02::00xx
  1077. */
  1078. uint8_t prefix[] = { 0xff, 0x02 };
  1079. if (tmp > 0 && tmp < 3)
  1080. {
  1081. prefix[1] = *g_hc06ptr;
  1082. g_hc06ptr++;
  1083. }
  1084. uncompress_addr(&addr, prefix, g_unc_mxconf[tmp],
  1085. ipv6->destipaddr);
  1086. }
  1087. }
  1088. else
  1089. {
  1090. /* No multicast */
  1091. /* Context based */
  1092. if ((iphc1 & SIXLOWPAN_IPHC_DAC) != 0)
  1093. {
  1094. FAR struct sixlowpan_addrcontext_s *addrcontext;
  1095. uint8_t dci = ((iphc1 & SIXLOWPAN_IPHC_CID) != 0) ? iphc[2] & 0x0f : 0;
  1096. addrcontext = find_addrcontext_bynumber(dci);
  1097. /* All valid cases below need the address context! */
  1098. if (addrcontext == NULL)
  1099. {
  1100. nerr("ERROR: Address context not found\n");
  1101. return;
  1102. }
  1103. uncompress_addr(&addr, addrcontext->prefix, g_unc_ctxconf[tmp],
  1104. ipv6->destipaddr);
  1105. }
  1106. else
  1107. {
  1108. /* Not address context based ipaddr=link local M = 0, DAC = 0 - same
  1109. * as SAC.
  1110. */
  1111. uncompress_addr(&addr, g_llprefix, g_unc_llconf[tmp],
  1112. ipv6->destipaddr);
  1113. }
  1114. }
  1115. g_uncomp_hdrlen += IPv6_HDRLEN;
  1116. /* Next header processing - continued */
  1117. if ((iphc0 & SIXLOWPAN_IPHC_NH) != 0)
  1118. {
  1119. FAR struct udp_hdr_s *udp = (FAR struct udp_hdr_s *)(bptr + IPv6_HDRLEN);
  1120. /* The next header is compressed, NHC is following */
  1121. if ((*g_hc06ptr & SIXLOWPAN_NHC_UDP_MASK) == SIXLOWPAN_NHC_UDP_ID)
  1122. {
  1123. uint8_t checksum_compressed;
  1124. ipv6->proto = IP_PROTO_UDP;
  1125. checksum_compressed = *g_hc06ptr & SIXLOWPAN_NHC_UDP_CHECKSUMC;
  1126. ninfo("Incoming header value: %i\n", *g_hc06ptr);
  1127. switch (*g_hc06ptr & SIXLOWPAN_NHC_UDP_CS_P_11)
  1128. {
  1129. case SIXLOWPAN_NHC_UDP_CS_P_00:
  1130. /* 1 byte for NHC, 4 byte for ports, 2 bytes chksum */
  1131. memcpy(&udp->srcport, g_hc06ptr + 1, 2);
  1132. memcpy(&udp->destport, g_hc06ptr + 3, 2);
  1133. ninfo("Uncompressed UDP ports (ptr+5): %x, %x\n",
  1134. htons(udp->srcport), htons(udp->destport));
  1135. g_hc06ptr += 5;
  1136. break;
  1137. case SIXLOWPAN_NHC_UDP_CS_P_01:
  1138. /* 1 byte for NHC + source 16bit inline, dest = 0xF0 + 8 bit
  1139. * inline
  1140. */
  1141. ninfo("Decompressing destination\n");
  1142. memcpy(&udp->srcport, g_hc06ptr + 1, 2);
  1143. udp->destport =
  1144. htons(SIXLOWPAN_UDP_8_BIT_PORT_MIN + (*(g_hc06ptr + 3)));
  1145. ninfo("Uncompressed UDP ports (ptr+4): %x, %x\n",
  1146. htons(udp->srcport), htons(udp->destport));
  1147. g_hc06ptr += 4;
  1148. break;
  1149. case SIXLOWPAN_NHC_UDP_CS_P_10:
  1150. /* 1 byte for NHC + source = 0xF0 + 8bit inline, dest = 16 bit
  1151. * inline
  1152. */
  1153. ninfo("Decompressing source\n");
  1154. udp->srcport =
  1155. htons(SIXLOWPAN_UDP_8_BIT_PORT_MIN + (*(g_hc06ptr + 1)));
  1156. memcpy(&udp->destport, g_hc06ptr + 2, 2);
  1157. ninfo("Uncompressed UDP ports (ptr+4): %x, %x\n",
  1158. htons(udp->srcport), htons(udp->destport));
  1159. g_hc06ptr += 4;
  1160. break;
  1161. case SIXLOWPAN_NHC_UDP_CS_P_11:
  1162. /* 1 byte for NHC, 1 byte for ports */
  1163. udp->srcport =
  1164. htons(SIXLOWPAN_UDP_4_BIT_PORT_MIN +
  1165. (*(g_hc06ptr + 1) >> 4));
  1166. udp->destport =
  1167. htons(SIXLOWPAN_UDP_4_BIT_PORT_MIN +
  1168. ((*(g_hc06ptr + 1)) & 0x0f));
  1169. ninfo("Uncompressed UDP ports (ptr+2): %x, %x\n",
  1170. htons(udp->srcport), htons(udp->destport));
  1171. g_hc06ptr += 2;
  1172. break;
  1173. default:
  1174. nerr("ERROR: Error unsupported UDP compression\n");
  1175. return;
  1176. }
  1177. if (!checksum_compressed)
  1178. {
  1179. /* Has_checksum, default */
  1180. memcpy(&udp->udpchksum, g_hc06ptr, 2);
  1181. g_hc06ptr += 2;
  1182. ninfo("Checksum included\n");
  1183. }
  1184. else
  1185. {
  1186. nwarn("WARNING: checksum *NOT* included\n");
  1187. }
  1188. g_uncomp_hdrlen += UDP_HDRLEN;
  1189. }
  1190. }
  1191. g_frame_hdrlen = g_hc06ptr - fptr;
  1192. /* IP length field. */
  1193. if (iplen == 0)
  1194. {
  1195. /* This is not a fragmented packet */
  1196. ipv6->len[0] = 0;
  1197. ipv6->len[1] = iob->io_len - g_frame_hdrlen + g_uncomp_hdrlen -
  1198. IPv6_HDRLEN;
  1199. }
  1200. else
  1201. {
  1202. /* This is a first fragment */
  1203. ipv6->len[0] = (iplen - IPv6_HDRLEN) >> 8;
  1204. ipv6->len[1] = (iplen - IPv6_HDRLEN) & 0x00ff;
  1205. }
  1206. /* Length field in UDP header */
  1207. if (ipv6->proto == IP_PROTO_UDP)
  1208. {
  1209. FAR struct udp_hdr_s *udp = (FAR struct udp_hdr_s *)(bptr + IPv6_HDRLEN);
  1210. memcpy(&udp->udplen, &ipv6->len[0], 2);
  1211. }
  1212. }
  1213. #endif /* CONFIG_NET_6LOWPAN_COMPRESSION_HC06 */