1 /** @file
2 @brief Network packet buffers for IP stack
3
4 Network data is passed between components using net_pkt.
5 */
6
7 /*
8 * Copyright (c) 2016 Intel Corporation
9 *
10 * SPDX-License-Identifier: Apache-2.0
11 */
12
13 #include <zephyr/logging/log.h>
14 LOG_MODULE_REGISTER(net_pkt, CONFIG_NET_PKT_LOG_LEVEL);
15
16 /* This enables allocation debugging but does not print so much output
17 * as that can slow things down a lot.
18 */
19 #undef NET_LOG_LEVEL
20 #if defined(CONFIG_NET_DEBUG_NET_PKT_ALLOC)
21 #define NET_LOG_LEVEL 5
22 #else
23 #define NET_LOG_LEVEL CONFIG_NET_PKT_LOG_LEVEL
24 #endif
25
26 #include <zephyr/kernel.h>
27 #include <zephyr/toolchain.h>
28 #include <string.h>
29 #include <zephyr/types.h>
30 #include <sys/types.h>
31
32 #include <zephyr/sys/util.h>
33
34 #include <zephyr/net/net_core.h>
35 #include <zephyr/net/net_ip.h>
36 #include <zephyr/net/buf.h>
37 #include <zephyr/net/net_pkt.h>
38 #include <zephyr/net/ethernet.h>
39 #include <zephyr/net/udp.h>
40
41 #include "net_private.h"
42 #include "tcp_internal.h"
43
44 /* Find max header size of IP protocol (IPv4 or IPv6) */
45 #if defined(CONFIG_NET_IPV6) || defined(CONFIG_NET_RAW_MODE) || \
46 defined(CONFIG_NET_SOCKETS_PACKET) || defined(CONFIG_NET_SOCKETS_OFFLOAD)
47 #define MAX_IP_PROTO_LEN NET_IPV6H_LEN
48 #else
49 #if defined(CONFIG_NET_IPV4)
50 #define MAX_IP_PROTO_LEN NET_IPV4H_LEN
51 #else
52 #if defined(CONFIG_NET_SOCKETS_CAN)
53 /* TODO: Use CAN MTU here instead of hard coded value. There was
54 * weird circular dependency issue so this needs more TLC.
55 */
56 #define MAX_IP_PROTO_LEN 8
57 #else
58 #if defined(CONFIG_NET_ETHERNET_BRIDGE) || \
59 defined(CONFIG_NET_L2_IEEE802154) || \
60 defined(CONFIG_NET_L2_CUSTOM_IEEE802154)
61 #define MAX_IP_PROTO_LEN 0
62 #else
63 #error "Some packet protocol (e.g. IPv6, IPv4, ETH, IEEE 802.15.4) needs to be selected."
64 #endif /* ETHERNET_BRIDGE / L2_IEEE802154 */
65 #endif /* SOCKETS_CAN */
66 #endif /* IPv4 */
67 #endif /* IPv6 */
68
69 /* Find max header size of "next" protocol (TCP, UDP or ICMP) */
70 #if defined(CONFIG_NET_TCP)
71 #define MAX_NEXT_PROTO_LEN NET_TCPH_LEN
72 #else
73 #if defined(CONFIG_NET_UDP)
74 #define MAX_NEXT_PROTO_LEN NET_UDPH_LEN
75 #else
76 #if defined(CONFIG_NET_SOCKETS_CAN)
77 #define MAX_NEXT_PROTO_LEN 0
78 #else
79 /* If no TCP and no UDP, apparently we still want pings to work. */
80 #define MAX_NEXT_PROTO_LEN NET_ICMPH_LEN
81 #endif /* SOCKETS_CAN */
82 #endif /* UDP */
83 #endif /* TCP */
84
85 /* Make sure that IP + TCP/UDP/ICMP headers fit into one fragment. This
86 * makes possible to cast a fragment pointer to protocol header struct.
87 */
88 #if defined(CONFIG_NET_BUF_FIXED_DATA_SIZE)
89 #if CONFIG_NET_BUF_DATA_SIZE < (MAX_IP_PROTO_LEN + MAX_NEXT_PROTO_LEN)
90 #if defined(STRING2)
91 #undef STRING2
92 #endif
93 #if defined(STRING)
94 #undef STRING
95 #endif
96 #define STRING2(x) #x
97 #define STRING(x) STRING2(x)
98 #pragma message "Data len " STRING(CONFIG_NET_BUF_DATA_SIZE)
99 #pragma message "Minimum len " STRING(MAX_IP_PROTO_LEN + MAX_NEXT_PROTO_LEN)
100 #error "Too small net_buf fragment size"
101 #endif
102 #endif /* CONFIG_NET_BUF_FIXED_DATA_SIZE */
103
104 #if CONFIG_NET_PKT_RX_COUNT <= 0
105 #error "Minimum value for CONFIG_NET_PKT_RX_COUNT is 1"
106 #endif
107
108 #if CONFIG_NET_PKT_TX_COUNT <= 0
109 #error "Minimum value for CONFIG_NET_PKT_TX_COUNT is 1"
110 #endif
111
112 #if CONFIG_NET_BUF_RX_COUNT <= 0
113 #error "Minimum value for CONFIG_NET_BUF_RX_COUNT is 1"
114 #endif
115
116 #if CONFIG_NET_BUF_TX_COUNT <= 0
117 #error "Minimum value for CONFIG_NET_BUF_TX_COUNT is 1"
118 #endif
119
120 K_MEM_SLAB_DEFINE(rx_pkts, sizeof(struct net_pkt), CONFIG_NET_PKT_RX_COUNT, 4);
121 K_MEM_SLAB_DEFINE(tx_pkts, sizeof(struct net_pkt), CONFIG_NET_PKT_TX_COUNT, 4);
122
123 #if defined(CONFIG_NET_BUF_FIXED_DATA_SIZE)
124
125 NET_BUF_POOL_FIXED_DEFINE(rx_bufs, CONFIG_NET_BUF_RX_COUNT, CONFIG_NET_BUF_DATA_SIZE,
126 CONFIG_NET_PKT_BUF_USER_DATA_SIZE, NULL);
127 NET_BUF_POOL_FIXED_DEFINE(tx_bufs, CONFIG_NET_BUF_TX_COUNT, CONFIG_NET_BUF_DATA_SIZE,
128 CONFIG_NET_PKT_BUF_USER_DATA_SIZE, NULL);
129
130 #else /* !CONFIG_NET_BUF_FIXED_DATA_SIZE */
131
132 NET_BUF_POOL_VAR_DEFINE(rx_bufs, CONFIG_NET_BUF_RX_COUNT, CONFIG_NET_BUF_DATA_POOL_SIZE,
133 CONFIG_NET_PKT_BUF_USER_DATA_SIZE, NULL);
134 NET_BUF_POOL_VAR_DEFINE(tx_bufs, CONFIG_NET_BUF_TX_COUNT, CONFIG_NET_BUF_DATA_POOL_SIZE,
135 CONFIG_NET_PKT_BUF_USER_DATA_SIZE, NULL);
136
137 #endif /* CONFIG_NET_BUF_FIXED_DATA_SIZE */
138
139 /* Allocation tracking is only available if separately enabled */
140 #if defined(CONFIG_NET_DEBUG_NET_PKT_ALLOC)
141 struct net_pkt_alloc {
142 union {
143 struct net_pkt *pkt;
144 struct net_buf *buf;
145 void *alloc_data;
146 };
147 const char *func_alloc;
148 const char *func_free;
149 uint16_t line_alloc;
150 uint16_t line_free;
151 uint8_t in_use;
152 bool is_pkt;
153 };
154
155 #define MAX_NET_PKT_ALLOCS (CONFIG_NET_PKT_RX_COUNT + \
156 CONFIG_NET_PKT_TX_COUNT + \
157 CONFIG_NET_BUF_RX_COUNT + \
158 CONFIG_NET_BUF_TX_COUNT + \
159 CONFIG_NET_DEBUG_NET_PKT_EXTERNALS)
160
161 static struct net_pkt_alloc net_pkt_allocs[MAX_NET_PKT_ALLOCS];
162
net_pkt_alloc_add(void * alloc_data,bool is_pkt,const char * func,int line)163 static void net_pkt_alloc_add(void *alloc_data, bool is_pkt,
164 const char *func, int line)
165 {
166 int i;
167
168 for (i = 0; i < MAX_NET_PKT_ALLOCS; i++) {
169 if (net_pkt_allocs[i].in_use) {
170 continue;
171 }
172
173 net_pkt_allocs[i].in_use = true;
174 net_pkt_allocs[i].is_pkt = is_pkt;
175 net_pkt_allocs[i].alloc_data = alloc_data;
176 net_pkt_allocs[i].func_alloc = func;
177 net_pkt_allocs[i].line_alloc = line;
178
179 return;
180 }
181 }
182
net_pkt_alloc_del(void * alloc_data,const char * func,int line)183 static void net_pkt_alloc_del(void *alloc_data, const char *func, int line)
184 {
185 int i;
186
187 for (i = 0; i < MAX_NET_PKT_ALLOCS; i++) {
188 if (net_pkt_allocs[i].in_use &&
189 net_pkt_allocs[i].alloc_data == alloc_data) {
190 net_pkt_allocs[i].func_free = func;
191 net_pkt_allocs[i].line_free = line;
192 net_pkt_allocs[i].in_use = false;
193
194 return;
195 }
196 }
197 }
198
net_pkt_alloc_find(void * alloc_data,const char ** func_free,int * line_free)199 static bool net_pkt_alloc_find(void *alloc_data,
200 const char **func_free,
201 int *line_free)
202 {
203 int i;
204
205 for (i = 0; i < MAX_NET_PKT_ALLOCS; i++) {
206 if (!net_pkt_allocs[i].in_use &&
207 net_pkt_allocs[i].alloc_data == alloc_data) {
208 *func_free = net_pkt_allocs[i].func_free;
209 *line_free = net_pkt_allocs[i].line_free;
210
211 return true;
212 }
213 }
214
215 return false;
216 }
217
net_pkt_allocs_foreach(net_pkt_allocs_cb_t cb,void * user_data)218 void net_pkt_allocs_foreach(net_pkt_allocs_cb_t cb, void *user_data)
219 {
220 int i;
221
222 for (i = 0; i < MAX_NET_PKT_ALLOCS; i++) {
223 if (net_pkt_allocs[i].in_use) {
224 cb(net_pkt_allocs[i].is_pkt ?
225 net_pkt_allocs[i].pkt : NULL,
226 net_pkt_allocs[i].is_pkt ?
227 NULL : net_pkt_allocs[i].buf,
228 net_pkt_allocs[i].func_alloc,
229 net_pkt_allocs[i].line_alloc,
230 net_pkt_allocs[i].func_free,
231 net_pkt_allocs[i].line_free,
232 net_pkt_allocs[i].in_use,
233 user_data);
234 }
235 }
236
237 for (i = 0; i < MAX_NET_PKT_ALLOCS; i++) {
238 if (!net_pkt_allocs[i].in_use) {
239 cb(net_pkt_allocs[i].is_pkt ?
240 net_pkt_allocs[i].pkt : NULL,
241 net_pkt_allocs[i].is_pkt ?
242 NULL : net_pkt_allocs[i].buf,
243 net_pkt_allocs[i].func_alloc,
244 net_pkt_allocs[i].line_alloc,
245 net_pkt_allocs[i].func_free,
246 net_pkt_allocs[i].line_free,
247 net_pkt_allocs[i].in_use,
248 user_data);
249 }
250 }
251 }
252 #else
253 #define net_pkt_alloc_add(alloc_data, is_pkt, func, line)
254 #define net_pkt_alloc_del(alloc_data, func, line)
255 #define net_pkt_alloc_find(alloc_data, func_free, line_free) false
256 #endif /* CONFIG_NET_DEBUG_NET_PKT_ALLOC */
257
258 #if defined(NET_PKT_DEBUG_ENABLED)
259
260 #define NET_FRAG_CHECK_IF_NOT_IN_USE(frag, ref) \
261 do { \
262 if (!(ref)) { \
263 NET_ERR("**ERROR** frag %p not in use (%s:%s():%d)", \
264 frag, __FILE__, __func__, __LINE__); \
265 } \
266 } while (0)
267
net_pkt_slab2str(struct k_mem_slab * slab)268 const char *net_pkt_slab2str(struct k_mem_slab *slab)
269 {
270 if (slab == &rx_pkts) {
271 return "RX";
272 } else if (slab == &tx_pkts) {
273 return "TX";
274 }
275
276 return "EXT";
277 }
278
net_pkt_pool2str(struct net_buf_pool * pool)279 const char *net_pkt_pool2str(struct net_buf_pool *pool)
280 {
281 if (pool == &rx_bufs) {
282 return "RDATA";
283 } else if (pool == &tx_bufs) {
284 return "TDATA";
285 }
286
287 return "EDATA";
288 }
289
get_frees(struct net_buf_pool * pool)290 static inline int16_t get_frees(struct net_buf_pool *pool)
291 {
292 #if defined(CONFIG_NET_BUF_POOL_USAGE)
293 return atomic_get(&pool->avail_count);
294 #else
295 return 0;
296 #endif
297 }
298
net_pkt_print_frags(struct net_pkt * pkt)299 void net_pkt_print_frags(struct net_pkt *pkt)
300 {
301 struct net_buf *frag;
302 size_t total = 0;
303 int count = 0, frag_size = 0;
304
305 if (!pkt) {
306 NET_INFO("pkt %p", pkt);
307 return;
308 }
309
310 NET_INFO("pkt %p frags %p", pkt, pkt->frags);
311
312 NET_ASSERT(pkt->frags);
313
314 frag = pkt->frags;
315 while (frag) {
316 total += frag->len;
317
318 frag_size = frag->size;
319
320 NET_INFO("[%d] frag %p len %d max len %u size %d pool %p",
321 count, frag, frag->len, net_buf_max_len(frag),
322 frag_size, net_buf_pool_get(frag->pool_id));
323
324 count++;
325
326 frag = frag->frags;
327 }
328
329 NET_INFO("Total data size %zu, occupied %d bytes, utilization %zu%%",
330 total, count * frag_size,
331 count ? (total * 100) / (count * frag_size) : 0);
332 }
333 #endif
334
335 #if CONFIG_NET_PKT_LOG_LEVEL >= LOG_LEVEL_DBG
get_name(struct net_buf_pool * pool)336 static inline const char *get_name(struct net_buf_pool *pool)
337 {
338 #if defined(CONFIG_NET_BUF_POOL_USAGE)
339 return pool->name;
340 #else
341 return "?";
342 #endif
343 }
344
get_size(struct net_buf_pool * pool)345 static inline int16_t get_size(struct net_buf_pool *pool)
346 {
347 #if defined(CONFIG_NET_BUF_POOL_USAGE)
348 return pool->pool_size;
349 #else
350 return 0;
351 #endif
352 }
353
slab2str(struct k_mem_slab * slab)354 static inline const char *slab2str(struct k_mem_slab *slab)
355 {
356 return net_pkt_slab2str(slab);
357 }
358
pool2str(struct net_buf_pool * pool)359 static inline const char *pool2str(struct net_buf_pool *pool)
360 {
361 return net_pkt_pool2str(pool);
362 }
363 #endif /* CONFIG_NET_PKT_LOG_LEVEL >= LOG_LEVEL_DBG */
364
365 #if NET_LOG_LEVEL >= LOG_LEVEL_DBG
net_pkt_get_reserve_data_debug(struct net_buf_pool * pool,size_t min_len,k_timeout_t timeout,const char * caller,int line)366 struct net_buf *net_pkt_get_reserve_data_debug(struct net_buf_pool *pool,
367 size_t min_len,
368 k_timeout_t timeout,
369 const char *caller,
370 int line)
371 #else /* NET_LOG_LEVEL >= LOG_LEVEL_DBG */
372 struct net_buf *net_pkt_get_reserve_data(struct net_buf_pool *pool,
373 size_t min_len, k_timeout_t timeout)
374 #endif /* NET_LOG_LEVEL >= LOG_LEVEL_DBG */
375 {
376 struct net_buf *frag;
377
378 if (k_is_in_isr()) {
379 timeout = K_NO_WAIT;
380 }
381
382 #if defined(CONFIG_NET_BUF_FIXED_DATA_SIZE)
383 if (min_len > CONFIG_NET_BUF_DATA_SIZE) {
384 NET_ERR("Requested too large fragment. Increase CONFIG_NET_BUF_DATA_SIZE.");
385 return NULL;
386 }
387
388 frag = net_buf_alloc(pool, timeout);
389 #else
390 frag = net_buf_alloc_len(pool, min_len, timeout);
391 #endif /* CONFIG_NET_BUF_FIXED_DATA_SIZE */
392
393 if (!frag) {
394 return NULL;
395 }
396
397 #if NET_LOG_LEVEL >= LOG_LEVEL_DBG
398 NET_FRAG_CHECK_IF_NOT_IN_USE(frag, frag->ref + 1U);
399 #endif
400
401 net_pkt_alloc_add(frag, false, caller, line);
402
403 #if CONFIG_NET_PKT_LOG_LEVEL >= LOG_LEVEL_DBG
404 NET_DBG("%s (%s) [%d] frag %p ref %d (%s():%d)",
405 pool2str(pool), get_name(pool), get_frees(pool),
406 frag, frag->ref, caller, line);
407 #endif
408
409 return frag;
410 }
411
412 /* Get a fragment, try to figure out the pool from where to get
413 * the data.
414 */
415 #if NET_LOG_LEVEL >= LOG_LEVEL_DBG
net_pkt_get_frag_debug(struct net_pkt * pkt,size_t min_len,k_timeout_t timeout,const char * caller,int line)416 struct net_buf *net_pkt_get_frag_debug(struct net_pkt *pkt, size_t min_len,
417 k_timeout_t timeout,
418 const char *caller, int line)
419 #else
420 struct net_buf *net_pkt_get_frag(struct net_pkt *pkt, size_t min_len,
421 k_timeout_t timeout)
422 #endif
423 {
424 #if defined(CONFIG_NET_CONTEXT_NET_PKT_POOL)
425 struct net_context *context;
426
427 context = net_pkt_context(pkt);
428 if (context && context->data_pool) {
429 #if NET_LOG_LEVEL >= LOG_LEVEL_DBG
430 return net_pkt_get_reserve_data_debug(context->data_pool(),
431 min_len, timeout,
432 caller, line);
433 #else
434 return net_pkt_get_reserve_data(context->data_pool(), min_len,
435 timeout);
436 #endif /* NET_LOG_LEVEL >= LOG_LEVEL_DBG */
437 }
438 #endif /* CONFIG_NET_CONTEXT_NET_PKT_POOL */
439
440 if (pkt->slab == &rx_pkts) {
441 #if NET_LOG_LEVEL >= LOG_LEVEL_DBG
442 return net_pkt_get_reserve_rx_data_debug(min_len, timeout,
443 caller, line);
444 #else
445 return net_pkt_get_reserve_rx_data(min_len, timeout);
446 #endif
447 }
448
449 #if NET_LOG_LEVEL >= LOG_LEVEL_DBG
450 return net_pkt_get_reserve_tx_data_debug(min_len, timeout, caller, line);
451 #else
452 return net_pkt_get_reserve_tx_data(min_len, timeout);
453 #endif
454 }
455
456 #if NET_LOG_LEVEL >= LOG_LEVEL_DBG
net_pkt_get_reserve_rx_data_debug(size_t min_len,k_timeout_t timeout,const char * caller,int line)457 struct net_buf *net_pkt_get_reserve_rx_data_debug(size_t min_len, k_timeout_t timeout,
458 const char *caller, int line)
459 {
460 return net_pkt_get_reserve_data_debug(&rx_bufs, min_len, timeout, caller, line);
461 }
462
net_pkt_get_reserve_tx_data_debug(size_t min_len,k_timeout_t timeout,const char * caller,int line)463 struct net_buf *net_pkt_get_reserve_tx_data_debug(size_t min_len, k_timeout_t timeout,
464 const char *caller, int line)
465 {
466 return net_pkt_get_reserve_data_debug(&tx_bufs, min_len, timeout, caller, line);
467 }
468
469 #else /* NET_LOG_LEVEL >= LOG_LEVEL_DBG */
470
net_pkt_get_reserve_rx_data(size_t min_len,k_timeout_t timeout)471 struct net_buf *net_pkt_get_reserve_rx_data(size_t min_len, k_timeout_t timeout)
472 {
473 return net_pkt_get_reserve_data(&rx_bufs, min_len, timeout);
474 }
475
net_pkt_get_reserve_tx_data(size_t min_len,k_timeout_t timeout)476 struct net_buf *net_pkt_get_reserve_tx_data(size_t min_len, k_timeout_t timeout)
477 {
478 return net_pkt_get_reserve_data(&tx_bufs, min_len, timeout);
479 }
480
481 #endif /* NET_LOG_LEVEL >= LOG_LEVEL_DBG */
482
483
484 #if defined(CONFIG_NET_CONTEXT_NET_PKT_POOL)
get_tx_slab(struct net_context * context)485 static inline struct k_mem_slab *get_tx_slab(struct net_context *context)
486 {
487 if (context->tx_slab) {
488 return context->tx_slab();
489 }
490
491 return NULL;
492 }
493
get_data_pool(struct net_context * context)494 static inline struct net_buf_pool *get_data_pool(struct net_context *context)
495 {
496 if (context->data_pool) {
497 return context->data_pool();
498 }
499
500 return NULL;
501 }
502 #else
503 #define get_tx_slab(...) NULL
504 #define get_data_pool(...) NULL
505 #endif /* CONFIG_NET_CONTEXT_NET_PKT_POOL */
506
507 #if NET_LOG_LEVEL >= LOG_LEVEL_DBG
net_pkt_unref_debug(struct net_pkt * pkt,const char * caller,int line)508 void net_pkt_unref_debug(struct net_pkt *pkt, const char *caller, int line)
509 {
510 struct net_buf *frag;
511
512 #else
513 void net_pkt_unref(struct net_pkt *pkt)
514 {
515 #endif /* NET_LOG_LEVEL >= LOG_LEVEL_DBG */
516 atomic_val_t ref;
517
518 if (!pkt) {
519 #if NET_LOG_LEVEL >= LOG_LEVEL_DBG
520 NET_ERR("*** ERROR *** pkt %p (%s():%d)", pkt, caller, line);
521 #endif
522 return;
523 }
524
525 do {
526 ref = atomic_get(&pkt->atomic_ref);
527 if (!ref) {
528 #if NET_LOG_LEVEL >= LOG_LEVEL_DBG
529 const char *func_freed;
530 int line_freed;
531
532 if (net_pkt_alloc_find(pkt, &func_freed, &line_freed)) {
533 NET_ERR("*** ERROR *** pkt %p is freed already "
534 "by %s():%d (%s():%d)",
535 pkt, func_freed, line_freed, caller,
536 line);
537 } else {
538 NET_ERR("*** ERROR *** pkt %p is freed already "
539 "(%s():%d)", pkt, caller, line);
540 }
541 #endif
542 return;
543 }
544 } while (!atomic_cas(&pkt->atomic_ref, ref, ref - 1));
545
546 #if NET_LOG_LEVEL >= LOG_LEVEL_DBG
547 #if CONFIG_NET_PKT_LOG_LEVEL >= LOG_LEVEL_DBG
548 NET_DBG("%s [%d] pkt %p ref %ld frags %p (%s():%d)",
549 slab2str(pkt->slab), k_mem_slab_num_free_get(pkt->slab),
550 pkt, ref - 1, pkt->frags, caller, line);
551 #endif
552 if (ref > 1) {
553 goto done;
554 }
555
556 frag = pkt->frags;
557 while (frag) {
558 #if CONFIG_NET_PKT_LOG_LEVEL >= LOG_LEVEL_DBG
559 NET_DBG("%s (%s) [%d] frag %p ref %d frags %p (%s():%d)",
560 pool2str(net_buf_pool_get(frag->pool_id)),
561 get_name(net_buf_pool_get(frag->pool_id)),
562 get_frees(net_buf_pool_get(frag->pool_id)), frag,
563 frag->ref - 1U, frag->frags, caller, line);
564 #endif
565
566 if (!frag->ref) {
567 const char *func_freed;
568 int line_freed;
569
570 if (net_pkt_alloc_find(frag,
571 &func_freed, &line_freed)) {
572 NET_ERR("*** ERROR *** frag %p is freed "
573 "already by %s():%d (%s():%d)",
574 frag, func_freed, line_freed,
575 caller, line);
576 } else {
577 NET_ERR("*** ERROR *** frag %p is freed "
578 "already (%s():%d)",
579 frag, caller, line);
580 }
581 }
582
583 net_pkt_alloc_del(frag, caller, line);
584
585 frag = frag->frags;
586 }
587
588 net_pkt_alloc_del(pkt, caller, line);
589 done:
590 #endif /* NET_LOG_LEVEL >= LOG_LEVEL_DBG */
591
592 if (ref > 1) {
593 return;
594 }
595
596 if (pkt->frags) {
597 net_pkt_frag_unref(pkt->frags);
598 }
599
600 if (IS_ENABLED(CONFIG_NET_DEBUG_NET_PKT_NON_FRAGILE_ACCESS)) {
601 pkt->buffer = NULL;
602 net_pkt_cursor_init(pkt);
603 }
604
605 k_mem_slab_free(pkt->slab, (void *)pkt);
606 }
607
608 #if NET_LOG_LEVEL >= LOG_LEVEL_DBG
609 struct net_pkt *net_pkt_ref_debug(struct net_pkt *pkt, const char *caller,
610 int line)
611 #else
612 struct net_pkt *net_pkt_ref(struct net_pkt *pkt)
613 #endif /* NET_LOG_LEVEL >= LOG_LEVEL_DBG */
614 {
615 atomic_val_t ref;
616
617 do {
618 ref = pkt ? atomic_get(&pkt->atomic_ref) : 0;
619 if (!ref) {
620 #if NET_LOG_LEVEL >= LOG_LEVEL_DBG
621 NET_ERR("*** ERROR *** pkt %p (%s():%d)",
622 pkt, caller, line);
623 #endif
624 return NULL;
625 }
626 } while (!atomic_cas(&pkt->atomic_ref, ref, ref + 1));
627
628 #if CONFIG_NET_PKT_LOG_LEVEL >= LOG_LEVEL_DBG
629 NET_DBG("%s [%d] pkt %p ref %ld (%s():%d)",
630 slab2str(pkt->slab), k_mem_slab_num_free_get(pkt->slab),
631 pkt, ref + 1, caller, line);
632 #endif
633
634
635 return pkt;
636 }
637
638 #if NET_LOG_LEVEL >= LOG_LEVEL_DBG
639 struct net_buf *net_pkt_frag_ref_debug(struct net_buf *frag,
640 const char *caller, int line)
641 #else
642 struct net_buf *net_pkt_frag_ref(struct net_buf *frag)
643 #endif /* NET_LOG_LEVEL >= LOG_LEVEL_DBG */
644 {
645 if (!frag) {
646 #if NET_LOG_LEVEL >= LOG_LEVEL_DBG
647 NET_ERR("*** ERROR *** frag %p (%s():%d)", frag, caller, line);
648 #endif
649 return NULL;
650 }
651
652 #if CONFIG_NET_PKT_LOG_LEVEL >= LOG_LEVEL_DBG
653 NET_DBG("%s (%s) [%d] frag %p ref %d (%s():%d)",
654 pool2str(net_buf_pool_get(frag->pool_id)),
655 get_name(net_buf_pool_get(frag->pool_id)),
656 get_frees(net_buf_pool_get(frag->pool_id)),
657 frag, frag->ref + 1U, caller, line);
658 #endif
659
660 return net_buf_ref(frag);
661 }
662
663
664 #if NET_LOG_LEVEL >= LOG_LEVEL_DBG
665 void net_pkt_frag_unref_debug(struct net_buf *frag,
666 const char *caller, int line)
667 #else
668 void net_pkt_frag_unref(struct net_buf *frag)
669 #endif /* NET_LOG_LEVEL >= LOG_LEVEL_DBG */
670 {
671 if (!frag) {
672 #if NET_LOG_LEVEL >= LOG_LEVEL_DBG
673 NET_ERR("*** ERROR *** frag %p (%s():%d)", frag, caller, line);
674 #endif
675 return;
676 }
677
678 #if CONFIG_NET_PKT_LOG_LEVEL >= LOG_LEVEL_DBG
679 NET_DBG("%s (%s) [%d] frag %p ref %d (%s():%d)",
680 pool2str(net_buf_pool_get(frag->pool_id)),
681 get_name(net_buf_pool_get(frag->pool_id)),
682 get_frees(net_buf_pool_get(frag->pool_id)),
683 frag, frag->ref - 1U, caller, line);
684 #endif
685
686 if (frag->ref == 1U) {
687 net_pkt_alloc_del(frag, caller, line);
688 }
689
690 net_buf_unref(frag);
691 }
692
693 #if NET_LOG_LEVEL >= LOG_LEVEL_DBG
694 struct net_buf *net_pkt_frag_del_debug(struct net_pkt *pkt,
695 struct net_buf *parent,
696 struct net_buf *frag,
697 const char *caller, int line)
698 #else
699 struct net_buf *net_pkt_frag_del(struct net_pkt *pkt,
700 struct net_buf *parent,
701 struct net_buf *frag)
702 #endif
703 {
704 #if CONFIG_NET_PKT_LOG_LEVEL >= LOG_LEVEL_DBG
705 NET_DBG("pkt %p parent %p frag %p ref %u (%s:%d)",
706 pkt, parent, frag, frag->ref, caller, line);
707 #endif
708
709 if (pkt->frags == frag && !parent) {
710 struct net_buf *tmp;
711
712 if (frag->ref == 1U) {
713 net_pkt_alloc_del(frag, caller, line);
714 }
715
716 tmp = net_buf_frag_del(NULL, frag);
717 pkt->frags = tmp;
718
719 return tmp;
720 }
721
722 if (frag->ref == 1U) {
723 net_pkt_alloc_del(frag, caller, line);
724 }
725
726 return net_buf_frag_del(parent, frag);
727 }
728
729 #if NET_LOG_LEVEL >= LOG_LEVEL_DBG
730 void net_pkt_frag_add_debug(struct net_pkt *pkt, struct net_buf *frag,
731 const char *caller, int line)
732 #else
733 void net_pkt_frag_add(struct net_pkt *pkt, struct net_buf *frag)
734 #endif
735 {
736 #if CONFIG_NET_PKT_LOG_LEVEL >= LOG_LEVEL_DBG
737 NET_DBG("pkt %p frag %p (%s:%d)", pkt, frag, caller, line);
738 #endif
739
740 /* We do not use net_buf_frag_add() as this one will refcount
741 * the frag once more if !pkt->frags
742 */
743 if (!pkt->frags) {
744 pkt->frags = frag;
745 return;
746 }
747
748 net_buf_frag_insert(net_buf_frag_last(pkt->frags), frag);
749 }
750
751 #if NET_LOG_LEVEL >= LOG_LEVEL_DBG
752 void net_pkt_frag_insert_debug(struct net_pkt *pkt, struct net_buf *frag,
753 const char *caller, int line)
754 #else
755 void net_pkt_frag_insert(struct net_pkt *pkt, struct net_buf *frag)
756 #endif
757 {
758 #if CONFIG_NET_PKT_LOG_LEVEL >= LOG_LEVEL_DBG
759 NET_DBG("pkt %p frag %p (%s:%d)", pkt, frag, caller, line);
760 #endif
761
762 net_buf_frag_last(frag)->frags = pkt->frags;
763 pkt->frags = frag;
764 }
765
766 void net_pkt_compact(struct net_pkt *pkt)
767 {
768 struct net_buf *frag, *prev;
769
770 NET_DBG("Compacting data in pkt %p", pkt);
771
772 frag = pkt->frags;
773 prev = NULL;
774
775 while (frag) {
776 if (frag->frags) {
777 /* Copy amount of data from next fragment to this
778 * fragment.
779 */
780 size_t copy_len;
781
782 copy_len = frag->frags->len;
783 if (copy_len > net_buf_tailroom(frag)) {
784 copy_len = net_buf_tailroom(frag);
785 }
786
787 memcpy(net_buf_tail(frag), frag->frags->data, copy_len);
788 net_buf_add(frag, copy_len);
789
790 memmove(frag->frags->data,
791 frag->frags->data + copy_len,
792 frag->frags->len - copy_len);
793
794 frag->frags->len -= copy_len;
795
796 /* Is there any more space in this fragment */
797 if (net_buf_tailroom(frag)) {
798 /* There is. This also means that the next
799 * fragment is empty as otherwise we could
800 * not have copied all data. Remove next
801 * fragment as there is no data in it any more.
802 */
803 net_pkt_frag_del(pkt, frag, frag->frags);
804
805 /* Then check next fragment */
806 continue;
807 }
808 } else {
809 if (!frag->len) {
810 /* Remove the last fragment because there is no
811 * data in it.
812 */
813 net_pkt_frag_del(pkt, prev, frag);
814
815 break;
816 }
817 }
818
819 prev = frag;
820 frag = frag->frags;
821 }
822 }
823
824 void net_pkt_get_info(struct k_mem_slab **rx,
825 struct k_mem_slab **tx,
826 struct net_buf_pool **rx_data,
827 struct net_buf_pool **tx_data)
828 {
829 if (rx) {
830 *rx = &rx_pkts;
831 }
832
833 if (tx) {
834 *tx = &tx_pkts;
835 }
836
837 if (rx_data) {
838 *rx_data = &rx_bufs;
839 }
840
841 if (tx_data) {
842 *tx_data = &tx_bufs;
843 }
844 }
845
846 #if defined(CONFIG_NET_DEBUG_NET_PKT_ALLOC)
847 void net_pkt_print(void)
848 {
849 NET_DBG("TX %u RX %u RDATA %d TDATA %d",
850 k_mem_slab_num_free_get(&tx_pkts),
851 k_mem_slab_num_free_get(&rx_pkts),
852 get_frees(&rx_bufs), get_frees(&tx_bufs));
853 }
854 #endif /* CONFIG_NET_DEBUG_NET_PKT_ALLOC */
855
856 /* New allocator and API starts here */
857
858 #if defined(CONFIG_NET_BUF_FIXED_DATA_SIZE)
859
860 #if NET_LOG_LEVEL >= LOG_LEVEL_DBG
861 static struct net_buf *pkt_alloc_buffer(struct net_buf_pool *pool,
862 size_t size, k_timeout_t timeout,
863 const char *caller, int line)
864 #else
865 static struct net_buf *pkt_alloc_buffer(struct net_buf_pool *pool,
866 size_t size, k_timeout_t timeout)
867 #endif
868 {
869 k_timepoint_t end = sys_timepoint_calc(timeout);
870 struct net_buf *first = NULL;
871 struct net_buf *current = NULL;
872
873 do {
874 struct net_buf *new;
875
876 new = net_buf_alloc_fixed(pool, timeout);
877 if (!new) {
878 goto error;
879 }
880
881 if (!first && !current) {
882 first = new;
883 } else {
884 current->frags = new;
885 }
886
887 current = new;
888 if (current->size > size) {
889 current->size = size;
890 }
891
892 size -= current->size;
893
894 timeout = sys_timepoint_timeout(end);
895
896 #if CONFIG_NET_PKT_LOG_LEVEL >= LOG_LEVEL_DBG
897 NET_FRAG_CHECK_IF_NOT_IN_USE(new, new->ref + 1);
898
899 net_pkt_alloc_add(new, false, caller, line);
900
901 NET_DBG("%s (%s) [%d] frag %p ref %d (%s():%d)",
902 pool2str(pool), get_name(pool), get_frees(pool),
903 new, new->ref, caller, line);
904 #endif
905 } while (size);
906
907 return first;
908 error:
909 if (first) {
910 net_buf_unref(first);
911 }
912
913 return NULL;
914 }
915
916 #else /* !CONFIG_NET_BUF_FIXED_DATA_SIZE */
917
918 #if NET_LOG_LEVEL >= LOG_LEVEL_DBG
919 static struct net_buf *pkt_alloc_buffer(struct net_buf_pool *pool,
920 size_t size, k_timeout_t timeout,
921 const char *caller, int line)
922 #else
923 static struct net_buf *pkt_alloc_buffer(struct net_buf_pool *pool,
924 size_t size, k_timeout_t timeout)
925 #endif
926 {
927 struct net_buf *buf;
928
929 buf = net_buf_alloc_len(pool, size, timeout);
930
931 #if CONFIG_NET_PKT_LOG_LEVEL >= LOG_LEVEL_DBG
932 NET_FRAG_CHECK_IF_NOT_IN_USE(buf, buf->ref + 1);
933
934 net_pkt_alloc_add(buf, false, caller, line);
935
936 NET_DBG("%s (%s) [%d] frag %p ref %d (%s():%d)",
937 pool2str(pool), get_name(pool), get_frees(pool),
938 buf, buf->ref, caller, line);
939 #endif
940
941 return buf;
942 }
943
944 #endif /* CONFIG_NET_BUF_FIXED_DATA_SIZE */
945
946 static size_t pkt_buffer_length(struct net_pkt *pkt,
947 size_t size,
948 enum net_ip_protocol proto,
949 size_t existing)
950 {
951 sa_family_t family = net_pkt_family(pkt);
952 size_t max_len;
953
954 if (net_pkt_iface(pkt)) {
955 max_len = net_if_get_mtu(net_pkt_iface(pkt));
956 } else {
957 max_len = 0;
958 }
959
960 /* Family vs iface MTU */
961 if (IS_ENABLED(CONFIG_NET_IPV6) && family == AF_INET6) {
962 if (IS_ENABLED(CONFIG_NET_IPV6_FRAGMENT) && (size > max_len)) {
963 /* We support larger packets if IPv6 fragmentation is
964 * enabled.
965 */
966 max_len = size;
967 }
968
969 max_len = MAX(max_len, NET_IPV6_MTU);
970 } else if (IS_ENABLED(CONFIG_NET_IPV4) && family == AF_INET) {
971 if (IS_ENABLED(CONFIG_NET_IPV4_FRAGMENT) && (size > max_len)) {
972 /* We support larger packets if IPv4 fragmentation is enabled */
973 max_len = size;
974 }
975
976 max_len = MAX(max_len, NET_IPV4_MTU);
977 } else { /* family == AF_UNSPEC */
978 #if defined (CONFIG_NET_L2_ETHERNET)
979 if (net_if_l2(net_pkt_iface(pkt)) ==
980 &NET_L2_GET_NAME(ETHERNET)) {
981 max_len += NET_ETH_MAX_HDR_SIZE;
982 } else
983 #endif /* CONFIG_NET_L2_ETHERNET */
984 {
985 /* Other L2 are not checked as the pkt MTU in this case
986 * is based on the IP layer (IPv6 most of the time).
987 */
988 max_len = size;
989 }
990 }
991
992 max_len -= existing;
993
994 return MIN(size, max_len);
995 }
996
997 static size_t pkt_estimate_headers_length(struct net_pkt *pkt,
998 sa_family_t family,
999 enum net_ip_protocol proto)
1000 {
1001 size_t hdr_len = 0;
1002
1003 if (family == AF_UNSPEC) {
1004 return 0;
1005 }
1006
1007 /* Family header */
1008 if (IS_ENABLED(CONFIG_NET_IPV6) && family == AF_INET6) {
1009 hdr_len += NET_IPV6H_LEN;
1010 } else if (IS_ENABLED(CONFIG_NET_IPV4) && family == AF_INET) {
1011 hdr_len += NET_IPV4H_LEN;
1012 }
1013
1014 /* + protocol header */
1015 if (IS_ENABLED(CONFIG_NET_TCP) && proto == IPPROTO_TCP) {
1016 hdr_len += NET_TCPH_LEN + NET_TCP_MAX_OPT_SIZE;
1017 } else if (IS_ENABLED(CONFIG_NET_UDP) && proto == IPPROTO_UDP) {
1018 hdr_len += NET_UDPH_LEN;
1019 } else if (proto == IPPROTO_ICMP || proto == IPPROTO_ICMPV6) {
1020 hdr_len += NET_ICMPH_LEN;
1021 }
1022
1023 NET_DBG("HDRs length estimation %zu", hdr_len);
1024
1025 return hdr_len;
1026 }
1027
1028 static size_t pkt_get_max_len(struct net_pkt *pkt)
1029 {
1030 struct net_buf *buf = pkt->buffer;
1031 size_t size = 0;
1032
1033 while (buf) {
1034 size += net_buf_max_len(buf);
1035 buf = buf->frags;
1036 }
1037
1038 return size;
1039 }
1040
1041 size_t net_pkt_available_buffer(struct net_pkt *pkt)
1042 {
1043 if (!pkt) {
1044 return 0;
1045 }
1046
1047 return pkt_get_max_len(pkt) - net_pkt_get_len(pkt);
1048 }
1049
1050 size_t net_pkt_available_payload_buffer(struct net_pkt *pkt,
1051 enum net_ip_protocol proto)
1052 {
1053 size_t hdr_len = 0;
1054 size_t len;
1055
1056 if (!pkt) {
1057 return 0;
1058 }
1059
1060 hdr_len = pkt_estimate_headers_length(pkt, net_pkt_family(pkt), proto);
1061 len = net_pkt_get_len(pkt);
1062
1063 hdr_len = hdr_len <= len ? 0 : hdr_len - len;
1064
1065 len = net_pkt_available_buffer(pkt) - hdr_len;
1066
1067 return len;
1068 }
1069
1070 void net_pkt_trim_buffer(struct net_pkt *pkt)
1071 {
1072 struct net_buf *buf, *prev;
1073
1074 buf = pkt->buffer;
1075 prev = buf;
1076
1077 while (buf) {
1078 struct net_buf *next = buf->frags;
1079
1080 if (!buf->len) {
1081 if (buf == pkt->buffer) {
1082 pkt->buffer = next;
1083 } else if (buf == prev->frags) {
1084 prev->frags = next;
1085 }
1086
1087 buf->frags = NULL;
1088 net_buf_unref(buf);
1089 } else {
1090 prev = buf;
1091 }
1092
1093 buf = next;
1094 }
1095 }
1096
1097 int net_pkt_remove_tail(struct net_pkt *pkt, size_t length)
1098 {
1099 struct net_buf *buf = pkt->buffer;
1100 size_t remaining_len = net_pkt_get_len(pkt);
1101
1102 if (remaining_len < length) {
1103 return -EINVAL;
1104 }
1105
1106 remaining_len -= length;
1107
1108 while (buf) {
1109 if (buf->len >= remaining_len) {
1110 buf->len = remaining_len;
1111
1112 if (buf->frags) {
1113 net_pkt_frag_unref(buf->frags);
1114 buf->frags = NULL;
1115 }
1116
1117 break;
1118 }
1119
1120 remaining_len -= buf->len;
1121 buf = buf->frags;
1122 }
1123
1124 return 0;
1125 }
1126
1127 #if NET_LOG_LEVEL >= LOG_LEVEL_DBG
1128 int net_pkt_alloc_buffer_debug(struct net_pkt *pkt,
1129 size_t size,
1130 enum net_ip_protocol proto,
1131 k_timeout_t timeout,
1132 const char *caller,
1133 int line)
1134 #else
1135 int net_pkt_alloc_buffer(struct net_pkt *pkt,
1136 size_t size,
1137 enum net_ip_protocol proto,
1138 k_timeout_t timeout)
1139 #endif
1140 {
1141 struct net_buf_pool *pool = NULL;
1142 size_t alloc_len = 0;
1143 size_t hdr_len = 0;
1144 struct net_buf *buf;
1145
1146 if (!size && proto == 0 && net_pkt_family(pkt) == AF_UNSPEC) {
1147 return 0;
1148 }
1149
1150 if (k_is_in_isr()) {
1151 timeout = K_NO_WAIT;
1152 }
1153
1154 /* Verifying existing buffer and take into account free space there */
1155 alloc_len = net_pkt_available_buffer(pkt);
1156 if (!alloc_len) {
1157 /* In case of no free space, it will account for header
1158 * space estimation
1159 */
1160 hdr_len = pkt_estimate_headers_length(pkt,
1161 net_pkt_family(pkt),
1162 proto);
1163 }
1164
1165 /* Calculate the maximum that can be allocated depending on size */
1166 alloc_len = pkt_buffer_length(pkt, size + hdr_len, proto, alloc_len);
1167
1168 NET_DBG("Data allocation maximum size %zu (requested %zu)",
1169 alloc_len, size);
1170
1171 if (pkt->context) {
1172 pool = get_data_pool(pkt->context);
1173 }
1174
1175 if (!pool) {
1176 pool = pkt->slab == &tx_pkts ? &tx_bufs : &rx_bufs;
1177 }
1178
1179 #if NET_LOG_LEVEL >= LOG_LEVEL_DBG
1180 buf = pkt_alloc_buffer(pool, alloc_len, timeout, caller, line);
1181 #else
1182 buf = pkt_alloc_buffer(pool, alloc_len, timeout);
1183 #endif
1184
1185 if (!buf) {
1186 #if NET_LOG_LEVEL >= LOG_LEVEL_DBG
1187 NET_ERR("Data buffer (%zd) allocation failed (%s:%d)",
1188 alloc_len, caller, line);
1189 #else
1190 NET_ERR("Data buffer (%zd) allocation failed.", alloc_len);
1191 #endif
1192 return -ENOMEM;
1193 }
1194
1195 net_pkt_append_buffer(pkt, buf);
1196
1197 return 0;
1198 }
1199
1200
1201 #if NET_LOG_LEVEL >= LOG_LEVEL_DBG
1202 int net_pkt_alloc_buffer_raw_debug(struct net_pkt *pkt, size_t size,
1203 k_timeout_t timeout, const char *caller,
1204 int line)
1205 #else
1206 int net_pkt_alloc_buffer_raw(struct net_pkt *pkt, size_t size,
1207 k_timeout_t timeout)
1208 #endif
1209 {
1210 struct net_buf_pool *pool = NULL;
1211 struct net_buf *buf;
1212
1213 if (size == 0) {
1214 return 0;
1215 }
1216
1217 if (k_is_in_isr()) {
1218 timeout = K_NO_WAIT;
1219 }
1220
1221 NET_DBG("Data allocation size %zu", size);
1222
1223 if (pkt->context) {
1224 pool = get_data_pool(pkt->context);
1225 }
1226
1227 if (!pool) {
1228 pool = pkt->slab == &tx_pkts ? &tx_bufs : &rx_bufs;
1229 }
1230
1231 #if NET_LOG_LEVEL >= LOG_LEVEL_DBG
1232 buf = pkt_alloc_buffer(pool, size, timeout, caller, line);
1233 #else
1234 buf = pkt_alloc_buffer(pool, size, timeout);
1235 #endif
1236
1237 if (!buf) {
1238 #if NET_LOG_LEVEL >= LOG_LEVEL_DBG
1239 NET_ERR("Data buffer (%zd) allocation failed (%s:%d)",
1240 size, caller, line);
1241 #else
1242 NET_ERR("Data buffer (%zd) allocation failed.", size);
1243 #endif
1244 return -ENOMEM;
1245 }
1246
1247 net_pkt_append_buffer(pkt, buf);
1248
1249 #if IS_ENABLED(CONFIG_NET_BUF_FIXED_DATA_SIZE)
1250 /* net_buf allocators shrink the buffer size to the requested size.
1251 * We don't want this behavior here, so restore the real size of the
1252 * last fragment.
1253 */
1254 buf = net_buf_frag_last(buf);
1255 buf->size = CONFIG_NET_BUF_DATA_SIZE;
1256 #endif
1257
1258 return 0;
1259 }
1260
1261 #if NET_LOG_LEVEL >= LOG_LEVEL_DBG
1262 static struct net_pkt *pkt_alloc(struct k_mem_slab *slab, k_timeout_t timeout,
1263 const char *caller, int line)
1264 #else
1265 static struct net_pkt *pkt_alloc(struct k_mem_slab *slab, k_timeout_t timeout)
1266 #endif
1267 {
1268 struct net_pkt *pkt;
1269 uint32_t create_time;
1270 int ret;
1271
1272 if (k_is_in_isr()) {
1273 timeout = K_NO_WAIT;
1274 }
1275
1276 if (IS_ENABLED(CONFIG_NET_PKT_RXTIME_STATS) ||
1277 IS_ENABLED(CONFIG_NET_PKT_TXTIME_STATS)) {
1278 create_time = k_cycle_get_32();
1279 } else {
1280 ARG_UNUSED(create_time);
1281 }
1282
1283 ret = k_mem_slab_alloc(slab, (void **)&pkt, timeout);
1284 if (ret) {
1285 return NULL;
1286 }
1287
1288 memset(pkt, 0, sizeof(struct net_pkt));
1289
1290 pkt->atomic_ref = ATOMIC_INIT(1);
1291 pkt->slab = slab;
1292
1293 if (IS_ENABLED(CONFIG_NET_IPV6)) {
1294 net_pkt_set_ipv6_next_hdr(pkt, 255);
1295 }
1296
1297 #if defined(CONFIG_NET_TX_DEFAULT_PRIORITY)
1298 #define TX_DEFAULT_PRIORITY CONFIG_NET_TX_DEFAULT_PRIORITY
1299 #else
1300 #define TX_DEFAULT_PRIORITY 0
1301 #endif
1302
1303 #if defined(CONFIG_NET_RX_DEFAULT_PRIORITY)
1304 #define RX_DEFAULT_PRIORITY CONFIG_NET_RX_DEFAULT_PRIORITY
1305 #else
1306 #define RX_DEFAULT_PRIORITY 0
1307 #endif
1308
1309 if (&tx_pkts == slab) {
1310 net_pkt_set_priority(pkt, TX_DEFAULT_PRIORITY);
1311 } else if (&rx_pkts == slab) {
1312 net_pkt_set_priority(pkt, RX_DEFAULT_PRIORITY);
1313 }
1314
1315 if (IS_ENABLED(CONFIG_NET_PKT_RXTIME_STATS) ||
1316 IS_ENABLED(CONFIG_NET_PKT_TXTIME_STATS)) {
1317 net_pkt_set_create_time(pkt, create_time);
1318 }
1319
1320 net_pkt_set_vlan_tag(pkt, NET_VLAN_TAG_UNSPEC);
1321
1322 #if NET_LOG_LEVEL >= LOG_LEVEL_DBG
1323 net_pkt_alloc_add(pkt, true, caller, line);
1324 #endif
1325
1326 net_pkt_cursor_init(pkt);
1327
1328 return pkt;
1329 }
1330
1331 #if NET_LOG_LEVEL >= LOG_LEVEL_DBG
1332 struct net_pkt *net_pkt_alloc_debug(k_timeout_t timeout,
1333 const char *caller, int line)
1334 #else
1335 struct net_pkt *net_pkt_alloc(k_timeout_t timeout)
1336 #endif
1337 {
1338 #if NET_LOG_LEVEL >= LOG_LEVEL_DBG
1339 return pkt_alloc(&tx_pkts, timeout, caller, line);
1340 #else
1341 return pkt_alloc(&tx_pkts, timeout);
1342 #endif
1343 }
1344
1345 #if NET_LOG_LEVEL >= LOG_LEVEL_DBG
1346 struct net_pkt *net_pkt_alloc_from_slab_debug(struct k_mem_slab *slab,
1347 k_timeout_t timeout,
1348 const char *caller, int line)
1349 #else
1350 struct net_pkt *net_pkt_alloc_from_slab(struct k_mem_slab *slab,
1351 k_timeout_t timeout)
1352 #endif
1353 {
1354 if (!slab) {
1355 return NULL;
1356 }
1357
1358 #if NET_LOG_LEVEL >= LOG_LEVEL_DBG
1359 return pkt_alloc(slab, timeout, caller, line);
1360 #else
1361 return pkt_alloc(slab, timeout);
1362 #endif
1363 }
1364
1365 #if NET_LOG_LEVEL >= LOG_LEVEL_DBG
1366 struct net_pkt *net_pkt_rx_alloc_debug(k_timeout_t timeout,
1367 const char *caller, int line)
1368 #else
1369 struct net_pkt *net_pkt_rx_alloc(k_timeout_t timeout)
1370 #endif
1371 {
1372 #if NET_LOG_LEVEL >= LOG_LEVEL_DBG
1373 return pkt_alloc(&rx_pkts, timeout, caller, line);
1374 #else
1375 return pkt_alloc(&rx_pkts, timeout);
1376 #endif
1377 }
1378
1379 #if NET_LOG_LEVEL >= LOG_LEVEL_DBG
1380 static struct net_pkt *pkt_alloc_on_iface(struct k_mem_slab *slab,
1381 struct net_if *iface,
1382 k_timeout_t timeout,
1383 const char *caller, int line)
1384 #else
1385 static struct net_pkt *pkt_alloc_on_iface(struct k_mem_slab *slab,
1386 struct net_if *iface,
1387 k_timeout_t timeout)
1388
1389 #endif
1390 {
1391 struct net_pkt *pkt;
1392
1393 #if NET_LOG_LEVEL >= LOG_LEVEL_DBG
1394 pkt = pkt_alloc(slab, timeout, caller, line);
1395 #else
1396 pkt = pkt_alloc(slab, timeout);
1397 #endif
1398
1399 if (pkt) {
1400 net_pkt_set_iface(pkt, iface);
1401 }
1402
1403 return pkt;
1404 }
1405
1406 #if NET_LOG_LEVEL >= LOG_LEVEL_DBG
1407 struct net_pkt *net_pkt_alloc_on_iface_debug(struct net_if *iface,
1408 k_timeout_t timeout,
1409 const char *caller,
1410 int line)
1411 #else
1412 struct net_pkt *net_pkt_alloc_on_iface(struct net_if *iface,
1413 k_timeout_t timeout)
1414 #endif
1415 {
1416 #if NET_LOG_LEVEL >= LOG_LEVEL_DBG
1417 return pkt_alloc_on_iface(&tx_pkts, iface, timeout, caller, line);
1418 #else
1419 return pkt_alloc_on_iface(&tx_pkts, iface, timeout);
1420 #endif
1421 }
1422
1423 #if NET_LOG_LEVEL >= LOG_LEVEL_DBG
1424 struct net_pkt *net_pkt_rx_alloc_on_iface_debug(struct net_if *iface,
1425 k_timeout_t timeout,
1426 const char *caller,
1427 int line)
1428 #else
1429 struct net_pkt *net_pkt_rx_alloc_on_iface(struct net_if *iface,
1430 k_timeout_t timeout)
1431 #endif
1432 {
1433 #if NET_LOG_LEVEL >= LOG_LEVEL_DBG
1434 return pkt_alloc_on_iface(&rx_pkts, iface, timeout, caller, line);
1435 #else
1436 return pkt_alloc_on_iface(&rx_pkts, iface, timeout);
1437 #endif
1438 }
1439
1440 #if NET_LOG_LEVEL >= LOG_LEVEL_DBG
1441 static struct net_pkt *
1442 pkt_alloc_with_buffer(struct k_mem_slab *slab,
1443 struct net_if *iface,
1444 size_t size,
1445 sa_family_t family,
1446 enum net_ip_protocol proto,
1447 k_timeout_t timeout,
1448 const char *caller,
1449 int line)
1450 #else
1451 static struct net_pkt *
1452 pkt_alloc_with_buffer(struct k_mem_slab *slab,
1453 struct net_if *iface,
1454 size_t size,
1455 sa_family_t family,
1456 enum net_ip_protocol proto,
1457 k_timeout_t timeout)
1458 #endif
1459 {
1460 k_timepoint_t end = sys_timepoint_calc(timeout);
1461 struct net_pkt *pkt;
1462 int ret;
1463
1464 NET_DBG("On iface %p size %zu", iface, size);
1465
1466 #if NET_LOG_LEVEL >= LOG_LEVEL_DBG
1467 pkt = pkt_alloc_on_iface(slab, iface, timeout, caller, line);
1468 #else
1469 pkt = pkt_alloc_on_iface(slab, iface, timeout);
1470 #endif
1471
1472 if (!pkt) {
1473 return NULL;
1474 }
1475
1476 net_pkt_set_family(pkt, family);
1477
1478 timeout = sys_timepoint_timeout(end);
1479 #if NET_LOG_LEVEL >= LOG_LEVEL_DBG
1480 ret = net_pkt_alloc_buffer_debug(pkt, size, proto, timeout,
1481 caller, line);
1482 #else
1483 ret = net_pkt_alloc_buffer(pkt, size, proto, timeout);
1484 #endif
1485
1486 if (ret) {
1487 net_pkt_unref(pkt);
1488 return NULL;
1489 }
1490
1491 return pkt;
1492 }
1493
1494 #if NET_LOG_LEVEL >= LOG_LEVEL_DBG
1495 struct net_pkt *net_pkt_alloc_with_buffer_debug(struct net_if *iface,
1496 size_t size,
1497 sa_family_t family,
1498 enum net_ip_protocol proto,
1499 k_timeout_t timeout,
1500 const char *caller,
1501 int line)
1502 #else
1503 struct net_pkt *net_pkt_alloc_with_buffer(struct net_if *iface,
1504 size_t size,
1505 sa_family_t family,
1506 enum net_ip_protocol proto,
1507 k_timeout_t timeout)
1508 #endif
1509 {
1510 #if NET_LOG_LEVEL >= LOG_LEVEL_DBG
1511 return pkt_alloc_with_buffer(&tx_pkts, iface, size, family,
1512 proto, timeout, caller, line);
1513 #else
1514 return pkt_alloc_with_buffer(&tx_pkts, iface, size, family,
1515 proto, timeout);
1516 #endif
1517 }
1518
1519 #if NET_LOG_LEVEL >= LOG_LEVEL_DBG
1520 struct net_pkt *net_pkt_rx_alloc_with_buffer_debug(struct net_if *iface,
1521 size_t size,
1522 sa_family_t family,
1523 enum net_ip_protocol proto,
1524 k_timeout_t timeout,
1525 const char *caller,
1526 int line)
1527 #else
1528 struct net_pkt *net_pkt_rx_alloc_with_buffer(struct net_if *iface,
1529 size_t size,
1530 sa_family_t family,
1531 enum net_ip_protocol proto,
1532 k_timeout_t timeout)
1533 #endif
1534 {
1535 #if NET_LOG_LEVEL >= LOG_LEVEL_DBG
1536 return pkt_alloc_with_buffer(&rx_pkts, iface, size, family,
1537 proto, timeout, caller, line);
1538 #else
1539 return pkt_alloc_with_buffer(&rx_pkts, iface, size, family,
1540 proto, timeout);
1541 #endif
1542 }
1543
1544 void net_pkt_append_buffer(struct net_pkt *pkt, struct net_buf *buffer)
1545 {
1546 if (!pkt->buffer) {
1547 pkt->buffer = buffer;
1548 net_pkt_cursor_init(pkt);
1549 } else {
1550 net_buf_frag_insert(net_buf_frag_last(pkt->buffer), buffer);
1551 }
1552 }
1553
1554 void net_pkt_cursor_init(struct net_pkt *pkt)
1555 {
1556 pkt->cursor.buf = pkt->buffer;
1557 if (pkt->cursor.buf) {
1558 pkt->cursor.pos = pkt->cursor.buf->data;
1559 } else {
1560 pkt->cursor.pos = NULL;
1561 }
1562 }
1563
1564 static void pkt_cursor_jump(struct net_pkt *pkt, bool write)
1565 {
1566 struct net_pkt_cursor *cursor = &pkt->cursor;
1567
1568 cursor->buf = cursor->buf->frags;
1569 while (cursor->buf) {
1570 const size_t len =
1571 write ? net_buf_max_len(cursor->buf) : cursor->buf->len;
1572
1573 if (!len) {
1574 cursor->buf = cursor->buf->frags;
1575 } else {
1576 break;
1577 }
1578 }
1579
1580 if (cursor->buf) {
1581 cursor->pos = cursor->buf->data;
1582 } else {
1583 cursor->pos = NULL;
1584 }
1585 }
1586
1587 static void pkt_cursor_advance(struct net_pkt *pkt, bool write)
1588 {
1589 struct net_pkt_cursor *cursor = &pkt->cursor;
1590 size_t len;
1591
1592 if (!cursor->buf) {
1593 return;
1594 }
1595
1596 len = write ? net_buf_max_len(cursor->buf) : cursor->buf->len;
1597 if ((cursor->pos - cursor->buf->data) == len) {
1598 pkt_cursor_jump(pkt, write);
1599 }
1600 }
1601
1602 static void pkt_cursor_update(struct net_pkt *pkt,
1603 size_t length, bool write)
1604 {
1605 struct net_pkt_cursor *cursor = &pkt->cursor;
1606 size_t len;
1607
1608 if (net_pkt_is_being_overwritten(pkt)) {
1609 write = false;
1610 }
1611
1612 len = write ? net_buf_max_len(cursor->buf) : cursor->buf->len;
1613 if (length + (cursor->pos - cursor->buf->data) == len &&
1614 !(net_pkt_is_being_overwritten(pkt) &&
1615 len < net_buf_max_len(cursor->buf))) {
1616 pkt_cursor_jump(pkt, write);
1617 } else {
1618 cursor->pos += length;
1619 }
1620 }
1621
1622 /* Internal function that does all operation (skip/read/write/memset) */
1623 static int net_pkt_cursor_operate(struct net_pkt *pkt,
1624 void *data, size_t length,
1625 bool copy, bool write)
1626 {
1627 /* We use such variable to avoid lengthy lines */
1628 struct net_pkt_cursor *c_op = &pkt->cursor;
1629
1630 while (c_op->buf && length) {
1631 size_t d_len, len;
1632
1633 pkt_cursor_advance(pkt, net_pkt_is_being_overwritten(pkt) ?
1634 false : write);
1635 if (c_op->buf == NULL) {
1636 break;
1637 }
1638
1639 if (write && !net_pkt_is_being_overwritten(pkt)) {
1640 d_len = net_buf_max_len(c_op->buf) -
1641 (c_op->pos - c_op->buf->data);
1642 } else {
1643 d_len = c_op->buf->len - (c_op->pos - c_op->buf->data);
1644 }
1645
1646 if (!d_len) {
1647 break;
1648 }
1649
1650 if (length < d_len) {
1651 len = length;
1652 } else {
1653 len = d_len;
1654 }
1655
1656 if (copy && data) {
1657 memcpy(write ? c_op->pos : data,
1658 write ? data : c_op->pos,
1659 len);
1660 } else if (data) {
1661 memset(c_op->pos, *(int *)data, len);
1662 }
1663
1664 if (write && !net_pkt_is_being_overwritten(pkt)) {
1665 net_buf_add(c_op->buf, len);
1666 }
1667
1668 pkt_cursor_update(pkt, len, write);
1669
1670 if (copy && data) {
1671 data = (uint8_t *) data + len;
1672 }
1673
1674 length -= len;
1675 }
1676
1677 if (length) {
1678 NET_DBG("Still some length to go %zu", length);
1679 return -ENOBUFS;
1680 }
1681
1682 return 0;
1683 }
1684
1685 int net_pkt_skip(struct net_pkt *pkt, size_t skip)
1686 {
1687 NET_DBG("pkt %p skip %zu", pkt, skip);
1688
1689 return net_pkt_cursor_operate(pkt, NULL, skip, false, true);
1690 }
1691
1692 int net_pkt_memset(struct net_pkt *pkt, int byte, size_t amount)
1693 {
1694 NET_DBG("pkt %p byte %d amount %zu", pkt, byte, amount);
1695
1696 return net_pkt_cursor_operate(pkt, &byte, amount, false, true);
1697 }
1698
1699 int net_pkt_read(struct net_pkt *pkt, void *data, size_t length)
1700 {
1701 NET_DBG("pkt %p data %p length %zu", pkt, data, length);
1702
1703 return net_pkt_cursor_operate(pkt, data, length, true, false);
1704 }
1705
1706 int net_pkt_read_be16(struct net_pkt *pkt, uint16_t *data)
1707 {
1708 uint8_t d16[2];
1709 int ret;
1710
1711 ret = net_pkt_read(pkt, d16, sizeof(uint16_t));
1712
1713 *data = d16[0] << 8 | d16[1];
1714
1715 return ret;
1716 }
1717
1718 int net_pkt_read_le16(struct net_pkt *pkt, uint16_t *data)
1719 {
1720 uint8_t d16[2];
1721 int ret;
1722
1723 ret = net_pkt_read(pkt, d16, sizeof(uint16_t));
1724
1725 *data = d16[1] << 8 | d16[0];
1726
1727 return ret;
1728 }
1729
1730 int net_pkt_read_be32(struct net_pkt *pkt, uint32_t *data)
1731 {
1732 uint8_t d32[4];
1733 int ret;
1734
1735 ret = net_pkt_read(pkt, d32, sizeof(uint32_t));
1736
1737 *data = d32[0] << 24 | d32[1] << 16 | d32[2] << 8 | d32[3];
1738
1739 return ret;
1740 }
1741
1742 int net_pkt_write(struct net_pkt *pkt, const void *data, size_t length)
1743 {
1744 NET_DBG("pkt %p data %p length %zu", pkt, data, length);
1745
1746 if (data == pkt->cursor.pos && net_pkt_is_contiguous(pkt, length)) {
1747 return net_pkt_skip(pkt, length);
1748 }
1749
1750 return net_pkt_cursor_operate(pkt, (void *)data, length, true, true);
1751 }
1752
1753 int net_pkt_copy(struct net_pkt *pkt_dst,
1754 struct net_pkt *pkt_src,
1755 size_t length)
1756 {
1757 struct net_pkt_cursor *c_dst = &pkt_dst->cursor;
1758 struct net_pkt_cursor *c_src = &pkt_src->cursor;
1759
1760 while (c_dst->buf && c_src->buf && length) {
1761 size_t s_len, d_len, len;
1762
1763 pkt_cursor_advance(pkt_dst, true);
1764 pkt_cursor_advance(pkt_src, false);
1765
1766 if (!c_dst->buf || !c_src->buf) {
1767 break;
1768 }
1769
1770 s_len = c_src->buf->len - (c_src->pos - c_src->buf->data);
1771 d_len = net_buf_max_len(c_dst->buf) - (c_dst->pos - c_dst->buf->data);
1772 if (length < s_len && length < d_len) {
1773 len = length;
1774 } else {
1775 if (d_len < s_len) {
1776 len = d_len;
1777 } else {
1778 len = s_len;
1779 }
1780 }
1781
1782 if (!len) {
1783 break;
1784 }
1785
1786 memcpy(c_dst->pos, c_src->pos, len);
1787
1788 if (!net_pkt_is_being_overwritten(pkt_dst)) {
1789 net_buf_add(c_dst->buf, len);
1790 }
1791
1792 pkt_cursor_update(pkt_dst, len, true);
1793 pkt_cursor_update(pkt_src, len, false);
1794
1795 length -= len;
1796 }
1797
1798 if (length) {
1799 NET_DBG("Still some length to go %zu", length);
1800 return -ENOBUFS;
1801 }
1802
1803 return 0;
1804 }
1805
1806 static int32_t net_pkt_find_offset(struct net_pkt *pkt, uint8_t *ptr)
1807 {
1808 struct net_buf *buf;
1809 uint32_t ret = -EINVAL;
1810 uint16_t offset;
1811
1812 if (!ptr || !pkt || !pkt->buffer) {
1813 return ret;
1814 }
1815
1816 offset = 0U;
1817 buf = pkt->buffer;
1818
1819 while (buf) {
1820 if (buf->data <= ptr && ptr <= (buf->data + buf->len)) {
1821 ret = offset + (ptr - buf->data);
1822 break;
1823 }
1824 offset += buf->len;
1825 buf = buf->frags;
1826 }
1827
1828 return ret;
1829 }
1830
1831 static void clone_pkt_lladdr(struct net_pkt *pkt, struct net_pkt *clone_pkt,
1832 struct net_linkaddr *lladdr)
1833 {
1834 int32_t ll_addr_offset;
1835
1836 if (!lladdr->addr)
1837 return;
1838
1839 ll_addr_offset = net_pkt_find_offset(pkt, lladdr->addr);
1840
1841 if (ll_addr_offset >= 0) {
1842 net_pkt_cursor_init(clone_pkt);
1843 net_pkt_skip(clone_pkt, ll_addr_offset);
1844 lladdr->addr = net_pkt_cursor_get_pos(clone_pkt);
1845 }
1846 }
1847
1848 #if defined(NET_PKT_HAS_CONTROL_BLOCK)
1849 static inline void clone_pkt_cb(struct net_pkt *pkt, struct net_pkt *clone_pkt)
1850 {
1851 memcpy(net_pkt_cb(clone_pkt), net_pkt_cb(pkt), sizeof(clone_pkt->cb));
1852 }
1853 #else
1854 static inline void clone_pkt_cb(struct net_pkt *pkt, struct net_pkt *clone_pkt)
1855 {
1856 ARG_UNUSED(pkt);
1857 ARG_UNUSED(clone_pkt);
1858 }
1859 #endif
1860
1861 static void clone_pkt_attributes(struct net_pkt *pkt, struct net_pkt *clone_pkt)
1862 {
1863 net_pkt_set_family(clone_pkt, net_pkt_family(pkt));
1864 net_pkt_set_context(clone_pkt, net_pkt_context(pkt));
1865 net_pkt_set_ip_hdr_len(clone_pkt, net_pkt_ip_hdr_len(pkt));
1866 net_pkt_set_ip_dscp(clone_pkt, net_pkt_ip_dscp(pkt));
1867 net_pkt_set_ip_ecn(clone_pkt, net_pkt_ip_ecn(pkt));
1868 net_pkt_set_vlan_tag(clone_pkt, net_pkt_vlan_tag(pkt));
1869 net_pkt_set_timestamp(clone_pkt, net_pkt_timestamp(pkt));
1870 net_pkt_set_priority(clone_pkt, net_pkt_priority(pkt));
1871 net_pkt_set_orig_iface(clone_pkt, net_pkt_orig_iface(pkt));
1872 net_pkt_set_captured(clone_pkt, net_pkt_is_captured(pkt));
1873 net_pkt_set_eof(clone_pkt, net_pkt_eof(pkt));
1874 net_pkt_set_ptp(clone_pkt, net_pkt_is_ptp(pkt));
1875 net_pkt_set_forwarding(clone_pkt, net_pkt_forwarding(pkt));
1876 net_pkt_set_chksum_done(clone_pkt, net_pkt_is_chksum_done(pkt));
1877 net_pkt_set_ip_reassembled(pkt, net_pkt_is_ip_reassembled(pkt));
1878
1879 net_pkt_set_l2_bridged(clone_pkt, net_pkt_is_l2_bridged(pkt));
1880 net_pkt_set_l2_processed(clone_pkt, net_pkt_is_l2_processed(pkt));
1881 net_pkt_set_ll_proto_type(clone_pkt, net_pkt_ll_proto_type(pkt));
1882
1883 if (pkt->buffer && clone_pkt->buffer) {
1884 memcpy(net_pkt_lladdr_src(clone_pkt), net_pkt_lladdr_src(pkt),
1885 sizeof(struct net_linkaddr));
1886 memcpy(net_pkt_lladdr_dst(clone_pkt), net_pkt_lladdr_dst(pkt),
1887 sizeof(struct net_linkaddr));
1888 /* The link header pointers are usable as-is if we
1889 * shallow-copied the buffer even if they point
1890 * into the fragment memory of the buffer,
1891 * otherwise we have to set the ll address pointer
1892 * relative to the new buffer to avoid dangling
1893 * pointers into the source packet.
1894 */
1895 if (pkt->buffer != clone_pkt->buffer) {
1896 clone_pkt_lladdr(pkt, clone_pkt, net_pkt_lladdr_src(clone_pkt));
1897 clone_pkt_lladdr(pkt, clone_pkt, net_pkt_lladdr_dst(clone_pkt));
1898 }
1899 }
1900
1901 if (IS_ENABLED(CONFIG_NET_IPV4) && net_pkt_family(pkt) == AF_INET) {
1902 net_pkt_set_ipv4_ttl(clone_pkt, net_pkt_ipv4_ttl(pkt));
1903 net_pkt_set_ipv4_opts_len(clone_pkt,
1904 net_pkt_ipv4_opts_len(pkt));
1905 } else if (IS_ENABLED(CONFIG_NET_IPV6) &&
1906 net_pkt_family(pkt) == AF_INET6) {
1907 net_pkt_set_ipv6_hop_limit(clone_pkt,
1908 net_pkt_ipv6_hop_limit(pkt));
1909 net_pkt_set_ipv6_ext_len(clone_pkt, net_pkt_ipv6_ext_len(pkt));
1910 net_pkt_set_ipv6_ext_opt_len(clone_pkt,
1911 net_pkt_ipv6_ext_opt_len(pkt));
1912 net_pkt_set_ipv6_hdr_prev(clone_pkt,
1913 net_pkt_ipv6_hdr_prev(pkt));
1914 net_pkt_set_ipv6_next_hdr(clone_pkt,
1915 net_pkt_ipv6_next_hdr(pkt));
1916 }
1917
1918 clone_pkt_cb(pkt, clone_pkt);
1919 }
1920
1921 static struct net_pkt *net_pkt_clone_internal(struct net_pkt *pkt,
1922 struct k_mem_slab *slab,
1923 k_timeout_t timeout)
1924 {
1925 size_t cursor_offset = net_pkt_get_current_offset(pkt);
1926 bool overwrite = net_pkt_is_being_overwritten(pkt);
1927 struct net_pkt_cursor backup;
1928 struct net_pkt *clone_pkt;
1929
1930 #if NET_LOG_LEVEL >= LOG_LEVEL_DBG
1931 clone_pkt = pkt_alloc_with_buffer(slab, net_pkt_iface(pkt),
1932 net_pkt_get_len(pkt),
1933 AF_UNSPEC, 0, timeout,
1934 __func__, __LINE__);
1935 #else
1936 clone_pkt = pkt_alloc_with_buffer(slab, net_pkt_iface(pkt),
1937 net_pkt_get_len(pkt),
1938 AF_UNSPEC, 0, timeout);
1939 #endif
1940 if (!clone_pkt) {
1941 return NULL;
1942 }
1943
1944 net_pkt_set_overwrite(pkt, true);
1945 net_pkt_cursor_backup(pkt, &backup);
1946 net_pkt_cursor_init(pkt);
1947
1948 if (net_pkt_copy(clone_pkt, pkt, net_pkt_get_len(pkt))) {
1949 net_pkt_unref(clone_pkt);
1950 net_pkt_cursor_restore(pkt, &backup);
1951 net_pkt_set_overwrite(pkt, overwrite);
1952 return NULL;
1953 }
1954 net_pkt_set_overwrite(clone_pkt, true);
1955
1956 clone_pkt_attributes(pkt, clone_pkt);
1957
1958 net_pkt_cursor_init(clone_pkt);
1959
1960 if (cursor_offset) {
1961 net_pkt_skip(clone_pkt, cursor_offset);
1962 }
1963 net_pkt_set_overwrite(clone_pkt, overwrite);
1964
1965 net_pkt_cursor_restore(pkt, &backup);
1966 net_pkt_set_overwrite(pkt, overwrite);
1967
1968 NET_DBG("Cloned %p to %p", pkt, clone_pkt);
1969
1970 return clone_pkt;
1971 }
1972
1973 struct net_pkt *net_pkt_clone(struct net_pkt *pkt, k_timeout_t timeout)
1974 {
1975 return net_pkt_clone_internal(pkt, pkt->slab, timeout);
1976 }
1977
1978 struct net_pkt *net_pkt_rx_clone(struct net_pkt *pkt, k_timeout_t timeout)
1979 {
1980 return net_pkt_clone_internal(pkt, &rx_pkts, timeout);
1981 }
1982
1983 struct net_pkt *net_pkt_shallow_clone(struct net_pkt *pkt, k_timeout_t timeout)
1984 {
1985 struct net_pkt *clone_pkt;
1986 struct net_buf *buf;
1987
1988 clone_pkt = net_pkt_alloc(timeout);
1989 if (!clone_pkt) {
1990 return NULL;
1991 }
1992
1993 net_pkt_set_iface(clone_pkt, net_pkt_iface(pkt));
1994 clone_pkt->buffer = pkt->buffer;
1995 buf = pkt->buffer;
1996
1997 net_pkt_frag_ref(buf);
1998
1999 clone_pkt_attributes(pkt, clone_pkt);
2000
2001 net_pkt_cursor_restore(clone_pkt, &pkt->cursor);
2002
2003 NET_DBG("Shallow cloned %p to %p", pkt, clone_pkt);
2004
2005 return clone_pkt;
2006 }
2007
2008 size_t net_pkt_remaining_data(struct net_pkt *pkt)
2009 {
2010 struct net_buf *buf;
2011 size_t data_length;
2012
2013 if (!pkt || !pkt->cursor.buf || !pkt->cursor.pos) {
2014 return 0;
2015 }
2016
2017 buf = pkt->cursor.buf;
2018 data_length = buf->len - (pkt->cursor.pos - buf->data);
2019
2020 buf = buf->frags;
2021 while (buf) {
2022 data_length += buf->len;
2023 buf = buf->frags;
2024 }
2025
2026 return data_length;
2027 }
2028
2029 int net_pkt_update_length(struct net_pkt *pkt, size_t length)
2030 {
2031 struct net_buf *buf;
2032
2033 for (buf = pkt->buffer; buf; buf = buf->frags) {
2034 if (buf->len < length) {
2035 length -= buf->len;
2036 } else {
2037 buf->len = length;
2038 length = 0;
2039 }
2040 }
2041
2042 return !length ? 0 : -EINVAL;
2043 }
2044
2045 int net_pkt_pull(struct net_pkt *pkt, size_t length)
2046 {
2047 struct net_pkt_cursor *c_op = &pkt->cursor;
2048
2049 while (length) {
2050 size_t left, rem;
2051
2052 pkt_cursor_advance(pkt, false);
2053
2054 if (!c_op->buf) {
2055 break;
2056 }
2057
2058 left = c_op->buf->len - (c_op->pos - c_op->buf->data);
2059 if (!left) {
2060 break;
2061 }
2062
2063 rem = left;
2064 if (rem > length) {
2065 rem = length;
2066 }
2067
2068 c_op->buf->len -= rem;
2069 left -= rem;
2070 if (left) {
2071 memmove(c_op->pos, c_op->pos+rem, left);
2072 } else {
2073 struct net_buf *buf = pkt->buffer;
2074
2075 if (buf) {
2076 pkt->buffer = buf->frags;
2077 buf->frags = NULL;
2078 net_buf_unref(buf);
2079 }
2080
2081 net_pkt_cursor_init(pkt);
2082 }
2083
2084 length -= rem;
2085 }
2086
2087 net_pkt_cursor_init(pkt);
2088
2089 if (length) {
2090 NET_DBG("Still some length to go %zu", length);
2091 return -ENOBUFS;
2092 }
2093
2094 return 0;
2095 }
2096
2097 uint16_t net_pkt_get_current_offset(struct net_pkt *pkt)
2098 {
2099 struct net_buf *buf = pkt->buffer;
2100 uint16_t offset;
2101
2102 if (!pkt->cursor.buf || !pkt->cursor.pos) {
2103 return 0;
2104 }
2105
2106 offset = 0U;
2107
2108 while (buf != pkt->cursor.buf) {
2109 offset += buf->len;
2110 buf = buf->frags;
2111 }
2112
2113 offset += pkt->cursor.pos - buf->data;
2114
2115 return offset;
2116 }
2117
2118 bool net_pkt_is_contiguous(struct net_pkt *pkt, size_t size)
2119 {
2120 size_t len = net_pkt_get_contiguous_len(pkt);
2121
2122 return len >= size;
2123 }
2124
2125 size_t net_pkt_get_contiguous_len(struct net_pkt *pkt)
2126 {
2127 pkt_cursor_advance(pkt, !net_pkt_is_being_overwritten(pkt));
2128
2129 if (pkt->cursor.buf && pkt->cursor.pos) {
2130 size_t len;
2131
2132 len = net_pkt_is_being_overwritten(pkt) ?
2133 pkt->cursor.buf->len : pkt->cursor.buf->size;
2134 len -= pkt->cursor.pos - pkt->cursor.buf->data;
2135 return len;
2136 }
2137
2138 return 0;
2139 }
2140
2141 void *net_pkt_get_data(struct net_pkt *pkt,
2142 struct net_pkt_data_access *access)
2143 {
2144 if (IS_ENABLED(CONFIG_NET_HEADERS_ALWAYS_CONTIGUOUS)) {
2145 if (!net_pkt_is_contiguous(pkt, access->size)) {
2146 return NULL;
2147 }
2148
2149 return pkt->cursor.pos;
2150 } else {
2151 if (net_pkt_is_contiguous(pkt, access->size)) {
2152 access->data = pkt->cursor.pos;
2153 } else if (net_pkt_is_being_overwritten(pkt)) {
2154 struct net_pkt_cursor backup;
2155
2156 if (!access->data) {
2157 NET_ERR("Uncontiguous data"
2158 " cannot be linearized");
2159 return NULL;
2160 }
2161
2162 net_pkt_cursor_backup(pkt, &backup);
2163
2164 if (net_pkt_read(pkt, access->data, access->size)) {
2165 net_pkt_cursor_restore(pkt, &backup);
2166 return NULL;
2167 }
2168
2169 net_pkt_cursor_restore(pkt, &backup);
2170 }
2171
2172 return access->data;
2173 }
2174
2175 return NULL;
2176 }
2177
2178 int net_pkt_set_data(struct net_pkt *pkt,
2179 struct net_pkt_data_access *access)
2180 {
2181 if (IS_ENABLED(CONFIG_NET_HEADERS_ALWAYS_CONTIGUOUS)) {
2182 return net_pkt_skip(pkt, access->size);
2183 }
2184
2185 return net_pkt_write(pkt, access->data, access->size);
2186 }
2187
2188 void net_pkt_init(void)
2189 {
2190 #if CONFIG_NET_PKT_LOG_LEVEL >= LOG_LEVEL_DBG
2191 NET_DBG("Allocating %u RX (%zu bytes), %u TX (%zu bytes), "
2192 "%d RX data (%u bytes) and %d TX data (%u bytes) buffers",
2193 k_mem_slab_num_free_get(&rx_pkts),
2194 (size_t)(k_mem_slab_num_free_get(&rx_pkts) *
2195 sizeof(struct net_pkt)),
2196 k_mem_slab_num_free_get(&tx_pkts),
2197 (size_t)(k_mem_slab_num_free_get(&tx_pkts) *
2198 sizeof(struct net_pkt)),
2199 get_frees(&rx_bufs), get_size(&rx_bufs),
2200 get_frees(&tx_bufs), get_size(&tx_bufs));
2201 #endif
2202 }
2203