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 7760d2902cSAsias He int uip_rx(struct iovec *iov, u16 in, struct uip_info *info) 7860d2902cSAsias He { 7960d2902cSAsias He struct virtio_net_hdr *vnet; 8060d2902cSAsias He struct uip_eth *eth; 8160d2902cSAsias He struct uip_buf *buf; 8260d2902cSAsias He int vnet_len; 8360d2902cSAsias He int eth_len; 8460d2902cSAsias He char *p; 8560d2902cSAsias He int len; 8660d2902cSAsias He int cnt; 8760d2902cSAsias He int i; 8860d2902cSAsias He 8960d2902cSAsias He /* 9060d2902cSAsias He * Sleep until there is a buffer for guest 9160d2902cSAsias He */ 9260d2902cSAsias He buf = uip_buf_get_used(info); 9360d2902cSAsias He 9460d2902cSAsias He /* 9560d2902cSAsias He * Fill device to guest buffer, vnet hdr fisrt 9660d2902cSAsias He */ 9760d2902cSAsias He vnet_len = iov[0].iov_len; 9860d2902cSAsias He vnet = iov[0].iov_base; 9960d2902cSAsias He if (buf->vnet_len > vnet_len) { 10060d2902cSAsias He len = -1; 10160d2902cSAsias He goto out; 10260d2902cSAsias He } 10360d2902cSAsias He memcpy(vnet, buf->vnet, buf->vnet_len); 10460d2902cSAsias He 10560d2902cSAsias He /* 10660d2902cSAsias He * Then, the real eth data 10760d2902cSAsias He * Note: Be sure buf->eth_len is not bigger than the buffer len that guest provides 10860d2902cSAsias He */ 10960d2902cSAsias He cnt = buf->eth_len; 11060d2902cSAsias He p = buf->eth; 11160d2902cSAsias He for (i = 1; i < in; i++) { 11260d2902cSAsias He eth_len = iov[i].iov_len; 11360d2902cSAsias He eth = iov[i].iov_base; 11460d2902cSAsias He if (cnt > eth_len) { 11560d2902cSAsias He memcpy(eth, p, eth_len); 11660d2902cSAsias He cnt -= eth_len; 11760d2902cSAsias He p += eth_len; 11860d2902cSAsias He } else { 11960d2902cSAsias He memcpy(eth, p, cnt); 12060d2902cSAsias He cnt -= cnt; 12160d2902cSAsias He break; 12260d2902cSAsias He } 12360d2902cSAsias He } 12460d2902cSAsias He 12560d2902cSAsias He if (cnt) { 12660d2902cSAsias He pr_warning("uip_rx error"); 12760d2902cSAsias He len = -1; 12860d2902cSAsias He goto out; 12960d2902cSAsias He } 13060d2902cSAsias He 13160d2902cSAsias He len = buf->vnet_len + buf->eth_len; 13260d2902cSAsias He 13360d2902cSAsias He out: 13460d2902cSAsias He uip_buf_set_free(info, buf); 13560d2902cSAsias He return len; 13660d2902cSAsias He } 13760d2902cSAsias 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 156*d3476f7dSSasha Levin mutex_init(&info->udp_socket_lock); 157*d3476f7dSSasha Levin mutex_init(&info->tcp_socket_lock); 158*d3476f7dSSasha Levin mutex_init(&info->buf_lock); 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 18780f43f64SAsias He uip_dhcp_get_dns(info); 18880f43f64SAsias He 18991b10270SAsias He return 0; 19091b10270SAsias He } 191