]> git.saurik.com Git - apple/xnu.git/blame - bsd/net/sixxlowpan.c
xnu-7195.81.3.tar.gz
[apple/xnu.git] / bsd / net / sixxlowpan.c
CommitLineData
cb323159
A
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
88errno_t
89compress_hdr_hc1(struct frame802154 *, u_int8_t *,
90 long *, size_t *, u_int8_t *);
91errno_t
92uncompress_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 */
280struct 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 */
417typedef struct uip_802154_shortaddr {
418 uint8_t addr[2];
419} uip_802154_shortaddr;
420/** \brief 64 bit 802.15.4 address */
421typedef struct uip_802154_longaddr {
422 uint8_t addr[8];
423} uip_802154_longaddr;
424
425/** \brief 802.11 address */
426typedef struct uip_80211_addr {
427 uint8_t addr[6];
428} uip_80211_addr;
429
430/** \brief 802.3 address */
431typedef struct uip_eth_addr {
432 uint8_t addr[6];
433} uip_eth_addr;
434typedef 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
467typedef union {
468 unsigned char u8[LINKADDR_SIZE];
469 uint16_t u16;
470} linkaddr_t;
471
472static void
473uip_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
491static errno_t
492compress_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
561errno_t
562compress_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 */
676errno_t
677uncompress_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
772errno_t
773sixxlowpan_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
818errno_t
819sixxlowpan_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 */
f427ee49
A
841 if (ieee02154hdr->payload_len < hdrlen) {
842 return EINVAL;
843 }
cb323159
A
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 */
f427ee49
A
856 if (ieee02154hdr->payload_len < hdroffset) {
857 return EINVAL;
858 }
cb323159
A
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
869errno_t
870sixxlowpan_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
883done:
884 return error;
885}
886
887errno_t
888sixxlowpan_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
901done:
902 return error;
903}