Skip to content
Snippets Groups Projects
Commit 6443a2bb authored by Yonezawa-T2's avatar Yonezawa-T2
Browse files

gnrc_pktbuf: Adds a function to duplicate packet chain

parent bc5b0c31
Branches
No related tags found
No related merge requests found
...@@ -136,6 +136,31 @@ static inline size_t gnrc_pkt_len(gnrc_pktsnip_t *pkt) ...@@ -136,6 +136,31 @@ static inline size_t gnrc_pkt_len(gnrc_pktsnip_t *pkt)
return len; return len;
} }
/**
* @brief Calculates length of a packet in byte upto (including) a snip with the given type.
*
* @param[in] pkt list of packet snips.
* @param[in] type type of snip to stop calculation.
*
* @return length of the list of headers.
*/
static inline size_t gnrc_pkt_len_upto(gnrc_pktsnip_t *pkt, gnrc_nettype_t type)
{
size_t len = 0;
while (pkt) {
len += pkt->size;
if (pkt->type == type) {
break;
}
pkt = pkt->next;
}
return len;
}
/** /**
* @brief Count the numbers of snips in the given packet * @brief Count the numbers of snips in the given packet
* *
......
...@@ -215,6 +215,56 @@ gnrc_pktsnip_t *gnrc_pktbuf_remove_snip(gnrc_pktsnip_t *pkt, gnrc_pktsnip_t *sni ...@@ -215,6 +215,56 @@ gnrc_pktsnip_t *gnrc_pktbuf_remove_snip(gnrc_pktsnip_t *pkt, gnrc_pktsnip_t *sni
*/ */
gnrc_pktsnip_t *gnrc_pktbuf_replace_snip(gnrc_pktsnip_t *pkt, gnrc_pktsnip_t *old, gnrc_pktsnip_t *add); gnrc_pktsnip_t *gnrc_pktbuf_replace_snip(gnrc_pktsnip_t *pkt, gnrc_pktsnip_t *old, gnrc_pktsnip_t *add);
/**
* @brief Duplicates pktsnip chain upto (including) a snip with the given type
* as a continuous snip.
*
* Example:
* Input:
* buffer
* +---------------------------+ +------+
* | size = 8 | data +-------->| |
* | type = NETTYPE_IPV6_EXT |------------+ +------+
* +---------------------------+ . .
* | next . .
* v . .
* +---------------------------+ +------+
* | size = 40 | data +----------->| |
* | type = NETTYPE_IPV6 |---------+ +------+
* +---------------------------+ . .
* | next . .
* v
* +---------------------------+ +------+
* | size = 14 | data +-------------->| |
* | type = NETTYPE_NETIF |------+ +------+
* +---------------------------+ . .
*
*
* Output:
* buffer
* +---------------------------+ +------+
* | size = 48 | data +-------->| |
* | type = NETTYPE_IPV6 |------------+ | |
* +---------------------------+ | |
* | +------+
* | . .
* | next . .
* v
* +---------------------------+ +------+
* | size = 14 | data +-------------->| |
* | type = NETTYPE_NETIF |------+ +------+
* +---------------------------+ . .
*
* The original snip is keeped as is except `users` decremented.
*
* @param[in,out] pkt The snip to duplicate.
* @param[in] type The type of snip to stop duplication.
*
* @return The duplicated snip, if succeeded.
* @return NULL, if no space is left in the packet buffer.
*/
gnrc_pktsnip_t *gnrc_pktbuf_duplicate_upto(gnrc_pktsnip_t *pkt, gnrc_nettype_t type);
#ifdef DEVELHELP #ifdef DEVELHELP
/** /**
* @brief Prints some statistics about the packet buffer to stdout. * @brief Prints some statistics about the packet buffer to stdout.
......
...@@ -25,114 +25,6 @@ ...@@ -25,114 +25,6 @@
#ifdef MODULE_GNRC_RPL_SRH #ifdef MODULE_GNRC_RPL_SRH
static size_t _cumulate_size_upto(gnrc_pktsnip_t *pkt, gnrc_nettype_t type)
{
size_t sum = 0;
for (; pkt != NULL; pkt = pkt->next) {
sum += pkt->size;
if (pkt->type == type) {
break;
}
}
return sum;
}
/**
* @brief duplicates pktsnip chain upto (including) a snip with the given type
* as a continuous snip.
*
* Example:
* Input:
* buffer
* +---------------------------+ +------+
* | size = 8 | data +-------->| |
* | type = NETTYPE_IPV6_EXT |------------+ +------+
* +---------------------------+ . .
* | next . .
* v . .
* +---------------------------+ +------+
* | size = 40 | data +----------->| |
* | type = NETTYPE_IPV6 |---------+ +------+
* +---------------------------+ . .
* | next . .
* v
* +---------------------------+ +------+
* | size = 14 | data +-------------->| |
* | type = NETTYPE_NETIF |------+ +------+
* +---------------------------+ . .
*
*
* Output:
* buffer
* +---------------------------+ +------+
* | size = 48 | data +-------->| |
* | type = NETTYPE_IPV6 |------------+ | |
* +---------------------------+ | |
* | +------+
* | . .
* | next . .
* v
* +---------------------------+ +------+
* | size = 14 | data +-------------->| |
* | type = NETTYPE_NETIF |------+ +------+
* +---------------------------+ . .
*
* The original snip is keeped as is except `users` decremented.
*
* @param[in,out] pkt The snip to duplicate.
* @param[in] type The type of snip to stop duplication.
*
* @return The duplicated snip, if succeeded.
* @return NULL, if no space is left in the packet buffer.
*/
static gnrc_pktsnip_t *_duplicate_upto(gnrc_pktsnip_t *pkt, gnrc_nettype_t type)
{
bool is_shared = pkt->users > 1;
size_t size = _cumulate_size_upto(pkt, type);
DEBUG("ipv6_ext: duplicating %d octets\n", (int) size);
gnrc_pktsnip_t *tmp;
gnrc_pktsnip_t *target = gnrc_pktsnip_search_type(pkt, GNRC_NETTYPE_IPV6);
gnrc_pktsnip_t *next = (target == NULL) ? NULL : target->next;
gnrc_pktsnip_t *new = gnrc_pktbuf_add(next, NULL, size, type);
if (new == NULL) {
return NULL;
}
/* copy payloads */
for (tmp = pkt; tmp != NULL; tmp = tmp->next) {
uint8_t *dest = ((uint8_t *)new->data) + (size - tmp->size);
memcpy(dest, tmp->data, tmp->size);
size -= tmp->size;
if (tmp->type == type) {
break;
}
}
/* decrements reference counters */
if (target != NULL) {
target->next = NULL;
}
gnrc_pktbuf_release(pkt);
if (is_shared && (target != NULL)) {
target->next = next;
}
return new;
}
enum gnrc_ipv6_ext_demux_status { enum gnrc_ipv6_ext_demux_status {
GNRC_IPV6_EXT_OK, GNRC_IPV6_EXT_OK,
GNRC_IPV6_EXT_FORWARDED, GNRC_IPV6_EXT_FORWARDED,
...@@ -155,10 +47,10 @@ static enum gnrc_ipv6_ext_demux_status _handle_rh(gnrc_pktsnip_t *current, gnrc_ ...@@ -155,10 +47,10 @@ static enum gnrc_ipv6_ext_demux_status _handle_rh(gnrc_pktsnip_t *current, gnrc_
the head. `ipv6_ext_rh_process` modifies the IPv6 header as well as the head. `ipv6_ext_rh_process` modifies the IPv6 header as well as
the extension header */ the extension header */
current_offset = _cumulate_size_upto(current->next, GNRC_NETTYPE_IPV6); current_offset = gnrc_pkt_len_upto(current->next, GNRC_NETTYPE_IPV6);
if (pkt->users != 1) { if (pkt->users != 1) {
if ((ipv6 = _duplicate_upto(pkt, GNRC_NETTYPE_IPV6)) == NULL) { if ((ipv6 = gnrc_pktbuf_duplicate_upto(pkt, GNRC_NETTYPE_IPV6)) == NULL) {
DEBUG("ipv6: could not get a copy of pkt\n"); DEBUG("ipv6: could not get a copy of pkt\n");
gnrc_pktbuf_release(pkt); gnrc_pktbuf_release(pkt);
return GNRC_IPV6_EXT_ERROR; return GNRC_IPV6_EXT_ERROR;
......
...@@ -217,9 +217,8 @@ void gnrc_pktbuf_hold(gnrc_pktsnip_t *pkt, unsigned int num) ...@@ -217,9 +217,8 @@ void gnrc_pktbuf_hold(gnrc_pktsnip_t *pkt, unsigned int num)
mutex_unlock(&_mutex); mutex_unlock(&_mutex);
} }
void gnrc_pktbuf_release_error(gnrc_pktsnip_t *pkt, uint32_t err) static void _release_error_locked(gnrc_pktsnip_t *pkt, uint32_t err)
{ {
mutex_lock(&_mutex);
while (pkt) { while (pkt) {
gnrc_pktsnip_t *tmp; gnrc_pktsnip_t *tmp;
assert(_pktbuf_contains(pkt)); assert(_pktbuf_contains(pkt));
...@@ -236,6 +235,12 @@ void gnrc_pktbuf_release_error(gnrc_pktsnip_t *pkt, uint32_t err) ...@@ -236,6 +235,12 @@ void gnrc_pktbuf_release_error(gnrc_pktsnip_t *pkt, uint32_t err)
gnrc_neterr_report(pkt, err); gnrc_neterr_report(pkt, err);
pkt = tmp; pkt = tmp;
} }
}
void gnrc_pktbuf_release_error(gnrc_pktsnip_t *pkt, uint32_t err)
{
mutex_lock(&_mutex);
_release_error_locked(pkt, err);
mutex_unlock(&_mutex); mutex_unlock(&_mutex);
} }
...@@ -526,4 +531,54 @@ gnrc_pktsnip_t *gnrc_pktbuf_replace_snip(gnrc_pktsnip_t *pkt, gnrc_pktsnip_t *ol ...@@ -526,4 +531,54 @@ gnrc_pktsnip_t *gnrc_pktbuf_replace_snip(gnrc_pktsnip_t *pkt, gnrc_pktsnip_t *ol
return pkt; return pkt;
} }
gnrc_pktsnip_t *gnrc_pktbuf_duplicate_upto(gnrc_pktsnip_t *pkt, gnrc_nettype_t type)
{
mutex_lock(&_mutex);
bool is_shared = pkt->users > 1;
size_t size = gnrc_pkt_len_upto(pkt, type);
DEBUG("ipv6_ext: duplicating %d octets\n", (int) size);
gnrc_pktsnip_t *tmp;
gnrc_pktsnip_t *target = gnrc_pktsnip_search_type(pkt, type);
gnrc_pktsnip_t *next = (target == NULL) ? NULL : target->next;
gnrc_pktsnip_t *new = _create_snip(next, NULL, size, type);
if (new == NULL) {
mutex_unlock(&_mutex);
return NULL;
}
/* copy payloads */
for (tmp = pkt; tmp != NULL; tmp = tmp->next) {
uint8_t *dest = ((uint8_t *)new->data) + (size - tmp->size);
memcpy(dest, tmp->data, tmp->size);
size -= tmp->size;
if (tmp->type == type) {
break;
}
}
/* decrements reference counters */
if (target != NULL) {
target->next = NULL;
}
_release_error_locked(pkt, GNRC_NETERR_SUCCESS);
if (is_shared && (target != NULL)) {
target->next = next;
}
mutex_unlock(&_mutex);
return new;
}
/** @} */ /** @} */
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment