/[H8]/trunk/docs/Microchip TCP_IP stack/TCPIP Stack/TCP.c
ViewVC logotype

Annotation of /trunk/docs/Microchip TCP_IP stack/TCPIP Stack/TCP.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 15 - (hide annotations) (download)
Thu Apr 19 09:01:15 2007 UTC (17 years, 2 months ago) by hedin
File MIME type: text/plain
File size: 65334 byte(s)
added the TCP/IP stack, source code.
1 hedin 15 /*********************************************************************
2     *
3     * Transmission Control Protocol (TCP) Communications Layer
4     * Module for Microchip TCP/IP Stack
5     * -Provides reliable, handshaked transport of application stream
6     * oriented data with flow control
7     * -Reference: RFC 793
8     *
9     *********************************************************************
10     * FileName: TCP.c
11     * Dependencies: string.h
12     * StackTsk.h
13     * Helpers.h
14     * IP.h
15     * MAC.h
16     * ARP.h
17     * Tick.h
18     * TCP.h
19     * Processor: PIC18, PIC24F, PIC24H, dsPIC30F, dsPIC33F
20     * Complier: Microchip C18 v3.02 or higher
21     * Microchip C30 v2.01 or higher
22     * Company: Microchip Technology, Inc.
23     *
24     * Software License Agreement
25     *
26     * Copyright © 2002-2007 Microchip Technology Inc. All rights
27     * reserved.
28     *
29     * Microchip licenses to you the right to use, modify, copy, and
30     * distribute:
31     * (i) the Software when embedded on a Microchip microcontroller or
32     * digital signal controller product (“Device”) which is
33     * integrated into Licensee’s product; or
34     * (ii) ONLY the Software driver source files ENC28J60.c and
35     * ENC28J60.h ported to a non-Microchip device used in
36     * conjunction with a Microchip ethernet controller for the
37     * sole purpose of interfacing with the ethernet controller.
38     *
39     * You should refer to the license agreement accompanying this
40     * Software for additional information regarding your rights and
41     * obligations.
42     *
43     * THE SOFTWARE AND DOCUMENTATION ARE PROVIDED “AS IS” WITHOUT
44     * WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT
45     * LIMITATION, ANY WARRANTY OF MERCHANTABILITY, FITNESS FOR A
46     * PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL
47     * MICROCHIP BE LIABLE FOR ANY INCIDENTAL, SPECIAL, INDIRECT OR
48     * CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF
49     * PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY OR SERVICES, ANY CLAIMS
50     * BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE
51     * THEREOF), ANY CLAIMS FOR INDEMNITY OR CONTRIBUTION, OR OTHER
52     * SIMILAR COSTS, WHETHER ASSERTED ON THE BASIS OF CONTRACT, TORT
53     * (INCLUDING NEGLIGENCE), BREACH OF WARRANTY, OR OTHERWISE.
54     *
55     *
56     * Author Date Comment
57     *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
58     * Nilesh Rajbharti 5/8/01 Original (Rev 1.0)
59     * Howard Schlunder 12/11/06 Changed almost everything to
60     * better meet RFC 793.
61     ********************************************************************/
62     #define __TCP_C
63    
64     #include "TCPIP Stack/TCPIP.h"
65    
66     #if defined(STACK_USE_TCP)
67    
68    
69     #define MAX_TCP_DATA_LEN (MAC_TX_BUFFER_SIZE - sizeof(TCP_HEADER) - sizeof(IP_HEADER) - sizeof(ETHER_HEADER))
70    
71     // TCP Timeout and retransmit numbers
72     #define TCP_START_TIMEOUT_VAL ((TICK)TICK_SECOND * (TICK)1)
73     #define TCP_TIME_WAIT_TIMEOUT_VAL ((TICK)TICK_SECOND * (TICK)0)
74     #define MAX_RETRY_COUNTS (5u)
75    
76     #define TCP_AUTO_TRANSMIT_TIMEOUT_VAL ((WORD)(TICK_SECOND/25))
77    
78     // TCP Flags defined in RFC
79     #define FIN (0x01)
80     #define SYN (0x02)
81     #define RST (0x04)
82     #define PSH (0x08)
83     #define ACK (0x10)
84     #define URG (0x20)
85    
86     // TCP Header
87     typedef struct _TCP_HEADER
88     {
89     WORD SourcePort;
90     WORD DestPort;
91     DWORD SeqNumber;
92     DWORD AckNumber;
93    
94     struct
95     {
96     unsigned char Reserved3 : 4;
97     unsigned char Val : 4;
98     } DataOffset;
99    
100     union
101     {
102     struct
103     {
104     unsigned char flagFIN : 1;
105     unsigned char flagSYN : 1;
106     unsigned char flagRST : 1;
107     unsigned char flagPSH : 1;
108     unsigned char flagACK : 1;
109     unsigned char flagURG : 1;
110     unsigned char Reserved2 : 2;
111     } bits;
112     BYTE byte;
113     } Flags;
114    
115     WORD Window;
116     WORD Checksum;
117     WORD UrgentPointer;
118     } TCP_HEADER;
119    
120     // TCP Options as defined by RFC
121     #define TCP_OPTIONS_END_OF_LIST (0x00u)
122     #define TCP_OPTIONS_NO_OP (0x01u)
123     #define TCP_OPTIONS_MAX_SEG_SIZE (0x02u)
124     typedef struct _TCP_OPTIONS
125     {
126     BYTE Kind;
127     BYTE Length;
128     WORD_VAL MaxSegSize;
129     } TCP_OPTIONS;
130    
131     #define SwapPseudoTCPHeader(h) (h.TCPLength = swaps(h.TCPLength))
132    
133     // IP pseudo header as defined by RFC 793
134     typedef struct _PSEUDO_HEADER
135     {
136     IP_ADDR SourceAddress;
137     IP_ADDR DestAddress;
138     BYTE Zero;
139     BYTE Protocol;
140     WORD TCPLength;
141     } PSEUDO_HEADER;
142    
143     #define LOCAL_PORT_START_NUMBER (1024u)
144     #define LOCAL_PORT_END_NUMBER (5000u)
145    
146    
147     // Local temp port numbers.
148     #ifdef STACK_CLIENT_MODE
149     static WORD NextPort __attribute__((persistent));
150     #endif
151    
152     #if defined(HI_TECH_C)
153     // The initializer forces this large array out of the bss section
154     // so we can link correctly.
155     TCB_STUB TCBStubs[MAX_TCP_SOCKETS] = {'\0'};
156     #else
157     // The TCB array is very large. With the C18 compiler, one must
158     // modify the linker script to make an array that spans more than
159     // one memory bank. To do this, make the necessary changes to your
160     // processor's linker script (.lkr). Here is an example showing
161     // gpr11 and 128 bytes of gpr12 being combined into one 384 byte
162     // block used exclusively by the TCB_MEM data section:
163     // ...
164     // //DATABANK NAME=gpr11 START=0xB00 END=0xBFF
165     // //DATABANK NAME=gpr12 START=0xC00 END=0xCFF
166     // DATABANK NAME=gpr11b START=0xB00 END=0xC7F PROTECTED
167     // DATABANK NAME=gpr12 START=0xC80 END=0xCFF
168     // ...
169     // SECTION NAME=TCP_TCB_RAM RAM=gpr11b
170     // ...
171     #pragma udata TCB_uRAM
172     TCB_STUB TCBStubs[MAX_TCP_SOCKETS];
173     #pragma udata // Return to any other RAM section
174     #endif
175    
176     static TCB MyTCB;
177     //static TCP_SOCKET hCurrentTCB = 0;
178    
179    
180     static void HandleTCPSeg(TCP_SOCKET hTCP, TCP_HEADER *h, WORD len);
181     static void SendTCP(TCP_SOCKET hTCP, BYTE flags);
182     static TCP_SOCKET FindMatchingSocket(TCP_HEADER *h, NODE_INFO *remote);
183     static void SwapTCPHeader(TCP_HEADER* header);
184     static void CloseSocket(TCP_SOCKET hTCP);
185     static void LoadTCB(TCP_SOCKET hTCP);
186     static void SaveTCB(TCP_SOCKET hTCP);
187     static BYTE ProcessRXBytes(TCB_STUB *ps, TCP_HEADER *h, WORD len);
188    
189    
190    
191     static void LoadTCB(TCP_SOCKET hTCP)
192     {
193     WORD PtrSave;
194     // if(hCurrentTCB == hTCP)
195     // return;
196    
197     // Load up the new TCB
198     // hCurrentTCB = hTCP;
199     PtrSave = MACSetReadPtr(TCBStubs[hTCP].bufferTxStart - sizeof(MyTCB));
200     MACGetArray((BYTE*)&MyTCB, sizeof(MyTCB));
201     MACSetReadPtr(PtrSave);
202     }
203    
204     static void SaveTCB(TCP_SOCKET hTCP)
205     {
206     WORD PtrSave;
207    
208     // hCurrentTCB = hTCP;
209    
210     // Save the current TCB
211     PtrSave = MACSetWritePtr(TCBStubs[hTCP].bufferTxStart - sizeof(MyTCB));
212     MACPutArray((BYTE*)&MyTCB, sizeof(MyTCB));
213     MACSetWritePtr(PtrSave);
214     }
215    
216    
217     /*********************************************************************
218     * Function: void TCPInit(void)
219     *
220     * PreCondition: None
221     *
222     * Input: None
223     *
224     * Output: TCP is initialized.
225     *
226     * Side Effects: None
227     *
228     * Overview: Initialize all socket states
229     *
230     * Note: This function is called only once during lifetime
231     * of the application.
232     ********************************************************************/
233     void TCPInit(void)
234     {
235     TCP_SOCKET hTCP;
236     TCB_STUB *ps;
237    
238     // Initialize all sockets.
239     for(hTCP = 0; hTCP < MAX_TCP_SOCKETS; hTCP++)
240     {
241     ps = &TCBStubs[hTCP];
242    
243     ps->smState = TCP_CLOSED;
244     ps->bufferTxStart = BASE_TCB_ADDR + sizeof(TCB) + hTCP*(sizeof(TCB) + (TCP_TX_FIFO_SIZE+1) + (TCP_RX_FIFO_SIZE+1));
245     ps->bufferRxStart = ps->bufferTxStart + TCP_TX_FIFO_SIZE+1;
246     ps->bufferEnd = ps->bufferRxStart + TCP_RX_FIFO_SIZE;
247     ps->Flags.bServer = FALSE;
248     ps->Flags.bTimerEnabled = FALSE;
249     ps->Flags.bTimer2Enabled = FALSE;
250     ps->Flags.bDelayedACKTimerEnabled = FALSE;
251     ps->Flags.bOneSegmentReceived = FALSE;
252     ps->Flags.bHalfFullFlush = FALSE;
253     ps->Flags.bTXASAP = FALSE;
254     }
255    
256     // Initialize random number generator
257     srand((WORD)TickGet());
258     }
259    
260    
261    
262     /*********************************************************************
263     * Function: TCP_SOCKET TCPListen(WORD port)
264     *
265     * PreCondition: TCPInit() is already called.
266     *
267     * Input: port - A TCP port to be opened.
268     *
269     * Output: Given port is opened and returned on success
270     * INVALID_SOCKET if no more sockets left.
271     *
272     * Side Effects: None
273     *
274     * Overview: None
275     *
276     * Note: None
277     ********************************************************************/
278     TCP_SOCKET TCPListen(WORD port)
279     {
280     TCP_SOCKET hTCP;
281     TCB_STUB *ps;
282    
283     for(hTCP = 0; hTCP < MAX_TCP_SOCKETS; hTCP++)
284     {
285     ps = &TCBStubs[hTCP];
286    
287     if(ps->smState == TCP_CLOSED)
288     {
289     ps->Flags.bServer = TRUE;
290     ps->smState = TCP_LISTEN;
291     ps->remoteHash.Val = port;
292     ps->txTail = ps->bufferTxStart;
293     ps->txHead = ps->bufferTxStart;
294     ps->rxTail = ps->bufferRxStart;
295     ps->rxHead = ps->bufferRxStart;
296    
297     MyTCB.sHoleSize = -1;
298     MyTCB.localPort.Val = port;
299     MyTCB.txUnackedTail = ps->bufferTxStart;
300     ((DWORD_VAL*)(&MyTCB.MySEQ))->w[0] = rand();
301     ((DWORD_VAL*)(&MyTCB.MySEQ))->w[1] = rand();
302     SaveTCB(hTCP);
303    
304     return hTCP;
305     }
306     }
307    
308     return INVALID_SOCKET;
309     }
310    
311    
312     /*********************************************************************
313     * FunctionL BOOL TCPGetRemoteInfo(TCP_SOCKET hTCP, SOCKET_INFO *RemoteInfo)
314     *
315     * PreCondition: TCPInit() is already called.
316     *
317     * Input: hTCP - Handle of socket to read
318     *
319     * Output: A new socket is created, connection request is
320     * sent and socket handle is returned.
321     *
322     * Side Effects: None
323     *
324     * Overview: None
325     *
326     * Note: None
327     *
328     ********************************************************************/
329     SOCKET_INFO* TCPGetRemoteInfo(TCP_SOCKET hTCP)
330     {
331     static SOCKET_INFO RemoteInfo;
332    
333     LoadTCB(hTCP);
334     memcpy((void*)&RemoteInfo.remote, (void*)&MyTCB.remote, sizeof(NODE_INFO));
335     RemoteInfo.remotePort.Val = MyTCB.remotePort.Val;
336    
337     return &RemoteInfo;
338     }
339    
340    
341     /*********************************************************************
342     * Function: TCP_SOCKET TCPConnect(NODE_INFO* remote,
343     * WORD remotePort)
344     *
345     * PreCondition: TCPInit() is already called.
346     *
347     * Input: remote - Remote node address info
348     * remotePort - remote port to be connected.
349     *
350     * Output: A new socket is created, connection request is
351     * sent and socket handle is returned.
352     *
353     * Side Effects: None
354     *
355     * Overview: None
356     *
357     * Note: By default this function is not included in
358     * source. You must define STACK_CLIENT_MODE to
359     * be able to use this function.
360     ********************************************************************/
361     #ifdef STACK_CLIENT_MODE
362     TCP_SOCKET TCPConnect(NODE_INFO *remote, WORD remotePort)
363     {
364     TCP_SOCKET hTCP;
365     TCB_STUB *ps;
366    
367     // Find an available socket
368     for(hTCP = 0; hTCP < MAX_TCP_SOCKETS; hTCP++)
369     {
370     ps = &TCBStubs[hTCP];
371    
372     if(ps->smState != TCP_CLOSED)
373     continue;
374    
375     // Zero out the TCB
376     memset((BYTE*)&MyTCB, 0x00, sizeof(MyTCB));
377    
378     // Each new socket that is opened by this node, gets the
379     // next sequential port number.
380     if(NextPort < LOCAL_PORT_START_NUMBER || NextPort > LOCAL_PORT_END_NUMBER)
381     NextPort = LOCAL_PORT_START_NUMBER;
382    
383     // Set the non-zero TCB fields
384     MyTCB.sHoleSize = -1;
385     MyTCB.localPort.Val = NextPort++;
386     MyTCB.remotePort.Val = remotePort;
387     memcpy((void*)&MyTCB.remote, (void*)remote, sizeof(NODE_INFO));
388     ((DWORD_VAL*)(&MyTCB.MySEQ))->w[0] = rand();
389     ((DWORD_VAL*)(&MyTCB.MySEQ))->w[1] = rand();
390     MyTCB.retryCount = 0;
391     MyTCB.retryInterval = TCP_START_TIMEOUT_VAL;
392    
393     // Zero out the buffer contents
394     MyTCB.txUnackedTail = ps->bufferTxStart;
395     ps->txHead = ps->bufferTxStart;
396     ps->txTail = ps->bufferTxStart;
397     ps->rxHead = ps->bufferRxStart;
398     ps->rxTail = ps->bufferRxStart;
399    
400     // Update the TCB Stub
401     ps->remoteHash.Val = (remote->IPAddr.w[1]+remote->IPAddr.w[0] + remotePort) ^ MyTCB.localPort.Val;
402     ps->smState = TCP_SYN_SENT;
403     ps->eventTime = TickGet() + TCP_START_TIMEOUT_VAL;
404     ps->Flags.bTimerEnabled = TRUE;
405    
406     // Save the TCB
407     SaveTCB(hTCP);
408    
409     // Send TCP SYNchronize (connect) request
410     SendTCP(hTCP, SYN);
411    
412     return hTCP;
413     }
414    
415     // If there is no socket available, return error.
416     return INVALID_SOCKET;
417     }
418     #endif
419    
420    
421    
422     /*********************************************************************
423     * Function: BOOL TCPIsConnected(TCP_SOCKET hTCP)
424     *
425     * PreCondition: TCPInit() is already called.
426     *
427     * Input: hTCP - Socket to be checked for connection.
428     *
429     * Output: TRUE if given socket is connected
430     * FALSE if given socket is not connected.
431     *
432     * Side Effects: None
433     *
434     * Overview: None
435     *
436     * Note: A socket is said to be connected only if it is in
437     * the TCP_ESTABLISHED state
438     ********************************************************************/
439     BOOL TCPIsConnected(TCP_SOCKET hTCP)
440     {
441     return TCBStubs[hTCP].smState == TCP_ESTABLISHED;
442     }
443    
444    
445    
446     /*********************************************************************
447     * Function: void TCPDisconnect(TCP_SOCKET hTCP)
448     *
449     * PreCondition: TCPInit() is already called
450     *
451     * Input: hTCP - Socket to be disconnected.
452     *
453     * Output: A disconnect request is sent for given socket.
454     * This function does nothing if the socket isn't
455     * currently connected.
456     *
457     * Side Effects: None
458     *
459     * Overview: None
460     *
461     * Note: None
462     ********************************************************************/
463     void TCPDisconnect(TCP_SOCKET hTCP)
464     {
465     TCB_STUB *ps;
466    
467     ps = &TCBStubs[hTCP];
468     LoadTCB(hTCP);
469    
470     switch(ps->smState)
471     {
472     //case TCP_CLOSED:
473     //case TCP_LISTEN:
474     //case TCP_LAST_ACK:
475     //case TCP_FIN_WAIT_1:
476     //case TCP_FIN_WAIT_2:
477     //case TCP_CLOSING:
478     //case TCP_TIME_WAIT:
479     // return;
480    
481     case TCP_SYN_SENT:
482     CloseSocket(hTCP);
483     break;
484    
485     case TCP_SYN_RECEIVED:
486     case TCP_ESTABLISHED:
487     MyTCB.MySEQ++;
488     SendTCP(hTCP, FIN | ACK);
489     ps->smState = TCP_FIN_WAIT_1;
490     // Clear timeout info
491     MyTCB.retryCount = 0;
492     MyTCB.retryInterval = TCP_START_TIMEOUT_VAL;
493     ps->eventTime = TickGet() + TCP_START_TIMEOUT_VAL;
494     ps->Flags.bTimerEnabled = TRUE;
495     break;
496    
497     case TCP_CLOSE_WAIT:
498     MyTCB.MySEQ++;
499     SendTCP(hTCP, FIN | ACK);
500     ps->smState = TCP_LAST_ACK;
501     // Clear timeout info
502     MyTCB.retryCount = 0;
503     MyTCB.retryInterval = TCP_START_TIMEOUT_VAL;
504     ps->eventTime = TickGet() + TCP_START_TIMEOUT_VAL;
505     ps->Flags.bTimerEnabled = TRUE;
506     break;
507     }
508    
509     SaveTCB(hTCP);
510     }
511    
512     /*********************************************************************
513     * Function: void TCPFlush(TCP_SOCKET hTCP)
514     *
515     * PreCondition: TCPInit() is already called.
516     *
517     * Input: s - Socket whose data is to be transmitted.
518     *
519     * Output: None
520     *
521     * Side Effects: None
522     *
523     * Overview: None
524     *
525     * Note: None
526     ********************************************************************/
527     void TCPFlush(TCP_SOCKET hTCP)
528     {
529     TCB_STUB *ps;
530    
531     ps = &TCBStubs[hTCP];
532     LoadTCB(hTCP);
533    
534     if(ps->txHead != MyTCB.txUnackedTail)
535     {
536     SendTCP(hTCP, PSH | ACK);
537    
538     // Clear timeout info
539     MyTCB.retryCount = 0;
540     MyTCB.retryInterval = TCP_START_TIMEOUT_VAL;
541     ps->eventTime = TickGet() + TCP_START_TIMEOUT_VAL;
542     ps->Flags.bTimerEnabled = TRUE;
543     }
544     SaveTCB(hTCP);
545     }
546    
547    
548    
549     /*********************************************************************
550     * Function: WORD TCPIsPutReady(TCP_SOCKET hTCP)
551     *
552     * PreCondition: TCPInit() is already called.
553     *
554     * Input: hTCP: handle of socket to test
555     *
556     * Output: Number of bytes that can be immediately placed
557     * in the transmit buffer.
558     *
559     * Side Effects: None
560     *
561     * Overview: None
562     *
563     * Note: None
564     ********************************************************************/
565     WORD TCPIsPutReady(TCP_SOCKET hTCP)
566     {
567     TCB_STUB *ps;
568    
569     ps = &TCBStubs[hTCP];
570    
571     // Unconnected sockets shouldn't be transmitting anything.
572     if(!((ps->smState == TCP_ESTABLISHED) || (ps->smState == TCP_CLOSE_WAIT)))
573     return 0;
574    
575     // Calculate the free space in this socket's TX FIFO
576     if(ps->txHead >= ps->txTail)
577     return (ps->bufferRxStart - ps->bufferTxStart - 1) - (ps->txHead - ps->txTail);
578     else
579     return ps->txTail - ps->txHead - 1;
580     }
581    
582    
583     /*********************************************************************
584     * Function: BOOL TCPPut(TCP_SOCKET hTCP, BYTE byte)
585     *
586     * PreCondition: TCPIsPutReady(s) != 0
587     *
588     * Input: hTCP: socket handle to use
589     * byte: a data byte to send
590     *
591     * Output: TRUE if given byte was put in transmit buffer
592     * FALSE if transmit buffer is full.
593     *
594     * Side Effects: None
595     *
596     * Overview: None
597     *
598     * Note: None
599     ********************************************************************/
600     BOOL TCPPut(TCP_SOCKET hTCP, BYTE byte)
601     {
602     TCB_STUB *ps;
603     WORD wFreeTXSpace;
604    
605     ps = &TCBStubs[hTCP];
606    
607     wFreeTXSpace = TCPIsPutReady(hTCP);
608     if(wFreeTXSpace == 0u)
609     return FALSE;
610     else if(wFreeTXSpace == 1u) // About to run out of space, lets transmit so the remote node might send an ACK back faster
611     TCPFlush(hTCP);
612    
613     // Send all current bytes if we are crossing half full
614     // This is required to improve performance with the delayed
615     // acknowledgement algorithm
616     if((!ps->Flags.bHalfFullFlush) && (wFreeTXSpace <= ((ps->bufferRxStart-ps->bufferTxStart)>>1)))
617     {
618     TCPFlush(hTCP);
619     ps->Flags.bHalfFullFlush = TRUE;
620     }
621    
622     MACSetWritePtr(ps->txHead);
623     MACPut(byte);
624     if(++ps->txHead >= ps->bufferRxStart)
625     ps->txHead = ps->bufferTxStart;
626    
627     // Send the last byte as a separate packet (likely will make the remote node send back ACK faster)
628     if(wFreeTXSpace == 1u)
629     TCPFlush(hTCP);
630    
631     // If not already enabled, start a timer so this data will
632     // eventually get sent even if the application doens't call
633     // TCPFlush()
634     if(!ps->Flags.bTimer2Enabled)
635     {
636     ps->Flags.bTimer2Enabled = TRUE;
637     ps->eventTime2 = (WORD)TickGet() + TCP_AUTO_TRANSMIT_TIMEOUT_VAL;
638     }
639    
640     return TRUE;
641     }
642    
643     /*********************************************************************
644     * Function: WORD TCPPutArray(TCP_SOCKET hTCP, BYTE *data, WORD len)
645     *
646     * PreCondition: None
647     *
648     * Input: hTCP - Socket handle to use
649     * data - Pointer to data to put
650     * len - Count of bytes to put
651     *
652     * Output: Count of bytes actually placed in the TX buffer
653     *
654     * Side Effects: None
655     *
656     * Overview: None
657     *
658     * Note: None
659     ********************************************************************/
660     WORD TCPPutArray(TCP_SOCKET hTCP, BYTE *data, WORD len)
661     {
662     WORD wActualLen;
663     WORD wFreeTXSpace;
664     WORD wRightLen = 0;
665     TCB_STUB *ps;
666    
667     ps = &TCBStubs[hTCP];
668    
669     wFreeTXSpace = TCPIsPutReady(hTCP);
670     if(wFreeTXSpace == 0u)
671     {
672     TCPFlush(hTCP);
673     return 0;
674     }
675    
676     wActualLen = wFreeTXSpace;
677     if(wFreeTXSpace > len)
678     wActualLen = len;
679    
680     // Send all current bytes if we are crossing half full
681     // This is required to improve performance with the delayed
682     // acknowledgement algorithm
683     if((!ps->Flags.bHalfFullFlush) && (wFreeTXSpace <= ((ps->bufferRxStart-ps->bufferTxStart)>>1)))
684     {
685     TCPFlush(hTCP);
686     ps->Flags.bHalfFullFlush = TRUE;
687     }
688    
689     // See if we need a two part put
690     if(ps->txHead + wActualLen >= ps->bufferRxStart)
691     {
692     wRightLen = ps->bufferRxStart-ps->txHead;
693     MACSetWritePtr(ps->txHead);
694     MACPutArray(data, wRightLen);
695     data += wRightLen;
696     wActualLen -= wRightLen;
697     ps->txHead = ps->bufferTxStart;
698     }
699    
700     MACSetWritePtr(ps->txHead);
701     MACPutArray(data, wActualLen);
702     ps->txHead += wActualLen;
703    
704     // Send these bytes right now if we are out of TX buffer space
705     if(wFreeTXSpace <= len)
706     TCPFlush(hTCP);
707    
708     // If not already enabled, start a timer so this data will
709     // eventually get sent even if the application doens't call
710     // TCPFlush()
711     if(!ps->Flags.bTimer2Enabled)
712     {
713     ps->Flags.bTimer2Enabled = TRUE;
714     ps->eventTime2 = (WORD)TickGet() + TCP_AUTO_TRANSMIT_TIMEOUT_VAL;
715     }
716    
717     return wActualLen + wRightLen;
718     }
719    
720     WORD TCPPutROMArray(TCP_SOCKET hTCP, ROM BYTE *data, WORD len)
721     {
722     WORD wActualLen;
723     WORD wFreeTXSpace;
724     WORD wRightLen = 0;
725     TCB_STUB *ps;
726    
727     ps = &TCBStubs[hTCP];
728    
729     wFreeTXSpace = TCPIsPutReady(hTCP);
730     if(wFreeTXSpace == 0u)
731     {
732     TCPFlush(hTCP);
733     return 0;
734     }
735    
736     // Send all current bytes if we are crossing half full
737     // This is required to improve performance with the delayed
738     // acknowledgement algorithm
739     if((!ps->Flags.bHalfFullFlush) && (wFreeTXSpace <= ((ps->bufferRxStart-ps->bufferTxStart)>>1)))
740     {
741     TCPFlush(hTCP);
742     ps->Flags.bHalfFullFlush = TRUE;
743     }
744    
745     wActualLen = wFreeTXSpace;
746     if(wFreeTXSpace > len)
747     wActualLen = len;
748    
749     // See if we need a two part put
750     if(ps->txHead + wActualLen >= ps->bufferRxStart)
751     {
752     wRightLen = ps->bufferRxStart-ps->txHead;
753     MACSetWritePtr(ps->txHead);
754     MACPutROMArray(data, wRightLen);
755     data += wRightLen;
756     wActualLen -= wRightLen;
757     ps->txHead = ps->bufferTxStart;
758     }
759    
760     MACSetWritePtr(ps->txHead);
761     MACPutROMArray(data, wActualLen);
762     ps->txHead += wActualLen;
763    
764     // Send these bytes right now if we are out of TX buffer space
765     if(wFreeTXSpace <= len)
766     TCPFlush(hTCP);
767    
768     // If not already enabled, start a timer so this data will
769     // eventually get sent even if the application doens't call
770     // TCPFlush()
771     if(!ps->Flags.bTimer2Enabled)
772     {
773     ps->Flags.bTimer2Enabled = TRUE;
774     ps->eventTime2 = (WORD)TickGet() + TCP_AUTO_TRANSMIT_TIMEOUT_VAL;
775     }
776    
777     return wActualLen + wRightLen;
778     }
779    
780    
781     /*********************************************************************
782     * Function: WORD TCPPutString(TCP_SOCKET hTCP, BYTE *data)
783     *
784     * PreCondition: None
785     *
786     * Input: hTCP - Socket handle to use
787     * data - Pointer to null terminated string to put
788     *
789     * Output: BYTE* - *data pointer incremented by the number of
790     * bytes actually placed in the TX FIFO
791     *
792     * Side Effects: None
793     *
794     * Overview: None
795     *
796     * Note: None
797     ********************************************************************/
798     BYTE* TCPPutString(TCP_SOCKET hTCP, BYTE *data)
799     {
800     return data + TCPPutArray(hTCP, data, strlen((char*)data));
801     }
802    
803     ROM BYTE* TCPPutROMString(TCP_SOCKET hTCP, ROM BYTE *data)
804     {
805     return data + TCPPutROMArray(hTCP, data, strlenpgm((ROM char*)data));
806     }
807    
808    
809     /*********************************************************************
810     * Function: void TCPDiscard(TCP_SOCKET hTCP)
811     *
812     * PreCondition: TCPInit() is already called.
813     *
814     * Input: hTCP - socket handle
815     *
816     * Output: None
817     *
818     * Side Effects: None
819     *
820     * Overview: Removes all pending data from the socket's RX
821     * FIFO.
822     *
823     * Note: None
824     ********************************************************************/
825     void TCPDiscard(TCP_SOCKET hTCP)
826     {
827     TCB_STUB *ps;
828    
829     if(TCPIsGetReady(hTCP))
830     {
831     ps = &TCBStubs[hTCP];
832     LoadTCB(hTCP);
833    
834     // Delete all data in the RX buffer
835     ps->rxTail = ps->rxHead;
836    
837     // Send a Window update message to the remote node
838     SendTCP(hTCP, ACK);
839    
840     SaveTCB(hTCP);
841     }
842     }
843    
844    
845     /*********************************************************************
846     * Function: WORD TCPIsGetReady(TCP_SOCKET hTCP)
847     *
848     * PreCondition: TCPInit() is already called.
849     *
850     * Input: hTCP - socket to test
851     *
852     * Output: Number of bytes that are available in socket 'hTCP'
853     * for immediate retrieval
854     *
855     * Side Effects: None
856     *
857     * Overview: None
858     *
859     * Note: None
860     ********************************************************************/
861     WORD TCPIsGetReady(TCP_SOCKET hTCP)
862     {
863     TCB_STUB *ps;
864    
865     ps = &TCBStubs[hTCP];
866    
867     if(ps->rxHead >= ps->rxTail)
868     return ps->rxHead - ps->rxTail;
869     else
870     return (ps->bufferEnd - ps->rxTail + 1) + (ps->rxHead - ps->bufferRxStart);
871     }
872    
873    
874     /*********************************************************************
875     * Function: BOOL TCPGet(TCP_SOCKET hTCP, BYTE *byte)
876     *
877     * PreCondition: TCPInit() is already called
878     *
879     * Input: hTCP - socket
880     * byte - Pointer to a byte.
881     *
882     * Output: TRUE if a byte was read.
883     * FALSE if byte was not read.
884     *
885     * Side Effects: None
886     *
887     * Overview: None
888     *
889     * Note: None
890     ********************************************************************/
891     BOOL TCPGet(TCP_SOCKET hTCP, BYTE *byte)
892     {
893     TCB_STUB *ps;
894     WORD GetReadyCount;
895    
896     GetReadyCount = TCPIsGetReady(hTCP);
897     if(GetReadyCount == 0u)
898     return FALSE;
899    
900     ps = &TCBStubs[hTCP];
901     MACSetReadPtr(ps->rxTail);
902     *byte = MACGet();
903     if(++ps->rxTail > ps->bufferEnd)
904     ps->rxTail = ps->bufferRxStart;
905    
906     // Send a window update if we've run out of data
907     if(GetReadyCount == 1u)
908     {
909     LoadTCB(hTCP);
910     SendTCP(hTCP, ACK);
911     SaveTCB(hTCP);
912     }
913     // If not already enabled, start a timer so a window
914     // update will get sent to the remote node at some point
915     else if(!ps->Flags.bTimer2Enabled)
916     {
917     ps->Flags.bTimer2Enabled = TRUE;
918     ps->eventTime2 = (WORD)TickGet() + TCP_AUTO_TRANSMIT_TIMEOUT_VAL;
919     }
920    
921    
922     return TRUE;
923     }
924    
925    
926     /*********************************************************************
927     * Function: WORD TCPGetArray(TCP_SOCKET hTCP, BYTE *buffer,
928     * WORD len)
929     *
930     * PreCondition: TCPInit() is already called
931     *
932     * Input: hTCP - socket handle
933     * buffer - Buffer to hold received data.
934     * len - Buffer length
935     *
936     * Output: Number of bytes loaded into buffer.
937     *
938     * Side Effects: None
939     *
940     * Overview: None
941     *
942     * Note: None
943     ********************************************************************/
944     WORD TCPGetArray(TCP_SOCKET hTCP, BYTE *buffer, WORD len)
945     {
946     WORD ActualLen;
947     WORD RightLen = 0;
948     TCB_STUB *ps;
949    
950     ps = &TCBStubs[hTCP];
951    
952     ActualLen = TCPIsGetReady(hTCP);
953     if(len > ActualLen)
954     len = ActualLen;
955    
956     // See if we need a two part get
957     if(ps->rxTail + len > ps->bufferEnd)
958     {
959     RightLen = ps->bufferEnd - ps->rxTail + 1;
960     MACSetReadPtr(ps->rxTail);
961     MACGetArray(buffer, RightLen);
962     if(buffer)
963     buffer += RightLen;
964     len -= RightLen;
965     ps->rxTail = ps->bufferRxStart;
966     }
967    
968     MACSetReadPtr(ps->rxTail);
969     MACGetArray(buffer, len);
970     ps->rxTail += len;
971    
972     // Send a window update if we've run low on data
973     if(ActualLen - len <= len)
974     {
975     LoadTCB(hTCP);
976     SendTCP(hTCP, ACK);
977     SaveTCB(hTCP);
978     }
979     else if(!ps->Flags.bTimer2Enabled)
980     // If not already enabled, start a timer so a window
981     // update will get sent to the remote node at some point
982     {
983     ps->Flags.bTimer2Enabled = TRUE;
984     ps->eventTime2 = (WORD)TickGet() + TCP_AUTO_TRANSMIT_TIMEOUT_VAL;
985     }
986    
987     return len + RightLen;
988     }
989    
990    
991     /*********************************************************************
992     * Function: WORD TCPGetRxFIFOFree(TCP_SOCKET hTCP)
993     *
994     * PreCondition: TCPInit() is already called
995     *
996     * Input: hTCP - TCP socket handle
997     *
998     * Output: Number of bytes that can still fit in the RX FIFO.
999     * 0 is returned if the FIFO is completely full.
1000     *
1001     * Side Effects: None
1002     *
1003     * Overview: None
1004     *
1005     * Note: None
1006     ********************************************************************/
1007     WORD TCPGetRxFIFOFree(TCP_SOCKET hTCP)
1008     {
1009     WORD wDataLen;
1010     WORD wFIFOSize;
1011    
1012     // Calculate total usable FIFO size
1013     wFIFOSize = TCBStubs[hTCP].bufferEnd - TCBStubs[hTCP].bufferRxStart;
1014    
1015     // Find out how many data bytes are actually in the RX FIFO
1016     wDataLen = TCPIsGetReady(hTCP);
1017    
1018     return wFIFOSize - wDataLen;
1019     }
1020    
1021     /*********************************************************************
1022     * Function: WORD TCPFindArray(TCP_SOCKET hTCP, BYTE *cFindArray, WORD wLen, WORD wStart, BOOL bTextCompare)
1023     *
1024     * PreCondition: TCPInit() is already called
1025     *
1026     * Input: hTCP - TCP socket handle
1027     * cFindArray - Pointer to an array of bytes to look for
1028     * wLen - Length of cFindArray
1029     * wStart - Position within the RX FIFO to begin searching. 0 is the beginning of the FIFO.
1030     * bTextCompare- Search using a case-insensitive algorithm if TRUE, otherwise, do a binary 1 to 1 search
1031     *
1032     * Output: 0xFFFF: Array not found
1033     * 0 to 65534: Location the array was found
1034     *
1035     * Side Effects: None
1036     *
1037     * Overview: None
1038     *
1039     * Note: As an example, if the RX FIFO contains:
1040     * "PIC MCUs are good."
1041     * and cFindArray -> "MCU"
1042     * and wLen -> 3
1043     * the value returned by the search function would be 4
1044     ********************************************************************/
1045     WORD TCPFindArray(TCP_SOCKET hTCP, BYTE *cFindArray, WORD wLen, WORD wStart, BOOL bTextCompare)
1046     {
1047     WORD wDataLen;
1048     WORD wBytesUntilWrap;
1049     WORD wLocation;
1050     WORD wLenStart;
1051     BYTE *cFindArrayStart;
1052     BYTE i, j, k;
1053     BYTE buffer[8];
1054     TCB_STUB *ps;
1055    
1056     if(wLen == 0u)
1057     return 0u;
1058    
1059     ps = &TCBStubs[hTCP];
1060    
1061     // Find out how many bytes are in the RX FIFO and return
1062     // immediately if we won't possibly find a match
1063     wDataLen = TCPIsGetReady(hTCP);
1064     if(wDataLen < wLen + wStart)
1065     return 0xFFFFu;
1066    
1067     wLocation = ps->rxTail + wStart;
1068     if(wLocation > ps->bufferEnd)
1069     wLocation -= ps->bufferEnd - ps->bufferRxStart + 1;
1070     MACSetReadPtr(wLocation);
1071     wBytesUntilWrap = ps->bufferEnd - wLocation + 1;
1072     wLocation = wStart;
1073     wLenStart = wLen;
1074     cFindArrayStart = cFindArray;
1075     j = *cFindArray++;
1076     if(bTextCompare)
1077     {
1078     if(j >= 'a' && j <= 'z')
1079     j += 'A'-'a';
1080     }
1081    
1082     // Search for the array
1083     while(1)
1084     {
1085     // Figure out how big of a chunk to read
1086     k = sizeof(buffer);
1087     if(k > wBytesUntilWrap)
1088     k = wBytesUntilWrap;
1089     if((WORD)k > wLen)
1090     k = wLen;
1091    
1092     // Read a chunk of data into the buffer
1093     MACGetArray(buffer, (WORD)k);
1094     wBytesUntilWrap -= k;
1095    
1096     if(wBytesUntilWrap == 0)
1097     {
1098     MACSetReadPtr(ps->bufferRxStart);
1099     wBytesUntilWrap = 0xFFFFu;
1100     }
1101    
1102     // Convert everything to uppercase
1103     if(bTextCompare)
1104     {
1105     for(i = 0; i < k; i++)
1106     {
1107     if(buffer[i] >= 'a' && buffer[i] <= 'z')
1108     buffer[i] += 'A'-'a';
1109    
1110     if(j == buffer[i])
1111     {
1112     if(--wLen == 0)
1113     return wLocation-wLenStart + i + 1;
1114     j = *cFindArray++;
1115     if(j >= 'a' && j <= 'z')
1116     j += 'A'-'a';
1117     }
1118     else
1119     {
1120     wLen = wLenStart;
1121     cFindArray = cFindArrayStart;
1122     j = *cFindArray++;
1123     if(j >= 'a' && j <= 'z')
1124     j += 'A'-'a';
1125     }
1126     }
1127     }
1128     else // Compare as is
1129     {
1130     for(i = 0; i < k; i++)
1131     {
1132     if(j == buffer[i])
1133     {
1134     if(--wLen == 0)
1135     return wLocation-wLenStart + i + 1;
1136     j = *cFindArray++;
1137     }
1138     else
1139     {
1140     wLen = wLenStart;
1141     cFindArray = cFindArrayStart;
1142     j = *cFindArray++;
1143     }
1144     }
1145     }
1146    
1147     // Check to see if it is impossible to find a match
1148     wDataLen -= k;
1149     if(wDataLen < wLen)
1150     return 0xFFFFu;
1151    
1152     wLocation += k;
1153     }
1154     }
1155    
1156     WORD TCPFindROMArray(TCP_SOCKET hTCP, ROM BYTE *cFindArray, WORD wLen, WORD wStart, BOOL bTextCompare)
1157     {
1158     WORD wDataLen;
1159     WORD wBytesUntilWrap;
1160     WORD wLocation;
1161     WORD wLenStart;
1162     ROM BYTE *cFindArrayStart;
1163     BYTE i, j, k;
1164     BYTE buffer[8];
1165     TCB_STUB *ps;
1166    
1167     if(wLen == 0u)
1168     return 0u;
1169    
1170     ps = &TCBStubs[hTCP];
1171    
1172     // Find out how many bytes are in the RX FIFO and return
1173     // immediately if we won't possibly find a match
1174     wDataLen = TCPIsGetReady(hTCP);
1175     if(wDataLen < wLen + wStart)
1176     return 0xFFFFu;
1177    
1178     wLocation = ps->rxTail + wStart;
1179     if(wLocation > ps->bufferEnd)
1180     wLocation -= ps->bufferEnd - ps->bufferRxStart + 1;
1181     MACSetReadPtr(wLocation);
1182     wBytesUntilWrap = ps->bufferEnd - wLocation + 1;
1183     wLocation = wStart;
1184     wLenStart = wLen;
1185     cFindArrayStart = cFindArray;
1186     j = *cFindArray++;
1187     if(bTextCompare)
1188     {
1189     if(j >= 'a' && j <= 'z')
1190     j += 'A'-'a';
1191     }
1192    
1193     // Search for the array
1194     while(1)
1195     {
1196     // Figure out how big of a chunk to read
1197     k = sizeof(buffer);
1198     if(k > wBytesUntilWrap)
1199     k = wBytesUntilWrap;
1200     if((WORD)k > wLen)
1201     k = wLen;
1202    
1203     // Read a chunk of data into the buffer
1204     MACGetArray(buffer, (WORD)k);
1205     wBytesUntilWrap -= k;
1206    
1207     if(wBytesUntilWrap == 0)
1208     {
1209     MACSetReadPtr(ps->bufferRxStart);
1210     wBytesUntilWrap = 0xFFFFu;
1211     }
1212    
1213     // Convert everything to uppercase
1214     if(bTextCompare)
1215     {
1216     for(i = 0; i < k; i++)
1217     {
1218     if(buffer[i] >= 'a' && buffer[i] <= 'z')
1219     buffer[i] += 'A'-'a';
1220    
1221     if(j == buffer[i])
1222     {
1223     if(--wLen == 0)
1224     return wLocation-wLenStart + i + 1;
1225     j = *cFindArray++;
1226     if(j >= 'a' && j <= 'z')
1227     j += 'A'-'a';
1228     }
1229     else
1230     {
1231     wLen = wLenStart;
1232     cFindArray = cFindArrayStart;
1233     j = *cFindArray++;
1234     if(j >= 'a' && j <= 'z')
1235     j += 'A'-'a';
1236     }
1237     }
1238     }
1239     else // Compare as is
1240     {
1241     for(i = 0; i < k; i++)
1242     {
1243     if(j == buffer[i])
1244     {
1245     if(--wLen == 0)
1246     return wLocation-wLenStart + i + 1;
1247     j = *cFindArray++;
1248     }
1249     else
1250     {
1251     wLen = wLenStart;
1252     cFindArray = cFindArrayStart;
1253     j = *cFindArray++;
1254     }
1255     }
1256     }
1257    
1258     // Check to see if it is impossible to find a match
1259     wDataLen -= k;
1260     if(wDataLen < wLen)
1261     return 0xFFFFu;
1262    
1263     wLocation += k;
1264     }
1265     }
1266    
1267     WORD TCPFind(TCP_SOCKET hTCP, BYTE cFind, WORD wStart, BOOL bTextCompare)
1268     {
1269     return TCPFindArray(hTCP, &cFind, sizeof(cFind), wStart, bTextCompare);
1270     }
1271    
1272    
1273     /*********************************************************************
1274     * Function: void TCPTick(void)
1275     *
1276     * PreCondition: TCPInit() is already called.
1277     *
1278     * Input: None
1279     *
1280     * Output: Each socket FSM is executed for any timeout
1281     * situation.
1282     *
1283     * Side Effects: None
1284     *
1285     * Overview: None
1286     *
1287     * Note: None
1288     ********************************************************************/
1289     void TCPTick(void)
1290     {
1291     TCP_SOCKET hTCP;
1292     TCB_STUB *ps;
1293     BOOL bACKSent;
1294    
1295     // Periodically all "not closed" sockets must perform timed operations
1296     for(hTCP = 0; hTCP < MAX_TCP_SOCKETS; hTCP++)
1297     {
1298     ps = &TCBStubs[hTCP];
1299    
1300     bACKSent = FALSE;
1301    
1302     // Transmit ASAP data if the medium is available
1303     if(ps->Flags.bTXASAP)
1304     {
1305     if(MACIsTxReady())
1306     {
1307     LoadTCB(hTCP);
1308     SendTCP(hTCP, ACK);
1309     SaveTCB(hTCP);
1310     bACKSent = TRUE;
1311     }
1312     }
1313    
1314     // Perform any needed window updates and data transmissions
1315     if(ps->Flags.bTimer2Enabled)
1316     {
1317     // See if the timeout has occured
1318     if((SHORT)(ps->eventTime2 - (WORD)TickGet()) <= (SHORT)0)
1319     {
1320     // Send out a window update and any bytes waiting in the TX FIFO
1321     if(!bACKSent)
1322     {
1323     LoadTCB(hTCP);
1324     SendTCP(hTCP, ACK);
1325     SaveTCB(hTCP);
1326     bACKSent = TRUE;
1327     }
1328     }
1329     }
1330    
1331     // Process Delayed ACKnowledgement timer
1332     if(ps->Flags.bDelayedACKTimerEnabled)
1333     {
1334     // See if the timeout has occured
1335     if((SHORT)(ps->delayedACKTime - (WORD)TickGet()) <= (SHORT)0)
1336     {
1337     if(!bACKSent)
1338     {
1339     // Send out our delayed ACK
1340     LoadTCB(hTCP);
1341     SendTCP(hTCP, ACK);
1342     SaveTCB(hTCP);
1343     bACKSent = TRUE;
1344     }
1345     }
1346     }
1347    
1348     // The TCP_CLOSED, TCP_LISTEN, and sometimes the TCP_ESTABLISHED
1349     // state don't need any timeout events
1350     if(!ps->Flags.bTimerEnabled)
1351     continue;
1352    
1353     // If timeout has not occured, do not do anything.
1354     if((LONG)(TickGet() - ps->eventTime) < (LONG)0)
1355     continue;
1356    
1357     // Load up extended MyTCB information
1358     // If bACKSent, then the TCB has already been loaded. No need to do it again.
1359     if(!bACKSent)
1360     LoadTCB(hTCP);
1361    
1362     // This will be one more attempt.
1363     MyTCB.retryCount++;
1364    
1365     // Update timeout value if there is need to wait longer.
1366     MyTCB.retryInterval <<= 1;
1367    
1368     // Restart timeout reference.
1369     ps->eventTime = TickGet() + MyTCB.retryInterval;
1370    
1371     // A timeout has occured. Respond to this timeout condition
1372     // depending on what state this socket is in.
1373     switch(ps->smState)
1374     {
1375     case TCP_SYN_SENT:
1376     // Keep sending SYN until we hear from remote node.
1377     // This may be for infinite time, in that case
1378     // caller must detect it and do something.
1379     MyTCB.retryInterval = TCP_START_TIMEOUT_VAL;
1380     MyTCB.retryCount = 0;
1381     SendTCP(hTCP, SYN);
1382     break;
1383    
1384     case TCP_SYN_RECEIVED:
1385     // We must receive ACK before timeout expires.
1386     // If not, resend SYN+ACK.
1387     // Abort, if maximum attempts counts are reached.
1388     if(MyTCB.retryCount <= MAX_RETRY_COUNTS)
1389     {
1390     SendTCP(hTCP, SYN | ACK);
1391     }
1392     else
1393     {
1394     if(ps->Flags.bServer)
1395     {
1396     SendTCP(hTCP, RST);
1397     CloseSocket(hTCP);
1398     }
1399     else
1400     {
1401     ps->smState = TCP_SYN_SENT;
1402     MyTCB.retryInterval = TCP_START_TIMEOUT_VAL;
1403     MyTCB.retryCount = 0;
1404     SendTCP(hTCP, SYN);
1405     }
1406     }
1407     break;
1408    
1409     case TCP_ESTABLISHED:
1410     if(MyTCB.txUnackedTail != ps->txTail)
1411     {
1412     // Retransmit any unacknowledged data
1413     if(MyTCB.retryCount <= MAX_RETRY_COUNTS)
1414     {
1415     // Roll back unacknowledged TX tail pointer
1416     MyTCB.MySEQ -= (LONG)(SHORT)(MyTCB.txUnackedTail - ps->txTail);
1417     if(MyTCB.txUnackedTail < ps->txTail)
1418     MyTCB.MySEQ -= (LONG)(SHORT)(ps->bufferRxStart - ps->bufferTxStart);
1419     MyTCB.txUnackedTail = ps->txTail;
1420    
1421     SendTCP(hTCP, PSH | ACK);
1422     }
1423     else
1424     {
1425     // No response back for too long, close connection
1426     // This could happen, for instance, if the communication
1427     // medium was lost
1428     MyTCB.MySEQ++;
1429     ps->smState = TCP_FIN_WAIT_1;
1430     MyTCB.retryInterval = TCP_START_TIMEOUT_VAL;
1431     MyTCB.retryCount = 0;
1432    
1433     SendTCP(hTCP, FIN | ACK);
1434     }
1435     }
1436     break;
1437    
1438     case TCP_FIN_WAIT_1:
1439     if(MyTCB.retryCount <= MAX_RETRY_COUNTS)
1440     {
1441     // Roll back unacknowledged TX tail pointer
1442     MyTCB.MySEQ -= (LONG)(SHORT)(MyTCB.txUnackedTail - ps->txTail);
1443     if(MyTCB.txUnackedTail < ps->txTail)
1444     MyTCB.MySEQ -= (LONG)(SHORT)(ps->bufferRxStart - ps->bufferTxStart);
1445     MyTCB.txUnackedTail = ps->txTail;
1446    
1447     // Send another FIN
1448     SendTCP(hTCP, FIN | ACK);
1449     }
1450     else
1451     {
1452     // Close on our own, we can't seem to communicate
1453     // with the remote node anymore
1454     SendTCP(hTCP, RST | ACK);
1455     CloseSocket(hTCP);
1456     }
1457     break;
1458    
1459     case TCP_FIN_WAIT_2:
1460     // Close on our own, we can't seem to communicate
1461     // with the remote node anymore
1462     SendTCP(hTCP, RST | ACK);
1463     CloseSocket(hTCP);
1464     break;
1465    
1466     case TCP_CLOSING:
1467     if(MyTCB.retryCount <= MAX_RETRY_COUNTS)
1468     {
1469     // Roll back unacknowledged TX tail pointer
1470     MyTCB.MySEQ -= (LONG)(SHORT)(MyTCB.txUnackedTail - ps->txTail);
1471     if(MyTCB.txUnackedTail < ps->txTail)
1472     MyTCB.MySEQ -= (LONG)(SHORT)(ps->bufferRxStart - ps->bufferTxStart);
1473     MyTCB.txUnackedTail = ps->txTail;
1474    
1475     // Send another ACK
1476     SendTCP(hTCP, ACK);
1477     }
1478     else
1479     {
1480     // Close on our own, we can't seem to communicate
1481     // with the remote node anymore
1482     SendTCP(hTCP, RST | ACK);
1483     CloseSocket(hTCP);
1484     }
1485     break;
1486    
1487     case TCP_TIME_WAIT:
1488     // Wait around for a while (2MSL) and then goto closed state
1489     CloseSocket(hTCP);
1490     break;
1491    
1492     case TCP_CLOSE_WAIT:
1493     if(MyTCB.retryCount <= MAX_RETRY_COUNTS)
1494     {
1495     // Roll back unacknowledged TX tail pointer
1496     MyTCB.MySEQ -= (LONG)(SHORT)(MyTCB.txUnackedTail - ps->txTail);
1497     if(MyTCB.txUnackedTail < ps->txTail)
1498     MyTCB.MySEQ -= (LONG)(SHORT)(ps->bufferRxStart - ps->bufferTxStart);
1499     MyTCB.txUnackedTail = ps->txTail;
1500    
1501     // Send ACK
1502     SendTCP(hTCP, ACK);
1503     }
1504     else
1505     {
1506     // We shouldn't get down here if the application properly closes the connection.
1507     // However, if it doesn't, we still need to ensure socket reuse, so let's forcefully close the socket.
1508     SendTCP(hTCP, RST | ACK);
1509     CloseSocket(hTCP);
1510     }
1511     break;
1512    
1513     case TCP_LAST_ACK:
1514     // Send some more FINs or close anyway
1515     if(MyTCB.retryCount <= MAX_RETRY_COUNTS)
1516     {
1517     SendTCP(hTCP, FIN | ACK);
1518     }
1519     else
1520     {
1521     SendTCP(hTCP, RST | ACK);
1522     CloseSocket(hTCP);
1523     }
1524     break;
1525     }
1526    
1527     SaveTCB(hTCP);
1528     }
1529     }
1530    
1531    
1532    
1533     /*********************************************************************
1534     * Function: BOOL TCPProcess(NODE_INFO* remote,
1535     * IP_ADDR *localIP,
1536     * WORD len)
1537     *
1538     * PreCondition: TCPInit() is already called AND
1539     * TCP segment is ready in MAC buffer
1540     *
1541     * Input: remote - Remote node info
1542     * len - Total length of TCP semgent.
1543     *
1544     * Output: TRUE if this function has completed its task
1545     * FALSE otherwise
1546     *
1547     * Side Effects: None
1548     *
1549     * Overview: None
1550     *
1551     * Note: None
1552     ********************************************************************/
1553     BOOL TCPProcess(NODE_INFO *remote, IP_ADDR *localIP, WORD len)
1554     {
1555     TCP_HEADER TCPHeader;
1556     PSEUDO_HEADER pseudoHeader;
1557     TCP_SOCKET socket;
1558     WORD_VAL checksum1;
1559     WORD_VAL checksum2;
1560     BYTE optionsSize;
1561    
1562     // Calculate IP pseudoheader checksum.
1563     pseudoHeader.SourceAddress = remote->IPAddr;
1564     pseudoHeader.DestAddress = *localIP;
1565     pseudoHeader.Zero = 0x0;
1566     pseudoHeader.Protocol = IP_PROT_TCP;
1567     pseudoHeader.TCPLength = len;
1568    
1569     SwapPseudoTCPHeader(pseudoHeader);
1570    
1571     checksum1.Val = ~CalcIPChecksum((BYTE*)&pseudoHeader,
1572     sizeof(pseudoHeader));
1573    
1574     // Now calculate TCP packet checksum in NIC RAM - should match
1575     // pesudo header checksum
1576     checksum2.Val = CalcIPBufferChecksum(len);
1577    
1578     // Compare checksums.
1579     if(checksum1.Val != checksum2.Val)
1580     {
1581     MACDiscardRx();
1582     return TRUE;
1583     }
1584    
1585     // Retrieve TCP header.
1586     IPSetRxBuffer(0);
1587     MACGetArray((BYTE*)&TCPHeader, sizeof(TCPHeader));
1588     SwapTCPHeader(&TCPHeader);
1589    
1590    
1591     // Skip over options to retrieve data bytes
1592     optionsSize = (BYTE)((TCPHeader.DataOffset.Val << 2)-
1593     sizeof(TCPHeader));
1594     len = len - optionsSize - sizeof(TCPHeader);
1595    
1596     // Find matching socket.
1597     socket = FindMatchingSocket(&TCPHeader, remote);
1598     if(socket != INVALID_SOCKET)
1599     {
1600     HandleTCPSeg(socket, &TCPHeader, len);
1601     SaveTCB(socket);
1602     }
1603     else
1604     {
1605     // If this is an unknown socket, or we don't have any
1606     // listening sockets available, discard it. We can't
1607     // process it right now.
1608     MACDiscardRx();
1609     }
1610    
1611     return TRUE;
1612     }
1613    
1614    
1615     /*********************************************************************
1616     * Function: static void SendTCP(TCP_SOCKET hTCP, BYTE flags)
1617     *
1618     * PreCondition: TCPInit() is already called
1619     * LoadTCP() is called with the value of hTCP
1620     *
1621     * Input: hTCP: Handle of socket to send packet with
1622     * flags: Additional TCP flags to include
1623     *
1624     * Output: A TCP segment is assembled and transmitted
1625     *
1626     * Side Effects: None
1627     *
1628     * Overview: None
1629     *
1630     * Note: Function does not save the MyTCB data. It is
1631     * the caller's responsibility to save it.
1632     ********************************************************************/
1633     static void SendTCP(TCP_SOCKET hTCP, BYTE flags)
1634     {
1635     TCB_STUB *ps;
1636     WORD_VAL wVal;
1637     TCP_HEADER header;
1638     TCP_OPTIONS options;
1639     PSEUDO_HEADER pseudoHeader;
1640     WORD len;
1641     WORD wEffectiveWindow;
1642    
1643     ps = &TCBStubs[hTCP];
1644    
1645     // Status will now be synched, disable automatic future
1646     // status transmissions
1647     ps->Flags.bTimer2Enabled = 0;
1648     ps->Flags.bTXASAP = 0;
1649     ps->Flags.bDelayedACKTimerEnabled = 0;
1650     ps->Flags.bOneSegmentReceived = 0;
1651    
1652     // Make sure that we can write to the MAC transmit area
1653     while(!IPIsTxReady());
1654    
1655     // Put all socket application data in the TX space
1656     if(flags & SYN)
1657     {
1658     // Don't put any data for SYN messages
1659     len = 0;
1660     }
1661     else
1662     {
1663     // Begin copying any application data over to the TX space
1664     if(ps->txHead == MyTCB.txUnackedTail)
1665     {
1666     len = 0;
1667     }
1668     else if(ps->txHead > MyTCB.txUnackedTail)
1669     {
1670     len = ps->txHead - MyTCB.txUnackedTail;
1671     wEffectiveWindow = MyTCB.remoteWindow;
1672     if(MyTCB.txUnackedTail >= ps->txTail)
1673     wEffectiveWindow -= MyTCB.txUnackedTail - ps->txTail;
1674     else
1675     wEffectiveWindow -= (ps->bufferRxStart - ps->bufferTxStart) - (ps->txTail - MyTCB.txUnackedTail);
1676    
1677     if(len > wEffectiveWindow)
1678     len = wEffectiveWindow;
1679    
1680     if(len > 576)
1681     {
1682     len = 576;
1683     ps->Flags.bTXASAP = 1;
1684     }
1685    
1686     MACMemCopyAsync(BASE_TX_ADDR+sizeof(ETHER_HEADER)+sizeof(IP_HEADER)+sizeof(TCP_HEADER), MyTCB.txUnackedTail, len);
1687     MyTCB.txUnackedTail += len;
1688     }
1689     else
1690     {
1691     pseudoHeader.TCPLength = ps->bufferRxStart - MyTCB.txUnackedTail;
1692     len = pseudoHeader.TCPLength + ps->txHead - ps->bufferTxStart;
1693    
1694     wEffectiveWindow = MyTCB.remoteWindow;
1695     if(MyTCB.txUnackedTail >= ps->txTail)
1696     wEffectiveWindow -= MyTCB.txUnackedTail - ps->txTail;
1697     else
1698     wEffectiveWindow -= (ps->bufferRxStart - ps->bufferTxStart) - (ps->txTail - MyTCB.txUnackedTail);
1699    
1700     if(len > wEffectiveWindow)
1701     len = wEffectiveWindow;
1702    
1703     if(len > 576)
1704     {
1705     len = 576;
1706     ps->Flags.bTXASAP = 1;
1707     }
1708    
1709     if(pseudoHeader.TCPLength > wEffectiveWindow)
1710     pseudoHeader.TCPLength = wEffectiveWindow;
1711    
1712     if(pseudoHeader.TCPLength > 576)
1713     pseudoHeader.TCPLength = 576;
1714    
1715     MACMemCopyAsync(BASE_TX_ADDR+sizeof(ETHER_HEADER)+sizeof(IP_HEADER)+sizeof(TCP_HEADER), MyTCB.txUnackedTail, pseudoHeader.TCPLength);
1716     pseudoHeader.TCPLength = len - pseudoHeader.TCPLength;
1717    
1718     // Copy any left over chunks of application data over
1719     if(pseudoHeader.TCPLength)
1720     {
1721     MACMemCopyAsync(BASE_TX_ADDR+sizeof(ETHER_HEADER)+sizeof(IP_HEADER)+sizeof(TCP_HEADER)+(ps->bufferRxStart-MyTCB.txUnackedTail), ps->bufferTxStart, pseudoHeader.TCPLength);
1722     }
1723    
1724     MyTCB.txUnackedTail += len;
1725     if(MyTCB.txUnackedTail >= ps->bufferRxStart)
1726     MyTCB.txUnackedTail -= ps->bufferRxStart-ps->bufferTxStart;
1727     }
1728     }
1729    
1730     header.SourcePort = MyTCB.localPort.Val;
1731     header.DestPort = MyTCB.remotePort.Val;
1732     if(flags & (SYN | FIN))
1733     header.SeqNumber = MyTCB.MySEQ-1;
1734     else
1735     header.SeqNumber = MyTCB.MySEQ;
1736     header.AckNumber = MyTCB.RemoteSEQ;
1737     header.Flags.bits.Reserved2 = 0;
1738     header.DataOffset.Reserved3 = 0;
1739     header.Flags.byte = flags;
1740     header.UrgentPointer = 0;
1741    
1742     // For next time
1743     MyTCB.MySEQ += (DWORD)len;
1744    
1745     // Calculate the amount of free space in the RX buffer area of this socket
1746     if(ps->rxHead >= ps->rxTail)
1747     header.Window = (ps->bufferEnd - ps->bufferRxStart) - (ps->rxHead - ps->rxTail);
1748     else
1749     header.Window = ps->rxTail - ps->rxHead - 1;
1750    
1751     // Calculate the amount of free space in the MAC RX buffer area and adjust window if needed
1752     wVal.Val = MACGetFreeRxSize()-64;
1753     if((SHORT)wVal.Val < (SHORT)0)
1754     wVal.Val = 0;
1755     // Force the remote node to throttle back if we are running low on general RX buffer space
1756     // if(header.Window > wVal.Val)
1757     if((header.Window > wVal.Val) && (wVal.Val < 2000))
1758     header.Window = wVal.Val;
1759    
1760     SwapTCPHeader(&header);
1761    
1762    
1763     len += sizeof(header);
1764    
1765     header.DataOffset.Val = sizeof(header) >> 2;
1766     if(flags & SYN)
1767     {
1768     len += sizeof(options);
1769     options.Kind = TCP_OPTIONS_MAX_SEG_SIZE;
1770     options.Length = 0x04;
1771    
1772     // Load MSS and swap to big endian
1773     options.MaxSegSize.Val = 0x4002; // 576
1774    
1775     header.DataOffset.Val += sizeof(options) >> 2;
1776     }
1777    
1778     // Calculate IP pseudoheader checksum.
1779     pseudoHeader.SourceAddress = AppConfig.MyIPAddr;
1780     pseudoHeader.DestAddress = MyTCB.remote.IPAddr;
1781     pseudoHeader.Zero = 0x0;
1782     pseudoHeader.Protocol = IP_PROT_TCP;
1783     pseudoHeader.TCPLength = len;
1784    
1785     SwapPseudoTCPHeader(pseudoHeader);
1786    
1787     header.Checksum = ~CalcIPChecksum((BYTE*)&pseudoHeader, sizeof(pseudoHeader));
1788    
1789     MACSetWritePtr(BASE_TX_ADDR + sizeof(ETHER_HEADER));
1790    
1791     // Write IP header.
1792     IPPutHeader(&MyTCB.remote, IP_PROT_TCP, len);
1793     MACPutArray((BYTE*)&header, sizeof(header));
1794     if(flags & SYN)
1795     MACPutArray((BYTE*)&options, sizeof(options));
1796    
1797     MACSetReadPtr(BASE_TX_ADDR + sizeof(ETHER_HEADER) + sizeof(IP_HEADER));
1798     wVal.Val = CalcIPBufferChecksum(len);
1799    
1800     // Update the TCP checksum and begin transmission of the packet
1801     MACSetWritePtr(BASE_TX_ADDR + sizeof(ETHER_HEADER) + sizeof(IP_HEADER) + 16);
1802     MACPutArray((BYTE*)&wVal, sizeof(WORD));
1803    
1804     while(!MACIsMemCopyDone());
1805     MACFlush();
1806     }
1807    
1808    
1809    
1810     /*********************************************************************
1811     * Function: static TCP_SOCKET FindMatchingSocket(TCP_HEADER *h,
1812     * NODE_INFO* remote)
1813     *
1814     * PreCondition: TCPInit() is already called
1815     *
1816     * Input: h - TCP Header to be matched against.
1817     * remote - Node who sent this header.
1818     *
1819     * Output: A socket that matches with given header and remote
1820     * node is searched.
1821     * If such socket is found, its index is returned
1822     * else INVALID_SOCKET is returned.
1823     *
1824     * Side Effects: None
1825     *
1826     * Overview: None
1827     *
1828     * Note: None
1829     ********************************************************************/
1830     static TCP_SOCKET FindMatchingSocket(TCP_HEADER *h, NODE_INFO *remote)
1831     {
1832     TCB_STUB *ps;
1833     TCP_SOCKET hTCP;
1834     TCP_SOCKET partialMatch;
1835     WORD hash;
1836    
1837     partialMatch = INVALID_SOCKET;
1838     hash = (remote->IPAddr.w[1]+remote->IPAddr.w[0] + h->SourcePort) ^ h->DestPort;
1839    
1840     for(hTCP = 0; hTCP < MAX_TCP_SOCKETS; hTCP++ )
1841     {
1842     ps = &TCBStubs[hTCP];
1843    
1844     if(ps->smState == TCP_CLOSED)
1845     {
1846     continue;
1847     }
1848     else if(ps->smState == TCP_LISTEN)
1849     {
1850     if(ps->remoteHash.Val == h->DestPort)
1851     partialMatch = hTCP;
1852     continue;
1853     }
1854     else if(ps->remoteHash.Val != hash)
1855     {
1856     continue;
1857     }
1858    
1859     LoadTCB(hTCP);
1860     if( h->DestPort == MyTCB.localPort.Val &&
1861     h->SourcePort == MyTCB.remotePort.Val &&
1862     remote->IPAddr.Val == MyTCB.remote.IPAddr.Val)
1863     {
1864     return hTCP;
1865     }
1866     }
1867    
1868     // We are not listening on this port, nor is a socket using it
1869     if(partialMatch == INVALID_SOCKET)
1870     return INVALID_SOCKET;
1871    
1872     // Set up the extended TCB with the info needed to establish a
1873     // connection and return this socket to the caller
1874     ps = &TCBStubs[partialMatch];
1875    
1876     ps->remoteHash.Val = hash;
1877     ps->txHead = ps->bufferTxStart;
1878     ps->txTail = ps->bufferTxStart;
1879     ps->rxHead = ps->bufferRxStart;
1880     ps->rxTail = ps->bufferRxStart;
1881     ps->Flags.bTimerEnabled = FALSE;
1882    
1883     memcpy((void*)&MyTCB.remote, (void*)remote, sizeof(NODE_INFO));
1884     MyTCB.remotePort.Val = h->SourcePort;
1885     MyTCB.localPort.Val = h->DestPort;
1886     ((DWORD_VAL*)(&MyTCB.MySEQ))->w[0] = rand();
1887     ((DWORD_VAL*)(&MyTCB.MySEQ))->w[1] = rand();
1888     MyTCB.txUnackedTail = ps->bufferTxStart;
1889    
1890     return partialMatch;
1891     }
1892    
1893    
1894    
1895     /*********************************************************************
1896     * Function: static void SwapTCPHeader(TCP_HEADER* header)
1897     *
1898     * PreCondition: None
1899     *
1900     * Input: header - TCP Header to be swapped.
1901     *
1902     * Output: Given header is swapped.
1903     *
1904     * Side Effects: None
1905     *
1906     * Overview: None
1907     *
1908     * Note: None
1909     ********************************************************************/
1910     static void SwapTCPHeader(TCP_HEADER* header)
1911     {
1912     header->SourcePort = swaps(header->SourcePort);
1913     header->DestPort = swaps(header->DestPort);
1914     header->SeqNumber = swapl(header->SeqNumber);
1915     header->AckNumber = swapl(header->AckNumber);
1916     header->Window = swaps(header->Window);
1917     header->Checksum = swaps(header->Checksum);
1918     header->UrgentPointer = swaps(header->UrgentPointer);
1919     }
1920    
1921    
1922    
1923     /*********************************************************************
1924     * Function: static void CloseSocket(TCP_SOCKET hTCP)
1925     *
1926     * PreCondition: TCPInit() is already called
1927     * LoadTCB() must be called with the value of hTCP
1928     *
1929     * Input: hTCP - Handle of socket to close/reinitialize
1930     *
1931     * Output: Given socket information is reset and any
1932     * buffered bytes held by this socket are discarded.
1933     *
1934     * Side Effects: None
1935     *
1936     * Overview: None
1937     *
1938     * Note: Function does not save the MyTCB data. It is
1939     * the caller's responsibility to save it.
1940     ********************************************************************/
1941     static void CloseSocket(TCP_SOCKET hTCP)
1942     {
1943     TCB_STUB *ps;
1944    
1945     ps = &TCBStubs[hTCP];
1946    
1947     ps->smState = ps->Flags.bServer ? TCP_LISTEN : TCP_CLOSED;
1948     ps->Flags.bTimerEnabled = FALSE;
1949     ps->Flags.bTimer2Enabled = FALSE;
1950     ps->Flags.bDelayedACKTimerEnabled = FALSE;
1951     ps->Flags.bOneSegmentReceived = FALSE;
1952     ps->Flags.bHalfFullFlush = FALSE;
1953     ps->Flags.bTXASAP = FALSE;
1954     ps->remoteHash.Val = MyTCB.localPort.Val;
1955     ps->txTail = ps->bufferTxStart;
1956     ps->txHead = ps->bufferTxStart;
1957     ps->rxTail = ps->bufferRxStart;
1958     ps->rxHead = ps->bufferRxStart;
1959     MyTCB.txUnackedTail = ps->bufferTxStart;
1960     ((DWORD_VAL*)(&MyTCB.MySEQ))->w[0] = rand();
1961     ((DWORD_VAL*)(&MyTCB.MySEQ))->w[1] = rand();
1962     }
1963    
1964    
1965    
1966     /*********************************************************************
1967     * Function: static void HandleTCPSeg(TCP_SOCKET hTCP, TCP_HEADER *h, WORD len)
1968     *
1969     * PreCondition: TCPInit() is already called AND
1970     * TCPProcess() is the caller.
1971     *
1972     * Input: hTCP - Socket that owns this segment
1973     * h - TCP Header
1974     * len - Total buffer length.
1975     *
1976     * Output: TCP FSM is executed on given socket with
1977     * given TCP segment.
1978     *
1979     * Side Effects: None
1980     *
1981     * Overview: None
1982     *
1983     * Note: None
1984     ********************************************************************/
1985     static void HandleTCPSeg(TCP_SOCKET hTCP, TCP_HEADER *h, WORD len)
1986     {
1987     DWORD dwTemp;
1988     WORD wTemp;
1989     LONG lMissingBytes;
1990     WORD wMissingBytes;
1991     WORD wFreeSpace;
1992     TCB_STUB *ps;
1993     BYTE flags;
1994    
1995     ps = &TCBStubs[hTCP];
1996     flags = 0x00;
1997    
1998    
1999     // Reset FSM, if RST is received.
2000     if(h->Flags.bits.flagRST)
2001     {
2002     SendTCP(hTCP, RST);
2003     CloseSocket(hTCP);
2004     MACDiscardRx();
2005     return;
2006     }
2007    
2008     // Update the local stored copy of the RemoteWindow
2009     // If previously we had a zero window, and now we don't
2010     // immediately send whatever was panding
2011     if((MyTCB.remoteWindow == 0u) && h->Window)
2012     ps->Flags.bTXASAP = 1;
2013     MyTCB.remoteWindow = h->Window;
2014    
2015    
2016     switch(ps->smState)
2017     {
2018     case TCP_LISTEN:
2019     if(!h->Flags.bits.flagSYN)
2020     {
2021     SendTCP(hTCP, RST);
2022     CloseSocket(hTCP);
2023     break;
2024     }
2025    
2026     flags = SYN | ACK;
2027     ps->smState = TCP_SYN_RECEIVED;
2028    
2029     // Clear timeout info
2030     MyTCB.retryCount = 0;
2031     MyTCB.retryInterval = TCP_START_TIMEOUT_VAL;
2032     ps->eventTime = TickGet() + TCP_START_TIMEOUT_VAL;
2033     ps->Flags.bTimerEnabled = TRUE;
2034    
2035     // We now have a sequence number for the remote node
2036     MyTCB.RemoteSEQ = h->SeqNumber + 1;
2037    
2038     break;
2039    
2040     case TCP_SYN_SENT:
2041     if(!h->Flags.bits.flagSYN)
2042     break;
2043    
2044     if(h->Flags.bits.flagACK)
2045     {
2046     // If SYN+ACK, we may need to go to TCP_ESTABLISHED state
2047     if(h->AckNumber == MyTCB.MySEQ)
2048     {
2049     flags = ACK;
2050     ps->smState = TCP_ESTABLISHED;
2051     ps->Flags.bTimerEnabled = FALSE;
2052    
2053     // Check for application data and make it
2054     // available, if present
2055     flags |= ProcessRXBytes(ps, h, len);
2056     }
2057     else
2058     {
2059     // ACK number incorrect: ignore this packet
2060     flags = RST;
2061     break;
2062     }
2063     }
2064     else
2065     {
2066     // Got SYN without ACK, need to go to TCP_SYN_RECEIVED state
2067     flags = SYN | ACK;
2068     ps->smState = TCP_SYN_RECEIVED;
2069    
2070     // Clear timeout info
2071     MyTCB.retryCount = 0;
2072     MyTCB.retryInterval = TCP_START_TIMEOUT_VAL;
2073     ps->eventTime = TickGet() + TCP_START_TIMEOUT_VAL;
2074     }
2075    
2076     // We now have a sequence number for the remote node
2077     MyTCB.RemoteSEQ = h->SeqNumber + 1;
2078    
2079     break;
2080    
2081     case TCP_SYN_RECEIVED:
2082     if(h->Flags.bits.flagACK && (h->AckNumber == MyTCB.MySEQ))
2083     {
2084     ps->smState = TCP_ESTABLISHED;
2085     ps->Flags.bTimerEnabled = FALSE;
2086    
2087     // Check for application data and make it
2088     // available, if present
2089     flags |= ProcessRXBytes(ps, h, len);
2090     }
2091    
2092     break;
2093    
2094     case TCP_ESTABLISHED:
2095     // Check for application data and make it
2096     // available, if present
2097     flags |= ProcessRXBytes(ps, h, len);
2098    
2099     // Handle any requests to close the connection
2100     if(h->Flags.bits.flagFIN)
2101     {
2102     MyTCB.RemoteSEQ++;
2103    
2104     if(len == 0u)
2105     {
2106     flags = FIN | ACK;
2107     MyTCB.MySEQ++;
2108     ps->smState = TCP_LAST_ACK;
2109     }
2110     else
2111     {
2112     // Don't send a FIN back immediately. The application
2113     // may want to send a little bit more data before closing
2114     // the socket.
2115     flags = ACK;
2116     ps->smState = TCP_CLOSE_WAIT;
2117     }
2118    
2119     // Clear timeout info
2120     MyTCB.retryCount = 0;
2121     MyTCB.retryInterval = TCP_START_TIMEOUT_VAL;
2122     ps->eventTime = TickGet() + TCP_START_TIMEOUT_VAL;
2123     ps->Flags.bTimerEnabled = TRUE;
2124     }
2125    
2126     break;
2127    
2128     case TCP_FIN_WAIT_1:
2129     if(h->Flags.bits.flagFIN && h->Flags.bits.flagACK && (h->AckNumber == MyTCB.MySEQ))
2130     {
2131     MyTCB.RemoteSEQ++;
2132     flags = ACK;
2133     ps->smState = TCP_TIME_WAIT;
2134     ps->eventTime = TickGet() + TCP_TIME_WAIT_TIMEOUT_VAL;
2135     }
2136     else if(h->Flags.bits.flagACK && (h->AckNumber == MyTCB.MySEQ))
2137     {
2138     ps->smState = TCP_FIN_WAIT_2;
2139     }
2140     else if(h->Flags.bits.flagFIN)
2141     {
2142     MyTCB.RemoteSEQ++;
2143     flags = ACK;
2144     ps->smState = TCP_CLOSING;
2145    
2146     // Clear timeout info
2147     MyTCB.retryCount = 0;
2148     MyTCB.retryInterval = TCP_START_TIMEOUT_VAL;
2149     ps->eventTime = TickGet() + TCP_START_TIMEOUT_VAL;
2150     }
2151    
2152     // Check for application data and make it
2153     // available, if present
2154     flags |= ProcessRXBytes(ps, h, len);
2155    
2156     break;
2157    
2158     case TCP_FIN_WAIT_2:
2159     if(h->Flags.bits.flagFIN)
2160     {
2161     MyTCB.RemoteSEQ++;
2162     flags = ACK;
2163     ps->smState = TCP_TIME_WAIT;
2164     ps->eventTime = TickGet() + TCP_TIME_WAIT_TIMEOUT_VAL;
2165     }
2166    
2167     // Check for application data and make it
2168     // available, if present
2169     flags |= ProcessRXBytes(ps, h, len);
2170    
2171     break;
2172    
2173     case TCP_CLOSING:
2174     if(h->Flags.bits.flagACK && (h->AckNumber == MyTCB.MySEQ))
2175     {
2176     ps->smState = TCP_TIME_WAIT;
2177     ps->eventTime = TickGet() + TCP_TIME_WAIT_TIMEOUT_VAL;
2178     }
2179    
2180     // Check for application data and make it
2181     // available, if present
2182     flags |= ProcessRXBytes(ps, h, len);
2183    
2184     break;
2185    
2186     case TCP_CLOSE_WAIT:
2187     flags = ACK;
2188     break;
2189    
2190     case TCP_LAST_ACK:
2191     if(h->Flags.bits.flagACK && (h->AckNumber == MyTCB.MySEQ))
2192     {
2193     CloseSocket(hTCP);
2194     }
2195     break;
2196    
2197     case TCP_TIME_WAIT:
2198     flags = RST;
2199     break;
2200     }
2201    
2202    
2203     // Throw away all ACKnowledged TX data
2204     if(h->Flags.bits.flagACK && (ps->smState != TCP_CLOSED) && (ps->smState != TCP_LISTEN))
2205     {
2206     // Calculate what the last acknowledged sequence number was
2207     dwTemp = MyTCB.MySEQ - (LONG)(SHORT)(MyTCB.txUnackedTail - ps->txTail);
2208     if(MyTCB.txUnackedTail < ps->txTail)
2209     dwTemp -= ps->bufferRxStart - ps->bufferTxStart;
2210    
2211     // Calcluate how many bytes were ACKed with this packet
2212     dwTemp = h->AckNumber - dwTemp;
2213     if(((LONG)(dwTemp) > 0) && (dwTemp <= ps->bufferRxStart - ps->bufferTxStart))
2214     {
2215     ps->Flags.bHalfFullFlush = FALSE;
2216    
2217     // Bytes ACKed, free up the TX FIFO space
2218     ps->txTail += dwTemp;
2219     if(ps->txTail >= ps->bufferRxStart)
2220     {
2221     ps->txTail -= ps->bufferRxStart - ps->bufferTxStart;
2222     }
2223    
2224     // No need to keep our retransmit timer going if we having nothing that needs ACKing anymore
2225     if((ps->smState == TCP_ESTABLISHED) && (ps->txTail == MyTCB.txUnackedTail))
2226     ps->Flags.bTimerEnabled = FALSE;
2227     }
2228     }
2229    
2230    
2231     while(!MACIsMemCopyDone());
2232     MACDiscardRx();
2233    
2234     if(flags)
2235     SendTCP(hTCP, flags);
2236     }
2237    
2238     /*********************************************************************
2239     * Function: static BYTE ProcessRXBytes(TCB_STUB *ps, TCP_HEADER *h, WORD len)
2240     *
2241     * PreCondition: None
2242     *
2243     * Input: *ps: Pointer to the current TCB_STUB which needs processing
2244     * *h: Pointer to the TCP_HEADER of the TCP packet we received
2245     * len: Number of TCP application layer bytes available
2246     *
2247     * Output: BYTE: Flags that should be transmitted back
2248     *
2249     * Side Effects: None
2250     *
2251     * Overview: None
2252     *
2253     * Note: This is an internal TCP layer function only.
2254     ********************************************************************/
2255     static BYTE ProcessRXBytes(TCB_STUB *ps, TCP_HEADER *h, WORD len)
2256     {
2257     WORD wTemp;
2258     LONG lMissingBytes;
2259     WORD wMissingBytes;
2260     WORD wFreeSpace;
2261    
2262     // Check for application data and make it
2263     // available, if present
2264     if(!len)
2265     return 0x00;
2266    
2267     // Calculate the number of bytes ahead of our head pointer this segment skips
2268     lMissingBytes = h->SeqNumber - MyTCB.RemoteSEQ;
2269     wMissingBytes = (WORD)lMissingBytes;
2270    
2271     // Calculate the RX FIFO space
2272     if(ps->rxHead >= ps->rxTail)
2273     wFreeSpace = (ps->bufferEnd - ps->bufferRxStart) - (ps->rxHead - ps->rxTail);
2274     else
2275     wFreeSpace = ps->rxTail - ps->rxHead - 1;
2276    
2277     // See if any of the segment data is within our RX window
2278     if(((LONG)wFreeSpace > lMissingBytes) && ((SHORT)wMissingBytes + (SHORT)len > (SHORT)0))
2279     {
2280     // See if there are bytes we must skip
2281     if((SHORT)wMissingBytes <= 0)
2282     {
2283     // Position packet read pointer to start of useful data area.
2284     IPSetRxBuffer((h->DataOffset.Val << 2) - wMissingBytes);
2285     len += wMissingBytes;
2286     MyTCB.RemoteSEQ += (DWORD)len;
2287    
2288     // Copy the application data from the packet into the socket RX FIFO
2289     // See if we need a two part copy (spans bufferEnd->bufferRxStart)
2290     if(ps->rxHead + len > ps->bufferEnd)
2291     {
2292     wTemp = ps->bufferEnd - ps->rxHead + 1;
2293     MACMemCopyAsync(ps->rxHead, -1, wTemp);
2294     MACMemCopyAsync(ps->bufferRxStart, -1, len - wTemp);
2295     ps->rxHead = ps->bufferRxStart + (len - wTemp);
2296     }
2297     else
2298     {
2299     MACMemCopyAsync(ps->rxHead, -1, len);
2300     ps->rxHead += len;
2301     }
2302    
2303     // See if we have a hole and other data waiting already in the RX FIFO
2304     if(MyTCB.sHoleSize != -1)
2305     {
2306     MyTCB.sHoleSize -= len;
2307     wTemp = MyTCB.wFutureDataSize + MyTCB.sHoleSize;
2308    
2309     // See if we just closed up a hole, and if so, advance head pointer
2310     if((SHORT)wTemp < (SHORT)0)
2311     {
2312     MyTCB.sHoleSize = -1;
2313     }
2314     else if(MyTCB.sHoleSize <= 0)
2315     {
2316     MyTCB.RemoteSEQ += wTemp;
2317     ps->rxHead += wTemp;
2318     if(ps->rxHead > ps->bufferEnd)
2319     ps->rxHead -= ps->bufferEnd - ps->bufferRxStart + 1;
2320     MyTCB.sHoleSize = -1;
2321     }
2322     }
2323     } // This packet is out of order or we lost a packet, see if we can generate a hole to accomodate it
2324     else if((SHORT)wMissingBytes > 0)
2325     {
2326     // Position packet read pointer to start of useful data area.
2327     IPSetRxBuffer(h->DataOffset.Val << 2);
2328    
2329     // See if we need a two part copy (spans bufferEnd->bufferRxStart)
2330     if(ps->rxHead + wMissingBytes + len > ps->bufferEnd)
2331     {
2332     // Calculate number of data bytes to copy before wraparound
2333     wTemp = ps->bufferEnd - ps->rxHead + 1 - wMissingBytes;
2334     if((SHORT)wTemp >= 0)
2335     {
2336     MACMemCopyAsync(ps->rxHead + wMissingBytes, -1, wTemp);
2337     MACMemCopyAsync(ps->bufferRxStart, -1, len - wTemp);
2338     }
2339     else
2340     {
2341     MACMemCopyAsync(ps->rxHead + wMissingBytes - (ps->bufferEnd - ps->bufferRxStart + 1), -1, len);
2342     }
2343     }
2344     else
2345     {
2346     MACMemCopyAsync(ps->rxHead + wMissingBytes, -1, len);
2347     }
2348    
2349     // Record the hole is here
2350     if(MyTCB.sHoleSize == -1)
2351     {
2352     MyTCB.sHoleSize = wMissingBytes;
2353     MyTCB.wFutureDataSize = len;
2354     }
2355     else
2356     {
2357     // We already have a hole, see if we can shrink the hole
2358     // or extend the future data size
2359     if(wMissingBytes < (WORD)MyTCB.sHoleSize)
2360     {
2361     if((wMissingBytes + len > (WORD)MyTCB.sHoleSize + MyTCB.wFutureDataSize) || (wMissingBytes + len < (WORD)MyTCB.sHoleSize))
2362     MyTCB.wFutureDataSize = len;
2363     else
2364     MyTCB.wFutureDataSize = (WORD)MyTCB.sHoleSize + MyTCB.wFutureDataSize - wMissingBytes;
2365     MyTCB.sHoleSize = wMissingBytes;
2366     }
2367     else if(wMissingBytes + len > (WORD)MyTCB.sHoleSize + MyTCB.wFutureDataSize)
2368     {
2369     MyTCB.wFutureDataSize += wMissingBytes + len - (WORD)MyTCB.sHoleSize - MyTCB.wFutureDataSize;
2370     }
2371    
2372     }
2373    
2374     // Request a fast retransmit from remote node by sending three duplicate ACKs
2375     //SendTCP(hTCP, ACK);
2376     //while(!MACIsTxReady());
2377     //MACFlush();
2378     //while(!MACIsTxReady());
2379     //MACFlush();
2380     }
2381     }
2382    
2383     // Make sure that we immediately send back an ack for the
2384     // second segment received
2385     if(ps->Flags.bOneSegmentReceived)
2386     return ACK;
2387    
2388     ps->Flags.bOneSegmentReceived = TRUE;
2389    
2390     // Do not send an ACK immediately back. Instead, we will
2391     // perform delayed acknowledgements. To do this, we will
2392     // just start a timer
2393     if(!ps->Flags.bDelayedACKTimerEnabled)
2394     {
2395     ps->Flags.bDelayedACKTimerEnabled = TRUE;
2396     ps->delayedACKTime = (WORD)TickGet() + (WORD)(TICK_SECOND/5);
2397     }
2398    
2399     return 0;
2400     }
2401    
2402     #endif //#if defined(STACK_USE_TCP)

  ViewVC Help
Powered by ViewVC 1.1.20