xref: /kvmtool/net/uip/core.c (revision d87b503f4d6e499dfcbc84fad3e4da7a900a3b47)
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