net: pkt: Introduce minimum length requirement to net_pkt_get_frag()

net_pkt_get_frag() and a few other functions did not specify the
allocated fragment length, incorrectly assuming that fixed-sized
buffers are always used.

In order to make the function work properly also with variable-sized
buffers, extend the function argument list with minimum expected
fragment length parameter. This allows to use net_buf_alloc_len()
allocator in variable buffer length configuration, as well as verify if
the fixed-sized buffer is large enough to satisfy the requirements
otherwise.

Update the existing codebase to provide the expected fragment length,
based on the context.

Signed-off-by: Robert Lubos <robert.lubos@nordicsemi.no>
This commit is contained in:
Robert Lubos 2022-11-15 17:17:21 +01:00 committed by Anas Nashif
commit 387a66131e
18 changed files with 112 additions and 65 deletions

View file

@ -1394,16 +1394,18 @@ static bool uncompress_IPHC_header(struct net_pkt *pkt)
cursor = frag->data + diff;
memmove(cursor, frag->data, frag->len - diff);
} else {
size_t frag_len = nhc ? NET_IPV6UDPH_LEN : NET_IPV6H_LEN;
NET_DBG("Not enough tailroom. Get new fragment");
cursor = pkt->buffer->data;
frag = net_pkt_get_frag(pkt, NET_6LO_RX_PKT_TIMEOUT);
frag = net_pkt_get_frag(pkt, frag_len, NET_6LO_RX_PKT_TIMEOUT);
if (!frag) {
NET_ERR("Can't get frag for uncompression");
return false;
}
net_buf_pull(pkt->buffer, compressed_hdr_size);
net_buf_add(frag, nhc ? NET_IPV6UDPH_LEN : NET_IPV6H_LEN);
net_buf_add(frag, frag_len);
}
ipv6 = (struct net_ipv6_hdr *)(frag->data);
@ -1537,7 +1539,7 @@ static inline int compress_ipv6_header(struct net_pkt *pkt)
return 0;
}
buffer = net_pkt_get_frag(pkt, K_FOREVER);
buffer = net_pkt_get_frag(pkt, 1, K_FOREVER);
if (!buffer) {
return -ENOBUFS;
}

View file

