1 #include "kvm/mutex.h"
2 #include "kvm/uip.h"
3
4 #include <linux/virtio_net.h>
5 #include <linux/kernel.h>
6 #include <linux/list.h>
7 #include <kvm/iovec.h>
8
uip_tx(struct iovec * iov,u16 out,struct uip_info * info)9 int uip_tx(struct iovec *iov, u16 out, struct uip_info *info)
10 {
11 void *vnet;
12 ssize_t len;
13 struct uip_tx_arg arg;
14 size_t eth_len, vnet_len;
15 struct uip_eth *eth;
16 void *vnet_buf = NULL;
17 void *eth_buf = NULL;
18 size_t iovcount = out;
19
20 u16 proto;
21
22 /*
23 * Buffer from guest to device
24 */
25 vnet_len = info->vnet_hdr_len;
26 vnet = iov[0].iov_base;
27
28 len = iov_size(iov, iovcount);
29 if (len <= (ssize_t)vnet_len)
30 return -EINVAL;
31
32 /* Try to avoid memcpy if possible */
33 if (iov[0].iov_len == vnet_len && out == 2) {
34 /* Legacy layout: first descriptor for vnet header */
35 eth = iov[1].iov_base;
36 eth_len = iov[1].iov_len;
37
38 } else if (out == 1) {
39 /* Single descriptor */
40 eth = (void *)vnet + vnet_len;
41 eth_len = iov[0].iov_len - vnet_len;
42
43 } else {
44 /* Any layout */
45 len = vnet_len;
46 vnet = vnet_buf = malloc(len);
47 if (!vnet)
48 return -ENOMEM;
49
50 len = memcpy_fromiovec_safe(vnet_buf, &iov, len, &iovcount);
51 if (len)
52 goto out_free_buf;
53
54 len = eth_len = iov_size(iov, iovcount);
55 eth = eth_buf = malloc(len);
56 if (!eth)
57 goto out_free_buf;
58
59 len = memcpy_fromiovec_safe(eth_buf, &iov, len, &iovcount);
60 if (len)
61 goto out_free_buf;
62 }
63
64 memset(&arg, 0, sizeof(arg));
65
66 arg.vnet_len = vnet_len;
67 arg.eth_len = eth_len;
68 arg.info = info;
69 arg.vnet = vnet;
70 arg.eth = eth;
71
72 /*
73 * Check package type
74 */
75 proto = ntohs(eth->type);
76
77 switch (proto) {
78 case UIP_ETH_P_ARP:
79 uip_tx_do_arp(&arg);
80 break;
81 case UIP_ETH_P_IP:
82 uip_tx_do_ipv4(&arg);
83 break;
84 }
85
86 free(vnet_buf);
87 free(eth_buf);
88
89 return vnet_len + eth_len;
90
91 out_free_buf:
92 free(vnet_buf);
93 free(eth_buf);
94 return -EINVAL;
95 }
96
uip_rx(struct iovec * iov,u16 in,struct uip_info * info)97 int uip_rx(struct iovec *iov, u16 in, struct uip_info *info)
98 {
99 struct uip_buf *buf;
100 int len;
101
102 /*
103 * Sleep until there is a buffer for guest
104 */
105 buf = uip_buf_get_used(info);
106
107 memcpy_toiovecend(iov, buf->vnet, 0, buf->vnet_len);
108 memcpy_toiovecend(iov, buf->eth, buf->vnet_len, buf->eth_len);
109
110 len = buf->vnet_len + buf->eth_len;
111
112 uip_buf_set_free(info, buf);
113 return len;
114 }
115
uip_static_init(struct uip_info * info)116 void uip_static_init(struct uip_info *info)
117 {
118 struct list_head *udp_socket_head;
119 struct list_head *tcp_socket_head;
120 struct list_head *buf_head;
121
122 udp_socket_head = &info->udp_socket_head;
123 tcp_socket_head = &info->tcp_socket_head;
124 buf_head = &info->buf_head;
125
126 INIT_LIST_HEAD(udp_socket_head);
127 INIT_LIST_HEAD(tcp_socket_head);
128 INIT_LIST_HEAD(buf_head);
129
130 mutex_init(&info->udp_socket_lock);
131 mutex_init(&info->tcp_socket_lock);
132 mutex_init(&info->buf_lock);
133
134 pthread_cond_init(&info->buf_used_cond, NULL);
135 pthread_cond_init(&info->buf_free_cond, NULL);
136
137 info->buf_used_nr = 0;
138 }
139
uip_init(struct uip_info * info)140 int uip_init(struct uip_info *info)
141 {
142 struct list_head *buf_head;
143 struct uip_buf *buf;
144 int buf_nr;
145 int i;
146
147 buf_head = &info->buf_head;
148 buf_nr = info->buf_nr;
149
150 for (i = 0; i < buf_nr; i++) {
151 buf = malloc(sizeof(*buf));
152 memset(buf, 0, sizeof(*buf));
153
154 buf->status = UIP_BUF_STATUS_FREE;
155 buf->info = info;
156 buf->id = i;
157 list_add_tail(&buf->list, buf_head);
158 }
159
160 list_for_each_entry(buf, buf_head, list) {
161 buf->vnet_len = info->vnet_hdr_len;
162 buf->vnet = malloc(buf->vnet_len);
163 buf->eth_len = 1024*64 + sizeof(struct uip_pseudo_hdr);
164 buf->eth = malloc(buf->eth_len);
165
166 memset(buf->vnet, 0, buf->vnet_len);
167 memset(buf->eth, 0, buf->eth_len);
168 }
169
170 info->buf_free_nr = buf_nr;
171
172 uip_dhcp_get_dns(info);
173
174 return 0;
175 }
176
uip_exit(struct uip_info * info)177 void uip_exit(struct uip_info *info)
178 {
179 struct uip_buf *buf, *next;
180
181 uip_udp_exit(info);
182 uip_tcp_exit(info);
183 uip_dhcp_exit(info);
184
185 list_for_each_entry_safe(buf, next, &info->buf_head, list) {
186 free(buf->vnet);
187 free(buf->eth);
188 list_del(&buf->list);
189 free(buf);
190 }
191 uip_static_init(info);
192 }
193