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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 15 - (show annotations) (download)
Thu Apr 19 09:01:15 2007 UTC (17 years, 1 month ago) by hedin
File MIME type: text/plain
File size: 65334 byte(s)
added the TCP/IP stack, source code.
1 /*********************************************************************
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