6 void build_tcp_hdr(unsigned long destip, unsigned int srcsock,
7 unsigned int destsock, long send_seq, long recv_seq,
8 int window, int flags, int ttl, int len, const void *buf)
12 ip = (struct iphdr *)buf;
13 build_ip_hdr(destip, ttl, IP_TCP, 0, len, buf);
14 tcp = (struct tcphdr *)(ip + 1);
15 tcp->src = htons(srcsock);
16 tcp->dst = htons(destsock);
17 tcp->seq = htonl(send_seq);
18 tcp->ack = htonl(recv_seq);
19 tcp->ctrl = htons(flags + (5 << 12)); /* No TCP options */
20 tcp->window = htons(window);
22 if ((tcp->chksum = tcpudpchksum(ip)) == 0)
26 /**************************************************************************
27 TCP_TRANSMIT - Send a TCP packet
28 **************************************************************************/
29 int tcp_transmit(unsigned long destip, unsigned int srcsock,
30 unsigned int destsock, long send_seq, long recv_seq,
31 int window, int flags, int len, const void *buf)
33 build_tcp_hdr(destip, srcsock, destsock, send_seq, recv_seq,
34 window, flags, 60, len, buf);
35 return ip_transmit(len, buf);
38 int tcp_reset(struct iphdr *ip) {
39 struct tcphdr *tcp = (struct tcphdr *)(ip + 1);
40 char buf[sizeof(struct iphdr) + sizeof(struct tcphdr)];
42 if (!(tcp->ctrl & htons(RST))) {
43 long seq = ntohl(tcp->seq) + ntohs(ip->len) -
44 sizeof(struct iphdr) -
45 ((ntohs(tcp->ctrl) >> 10) & 0x3C);
46 if (tcp->ctrl & htons(SYN|FIN))
48 return tcp_transmit(ntohl(ip->src.s_addr),
49 ntohs(tcp->dst), ntohs(tcp->src),
50 tcp->ctrl&htons(ACK) ? ntohl(tcp->ack) : 0,
51 seq, TCP_MAX_WINDOW, RST, sizeof(buf), buf);
56 /**************************************************************************
57 TCP - Simple-minded TCP stack. Can only send data once and then
58 receive the response. The algorithm for computing window
59 sizes and delaying ack's is currently broken, and thus
60 disabled. Performance would probably improve a little, if
61 this gets fixed. FIXME
62 **************************************************************************/
63 static int await_tcp(int ival, void *ptr, unsigned short ptype __unused,
64 struct iphdr *ip, struct udphdr *udp __unused,
70 if (arptable[ARP_CLIENT].ipaddr.s_addr != ip->dest.s_addr)
72 if (ntohs(tcp->dst) != ival) {
80 int tcp_transaction(unsigned long destip, unsigned int destsock, void *ptr,
81 int (*send)(int len, void *buf, void *ptr),
82 int (*recv)(int len, const void *buf, void *ptr)) {
83 static uint16_t srcsock = 0;
85 long send_seq = currticks();
92 char buf[128]; /* Small outgoing buffer */
95 int window = 3*TCP_MIN_WINDOW;
100 long rto = TCP_INITIAL_TIMEOUT;
101 int retry = TCP_MAX_TIMEOUT/TCP_INITIAL_TIMEOUT;
102 enum { CLOSED, SYN_RCVD, ESTABLISHED,
103 FIN_WAIT_1, FIN_WAIT_2 } state = CLOSED;
106 srcsock = currticks();
108 if (++srcsock < 1024)
116 if (!tcp_transmit(destip, srcsock, destsock, send_seq,
117 recv_seq, window, ctrl,
118 sizeof(struct iphdr) + sizeof(struct tcphdr)+
122 last_sent = currticks();
125 if (!await_reply(await_tcp, srcsock, &tcp,
126 (state == ESTABLISHED && !can_send)
127 ? TCP_MAX_TIMEOUT : rto)) {
128 if (state == ESTABLISHED) {
136 if (state == FIN_WAIT_1 || state == FIN_WAIT_2)
141 if (state == SYN_RCVD) {
142 tcp_transmit(destip, srcsock, destsock,
143 send_seq, 0, window, RST,
144 sizeof(struct iphdr) +
145 sizeof(struct tcphdr), buf);
153 retry = TCP_MAX_RETRY;
155 if (tcp->ctrl & htons(ACK) ) {
157 int syn_ack, consumed;
159 if (state == FIN_WAIT_1 || state == FIN_WAIT_2) {
164 syn_ack = state == CLOSED || state == SYN_RCVD;
165 consumed = ntohl(tcp->ack) - send_seq - syn_ack;
166 if (consumed < 0 || consumed > can_send) {
167 tcp_reset((struct iphdr *)&nic.packet[ETH_HLEN]);
171 rtt = currticks() - last_sent;
172 srtt = !srtt ? rtt : (srtt*4 + rtt)/5;
174 if (rto < TCP_MIN_TIMEOUT)
175 rto = TCP_MIN_TIMEOUT;
176 else if (rto > TCP_MAX_TIMEOUT)
177 rto = TCP_MAX_TIMEOUT;
179 can_send -= consumed;
180 send_seq += consumed + syn_ack;
181 data = buf + sizeof(struct iphdr) + sizeof(struct tcphdr);
183 memmove(data, data + consumed, can_send);
188 more_data = buf + sizeof(buf) - data;
190 more_data = send(more_data, data, ptr);
191 can_send += more_data;
193 sent_all = !more_data;
195 if (state == SYN_RCVD) {
200 if (tcp->ctrl & htons(RST))
202 } else if (tcp->ctrl & htons(RST)) {
209 ip = (struct iphdr *)&nic.packet[ETH_HLEN];
210 header_size = sizeof(struct iphdr) + ((ntohs(tcp->ctrl)>>10)&0x3C);
211 payload = ntohs(ip->len) - header_size;
212 if (payload > 0 && state == ESTABLISHED) {
213 int old_bytes = recv_seq - (long)ntohl(tcp->seq);
214 if (old_bytes >= 0 && payload - old_bytes > 0) {
215 recv_seq += payload - old_bytes;
216 if (state != FIN_WAIT_1 && state != FIN_WAIT_2 &&
217 !recv(payload - old_bytes,
218 &nic.packet[ETH_HLEN+header_size+old_bytes],
222 if ((state == ESTABLISHED || state == SYN_RCVD) &&
223 !(tcp->ctrl & htons(FIN))) {
224 int in_window = window - 2*TCP_MIN_WINDOW >
226 ctrl = can_send ? PSH|ACK : ACK;
227 if (!can_send && in_window) {
228 /* Window scaling is broken right now, just fall back to acknowledging every */
229 /* packet immediately and unconditionally. FIXME */ /***/
230 /* if (await_reply(await_tcp, srcsock,
237 window += TCP_MIN_WINDOW;
238 if (window > TCP_MAX_WINDOW)
239 window = TCP_MAX_WINDOW;
244 /* saw old data again, must have lost packets */
246 if (window < 2*TCP_MIN_WINDOW)
247 window = 2*TCP_MIN_WINDOW;
251 if (tcp->ctrl & htons(FIN)) {
252 if (state == ESTABLISHED) {
254 } else if (state == FIN_WAIT_1 || state == FIN_WAIT_2) {
259 return (tcp_transmit(destip, srcsock, destsock,
260 send_seq, recv_seq + 1, window, ctrl,
261 sizeof(struct iphdr) +
262 sizeof(struct tcphdr), buf) &&
263 (state == ESTABLISHED ||
264 state == FIN_WAIT_1 || state == FIN_WAIT_2) &&
268 if (state == CLOSED) {
269 if (tcp->ctrl & htons(SYN)) {
270 recv_seq = ntohl(tcp->seq) + 1;
271 if (!(tcp->ctrl & htons(ACK))) {
282 if (can_send || payload) {