gnrc_pktbuf.c 2.15 KB
/*
 * Copyright (C) 2017 Freie Universität Berlin
 *
 * This file is subject to the terms and conditions of the GNU Lesser
 * General Public License v2.1. See the file LICENSE in the top level
 * directory for more details.
 */

/**
 * @{
 *
 * @file
 * @author  Martine Lenders <m.lenders@fu-berlin.de>
 */

#include <sys/uio.h>

#include "net/gnrc/pktbuf.h"

gnrc_pktsnip_t *gnrc_pktbuf_get_iovec(gnrc_pktsnip_t *pkt, size_t *len)
{
    size_t length;
    gnrc_pktsnip_t *head;
    struct iovec *vec;

    assert(len != NULL);
    if (pkt == NULL) {
        *len = 0;
        return NULL;
    }

    /* count the number of snips in the packet and allocate the IOVEC */
    length = gnrc_pkt_count(pkt);
    head = gnrc_pktbuf_add(pkt, NULL, (length * sizeof(struct iovec)),
                           GNRC_NETTYPE_IOVEC);
    if (head == NULL) {
        *len = 0;
        return NULL;
    }

    assert(head->data != NULL);
    vec = (struct iovec *)(head->data);
    /* fill the IOVEC */
    while (pkt != NULL) {
        vec->iov_base = pkt->data;
        vec->iov_len = pkt->size;
        ++vec;
        pkt = pkt->next;
    }
    *len = length;
    return head;
}

gnrc_pktsnip_t *gnrc_pktbuf_remove_snip(gnrc_pktsnip_t *pkt,
                                        gnrc_pktsnip_t *snip)
{
    LL_DELETE(pkt, snip);
    snip->next = NULL;
    gnrc_pktbuf_release(snip);

    return pkt;
}

gnrc_pktsnip_t *gnrc_pktbuf_replace_snip(gnrc_pktsnip_t *pkt,
                                         gnrc_pktsnip_t *old,
                                         gnrc_pktsnip_t *add)
{
    /* If add is a list we need to preserve its tail */
    if (add->next != NULL) {
        gnrc_pktsnip_t *tail = add->next;
        gnrc_pktsnip_t *back;
        LL_SEARCH_SCALAR(tail, back, next, NULL); /* find the last snip in add */
        /* Replace old */
        LL_REPLACE_ELEM(pkt, old, add);
        /* and wire in the tail between */
        back->next = add->next;
        add->next = tail;
    }
    else {
        /* add is a single element, has no tail, simply replace */
        LL_REPLACE_ELEM(pkt, old, add);
    }
    old->next = NULL;
    gnrc_pktbuf_release(old);

    return pkt;
}


/** @} */