1*dd7a270bSAsias He #include "kvm/uip.h" 2*dd7a270bSAsias He 3*dd7a270bSAsias He #include <linux/virtio_net.h> 4*dd7a270bSAsias He #include <linux/kernel.h> 5*dd7a270bSAsias He #include <linux/list.h> 6*dd7a270bSAsias He #include <sys/socket.h> 7*dd7a270bSAsias He #include <sys/epoll.h> 8*dd7a270bSAsias He #include <fcntl.h> 9*dd7a270bSAsias He 10*dd7a270bSAsias He #define UIP_UDP_MAX_EVENTS 1000 11*dd7a270bSAsias He 12*dd7a270bSAsias He static struct uip_udp_socket *uip_udp_socket_find(struct uip_tx_arg *arg, u32 sip, u32 dip, u16 sport, u16 dport) 13*dd7a270bSAsias He { 14*dd7a270bSAsias He struct list_head *sk_head; 15*dd7a270bSAsias He struct uip_udp_socket *sk; 16*dd7a270bSAsias He pthread_mutex_t *sk_lock; 17*dd7a270bSAsias He struct epoll_event ev; 18*dd7a270bSAsias He int flags; 19*dd7a270bSAsias He int ret; 20*dd7a270bSAsias He 21*dd7a270bSAsias He sk_head = &arg->info->udp_socket_head; 22*dd7a270bSAsias He sk_lock = &arg->info->udp_socket_lock; 23*dd7a270bSAsias He 24*dd7a270bSAsias He /* 25*dd7a270bSAsias He * Find existing sk 26*dd7a270bSAsias He */ 27*dd7a270bSAsias He mutex_lock(sk_lock); 28*dd7a270bSAsias He list_for_each_entry(sk, sk_head, list) { 29*dd7a270bSAsias He if (sk->sip == sip && sk->dip == dip && sk->sport == sport && sk->dport == dport) { 30*dd7a270bSAsias He mutex_unlock(sk_lock); 31*dd7a270bSAsias He return sk; 32*dd7a270bSAsias He } 33*dd7a270bSAsias He } 34*dd7a270bSAsias He mutex_unlock(sk_lock); 35*dd7a270bSAsias He 36*dd7a270bSAsias He /* 37*dd7a270bSAsias He * Allocate new one 38*dd7a270bSAsias He */ 39*dd7a270bSAsias He sk = malloc(sizeof(*sk)); 40*dd7a270bSAsias He memset(sk, 0, sizeof(*sk)); 41*dd7a270bSAsias He 42*dd7a270bSAsias He sk->lock = sk_lock; 43*dd7a270bSAsias He 44*dd7a270bSAsias He sk->fd = socket(AF_INET, SOCK_DGRAM, 0); 45*dd7a270bSAsias He if (sk->fd < 0) 46*dd7a270bSAsias He goto out; 47*dd7a270bSAsias He 48*dd7a270bSAsias He /* 49*dd7a270bSAsias He * Set non-blocking 50*dd7a270bSAsias He */ 51*dd7a270bSAsias He flags = fcntl(sk->fd, F_GETFL, 0); 52*dd7a270bSAsias He flags |= O_NONBLOCK; 53*dd7a270bSAsias He fcntl(sk->fd, F_SETFL, flags); 54*dd7a270bSAsias He 55*dd7a270bSAsias He /* 56*dd7a270bSAsias He * Add sk->fd to epoll_wait 57*dd7a270bSAsias He */ 58*dd7a270bSAsias He ev.events = EPOLLIN; 59*dd7a270bSAsias He ev.data.fd = sk->fd; 60*dd7a270bSAsias He ev.data.ptr = sk; 61*dd7a270bSAsias He if (arg->info->udp_epollfd <= 0) 62*dd7a270bSAsias He arg->info->udp_epollfd = epoll_create(UIP_UDP_MAX_EVENTS); 63*dd7a270bSAsias He ret = epoll_ctl(arg->info->udp_epollfd, EPOLL_CTL_ADD, sk->fd, &ev); 64*dd7a270bSAsias He if (ret == -1) 65*dd7a270bSAsias He pr_warning("epoll_ctl error"); 66*dd7a270bSAsias He 67*dd7a270bSAsias He sk->addr.sin_family = AF_INET; 68*dd7a270bSAsias He sk->addr.sin_addr.s_addr = dip; 69*dd7a270bSAsias He sk->addr.sin_port = dport; 70*dd7a270bSAsias He 71*dd7a270bSAsias He sk->sip = sip; 72*dd7a270bSAsias He sk->dip = dip; 73*dd7a270bSAsias He sk->sport = sport; 74*dd7a270bSAsias He sk->dport = dport; 75*dd7a270bSAsias He 76*dd7a270bSAsias He mutex_lock(sk_lock); 77*dd7a270bSAsias He list_add_tail(&sk->list, sk_head); 78*dd7a270bSAsias He mutex_unlock(sk_lock); 79*dd7a270bSAsias He 80*dd7a270bSAsias He return sk; 81*dd7a270bSAsias He 82*dd7a270bSAsias He out: 83*dd7a270bSAsias He free(sk); 84*dd7a270bSAsias He return NULL; 85*dd7a270bSAsias He } 86*dd7a270bSAsias He 87*dd7a270bSAsias He static int uip_udp_socket_send(struct uip_udp_socket *sk, struct uip_udp *udp) 88*dd7a270bSAsias He { 89*dd7a270bSAsias He int len; 90*dd7a270bSAsias He int ret; 91*dd7a270bSAsias He 92*dd7a270bSAsias He len = ntohs(udp->len) - uip_udp_hdrlen(udp); 93*dd7a270bSAsias He 94*dd7a270bSAsias He ret = sendto(sk->fd, udp->payload, len, 0, (struct sockaddr *)&sk->addr, sizeof(sk->addr)); 95*dd7a270bSAsias He if (ret != len) 96*dd7a270bSAsias He return -1; 97*dd7a270bSAsias He 98*dd7a270bSAsias He return 0; 99*dd7a270bSAsias He } 100*dd7a270bSAsias He 101*dd7a270bSAsias He static void *uip_udp_socket_thread(void *p) 102*dd7a270bSAsias He { 103*dd7a270bSAsias He struct epoll_event events[UIP_UDP_MAX_EVENTS]; 104*dd7a270bSAsias He struct uip_udp_socket *sk; 105*dd7a270bSAsias He struct uip_info *info; 106*dd7a270bSAsias He struct uip_eth *eth2; 107*dd7a270bSAsias He struct uip_udp *udp2; 108*dd7a270bSAsias He struct uip_buf *buf; 109*dd7a270bSAsias He struct uip_ip *ip2; 110*dd7a270bSAsias He u8 *payload; 111*dd7a270bSAsias He int nfds; 112*dd7a270bSAsias He int ret; 113*dd7a270bSAsias He int i; 114*dd7a270bSAsias He 115*dd7a270bSAsias He info = p; 116*dd7a270bSAsias He 117*dd7a270bSAsias He do { 118*dd7a270bSAsias He payload = malloc(UIP_MAX_UDP_PAYLOAD); 119*dd7a270bSAsias He } while (!payload); 120*dd7a270bSAsias He 121*dd7a270bSAsias He while (1) { 122*dd7a270bSAsias He nfds = epoll_wait(info->udp_epollfd, events, UIP_UDP_MAX_EVENTS, -1); 123*dd7a270bSAsias He 124*dd7a270bSAsias He if (nfds == -1) 125*dd7a270bSAsias He continue; 126*dd7a270bSAsias He 127*dd7a270bSAsias He for (i = 0; i < nfds; i++) { 128*dd7a270bSAsias He 129*dd7a270bSAsias He sk = events[i].data.ptr; 130*dd7a270bSAsias He ret = recvfrom(sk->fd, payload, UIP_MAX_UDP_PAYLOAD, 0, NULL, NULL); 131*dd7a270bSAsias He if (ret < 0) 132*dd7a270bSAsias He continue; 133*dd7a270bSAsias He 134*dd7a270bSAsias He /* 135*dd7a270bSAsias He * Get free buffer to send data to guest 136*dd7a270bSAsias He */ 137*dd7a270bSAsias He buf = uip_buf_get_free(info); 138*dd7a270bSAsias He 139*dd7a270bSAsias He /* 140*dd7a270bSAsias He * Cook a ethernet frame 141*dd7a270bSAsias He */ 142*dd7a270bSAsias He udp2 = (struct uip_udp *)(buf->eth); 143*dd7a270bSAsias He eth2 = (struct uip_eth *)buf->eth; 144*dd7a270bSAsias He ip2 = (struct uip_ip *)(buf->eth); 145*dd7a270bSAsias He 146*dd7a270bSAsias He eth2->src = info->host_mac; 147*dd7a270bSAsias He eth2->dst = info->guest_mac; 148*dd7a270bSAsias He eth2->type = htons(UIP_ETH_P_IP); 149*dd7a270bSAsias He 150*dd7a270bSAsias He ip2->vhl = UIP_IP_VER_4 | UIP_IP_HDR_LEN; 151*dd7a270bSAsias He ip2->tos = 0; 152*dd7a270bSAsias He ip2->id = 0; 153*dd7a270bSAsias He ip2->flgfrag = 0; 154*dd7a270bSAsias He ip2->ttl = UIP_IP_TTL; 155*dd7a270bSAsias He ip2->proto = UIP_IP_P_UDP; 156*dd7a270bSAsias He ip2->csum = 0; 157*dd7a270bSAsias He ip2->sip = sk->dip; 158*dd7a270bSAsias He ip2->dip = sk->sip; 159*dd7a270bSAsias He 160*dd7a270bSAsias He udp2->sport = sk->dport; 161*dd7a270bSAsias He udp2->dport = sk->sport; 162*dd7a270bSAsias He udp2->len = htons(ret + uip_udp_hdrlen(udp2)); 163*dd7a270bSAsias He udp2->csum = 0; 164*dd7a270bSAsias He 165*dd7a270bSAsias He memcpy(udp2->payload, payload, ret); 166*dd7a270bSAsias He 167*dd7a270bSAsias He ip2->len = udp2->len + htons(uip_ip_hdrlen(ip2)); 168*dd7a270bSAsias He ip2->csum = uip_csum_ip(ip2); 169*dd7a270bSAsias He udp2->csum = uip_csum_udp(udp2); 170*dd7a270bSAsias He 171*dd7a270bSAsias He /* 172*dd7a270bSAsias He * virtio_net_hdr 173*dd7a270bSAsias He */ 174*dd7a270bSAsias He buf->vnet_len = sizeof(struct virtio_net_hdr); 175*dd7a270bSAsias He memset(buf->vnet, 0, buf->vnet_len); 176*dd7a270bSAsias He 177*dd7a270bSAsias He buf->eth_len = ntohs(ip2->len) + uip_eth_hdrlen(&ip2->eth); 178*dd7a270bSAsias He 179*dd7a270bSAsias He /* 180*dd7a270bSAsias He * Send data received from socket to guest 181*dd7a270bSAsias He */ 182*dd7a270bSAsias He uip_buf_set_used(info, buf); 183*dd7a270bSAsias He } 184*dd7a270bSAsias He } 185*dd7a270bSAsias He 186*dd7a270bSAsias He free(payload); 187*dd7a270bSAsias He pthread_exit(NULL); 188*dd7a270bSAsias He return NULL; 189*dd7a270bSAsias He } 190*dd7a270bSAsias He 191*dd7a270bSAsias He int uip_tx_do_ipv4_udp(struct uip_tx_arg *arg) 192*dd7a270bSAsias He { 193*dd7a270bSAsias He struct uip_udp_socket *sk; 194*dd7a270bSAsias He struct uip_info *info; 195*dd7a270bSAsias He struct uip_udp *udp; 196*dd7a270bSAsias He struct uip_ip *ip; 197*dd7a270bSAsias He int ret; 198*dd7a270bSAsias He 199*dd7a270bSAsias He udp = (struct uip_udp *)(arg->eth); 200*dd7a270bSAsias He ip = (struct uip_ip *)(arg->eth); 201*dd7a270bSAsias He info = arg->info; 202*dd7a270bSAsias He 203*dd7a270bSAsias He /* 204*dd7a270bSAsias He * Find socket we have allocated before, otherwise allocate one 205*dd7a270bSAsias He */ 206*dd7a270bSAsias He sk = uip_udp_socket_find(arg, ip->sip, ip->dip, udp->sport, udp->dport); 207*dd7a270bSAsias He if (!sk) 208*dd7a270bSAsias He return -1; 209*dd7a270bSAsias He 210*dd7a270bSAsias He /* 211*dd7a270bSAsias He * Send out UDP data to remote host 212*dd7a270bSAsias He */ 213*dd7a270bSAsias He ret = uip_udp_socket_send(sk, udp); 214*dd7a270bSAsias He if (ret) 215*dd7a270bSAsias He return -1; 216*dd7a270bSAsias He 217*dd7a270bSAsias He if (!info->udp_thread) 218*dd7a270bSAsias He pthread_create(&info->udp_thread, NULL, uip_udp_socket_thread, (void *)info); 219*dd7a270bSAsias He 220*dd7a270bSAsias He return 0; 221*dd7a270bSAsias He } 222