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> 77200d3a1SSasha Levin #include <kvm/iovec.h> 891b10270SAsias He 90c847458SAsias He int uip_tx(struct iovec *iov, u16 out, struct uip_info *info) 100c847458SAsias He { 117668c3a6SSasha Levin void *vnet; 120c847458SAsias He struct uip_tx_arg arg; 130c847458SAsias He int eth_len, vnet_len; 140c847458SAsias He struct uip_eth *eth; 150c847458SAsias He u8 *buf = NULL; 160c847458SAsias He u16 proto; 170c847458SAsias He int i; 180c847458SAsias He 190c847458SAsias He /* 200c847458SAsias He * Buffer from guest to device 210c847458SAsias He */ 220c847458SAsias He vnet_len = iov[0].iov_len; 230c847458SAsias He vnet = iov[0].iov_base; 240c847458SAsias He 250c847458SAsias He eth_len = iov[1].iov_len; 260c847458SAsias He eth = iov[1].iov_base; 270c847458SAsias He 280c847458SAsias He /* 290c847458SAsias He * In case, ethernet frame is in more than one iov entry. 300c847458SAsias He * Copy iov buffer into one linear buffer. 310c847458SAsias He */ 320c847458SAsias He if (out > 2) { 330c847458SAsias He eth_len = 0; 340c847458SAsias He for (i = 1; i < out; i++) 350c847458SAsias He eth_len += iov[i].iov_len; 360c847458SAsias He 370c847458SAsias He buf = malloc(eth_len); 380c847458SAsias He if (!buf) 396d6cc14bSWill Deacon return -ENOMEM; 400c847458SAsias He 410c847458SAsias He eth = (struct uip_eth *)buf; 420c847458SAsias He for (i = 1; i < out; i++) { 430c847458SAsias He memcpy(buf, iov[i].iov_base, iov[i].iov_len); 440c847458SAsias He buf += iov[i].iov_len; 450c847458SAsias He } 460c847458SAsias He } 470c847458SAsias He 480c847458SAsias He memset(&arg, 0, sizeof(arg)); 490c847458SAsias He 500c847458SAsias He arg.vnet_len = vnet_len; 510c847458SAsias He arg.eth_len = eth_len; 520c847458SAsias He arg.info = info; 530c847458SAsias He arg.vnet = vnet; 540c847458SAsias He arg.eth = eth; 550c847458SAsias He 560c847458SAsias He /* 570c847458SAsias He * Check package type 580c847458SAsias He */ 590c847458SAsias He proto = ntohs(eth->type); 600c847458SAsias He 610c847458SAsias He switch (proto) { 620c847458SAsias He case UIP_ETH_P_ARP: 630c847458SAsias He uip_tx_do_arp(&arg); 640c847458SAsias He break; 650c847458SAsias He case UIP_ETH_P_IP: 660c847458SAsias He uip_tx_do_ipv4(&arg); 670c847458SAsias He break; 680c847458SAsias He default: 690c847458SAsias He break; 700c847458SAsias He } 710c847458SAsias He 720c847458SAsias He if (out > 2 && buf) 730c847458SAsias He free(eth); 740c847458SAsias He 750c847458SAsias He return vnet_len + eth_len; 760c847458SAsias He } 770c847458SAsias He 7860d2902cSAsias He int uip_rx(struct iovec *iov, u16 in, struct uip_info *info) 7960d2902cSAsias He { 8060d2902cSAsias He struct uip_buf *buf; 8160d2902cSAsias He int len; 8260d2902cSAsias He 8360d2902cSAsias He /* 8460d2902cSAsias He * Sleep until there is a buffer for guest 8560d2902cSAsias He */ 8660d2902cSAsias He buf = uip_buf_get_used(info); 8760d2902cSAsias He 887200d3a1SSasha Levin memcpy_toiovecend(iov, buf->vnet, 0, buf->vnet_len); 897200d3a1SSasha Levin memcpy_toiovecend(iov, buf->eth, buf->vnet_len, buf->eth_len); 9060d2902cSAsias He 9160d2902cSAsias He len = buf->vnet_len + buf->eth_len; 9260d2902cSAsias He 9360d2902cSAsias He uip_buf_set_free(info, buf); 9460d2902cSAsias He return len; 9560d2902cSAsias He } 9660d2902cSAsias He 975f3aaf22SMarc Zyngier void uip_static_init(struct uip_info *info) 9891b10270SAsias He { 9991b10270SAsias He struct list_head *udp_socket_head; 10091b10270SAsias He struct list_head *tcp_socket_head; 10191b10270SAsias He struct list_head *buf_head; 10291b10270SAsias He 10391b10270SAsias He udp_socket_head = &info->udp_socket_head; 10491b10270SAsias He tcp_socket_head = &info->tcp_socket_head; 10591b10270SAsias He buf_head = &info->buf_head; 10691b10270SAsias He 10791b10270SAsias He INIT_LIST_HEAD(udp_socket_head); 10891b10270SAsias He INIT_LIST_HEAD(tcp_socket_head); 10991b10270SAsias He INIT_LIST_HEAD(buf_head); 11091b10270SAsias He 111d3476f7dSSasha Levin mutex_init(&info->udp_socket_lock); 112d3476f7dSSasha Levin mutex_init(&info->tcp_socket_lock); 113d3476f7dSSasha Levin mutex_init(&info->buf_lock); 11491b10270SAsias He 11591b10270SAsias He pthread_cond_init(&info->buf_used_cond, NULL); 11691b10270SAsias He pthread_cond_init(&info->buf_free_cond, NULL); 11791b10270SAsias He 1185f3aaf22SMarc Zyngier info->buf_used_nr = 0; 1195f3aaf22SMarc Zyngier } 1205f3aaf22SMarc Zyngier 1215f3aaf22SMarc Zyngier int uip_init(struct uip_info *info) 1225f3aaf22SMarc Zyngier { 1235f3aaf22SMarc Zyngier struct list_head *buf_head; 1245f3aaf22SMarc Zyngier struct uip_buf *buf; 1255f3aaf22SMarc Zyngier int buf_nr; 1265f3aaf22SMarc Zyngier int i; 1275f3aaf22SMarc Zyngier 1285f3aaf22SMarc Zyngier buf_head = &info->buf_head; 1295f3aaf22SMarc Zyngier buf_nr = info->buf_nr; 13091b10270SAsias He 13191b10270SAsias He for (i = 0; i < buf_nr; i++) { 13291b10270SAsias He buf = malloc(sizeof(*buf)); 13391b10270SAsias He memset(buf, 0, sizeof(*buf)); 13491b10270SAsias He 13591b10270SAsias He buf->status = UIP_BUF_STATUS_FREE; 13691b10270SAsias He buf->info = info; 13791b10270SAsias He buf->id = i; 13891b10270SAsias He list_add_tail(&buf->list, buf_head); 13991b10270SAsias He } 14091b10270SAsias He 14191b10270SAsias He list_for_each_entry(buf, buf_head, list) { 142643f6c08SSasha Levin buf->vnet_len = info->vnet_hdr_len; 143643f6c08SSasha Levin buf->vnet = malloc(buf->vnet_len); 14491b10270SAsias He buf->eth_len = 1024*64 + sizeof(struct uip_pseudo_hdr); 145643f6c08SSasha Levin buf->eth = malloc(buf->eth_len); 14691b10270SAsias He 14791b10270SAsias He memset(buf->vnet, 0, buf->vnet_len); 14891b10270SAsias He memset(buf->eth, 0, buf->eth_len); 14991b10270SAsias He } 15091b10270SAsias He 15191b10270SAsias He info->buf_free_nr = buf_nr; 15291b10270SAsias He 15380f43f64SAsias He uip_dhcp_get_dns(info); 15480f43f64SAsias He 15591b10270SAsias He return 0; 15691b10270SAsias He } 157*d87b503fSJean-Philippe Brucker 158*d87b503fSJean-Philippe Brucker void uip_exit(struct uip_info *info) 159*d87b503fSJean-Philippe Brucker { 160*d87b503fSJean-Philippe Brucker struct uip_buf *buf, *next; 161*d87b503fSJean-Philippe Brucker 162*d87b503fSJean-Philippe Brucker uip_udp_exit(info); 163*d87b503fSJean-Philippe Brucker uip_tcp_exit(info); 164*d87b503fSJean-Philippe Brucker uip_dhcp_exit(info); 165*d87b503fSJean-Philippe Brucker 166*d87b503fSJean-Philippe Brucker list_for_each_entry_safe(buf, next, &info->buf_head, list) { 167*d87b503fSJean-Philippe Brucker free(buf->vnet); 168*d87b503fSJean-Philippe Brucker free(buf->eth); 169*d87b503fSJean-Philippe Brucker list_del(&buf->list); 170*d87b503fSJean-Philippe Brucker free(buf); 171*d87b503fSJean-Philippe Brucker } 172*d87b503fSJean-Philippe Brucker uip_static_init(info); 173*d87b503fSJean-Philippe Brucker } 174