diff --git a/src/extra/pktbuff.c b/src/extra/pktbuff.c index 6250fbf3ac8b..985bb48ac986 100644 --- a/src/extra/pktbuff.c +++ b/src/extra/pktbuff.c @@ -29,6 +29,58 @@ * @{ */ +static struct pkt_buff *__pktb_alloc(int family, void *data, size_t len, + size_t extra) +{ + struct pkt_buff *pktb; + + pktb = calloc(1, sizeof(struct pkt_buff) + len + extra); + if (pktb == NULL) + return NULL; + + return pktb; +} + +static int pktb_setup_family(struct pkt_buff *pktb, int family) +{ + switch(family) { + case AF_INET: + case AF_INET6: + pktb->network_header = pktb->data; + break; + case AF_BRIDGE: { + struct ethhdr *ethhdr = (struct ethhdr *)pktb->data; + + pktb->mac_header = pktb->data; + + switch(ethhdr->h_proto) { + case ETH_P_IP: + case ETH_P_IPV6: + pktb->network_header = pktb->data + ETH_HLEN; + break; + default: + /* This protocol is unsupported. */ + errno = EPROTONOSUPPORT; + return -1; + } + break; + } + } + + return 0; +} + +static void pktb_setup_metadata(struct pkt_buff *pktb, void *pkt_data, + size_t len, size_t extra) +{ + pktb->len = len; + pktb->data_len = len + extra; + + pktb->head = pkt_data; + pktb->data = pkt_data; + pktb->tail = pktb->head + len; +} + /** * pktb_alloc - allocate a new packet buffer * \param family Indicate what family. Currently supported families are @@ -54,45 +106,41 @@ struct pkt_buff *pktb_alloc(int family, void *data, size_t len, size_t extra) struct pkt_buff *pktb; void *pkt_data; - pktb = calloc(1, sizeof(struct pkt_buff) + len + extra); - if (pktb == NULL) + pktb = __pktb_alloc(family, data, len, extra); + if (!pktb) return NULL; /* Better make sure alignment is correct. */ pkt_data = (uint8_t *)pktb + sizeof(struct pkt_buff); memcpy(pkt_data, data, len); - pktb->len = len; - pktb->data_len = len + extra; + pktb_setup_metadata(pktb, pkt_data, len, extra); - pktb->head = pkt_data; - pktb->data = pkt_data; - pktb->tail = pktb->head + len; + if (pktb_setup_family(pktb, family) < 0) { + free(pktb); + return NULL; + } - switch(family) { - case AF_INET: - case AF_INET6: - pktb->network_header = pktb->data; - break; - case AF_BRIDGE: { - struct ethhdr *ethhdr = (struct ethhdr *)pktb->data; + return pktb; +} - pktb->mac_header = pktb->data; +EXPORT_SYMBOL +struct pkt_buff *pktb_alloc_data(int family, void *data, size_t len) +{ + struct pkt_buff *pktb; - switch(ethhdr->h_proto) { - case ETH_P_IP: - case ETH_P_IPV6: - pktb->network_header = pktb->data + ETH_HLEN; - break; - default: - /* This protocol is unsupported. */ - errno = EPROTONOSUPPORT; - free(pktb); - return NULL; - } - break; - } + pktb = __pktb_alloc(family, data, 0, 0); + if (!pktb) + return NULL; + + pktb->data = data; + pktb_setup_metadata(pktb, data, len, 0); + + if (pktb_setup_family(pktb, family) < 0) { + free(pktb); + return NULL; } + return pktb; }