xref: /xnu-8020.140.41/bsd/net/sixxlowpan.c (revision 27b03b360a988dfd3dfdf34262bb0042026747cc)
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 <[email protected]>
65  * \author Nicolas Tsiftes <[email protected]>
66  * \author Niclas Finne <[email protected]>
67  * \author Mathilde Durvy <[email protected]>
68  * \author Julien Abeille <[email protected]>
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
uip_ds6_set_addr_iid(struct in6_addr * ipaddr,uip_lladdr_t * lladdr)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
compress_hdr_ipv6(__unused struct frame802154 * ieee02154hdr,__unused u_int8_t * payload,long * hdroffset,size_t * hdrlen,u_int8_t * hdrbuf)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
compress_hdr_hc1(struct frame802154 * ieee02154hdr,u_int8_t * payload,long * hdroffset,size_t * hdrlen,u_int8_t * hdrbuf)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
uncompress_hdr_hc1(struct frame802154 * frame,u_int8_t * payload,uint16_t ip_len,long * hdroffset,size_t * hdrlen,u_int8_t * hdrbuf)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
sixxlowpan_compress(struct frame802154 * ieee02154hdr,u_int8_t * payload)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
sixxlowpan_uncompress(struct frame802154 * ieee02154hdr,u_int8_t * payload)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
sixxlowpan_output(struct frame802154 * ieee02154hdr,u_int8_t * payload)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
sixxlowpan_input(struct frame802154 * ieee02154hdr,u_int8_t * payload)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 }
904