3 #include <linux/virtio_net.h>
4 #include <linux/kernel.h>
5 #include <linux/list.h>
7 static int uip_tcp_socket_close(struct uip_tcp_socket
*sk
, int how
)
11 if (sk
->write_done
&& sk
->read_done
) {
12 shutdown(sk
->fd
, SHUT_RDWR
);
17 mutex_unlock(sk
->lock
);
25 static struct uip_tcp_socket
*uip_tcp_socket_find(struct uip_tx_arg
*arg
, u32 sip
, u32 dip
, u16 sport
, u16 dport
)
27 struct list_head
*sk_head
;
28 pthread_mutex_t
*sk_lock
;
29 struct uip_tcp_socket
*sk
;
31 sk_head
= &arg
->info
->tcp_socket_head
;
32 sk_lock
= &arg
->info
->tcp_socket_lock
;
35 list_for_each_entry(sk
, sk_head
, list
) {
36 if (sk
->sip
== sip
&& sk
->dip
== dip
&& sk
->sport
== sport
&& sk
->dport
== dport
) {
37 mutex_unlock(sk_lock
);
41 mutex_unlock(sk_lock
);
46 static struct uip_tcp_socket
*uip_tcp_socket_alloc(struct uip_tx_arg
*arg
, u32 sip
, u32 dip
, u16 sport
, u16 dport
)
48 struct list_head
*sk_head
;
49 struct uip_tcp_socket
*sk
;
50 pthread_mutex_t
*sk_lock
;
55 tcp
= (struct uip_tcp
*)arg
->eth
;
56 ip
= (struct uip_ip
*)arg
->eth
;
58 sk_head
= &arg
->info
->tcp_socket_head
;
59 sk_lock
= &arg
->info
->tcp_socket_lock
;
61 sk
= malloc(sizeof(*sk
));
62 memset(sk
, 0, sizeof(*sk
));
67 sk
->fd
= socket(AF_INET
, SOCK_STREAM
, 0);
68 sk
->addr
.sin_family
= AF_INET
;
69 sk
->addr
.sin_addr
.s_addr
= dip
;
70 sk
->addr
.sin_port
= dport
;
72 ret
= connect(sk
->fd
, (struct sockaddr
*)&sk
->addr
, sizeof(sk
->addr
));
80 sk
->sport
= tcp
->sport
;
81 sk
->dport
= tcp
->dport
;
84 list_add_tail(&sk
->list
, sk_head
);
85 mutex_unlock(sk_lock
);
90 static int uip_tcp_payload_send(struct uip_tcp_socket
*sk
, u8 flag
, u16 payload_len
)
92 struct uip_info
*info
;
101 * Get free buffer to send data to guest
103 buf
= uip_buf_get_free(info
);
106 * Cook a ethernet frame
108 tcp2
= (struct uip_tcp
*)buf
->eth
;
109 eth2
= (struct uip_eth
*)buf
->eth
;
110 ip2
= (struct uip_ip
*)buf
->eth
;
112 eth2
->src
= info
->host_mac
;
113 eth2
->dst
= info
->guest_mac
;
114 eth2
->type
= htons(UIP_ETH_P_IP
);
116 ip2
->vhl
= UIP_IP_VER_4
| UIP_IP_HDR_LEN
;
120 ip2
->ttl
= UIP_IP_TTL
;
121 ip2
->proto
= UIP_IP_P_TCP
;
126 tcp2
->sport
= sk
->dport
;
127 tcp2
->dport
= sk
->sport
;
128 tcp2
->seq
= htonl(sk
->seq_server
);
129 tcp2
->ack
= htonl(sk
->ack_server
);
131 * Diable TCP options, tcp hdr len equals 20 bytes
133 tcp2
->off
= UIP_TCP_HDR_LEN
;
135 tcp2
->win
= htons(UIP_TCP_WIN_SIZE
);
140 memcpy(uip_tcp_payload(tcp2
), sk
->payload
, payload_len
);
142 ip2
->len
= htons(uip_tcp_hdrlen(tcp2
) + payload_len
+ uip_ip_hdrlen(ip2
));
143 ip2
->csum
= uip_csum_ip(ip2
);
144 tcp2
->csum
= uip_csum_tcp(tcp2
);
149 buf
->vnet_len
= sizeof(struct virtio_net_hdr
);
150 memset(buf
->vnet
, 0, buf
->vnet_len
);
152 buf
->eth_len
= ntohs(ip2
->len
) + uip_eth_hdrlen(&ip2
->eth
);
155 * Increase server seq
157 sk
->seq_server
+= payload_len
;
160 * Send data received from socket to guest
162 uip_buf_set_used(info
, buf
);
167 static void *uip_tcp_socket_thread(void *p
)
169 struct uip_tcp_socket
*sk
;
175 payload
= malloc(UIP_MAX_TCP_PAYLOAD
);
176 sk
->payload
= payload
;
182 ret
= read(sk
->fd
, payload
, UIP_MAX_TCP_PAYLOAD
);
184 if (ret
<= 0 || ret
> UIP_MAX_TCP_PAYLOAD
)
187 uip_tcp_payload_send(sk
, UIP_TCP_FLAG_ACK
, ret
);
193 * Close server to guest TCP connection
195 uip_tcp_socket_close(sk
, SHUT_RD
);
197 uip_tcp_payload_send(sk
, UIP_TCP_FLAG_FIN
| UIP_TCP_FLAG_ACK
, 0);
208 static int uip_tcp_socket_receive(struct uip_tcp_socket
*sk
)
211 return pthread_create(&sk
->thread
, NULL
, uip_tcp_socket_thread
, (void *)sk
);
216 static int uip_tcp_socket_send(struct uip_tcp_socket
*sk
, struct uip_tcp
*tcp
)
225 payload
= uip_tcp_payload(tcp
);
226 len
= uip_tcp_payloadlen(tcp
);
228 ret
= write(sk
->fd
, payload
, len
);
230 pr_warning("tcp send error");
235 int uip_tx_do_ipv4_tcp(struct uip_tx_arg
*arg
)
237 struct uip_tcp_socket
*sk
;
242 tcp
= (struct uip_tcp
*)arg
->eth
;
243 ip
= (struct uip_ip
*)arg
->eth
;
246 * Guest is trying to start a TCP session, let's fake SYN-ACK to guest
248 if (uip_tcp_is_syn(tcp
)) {
249 sk
= uip_tcp_socket_alloc(arg
, ip
->sip
, ip
->dip
, tcp
->sport
, tcp
->dport
);
256 sk
->isn_guest
= uip_tcp_isn(tcp
);
257 sk
->isn_server
= uip_tcp_isn_alloc();
259 sk
->seq_server
= sk
->isn_server
;
260 sk
->ack_server
= sk
->isn_guest
+ 1;
261 uip_tcp_payload_send(sk
, UIP_TCP_FLAG_SYN
| UIP_TCP_FLAG_ACK
, 0);
265 * Start receive thread for data from remote to guest
267 uip_tcp_socket_receive(sk
);
273 * Find socket we have allocated
275 sk
= uip_tcp_socket_find(arg
, ip
->sip
, ip
->dip
, tcp
->sport
, tcp
->dport
);
279 sk
->guest_acked
= ntohl(tcp
->ack
);
281 if (uip_tcp_is_fin(tcp
)) {
287 uip_tcp_payload_send(sk
, UIP_TCP_FLAG_ACK
, 0);
290 * Close guest to server TCP connection
292 uip_tcp_socket_close(sk
, SHUT_WR
);
298 * Ignore guest to server frames with zero tcp payload
300 if (uip_tcp_payloadlen(tcp
) == 0)
304 * Sent out TCP data to remote host
306 ret
= uip_tcp_socket_send(sk
, tcp
);
310 * Send ACK to guest imediately
312 sk
->ack_server
+= ret
;
313 uip_tcp_payload_send(sk
, UIP_TCP_FLAG_ACK
, 0);