tools/kvm: fix assumption of no IP options

This commit is contained in:
Alan
2015-02-09 13:57:47 +00:00
committed by Dimitri John Ledkov
parent 43d2781c27
commit 93454e8983
8 changed files with 170 additions and 144 deletions
+1 -1
View File
@@ -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
+26 -19
View File
@@ -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);
+3 -11
View File
@@ -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;
+6 -3
View File
@@ -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;
+25 -16
View File
@@ -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;
}
}
+8 -4
View File
@@ -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);
+97 -87
View File
@@ -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;
/*
+4 -3
View File
@@ -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)