diff --git a/src/core/nic.c b/src/core/nic.c index 53dac57e..fc8deebe 100644 --- a/src/core/nic.c +++ b/src/core/nic.c @@ -219,7 +219,6 @@ static int rarp(void); #else static int bootp(void); #endif -static unsigned short tcpudpchksum(struct iphdr *ip); /* @@ -320,9 +319,6 @@ static int nic_load ( struct type_dev *type_dev, char *kernel; /* Now use TFTP to load file */ -#ifdef DOWNLOAD_PROTO_NFS - rpc_init(); -#endif kernel = KERNEL_BUF[0] == '\0' ? #ifdef DEFAULT_BOOTFILE DEFAULT_BOOTFILE @@ -529,29 +525,6 @@ void build_udp_hdr(unsigned long destip, udp->chksum = 0xffff; } -#ifdef DOWNLOAD_PROTO_HTTP -void build_tcp_hdr(unsigned long destip, unsigned int srcsock, - unsigned int destsock, long send_seq, long recv_seq, - int window, int flags, int ttl, int len, const void *buf) -{ - struct iphdr *ip; - struct tcphdr *tcp; - ip = (struct iphdr *)buf; - build_ip_hdr(destip, ttl, IP_TCP, 0, len, buf); - tcp = (struct tcphdr *)(ip + 1); - tcp->src = htons(srcsock); - tcp->dst = htons(destsock); - tcp->seq = htonl(send_seq); - tcp->ack = htonl(recv_seq); - tcp->ctrl = htons(flags + (5 << 12)); /* No TCP options */ - tcp->window = htons(window); - tcp->chksum = 0; - if ((tcp->chksum = tcpudpchksum(ip)) == 0) - tcp->chksum = 0xffff; -} -#endif - - /************************************************************************** UDP_TRANSMIT - Send an UDP datagram **************************************************************************/ @@ -562,37 +535,6 @@ int udp_transmit(unsigned long destip, unsigned int srcsock, return ip_transmit(len, buf); } -/************************************************************************** -TCP_TRANSMIT - Send a TCP packet -**************************************************************************/ -#ifdef DOWNLOAD_PROTO_HTTP -int tcp_transmit(unsigned long destip, unsigned int srcsock, - unsigned int destsock, long send_seq, long recv_seq, - int window, int flags, int len, const void *buf) -{ - build_tcp_hdr(destip, srcsock, destsock, send_seq, recv_seq, - window, flags, 60, len, buf); - return ip_transmit(len, buf); -} - -int tcp_reset(struct iphdr *ip) { - struct tcphdr *tcp = (struct tcphdr *)(ip + 1); - char buf[sizeof(struct iphdr) + sizeof(struct tcphdr)]; - - if (!(tcp->ctrl & htons(RST))) { - long seq = ntohl(tcp->seq) + ntohs(ip->len) - - sizeof(struct iphdr) - - ((ntohs(tcp->ctrl) >> 10) & 0x3C); - if (tcp->ctrl & htons(SYN|FIN)) - seq++; - return tcp_transmit(ntohl(ip->src.s_addr), - ntohs(tcp->dst), ntohs(tcp->src), - tcp->ctrl&htons(ACK) ? ntohl(tcp->ack) : 0, - seq, TCP_MAX_WINDOW, RST, sizeof(buf), buf); - } - return (1); -} -#endif /************************************************************************** QDRAIN - clear the nic's receive queue @@ -616,9 +558,6 @@ void rx_qdrain(void) await_reply(await_qdrain, 0, NULL, 0); } -#ifdef DOWNLOAD_PROTO_TFTP -#endif /* DOWNLOAD_PROTO_TFTP */ - #ifdef RARP_NOT_BOOTP /************************************************************************** RARP - Get my IP address and load information @@ -876,7 +815,7 @@ static int bootp(void) } #endif /* RARP_NOT_BOOTP */ -static uint16_t tcpudpchksum(struct iphdr *ip) +uint16_t tcpudpchksum(struct iphdr *ip) { struct udp_pseudo_hdr pseudo; uint16_t checksum; @@ -1034,239 +973,6 @@ void join_group(int slot, unsigned long group) #include "proto_eth_slow.c" -/************************************************************************** -TCP - Simple-minded TCP stack. Can only send data once and then - receive the response. The algorithm for computing window - sizes and delaying ack's is currently broken, and thus - disabled. Performance would probably improve a little, if - this gets fixed. FIXME -**************************************************************************/ -#ifdef DOWNLOAD_PROTO_HTTP -static int await_tcp(int ival, void *ptr, unsigned short ptype __unused, - struct iphdr *ip, struct udphdr *udp __unused, - struct tcphdr *tcp) -{ - if (!tcp) { - return 0; - } - if (arptable[ARP_CLIENT].ipaddr.s_addr != ip->dest.s_addr) - return 0; - if (ntohs(tcp->dst) != ival) { - tcp_reset(ip); - return 0; - } - *(void **)ptr = tcp; - return 1; -} - -int tcp_transaction(unsigned long destip, unsigned int destsock, void *ptr, - int (*send)(int len, void *buf, void *ptr), - int (*recv)(int len, const void *buf, void *ptr)) { - static uint16_t srcsock = 0; - int rc = 1; - long send_seq = currticks(); - long recv_seq = 0; - int can_send = 0; - int sent_all = 0; - struct iphdr *ip; - struct tcphdr *tcp; - int ctrl = SYN; - char buf[128]; /* Small outgoing buffer */ - long payload; - int header_size; - int window = 3*TCP_MIN_WINDOW; - long last_ack = 0; - long last_sent = 0; - long rtt = 0; - long srtt = 0; - long rto = TCP_INITIAL_TIMEOUT; - int retry = TCP_MAX_TIMEOUT/TCP_INITIAL_TIMEOUT; - enum { CLOSED, SYN_RCVD, ESTABLISHED, - FIN_WAIT_1, FIN_WAIT_2 } state = CLOSED; - - if (!srcsock) { - srcsock = currticks(); - } - if (++srcsock < 1024) - srcsock += 1024; - - await_reply(await_qdrain, 0, NULL, 0); - - send_data: - if (ctrl & ACK) - last_ack = recv_seq; - if (!tcp_transmit(destip, srcsock, destsock, send_seq, - recv_seq, window, ctrl, - sizeof(struct iphdr) + sizeof(struct tcphdr)+ - can_send, buf)) { - return (0); - } - last_sent = currticks(); - - recv_data: - if (!await_reply(await_tcp, srcsock, &tcp, - (state == ESTABLISHED && !can_send) - ? TCP_MAX_TIMEOUT : rto)) { - if (state == ESTABLISHED) { - close: - ctrl = FIN|ACK; - state = FIN_WAIT_1; - rc = 0; - goto send_data; - } - - if (state == FIN_WAIT_1 || state == FIN_WAIT_2) - return (rc); - - if (--retry <= 0) { - /* time out */ - if (state == SYN_RCVD) { - tcp_transmit(destip, srcsock, destsock, - send_seq, 0, window, RST, - sizeof(struct iphdr) + - sizeof(struct tcphdr), buf); - } - return (0); - } - /* retransmit */ - goto send_data; - } - got_data: - retry = TCP_MAX_RETRY; - - if (tcp->ctrl & htons(ACK) ) { - char *data; - int syn_ack, consumed; - - if (state == FIN_WAIT_1 || state == FIN_WAIT_2) { - state = FIN_WAIT_2; - ctrl = ACK; - goto consume_data; - } - syn_ack = state == CLOSED || state == SYN_RCVD; - consumed = ntohl(tcp->ack) - send_seq - syn_ack; - if (consumed < 0 || consumed > can_send) { - tcp_reset((struct iphdr *)&nic.packet[ETH_HLEN]); - goto recv_data; - } - - rtt = currticks() - last_sent; - srtt = !srtt ? rtt : (srtt*4 + rtt)/5; - rto = srtt + srtt/2; - if (rto < TCP_MIN_TIMEOUT) - rto = TCP_MIN_TIMEOUT; - else if (rto > TCP_MAX_TIMEOUT) - rto = TCP_MAX_TIMEOUT; - - can_send -= consumed; - send_seq += consumed + syn_ack; - data = buf + sizeof(struct iphdr) + sizeof(struct tcphdr); - if (can_send) { - memmove(data, data + consumed, can_send); - } - if (!sent_all) { - int more_data; - data += can_send; - more_data = buf + sizeof(buf) - data; - if (more_data > 0) { - more_data = send(more_data, data, ptr); - can_send += more_data; - } - sent_all = !more_data; - } - if (state == SYN_RCVD) { - state = ESTABLISHED; - ctrl = PSH|ACK; - goto consume_data; - } - if (tcp->ctrl & htons(RST)) - return (0); - } else if (tcp->ctrl & htons(RST)) { - if (state == CLOSED) - goto recv_data; - return (0); - } - - consume_data: - ip = (struct iphdr *)&nic.packet[ETH_HLEN]; - header_size = sizeof(struct iphdr) + ((ntohs(tcp->ctrl)>>10)&0x3C); - payload = ntohs(ip->len) - header_size; - if (payload > 0 && state == ESTABLISHED) { - int old_bytes = recv_seq - (long)ntohl(tcp->seq); - if (old_bytes >= 0 && payload - old_bytes > 0) { - recv_seq += payload - old_bytes; - if (state != FIN_WAIT_1 && state != FIN_WAIT_2 && - !recv(payload - old_bytes, - &nic.packet[ETH_HLEN+header_size+old_bytes], - ptr)) { - goto close; - } - if ((state == ESTABLISHED || state == SYN_RCVD) && - !(tcp->ctrl & htons(FIN))) { - int in_window = window - 2*TCP_MIN_WINDOW > - recv_seq - last_ack; - ctrl = can_send ? PSH|ACK : ACK; - if (!can_send && in_window) { -/* Window scaling is broken right now, just fall back to acknowledging every */ -/* packet immediately and unconditionally. FIXME */ /***/ -/* if (await_reply(await_tcp, srcsock, - &tcp, rto)) - goto got_data; - else */ - goto send_data; - } - if (!in_window) { - window += TCP_MIN_WINDOW; - if (window > TCP_MAX_WINDOW) - window = TCP_MAX_WINDOW; - } - goto send_data; - } - } else { - /* saw old data again, must have lost packets */ - window /= 2; - if (window < 2*TCP_MIN_WINDOW) - window = 2*TCP_MIN_WINDOW; - } - } - - if (tcp->ctrl & htons(FIN)) { - if (state == ESTABLISHED) { - ctrl = FIN|ACK; - } else if (state == FIN_WAIT_1 || state == FIN_WAIT_2) { - ctrl = ACK; - } else { - ctrl = RST; - } - return (tcp_transmit(destip, srcsock, destsock, - send_seq, recv_seq + 1, window, ctrl, - sizeof(struct iphdr) + - sizeof(struct tcphdr), buf) && - (state == ESTABLISHED || - state == FIN_WAIT_1 || state == FIN_WAIT_2) && - !can_send); - } - - if (state == CLOSED) { - if (tcp->ctrl & htons(SYN)) { - recv_seq = ntohl(tcp->seq) + 1; - if (!(tcp->ctrl & htons(ACK))) { - state = SYN_RCVD; - ctrl = SYN|ACK|PSH; - goto send_data; - } else { - state = ESTABLISHED; - ctrl = PSH|ACK; - } - } - } - - if (can_send || payload) { - goto send_data; - } - goto recv_data; -} -#endif /************************************************************************** AWAIT_REPLY - Wait until we get a response for our request @@ -1361,7 +1067,6 @@ int await_reply(reply_t reply, int ival, void *ptr, long timeout) } } tcp = 0; -#ifdef DOWNLOAD_PROTO_HTTP if (ip && (ip->protocol == IP_TCP) && (nic.packetlen >= ETH_HLEN + sizeof(struct iphdr) + sizeof(struct tcphdr))){ @@ -1377,7 +1082,6 @@ int await_reply(reply_t reply, int ival, void *ptr, long timeout) } } -#endif result = reply(ival, ptr, ptype, ip, udp, tcp); if (result > 0) { return result; diff --git a/src/include/ip.h b/src/include/ip.h index 85c299ba..5c9b7271 100644 --- a/src/include/ip.h +++ b/src/include/ip.h @@ -18,4 +18,6 @@ struct iphdr { struct in_addr dest; } PACKED; +extern uint16_t tcpudpchksum(struct iphdr *ip); + #endif /* _IP_H */ diff --git a/src/include/tcp.h b/src/include/tcp.h index f570d8ef..93e1485e 100644 --- a/src/include/tcp.h +++ b/src/include/tcp.h @@ -9,10 +9,6 @@ #define TCP_MIN_WINDOW (1500-TCP_MAX_HEADER) #define TCP_MAX_WINDOW (65535-TCP_MAX_HEADER) - -#define MAX_URL 80 - - #define FIN 1 #define SYN 2 #define RST 4 @@ -32,4 +28,10 @@ struct tcphdr { uint16_t urgent; }; +extern int tcp_transaction ( unsigned long destip, unsigned int destsock, + void *ptr, + int (*send)(int len, void *buf, void *ptr), + int (*recv)(int len, const void *buf, void *ptr)); + + #endif /* _TCP_H */ diff --git a/src/proto/tcp.c b/src/proto/tcp.c new file mode 100644 index 00000000..197bfce2 --- /dev/null +++ b/src/proto/tcp.c @@ -0,0 +1,286 @@ +#include "etherboot.h" +#include "ip.h" +#include "tcp.h" + + +void build_tcp_hdr(unsigned long destip, unsigned int srcsock, + unsigned int destsock, long send_seq, long recv_seq, + int window, int flags, int ttl, int len, const void *buf) +{ + struct iphdr *ip; + struct tcphdr *tcp; + ip = (struct iphdr *)buf; + build_ip_hdr(destip, ttl, IP_TCP, 0, len, buf); + tcp = (struct tcphdr *)(ip + 1); + tcp->src = htons(srcsock); + tcp->dst = htons(destsock); + tcp->seq = htonl(send_seq); + tcp->ack = htonl(recv_seq); + tcp->ctrl = htons(flags + (5 << 12)); /* No TCP options */ + tcp->window = htons(window); + tcp->chksum = 0; + if ((tcp->chksum = tcpudpchksum(ip)) == 0) + tcp->chksum = 0xffff; +} + +/************************************************************************** +TCP_TRANSMIT - Send a TCP packet +**************************************************************************/ +int tcp_transmit(unsigned long destip, unsigned int srcsock, + unsigned int destsock, long send_seq, long recv_seq, + int window, int flags, int len, const void *buf) +{ + build_tcp_hdr(destip, srcsock, destsock, send_seq, recv_seq, + window, flags, 60, len, buf); + return ip_transmit(len, buf); +} + +int tcp_reset(struct iphdr *ip) { + struct tcphdr *tcp = (struct tcphdr *)(ip + 1); + char buf[sizeof(struct iphdr) + sizeof(struct tcphdr)]; + + if (!(tcp->ctrl & htons(RST))) { + long seq = ntohl(tcp->seq) + ntohs(ip->len) - + sizeof(struct iphdr) - + ((ntohs(tcp->ctrl) >> 10) & 0x3C); + if (tcp->ctrl & htons(SYN|FIN)) + seq++; + return tcp_transmit(ntohl(ip->src.s_addr), + ntohs(tcp->dst), ntohs(tcp->src), + tcp->ctrl&htons(ACK) ? ntohl(tcp->ack) : 0, + seq, TCP_MAX_WINDOW, RST, sizeof(buf), buf); + } + return (1); +} + +/************************************************************************** +TCP - Simple-minded TCP stack. Can only send data once and then + receive the response. The algorithm for computing window + sizes and delaying ack's is currently broken, and thus + disabled. Performance would probably improve a little, if + this gets fixed. FIXME +**************************************************************************/ +static int await_tcp(int ival, void *ptr, unsigned short ptype __unused, + struct iphdr *ip, struct udphdr *udp __unused, + struct tcphdr *tcp) +{ + if (!tcp) { + return 0; + } + if (arptable[ARP_CLIENT].ipaddr.s_addr != ip->dest.s_addr) + return 0; + if (ntohs(tcp->dst) != ival) { + tcp_reset(ip); + return 0; + } + *(void **)ptr = tcp; + return 1; +} + +int tcp_transaction(unsigned long destip, unsigned int destsock, void *ptr, + int (*send)(int len, void *buf, void *ptr), + int (*recv)(int len, const void *buf, void *ptr)) { + static uint16_t srcsock = 0; + int rc = 1; + long send_seq = currticks(); + long recv_seq = 0; + int can_send = 0; + int sent_all = 0; + struct iphdr *ip; + struct tcphdr *tcp; + int ctrl = SYN; + char buf[128]; /* Small outgoing buffer */ + long payload; + int header_size; + int window = 3*TCP_MIN_WINDOW; + long last_ack = 0; + long last_sent = 0; + long rtt = 0; + long srtt = 0; + long rto = TCP_INITIAL_TIMEOUT; + int retry = TCP_MAX_TIMEOUT/TCP_INITIAL_TIMEOUT; + enum { CLOSED, SYN_RCVD, ESTABLISHED, + FIN_WAIT_1, FIN_WAIT_2 } state = CLOSED; + + if (!srcsock) { + srcsock = currticks(); + } + if (++srcsock < 1024) + srcsock += 1024; + + rx_qdrain(); + + send_data: + if (ctrl & ACK) + last_ack = recv_seq; + if (!tcp_transmit(destip, srcsock, destsock, send_seq, + recv_seq, window, ctrl, + sizeof(struct iphdr) + sizeof(struct tcphdr)+ + can_send, buf)) { + return (0); + } + last_sent = currticks(); + + recv_data: + if (!await_reply(await_tcp, srcsock, &tcp, + (state == ESTABLISHED && !can_send) + ? TCP_MAX_TIMEOUT : rto)) { + if (state == ESTABLISHED) { + close: + ctrl = FIN|ACK; + state = FIN_WAIT_1; + rc = 0; + goto send_data; + } + + if (state == FIN_WAIT_1 || state == FIN_WAIT_2) + return (rc); + + if (--retry <= 0) { + /* time out */ + if (state == SYN_RCVD) { + tcp_transmit(destip, srcsock, destsock, + send_seq, 0, window, RST, + sizeof(struct iphdr) + + sizeof(struct tcphdr), buf); + } + return (0); + } + /* retransmit */ + goto send_data; + } + /* got_data: */ + retry = TCP_MAX_RETRY; + + if (tcp->ctrl & htons(ACK) ) { + char *data; + int syn_ack, consumed; + + if (state == FIN_WAIT_1 || state == FIN_WAIT_2) { + state = FIN_WAIT_2; + ctrl = ACK; + goto consume_data; + } + syn_ack = state == CLOSED || state == SYN_RCVD; + consumed = ntohl(tcp->ack) - send_seq - syn_ack; + if (consumed < 0 || consumed > can_send) { + tcp_reset((struct iphdr *)&nic.packet[ETH_HLEN]); + goto recv_data; + } + + rtt = currticks() - last_sent; + srtt = !srtt ? rtt : (srtt*4 + rtt)/5; + rto = srtt + srtt/2; + if (rto < TCP_MIN_TIMEOUT) + rto = TCP_MIN_TIMEOUT; + else if (rto > TCP_MAX_TIMEOUT) + rto = TCP_MAX_TIMEOUT; + + can_send -= consumed; + send_seq += consumed + syn_ack; + data = buf + sizeof(struct iphdr) + sizeof(struct tcphdr); + if (can_send) { + memmove(data, data + consumed, can_send); + } + if (!sent_all) { + int more_data; + data += can_send; + more_data = buf + sizeof(buf) - data; + if (more_data > 0) { + more_data = send(more_data, data, ptr); + can_send += more_data; + } + sent_all = !more_data; + } + if (state == SYN_RCVD) { + state = ESTABLISHED; + ctrl = PSH|ACK; + goto consume_data; + } + if (tcp->ctrl & htons(RST)) + return (0); + } else if (tcp->ctrl & htons(RST)) { + if (state == CLOSED) + goto recv_data; + return (0); + } + + consume_data: + ip = (struct iphdr *)&nic.packet[ETH_HLEN]; + header_size = sizeof(struct iphdr) + ((ntohs(tcp->ctrl)>>10)&0x3C); + payload = ntohs(ip->len) - header_size; + if (payload > 0 && state == ESTABLISHED) { + int old_bytes = recv_seq - (long)ntohl(tcp->seq); + if (old_bytes >= 0 && payload - old_bytes > 0) { + recv_seq += payload - old_bytes; + if (state != FIN_WAIT_1 && state != FIN_WAIT_2 && + !recv(payload - old_bytes, + &nic.packet[ETH_HLEN+header_size+old_bytes], + ptr)) { + goto close; + } + if ((state == ESTABLISHED || state == SYN_RCVD) && + !(tcp->ctrl & htons(FIN))) { + int in_window = window - 2*TCP_MIN_WINDOW > + recv_seq - last_ack; + ctrl = can_send ? PSH|ACK : ACK; + if (!can_send && in_window) { +/* Window scaling is broken right now, just fall back to acknowledging every */ +/* packet immediately and unconditionally. FIXME */ /***/ +/* if (await_reply(await_tcp, srcsock, + &tcp, rto)) + goto got_data; + else */ + goto send_data; + } + if (!in_window) { + window += TCP_MIN_WINDOW; + if (window > TCP_MAX_WINDOW) + window = TCP_MAX_WINDOW; + } + goto send_data; + } + } else { + /* saw old data again, must have lost packets */ + window /= 2; + if (window < 2*TCP_MIN_WINDOW) + window = 2*TCP_MIN_WINDOW; + } + } + + if (tcp->ctrl & htons(FIN)) { + if (state == ESTABLISHED) { + ctrl = FIN|ACK; + } else if (state == FIN_WAIT_1 || state == FIN_WAIT_2) { + ctrl = ACK; + } else { + ctrl = RST; + } + return (tcp_transmit(destip, srcsock, destsock, + send_seq, recv_seq + 1, window, ctrl, + sizeof(struct iphdr) + + sizeof(struct tcphdr), buf) && + (state == ESTABLISHED || + state == FIN_WAIT_1 || state == FIN_WAIT_2) && + !can_send); + } + + if (state == CLOSED) { + if (tcp->ctrl & htons(SYN)) { + recv_seq = ntohl(tcp->seq) + 1; + if (!(tcp->ctrl & htons(ACK))) { + state = SYN_RCVD; + ctrl = SYN|ACK|PSH; + goto send_data; + } else { + state = ESTABLISHED; + ctrl = PSH|ACK; + } + } + } + + if (can_send || payload) { + goto send_data; + } + goto recv_data; +}