xref: /kvmtool/net/uip/core.c (revision 0c847458003a6f37784eef39e86c96352ba1bfe2)
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 
8*0c847458SAsias He int uip_tx(struct iovec *iov, u16 out, struct uip_info *info)
9*0c847458SAsias He {
10*0c847458SAsias He 	struct virtio_net_hdr *vnet;
11*0c847458SAsias He 	struct uip_tx_arg arg;
12*0c847458SAsias He 	int eth_len, vnet_len;
13*0c847458SAsias He 	struct uip_eth *eth;
14*0c847458SAsias He 	u8 *buf = NULL;
15*0c847458SAsias He 	u16 proto;
16*0c847458SAsias He 	int i;
17*0c847458SAsias He 
18*0c847458SAsias He 	/*
19*0c847458SAsias He 	 * Buffer from guest to device
20*0c847458SAsias He 	 */
21*0c847458SAsias He 	vnet_len = iov[0].iov_len;
22*0c847458SAsias He 	vnet	 = iov[0].iov_base;
23*0c847458SAsias He 
24*0c847458SAsias He 	eth_len	 = iov[1].iov_len;
25*0c847458SAsias He 	eth	 = iov[1].iov_base;
26*0c847458SAsias He 
27*0c847458SAsias He 	/*
28*0c847458SAsias He 	 * In case, ethernet frame is in more than one iov entry.
29*0c847458SAsias He 	 * Copy iov buffer into one linear buffer.
30*0c847458SAsias He 	 */
31*0c847458SAsias He 	if (out > 2) {
32*0c847458SAsias He 		eth_len = 0;
33*0c847458SAsias He 		for (i = 1; i < out; i++)
34*0c847458SAsias He 			eth_len += iov[i].iov_len;
35*0c847458SAsias He 
36*0c847458SAsias He 		buf = malloc(eth_len);
37*0c847458SAsias He 		if (!buf)
38*0c847458SAsias He 			return -1;
39*0c847458SAsias He 
40*0c847458SAsias He 		eth = (struct uip_eth *)buf;
41*0c847458SAsias He 		for (i = 1; i < out; i++) {
42*0c847458SAsias He 			memcpy(buf, iov[i].iov_base, iov[i].iov_len);
43*0c847458SAsias He 			buf += iov[i].iov_len;
44*0c847458SAsias He 		}
45*0c847458SAsias He 	}
46*0c847458SAsias He 
47*0c847458SAsias He 	memset(&arg, 0, sizeof(arg));
48*0c847458SAsias He 
49*0c847458SAsias He 	arg.vnet_len = vnet_len;
50*0c847458SAsias He 	arg.eth_len = eth_len;
51*0c847458SAsias He 	arg.info = info;
52*0c847458SAsias He 	arg.vnet = vnet;
53*0c847458SAsias He 	arg.eth = eth;
54*0c847458SAsias He 
55*0c847458SAsias He 	/*
56*0c847458SAsias He 	 * Check package type
57*0c847458SAsias He 	 */
58*0c847458SAsias He 	proto = ntohs(eth->type);
59*0c847458SAsias He 
60*0c847458SAsias He 	switch (proto) {
61*0c847458SAsias He 	case UIP_ETH_P_ARP:
62*0c847458SAsias He 		uip_tx_do_arp(&arg);
63*0c847458SAsias He 		break;
64*0c847458SAsias He 	case UIP_ETH_P_IP:
65*0c847458SAsias He 		uip_tx_do_ipv4(&arg);
66*0c847458SAsias He 		break;
67*0c847458SAsias He 	default:
68*0c847458SAsias He 		break;
69*0c847458SAsias He 	}
70*0c847458SAsias He 
71*0c847458SAsias He 	if (out > 2 && buf)
72*0c847458SAsias He 		free(eth);
73*0c847458SAsias He 
74*0c847458SAsias He 	return vnet_len + eth_len;
75*0c847458SAsias He }
76*0c847458SAsias He 
7791b10270SAsias He int uip_init(struct uip_info *info)
7891b10270SAsias He {
7991b10270SAsias He 	struct list_head *udp_socket_head;
8091b10270SAsias He 	struct list_head *tcp_socket_head;
8191b10270SAsias He 	struct list_head *buf_head;
8291b10270SAsias He 	struct uip_buf *buf;
8391b10270SAsias He 	int buf_nr;
8491b10270SAsias He 	int i;
8591b10270SAsias He 
8691b10270SAsias He 	udp_socket_head	= &info->udp_socket_head;
8791b10270SAsias He 	tcp_socket_head	= &info->tcp_socket_head;
8891b10270SAsias He 	buf_head	= &info->buf_head;
8991b10270SAsias He 	buf_nr		= info->buf_nr;
9091b10270SAsias He 
9191b10270SAsias He 	INIT_LIST_HEAD(udp_socket_head);
9291b10270SAsias He 	INIT_LIST_HEAD(tcp_socket_head);
9391b10270SAsias He 	INIT_LIST_HEAD(buf_head);
9491b10270SAsias He 
9591b10270SAsias He 	pthread_mutex_init(&info->udp_socket_lock, NULL);
9691b10270SAsias He 	pthread_mutex_init(&info->tcp_socket_lock, NULL);
9791b10270SAsias He 	pthread_mutex_init(&info->buf_lock, NULL);
9891b10270SAsias He 
9991b10270SAsias He 	pthread_cond_init(&info->buf_used_cond, NULL);
10091b10270SAsias He 	pthread_cond_init(&info->buf_free_cond, NULL);
10191b10270SAsias He 
10291b10270SAsias He 
10391b10270SAsias He 	for (i = 0; i < buf_nr; i++) {
10491b10270SAsias He 		buf = malloc(sizeof(*buf));
10591b10270SAsias He 		memset(buf, 0, sizeof(*buf));
10691b10270SAsias He 
10791b10270SAsias He 		buf->status	= UIP_BUF_STATUS_FREE;
10891b10270SAsias He 		buf->info	= info;
10991b10270SAsias He 		buf->id		= i;
11091b10270SAsias He 		list_add_tail(&buf->list, buf_head);
11191b10270SAsias He 	}
11291b10270SAsias He 
11391b10270SAsias He 	list_for_each_entry(buf, buf_head, list) {
11491b10270SAsias He 		buf->vnet	= malloc(sizeof(struct virtio_net_hdr));
11591b10270SAsias He 		buf->vnet_len	= sizeof(struct virtio_net_hdr);
11691b10270SAsias He 		buf->eth	= malloc(1024*64 + sizeof(struct uip_pseudo_hdr));
11791b10270SAsias He 		buf->eth_len	= 1024*64 + sizeof(struct uip_pseudo_hdr);
11891b10270SAsias He 
11991b10270SAsias He 		memset(buf->vnet, 0, buf->vnet_len);
12091b10270SAsias He 		memset(buf->eth, 0, buf->eth_len);
12191b10270SAsias He 	}
12291b10270SAsias He 
12391b10270SAsias He 	info->buf_free_nr = buf_nr;
12491b10270SAsias He 	info->buf_used_nr = 0;
12591b10270SAsias He 
12691b10270SAsias He 	return 0;
12791b10270SAsias He }
128