static bool net_tx_pkt_parse_headers(struct NetTxPkt *pkt)

{

    struct iovec *l2_hdr, *l3_hdr;

    size_t bytes_read;

    size_t full_ip6hdr_len;

    uint16_t l3_proto;



    assert(pkt);



    l2_hdr = &pkt->vec[NET_TX_PKT_L2HDR_FRAG];

    l3_hdr = &pkt->vec[NET_TX_PKT_L3HDR_FRAG];



    bytes_read = iov_to_buf(pkt->raw, pkt->raw_frags, 0, l2_hdr->iov_base,

                            ETH_MAX_L2_HDR_LEN);

    if (bytes_read < sizeof(struct eth_header)) {

        l2_hdr->iov_len = 0;

        return false;

    }



    l2_hdr->iov_len = sizeof(struct eth_header);

    switch (be16_to_cpu(PKT_GET_ETH_HDR(l2_hdr->iov_base)->h_proto)) {

    case ETH_P_VLAN:

        l2_hdr->iov_len += sizeof(struct vlan_header);

        break;

    case ETH_P_DVLAN:

        l2_hdr->iov_len += 2 * sizeof(struct vlan_header);

        break;

    }



    if (bytes_read < l2_hdr->iov_len) {

        l2_hdr->iov_len = 0;

        return false;

    }



    l3_proto = eth_get_l3_proto(l2_hdr->iov_base, l2_hdr->iov_len);



    switch (l3_proto) {

    case ETH_P_IP:

        l3_hdr->iov_base = g_malloc(ETH_MAX_IP4_HDR_LEN);



        bytes_read = iov_to_buf(pkt->raw, pkt->raw_frags, l2_hdr->iov_len,

                                l3_hdr->iov_base, sizeof(struct ip_header));



        if (bytes_read < sizeof(struct ip_header)) {

            l3_hdr->iov_len = 0;

            return false;

        }



        l3_hdr->iov_len = IP_HDR_GET_LEN(l3_hdr->iov_base);

        pkt->l4proto = ((struct ip_header *) l3_hdr->iov_base)->ip_p;



        /* copy optional IPv4 header data */

        bytes_read = iov_to_buf(pkt->raw, pkt->raw_frags,

                                l2_hdr->iov_len + sizeof(struct ip_header),

                                l3_hdr->iov_base + sizeof(struct ip_header),

                                l3_hdr->iov_len - sizeof(struct ip_header));

        if (bytes_read < l3_hdr->iov_len - sizeof(struct ip_header)) {

            l3_hdr->iov_len = 0;

            return false;

        }

        break;



    case ETH_P_IPV6:

        if (!eth_parse_ipv6_hdr(pkt->raw, pkt->raw_frags, l2_hdr->iov_len,

                               &pkt->l4proto, &full_ip6hdr_len)) {

            l3_hdr->iov_len = 0;

            return false;

        }



        l3_hdr->iov_base = g_malloc(full_ip6hdr_len);



        bytes_read = iov_to_buf(pkt->raw, pkt->raw_frags, l2_hdr->iov_len,

                                l3_hdr->iov_base, full_ip6hdr_len);



        if (bytes_read < full_ip6hdr_len) {

            l3_hdr->iov_len = 0;

            return false;

        } else {

            l3_hdr->iov_len = full_ip6hdr_len;

        }

        break;



    default:

        l3_hdr->iov_len = 0;

        break;

    }



    net_tx_pkt_calculate_hdr_len(pkt);

    pkt->packet_type = get_eth_packet_type(l2_hdr->iov_base);

    return true;

}
