net/nbuf: Introduce the net_nbuf_linear_copy routine

This commit adds one routine previously found at the DNS resolver
library. The net_nbuf_linear_copy routine allows to "linearize"
an IP stack network buffer. This routine is required by functions
that must jump between big chunks of data that in this case may
lie between many fragments. Tracking fragments may be a tedious
task, so getting a linear copy of the buffer will reduce code
complexity altough it increases memory consumption.

The DNS client library is updated to reflect these changes.

Change-Id: Iae321f99fa9b05fae7e722b6d41baac427d82d7e
Signed-off-by: Flavio Santes <flavio.santes@intel.com>
This commit is contained in:
Flavio Santes 2016-12-13 12:33:19 -06:00 committed by Tomasz Bursztyka
commit c015c0e2c8
3 changed files with 57 additions and 38 deletions

View file

@ -511,6 +511,22 @@ static inline struct net_buf *net_nbuf_copy_all(struct net_buf *buf,
return net_nbuf_copy(buf, net_buf_frags_len(buf), reserve);
}
/**
* @brief net_nbuf_linear_copy Copy len bytes from src starting from
* offset to dst
* @details This routine assumes that dst is conformed by
* one fragment with enough space to store len
* bytes starting from offset at src.
* @param dst Destination buffer
* @param src Source buffer that may be fragmented
* @param offset Starting point to copy from
* @param len Number of bytes to copy
* @return 0 on success
* @return -ENOMEM on error
*/
int net_nbuf_linear_copy(struct net_buf *dst, struct net_buf *src,
uint16_t offset, uint16_t len);
/**
* @brief Compact the fragment list.
*

View file

@ -636,6 +636,45 @@ struct net_buf *net_nbuf_copy(struct net_buf *orig, size_t amount,
return first;
}
int net_nbuf_linear_copy(struct net_buf *dst, struct net_buf *src,
uint16_t offset, uint16_t len)
{
uint16_t to_copy;
uint16_t copied;
if (dst->size < len) {
return -ENOMEM;
}
/* find the right fragment to start copying from */
while (src && offset >= src->len) {
offset -= src->len;
src = src->frags;
}
/* traverse the fragment chain until len bytes are copied */
copied = 0;
while (src && len > 0) {
to_copy = min(len, src->len - offset);
memcpy(dst->data + copied, src->data + offset, to_copy);
copied += to_copy;
/* to_copy is always <= len */
len -= to_copy;
src = src->frags;
/* after the first iteration, this value will be 0 */
offset = 0;
}
if (len > 0) {
return -ENOMEM;
}
dst->len = copied;
return 0;
}
bool net_nbuf_is_compact(struct net_buf *buf)
{
struct net_buf *last;

View file

@ -221,10 +221,6 @@ void cb_recv(struct net_context *net_ctx, struct net_buf *buf, int status,
k_sem_give(&ctx->rx_sem);
}
static
int nbuf_copy(struct net_buf *dst, struct net_buf *src, int offset,
int len);
static
int dns_read(struct dns_context *ctx, struct net_buf *dns_data,
uint16_t dns_id, uint8_t *cname, uint16_t *cname_len)
@ -271,7 +267,8 @@ int dns_read(struct dns_context *ctx, struct net_buf *dns_data,
DNS_RESOLVER_MAX_BUF_SIZE);
offset = net_buf_frags_len(ctx->rx_buf) - data_len;
if (nbuf_copy(dns_data, ctx->rx_buf, offset, data_len) != 0) {
rc = net_nbuf_linear_copy(dns_data, ctx->rx_buf, offset, data_len);
if (rc != 0) {
rc = -ENOMEM;
goto exit_error;
}
@ -375,36 +372,3 @@ exit_error:
net_nbuf_unref(ctx->rx_buf);
return rc;
}
static
int nbuf_copy(struct net_buf *dst, struct net_buf *src, int offset,
int len)
{
int copied;
int to_copy;
/* find the right fragment to start copying from */
while (src && offset >= src->len) {
offset -= src->len;
src = src->frags;
}
/* traverse the fragment chain until len bytes are copied */
copied = 0;
while (src && len > 0) {
to_copy = min(len, src->len - offset);
memcpy(dst->data + copied, src->data + offset, to_copy);
copied += to_copy;
len -= to_copy;
src = src->frags;
/* after the first iteration, this value will be 0 */
offset = 0;
}
if (len > 0) {
return -ENOMEM;
}
return 0;
}