diff --git a/Makefile b/Makefile index 151fa9d..cdc1202 100644 --- a/Makefile +++ b/Makefile @@ -331,7 +331,7 @@ WARNINGS += -Wundef WARNINGS += -Wvolatile-register-var WARNINGS += -Wwrite-strings -CFLAGS += $(WARNINGS) +CFLAGS += $(WARNINGS) -DCONFIG_HAS_AIO ifneq ($(WERROR),0) CFLAGS += -Werror diff --git a/include/kvm/uip.h b/include/kvm/uip.h index a9a8d85..5d33532 100644 --- a/include/kvm/uip.h +++ b/include/kvm/uip.h @@ -21,6 +21,10 @@ #define UIP_IP_P_TCP 0X06 #define UIP_IP_P_ICMP 0X01 +#define UIP_ICMP_ECHO_REPLY 0 +#define UIP_ICMP_UNREACH 5 +#define UIP_ICMP_ECHO 8 + #define UIP_TCP_HDR_LEN 0x50 #define UIP_TCP_WIN_SIZE 14600 #define UIP_TCP_FLAG_FIN 1 @@ -116,7 +120,6 @@ struct uip_ip { } __attribute__((packed)); struct uip_icmp { - struct uip_ip ip; u8 type; u8 code; u16 csum; @@ -125,10 +128,6 @@ struct uip_icmp { } __attribute__((packed)); struct uip_udp { - /* - * FIXME: IP Options (IP hdr len > 20 bytes) are not supported - */ - struct uip_ip ip; u16 sport; u16 dport; /* @@ -140,10 +139,6 @@ struct uip_udp { } __attribute__((packed)); struct uip_tcp { - /* - * FIXME: IP Options (IP hdr len > 20 bytes) are not supported - */ - struct uip_ip ip; u16 sport; u16 dport; u32 seq; @@ -250,6 +245,7 @@ struct uip_tcp_socket { u32 dip, sip; u8 *payload; int fd; + int dead; }; struct uip_tx_arg { @@ -265,6 +261,11 @@ static inline u16 uip_ip_hdrlen(struct uip_ip *ip) return (ip->vhl & 0x0f) * 4; } +static inline void *uip_ip_proto(struct uip_ip *ip) +{ + return ((uint8_t *)&(ip->vhl)) + (ip->vhl & 0x0f) * 4; +} + static inline u16 uip_ip_len(struct uip_ip *ip) { return htons(ip->len); @@ -285,18 +286,14 @@ static inline u16 uip_tcp_hdrlen(struct uip_tcp *tcp) return (tcp->off >> 4) * 4; } -static inline u16 uip_tcp_len(struct uip_tcp *tcp) +static inline u16 uip_tcp_len(struct uip_ip *ip, struct uip_tcp *tcp) { - struct uip_ip *ip; - - ip = &tcp->ip; - return uip_ip_len(ip) - uip_ip_hdrlen(ip); } -static inline u16 uip_tcp_payloadlen(struct uip_tcp *tcp) +static inline u16 uip_tcp_payloadlen(struct uip_ip *ip, struct uip_tcp *tcp) { - return uip_tcp_len(tcp) - uip_tcp_hdrlen(tcp); + return uip_tcp_len(ip, tcp) - uip_tcp_hdrlen(tcp); } static inline u8 *uip_tcp_payload(struct uip_tcp *tcp) @@ -304,6 +301,11 @@ static inline u8 *uip_tcp_payload(struct uip_tcp *tcp) return (u8 *)&tcp->sport + uip_tcp_hdrlen(tcp); } +static inline bool uip_tcp_is_rst(struct uip_tcp *tcp) +{ + return (tcp->flg & UIP_TCP_FLAG_RST) != 0; +} + static inline bool uip_tcp_is_syn(struct uip_tcp *tcp) { return (tcp->flg & UIP_TCP_FLAG_SYN) != 0; @@ -314,6 +316,11 @@ static inline bool uip_tcp_is_fin(struct uip_tcp *tcp) return (tcp->flg & UIP_TCP_FLAG_FIN) != 0; } +static inline bool uip_tcp_is_ack(struct uip_tcp *tcp) +{ + return (tcp->flg & UIP_TCP_FLAG_ACK) != 0; +} + static inline u32 uip_tcp_isn(struct uip_tcp *tcp) { return ntohl(tcp->seq); @@ -344,9 +351,9 @@ int uip_tx_do_ipv4_udp(struct uip_tx_arg *arg); int uip_tx_do_ipv4(struct uip_tx_arg *arg); int uip_tx_do_arp(struct uip_tx_arg *arg); -u16 uip_csum_icmp(struct uip_icmp *icmp); -u16 uip_csum_udp(struct uip_udp *udp); -u16 uip_csum_tcp(struct uip_tcp *tcp); +u16 uip_csum_icmp(struct uip_ip *ip, struct uip_icmp *icmp); +u16 uip_csum_udp(struct uip_ip *ip, struct uip_udp *udp); +u16 uip_csum_tcp(struct uip_ip *ip, struct uip_tcp *tcp); u16 uip_csum_ip(struct uip_ip *ip); struct uip_buf *uip_buf_set_used(struct uip_info *info, struct uip_buf *buf); diff --git a/net/uip/csum.c b/net/uip/csum.c index 7ca8bad..8f21da5 100644 --- a/net/uip/csum.c +++ b/net/uip/csum.c @@ -24,23 +24,17 @@ u16 uip_csum_ip(struct uip_ip *ip) return uip_csum(0, &ip->vhl, uip_ip_hdrlen(ip)); } -u16 uip_csum_icmp(struct uip_icmp *icmp) +u16 uip_csum_icmp(struct uip_ip *ip, struct uip_icmp *icmp) { - struct uip_ip *ip; - - ip = &icmp->ip; return icmp->csum = uip_csum(0, &icmp->type, htons(ip->len) - uip_ip_hdrlen(ip) - 8); /* icmp header len = 8 */ } -u16 uip_csum_udp(struct uip_udp *udp) +u16 uip_csum_udp(struct uip_ip *ip, struct uip_udp *udp) { struct uip_pseudo_hdr hdr; - struct uip_ip *ip; int udp_len; u8 *pad; - ip = &udp->ip; - hdr.sip = ip->sip; hdr.dip = ip->dip; hdr.zero = 0; @@ -61,14 +55,12 @@ u16 uip_csum_udp(struct uip_udp *udp) } -u16 uip_csum_tcp(struct uip_tcp *tcp) +u16 uip_csum_tcp(struct uip_ip *ip, struct uip_tcp *tcp) { struct uip_pseudo_hdr hdr; - struct uip_ip *ip; u16 tcp_len; u8 *pad; - ip = &tcp->ip; tcp_len = ntohs(ip->len) - uip_ip_hdrlen(ip); hdr.sip = ip->sip; diff --git a/net/uip/dhcp.c b/net/uip/dhcp.c index b17d352..f706eba 100644 --- a/net/uip/dhcp.c +++ b/net/uip/dhcp.c @@ -144,9 +144,10 @@ static int uip_dhcp_fill_option(struct uip_info *info, struct uip_dhcp *dhcp, in static int uip_dhcp_make_pkg(struct uip_info *info, struct uip_udp_socket *sk, struct uip_buf *buf, u8 reply_msg_type) { struct uip_dhcp *dhcp; + struct uip_ip *ip; - dhcp = (struct uip_dhcp *)buf->eth; - + ip = (struct uip_ip *)buf->eth; + dhcp = (struct uip_dhcp *)(ip + 1); dhcp->msg_type = 2; dhcp->client_ip = 0; dhcp->your_ip = htonl(info->guest_ip); @@ -166,12 +167,14 @@ static int uip_dhcp_make_pkg(struct uip_info *info, struct uip_udp_socket *sk, s int uip_tx_do_ipv4_udp_dhcp(struct uip_tx_arg *arg) { struct uip_udp_socket sk; + struct uip_ip *ip; struct uip_dhcp *dhcp; struct uip_info *info; struct uip_buf *buf; u8 reply_msg_type; - dhcp = (struct uip_dhcp *)arg->eth; + ip = (struct uip_ip *)arg->eth; + dhcp = (struct uip_dhcp *)(((uint8_t *)ip) + uip_ip_hdrlen(ip)); if (uip_dhcp_is_discovery(dhcp)) reply_msg_type = UIP_DHCP_OFFER; diff --git a/net/uip/icmp.c b/net/uip/icmp.c index 233297c..ee98ebc 100644 --- a/net/uip/icmp.c +++ b/net/uip/icmp.c @@ -4,26 +4,35 @@ int uip_tx_do_ipv4_icmp(struct uip_tx_arg *arg) { struct uip_ip *ip, *ip2; struct uip_icmp *icmp2; + struct uip_icmp *icmp; struct uip_buf *buf; - buf = uip_buf_clone(arg); - - icmp2 = (struct uip_icmp *)(buf->eth); - ip2 = (struct uip_ip *)(buf->eth); ip = (struct uip_ip *)(arg->eth); + icmp = uip_ip_proto(ip); - ip2->sip = ip->dip; - ip2->dip = ip->sip; - ip2->csum = 0; - /* - * ICMP reply: 0 - */ - icmp2->type = 0; - icmp2->csum = 0; - ip2->csum = uip_csum_ip(ip2); - icmp2->csum = uip_csum_icmp(icmp2); + /* Check the icmp type first.. */ - uip_buf_set_used(arg->info, buf); + switch(icmp->type) { + case UIP_ICMP_ECHO: + buf = uip_buf_clone(arg); + ip2 = (struct uip_ip *)(buf->eth); + icmp2 = uip_ip_proto(ip2); + ip2->sip = ip->dip; + ip2->dip = ip->sip; + ip2->csum = 0; + /* + * ICMP reply: 0 + */ + icmp2->type = UIP_ICMP_ECHO_REPLY; + icmp2->csum = 0; + ip2->csum = uip_csum_ip(ip2); + icmp2->csum = uip_csum_icmp(ip2, icmp2); - return 0; + uip_buf_set_used(arg->info, buf); + + return 0; + /* FIXME: need to process unreachable reports */ + default: + return 0; + } } diff --git a/net/uip/ipv4.c b/net/uip/ipv4.c index 58373fd..97812e2 100644 --- a/net/uip/ipv4.c +++ b/net/uip/ipv4.c @@ -3,14 +3,18 @@ int uip_tx_do_ipv4(struct uip_tx_arg *arg) { struct uip_ip *ip; + int n; + uint8_t *p; ip = (struct uip_ip *)(arg->eth); - if (uip_ip_hdrlen(ip) != 20) { - pr_warning("IP header length is not 20 bytes"); - return -1; - } + p = (uint8_t *)arg->eth; + for (n = 0; n < 64; n++) { + printf("%02X ", *p++); + if ((n & 7) == 7) + printf("\n"); + } switch (ip->proto) { case UIP_IP_P_ICMP: uip_tx_do_ipv4_icmp(arg); diff --git a/net/uip/tcp.c b/net/uip/tcp.c index 3c30ade..964c929 100644 --- a/net/uip/tcp.c +++ b/net/uip/tcp.c @@ -45,54 +45,6 @@ static struct uip_tcp_socket *uip_tcp_socket_find(struct uip_tx_arg *arg, u32 si return NULL; } -static struct uip_tcp_socket *uip_tcp_socket_alloc(struct uip_tx_arg *arg, u32 sip, u32 dip, u16 sport, u16 dport) -{ - struct list_head *sk_head; - struct uip_tcp_socket *sk; - struct mutex *sk_lock; - struct uip_tcp *tcp; - struct uip_ip *ip; - int ret; - - tcp = (struct uip_tcp *)arg->eth; - ip = (struct uip_ip *)arg->eth; - - sk_head = &arg->info->tcp_socket_head; - sk_lock = &arg->info->tcp_socket_lock; - - sk = malloc(sizeof(*sk)); - memset(sk, 0, sizeof(*sk)); - - sk->lock = sk_lock; - sk->info = arg->info; - - sk->fd = socket(AF_INET, SOCK_STREAM, 0); - sk->addr.sin_family = AF_INET; - sk->addr.sin_port = dport; - sk->addr.sin_addr.s_addr = dip; - - pthread_cond_init(&sk->cond, NULL); - - if (ntohl(dip) == arg->info->host_ip) - sk->addr.sin_addr.s_addr = inet_addr("127.0.0.1"); - - ret = connect(sk->fd, (struct sockaddr *)&sk->addr, sizeof(sk->addr)); - if (ret) { - free(sk); - return NULL; - } - - sk->sip = ip->sip; - sk->dip = ip->dip; - sk->sport = tcp->sport; - sk->dport = tcp->dport; - - mutex_lock(sk_lock); - list_add_tail(&sk->list, sk_head); - mutex_unlock(sk_lock); - - return sk; -} static int uip_tcp_payload_send(struct uip_tcp_socket *sk, u8 flag, u16 payload_len) { @@ -112,9 +64,9 @@ static int uip_tcp_payload_send(struct uip_tcp_socket *sk, u8 flag, u16 payload_ /* * Cook a ethernet frame */ - tcp2 = (struct uip_tcp *)buf->eth; eth2 = (struct uip_eth *)buf->eth; ip2 = (struct uip_ip *)buf->eth; + tcp2 = (struct uip_tcp *)(ip2 + 1); eth2->src = info->host_mac; eth2->dst = info->guest_mac; @@ -148,7 +100,7 @@ static int uip_tcp_payload_send(struct uip_tcp_socket *sk, u8 flag, u16 payload_ ip2->len = htons(uip_tcp_hdrlen(tcp2) + payload_len + uip_ip_hdrlen(ip2)); ip2->csum = uip_csum_ip(ip2); - tcp2->csum = uip_csum_tcp(tcp2); + tcp2->csum = uip_csum_tcp(ip2, tcp2); /* * virtio_net_hdr @@ -171,6 +123,57 @@ static int uip_tcp_payload_send(struct uip_tcp_socket *sk, u8 flag, u16 payload_ return 0; } +static struct uip_tcp_socket *uip_tcp_socket_alloc(struct uip_tx_arg *arg, u32 sip, u32 dip, u16 sport, u16 dport) +{ + struct list_head *sk_head; + struct uip_tcp_socket *sk; + struct mutex *sk_lock; + struct uip_tcp *tcp; + struct uip_ip *ip; + int ret; + + ip = (struct uip_ip *)arg->eth; + tcp = (struct uip_tcp *)(ip + 1); + + sk_head = &arg->info->tcp_socket_head; + sk_lock = &arg->info->tcp_socket_lock; + + sk = malloc(sizeof(*sk)); + memset(sk, 0, sizeof(*sk)); + + sk->lock = sk_lock; + sk->info = arg->info; + + sk->fd = socket(AF_INET, SOCK_STREAM, 0); + sk->addr.sin_family = AF_INET; + sk->addr.sin_port = dport; + sk->addr.sin_addr.s_addr = dip; + + pthread_cond_init(&sk->cond, NULL); + + if (ntohl(dip) == arg->info->host_ip) + sk->addr.sin_addr.s_addr = inet_addr("127.0.0.1"); + + sk->sip = ip->sip; + sk->dip = ip->dip; + sk->sport = tcp->sport; + sk->dport = tcp->dport; + + ret = connect(sk->fd, (struct sockaddr *)&sk->addr, sizeof(sk->addr)); + if (ret) { + perror("connect"); + uip_tcp_payload_send(sk, UIP_TCP_FLAG_RST, 0); + free(sk); + return NULL; + } + + mutex_lock(sk_lock); + list_add_tail(&sk->list, sk_head); + mutex_unlock(sk_lock); + + return sk; +} + static void *uip_tcp_socket_thread(void *p) { struct uip_tcp_socket *sk; @@ -190,7 +193,7 @@ static void *uip_tcp_socket_thread(void *p) ret = read(sk->fd, payload, UIP_MAX_TCP_PAYLOAD); - if (ret <= 0 || ret > UIP_MAX_TCP_PAYLOAD) + if (ret <= 0 || ret > UIP_MAX_TCP_PAYLOAD || sk->dead) goto out; left = ret; @@ -238,7 +241,8 @@ static int uip_tcp_socket_receive(struct uip_tcp_socket *sk) return 0; } -static int uip_tcp_socket_send(struct uip_tcp_socket *sk, struct uip_tcp *tcp) +static int uip_tcp_socket_send(struct uip_tcp_socket *sk, struct uip_ip *ip, + struct uip_tcp *tcp) { int len; int ret; @@ -248,7 +252,7 @@ static int uip_tcp_socket_send(struct uip_tcp_socket *sk, struct uip_tcp *tcp) return 0; payload = uip_tcp_payload(tcp); - len = uip_tcp_payloadlen(tcp); + len = uip_tcp_payloadlen(ip, tcp); ret = write(sk->fd, payload, len); if (ret != len) @@ -264,44 +268,44 @@ int uip_tx_do_ipv4_tcp(struct uip_tx_arg *arg) struct uip_ip *ip; int ret; - tcp = (struct uip_tcp *)arg->eth; ip = (struct uip_ip *)arg->eth; - - /* - * Guest is trying to start a TCP session, let's fake SYN-ACK to guest - */ - if (uip_tcp_is_syn(tcp)) { - sk = uip_tcp_socket_alloc(arg, ip->sip, ip->dip, tcp->sport, tcp->dport); - if (!sk) - return -1; - - sk->window_size = ntohs(tcp->win); - - /* - * Setup ISN number - */ - sk->isn_guest = uip_tcp_isn(tcp); - sk->isn_server = uip_tcp_isn_alloc(); - - sk->seq_server = sk->isn_server; - sk->ack_server = sk->isn_guest + 1; - uip_tcp_payload_send(sk, UIP_TCP_FLAG_SYN | UIP_TCP_FLAG_ACK, 0); - sk->seq_server += 1; - - /* - * Start receive thread for data from remote to guest - */ - uip_tcp_socket_receive(sk); - - goto out; - } + tcp = uip_ip_proto(ip); /* * Find socket we have allocated */ sk = uip_tcp_socket_find(arg, ip->sip, ip->dip, tcp->sport, tcp->dport); - if (!sk) - return -1; + if (!sk) { + /* + * Guest is trying to start a TCP session, let's fake SYN-ACK to guest + */ + if (uip_tcp_is_syn(tcp) && !uip_tcp_is_rst(tcp)) { + sk = uip_tcp_socket_alloc(arg, ip->sip, ip->dip, tcp->sport, tcp->dport); + if (!sk) + return -1; + sk->window_size = ntohs(tcp->win); + + /* + * Setup ISN number + */ + sk->isn_guest = uip_tcp_isn(tcp); + sk->isn_server = uip_tcp_isn_alloc(); + + sk->seq_server = sk->isn_server; + sk->ack_server = sk->isn_guest + 1; + uip_tcp_payload_send(sk, + UIP_TCP_FLAG_SYN | UIP_TCP_FLAG_ACK, 0); + sk->seq_server += 1; + + /* + * Start receive thread for data from remote to guest + */ + uip_tcp_socket_receive(sk); + + goto out; + } + } + mutex_lock(sk->lock); sk->window_size = ntohs(tcp->win); @@ -309,6 +313,12 @@ int uip_tx_do_ipv4_tcp(struct uip_tx_arg *arg) pthread_cond_signal(&sk->cond); mutex_unlock(sk->lock); + if (uip_tcp_is_rst(tcp)) { + sk->dead = 1; + goto out; + } + + /* Really ought to do fin processing post data */ if (uip_tcp_is_fin(tcp)) { if (sk->write_done) goto out; @@ -328,13 +338,13 @@ int uip_tx_do_ipv4_tcp(struct uip_tx_arg *arg) /* * Ignore guest to server frames with zero tcp payload */ - if (uip_tcp_payloadlen(tcp) == 0) + if (uip_tcp_payloadlen(ip, tcp) == 0) goto out; /* * Sent out TCP data to remote host */ - ret = uip_tcp_socket_send(sk, tcp); + ret = uip_tcp_socket_send(sk, ip, tcp); if (ret < 0) return -1; /* diff --git a/net/uip/udp.c b/net/uip/udp.c index dd288c5..9dddb4f 100644 --- a/net/uip/udp.c +++ b/net/uip/udp.c @@ -108,9 +108,9 @@ int uip_udp_make_pkg(struct uip_info *info, struct uip_udp_socket *sk, struct ui /* * Cook a ethernet frame */ - udp2 = (struct uip_udp *)(buf->eth); eth2 = (struct uip_eth *)buf->eth; ip2 = (struct uip_ip *)(buf->eth); + udp2 = (struct uip_udp *)(ip2 + 1); eth2->src = info->host_mac; eth2->dst = info->guest_mac; @@ -137,7 +137,7 @@ int uip_udp_make_pkg(struct uip_info *info, struct uip_udp_socket *sk, struct ui ip2->len = udp2->len + htons(uip_ip_hdrlen(ip2)); ip2->csum = uip_csum_ip(ip2); - udp2->csum = uip_csum_udp(udp2); + udp2->csum = uip_csum_udp(ip2, udp2); /* * virtio_net_hdr @@ -209,8 +209,8 @@ int uip_tx_do_ipv4_udp(struct uip_tx_arg *arg) struct uip_ip *ip; int ret; - udp = (struct uip_udp *)(arg->eth); ip = (struct uip_ip *)(arg->eth); + udp = uip_ip_proto(ip); info = arg->info; if (uip_udp_is_dhcp(udp)) { @@ -230,6 +230,7 @@ int uip_tx_do_ipv4_udp(struct uip_tx_arg *arg) */ ret = uip_udp_socket_send(sk, udp); if (ret) + /* FIXME: icmp port unreach */ return -1; if (!info->udp_thread)