191b10270SAsias He #include "kvm/mutex.h" 291b10270SAsias He #include "kvm/uip.h" 391b10270SAsias He 491b10270SAsias He #include <linux/virtio_net.h> 591b10270SAsias He #include <linux/kernel.h> 691b10270SAsias He #include <linux/list.h> 791b10270SAsias He 80c847458SAsias He int uip_tx(struct iovec *iov, u16 out, struct uip_info *info) 90c847458SAsias He { 100c847458SAsias He struct virtio_net_hdr *vnet; 110c847458SAsias He struct uip_tx_arg arg; 120c847458SAsias He int eth_len, vnet_len; 130c847458SAsias He struct uip_eth *eth; 140c847458SAsias He u8 *buf = NULL; 150c847458SAsias He u16 proto; 160c847458SAsias He int i; 170c847458SAsias He 180c847458SAsias He /* 190c847458SAsias He * Buffer from guest to device 200c847458SAsias He */ 210c847458SAsias He vnet_len = iov[0].iov_len; 220c847458SAsias He vnet = iov[0].iov_base; 230c847458SAsias He 240c847458SAsias He eth_len = iov[1].iov_len; 250c847458SAsias He eth = iov[1].iov_base; 260c847458SAsias He 270c847458SAsias He /* 280c847458SAsias He * In case, ethernet frame is in more than one iov entry. 290c847458SAsias He * Copy iov buffer into one linear buffer. 300c847458SAsias He */ 310c847458SAsias He if (out > 2) { 320c847458SAsias He eth_len = 0; 330c847458SAsias He for (i = 1; i < out; i++) 340c847458SAsias He eth_len += iov[i].iov_len; 350c847458SAsias He 360c847458SAsias He buf = malloc(eth_len); 370c847458SAsias He if (!buf) 380c847458SAsias He return -1; 390c847458SAsias He 400c847458SAsias He eth = (struct uip_eth *)buf; 410c847458SAsias He for (i = 1; i < out; i++) { 420c847458SAsias He memcpy(buf, iov[i].iov_base, iov[i].iov_len); 430c847458SAsias He buf += iov[i].iov_len; 440c847458SAsias He } 450c847458SAsias He } 460c847458SAsias He 470c847458SAsias He memset(&arg, 0, sizeof(arg)); 480c847458SAsias He 490c847458SAsias He arg.vnet_len = vnet_len; 500c847458SAsias He arg.eth_len = eth_len; 510c847458SAsias He arg.info = info; 520c847458SAsias He arg.vnet = vnet; 530c847458SAsias He arg.eth = eth; 540c847458SAsias He 550c847458SAsias He /* 560c847458SAsias He * Check package type 570c847458SAsias He */ 580c847458SAsias He proto = ntohs(eth->type); 590c847458SAsias He 600c847458SAsias He switch (proto) { 610c847458SAsias He case UIP_ETH_P_ARP: 620c847458SAsias He uip_tx_do_arp(&arg); 630c847458SAsias He break; 640c847458SAsias He case UIP_ETH_P_IP: 650c847458SAsias He uip_tx_do_ipv4(&arg); 660c847458SAsias He break; 670c847458SAsias He default: 680c847458SAsias He break; 690c847458SAsias He } 700c847458SAsias He 710c847458SAsias He if (out > 2 && buf) 720c847458SAsias He free(eth); 730c847458SAsias He 740c847458SAsias He return vnet_len + eth_len; 750c847458SAsias He } 760c847458SAsias He 77*60d2902cSAsias He int uip_rx(struct iovec *iov, u16 in, struct uip_info *info) 78*60d2902cSAsias He { 79*60d2902cSAsias He struct virtio_net_hdr *vnet; 80*60d2902cSAsias He struct uip_eth *eth; 81*60d2902cSAsias He struct uip_buf *buf; 82*60d2902cSAsias He int vnet_len; 83*60d2902cSAsias He int eth_len; 84*60d2902cSAsias He char *p; 85*60d2902cSAsias He int len; 86*60d2902cSAsias He int cnt; 87*60d2902cSAsias He int i; 88*60d2902cSAsias He 89*60d2902cSAsias He /* 90*60d2902cSAsias He * Sleep until there is a buffer for guest 91*60d2902cSAsias He */ 92*60d2902cSAsias He buf = uip_buf_get_used(info); 93*60d2902cSAsias He 94*60d2902cSAsias He /* 95*60d2902cSAsias He * Fill device to guest buffer, vnet hdr fisrt 96*60d2902cSAsias He */ 97*60d2902cSAsias He vnet_len = iov[0].iov_len; 98*60d2902cSAsias He vnet = iov[0].iov_base; 99*60d2902cSAsias He if (buf->vnet_len > vnet_len) { 100*60d2902cSAsias He len = -1; 101*60d2902cSAsias He goto out; 102*60d2902cSAsias He } 103*60d2902cSAsias He memcpy(vnet, buf->vnet, buf->vnet_len); 104*60d2902cSAsias He 105*60d2902cSAsias He /* 106*60d2902cSAsias He * Then, the real eth data 107*60d2902cSAsias He * Note: Be sure buf->eth_len is not bigger than the buffer len that guest provides 108*60d2902cSAsias He */ 109*60d2902cSAsias He cnt = buf->eth_len; 110*60d2902cSAsias He p = buf->eth; 111*60d2902cSAsias He for (i = 1; i < in; i++) { 112*60d2902cSAsias He eth_len = iov[i].iov_len; 113*60d2902cSAsias He eth = iov[i].iov_base; 114*60d2902cSAsias He if (cnt > eth_len) { 115*60d2902cSAsias He memcpy(eth, p, eth_len); 116*60d2902cSAsias He cnt -= eth_len; 117*60d2902cSAsias He p += eth_len; 118*60d2902cSAsias He } else { 119*60d2902cSAsias He memcpy(eth, p, cnt); 120*60d2902cSAsias He cnt -= cnt; 121*60d2902cSAsias He break; 122*60d2902cSAsias He } 123*60d2902cSAsias He } 124*60d2902cSAsias He 125*60d2902cSAsias He if (cnt) { 126*60d2902cSAsias He pr_warning("uip_rx error"); 127*60d2902cSAsias He len = -1; 128*60d2902cSAsias He goto out; 129*60d2902cSAsias He } 130*60d2902cSAsias He 131*60d2902cSAsias He len = buf->vnet_len + buf->eth_len; 132*60d2902cSAsias He 133*60d2902cSAsias He out: 134*60d2902cSAsias He uip_buf_set_free(info, buf); 135*60d2902cSAsias He return len; 136*60d2902cSAsias He } 137*60d2902cSAsias He 13891b10270SAsias He int uip_init(struct uip_info *info) 13991b10270SAsias He { 14091b10270SAsias He struct list_head *udp_socket_head; 14191b10270SAsias He struct list_head *tcp_socket_head; 14291b10270SAsias He struct list_head *buf_head; 14391b10270SAsias He struct uip_buf *buf; 14491b10270SAsias He int buf_nr; 14591b10270SAsias He int i; 14691b10270SAsias He 14791b10270SAsias He udp_socket_head = &info->udp_socket_head; 14891b10270SAsias He tcp_socket_head = &info->tcp_socket_head; 14991b10270SAsias He buf_head = &info->buf_head; 15091b10270SAsias He buf_nr = info->buf_nr; 15191b10270SAsias He 15291b10270SAsias He INIT_LIST_HEAD(udp_socket_head); 15391b10270SAsias He INIT_LIST_HEAD(tcp_socket_head); 15491b10270SAsias He INIT_LIST_HEAD(buf_head); 15591b10270SAsias He 15691b10270SAsias He pthread_mutex_init(&info->udp_socket_lock, NULL); 15791b10270SAsias He pthread_mutex_init(&info->tcp_socket_lock, NULL); 15891b10270SAsias He pthread_mutex_init(&info->buf_lock, NULL); 15991b10270SAsias He 16091b10270SAsias He pthread_cond_init(&info->buf_used_cond, NULL); 16191b10270SAsias He pthread_cond_init(&info->buf_free_cond, NULL); 16291b10270SAsias He 16391b10270SAsias He 16491b10270SAsias He for (i = 0; i < buf_nr; i++) { 16591b10270SAsias He buf = malloc(sizeof(*buf)); 16691b10270SAsias He memset(buf, 0, sizeof(*buf)); 16791b10270SAsias He 16891b10270SAsias He buf->status = UIP_BUF_STATUS_FREE; 16991b10270SAsias He buf->info = info; 17091b10270SAsias He buf->id = i; 17191b10270SAsias He list_add_tail(&buf->list, buf_head); 17291b10270SAsias He } 17391b10270SAsias He 17491b10270SAsias He list_for_each_entry(buf, buf_head, list) { 17591b10270SAsias He buf->vnet = malloc(sizeof(struct virtio_net_hdr)); 17691b10270SAsias He buf->vnet_len = sizeof(struct virtio_net_hdr); 17791b10270SAsias He buf->eth = malloc(1024*64 + sizeof(struct uip_pseudo_hdr)); 17891b10270SAsias He buf->eth_len = 1024*64 + sizeof(struct uip_pseudo_hdr); 17991b10270SAsias He 18091b10270SAsias He memset(buf->vnet, 0, buf->vnet_len); 18191b10270SAsias He memset(buf->eth, 0, buf->eth_len); 18291b10270SAsias He } 18391b10270SAsias He 18491b10270SAsias He info->buf_free_nr = buf_nr; 18591b10270SAsias He info->buf_used_nr = 0; 18691b10270SAsias He 18791b10270SAsias He return 0; 18891b10270SAsias He } 189