func: static int virtio_net_handle_mac(VirtIONet *n, uint8_t cmd,
  
                                   struct iovec *iov, unsigned int iov_cnt)
  
  {
  
      struct virtio_net_ctrl_mac mac_data;
  
      size_t s;
  
      NetClientState *nc = qemu_get_queue(n->nic);
  
  
  
      if (cmd == VIRTIO_NET_CTRL_MAC_ADDR_SET) {
  
          if (iov_size(iov, iov_cnt) != sizeof(n->mac)) {
  
              return VIRTIO_NET_ERR;
  
          }
  
          s = iov_to_buf(iov, iov_cnt, 0, &n->mac, sizeof(n->mac));
  
          assert(s == sizeof(n->mac));
  
          qemu_format_nic_info_str(qemu_get_queue(n->nic), n->mac);
  
          rxfilter_notify(nc);
  
  
  
          return VIRTIO_NET_OK;
  
      }
  
  
  
      if (cmd != VIRTIO_NET_CTRL_MAC_TABLE_SET) {
  
          return VIRTIO_NET_ERR;
  
      }
  
  
  
      int in_use = 0;
  
      int first_multi = 0;
  
      uint8_t uni_overflow = 0;
  
      uint8_t multi_overflow = 0;
  
      uint8_t *macs = g_malloc0(MAC_TABLE_ENTRIES * ETH_ALEN);
  
  
  
      s = iov_to_buf(iov, iov_cnt, 0, &mac_data.entries,
  
                     sizeof(mac_data.entries));
  
      mac_data.entries = ldl_p(&mac_data.entries);
  
      if (s != sizeof(mac_data.entries)) {
  
          goto error;
  
      }
  
      iov_discard_front(&iov, &iov_cnt, s);
  
  
  
      if (mac_data.entries * ETH_ALEN > iov_size(iov, iov_cnt)) {
  
          goto error;
  
      }
  
  
  
      if (mac_data.entries <= MAC_TABLE_ENTRIES) {
  
          s = iov_to_buf(iov, iov_cnt, 0, macs,
  
                         mac_data.entries * ETH_ALEN);
  
          if (s != mac_data.entries * ETH_ALEN) {
  
              goto error;
  
          }
  
          in_use += mac_data.entries;
  
      } else {
  
          uni_overflow = 1;
  
      }
  
  
  
      iov_discard_front(&iov, &iov_cnt, mac_data.entries * ETH_ALEN);
  
  
  
      first_multi = in_use;
  
  
  
      s = iov_to_buf(iov, iov_cnt, 0, &mac_data.entries,
  
                     sizeof(mac_data.entries));
  
      mac_data.entries = ldl_p(&mac_data.entries);
  
      if (s != sizeof(mac_data.entries)) {
  
          goto error;
  
      }
  
  
  
      iov_discard_front(&iov, &iov_cnt, s);
  
  
  
      if (mac_data.entries * ETH_ALEN != iov_size(iov, iov_cnt)) {
  
          goto error;
  
      }
  
  
  
      if (in_use + mac_data.entries <= MAC_TABLE_ENTRIES) {
  
          s = iov_to_buf(iov, iov_cnt, 0, &macs[in_use * ETH_ALEN],
  
                         mac_data.entries * ETH_ALEN);
  
          if (s != mac_data.entries * ETH_ALEN) {
  
              goto error;
  
          }
  
          in_use += mac_data.entries;
  
      } else {
  
          multi_overflow = 1;
  
      }
  
  
  
      n->mac_table.in_use = in_use;
  
      n->mac_table.first_multi = first_multi;
  
      n->mac_table.uni_overflow = uni_overflow;
  
      n->mac_table.multi_overflow = multi_overflow;
  
      memcpy(n->mac_table.macs, macs, MAC_TABLE_ENTRIES * ETH_ALEN);
  
      g_free(macs);
  
      rxfilter_notify(nc);
  
  
  
      return VIRTIO_NET_OK;
  
  
  
  error:
  
      g_free(macs);
  
      return VIRTIO_NET_ERR;
  
  }
  