1 /*
2 * Copyright (c) 2016 Intel Corporation
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 /**
8 * @file
9 * @brief 802.15.4 6LoWPAN fragment handler implementation
10 */
11
12 #include <zephyr/logging/log.h>
13 LOG_MODULE_REGISTER(net_ieee802154_6lo_fragment, CONFIG_NET_L2_IEEE802154_LOG_LEVEL);
14
15 #include "6lo.h"
16 #include "6lo_private.h"
17 #include "ieee802154_6lo_fragment.h"
18 #include "net_private.h"
19
20 #include <errno.h>
21
22 #include <zephyr/net/net_core.h>
23 #include <zephyr/net/net_if.h>
24 #include <zephyr/net/net_pkt.h>
25 #include <zephyr/net/net_stats.h>
26 #include <zephyr/net/udp.h>
27
28 #define NET_FRAG_DISPATCH_MASK 0xF8
29 #define NET_FRAG_OFFSET_POS (NET_6LO_FRAG_DATAGRAM_SIZE_LEN + NET_6LO_FRAG_DATAGRAM_OFFSET_LEN)
30
31 #define BUF_TIMEOUT K_MSEC(50)
32
33 #define FRAG_REASSEMBLY_TIMEOUT K_SECONDS(CONFIG_NET_L2_IEEE802154_REASSEMBLY_TIMEOUT)
34 #define REASS_CACHE_SIZE CONFIG_NET_L2_IEEE802154_FRAGMENT_REASS_CACHE_SIZE
35
36 /**
37 * Reassemble cache : Depends on cache size it used for reassemble
38 * IPv6 packets simultaneously.
39 */
40 struct frag_cache {
41 struct k_work_delayable timer; /* Reassemble timer */
42 struct net_pkt *pkt; /* Reassemble packet */
43 uint16_t size; /* Datagram size */
44 uint16_t tag; /* Datagram tag */
45 bool used;
46 };
47
48 static struct frag_cache cache[REASS_CACHE_SIZE];
49
50 /**
51 * RFC 4944, section 5.3
52 * If an entire payload (e.g., IPv6) datagram fits within a single 802.15.4
53 * frame, it is unfragmented and the LoWPAN encapsulation should not contain
54 * a fragmentation header. If the datagram does not fit within a single
55 * IEEE 802.15.4 frame, it SHALL be broken into link fragments. As the
56 * fragment offset can only express multiples of eight bytes, all link
57 * fragments for a datagram except the last one MUST be multiples of eight
58 * bytes in length.
59 *
60 * RFC 7668, section 3 (IPv6 over Bluetooth Low Energy)
61 * Functionality is comprised of link-local IPv6 addresses and stateless
62 * IPv6 address autoconfiguration, Neighbor Discovery, and header compression
63 * Fragmentation features from 6LoWPAN standards are not used due to Bluetooth
64 * LE's link-layer fragmentation support.
65 */
66
67 /**
68 * 1 2 3
69 * 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
70 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
71 * |1 1 0 0 0| datagram_size | datagram_tag |
72 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
73 *
74 * 1 2 3
75 * 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
76 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
77 * |1 1 0 0 0| datagram_size | datagram_tag |
78 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
79 * |datagram_offset|
80 * +-+-+-+-+-+-+-+-+
81 */
82
set_datagram_size(uint8_t * ptr,uint16_t size)83 static inline void set_datagram_size(uint8_t *ptr, uint16_t size)
84 {
85 ptr[0] |= ((size & 0x7FF) >> 8);
86 ptr[1] = (uint8_t)size;
87 }
88
set_datagram_tag(uint8_t * ptr,uint16_t tag)89 static inline void set_datagram_tag(uint8_t *ptr, uint16_t tag)
90 {
91 ptr[0] = tag >> 8;
92 ptr[1] = (uint8_t)tag;
93 }
94
set_up_frag_hdr(struct net_buf * frag,uint16_t size,uint8_t offset)95 static inline void set_up_frag_hdr(struct net_buf *frag, uint16_t size, uint8_t offset)
96 {
97 static uint16_t datagram_tag;
98
99 bool is_first_frag = !offset;
100 uint8_t pos = frag->len;
101
102 if (is_first_frag) {
103 datagram_tag++;
104 net_buf_add(frag, NET_6LO_FRAG1_HDR_LEN);
105 frag->data[pos] = NET_6LO_DISPATCH_FRAG1;
106 } else {
107 net_buf_add(frag, NET_6LO_FRAGN_HDR_LEN);
108 frag->data[pos] = NET_6LO_DISPATCH_FRAGN;
109 }
110
111 set_datagram_size(frag->data + pos, size);
112 pos += NET_6LO_FRAG_DATAGRAM_SIZE_LEN;
113
114 set_datagram_tag(frag->data + pos, datagram_tag);
115 pos += NET_6LO_FRAG_DATAGRAM_OFFSET_LEN;
116
117 if (!is_first_frag) {
118 frag->data[pos] = offset;
119 }
120 }
121
calc_payload_capacity(struct net_buf * frag)122 static inline uint8_t calc_payload_capacity(struct net_buf *frag)
123 {
124 uint8_t capacity = frag->size - frag->len;
125
126 return (capacity & 0xF8);
127 }
128
copy_data(struct ieee802154_6lo_fragment_ctx * ctx,struct net_buf * frame_buf,uint8_t capacity)129 static inline uint8_t copy_data(struct ieee802154_6lo_fragment_ctx *ctx, struct net_buf *frame_buf,
130 uint8_t capacity)
131 {
132 uint8_t remainder = ctx->buf->len - (ctx->pos - ctx->buf->data);
133 uint8_t move = MIN(remainder, capacity);
134
135 memcpy(frame_buf->data + frame_buf->len, ctx->pos, move);
136 net_buf_add(frame_buf, move);
137
138 return move;
139 }
140
update_fragment_ctx(struct ieee802154_6lo_fragment_ctx * ctx,uint8_t moved)141 static inline void update_fragment_ctx(struct ieee802154_6lo_fragment_ctx *ctx, uint8_t moved)
142 {
143 uint8_t remainder = (ctx->buf->len - (ctx->pos - ctx->buf->data));
144 bool next_frag = moved == remainder;
145
146 if (next_frag) {
147 ctx->buf = ctx->buf->frags;
148 if (ctx->buf) {
149 ctx->pos = ctx->buf->data;
150 }
151 } else {
152 ctx->pos += moved;
153 }
154 }
155
156 /**
157 * ch : compressed (IPv6) header(s)
158 * fh : fragment header (dispatch + size + tag + [offset])
159 * p : payload (first fragment holds IPv6 hdr as payload)
160 * e : empty space
161 * ll : link layer
162 *
163 * Input frame_buf to ieee802154_6lo_fragment() looks like below
164 *
165 * | ll |
166 *
167 * After fragment creation, frame_buf will look like:
168 *
169 * | ll + fh + p + e |
170 *
171 * p being taken from current pkt buffer and position.
172 *
173 * Space in every fragment is because fragment payload should be multiple
174 * of 8 octets (we have predefined packets at compile time, data packet mtu
175 * is set already).
176 *
177 * If it's the first fragment being created, fh will not own any offset
178 * (so it will be 1 byte smaller)
179 */
ieee802154_6lo_fragment(struct ieee802154_6lo_fragment_ctx * ctx,struct net_buf * frame_buf,bool iphc)180 struct net_buf *ieee802154_6lo_fragment(struct ieee802154_6lo_fragment_ctx *ctx,
181 struct net_buf *frame_buf, bool iphc)
182 {
183 uint8_t capacity;
184
185 set_up_frag_hdr(frame_buf, ctx->pkt_size, ctx->offset);
186
187 capacity = calc_payload_capacity(frame_buf);
188 ctx->processed += capacity;
189
190 bool is_first_frag = !ctx->offset;
191
192 if (is_first_frag) {
193 /* First fragment needs to take into account 6lo */
194 if (iphc) {
195 capacity -= ctx->hdr_diff;
196 } else {
197 /* Adding IPv6 dispatch header */
198 capacity += 1U;
199 }
200 }
201
202 while (capacity && ctx->buf) {
203 uint8_t moved = copy_data(ctx, frame_buf, capacity);
204
205 update_fragment_ctx(ctx, moved);
206 capacity -= moved;
207 }
208
209 ctx->offset = ctx->processed >> 3;
210
211 return ctx->buf;
212 }
213
get_datagram_type(uint8_t * ptr)214 static inline uint8_t get_datagram_type(uint8_t *ptr)
215 {
216 return ptr[0] & NET_FRAG_DISPATCH_MASK;
217 }
218
get_datagram_size(uint8_t * ptr)219 static inline uint16_t get_datagram_size(uint8_t *ptr)
220 {
221 return ((ptr[0] & 0x1F) << 8) | ptr[1];
222 }
223
get_datagram_tag(uint8_t * ptr)224 static inline uint16_t get_datagram_tag(uint8_t *ptr)
225 {
226 return (ptr[0] << 8) | ptr[1];
227 }
228
update_protocol_header_lengths(struct net_pkt * pkt,uint16_t size)229 static void update_protocol_header_lengths(struct net_pkt *pkt, uint16_t size)
230 {
231 NET_PKT_DATA_ACCESS_DEFINE(ipv6_access, struct net_ipv6_hdr);
232 struct net_ipv6_hdr *ipv6;
233
234 ipv6 = (struct net_ipv6_hdr *)net_pkt_get_data(pkt, &ipv6_access);
235 if (!ipv6) {
236 NET_ERR("could not get IPv6 header");
237 return;
238 }
239
240 net_pkt_set_ip_hdr_len(pkt, NET_IPV6H_LEN);
241 ipv6->len = htons(size - NET_IPV6H_LEN);
242
243 net_pkt_set_data(pkt, &ipv6_access);
244
245 if (ipv6->nexthdr == IPPROTO_UDP) {
246 NET_PKT_DATA_ACCESS_DEFINE(udp_access, struct net_udp_hdr);
247 struct net_udp_hdr *udp;
248
249 udp = (struct net_udp_hdr *)net_pkt_get_data(pkt, &udp_access);
250 if (udp) {
251 udp->len = htons(size - NET_IPV6H_LEN);
252 net_pkt_set_data(pkt, &udp_access);
253 } else {
254 NET_ERR("could not get UDP header");
255 }
256 }
257 }
258
clear_reass_cache(uint16_t size,uint16_t tag)259 static inline void clear_reass_cache(uint16_t size, uint16_t tag)
260 {
261 uint8_t i;
262
263 for (i = 0U; i < REASS_CACHE_SIZE; i++) {
264 if (!(cache[i].size == size && cache[i].tag == tag)) {
265 continue;
266 }
267
268 if (cache[i].pkt) {
269 net_pkt_unref(cache[i].pkt);
270 }
271
272 cache[i].pkt = NULL;
273 cache[i].size = 0U;
274 cache[i].tag = 0U;
275 cache[i].used = false;
276 k_work_cancel_delayable(&cache[i].timer);
277 }
278 }
279
280 /**
281 * If the reassembly not completed within reassembly timeout discard
282 * the whole packet.
283 */
reass_timeout(struct k_work * work)284 static void reass_timeout(struct k_work *work)
285 {
286 struct k_work_delayable *dwork = k_work_delayable_from_work(work);
287 struct frag_cache *fcache = CONTAINER_OF(dwork, struct frag_cache, timer);
288
289 if (fcache->pkt) {
290 net_pkt_unref(fcache->pkt);
291 }
292
293 fcache->pkt = NULL;
294 fcache->size = 0U;
295 fcache->tag = 0U;
296 fcache->used = false;
297 }
298
299 /**
300 * Upon reception of first fragment with respective of size and tag
301 * create a new cache. If number of unused cache are out then
302 * discard the fragments.
303 */
set_reass_cache(struct net_pkt * pkt,uint16_t size,uint16_t tag)304 static inline struct frag_cache *set_reass_cache(struct net_pkt *pkt, uint16_t size, uint16_t tag)
305 {
306 int i;
307
308 for (i = 0; i < REASS_CACHE_SIZE; i++) {
309 if (cache[i].used) {
310 continue;
311 }
312
313 cache[i].pkt = pkt;
314 cache[i].size = size;
315 cache[i].tag = tag;
316 cache[i].used = true;
317
318 k_work_init_delayable(&cache[i].timer, reass_timeout);
319 k_work_reschedule(&cache[i].timer, FRAG_REASSEMBLY_TIMEOUT);
320 return &cache[i];
321 }
322
323 return NULL;
324 }
325
326 /**
327 * Return cache if it matches with size and tag of stored caches,
328 * otherwise return NULL.
329 */
get_reass_cache(uint16_t size,uint16_t tag)330 static inline struct frag_cache *get_reass_cache(uint16_t size, uint16_t tag)
331 {
332 uint8_t i;
333
334 for (i = 0U; i < REASS_CACHE_SIZE; i++) {
335 if (cache[i].used) {
336 if (cache[i].size == size && cache[i].tag == tag) {
337 return &cache[i];
338 }
339 }
340 }
341
342 return NULL;
343 }
344
fragment_append(struct net_pkt * pkt,struct net_buf * frag)345 static inline void fragment_append(struct net_pkt *pkt, struct net_buf *frag)
346 {
347 if (get_datagram_type(frag->data) == NET_6LO_DISPATCH_FRAG1) {
348 /* Always make sure first fragment is inserted first
349 * This will be useful for fragment_cached_pkt_len()
350 */
351 frag->frags = pkt->buffer;
352 pkt->buffer = frag;
353 } else {
354 net_pkt_append_buffer(pkt, frag);
355 }
356 }
357
fragment_cached_pkt_len(struct net_pkt * pkt)358 static inline size_t fragment_cached_pkt_len(struct net_pkt *pkt)
359 {
360 size_t len = 0U;
361 struct net_buf *frag;
362 int hdr_diff;
363 uint8_t *data;
364
365 frag = pkt->buffer;
366 while (frag) {
367 uint16_t frag_hdr_len = NET_6LO_FRAGN_HDR_LEN;
368
369 if (get_datagram_type(frag->data) == NET_6LO_DISPATCH_FRAG1) {
370 frag_hdr_len = NET_6LO_FRAG1_HDR_LEN;
371 }
372
373 len += frag->len - frag_hdr_len;
374
375 frag = frag->frags;
376 }
377
378 /* 6lo assumes that fragment header has been removed,
379 * and in our side we assume first buffer is always the first fragment.
380 */
381 data = pkt->buffer->data;
382 pkt->buffer->data += NET_6LO_FRAG1_HDR_LEN;
383
384 hdr_diff = net_6lo_uncompress_hdr_diff(pkt);
385
386 pkt->buffer->data = data;
387
388 if (hdr_diff == INT_MAX) {
389 return 0;
390 }
391
392 return len + hdr_diff;
393 }
394
fragment_offset(struct net_buf * frag)395 static inline uint16_t fragment_offset(struct net_buf *frag)
396 {
397 if (get_datagram_type(frag->data) == NET_6LO_DISPATCH_FRAG1) {
398 return 0;
399 }
400
401 return ((uint16_t)frag->data[NET_FRAG_OFFSET_POS] << 3);
402 }
403
fragment_move_back(struct net_pkt * pkt,struct net_buf * frag,struct net_buf * stop)404 static void fragment_move_back(struct net_pkt *pkt, struct net_buf *frag, struct net_buf *stop)
405 {
406 struct net_buf *prev, *current;
407
408 prev = NULL;
409 current = pkt->buffer;
410
411 while (current && current != stop) {
412 if (fragment_offset(frag) < fragment_offset(current)) {
413 if (prev) {
414 prev->frags = frag;
415 }
416
417 frag->frags = current;
418 break;
419 }
420
421 prev = current;
422 current = current->frags;
423 }
424 }
425
fragment_remove_headers(struct net_pkt * pkt)426 static inline void fragment_remove_headers(struct net_pkt *pkt)
427 {
428 struct net_buf *frag;
429
430 frag = pkt->buffer;
431 while (frag) {
432 uint16_t frag_hdr_len = NET_6LO_FRAGN_HDR_LEN;
433
434 if (get_datagram_type(frag->data) == NET_6LO_DISPATCH_FRAG1) {
435 frag_hdr_len = NET_6LO_FRAG1_HDR_LEN;
436 }
437
438 memmove(frag->data, frag->data + frag_hdr_len, frag->len - frag_hdr_len);
439 frag->len -= frag_hdr_len;
440
441 frag = frag->frags;
442 }
443 }
444
fragment_reconstruct_packet(struct net_pkt * pkt)445 static inline void fragment_reconstruct_packet(struct net_pkt *pkt)
446 {
447 struct net_buf *prev, *current, *next;
448
449 prev = NULL;
450 current = pkt->buffer;
451
452 while (current) {
453 next = current->frags;
454
455 if (!prev || (fragment_offset(prev) > fragment_offset(current))) {
456 prev = current;
457 } else {
458 fragment_move_back(pkt, current, prev);
459 }
460
461 current = next;
462 }
463
464 /* Let's remove now useless fragmentation headers */
465 fragment_remove_headers(pkt);
466 }
467
fragment_packet_valid(struct net_pkt * pkt)468 static inline bool fragment_packet_valid(struct net_pkt *pkt)
469 {
470 return (get_datagram_type(pkt->buffer->data) == NET_6LO_DISPATCH_FRAG1);
471 }
472
473 /**
474 * Parse size and tag from the fragment, check if we have any cache
475 * related to it. If not create a new cache.
476 * Remove the fragmentation header and uncompress IPv6 and related headers.
477 * Cache Rx part of fragment along with data buf for the first fragment
478 * in the cache, remaining fragments just cache data fragment, unref
479 * RX pkt. So in both the cases caller can assume packet is consumed.
480 */
fragment_add_to_cache(struct net_pkt * pkt)481 static inline enum net_verdict fragment_add_to_cache(struct net_pkt *pkt)
482 {
483 bool first_frag = false;
484 struct frag_cache *fcache;
485 struct net_buf *frag;
486 uint16_t size;
487 uint16_t tag;
488 uint8_t type;
489
490 frag = pkt->buffer;
491 type = get_datagram_type(frag->data);
492
493 if ((type == NET_6LO_DISPATCH_FRAG1 && frag->len < NET_6LO_FRAG1_HDR_LEN) ||
494 (type == NET_6LO_DISPATCH_FRAGN && frag->len < NET_6LO_FRAGN_HDR_LEN)) {
495 return NET_DROP;
496 }
497
498 /* Parse total size of packet */
499 size = get_datagram_size(frag->data);
500
501 /* Parse the datagram tag */
502 tag = get_datagram_tag(frag->data + NET_6LO_FRAG_DATAGRAM_SIZE_LEN);
503
504 /* If there are no fragments in the cache means this frag
505 * is the first one. So cache Rx pkt otherwise not.
506 */
507 pkt->buffer = NULL;
508
509 fcache = get_reass_cache(size, tag);
510 if (!fcache) {
511 fcache = set_reass_cache(pkt, size, tag);
512 if (!fcache) {
513 NET_ERR("Could not get a cache entry");
514 pkt->buffer = frag;
515 return NET_DROP;
516 }
517
518 first_frag = true;
519 }
520
521 fragment_append(fcache->pkt, frag);
522
523 if (fragment_cached_pkt_len(fcache->pkt) == fcache->size) {
524 if (!first_frag) {
525 /* Assign buffer back to input packet. */
526 pkt->buffer = fcache->pkt->buffer;
527 fcache->pkt->buffer = NULL;
528 } else {
529 /* in case pkt == fcache->pkt, we don't want
530 * to unref it while clearing the cache.
531 */
532 fcache->pkt = NULL;
533 }
534
535 clear_reass_cache(size, tag);
536
537 if (!fragment_packet_valid(pkt)) {
538 NET_ERR("Invalid fragmented packet");
539 return NET_DROP;
540 }
541
542 fragment_reconstruct_packet(pkt);
543
544 if (!net_6lo_uncompress(pkt)) {
545 NET_ERR("Could not uncompress. Bogus packet?");
546 return NET_DROP;
547 }
548
549 net_pkt_cursor_init(pkt);
550
551 update_protocol_header_lengths(pkt, size);
552
553 net_pkt_cursor_init(pkt);
554
555 NET_DBG("All fragments received and reassembled");
556
557 return NET_CONTINUE;
558 }
559
560 /* Unref Rx part of original packet */
561 if (!first_frag) {
562 net_pkt_unref(pkt);
563 }
564
565 return NET_OK;
566 }
567
ieee802154_6lo_reassemble(struct net_pkt * pkt)568 enum net_verdict ieee802154_6lo_reassemble(struct net_pkt *pkt)
569 {
570 if (!pkt || !pkt->buffer) {
571 NET_ERR("Nothing to reassemble");
572 return NET_DROP;
573 }
574
575 if (get_datagram_type(pkt->buffer->data) >= NET_6LO_DISPATCH_FRAG1) {
576 return fragment_add_to_cache(pkt);
577 } else {
578 NET_DBG("No frag dispatch (%02x)", pkt->buffer->data[0]);
579 /* Received unfragmented packet, uncompress */
580 if (net_6lo_uncompress(pkt)) {
581 return NET_CONTINUE;
582 }
583
584 NET_ERR("Could not uncompress. Bogus packet?");
585 }
586
587 return NET_DROP;
588 }
589