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