@ -368,27 +368,32 @@ void net_pkt_print_frags(struct net_pkt *pkt)
#if NET_LOG_LEVEL >= LOG_LEVEL_DBG
struct net_buf *net_pkt_get_reserve_data_debug(struct net_buf_pool *pool,
size_t min_len,
k_timeout_t timeout,
const char *caller,
int line)
#else /* NET_LOG_LEVEL >= LOG_LEVEL_DBG */
struct net_buf *net_pkt_get_reserve_data(struct net_buf_pool *pool,
k_timeout_t timeout)
size_t min_len, k_timeout_t timeout)
#endif /* NET_LOG_LEVEL >= LOG_LEVEL_DBG */
{
struct net_buf *frag;
/*
* The reserve_head variable in the function will tell
* the size of the link layer headers if there are any.
*/
if (k_is_in_isr()) {
frag = net_buf_alloc(pool, K_NO_WAIT);
} else {
frag = net_buf_alloc(pool, timeout);
timeout = K_NO_WAIT;
}
#if defined(CONFIG_NET_BUF_FIXED_DATA_SIZE)
if (min_len > CONFIG_NET_BUF_DATA_SIZE) {
NET_ERR("Requested too large fragment. Increase CONFIG_NET_BUF_DATA_SIZE.");
return NULL;
}
frag = net_buf_alloc(pool, timeout);
#else
frag = net_buf_alloc_len(pool, min_len, timeout);
#endif /* CONFIG_NET_BUF_FIXED_DATA_SIZE */
if (!frag) {
return NULL;
}
@ -412,11 +417,11 @@ struct net_buf *net_pkt_get_reserve_data(struct net_buf_pool *pool,
* the data.
*/
#if NET_LOG_LEVEL >= LOG_LEVEL_DBG
struct net_buf *net_pkt_get_frag_debug(struct net_pkt *pkt,
struct net_buf *net_pkt_get_frag_debug(struct net_pkt *pkt, size_t min_len,
k_timeout_t timeout,
const char *caller, int line)
#else
struct net_buf *net_pkt_get_frag(struct net_pkt *pkt,
struct net_buf *net_pkt_get_frag(struct net_pkt *pkt, size_t min_len,
k_timeout_t timeout)
#endif
{
@ -427,52 +432,54 @@ struct net_buf *net_pkt_get_frag(struct net_pkt *pkt,
if (context && context->data_pool) {
#if NET_LOG_LEVEL >= LOG_LEVEL_DBG
return net_pkt_get_reserve_data_debug(context->data_pool(),
timeout, caller, line);
min_len, timeout,
caller, line);
#else
return net_pkt_get_reserve_data(context->data_pool(), timeout);
return net_pkt_get_reserve_data(context->data_pool(), min_len,
timeout);
#endif /* NET_LOG_LEVEL >= LOG_LEVEL_DBG */
}
#endif /* CONFIG_NET_CONTEXT_NET_PKT_POOL */
if (pkt->slab == &rx_pkts) {
#if NET_LOG_LEVEL >= LOG_LEVEL_DBG
return net_pkt_get_reserve_rx_data_debug(timeout,
return net_pkt_get_reserve_rx_data_debug(min_len, timeout,
caller, line);
#else
return net_pkt_get_reserve_rx_data(timeout);
return net_pkt_get_reserve_rx_data(min_len, timeout);
#endif
}
#if NET_LOG_LEVEL >= LOG_LEVEL_DBG
return net_pkt_get_reserve_tx_data_debug(timeout, caller, line);
return net_pkt_get_reserve_tx_data_debug(min_len, timeout, caller, line);
#else
return net_pkt_get_reserve_tx_data(timeout);
return net_pkt_get_reserve_tx_data(min_len, timeout);
#endif
}
#if NET_LOG_LEVEL >= LOG_LEVEL_DBG
struct net_buf *net_pkt_get_reserve_rx_data_debug(k_timeout_t timeout,
struct net_buf *net_pkt_get_reserve_rx_data_debug(size_t min_len, k_timeout_t timeout,
const char *caller, int line)
{
return net_pkt_get_reserve_data_debug(&rx_bufs, timeout, caller, line);
return net_pkt_get_reserve_data_debug(&rx_bufs, min_len, timeout, caller, line);
}
struct net_buf *net_pkt_get_reserve_tx_data_debug(k_timeout_t timeout,
struct net_buf *net_pkt_get_reserve_tx_data_debug(size_t min_len, k_timeout_t timeout,
const char *caller, int line)
{
return net_pkt_get_reserve_data_debug(&tx_bufs, timeout, caller, line);
return net_pkt_get_reserve_data_debug(&tx_bufs, min_len, timeout, caller, line);
}
#else /* NET_LOG_LEVEL >= LOG_LEVEL_DBG */
struct net_buf *net_pkt_get_reserve_rx_data(k_timeout_t timeout)
struct net_buf *net_pkt_get_reserve_rx_data(size_t min_len, k_timeout_t timeout)
{
return net_pkt_get_reserve_data(&rx_bufs, timeout);
return net_pkt_get_reserve_data(&rx_bufs, min_len, timeout);
}
struct net_buf *net_pkt_get_reserve_tx_data(k_timeout_t timeout)
struct net_buf *net_pkt_get_reserve_tx_data(size_t min_len, k_timeout_t timeout)
{
return net_pkt_get_reserve_data(&tx_bufs, timeout);
return net_pkt_get_reserve_data(&tx_bufs, min_len, timeout);
}
#endif /* NET_LOG_LEVEL >= LOG_LEVEL_DBG */

View file

@ -92,7 +92,7 @@ static int tcp_pkt_linearize(struct net_pkt *pkt, size_t pos, size_t len)
goto out;
}
buf = net_pkt_get_frag(pkt, TCP_PKT_ALLOC_TIMEOUT);
buf = net_pkt_get_frag(pkt, len, TCP_PKT_ALLOC_TIMEOUT);
if (!buf || buf->size < len) {
if (buf) {

View file

@ -50,6 +50,12 @@ extern int net_bt_shell_init(void);
#define net_bt_shell_init(...)
#endif
#if defined(CONFIG_NET_BUF_FIXED_DATA_SIZE)
#define IPSP_FRAG_LEN CONFIG_NET_BUF_DATA_SIZE
#else
#define IPSP_FRAG_LEN L2CAP_IPSP_MTU
#endif /* CONFIG_NET_BUF_FIXED_DATA_SIZE */
struct bt_if_conn {
struct net_if *iface;
struct bt_l2cap_le_chan ipsp_chan;
@ -259,7 +265,7 @@ static struct net_buf *ipsp_alloc_buf(struct bt_l2cap_chan *chan)
{
NET_DBG("Channel %p requires buffer", chan);
return net_pkt_get_reserve_rx_data(BUF_TIMEOUT);
return net_pkt_get_reserve_rx_data(IPSP_FRAG_LEN, BUF_TIMEOUT);
}
static const struct bt_l2cap_chan_ops ipsp_ops = {

View file

@ -508,8 +508,11 @@ static struct net_buf *ethernet_fill_header(struct ethernet_context *ctx,
{
struct net_buf *hdr_frag;
struct net_eth_hdr *hdr;
size_t hdr_len = IS_ENABLED(CONFIG_NET_VLAN) ?
sizeof(struct net_eth_vlan_hdr) :
sizeof(struct net_eth_hdr);
hdr_frag = net_pkt_get_frag(pkt, NET_BUF_TIMEOUT);
hdr_frag = net_pkt_get_frag(pkt, hdr_len, NET_BUF_TIMEOUT);
if (!hdr_frag) {
return NULL;
}

View file

@ -460,7 +460,8 @@ int ppp_send_pkt(struct ppp_fsm *fsm, struct net_if *iface,
} else {
struct net_buf *buf;
buf = net_pkt_get_reserve_tx_data(PPP_BUF_ALLOC_TIMEOUT);
buf = net_pkt_get_reserve_tx_data(sizeof(uint16_t) + len,
PPP_BUF_ALLOC_TIMEOUT);
if (!buf) {
LOG_ERR("failed to allocate buffer");
goto out_of_mem;