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