568aa092405f740c9907c934422243f44e47e4ec
Stefan Schuermans header fix

Stefan Schuermans authored 12 years ago

1) /* flaneth - flash and ethernet
2)    Copyright (C) 2007-2012 Stefan Schuermans <stefan@schuermans.info>
3)    Copyleft: GNU public license V2 - http://www.gnu.org/copyleft/gpl.html
4)    a BlinkenArea project - http://www.blinkenarea.org/ */
Stefan Schuermans 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) {
Stefan Schuermans make more warnings visible...

Stefan Schuermans authored 12 years ago

1158)   (void)ConnNo;
Stefan Schuermans initial commit after making...

Stefan Schuermans authored 12 years ago

1159) }
1160) 
1161) void TcpDummyClose(unsigned char ConnNo)
1162) {
Stefan Schuermans make more warnings visible...

Stefan Schuermans authored 12 years ago

1163)   (void)ConnNo;
Stefan Schuermans initial commit after making...

Stefan Schuermans authored 12 years ago

1164) }
1165) 
1166) unsigned short TcpDummySend(unsigned char ConnNo, unsigned long Pos,
1167)                             unsigned char *pBuffer, unsigned short MaxLen)
1168) {
1169)   return 0;
Stefan Schuermans make more warnings visible...

Stefan Schuermans authored 12 years ago

1170)   (void)ConnNo;
1171)   (void)Pos;
1172)   (void)pBuffer;
1173)   (void)MaxLen;
Stefan Schuermans initial commit after making...

Stefan Schuermans authored 12 years ago

1174) }
1175) 
1176) void TcpDummySent(unsigned char ConnNo, unsigned long Pos)
1177) {
Stefan Schuermans make more warnings visible...

Stefan Schuermans authored 12 years ago

1178)   (void)ConnNo;
1179)   (void)Pos;
Stefan Schuermans initial commit after making...

Stefan Schuermans authored 12 years ago

1180) }
1181) 
1182) unsigned short TcpDummyReceived(unsigned char ConnNo, unsigned long Pos,
1183)                                 unsigned char *pBuffer, unsigned short Len,
1184)                                 unsigned short curWnd)
1185) {
1186)   return max(curWnd, 128);
Stefan Schuermans make more warnings visible...

Stefan Schuermans authored 12 years ago

1187)   (void)ConnNo;
1188)   (void)Pos;
1189)   (void)pBuffer;
1190)   (void)Len;