initial commit after making...
Stefan Schuermans authored 12 years ago
|
5)
6) #include <stdio.h>
7)
8) #include "config.h"
9) #include "checksum.h"
10) #include "debug.h"
11) #include "ethernet.h"
12) #include "http.h"
13) #include "ip.h"
14) #include "macros.h"
15) #include "nethelp.h"
16) #include "random.h"
17) #include "tcp.h"
18)
19) #define TCP_URG 0x20
20) #define TCP_ACK 0x10
21) #define TCP_PSH 0x08
22) #define TCP_RST 0x04
23) #define TCP_SYN 0x02
24) #define TCP_FIN 0x01
25) #define TCP_FLAGS 0x3F
26)
27) #define TcpResendTicks 5 // time after which to resend a packet not
28) // ACKed (in 200ms steps, max. 255)
29) #define TcpTimeWaitTicks 20 // time to wait in TIME_WAIT state (in 200ms
30) // steps, max. 255)
31) #define TcpTimeoutTicks 50 // maximum idle time of connection before it
32) // is reset (in 200ms steps, max. 255)
33) #define TcpMaxLifeTimeTicks 150 // maximum lifetime of connection before it
34) // is reset (in 200ms steps, max. 255)
35)
36) // TCP connections
37) struct TcpConnection TcpConns[8];
38)
39) // initialize
40) void TcpInit(void) // (extern)
41) {
42) unsigned char i;
43)
44) // set all connections to closed
45) for (i = 0; i < count(TcpConns); i++)
46) TcpConns[i].State = TCP_CLOSED;
47) }
48)
49) // send a TCP packet
50) // pData must point to a struct TcpPacket with TcpHdr.SrcPort,
51) // TcpHdr.DestPort,
52) // TcpHdr.SeqNo, TcpHdr.AckNo, TcpHdr.WndSz and IpHdr.Dest already
53) // initialized
54) static void TcpSendPacket(unsigned char *pData, unsigned short Length,
55) unsigned char optLen, unsigned char flags)
56) {
57) struct TcpPacket *pTcpPack;
58) unsigned int chk;
59)
60) // packet too short
61) if (Length < sizeof(struct TcpPacket) + optLen)
62) return;
63)
64) // convert pointer to UDP packet
65) // (this saves us from always casting pData)
66) pTcpPack = (struct TcpPacket *)pData;
67)
68) debug_tcp_printf("send src=%u dest=%u flags=%s%s%s%s%s%s len=%u",
69) ntohs(pTcpPack->TcpHdr.SrcPort),
70) ntohs(pTcpPack->TcpHdr.DestPort),
71) flags & TCP_URG ? "U" : "",
72) flags & TCP_ACK ? "A" : "",
73) flags & TCP_PSH ? "P" : "",
74) flags & TCP_RST ? "R" : "",
75) flags & TCP_SYN ? "S" : "",
76) flags & TCP_FIN ? "F" : "", Length);
77)
78) // fill in header values
79) pTcpPack->TcpHdr.Ofs_Flags =
80) htons((unsigned short)((optLen + 23) & 0x3C) << 10 |
81) (unsigned short)(flags & TCP_FLAGS));
82) pTcpPack->TcpHdr.Chk = 0x0000;
83) pTcpPack->TcpHdr.UrgentPtr = 0x0000;
84) ip_cpy(pTcpPack->IpHdr.Src, ConfigIp); // put IP already here into
85) // IP header
86) // because it is needed for calculation of UDP checksum
87)
88) // generate checksum
89) chk = Checksum((unsigned char *)&pTcpPack->IpHdr.Src,
90) Length - sizeof(struct EthernetHeader) -
91) sizeof(struct IpHeader) + 8, 0x0006,
92) Length - sizeof(struct EthernetHeader) -
93) sizeof(struct IpHeader));
94) pTcpPack->TcpHdr.Chk = htons(chk);
95)
96) // send TCP packet
97) pTcpPack->IpHdr.Proto = 0x06; // TCP
98) IpSend(pData, Length);
99) }
100)
101) // send an empty segment
102) static void TcpEmptySegment(struct TcpConnection *pConn, unsigned long seq,
103) unsigned long ack, unsigned char flags)
104) {
105) struct TcpPacket EsPack;
106)
107) // send empty TCP segment
108) EsPack.TcpHdr.SrcPort = htons(pConn->LocalPort);
109) EsPack.TcpHdr.DestPort = htons(pConn->RemotePort);
110) EsPack.TcpHdr.SeqNo = htonl(seq);
111) EsPack.TcpHdr.AckNo = htonl(ack);
112) EsPack.TcpHdr.WndSz = htons(pConn->RcvWnd);
113) ip_cpy(EsPack.IpHdr.Dest, pConn->RemoteIp);
114) TcpSendPacket((unsigned char *)&EsPack, sizeof(EsPack), 0, flags);
115) return;
116) }
117)
118) // send a SYN segment (empty with MSS option set)
119) static void TcpSynSegment(struct TcpConnection *pConn, unsigned long seq,
120) unsigned long ack, unsigned char flags)
121) {
122) struct {
123) struct TcpPacket Tcp;
124) struct {
125) unsigned char Kind, Len;
126) unsigned short Mss;
127) } MssOpt;
128) } Pack;
129)
130) // send empty TCP segment with MSS
131) Pack.Tcp.TcpHdr.SrcPort = htons(pConn->LocalPort);
132) Pack.Tcp.TcpHdr.DestPort = htons(pConn->RemotePort);
133) Pack.Tcp.TcpHdr.SeqNo = htonl(seq);
134) Pack.Tcp.TcpHdr.AckNo = htonl(ack);
135) Pack.Tcp.TcpHdr.WndSz = htons(pConn->RcvWnd);
136) ip_cpy(Pack.Tcp.IpHdr.Dest, pConn->RemoteIp);
137) Pack.MssOpt.Kind = 2;
138) Pack.MssOpt.Len = 4;
139) Pack.MssOpt.Mss = htons(256);
140) TcpSendPacket((unsigned char *)&Pack, sizeof(Pack), sizeof(Pack.MssOpt),
141) flags);
142) return;
143) }
144)
145) // send a data segment
146) static void TcpSendDataSegment(unsigned char connNo,
147) struct TcpConnection *pConn, char needSendAck)
148) {
149) unsigned long sendDataLenL;
150) unsigned short sendDataLen, len;
151) struct {
152) struct TcpPacket Tcp;
153) unsigned char Data[256]; // do not use larger segments to save stack
154) // memory
155) } Packet;
156)
157) // if outbound connection is not closed yet
158) if (pConn->State == TCP_ESTAB || pConn->State == TCP_CLOSE_WAIT) {
159) // get maximum number of bytes that might be sent in this segment
160) sendDataLenL =
161) (unsigned long)pConn->SndWnd - (pConn->SndNxt - pConn->SndUna);
162) if ((signed long)sendDataLenL < 0) // just to be on the safe side - this
163) // should never happen
164) sendDataLen = 0;
165) sendDataLen =
166) (unsigned short)min(sendDataLenL, (unsigned long)pConn->Mss);
167) sendDataLen = min(sendDataLen, sizeof(Packet.Data));
168) // get data to send from user
169) if (sendDataLen > 0) {
170) debug_tcp_printf("notify send no=%u pos=%lu max_len=%u",
171) connNo, pConn->SndNxt - (pConn->Iss + 1), sendDataLen);
172) len =
173) pConn->Notify->Send(connNo, pConn->SndNxt - (pConn->Iss + 1),
174) Packet.Data, sendDataLen);
175) if (len > sendDataLen) // returned 0xFFFF (or any number too large)
176) // to close connection
177) {
178) debug_tcp_printf("notify send no=%u close", connNo);
179) TcpEmptySegment(pConn, pConn->SndNxt, pConn->RcvNxt, TCP_FIN | TCP_ACK); // send
180) // TCP
181) // FIN
182) pConn->SndNxt++;
183) pConn->State = TCP_FIN_WAIT_1; // go to state FIN-WAIT-1
184) debug_tcp_printf("notify close no=%u", connNo);
185) pConn->Notify->Close(connNo); // signal "connection closed" to user
186) return;
187) }
188) debug_tcp_printf("notify send no=%u len=%u", connNo, len);
189) sendDataLen = len;
190) }
191) }
192) // if outbound connection is already closed
193) else
194) // do not send data
195) sendDataLen = 0;
196)
197) // send a segment if data is available or an ACK needs to be sent
198) if (sendDataLen > 0 || needSendAck) {
199) // send TCP segment
200) Packet.Tcp.TcpHdr.SrcPort = htons(pConn->LocalPort);
201) Packet.Tcp.TcpHdr.DestPort = htons(pConn->RemotePort);
202) Packet.Tcp.TcpHdr.SeqNo = htonl(pConn->SndNxt);
203) Packet.Tcp.TcpHdr.AckNo = htonl(pConn->RcvNxt);
204) Packet.Tcp.TcpHdr.WndSz = htons(pConn->RcvWnd);
205) ip_cpy(Packet.Tcp.IpHdr.Dest, pConn->RemoteIp);
206) TcpSendPacket((unsigned char *)&Packet,
207) sizeof(struct TcpPacket) + sendDataLen, 0,
208) sendDataLen > 0 ? TCP_ACK | TCP_PSH : TCP_ACK);
209) pConn->SndNxt += sendDataLen;
210) }
211) }
212)
213) // tick procedure - call every 200ms
214) void TcpTick200(void) // (extern)
215) {
216) unsigned char i, MaxTicks;
217)
218) // for all active connections
219) for (i = 0; i < count(TcpConns); i++) {
220)
221) if (TcpConns[i].State != TCP_CLOSED) {
222) // increase normal timer
223) TcpConns[i].Ticks++;
224)
225) // get maximum value for normal timer
226) MaxTicks =
227) TcpConns[i].State ==
228) TCP_TIME_WAIT ? TcpTimeWaitTicks : TcpResendTicks;
229) // normal timer elapsed
230) if (TcpConns[i].Ticks >= MaxTicks) {
231) // reset normal timer
232) TcpConns[i].Ticks = 0;
233)
234) // different behaviour in different states
235) switch (TcpConns[i].State) {
236)
237) case TCP_SYN_RCVD:
238) // resend SYN,ACK segment
239) TcpSynSegment(&TcpConns[i], TcpConns[i].SndUna, TcpConns[i].RcvNxt,
240) TCP_SYN | TCP_ACK);
241) TcpConns[i].SndNxt = TcpConns[i].SndUna + 1;
242) break;
243)
244) case TCP_SYN_SENT:
245) // resend SYN segment
246) TcpSynSegment(&TcpConns[i], TcpConns[i].SndUna, 0, TCP_SYN);
247) TcpConns[i].SndNxt = TcpConns[i].SndUna + 1;
248) break;
249)
250) case TCP_ESTAB:
251) case TCP_CLOSE_WAIT:
252) // if something is not yet ACKed
253) if ((long)(TcpConns[i].SndUna - TcpConns[i].SndNxt) < 0) {
254) // resend data segment
255) TcpConns[i].SndNxt = TcpConns[i].SndUna; // some kind of "go
256) // back N"
257) // BUG: this is not really "go back N"
258) // according to RFC793, every segment sent and not acknowledged
259) // has to be stored
260) // in the resend queue until is is acknowledged
261) // but this is not possible on a microcontroller with 4kB of RAM
262) TcpSendDataSegment(i, &TcpConns[i], 0);
263) }
264) break;
265)
266) case TCP_FIN_WAIT_1:
267) case TCP_CLOSING:
268) case TCP_LAST_ACK:
269) // resend FIN segment
270) TcpEmptySegment(&TcpConns[i], TcpConns[i].SndUna,
271) TcpConns[i].RcvNxt, TCP_FIN | TCP_ACK);
272) TcpConns[i].SndNxt = TcpConns[i].SndUna + 1;
273) break;
274)
275) case TCP_TIME_WAIT:
276) // close connection, free TCB
277) TcpConns[i].State = TCP_CLOSED;
278) break;
279)
280) } // switch( TcpConns[i].State )
281)
282) } // if( TcpConns[i].Ticks >= ...
283)
284) } // if( TcpConns[i].State != ...
285)
286) if (TcpConns[i].State != TCP_CLOSED) {
287) // increase timeout timer
288) TcpConns[i].Timeout++;
289)
290) // timeout timer elapsed
291) if (TcpConns[i].Timeout >= TcpTimeoutTicks) {
292) // send a RST segment
293) TcpEmptySegment(&TcpConns[i], TcpConns[i].SndUna, TcpConns[i].RcvNxt,
294) TCP_RST);
295) // depending on state ...
296) switch (TcpConns[i].State) {
297) case TCP_SYN_RCVD:
298) case TCP_ESTAB:
299) case TCP_CLOSE_WAIT:
300) TcpConns[i].State = TCP_CLOSED; // close connection
301) debug_tcp_printf("notify close no=%u", i);
302) TcpConns[i].Notify->Close(i); // tell user that connection was
303) // closed
304) break;
305) default:
306) TcpConns[i].State = TCP_CLOSED; // close connection
307) }
308)
309) } // if( TcpConns[i].Timeout >= ...
310)
311) } // if( TcpConns[i].State != ...
312)
313) if (TcpConns[i].State != TCP_CLOSED) {
314) // increase lifetime timer
315) TcpConns[i].LifeTime++;
316)
317) // lifetime timer elapsed
318) // - connections may not last forever - even not with traffic on them
319) if (TcpConns[i].LifeTime >= TcpMaxLifeTimeTicks) {
320) // send a RST segment
321) TcpEmptySegment(&TcpConns[i], TcpConns[i].SndUna, TcpConns[i].RcvNxt,
322) TCP_RST);
323) // depending on state ...
324) switch (TcpConns[i].State) {
325) case TCP_SYN_RCVD:
326) case TCP_ESTAB:
327) case TCP_CLOSE_WAIT:
328) TcpConns[i].State = TCP_CLOSED; // close connection
329) debug_tcp_printf("notify close no=%u", i);
330) TcpConns[i].Notify->Close(i); // tell user that connection was
331) // closed
332) break;
333) default:
334) TcpConns[i].State = TCP_CLOSED; // close connection
335) }
336) } // if( TcpConns[i].LifeTime >= ...
337)
338) } // if( TcpConns[i].State != ...
339)
340) } // for( i ...
341) }
342)
343) // process a received TCP packet
344) void TcpRecv(unsigned char *pData, unsigned short Length) // (extern)
345) {
346) struct TcpPacket *pTcpPack;
347) unsigned long seq, ack, seqEnd;
348) unsigned short localPort, remotePort, wnd, mss, ofs, len, tmp, rcvWnd;
349) unsigned char i, flags, *optPtr, optLen, connNo;
350) struct TcpConnection *pConn;
351) char accept, sendAck;
352) struct TcpNotify *pNotify;
353)
354) // packet too short
355) if (Length < sizeof(struct TcpPacket))
356) return;
357)
358) // convert pointer to TCP packet
359) // (this saves us from always casting pData)
360) pTcpPack = (struct TcpPacket *)pData;
361)
362) // test checksum
363) if (Checksum((unsigned char *)&pTcpPack->IpHdr.Src,
364) Length - sizeof(struct EthernetHeader) -
365) sizeof(struct IpHeader) + 8, 0x0006,
366) Length - sizeof(struct EthernetHeader) -
367) sizeof(struct IpHeader)) != 0)
368) return;
369)
370) // get local and remote port
371) localPort = ntohs(pTcpPack->TcpHdr.DestPort);
372) remotePort = ntohs(pTcpPack->TcpHdr.SrcPort);
373)
374) // ignore packets sent from or to port 0
375) // - this might be some attack
376) if (localPort == 0 || remotePort == 0)
377) return;
378)
379) // get sequence number, acknowledge number and window size
380) seq = ntohl(pTcpPack->TcpHdr.SeqNo);
381) ack = ntohl(pTcpPack->TcpHdr.AckNo);
382) wnd = ntohs(pTcpPack->TcpHdr.WndSz);
383) // maximum segment size: liberal default according to RFC879
384) mss = 536;
385)
386) // get flags
387) flags = ntohs(pTcpPack->TcpHdr.Ofs_Flags) & 0x003F;
388)
389) // get data offset and segment length in bytes
390) ofs = (ntohs(pTcpPack->TcpHdr.Ofs_Flags) & 0xF000) >> 10;
391) if (ofs < 20 || ofs > Length - sizeof(struct EthernetHeader) - sizeof(struct IpHeader)) // invalid
392) // offset
393) return; // remote side is unable to build valid TCP packets - ignore
394)
395) // get segment length (length of data in segment)
396) len =
397) Length - sizeof(struct EthernetHeader) - sizeof(struct IpHeader) - ofs;
398)
399) debug_tcp_printf("recv src=%u dest=%u flags=%s%s%s%s%s%s len=%u",
400) ntohs(pTcpPack->TcpHdr.SrcPort),
401) ntohs(pTcpPack->TcpHdr.DestPort),
402) flags & TCP_URG ? "U" : "",
403) flags & TCP_ACK ? "A" : "",
404) flags & TCP_PSH ? "P" : "",
405) flags & TCP_RST ? "R" : "",
406) flags & TCP_SYN ? "S" : "",
407) flags & TCP_FIN ? "F" : "", Length);
408)
409) // process options
410) optLen = (unsigned char)(ofs - 20);
411) optPtr = (unsigned char *)&pTcpPack->TcpHdr + sizeof(struct TcpHeader);
412) while (optLen > 0) {
413) switch (*optPtr) {
414) // end of options
415) case 0:
416) optLen = 0;
417) break;
418) // no operation
419) case 1:
420) optLen--;
421) optPtr++;
422) break;
423) // maximum segment size
424) case 2:
425) if (optLen < 4 || optPtr[1] != 4) {
426) optPtr = NULL; // error
427) optLen = 0;
428) break;
429) }
430) mss = ntohs(*(unsigned short *)(optPtr + 2));
431) optLen -= 4;
432) optPtr += 4;
433) break;
434) // unknown option
435) default:
436) if (optLen < 2 || optPtr[1] > optLen) {
437) optPtr = NULL; // error
438) optLen = 0;
439) }
440) optLen -= optPtr[1]; // ignore this option
441) optPtr += optPtr[1];
442) } // switch( *optPtr )
443) } // while( optLen > 0 )
444) if (optPtr == NULL) // some error during option parsing
445) return; // remote side is unable to build valid TCP packets - ignore
446)
447) // get sequence number at end of this segment
448) seqEnd = seq + len;
449) if (flags & TCP_SYN) // TCP SYN counts as 1 in sequence number space
450) seqEnd++;
451) if (flags & TCP_FIN) // TCP FIN counts as 1 in sequence number space
452) seqEnd++;
453)
454) // search connection
455) for (i = 0; i < count(TcpConns); i++)
456) if (TcpConns[i].State != TCP_CLOSED &&
457) ip_eq(TcpConns[i].RemoteIp, pTcpPack->IpHdr.Src) &&
458) TcpConns[i].LocalPort == localPort &&
459) TcpConns[i].RemotePort == remotePort)
460) break;
461)
462) // connection not found, only SYN flag set, no data
463) if (i >= count(TcpConns) && flags == TCP_SYN && len == 0) {
464) // accept connections on some ports (note: localPort cannot be 0 because
465) // of check above)
466) rcvWnd = 0;
467) pNotify = NULL;
468) // HTTP
469) if (localPort == ConfigHttpPort) {
470) rcvWnd = 256; // connection shall be accepted
471) pNotify = &HttpNotify;
472) }
473) // connection shall be accepted
474) if (pNotify != NULL) {
475) // search empty connection slot
476) for (i = 0; i < count(TcpConns); i++)
477) if (TcpConns[i].State == TCP_CLOSED)
478) break;
479) // free connection slot found
480) if (i < count(TcpConns)) {
481) // create new connection (passive) in this slot
482) ip_cpy(TcpConns[i].RemoteIp, pTcpPack->IpHdr.Src);
483) TcpConns[i].LocalPort = localPort;
484) TcpConns[i].RemotePort = remotePort;
485) TcpConns[i].State = TCP_LISTEN;
486) TcpConns[i].Ticks = 0;
487) TcpConns[i].Timeout = 0;
488) TcpConns[i].LifeTime = 0;
489) TcpConns[i].RcvWnd = rcvWnd;
490) TcpConns[i].Notify = pNotify;
491) }
492) }
493) }
494) // connection still not found
495) if (i >= count(TcpConns)) {
496) struct TcpPacket EsPack;
497) unsigned char EsFlags;
498)
499) // do nothing if RST flag is set
500) if (flags & TCP_RST)
501) return;
502)
503) // send TCP RST
504) EsPack.TcpHdr.SrcPort = htons(localPort);
505) EsPack.TcpHdr.DestPort = htons(remotePort);
506) EsPack.TcpHdr.WndSz = htons(0);
507) ip_cpy(EsPack.IpHdr.Dest, pTcpPack->IpHdr.Src);
508) if (flags & TCP_ACK) {
509) EsPack.TcpHdr.SeqNo = htonl(ack);
510) EsPack.TcpHdr.AckNo = htonl(0);
511) EsFlags = TCP_RST;
512) } else {
513) EsPack.TcpHdr.SeqNo = htonl(0);
514) EsPack.TcpHdr.AckNo = htonl(seqEnd);
515) EsFlags = TCP_RST | TCP_ACK;
516) }
517) TcpSendPacket((unsigned char *)&EsPack, sizeof(EsPack), 0, EsFlags);
518) return;
519) }
520) // a connection was found - save number and pointer to it
521) connNo = i;
522) pConn = &TcpConns[i];
523)
524) // reset connection on reception of urgent data (URG flag set)
525) // BUG: urgent data must be supported according to RFC793
526) // but urgent data is not used in protocols we use, so leave this out here
527) // to save time and memory
528) if (flags & TCP_URG) {
529) // send TCP RST
530) if (flags & TCP_ACK)
531) TcpEmptySegment(pConn, ack, 0, TCP_RST);
532) else
533) TcpEmptySegment(pConn, 0, seqEnd, TCP_RST | TCP_ACK);
534) return;
535) }
536) // different behaviour in different states according to RFC793
537) switch (pConn->State) {
538)
539) case TCP_LISTEN:
540) if (flags & TCP_RST) // An incoming RST should be ignored.
541) return;
542) if (flags & TCP_ACK) // Any acknowledgment is bad if it arrives on
543) // a connection still in the LISTEN state.
544) {
545) TcpEmptySegment(pConn, ack, 0, TCP_RST); // An acceptable reset
546) // segment should be formed
547) // for any arriving
548) // ACK-bearing segment.
549) pConn->Ticks = 0; // restart timer
550) return;
551) }
552) if (flags & TCP_SYN) // third check for a SYN
553) {
554) pConn->RcvNxt = seq + 1; // Set RCV.NXT to SEG.SEQ+1,
555) pConn->Irs = seq; // IRS is set to SEG.SEQ
556) RandomGetData((unsigned char *)&pConn->Iss, sizeof(pConn->Iss)); // ISS
557) // should
558) // be
559) // selected
560) // (randomly!!!)
561) TcpSynSegment(pConn, pConn->Iss, pConn->RcvNxt, TCP_SYN | TCP_ACK); // and
562) // a
563) // SYN
564) // segment
565) // sent
566) pConn->SndNxt = pConn->Iss + 1; // SND.NXT is set to ISS+1
567) pConn->SndUna = pConn->Iss; // and SND.UNA to ISS
568) pConn->State = TCP_SYN_RCVD; // The connection state should be
569) // changed to SYN-RECEIVED.
570) pConn->SndWnd = wnd; // initialize send window from packet
571) pConn->SndWl1 = seq;
572) pConn->SndWl2 = ack;
573) pConn->Mss = mss; // save maximum segment size
574) pConn->Ticks = 0; // restart timer
575) return;
576) }
577) // fourth other text or control
578) // So you are unlikely to get here, but if you do, drop the segment, and
579) // return.
580) return;
581)
582) case TCP_SYN_SENT:
583) accept = 0;
584) if (flags & TCP_ACK) // If the ACK bit is set
585) {
586) if ((long)(ack - pConn->Iss) <= 0 || (long)(ack - pConn->SndNxt) > 0) // If
587) // SEG.ACK
588) // =<
589) // ISS,
590) // or
591) // SEG.ACK
592) // >
593) // SND.NXT,
594) {
595) if (!(flags & TCP_RST)) // (unless the RST bit is set)
596) TcpEmptySegment(pConn, ack, 0, TCP_RST); // send a reset
597) return; // and discard the segment. Return.
598) }
599) accept = (long)(pConn->SndUna - ack) <= 0 && (long)(ack - pConn->SndNxt) <= 0; // If
600) // SND.UNA
601) // =<
602) // SEG.ACK
603) // =<
604) // SND.NXT
605) // then
606) // the
607) // ACK
608) // is
609) // acceptable.
610) }
611) if (flags & TCP_RST) // If the RST bit is set
612) {
613) if (accept) // If the ACK was acceptable
614) pConn->State = TCP_CLOSED; // enter CLOSED state, delete TCB,
615) return; // drop the segment and return.
616) }
617) if ((accept || !(flags & TCP_ACK)) && // This step should be
618) // reached only if the ACK is
619) // ok, or there is no ACK,
620) flags & TCP_SYN) // If the SYN bit is on
621) {
622) pConn->RcvNxt = seq + 1; // RCV.NXT is set to SEG.SEQ+1,
623) pConn->Irs = seq; // IRS is set to SEG.SEQ.
624) pConn->SndWl2 = pConn->RcvNxt; // last acknowledge number when
625) // updating the window size is first
626) // acknowledge number at all
627) if (accept) // (if there is an ACK)
628) pConn->SndUna = ack; // SND.UNA should be advanced to equal
629) // SEG.ACK
630) pConn->SndWnd = wnd; // initialize send window from packet
631) pConn->SndWl1 = seq;
632) pConn->SndWl2 = ack;
633) pConn->Mss = mss; // save maximum segment size
634) if ((long)(pConn->SndUna - pConn->Iss) > 0) // If SND.UNA > ISS
635) // (our SYN has been
636) // ACKed),
637) {
638) pConn->State = TCP_ESTAB; // change the connection state to
639) // ESTABLISHED,
640) debug_tcp_printf("notify connect no=%u", connNo);
641) pConn->Notify->Connect(connNo); // signal "connected"
642) TcpEmptySegment(pConn, pConn->SndNxt, pConn->RcvNxt, TCP_ACK); // form
643) // an
644) // ACK
645) // segment
646) // and
647) // send
648) // it.
649) } else // Otherwise
650) {
651) pConn->State = TCP_SYN_RCVD; // enter SYN-RECEIVED,
652) TcpSynSegment(pConn, pConn->Iss, pConn->RcvNxt, TCP_SYN | TCP_ACK); // form
653) // a
654) // SYN,ACK
655) // segment
656) // and
657) // send
658) // it.
659) }
660) pConn->Ticks = 0; // restart timer
661) }
662) return;
663)
664) } // switch( pConn->State )
665)
666) // Otherwise,
667)
668) // first check sequence number
669) if (len == 0)
670) if (pConn->RcvWnd == 0)
671) accept = seq == pConn->RcvNxt; // SEG.SEQ = RCV.NXT
672) else
673) accept = (long)(pConn->RcvNxt - seq) <= 0 && // RCV.NXT =< SEG.SEQ
674) // < RCV.NXT+RCV.WND
675) (long)(seq - (pConn->RcvNxt + pConn->RcvWnd)) < 0;
676) else if (pConn->RcvWnd == 0)
677) accept = 0; // not acceptable
678) else
679) accept = ((long)(pConn->RcvNxt - seq) <= 0 && // RCV.NXT =< SEG.SEQ
680) // < RCV.NXT+RCV.WND
681) (long)(seq - (pConn->RcvNxt + pConn->RcvWnd)) < 0) || ((long)(pConn->RcvNxt - (seq + len - 1) <= 0) && // or
682) // RCV.NXT
683) // =<
684) // SEG.SEQ+SEG.LEN-1
685) // <
686) // RCV.NXT+RCV.WND
687) (long)((seq + len - 1) - (pConn->RcvNxt + pConn->RcvWnd)) < 0);
688)
689) // because there is not enough memory to store segments needed later,
690) // we only accept segments with SEG.SEQ <= RCV.NXT
691) // thus, we reject the segment if SEG.SEQ > RCV.NXT
692) // BAD PERFORMANCE: this is _not_ a bug, but a major impact on performace
693) // when packets arrive out of order
694) // - however, we cannot do something against it,
695) // because there is not enough memory available on the controller
696) // to store segements for later processing
697) if (accept && (long)(seq - pConn->RcvNxt) > 0)
698) accept = 0;
699)
700) // If an incoming segment is not acceptable
701) if (!accept) {
702) /* disabled this - sometimes it ssems to generates endless ACKs being
703) exchanged with remote host) if( ! (flags & TCP_RST) ) // (unless the
704) RST bit is set) TcpEmptySegment( pConn, pConn->SndNxt, pConn->RcvNxt,
705) TCP_ACK ); // an acknowledgment should be sent in reply */
706) return; // drop the unacceptable segment and return.
707) }
708) // if segment contains duplicate data
709) tmp = pConn->RcvNxt - seq; // cannot be negative because of checks above
710) if (tmp > 0) {
711) // remove duplicate SYN flag from segment
712) if (flags & TCP_SYN) {
713) flags &= ~TCP_SYN;
714) tmp--;
715) }
716) // remove duplicate data from segment
717) ofs += tmp;
718) len -= tmp; // length cannot become negative here because of checks above
719) // now this segments starts with the expected sequence number
720) seq = pConn->RcvNxt;
721) }
722) // if segment extends beyond end of receive window
723) if (len > pConn->RcvWnd) {
724) // remove data behind receive window
725) seqEnd -= len - pConn->RcvWnd;
726) len = pConn->RcvWnd;
727) }
728) // restart timer, because this was an acceptable segment
729) pConn->Ticks = 0;
730)
731) // second check the RST bit,
732) if (flags & TCP_RST) {
733) switch (pConn->State) {
734)
735) case TCP_SYN_RCVD:
736) pConn->State = TCP_CLOSED; // enter the CLOSED state and delete
737) // the TCB, an return.
738) debug_tcp_printf("notify close no=%u", connNo);
739) pConn->Notify->Close(connNo); // signal "connection refused"
740) return;
741)
742) case TCP_ESTAB:
743) case TCP_FIN_WAIT_1:
744) case TCP_FIN_WAIT_2:
745) case TCP_CLOSE_WAIT:
746) pConn->State = TCP_CLOSED; // Enter the CLOSED state, delete the
747) // TCB, and return.
748) debug_tcp_printf("notify close no=%u", connNo);
749) pConn->Notify->Close(connNo); // signal "connection reset"
750) return;
751)
752) case TCP_CLOSING:
753) case TCP_LAST_ACK:
754) case TCP_TIME_WAIT:
755) pConn->State = TCP_CLOSED; // enter the CLOSED state, delete the
756) // TCB, and return.
757) return;
758)
759) } // switch( pConn->State )
760) } // if( flags & TCP_RST )
761)
762) // third check security and precedence
763) // - this does not apply to our implementation because we do not support
764) // security and precedence on TCP layer
765)
766) // fourth, check the SYN bit
767) if (flags & TCP_SYN) {
768) switch (pConn->State) {
769)
770) case TCP_SYN_RCVD:
771) case TCP_ESTAB:
772) case TCP_FIN_WAIT_1:
773) case TCP_FIN_WAIT_2:
774) case TCP_CLOSE_WAIT:
775) // If the SYN is in the window it is an error,
776) // - this is always the case here, because SYN not in window would habe
777) // been removed above
778) TcpEmptySegment(pConn, ack, 0, TCP_RST); // send a reset,
779) pConn->State = TCP_CLOSED; // enter the CLOSED state, delete the
780) // TCB, and return.
781) debug_tcp_printf("notify close no=%u", connNo);
782) pConn->Notify->Close(connNo); // signal "connection reset"
783) return;
784)
785) case TCP_CLOSING:
786) case TCP_LAST_ACK:
787) case TCP_TIME_WAIT:
788) // If the SYN is in the window it is an error,
789) // - this is always the case here, because SYN not in window would habe
790) // been removed above
791) TcpEmptySegment(pConn, ack, 0, TCP_RST); // send a reset,
792) pConn->State = TCP_CLOSED; // enter the CLOSED state, delete the
793) // TCB, and return.
794) return;
795)
796) } // switch( pConn->State )
797) } // if( flags & TCP_SYN )
798)
799) // fifth check the ACK field,
800) if (!(flags & TCP_ACK)) // if the ACK bit is off
801) return; // drop the segment and return
802) switch (pConn->State) {
803)
804) case TCP_SYN_RCVD:
805) if ((long)(pConn->SndUna - ack) <= 0 && // If SND.UNA =< SEG.ACK =<
806) // SND.NXT
807) (long)(ack - pConn->SndNxt) <= 0) {
808) pConn->State = TCP_ESTAB; // then enter ESTABLISHED state
809) debug_tcp_printf("notify connect no=%u", connNo);
810) pConn->Notify->Connect(connNo); // signal "connected"
811) // and continue processing.
812) } else // If the segment acknowledgment is not acceptable,
813) {
814) TcpEmptySegment(pConn, ack, 0, TCP_RST); // form a reset segment, and
815) // send it.
816) return; // drop this segment
817) }
818) // no break here
819)
820) case TCP_ESTAB:
821) case TCP_FIN_WAIT_1:
822) case TCP_FIN_WAIT_2:
823) case TCP_CLOSE_WAIT:
824) case TCP_CLOSING:
825) if ((long)(ack - pConn->SndUna) <= 0) // If the ACK is a duplicate
826) // (SEG.ACK <= SND.UNA),
827) break; // it can be ignored.
828) if ((long)(ack - pConn->SndNxt) > 0) // If the ACK acks something
829) // not yet sent (SEG.ACK >
830) // SND.NXT)
831) {
832) TcpEmptySegment(pConn, pConn->SndNxt, pConn->RcvNxt, TCP_ACK); // then
833) // send
834) // an
835) // ACK,
836) return; // drop the segment, and return.
837) }
838) // here: SND.UNA < SEG.ACK =< SND.NXT
839) pConn->SndUna = ack; // set SND.UNA <- SEG.ACK.
840) if ((long)(pConn->SndWl1 - seq) < 0 || // If SND.WL1 < SEG.SEQ
841) (pConn->SndWl1 == seq && (long)(pConn->SndWl2 - ack) <= 0)) // or
842) // (SND.WL1
843) // =
844) // SEG.SEQ
845) // and
846) // SND.WL2
847) // =<
848) // SEG.ACK),
849) {
850) pConn->SndWnd = wnd; // set SND.WND <- SEG.WND,
851) pConn->SndWl1 = seq; // set SND.WL1 <- SEG.SEQ,
852) pConn->SndWl2 = ack; // and set SND.WL2 <- SEG.ACK.
853) }
854) pConn->Timeout = 0; // restart timeout timer
855) debug_tcp_printf("notify sent no=%u pos=%lu",
856) connNo, pConn->SndNxt - (pConn->Iss + 1));
857) pConn->Notify->Sent(connNo, pConn->SndUna - (pConn->Iss + 1)); // signal
858) // "send
859) // completed"
860) // (up
861) // to
862) // ack)
863) // additional processing
864) switch (pConn->State) {
865) case TCP_FIN_WAIT_1:
866) if (pConn->SndUna == pConn->SndNxt) // if our FIN is now
867) // acknowledged
868) pConn->State = TCP_FIN_WAIT_2; // then enter FIN-WAIT-2 and continue
869) // processing in that state.
870) // no break here
871) case TCP_FIN_WAIT_2:
872) if (pConn->SndUna == pConn->SndNxt) // if the retransmission
873) // queue is empty,
874) {
875) debug_tcp_printf("notify close no=%u", connNo);
876) pConn->Notify->Close(connNo); // the user's CLOSE can be
877) // acknowledged
878) }
879) break;
880) case TCP_CLOSING:
881) if (pConn->SndUna == pConn->SndNxt) // if the ACK acknowledges
882) // our FIN
883) pConn->State = TCP_TIME_WAIT; // then enter the TIME-WAIT state,
884) else
885) return; // otherwise ignore the segment.
886) break;
887) }
888) break;
889)
890) case TCP_LAST_ACK:
891) // The only thing that can arrive in this state is an acknowledgment of
892) // our FIN.
893) if (pConn->SndUna == pConn->SndNxt) // If our FIN is now acknowledged,
894) {
895) pConn->State = TCP_CLOSED; // delete the TCB, enter the CLOSED
896) // state,
897) return; // and return.
898) }
899) break;
900)
901) case TCP_TIME_WAIT:
902) // The only thing that can arrive in this state is a retransmission of
903) // the remote FIN.
904) TcpEmptySegment(pConn, ack, seqEnd, TCP_ACK); // Acknowledge it,
905) break;
906)
907) } // switch( pConn->State )
908)
909) // sixth, check the URG bit,
910) // - this cannot occur, because we have alredy reset the connection if URG
911) // was set
912)
913) // no ACK needs to be sent yet
914) sendAck = 0;
915)
916) // seventh, process the segment text,
917) if (len > 0) {
918) switch (pConn->State) {
919)
920) case TCP_ESTAB:
921) case TCP_FIN_WAIT_1:
922) case TCP_FIN_WAIT_2:
923) pConn->RcvWnd -= len; // make receive window smaller (len <=
924) // pConn->RcvWnd)
925) pConn->RcvNxt += len; // advance sequence number of next data to
926) // receive
927) pConn->Timeout = 0; // restart timeout timer
928) debug_tcp_printf("notify recv no=%u pos=%lu len=%u, min_wnd=%u",
929) connNo, pConn->RcvNxt - (pConn->Irs + 1) - len, len,
930) pConn->RcvWnd);
931) pConn->RcvWnd = pConn->Notify->Received(connNo, pConn->RcvNxt - (pConn->Irs + 1) - len, // give
932) // received
933) // data
934) // to
935) // user
936) (unsigned char *)&pTcpPack->TcpHdr + ofs, len, // (update
937) // receive
938) // window
939) // size)
940) pConn->RcvWnd);
941) debug_tcp_printf("notify recv no=%u wnd=%u", connNo, pConn->RcvWnd);
942) sendAck = 1; // remember to send an ACK
943) break;
944)
945) } // switch( pConn->State )
946) } // if( len > 0 )
947)
948) // eighth, check the FIN bit,
949) if (flags & TCP_FIN) {
950) switch (pConn->State) {
951)
952) case TCP_SYN_RCVD:
953) case TCP_ESTAB:
954) sendAck = 1; // remember to send an ACK
955) pConn->RcvNxt++; // FIN counts as one in sequence number space
956) pConn->State = TCP_CLOSE_WAIT; // Enter the CLOSE-WAIT state.
957) // close outbound part of the connection
958) // i.e. do an automatic call to close
959) TcpEmptySegment(pConn, pConn->SndNxt, pConn->RcvNxt, TCP_FIN | TCP_ACK); // send
960) // a
961) // FIN
962) pConn->SndNxt++;
963) pConn->State = TCP_CLOSING;
964) debug_tcp_printf("notify close no=%u", connNo);
965) pConn->Notify->Close(connNo); // signal "connection closed" to user
966) return; // we do not need to send an ack, becaue we already sent it
967) // with our FIN
968)
969) case TCP_FIN_WAIT_1:
970) sendAck = 1; // remember to send an ACK
971) pConn->RcvNxt++; // FIN counts as one in sequence number space
972) pConn->State = TCP_CLOSING; // Enter the CLOSING state.
973) break;
974)
975) case TCP_FIN_WAIT_2:
976) sendAck = 1; // remember to send an ACK
977) pConn->RcvNxt++; // FIN counts as one in sequence number space
978) pConn->State = TCP_TIME_WAIT; // Enter the TIME-WAIT state.
979) break;
980)
981) case TCP_CLOSING:
982) case TCP_CLOSE_WAIT:
983) case TCP_LAST_ACK:
984) case TCP_TIME_WAIT:
985) sendAck = 1; // remember to send an ACK
986) break;
987)
988) } // switch( pConn->State )
989) }
990) // send data / ACK segment
991) TcpSendDataSegment(connNo, pConn, sendAck);
992) }
993)
994) // open a TCP connection
995) // must not be called from a TCP notification function
996) // returns the connection number of the new connection of 0xFF in case of
997) // error
998) unsigned char TcpOpen(unsigned char *remoteIp, unsigned short remotePort, // (extern)
999) unsigned short initialWnd, struct TcpNotify *Notify)
1000) #define TcpOpenLocalPortMin 32768
1001) #define TcpOpenLocalPortRange 16384
1002) {
1003) static unsigned short nextLocalPort = TcpOpenLocalPortMin; // local port
1004) // to use for
1005) // next TCP
1006) // connection
1007) unsigned short localPort;
1008) unsigned char i;
1009)
1010) debug_tcp_printf("open ip=%u.%u.%u.%u port=%u",
1011) remoteIp[0], remoteIp[1], remoteIp[2], remoteIp[3],
1012) remotePort);
1013)
1014) // search an unused local port
1015) for (localPort = nextLocalPort;; localPort++) {
1016) for (i = 0; i < count(TcpConns); i++)
1017) if (TcpConns[i].State != TCP_CLOSED &&
1018) TcpConns[i].LocalPort == localPort)
1019) break;
1020) if (i >= count(TcpConns))
1021) break;
1022) }
1023) // save next local port to use
1024) nextLocalPort = localPort + 1;
1025) if (nextLocalPort >= TcpOpenLocalPortMin + TcpOpenLocalPortRange)
1026) nextLocalPort = TcpOpenLocalPortMin;
1027)
1028) // search empty connection slot
1029) for (i = 0; i < count(TcpConns); i++)
1030) if (TcpConns[i].State == TCP_CLOSED)
1031) break;
1032) // no free connection slot found
1033) if (i >= count(TcpConns))
1034) return 0xFF;
1035)
1036) // create new connection in this slot
1037) ip_cpy(TcpConns[i].RemoteIp, remoteIp);
1038) TcpConns[i].LocalPort = localPort;
1039) TcpConns[i].RemotePort = remotePort;
1040) TcpConns[i].RcvNxt = 0;
1041) TcpConns[i].Irs = 0;
1042) RandomGetData((unsigned char *)&TcpConns[i].Iss, sizeof(TcpConns[i].Iss)); // An
1043) // initial
1044) // send
1045) // sequence
1046) // number
1047) // (ISS)
1048) // is
1049) // selected.
1050) TcpSynSegment(&TcpConns[i], TcpConns[i].Iss, 0, TCP_SYN); // A SYN
1051) // segment of
1052) // the form
1053) // <SEQ=ISS><CTL=SYN>
1054) // is sent.
1055) TcpConns[i].SndUna = TcpConns[i].Iss; // Set SND.UNA to ISS,
1056) TcpConns[i].SndNxt = TcpConns[i].Iss + 1; // SND.NXT to ISS+1,
1057) TcpConns[i].State = TCP_SYN_SENT; // enter SYN-SENT state,
1058) TcpConns[i].SndWnd = 0; // not allowed to send data for now
1059) TcpConns[i].SndWl1 = 0; // window size was never updated
1060) TcpConns[i].SndWl2 = 0;
1061) TcpConns[i].Ticks = 0; // restart timers
1062) TcpConns[i].Timeout = 0;
1063) TcpConns[i].LifeTime = 0;
1064) TcpConns[i].RcvWnd = initialWnd;
1065) TcpConns[i].Notify = Notify;
1066)
1067) debug_tcp_printf("open no=%u", i);
1068)
1069) // return connection number
1070) return i;
1071) }
1072)
1073) // close a TCP connection
1074) // must not be called from a TCP notification function
1075) void TcpClose(unsigned char connNo) // (extern)
1076) {
1077) struct TcpConnection *pConn;
1078)
1079) debug_tcp_printf("close no=%u", connNo);
1080)
1081) // connection does not exist
1082) if (connNo >= count(TcpConns) || TcpConns[connNo].State == TCP_CLOSED)
1083) return;
1084)
1085) // get connection
1086) pConn = &TcpConns[connNo];
1087)
1088) // different actions in different states accroding to RFC793
1089) switch (pConn->State) {
1090)
1091) case TCP_LISTEN:
1092) case TCP_SYN_SENT:
1093) pConn->State = TCP_CLOSED; // Delete TCB, enter CLOSED state,
1094) break; // and return.
1095)
1096) case TCP_SYN_RCVD:
1097) case TCP_ESTAB:
1098) TcpEmptySegment(pConn, pConn->SndNxt, pConn->RcvNxt, TCP_FIN | TCP_ACK); // form
1099) // a
1100) // FIN
1101) // segment
1102) // and
1103) // send
1104) // it,
1105) pConn->SndNxt++;
1106) pConn->State = TCP_FIN_WAIT_1; // and enter FIN-WAIT-1 state;
1107) debug_tcp_printf("notify close no=%u", connNo);
1108) pConn->Notify->Close(connNo); // signal "connection closed" to user
1109) break;
1110)
1111) case TCP_CLOSE_WAIT:
1112) TcpEmptySegment(pConn, pConn->SndNxt, pConn->RcvNxt, TCP_FIN | TCP_ACK); // send
1113) // a
1114) // FIN
1115) // segment,
1116) pConn->SndNxt++;
1117) pConn->State = TCP_CLOSING; // enter CLOSING state.
1118) debug_tcp_printf("notify close no=%u", connNo);
1119) pConn->Notify->Close(connNo); // signal "connection closed" to user
1120) break;
1121)
1122) } // switch( pConn->State )
1123) }
1124)
1125) // request sending on a TCP connection
1126) // must not be called from a TCP notification function
1127) // this makes the send notification to be called if possible
1128) void TcpSend(unsigned char connNo) // (extern)
1129) {
1130) struct TcpConnection *pConn;
1131)
1132) debug_tcp_printf("send no=%u", connNo);
1133)
1134) // connection does not exist
1135) if (connNo >= count(TcpConns) || TcpConns[connNo].State == TCP_CLOSED)
1136) return;
1137)
1138) // get connection
1139) pConn = &TcpConns[connNo];
1140)
1141) // different behaviour in different states
1142) switch (pConn->State) {
1143)
1144) case TCP_ESTAB:
1145) case TCP_CLOSE_WAIT:
1146) // if nothing is sent and not yet ACKed
1147) if (pConn->SndUna == pConn->SndNxt)
1148) // send a data segment
1149) TcpSendDataSegment(connNo, pConn, 0);
1150) break;
1151)
1152) } // switch( TcpConns[i].State )
1153) }
1154)
1155) // dummy notification functions
1156) void TcpDummyConnect(unsigned char ConnNo)
1157) {
|