}
int uip_tx(struct iovec *iov, u16 out, struct uip_info *info);
+int uip_rx(struct iovec *iov, u16 in, struct uip_info *info);
int uip_init(struct uip_info *info);
int uip_tx_do_ipv4_icmp(struct uip_tx_arg *arg);
return vnet_len + eth_len;
}
+int uip_rx(struct iovec *iov, u16 in, struct uip_info *info)
+{
+ struct virtio_net_hdr *vnet;
+ struct uip_eth *eth;
+ struct uip_buf *buf;
+ int vnet_len;
+ int eth_len;
+ char *p;
+ int len;
+ int cnt;
+ int i;
+
+ /*
+ * Sleep until there is a buffer for guest
+ */
+ buf = uip_buf_get_used(info);
+
+ /*
+ * Fill device to guest buffer, vnet hdr fisrt
+ */
+ vnet_len = iov[0].iov_len;
+ vnet = iov[0].iov_base;
+ if (buf->vnet_len > vnet_len) {
+ len = -1;
+ goto out;
+ }
+ memcpy(vnet, buf->vnet, buf->vnet_len);
+
+ /*
+ * Then, the real eth data
+ * Note: Be sure buf->eth_len is not bigger than the buffer len that guest provides
+ */
+ cnt = buf->eth_len;
+ p = buf->eth;
+ for (i = 1; i < in; i++) {
+ eth_len = iov[i].iov_len;
+ eth = iov[i].iov_base;
+ if (cnt > eth_len) {
+ memcpy(eth, p, eth_len);
+ cnt -= eth_len;
+ p += eth_len;
+ } else {
+ memcpy(eth, p, cnt);
+ cnt -= cnt;
+ break;
+ }
+ }
+
+ if (cnt) {
+ pr_warning("uip_rx error");
+ len = -1;
+ goto out;
+ }
+
+ len = buf->vnet_len + buf->eth_len;
+
+out:
+ uip_buf_set_free(info, buf);
+ return len;
+}
+
int uip_init(struct uip_info *info)
{
struct list_head *udp_socket_head;