xref: /kvmtool/net/uip/tcp.c (revision 3909f9b57bbf5e9c8654e2592abc9dc35878630a)
1 #include "kvm/uip.h"
2 
3 #include <linux/virtio_net.h>
4 #include <linux/kernel.h>
5 #include <linux/list.h>
6 #include <arpa/inet.h>
7 
8 static int uip_tcp_socket_close(struct uip_tcp_socket *sk, int how)
9 {
10 	shutdown(sk->fd, how);
11 
12 	if (sk->write_done && sk->read_done) {
13 		shutdown(sk->fd, SHUT_RDWR);
14 		close(sk->fd);
15 
16 		mutex_lock(sk->lock);
17 		list_del(&sk->list);
18 		mutex_unlock(sk->lock);
19 
20 		free(sk);
21 	}
22 
23 	return 0;
24 }
25 
26 static struct uip_tcp_socket *uip_tcp_socket_find(struct uip_tx_arg *arg, u32 sip, u32 dip, u16 sport, u16 dport)
27 {
28 	struct list_head *sk_head;
29 	pthread_mutex_t *sk_lock;
30 	struct uip_tcp_socket *sk;
31 
32 	sk_head = &arg->info->tcp_socket_head;
33 	sk_lock = &arg->info->tcp_socket_lock;
34 
35 	mutex_lock(sk_lock);
36 	list_for_each_entry(sk, sk_head, list) {
37 		if (sk->sip == sip && sk->dip == dip && sk->sport == sport && sk->dport == dport) {
38 			mutex_unlock(sk_lock);
39 			return sk;
40 		}
41 	}
42 	mutex_unlock(sk_lock);
43 
44 	return NULL;
45 }
46 
47 static struct uip_tcp_socket *uip_tcp_socket_alloc(struct uip_tx_arg *arg, u32 sip, u32 dip, u16 sport, u16 dport)
48 {
49 	struct list_head *sk_head;
50 	struct uip_tcp_socket *sk;
51 	pthread_mutex_t *sk_lock;
52 	struct uip_tcp *tcp;
53 	struct uip_ip *ip;
54 	int ret;
55 
56 	tcp = (struct uip_tcp *)arg->eth;
57 	ip = (struct uip_ip *)arg->eth;
58 
59 	sk_head = &arg->info->tcp_socket_head;
60 	sk_lock = &arg->info->tcp_socket_lock;
61 
62 	sk = malloc(sizeof(*sk));
63 	memset(sk, 0, sizeof(*sk));
64 
65 	sk->lock			= sk_lock;
66 	sk->info			= arg->info;
67 
68 	sk->fd				= socket(AF_INET, SOCK_STREAM, 0);
69 	sk->addr.sin_family		= AF_INET;
70 	sk->addr.sin_port		= dport;
71 	sk->addr.sin_addr.s_addr	= dip;
72 
73 	pthread_cond_init(&sk->cond, NULL);
74 
75 	if (ntohl(dip) == arg->info->host_ip)
76 		sk->addr.sin_addr.s_addr = inet_addr("127.0.0.1");
77 
78 	ret = connect(sk->fd, (struct sockaddr *)&sk->addr, sizeof(sk->addr));
79 	if (ret) {
80 		free(sk);
81 		return NULL;
82 	}
83 
84 	sk->sip		= ip->sip;
85 	sk->dip		= ip->dip;
86 	sk->sport	= tcp->sport;
87 	sk->dport	= tcp->dport;
88 
89 	mutex_lock(sk_lock);
90 	list_add_tail(&sk->list, sk_head);
91 	mutex_unlock(sk_lock);
92 
93 	return sk;
94 }
95 
96 static int uip_tcp_payload_send(struct uip_tcp_socket *sk, u8 flag, u16 payload_len)
97 {
98 	struct uip_info *info;
99 	struct uip_eth *eth2;
100 	struct uip_tcp *tcp2;
101 	struct uip_buf *buf;
102 	struct uip_ip *ip2;
103 
104 	info		= sk->info;
105 
106 	/*
107 	 * Get free buffer to send data to guest
108 	 */
109 	buf		= uip_buf_get_free(info);
110 
111 	/*
112 	 * Cook a ethernet frame
113 	 */
114 	tcp2		= (struct uip_tcp *)buf->eth;
115 	eth2		= (struct uip_eth *)buf->eth;
116 	ip2		= (struct uip_ip *)buf->eth;
117 
118 	eth2->src	= info->host_mac;
119 	eth2->dst	= info->guest_mac;
120 	eth2->type	= htons(UIP_ETH_P_IP);
121 
122 	ip2->vhl	= UIP_IP_VER_4 | UIP_IP_HDR_LEN;
123 	ip2->tos	= 0;
124 	ip2->id		= 0;
125 	ip2->flgfrag	= 0;
126 	ip2->ttl	= UIP_IP_TTL;
127 	ip2->proto	= UIP_IP_P_TCP;
128 	ip2->csum	= 0;
129 	ip2->sip	= sk->dip;
130 	ip2->dip	= sk->sip;
131 
132 	tcp2->sport	= sk->dport;
133 	tcp2->dport	= sk->sport;
134 	tcp2->seq	= htonl(sk->seq_server);
135 	tcp2->ack	= htonl(sk->ack_server);
136 	/*
137 	 * Diable TCP options, tcp hdr len equals 20 bytes
138 	 */
139 	tcp2->off	= UIP_TCP_HDR_LEN;
140 	tcp2->flg	= flag;
141 	tcp2->win	= htons(UIP_TCP_WIN_SIZE);
142 	tcp2->csum	= 0;
143 	tcp2->urgent	= 0;
144 
145 	if (payload_len > 0)
146 		memcpy(uip_tcp_payload(tcp2), sk->payload, payload_len);
147 
148 	ip2->len	= htons(uip_tcp_hdrlen(tcp2) + payload_len + uip_ip_hdrlen(ip2));
149 	ip2->csum	= uip_csum_ip(ip2);
150 	tcp2->csum	= uip_csum_tcp(tcp2);
151 
152 	/*
153 	 * virtio_net_hdr
154 	 */
155 	buf->vnet_len	= sizeof(struct virtio_net_hdr);
156 	memset(buf->vnet, 0, buf->vnet_len);
157 
158 	buf->eth_len	= ntohs(ip2->len) + uip_eth_hdrlen(&ip2->eth);
159 
160 	/*
161 	 * Increase server seq
162 	 */
163 	sk->seq_server  += payload_len;
164 
165 	/*
166 	 * Send data received from socket to guest
167 	 */
168 	uip_buf_set_used(info, buf);
169 
170 	return 0;
171 }
172 
173 static void *uip_tcp_socket_thread(void *p)
174 {
175 	struct uip_tcp_socket *sk;
176 	int len, left, ret;
177 	u8 *payload, *pos;
178 
179 	sk = p;
180 
181 	payload = malloc(UIP_MAX_TCP_PAYLOAD);
182 	if (!payload)
183 		goto out;
184 
185 	while (1) {
186 		pos = payload;
187 
188 		ret = read(sk->fd, payload, UIP_MAX_TCP_PAYLOAD);
189 
190 		if (ret <= 0 || ret > UIP_MAX_TCP_PAYLOAD)
191 			goto out;
192 
193 		left = ret;
194 
195 		while (left > 0) {
196 			mutex_lock(sk->lock);
197 			while ((len = sk->guest_acked + sk->window_size - sk->seq_server) <= 0)
198 				pthread_cond_wait(&sk->cond, sk->lock);
199 			mutex_unlock(sk->lock);
200 
201 			sk->payload = pos;
202 			if (len > left)
203 				len = left;
204 			if (len > UIP_MAX_TCP_PAYLOAD)
205 				len = UIP_MAX_TCP_PAYLOAD;
206 			left -= len;
207 			pos += len;
208 
209 			uip_tcp_payload_send(sk, UIP_TCP_FLAG_ACK, len);
210 		}
211 	}
212 
213 out:
214 	/*
215 	 * Close server to guest TCP connection
216 	 */
217 	uip_tcp_socket_close(sk, SHUT_RD);
218 
219 	uip_tcp_payload_send(sk, UIP_TCP_FLAG_FIN | UIP_TCP_FLAG_ACK, 0);
220 	sk->seq_server += 1;
221 
222 	sk->read_done = 1;
223 
224 	free(payload);
225 	pthread_exit(NULL);
226 
227 	return NULL;
228 }
229 
230 static int uip_tcp_socket_receive(struct uip_tcp_socket *sk)
231 {
232 	if (sk->thread == 0)
233 		return pthread_create(&sk->thread, NULL, uip_tcp_socket_thread, (void *)sk);
234 
235 	return 0;
236 }
237 
238 static int uip_tcp_socket_send(struct uip_tcp_socket *sk, struct uip_tcp *tcp)
239 {
240 	int len;
241 	int ret;
242 	u8 *payload;
243 
244 	if (sk->write_done)
245 		return 0;
246 
247 	payload = uip_tcp_payload(tcp);
248 	len = uip_tcp_payloadlen(tcp);
249 
250 	ret = write(sk->fd, payload, len);
251 	if (ret != len)
252 		pr_warning("tcp send error");
253 
254 	return ret;
255 }
256 
257 int uip_tx_do_ipv4_tcp(struct uip_tx_arg *arg)
258 {
259 	struct uip_tcp_socket *sk;
260 	struct uip_tcp *tcp;
261 	struct uip_ip *ip;
262 	int ret;
263 
264 	tcp = (struct uip_tcp *)arg->eth;
265 	ip = (struct uip_ip *)arg->eth;
266 
267 	/*
268 	 * Guest is trying to start a TCP session, let's fake SYN-ACK to guest
269 	 */
270 	if (uip_tcp_is_syn(tcp)) {
271 		sk = uip_tcp_socket_alloc(arg, ip->sip, ip->dip, tcp->sport, tcp->dport);
272 		if (!sk)
273 			return -1;
274 
275 		sk->window_size = ntohs(tcp->win);
276 
277 		/*
278 		 * Setup ISN number
279 		 */
280 		sk->isn_guest  = uip_tcp_isn(tcp);
281 		sk->isn_server = uip_tcp_isn_alloc();
282 
283 		sk->seq_server = sk->isn_server;
284 		sk->ack_server = sk->isn_guest + 1;
285 		uip_tcp_payload_send(sk, UIP_TCP_FLAG_SYN | UIP_TCP_FLAG_ACK, 0);
286 		sk->seq_server += 1;
287 
288 		/*
289 		 * Start receive thread for data from remote to guest
290 		 */
291 		uip_tcp_socket_receive(sk);
292 
293 		goto out;
294 	}
295 
296 	/*
297 	 * Find socket we have allocated
298 	 */
299 	sk = uip_tcp_socket_find(arg, ip->sip, ip->dip, tcp->sport, tcp->dport);
300 	if (!sk)
301 		return -1;
302 
303 	mutex_lock(sk->lock);
304 	sk->window_size = ntohs(tcp->win);
305 	sk->guest_acked = ntohl(tcp->ack);
306 	pthread_cond_signal(&sk->cond);
307 	mutex_unlock(sk->lock);
308 
309 	if (uip_tcp_is_fin(tcp)) {
310 		if (sk->write_done)
311 			goto out;
312 
313 		sk->write_done = 1;
314 		sk->ack_server += 1;
315 		uip_tcp_payload_send(sk, UIP_TCP_FLAG_ACK, 0);
316 
317 		/*
318 		 * Close guest to server TCP connection
319 		 */
320 		uip_tcp_socket_close(sk, SHUT_WR);
321 
322 		goto out;
323 	}
324 
325 	/*
326 	 * Ignore guest to server frames with zero tcp payload
327 	 */
328 	if (uip_tcp_payloadlen(tcp) == 0)
329 		goto out;
330 
331 	/*
332 	 * Sent out TCP data to remote host
333 	 */
334 	ret = uip_tcp_socket_send(sk, tcp);
335 	if (ret < 0)
336 		return -1;
337 	/*
338 	 * Send ACK to guest imediately
339 	 */
340 	sk->ack_server += ret;
341 	uip_tcp_payload_send(sk, UIP_TCP_FLAG_ACK, 0);
342 
343 out:
344 	return 0;
345 }
346