]> git.saurik.com Git - apple/xnu.git/blob - bsd/net/sixxlowpan.c
xnu-7195.50.7.100.1.tar.gz
[apple/xnu.git] / bsd / net / sixxlowpan.c
1 /*
2 * Copyright (c) 2017 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28 /*
29 * Copyright (c) 2008, Swedish Institute of Computer Science.
30 * All rights reserved.
31 *
32 * Redistribution and use in source and binary forms, with or without
33 * modification, are permitted provided that the following conditions
34 * are met:
35 * 1. Redistributions of source code must retain the above copyright
36 * notice, this list of conditions and the following disclaimer.
37 * 2. Redistributions in binary form must reproduce the above copyright
38 * notice, this list of conditions and the following disclaimer in the
39 * documentation and/or other materials provided with the distribution.
40 * 3. Neither the name of the Institute nor the names of its contributors
41 * may be used to endorse or promote products derived from this software
42 * without specific prior written permission.
43 *
44 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
45 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
46 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
47 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
48 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
49 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
50 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
51 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
52 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
53 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
54 * SUCH DAMAGE.
55 *
56 * This file is part of the Contiki operating system.
57 *
58 */
59
60 /**
61 * \file
62 * Header file for the 6lowpan implementation
63 * (RFC4944 and draft-hui-6lowpan-hc-01)
64 * \author Adam Dunkels <adam@sics.se>
65 * \author Nicolas Tsiftes <nvt@sics.se>
66 * \author Niclas Finne <nfi@sics.se>
67 * \author Mathilde Durvy <mdurvy@cisco.com>
68 * \author Julien Abeille <jabeille@cisco.com>
69 */
70
71
72 #include <sys/types.h>
73 #include <sys/queue.h>
74 #include <sys/domain.h>
75 #include <net/ethernet.h>
76 #include <netinet/ip.h>
77 #include <netinet/ip6.h>
78 #include <netinet/tcp.h>
79 #include <netinet/udp.h>
80 #include <netinet/icmp6.h>
81 #include <sys/errno.h>
82 #include <libkern/libkern.h>
83
84
85 #include <net/sixxlowpan.h>
86 #include <net/frame802154.h>
87
88 errno_t
89 compress_hdr_hc1(struct frame802154 *, u_int8_t *,
90 long *, size_t *, u_int8_t *);
91 errno_t
92 uncompress_hdr_hc1(struct frame802154 *, u_int8_t *,
93 uint16_t, long *, size_t *, u_int8_t *);
94
95
96
97 /**
98 * \addtogroup sicslowpan
99 * @{
100 */
101
102 /**
103 * \name General sicslowpan defines
104 * @{
105 */
106 /* Min and Max compressible UDP ports - HC06 */
107 #define SICSLOWPAN_UDP_PORT_MIN 0xF0B0
108 #define SICSLOWPAN_UDP_PORT_MAX 0xF0BF /* F0B0 + 15 */
109
110 /** @} */
111
112 /**
113 * \name 6lowpan compressions
114 * @{
115 */
116 #define SICSLOWPAN_COMPRESSION_IPV6 0
117 #define SICSLOWPAN_COMPRESSION_HC1 1
118 #define SICSLOWPAN_COMPRESSION_HC06 2
119 /** @} */
120
121 /**
122 * \name 6lowpan dispatches
123 * @{
124 */
125 #define SICSLOWPAN_DISPATCH_IPV6 0x41 /* 01000001 = 65 */
126 #define SICSLOWPAN_DISPATCH_HC1 0x42 /* 01000010 = 66 */
127 #define SICSLOWPAN_DISPATCH_IPHC 0x60 /* 011xxxxx = ... */
128 #define SICSLOWPAN_DISPATCH_FRAG1 0xc0 /* 11000xxx */
129 #define SICSLOWPAN_DISPATCH_FRAGN 0xe0 /* 11100xxx */
130 /** @} */
131
132 /** \name HC1 encoding
133 * @{
134 */
135 #define SICSLOWPAN_HC1_NH_UDP 0x02
136 #define SICSLOWPAN_HC1_NH_TCP 0x06
137 #define SICSLOWPAN_HC1_NH_ICMP6 0x04
138 /** @} */
139
140 /** \name HC_UDP encoding (works together with HC1)
141 * @{
142 */
143 #define SICSLOWPAN_HC_UDP_ALL_C 0xE0
144 /** @} */
145
146 /**
147 * \name IPHC encoding
148 * @{
149 */
150 /*
151 * Values of fields within the IPHC encoding first byte
152 * (C stands for compressed and I for inline)
153 */
154 #define SICSLOWPAN_IPHC_FL_C 0x10
155 #define SICSLOWPAN_IPHC_TC_C 0x08
156 #define SICSLOWPAN_IPHC_NH_C 0x04
157 #define SICSLOWPAN_IPHC_TTL_1 0x01
158 #define SICSLOWPAN_IPHC_TTL_64 0x02
159 #define SICSLOWPAN_IPHC_TTL_255 0x03
160 #define SICSLOWPAN_IPHC_TTL_I 0x00
161
162
163 /* Values of fields within the IPHC encoding second byte */
164 #define SICSLOWPAN_IPHC_CID 0x80
165
166 #define SICSLOWPAN_IPHC_SAC 0x40
167 #define SICSLOWPAN_IPHC_SAM_00 0x00
168 #define SICSLOWPAN_IPHC_SAM_01 0x10
169 #define SICSLOWPAN_IPHC_SAM_10 0x20
170 #define SICSLOWPAN_IPHC_SAM_11 0x30
171
172 #define SICSLOWPAN_IPHC_SAM_BIT 4
173
174 #define SICSLOWPAN_IPHC_M 0x08
175 #define SICSLOWPAN_IPHC_DAC 0x04
176 #define SICSLOWPAN_IPHC_DAM_00 0x00
177 #define SICSLOWPAN_IPHC_DAM_01 0x01
178 #define SICSLOWPAN_IPHC_DAM_10 0x02
179 #define SICSLOWPAN_IPHC_DAM_11 0x03
180
181 #define SICSLOWPAN_IPHC_DAM_BIT 0
182
183 /* Link local context number */
184 #define SICSLOWPAN_IPHC_ADDR_CONTEXT_LL 0
185 /* 16-bit multicast addresses compression */
186 #define SICSLOWPAN_IPHC_MCAST_RANGE 0xA0
187 /** @} */
188
189 /* NHC_EXT_HDR */
190 #define SICSLOWPAN_NHC_MASK 0xF0
191 #define SICSLOWPAN_NHC_EXT_HDR 0xE0
192
193 /**
194 * \name LOWPAN_UDP encoding (works together with IPHC)
195 * @{
196 */
197 /**
198 * \name LOWPAN_UDP encoding (works together with IPHC)
199 * @{
200 */
201 #define SICSLOWPAN_NHC_UDP_MASK 0xF8
202 #define SICSLOWPAN_NHC_UDP_ID 0xF0
203 #define SICSLOWPAN_NHC_UDP_CHECKSUMC 0x04
204 #define SICSLOWPAN_NHC_UDP_CHECKSUMI 0x00
205 /* values for port compression, _with checksum_ ie bit 5 set to 0 */
206 #define SICSLOWPAN_NHC_UDP_CS_P_00 0xF0 /* all inline */
207 #define SICSLOWPAN_NHC_UDP_CS_P_01 0xF1 /* source 16bit inline, dest = 0xF0 + 8 bit inline */
208 #define SICSLOWPAN_NHC_UDP_CS_P_10 0xF2 /* source = 0xF0 + 8bit inline, dest = 16 bit inline */
209 #define SICSLOWPAN_NHC_UDP_CS_P_11 0xF3 /* source & dest = 0xF0B + 4bit inline */
210 /** @} */
211
212
213 /**
214 * \name The 6lowpan "headers" length
215 * @{
216 */
217
218 #define SICSLOWPAN_IPV6_HDR_LEN 1 /*one byte*/
219 #define SICSLOWPAN_HC1_HDR_LEN 3
220 #define SICSLOWPAN_HC1_HC_UDP_HDR_LEN 7
221 #define SICSLOWPAN_FRAG1_HDR_LEN 4
222 #define SICSLOWPAN_FRAGN_HDR_LEN 5
223
224 // Minimum size of the compressed 6LoWPAN header length
225 #define SICSLOWPAN_MIN_COMP_HDR_LEN 7
226
227 // Minimum size of the uncompressed IPv6 header length
228 #define SICSLOWPAN_MIN_UNCOMP_HDR_LEN 40
229
230
231 #define UIP_IPH_LEN 40
232 #define UIP_UDPH_LEN 8 /* Size of UDP header */
233 #define UIP_TCPH_LEN 20 /* Size of TCP header */
234 #define UIP_ICMPH_LEN 4 /* Size of ICMP header */
235
236 /** @} */
237
238 /**
239 * \brief The header for fragments
240 * \note We do not define different structures for FRAG1
241 * and FRAGN headers, which are different. For FRAG1, the
242 * offset field is just not used
243 */
244 /* struct sicslowpan_frag_hdr { */
245 /* uint16_t dispatch_size; */
246 /* uint16_t tag; */
247 /* uint8_t offset; */
248 /* }; */
249
250 /**
251 * \brief The HC1 header when HC_UDP is not used
252 *
253 * When all fields are compressed and HC_UDP is not used,
254 * we use this structure. If HC_UDP is used, the ttl is
255 * in another spot, and we use the sicslowpan_hc1_hc_udp
256 * structure
257 */
258 /* struct sicslowpan_hc1_hdr { */
259 /* uint8_t dispatch; */
260 /* uint8_t encoding; */
261 /* uint8_t ttl; */
262 /* }; */
263
264 /**
265 * \brief HC1 followed by HC_UDP
266 */
267 /* struct sicslowpan_hc1_hc_udp_hdr { */
268 /* uint8_t dispatch; */
269 /* uint8_t hc1_encoding; */
270 /* uint8_t hc_udp_encoding; */
271 /* uint8_t ttl; */
272 /* uint8_t ports; */
273 /* uint16_t udpchksum; */
274 /* }; */
275
276 /**
277 * \brief An address context for IPHC address compression
278 * each context can have upto 8 bytes
279 */
280 struct sicslowpan_addr_context {
281 uint8_t used; /* possibly use as prefix-length */
282 uint8_t number;
283 uint8_t prefix[8];
284 };
285
286 /**
287 * \name Address compressibility test functions
288 * @{
289 */
290
291 /**
292 * \brief check whether we can compress the IID in
293 * address 'a' to 16 bits.
294 * This is used for unicast addresses only, and is true
295 * if the address is on the format \<PREFIX\>::0000:00ff:fe00:XXXX
296 * NOTE: we currently assume 64-bits prefixes
297 */
298 #define sicslowpan_is_iid_16_bit_compressable(a) \
299 ((((a)->u16[4]) == 0) && \
300 (((a)->u8[10]) == 0)&& \
301 (((a)->u8[11]) == 0xff)&& \
302 (((a)->u8[12]) == 0xfe)&& \
303 (((a)->u8[13]) == 0))
304
305 /**
306 * \brief check whether the 9-bit group-id of the
307 * compressed multicast address is known. It is true
308 * if the 9-bit group is the all nodes or all routers
309 * group.
310 * \param a is typed uint8_t *
311 */
312 #define sicslowpan_is_mcast_addr_decompressable(a) \
313 (((*a & 0x01) == 0) && \
314 ((*(a + 1) == 0x01) || (*(a + 1) == 0x02)))
315
316 /**
317 * \brief check whether the 112-bit group-id of the
318 * multicast address is mappable to a 9-bit group-id
319 * It is true if the group is the all nodes or all
320 * routers group.
321 */
322 #define sicslowpan_is_mcast_addr_compressable(a) \
323 ((((a)->u16[1]) == 0) && \
324 (((a)->u16[2]) == 0) && \
325 (((a)->u16[3]) == 0) && \
326 (((a)->u16[4]) == 0) && \
327 (((a)->u16[5]) == 0) && \
328 (((a)->u16[6]) == 0) && \
329 (((a)->u8[14]) == 0) && \
330 ((((a)->u8[15]) == 1) || (((a)->u8[15]) == 2)))
331
332 /* FFXX::00XX:XXXX:XXXX */
333 #define sicslowpan_is_mcast_addr_compressable48(a) \
334 ((((a)->u16[1]) == 0) && \
335 (((a)->u16[2]) == 0) && \
336 (((a)->u16[3]) == 0) && \
337 (((a)->u16[4]) == 0) && \
338 (((a)->u8[10]) == 0))
339
340 /* FFXX::00XX:XXXX */
341 #define sicslowpan_is_mcast_addr_compressable32(a) \
342 ((((a)->u16[1]) == 0) && \
343 (((a)->u16[2]) == 0) && \
344 (((a)->u16[3]) == 0) && \
345 (((a)->u16[4]) == 0) && \
346 (((a)->u16[5]) == 0) && \
347 (((a)->u8[12]) == 0))
348
349 /* FF02::00XX */
350 #define sicslowpan_is_mcast_addr_compressable8(a) \
351 ((((a)->u8[1]) == 2) && \
352 (((a)->u16[1]) == 0) && \
353 (((a)->u16[2]) == 0) && \
354 (((a)->u16[3]) == 0) && \
355 (((a)->u16[4]) == 0) && \
356 (((a)->u16[5]) == 0) && \
357 (((a)->u16[6]) == 0) && \
358 (((a)->u8[14]) == 0))
359
360 #define uip_is_addr_mac_addr_based(a, m) \
361 ((((a)->s6_addr[8]) == (((m)[0]) ^ 0x02)) && \
362 (((a)->s6_addr[9]) == (m)[1]) && \
363 (((a)->s6_addr[10]) == (m)[2]) && \
364 (((a)->s6_addr[11]) == (m)[3]) && \
365 (((a)->s6_addr[12]) == (m)[4]) && \
366 (((a)->s6_addr[13]) == (m)[5]) && \
367 (((a)->s6_addr[14]) == (m)[6]) && \
368 (((a)->s6_addr[15]) == (m)[7]))
369
370 /**
371 * Construct an IPv6 address from eight 16-bit words.
372 *
373 * This function constructs an IPv6 address.
374 *
375 * \hideinitializer
376 */
377 #define uip_ip6addr(addr, addr0, addr1, addr2, addr3, addr4, addr5, addr6, addr7) do {\
378 (addr)->s6_addr[0] = htons(addr0); \
379 (addr)->s6_addr[1] = htons(addr1); \
380 (addr)->s6_addr[2] = htons(addr2); \
381 (addr)->s6_addr[3] = htons(addr3); \
382 (addr)->s6_addr[4] = htons(addr4); \
383 (addr)->s6_addr[5] = htons(addr5); \
384 (addr)->s6_addr[6] = htons(addr6); \
385 (addr)->s6_addr[7] = htons(addr7); \
386 } while(0)
387
388 /**
389 * Construct an IPv6 address from sixteen 8-bit words.
390 *
391 * This function constructs an IPv6 address.
392 *
393 * \hideinitializer
394 */
395 #define uip_ip6addr_u8(addr, addr0, addr1, addr2, addr3, addr4, addr5, addr6, addr7, addr8, addr9, addr10, addr11, addr12, addr13, addr14, addr15) do {\
396 (addr)->s6_addr[0] = addr0; \
397 (addr)->s6_addr[1] = addr1; \
398 (addr)->s6_addr[2] = addr2; \
399 (addr)->s6_addr[3] = addr3; \
400 (addr)->s6_addr[4] = addr4; \
401 (addr)->s6_addr[5] = addr5; \
402 (addr)->s6_addr[6] = addr6; \
403 (addr)->s6_addr[7] = addr7; \
404 (addr)->s6_addr[8] = addr8; \
405 (addr)->s6_addr[9] = addr9; \
406 (addr)->s6_addr[10] = addr10; \
407 (addr)->s6_addr[11] = addr11; \
408 (addr)->s6_addr[12] = addr12; \
409 (addr)->s6_addr[13] = addr13; \
410 (addr)->s6_addr[14] = addr14; \
411 (addr)->s6_addr[15] = addr15; \
412 } while(0)
413
414
415
416 /** \brief 16 bit 802.15.4 address */
417 typedef struct uip_802154_shortaddr {
418 uint8_t addr[2];
419 } uip_802154_shortaddr;
420 /** \brief 64 bit 802.15.4 address */
421 typedef struct uip_802154_longaddr {
422 uint8_t addr[8];
423 } uip_802154_longaddr;
424
425 /** \brief 802.11 address */
426 typedef struct uip_80211_addr {
427 uint8_t addr[6];
428 } uip_80211_addr;
429
430 /** \brief 802.3 address */
431 typedef struct uip_eth_addr {
432 uint8_t addr[6];
433 } uip_eth_addr;
434 typedef uip_802154_longaddr uip_lladdr_t;
435
436 #define UIP_802154_SHORTADDR_LEN 2
437 #define UIP_802154_LONGADDR_LEN 8
438 #define UIP_LLADDR_LEN UIP_802154_LONGADDR_LEN
439
440
441 #define GET16(ptr) (((uint16_t)(((u_int8_t *)ptr)[0] << 8)) | (((u_int8_t *)ptr)[1]))
442 #define SET16(ptr, value) do { \
443 ((u_int8_t *)ptr)[0] = ((value) >> 8) & 0xff; \
444 ((u_int8_t *)ptr)[1] = (value) & 0xff; \
445 } while(0)
446
447 /** \name Pointers in the packetbuf buffer
448 * @{
449 */
450 #define PACKETBUF_FRAG_DISPATCH_SIZE 0 /* 16 bit */
451 #define PACKETBUF_FRAG_TAG 2 /* 16 bit */
452 #define PACKETBUF_FRAG_OFFSET 4 /* 8 bit */
453
454 #define PACKETBUF_HC1_DISPATCH 0 /* 8 bit */
455 #define PACKETBUF_HC1_ENCODING 1 /* 8 bit */
456 #define PACKETBUF_HC1_TTL 2 /* 8 bit */
457
458 #define PACKETBUF_HC1_HC_UDP_DISPATCH 0 /* 8 bit */
459 #define PACKETBUF_HC1_HC_UDP_HC1_ENCODING 1 /* 8 bit */
460 #define PACKETBUF_HC1_HC_UDP_UDP_ENCODING 2 /* 8 bit */
461 #define PACKETBUF_HC1_HC_UDP_TTL 3 /* 8 bit */
462 #define PACKETBUF_HC1_HC_UDP_PORTS 4 /* 8 bit */
463 #define PACKETBUF_HC1_HC_UDP_CHKSUM 5 /* 16 bit */
464
465
466 #define LINKADDR_SIZE 8
467 typedef union {
468 unsigned char u8[LINKADDR_SIZE];
469 uint16_t u16;
470 } linkaddr_t;
471
472 static void
473 uip_ds6_set_addr_iid(struct in6_addr *ipaddr, uip_lladdr_t *lladdr)
474 {
475 /* We consider only links with IEEE EUI-64 identifier or
476 * IEEE 48-bit MAC addresses */
477 #if (UIP_LLADDR_LEN == 8)
478 memcpy(ipaddr->s6_addr + 8, lladdr, UIP_LLADDR_LEN);
479 ipaddr->s6_addr[8] ^= 0x02;
480 #elif (UIP_LLADDR_LEN == 6)
481 memcpy(ipaddr->s6_addr + 8, lladdr, 3);
482 ipaddr->s6_addr[11] = 0xff;
483 ipaddr->s6_addr[12] = 0xfe;
484 memcpy(ipaddr->s6_addr + 13, (uint8_t *)lladdr + 3, 3);
485 ipaddr->s6_addr[8] ^= 0x02;
486 #else
487 #error uip-ds6.c cannot build interface address when UIP_LLADDR_LEN is not 6 or 8
488 #endif
489 }
490
491 static errno_t
492 compress_hdr_ipv6(__unused struct frame802154 *ieee02154hdr,
493 __unused u_int8_t *payload,
494 long *hdroffset, size_t *hdrlen, u_int8_t *hdrbuf)
495 {
496 /*
497 * Negative offset: 6LoWPAN header needs to ve prepended to the data
498 */
499 *hdroffset = -SICSLOWPAN_IPV6_HDR_LEN;
500 *hdrlen = SICSLOWPAN_IPV6_HDR_LEN;
501 hdrbuf[0] = SICSLOWPAN_DISPATCH_IPV6;
502
503 return 0;
504 }
505
506
507 #if 0
508 /*--------------------------------------------------------------------*/
509 /** \name HC1 compression and uncompression functions
510 * @{ */
511 /*--------------------------------------------------------------------*/
512 /**
513 * \brief Compress IP/UDP header using HC1 and HC_UDP
514 *
515 * This function is called by the 6lowpan code to create a compressed
516 * 6lowpan packet in the packetbuf buffer from a full IPv6 packet in the
517 * uip_buf buffer.
518 *
519 *
520 * If we can compress everything, we use HC1 dispatch, if not we use
521 * IPv6 dispatch.\n
522 * We can compress everything if:
523 * - IP version is
524 * - Flow label and traffic class are 0
525 * - Both src and dest ip addresses are link local
526 * - Both src and dest interface ID are recoverable from lower layer
527 * header
528 * - Next header is either ICMP, UDP or TCP
529 * Moreover, if next header is UDP, we try to compress it using HC_UDP.
530 * This is feasible is both ports are between F0B0 and F0B0 + 15\n\n
531 *
532 * Resulting header structure:
533 * - For ICMP, TCP, non compressed UDP\n
534 * HC1 encoding = 11111010 (UDP) 11111110 (TCP) 11111100 (ICMP)\n
535 * \verbatim
536 * 1 2 3
537 * 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
538 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
539 * | LoWPAN HC1 Dsp | HC1 encoding | IPv6 Hop limit| L4 hdr + data|
540 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
541 * | ...
542 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
543 * \endverbatim
544 *
545 * - For compressed UDP
546 * HC1 encoding = 11111011, HC_UDP encoding = 11100000\n
547 * \verbatim
548 * 1 2 3
549 * 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
550 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
551 * | LoWPAN HC1 Dsp| HC1 encoding | HC_UDP encod.| IPv6 Hop limit|
552 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
553 * | src p.| dst p.| UDP checksum | L4 data...
554 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
555 * \endverbatim
556 *
557 * \param link_destaddr L2 destination address, needed to compress the
558 * IP destination field
559 */
560 #endif
561 errno_t
562 compress_hdr_hc1(struct frame802154 *ieee02154hdr, u_int8_t *payload,
563 long *hdroffset, size_t *hdrlen, u_int8_t *hdrbuf)
564 {
565 struct ip6_hdr *ip6 = (struct ip6_hdr *)(payload);
566
567 if (*hdrlen < SICSLOWPAN_MIN_COMP_HDR_LEN) {
568 return EINVAL;
569 }
570
571 *hdroffset = 0;
572
573 /*
574 * Check if all the assumptions for full compression
575 * are valid :
576 */
577 if ((ip6->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION ||
578 !IN6_IS_ADDR_LINKLOCAL(&ip6->ip6_src) ||
579 !uip_is_addr_mac_addr_based(&ip6->ip6_src, ieee02154hdr->src_addr) ||
580 !IN6_IS_ADDR_LINKLOCAL(&ip6->ip6_dst) ||
581 !uip_is_addr_mac_addr_based(&ip6->ip6_dst,
582 ieee02154hdr->dest_addr) ||
583 (ip6->ip6_nxt != IPPROTO_ICMPV6 &&
584 ip6->ip6_nxt != IPPROTO_UDP &&
585 ip6->ip6_nxt != IPPROTO_TCP)) {
586 /*
587 * IPV6 DISPATCH
588 * Something cannot be compressed, use IPV6 DISPATCH,
589 * compress nothing, copy IPv6 header in packetbuf buffer
590 */
591 return compress_hdr_ipv6(ieee02154hdr, payload, hdroffset, hdrlen, hdrbuf);
592 } else {
593 /*
594 * HC1 DISPATCH
595 * maximum compresssion:
596 * All fields in the IP header but Hop Limit are elided
597 * If next header is UDP, we compress UDP header using HC2
598 */
599 hdrbuf[PACKETBUF_HC1_DISPATCH] = SICSLOWPAN_DISPATCH_HC1;
600
601 switch (ip6->ip6_nxt) {
602 case IPPROTO_ICMPV6:
603 /* HC1 encoding and ttl */
604 hdrbuf[PACKETBUF_HC1_ENCODING] = 0xFC;
605 hdrbuf[PACKETBUF_HC1_TTL] = ip6->ip6_hlim;
606 *hdrlen = SICSLOWPAN_HC1_HDR_LEN;
607 *hdroffset = sizeof(struct ip6_hdr);
608 break;
609
610 case IPPROTO_TCP:
611 /* HC1 encoding and ttl */
612 hdrbuf[PACKETBUF_HC1_ENCODING] = 0xFE;
613 hdrbuf[PACKETBUF_HC1_TTL] = ip6->ip6_hlim;
614 *hdrlen = SICSLOWPAN_HC1_HDR_LEN;
615 *hdroffset = sizeof(struct ip6_hdr);
616 break;
617
618 case IPPROTO_UDP: {
619 struct udphdr *udp = (struct udphdr *)(uintptr_t)(ip6 + 1);
620
621 /*
622 * try to compress UDP header (we do only full compression).
623 * This is feasible if both src and dest ports are between
624 * SICSLOWPAN_UDP_PORT_MIN and SICSLOWPAN_UDP_PORT_MIN + 15
625 */
626 printf("source/remote ports %u/%u\n", ntohs(udp->uh_sport), ntohs(udp->uh_dport));
627 if (ntohs(udp->uh_sport) >= SICSLOWPAN_UDP_PORT_MIN &&
628 ntohs(udp->uh_sport) < SICSLOWPAN_UDP_PORT_MAX &&
629 ntohs(udp->uh_dport) >= SICSLOWPAN_UDP_PORT_MIN &&
630 ntohs(udp->uh_dport) < SICSLOWPAN_UDP_PORT_MAX) {
631 /* HC1 encoding */
632 hdrbuf[PACKETBUF_HC1_HC_UDP_HC1_ENCODING] = 0xFB;
633
634 /* HC_UDP encoding, ttl, src and dest ports, checksum */
635 hdrbuf[PACKETBUF_HC1_HC_UDP_UDP_ENCODING] = 0xE0;
636 hdrbuf[PACKETBUF_HC1_HC_UDP_TTL] = ip6->ip6_hlim;
637
638 hdrbuf[PACKETBUF_HC1_HC_UDP_PORTS] =
639 (uint8_t)((ntohs(udp->uh_sport) - SICSLOWPAN_UDP_PORT_MIN) << 4) +
640 (uint8_t)((ntohs(udp->uh_dport) - SICSLOWPAN_UDP_PORT_MIN));
641
642 memcpy(&hdrbuf[PACKETBUF_HC1_HC_UDP_CHKSUM], &udp->uh_sum, 2);
643 *hdrlen = SICSLOWPAN_HC1_HC_UDP_HDR_LEN;
644 *hdroffset = sizeof(struct ip6_hdr) + sizeof(struct udphdr);
645 } else {
646 /* HC1 encoding and ttl */
647 hdrbuf[PACKETBUF_HC1_ENCODING] = 0xFA;
648 hdrbuf[PACKETBUF_HC1_TTL] = ip6->ip6_hlim;
649 *hdrlen = SICSLOWPAN_HC1_HDR_LEN;
650 *hdroffset = sizeof(struct ip6_hdr);
651 }
652 break;
653 }
654 }
655 }
656 return 0;
657 }
658
659
660 /*--------------------------------------------------------------------*/
661 /**
662 * \brief Uncompress HC1 (and HC_UDP) headers and put them in
663 * sicslowpan_buf
664 *
665 * This function is called by the input function when the dispatch is
666 * HC1.
667 * We %process the packet in the packetbuf buffer, uncompress the header
668 * fields, and copy the result in the sicslowpan buffer.
669 * At the end of the decompression, packetbuf_hdr_len and uncompressed_hdr_len
670 * are set to the appropriate values
671 *
672 * \param ip_len Equal to 0 if the packet is not a fragment (IP length
673 * is then inferred from the L2 length), non 0 if the packet is a 1st
674 * fragment.
675 */
676 errno_t
677 uncompress_hdr_hc1(struct frame802154 *frame, u_int8_t *payload,
678 uint16_t ip_len, long *hdroffset, size_t *hdrlen, u_int8_t *hdrbuf)
679 {
680 struct ip6_hdr *ip6 = (struct ip6_hdr *)hdrbuf;
681
682 if (payload[PACKETBUF_HC1_DISPATCH] == SICSLOWPAN_DISPATCH_IPV6) {
683 *hdroffset = -SICSLOWPAN_IPV6_HDR_LEN;
684 *hdrlen = SICSLOWPAN_IPV6_HDR_LEN;
685 return 0;
686 }
687
688 *hdroffset = 0;
689
690 /* version, traffic class, flow label */
691 ip6->ip6_flow = 0;
692 ip6->ip6_vfc = IPV6_VERSION;
693
694 /* src and dest ip addresses */
695 uip_ip6addr_u8(&ip6->ip6_src, 0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
696 uip_ds6_set_addr_iid(&ip6->ip6_src,
697 (uip_lladdr_t *)frame->src_addr);
698
699 uip_ip6addr_u8(&ip6->ip6_dst, 0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
700 uip_ds6_set_addr_iid(&ip6->ip6_dst,
701 (uip_lladdr_t *)frame->dest_addr);
702
703 *hdrlen = UIP_IPH_LEN;
704
705 /* Next header field */
706 switch (payload[PACKETBUF_HC1_ENCODING] & 0x06) {
707 case SICSLOWPAN_HC1_NH_ICMP6:
708 ip6->ip6_nxt = IPPROTO_ICMPV6;
709 ip6->ip6_hlim = payload[PACKETBUF_HC1_TTL];
710 *hdroffset = SICSLOWPAN_HC1_HDR_LEN;
711 break;
712
713 case SICSLOWPAN_HC1_NH_TCP:
714 ip6->ip6_nxt = IPPROTO_TCP;
715 ip6->ip6_hlim = payload[PACKETBUF_HC1_TTL];
716 *hdroffset = SICSLOWPAN_HC1_HDR_LEN;
717 break;
718
719 case SICSLOWPAN_HC1_NH_UDP:
720 ip6->ip6_nxt = IPPROTO_UDP;
721 if (payload[PACKETBUF_HC1_HC_UDP_HC1_ENCODING] & 0x01) {
722 struct udphdr *udp = (struct udphdr *)(uintptr_t)ip6;
723
724 /* UDP header is compressed with HC_UDP */
725 if (payload[PACKETBUF_HC1_HC_UDP_UDP_ENCODING] !=
726 SICSLOWPAN_HC_UDP_ALL_C) {
727 printf("sicslowpan (uncompress_hdr), packet not supported");
728 return EINVAL;
729 }
730 /* IP TTL */
731
732 ip6->ip6_hlim = payload[PACKETBUF_HC1_HC_UDP_TTL];
733 /* UDP ports, len, checksum */
734 udp->uh_sport =
735 htons(SICSLOWPAN_UDP_PORT_MIN + (payload[PACKETBUF_HC1_HC_UDP_PORTS] >> 4));
736 udp->uh_dport =
737 htons(SICSLOWPAN_UDP_PORT_MIN + (payload[PACKETBUF_HC1_HC_UDP_PORTS] & 0x0F));
738
739 memcpy(&udp->uh_sum, &payload[PACKETBUF_HC1_HC_UDP_CHKSUM], 2);
740 *hdrlen += UIP_UDPH_LEN;
741 *hdroffset = SICSLOWPAN_HC1_HC_UDP_HDR_LEN;
742 } else {
743 ip6->ip6_hlim = payload[PACKETBUF_HC1_TTL];
744 *hdroffset = SICSLOWPAN_HC1_HDR_LEN;
745 }
746 break;
747
748 default:
749 /* this shouldn't happen, drop */
750 return EINVAL;
751 }
752
753 /* IP length field. */
754 if (ip_len == 0) {
755 size_t len = frame->payload_len - *hdroffset + *hdrlen - sizeof(struct ip6_hdr);
756
757 /* This is not a fragmented packet */
758 SET16(&ip6->ip6_plen, len);
759 } else {
760 /* This is a 1st fragment */
761 SET16(&ip6->ip6_plen, ip_len - UIP_IPH_LEN);
762 }
763 /* length field in UDP header */
764 if (ip6->ip6_nxt == IPPROTO_UDP) {
765 struct udphdr *udp = (struct udphdr *)(uintptr_t)ip6;
766
767 memcpy(&udp->uh_ulen, &ip6->ip6_plen, 2);
768 }
769 return 0;
770 }
771
772 errno_t
773 sixxlowpan_compress(struct frame802154 *ieee02154hdr, u_int8_t *payload)
774 {
775 long hdroffset;
776 size_t hdrlen;
777 u_int8_t hdrbuf[128];
778 errno_t error;
779
780 bzero(hdrbuf, sizeof(hdrbuf));
781 hdrlen = sizeof(hdrbuf);
782
783 error = compress_hdr_hc1(ieee02154hdr, payload,
784 &hdroffset, &hdrlen, hdrbuf);
785 if (error != 0) {
786 return error;
787 }
788
789 if (hdroffset < 0) {
790 /*
791 * hdroffset negative means that we have to add
792 * hdrlen of extra stuff
793 */
794 memmove(&payload[hdrlen],
795 &payload[0],
796 ieee02154hdr->payload_len);
797 memcpy(&payload[0], hdrbuf, hdrlen);
798
799 ieee02154hdr->payload_len += hdrlen;
800 } else if (hdroffset > 0) {
801 /*
802 * hdroffset is the size of the compressed header
803 *
804 * hdrlen is the size of the data that has been compressed
805 * -- i.e. when the untouched data starts
806 */
807 memmove(&payload[hdrlen],
808 &payload[hdroffset],
809 ieee02154hdr->payload_len - hdroffset);
810 memcpy(&payload[0], hdrbuf, hdrlen);
811
812 ieee02154hdr->payload_len += hdrlen - hdroffset;
813 }
814
815 return 0;
816 }
817
818 errno_t
819 sixxlowpan_uncompress(struct frame802154 *ieee02154hdr, u_int8_t *payload)
820 {
821 long hdroffset;
822 size_t hdrlen;
823 u_int8_t hdrbuf[128];
824 errno_t error;
825
826 bzero(hdrbuf, sizeof(hdrbuf));
827 hdrlen = sizeof(hdrbuf);
828
829 error = uncompress_hdr_hc1(ieee02154hdr, (u_int8_t *)payload,
830 0, &hdroffset, &hdrlen, hdrbuf);
831
832 if (error != 0) {
833 return error;
834 }
835
836 if (hdroffset < 0) {
837 /*
838 * hdroffset negative means that we have to remove
839 * hdrlen of extra stuff
840 */
841 if (ieee02154hdr->payload_len < hdrlen) {
842 return EINVAL;
843 }
844 memmove(&payload[0],
845 &payload[hdrlen],
846 ieee02154hdr->payload_len - hdrlen);
847 ieee02154hdr->payload_len -= hdrlen;
848 } else {
849 /*
850 * hdroffset is the size of the compressed header
851 * -- i.e. when the untouched data starts
852 *
853 * hdrlen is the size of the decompressed header
854 * that takes the place of compressed header of size hdroffset
855 */
856 if (ieee02154hdr->payload_len < hdroffset) {
857 return EINVAL;
858 }
859 memmove(payload + hdrlen,
860 payload + hdroffset,
861 ieee02154hdr->payload_len - hdroffset);
862 memcpy(payload, hdrbuf, hdrlen);
863 ieee02154hdr->payload_len += hdrlen - hdroffset;
864 }
865
866 return 0;
867 }
868
869 errno_t
870 sixxlowpan_output(struct frame802154 *ieee02154hdr, u_int8_t *payload)
871 {
872 errno_t error = 0;
873
874 error = sixxlowpan_compress(ieee02154hdr, payload);
875 if (error != 0) {
876 goto done;
877 }
878
879 /*
880 * TO DO: fragmentation
881 */
882
883 done:
884 return error;
885 }
886
887 errno_t
888 sixxlowpan_input(struct frame802154 *ieee02154hdr, u_int8_t *payload)
889 {
890 errno_t error = 0;
891
892 error = sixxlowpan_uncompress(ieee02154hdr, payload);
893 if (error != 0) {
894 goto done;
895 }
896
897 /*
898 * TO DO: fragmentation
899 */
900
901 done:
902 return error;
903 }