]>
Commit | Line | Data |
---|---|---|
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 | ||
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 | */ | |
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 | ||
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 | } |