mirror of
https://github.com/xcat2/xNBA.git
synced 2025-01-05 11:05:07 +00:00
Split TCP code out into proto/tcp.c
This commit is contained in:
parent
cc980d1c94
commit
a918abc036
298
src/core/nic.c
298
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;
|
||||
|
@ -18,4 +18,6 @@ struct iphdr {
|
||||
struct in_addr dest;
|
||||
} PACKED;
|
||||
|
||||
extern uint16_t tcpudpchksum(struct iphdr *ip);
|
||||
|
||||
#endif /* _IP_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 */
|
||||
|
286
src/proto/tcp.c
Normal file
286
src/proto/tcp.c
Normal file
@ -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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user