static int virtio_net_handle_mac(VirtIONet *n, uint8_t cmd,

                                 VirtQueueElement *elem)

{

    struct virtio_net_ctrl_mac mac_data;



    if (cmd != VIRTIO_NET_CTRL_MAC_TABLE_SET || elem->out_num != 3 ||

        elem->out_sg[1].iov_len < sizeof(mac_data) ||

        elem->out_sg[2].iov_len < sizeof(mac_data))

        return VIRTIO_NET_ERR;



    n->mac_table.in_use = 0;

    memset(n->mac_table.macs, 0, MAC_TABLE_ENTRIES * ETH_ALEN);



    mac_data.entries = ldl_le_p(elem->out_sg[1].iov_base);



    if (sizeof(mac_data.entries) +

        (mac_data.entries * ETH_ALEN) > elem->out_sg[1].iov_len)

        return VIRTIO_NET_ERR;



    if (mac_data.entries <= MAC_TABLE_ENTRIES) {

        memcpy(n->mac_table.macs, elem->out_sg[1].iov_base + sizeof(mac_data),

               mac_data.entries * ETH_ALEN);

        n->mac_table.in_use += mac_data.entries;

    } else {

        n->promisc = 1;

        return VIRTIO_NET_OK;

    }



    mac_data.entries = ldl_le_p(elem->out_sg[2].iov_base);



    if (sizeof(mac_data.entries) +

        (mac_data.entries * ETH_ALEN) > elem->out_sg[2].iov_len)

        return VIRTIO_NET_ERR;



    if (mac_data.entries) {

        if (n->mac_table.in_use + mac_data.entries <= MAC_TABLE_ENTRIES) {

            memcpy(n->mac_table.macs + (n->mac_table.in_use * ETH_ALEN),

                   elem->out_sg[2].iov_base + sizeof(mac_data),

                   mac_data.entries * ETH_ALEN);

            n->mac_table.in_use += mac_data.entries;

        } else

            n->allmulti = 1;

    }



    return VIRTIO_NET_OK;

}
