?lang_form? ?lang_select? ?lang_submit? ?lang_endform?
{HEADER END}
{BLAME START}

library

?curdirlinks? -

Blame information for rev 32

Line No. Rev Author Line
1 32 kaklik /*********************************************************************
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: IP, Tick, Ethernet/WiFi (ENC28J60.c, ETH97J60.c,
12 * ENCX24J600.c, or WFMac.c), ARP (optional),
13 * DNS (optional)
14 * Processor: PIC18, PIC24F, PIC24H, dsPIC30F, dsPIC33F, PIC32
15 * Compiler: Microchip C32 v1.05 or higher
16 * Microchip C30 v3.12 or higher
17 * Microchip C18 v3.30 or higher
18 * HI-TECH PICC-18 PRO 9.63PL2 or higher
19 * Company: Microchip Technology, Inc.
20 *
21 * Software License Agreement
22 *
23 * Copyright (C) 2002-2009 Microchip Technology Inc. All rights
24 * reserved.
25 *
26 * Microchip licenses to you the right to use, modify, copy, and
27 * distribute:
28 * (i) the Software when embedded on a Microchip microcontroller or
29 * digital signal controller product ("Device") which is
30 * integrated into Licensee's product; or
31 * (ii) ONLY the Software driver source files ENC28J60.c, ENC28J60.h,
32 * ENCX24J600.c and ENCX24J600.h ported to a non-Microchip device
33 * used in conjunction with a Microchip ethernet controller for
34 * the sole purpose of interfacing with the ethernet controller.
35 *
36 * You should refer to the license agreement accompanying this
37 * Software for additional information regarding your rights and
38 * obligations.
39 *
40 * THE SOFTWARE AND DOCUMENTATION ARE PROVIDED "AS IS" WITHOUT
41 * WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT
42 * LIMITATION, ANY WARRANTY OF MERCHANTABILITY, FITNESS FOR A
43 * PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL
44 * MICROCHIP BE LIABLE FOR ANY INCIDENTAL, SPECIAL, INDIRECT OR
45 * CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF
46 * PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY OR SERVICES, ANY CLAIMS
47 * BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE
48 * THEREOF), ANY CLAIMS FOR INDEMNITY OR CONTRIBUTION, OR OTHER
49 * SIMILAR COSTS, WHETHER ASSERTED ON THE BASIS OF CONTRACT, TORT
50 * (INCLUDING NEGLIGENCE), BREACH OF WARRANTY, OR OTHERWISE.
51 *
52 *
53 * Author Date Comment
54 *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
55 * Nilesh Rajbharti 5/8/01 Original (Rev 1.0)
56 * Howard Schlunder 12/11/06 Changed almost everything to
57 * better meet RFC 793.
58 ********************************************************************/
59 #define __TCP_C
60  
61 #include "TCPIP Stack/TCPIP.h"
62  
63 #if defined(STACK_USE_TCP)
64  
65 /****************************************************************************
66 Section:
67 Configuration Parameters
68 ***************************************************************************/
69  
70 // Starting port for client sockets
71 #define LOCAL_PORT_START_NUMBER (1024u)
72 // End port for client sockets
73 #define LOCAL_PORT_END_NUMBER (5000u)
74  
75 // For debugging only. Normal applications should never enable these
76 //#define DEBUG_GENERATE_TX_LOSS 31129
77 //#define DEBUG_GENERATE_RX_LOSS 32113
78  
79 // A lot of pointer dereference code can be removed if you
80 // locally copy TCBStubs to an absolute memory location.
81 // If you define TCP_OPTIMIZE_FOR_SIZE, local caching will
82 // occur and will substantially decrease the entire TCP ROM
83 // footprint (up to 35%). If you leave TCP_OPTIMIZE_FOR_SIZE
84 // undefined, the local caching will be disabled. On PIC18
85 // products, this will improve TCP performance/throughput by
86 // approximately 15%.
87 #define TCP_OPTIMIZE_FOR_SIZE
88  
89 // For smallest size and best throughput, TCP_OPTIMIZE_FOR_SIZE
90 // should always be enabled on PIC24/dsPIC products. On PIC32
91 // products there is very little difference and depnds on compiler
92 // optimization level
93 #if defined(__C30__) && !defined(TCP_OPTIMIZE_FOR_SIZE)
94 #define TCP_OPTIMIZE_FOR_SIZE
95 #elif defined(__C32__) && defined(TCP_OPTIMIZE_FOR_SIZE)
96 #undef TCP_OPTIMIZE_FOR_SIZE
97 #endif
98  
99 // TCP Maximum Segment Size for TX. The TX maximum segment size is actually
100 // govered by the remote node's MSS option advirtised during connection
101 // establishment. However, if the remote node specifies an unhandlably large
102 // MSS (ex: > Ethernet MTU), this define sets a hard limit so that we don't
103 // cause any TX buffer overflows. If the remote node does not advirtise a MSS
104 // option, all TX segments are fixed at 536 bytes maximum.
105 #define TCP_MAX_SEG_SIZE_TX (1460u)
106  
107 // TCP Maximum Segment Size for RX. This value is advirtised during connection
108 // establishment and the remote node should obey it. This should be set to 536
109 // to avoid IP layer fragmentation from causing packet loss. However, raising
110 // its value can enhance performance at the (small) risk of introducing
111 // incompatibility with certain special remote nodes (ex: ones connected via a
112 // slow dial up modem).
113 #define TCP_MAX_SEG_SIZE_RX (536u)
114  
115 // TCP Timeout and retransmit numbers
116 #define TCP_START_TIMEOUT_VAL ((DWORD)TICK_SECOND*1) // Timeout to retransmit unacked data
117 #define TCP_DELAYED_ACK_TIMEOUT ((DWORD)TICK_SECOND/10) // Timeout for delayed-acknowledgement algorithm
118 #define TCP_FIN_WAIT_2_TIMEOUT ((DWORD)TICK_SECOND*5) // Timeout for FIN WAIT 2 state
119 #define TCP_KEEP_ALIVE_TIMEOUT ((DWORD)TICK_SECOND*10) // Timeout for keep-alive messages when no traffic is sent
120 #define TCP_CLOSE_WAIT_TIMEOUT ((DWORD)TICK_SECOND/5) // Timeout for the CLOSE_WAIT state
121 #define TCP_MAX_RETRIES (5u) // Maximum number of retransmission attempts
122 #define TCP_MAX_UNACKED_KEEP_ALIVES (6u) // Maximum number of keep-alive messages that can be sent without receiving a response before automatically closing the connection
123 #define TCP_MAX_SYN_RETRIES (2u) // Smaller than all other retries to reduce SYN flood DoS duration
124  
125 #define TCP_AUTO_TRANSMIT_TIMEOUT_VAL (TICK_SECOND/25ull) // Timeout before automatically transmitting unflushed data
126 #define TCP_WINDOW_UPDATE_TIMEOUT_VAL (TICK_SECOND/5ull) // Timeout before automatically transmitting a window update due to a TCPGet() or TCPGetArray() function call
127  
128 #define TCP_SYN_QUEUE_MAX_ENTRIES (3u) // Number of TCP RX SYN packets to save if they cannot be serviced immediately
129 #define TCP_SYN_QUEUE_TIMEOUT ((DWORD)TICK_SECOND*3) // Timeout for when SYN queue entries are deleted if unserviceable
130  
131 /****************************************************************************
132 Section:
133 TCP Header Data Types
134 ***************************************************************************/
135  
136 #define FIN (0x01) // FIN Flag as defined in RFC
137 #define SYN (0x02) // SYN Flag as defined in RFC
138 #define RST (0x04) // Reset Flag as defined in RFC
139 #define PSH (0x08) // Push Flag as defined in RFC
140 #define ACK (0x10) // Acknowledge Flag as defined in RFC
141 #define URG (0x20) // Urgent Flag as defined in RFC
142  
143 // TCP Header Data Structure
144 typedef struct
145 {
146 WORD SourcePort; // Local port number
147 WORD DestPort; // Remote port number
148 DWORD SeqNumber; // Local sequence number
149 DWORD AckNumber; // Acknowledging remote sequence number
150  
151 struct
152 {
153 unsigned char Reserved3 : 4;
154 unsigned char Val : 4;
155 } DataOffset; // Data offset flags nibble
156  
157 union
158 {
159 struct
160 {
161 unsigned char flagFIN : 1;
162 unsigned char flagSYN : 1;
163 unsigned char flagRST : 1;
164 unsigned char flagPSH : 1;
165 unsigned char flagACK : 1;
166 unsigned char flagURG : 1;
167 unsigned char Reserved2 : 2;
168 } bits;
169 BYTE byte;
170 } Flags; // TCP Flags as defined in RFC
171  
172 WORD Window; // Local free RX buffer window
173 WORD Checksum; // Data payload checksum
174 WORD UrgentPointer; // Urgent pointer
175 } TCP_HEADER;
176  
177 #define TCP_OPTIONS_END_OF_LIST (0x00u) // End of List TCP Option Flag
178 #define TCP_OPTIONS_NO_OP (0x01u) // No Op TCP Option
179 #define TCP_OPTIONS_MAX_SEG_SIZE (0x02u) // Maximum segment size TCP flag
180 typedef struct
181 {
182 BYTE Kind; // Type of option
183 BYTE Length; // Length
184 WORD_VAL MaxSegSize; // Maximum segment size
185 } TCP_OPTIONS; // TCP Options data structure
186  
187 // Structure containing all the important elements of an incomming
188 // SYN packet in order to establish a connection at a future time
189 // if all sockets on the listening port are already connected to
190 // someone
191 typedef struct
192 {
193 NODE_INFO niSourceAddress;// Remote IP address and MAC address
194 WORD wSourcePort; // Remote TCP port number that the response SYN needs to be sent to
195 DWORD dwSourceSEQ; // Remote TCP SEQuence number that must be ACKnowledged when we send our response SYN
196 WORD wDestPort; // Local TCP port which the original SYN was destined for
197 WORD wTimestamp; // Timer to expire old SYN packets that can't be serviced at all
198 } TCP_SYN_QUEUE;
199  
200  
201 #if defined(STACK_CLIENT_MODE)
202 static WORD NextPort __attribute__((persistent)); // Tracking variable for next local client port number
203 #endif
204  
205 /****************************************************************************
206 Section:
207 TCB Definitions
208 ***************************************************************************/
209  
210 // Determines the number of defined TCP sockets
211 #define TCP_SOCKET_COUNT (sizeof(TCPSocketInitializer)/sizeof(TCPSocketInitializer[0]))
212  
213  
214 #if defined(HI_TECH_C)
215 // The initializer forces this large array out of the bss section
216 // so we can link correctly.
217 #pragma psect bigdata=TCB_uRAM_BIG
218 #pragma psect data=TCB_uRAM
219 static TCB_STUB TCBStubs[TCP_SOCKET_COUNT] = {'\0'};
220 #pragma psect data=ordinary_data_sect
221 #pragma psect bigdata=ordinary_data_sect_big
222 #else
223 // The TCB array is very large. With the C18 compiler, one must
224 // modify the linker script to make an array that spans more than
225 // one memory bank. To do this, make the necessary changes to your
226 // processor's linker script (.lkr). Here is an example showing
227 // gpr11 and 128 bytes of gpr12 being combined into one 384 byte
228 // block used exclusively by the TCB_uRAM data section:
229 // ...
230 // //DATABANK NAME=gpr11 START=0xB00 END=0xBFF
231 // //DATABANK NAME=gpr12 START=0xC00 END=0xCFF
232 // DATABANK NAME=gpr11b START=0xB00 END=0xC7F PROTECTED
233 // DATABANK NAME=gpr12 START=0xC80 END=0xCFF
234 // ...
235 // SECTION NAME=TCB_uRAM RAM=gpr11b
236 // ...
237 #if defined(__18CXX) && !defined(HI_TECH_C)
238 #pragma udata TCB_uRAM
239 #endif
240 static TCB_STUB TCBStubs[TCP_SOCKET_COUNT];
241 #if defined(__18CXX) && !defined(HI_TECH_C)
242 #pragma udata // Return to any other RAM section
243 #endif
244 #endif
245  
246 static TCB MyTCB; // Currently loaded TCB
247 static TCP_SOCKET hCurrentTCP = INVALID_SOCKET; // Current TCP socket
248 #if TCP_SYN_QUEUE_MAX_ENTRIES
249 #if defined(__18CXX) && !defined(HI_TECH_C)
250 #pragma udata SYN_QUEUE_RAM_SECT
251 #endif
252 static TCP_SYN_QUEUE SYNQueue[TCP_SYN_QUEUE_MAX_ENTRIES]; // Array of saved incoming SYN requests that need to be serviced later
253 #if defined(__18CXX) && !defined(HI_TECH_C)
254 #pragma udata
255 #endif
256 #endif
257  
258 /****************************************************************************
259 Section:
260 Function Prototypes
261 ***************************************************************************/
262  
263 static void TCPRAMCopy(PTR_BASE wDest, BYTE vDestType, PTR_BASE wSource, BYTE vSourceType, WORD wLength);
264  
265 #if defined(__18CXX)
266 static void TCPRAMCopyROM(PTR_BASE wDest, BYTE wDestType, ROM BYTE* wSource, WORD wLength);
267 #else
268 #define TCPRAMCopyROM(a,b,c,d) TCPRAMCopy(a,b,c,TCP_PIC_RAM,d)
269 #endif
270  
271 static void SendTCP(BYTE vTCPFlags, BYTE vSendFlags);
272 static void HandleTCPSeg(TCP_HEADER* h, WORD len);
273 static BOOL FindMatchingSocket(TCP_HEADER* h, NODE_INFO* remote);
274 static void SwapTCPHeader(TCP_HEADER* header);
275 static void CloseSocket(void);
276 static void SyncTCB(void);
277  
278 // Indicates if this packet is a retransmission (no reset) or a new packet (reset required)
279 #define SENDTCP_RESET_TIMERS 0x01
280 // Instead of transmitting normal data, a garbage octet is transmitted according to RFC 1122 section 4.2.3.6
281 #define SENDTCP_KEEP_ALIVE 0x02
282  
283  
284 /****************************************************************************
285 Section:
286 TCB Optimization Configuration
287 ***************************************************************************/
288  
289 #if defined(TCP_OPTIMIZE_FOR_SIZE)
290 static TCB_STUB MyTCBStub;
291  
292 // Flushes MyTCBStub cache and loads up the specified TCB_STUB.
293 // Does nothing on cache hit.
294 static void SyncTCBStub(TCP_SOCKET hTCP)
295 {
296 if(hCurrentTCP == hTCP)
297 return;
298  
299 if(hCurrentTCP != INVALID_SOCKET)
300 {
301 // Save the current TCB stub
302 memcpy((void*)&TCBStubs[hCurrentTCP], (void*)&MyTCBStub, sizeof(MyTCBStub));
303 }
304  
305 hCurrentTCP = hTCP;
306  
307 if(hTCP == INVALID_SOCKET)
308 return;
309  
310 // Load up the new TCB stub
311 memcpy((void*)&MyTCBStub, (void*)&TCBStubs[hTCP], sizeof(MyTCBStub));
312 }
313 #else
314 // Flushes MyTCBStub cache and loads up the specified TCB_STUB.
315 // Does nothing on cache hit.
316 #define SyncTCBStub(a) hCurrentTCP = (a)
317 // Alias to current TCP stub.
318 #define MyTCBStub TCBStubs[hCurrentTCP]
319 #endif
320  
321  
322  
323 // Flushes MyTCB cache and loads up the specified TCB.
324 // Does nothing on cache hit.
325 static void SyncTCB(void)
326 {
327 static TCP_SOCKET hLastTCB = INVALID_SOCKET;
328  
329 if(hLastTCB == hCurrentTCP)
330 return;
331  
332 if(hLastTCB != INVALID_SOCKET)
333 {
334 // Save the current TCB
335 TCPRAMCopy(TCBStubs[hLastTCB].bufferTxStart - sizeof(MyTCB), TCBStubs[hLastTCB].vMemoryMedium, (PTR_BASE)&MyTCB, TCP_PIC_RAM, sizeof(MyTCB));
336 }
337  
338 // Load up the new TCB
339 hLastTCB = hCurrentTCP;
340 TCPRAMCopy((PTR_BASE)&MyTCB, TCP_PIC_RAM, MyTCBStub.bufferTxStart - sizeof(MyTCB), MyTCBStub.vMemoryMedium, sizeof(MyTCB));
341 }
342  
343  
344 /*****************************************************************************
345 Function:
346 void TCPInit(void)
347  
348 Summary:
349 Initializes the TCP module.
350  
351 Description:
352 Initializes the TCP module. This function sets up the TCP buffers
353 in memory and initializes each socket to the CLOSED state. If
354 insufficient memory was allocated for the TCP sockets, the function
355 will hang here to be captured by the debugger.
356  
357 Precondition:
358 None
359  
360 Parameters:
361 None
362  
363 Returns:
364 None
365  
366 Remarks:
367 This function is called only one during lifetime of the application.
368 ***************************************************************************/
369 void TCPInit(void)
370 {
371 BYTE i;
372 BYTE vSocketsAllocated;
373 WORD wTXSize, wRXSize;
374 PTR_BASE ptrBaseAddress;
375 BYTE vMedium;
376 #if TCP_ETH_RAM_SIZE > 0
377 WORD wCurrentETHAddress = TCP_ETH_RAM_BASE_ADDRESS;
378 #endif
379 #if TCP_PIC_RAM_SIZE > 0
380 PTR_BASE ptrCurrentPICAddress = TCP_PIC_RAM_BASE_ADDRESS;
381 #endif
382 #if TCP_SPI_RAM_SIZE > 0
383 WORD wCurrentSPIAddress = TCP_SPI_RAM_BASE_ADDRESS;
384 #endif
385  
386 #if defined(STACK_CLIENT_MODE)
387 // Initialize NextPort to a random value if it is zero (such as after
388 // reset on a PIC32 or PIC18 when the static memory initializer is
389 // used). By starting with a random number, we decrease the risk of
390 // reusing a port number that was previously used if the user power
391 // cycles the device.
392 if(NextPort == 0u)
393 NextPort = (((WORD)GenerateRandomDWORD()) & 0x07FFu) + LOCAL_PORT_START_NUMBER;
394 #endif
395  
396  
397 // Mark all SYN Queue entries as invalid by zeroing the memory
398 #if TCP_SYN_QUEUE_MAX_ENTRIES
399 memset((void*)SYNQueue, 0x00, sizeof(SYNQueue));
400 #endif
401  
402 // Allocate all socket FIFO addresses
403 vSocketsAllocated = 0;
404 for(i = 0; i < TCP_SOCKET_COUNT; i++)
405 {
406 // Generate all needed sockets of each type (TCP_PURPOSE_*)
407 SyncTCBStub(i);
408  
409 vMedium = TCPSocketInitializer[i].vMemoryMedium;
410 wTXSize = TCPSocketInitializer[i].wTXBufferSize;
411 wRXSize = TCPSocketInitializer[i].wRXBufferSize;
412  
413 switch(vMedium)
414 {
415 #if TCP_ETH_RAM_SIZE > 0
416 case TCP_ETH_RAM:
417 ptrBaseAddress = wCurrentETHAddress;
418 wCurrentETHAddress += sizeof(TCB) + wTXSize+1 + wRXSize+1;
419 // Do a sanity check to ensure that we aren't going to use memory that hasn't been allocated to us.
420 // If your code locks up right here, it means you've incorrectly allocated your TCP socket buffers in TCPIPConfig.h. See the TCP memory allocation section. More RAM needs to be allocated to the base memory mediums, or the individual sockets TX and RX FIFOS and socket quantiy needs to be shrunken.
421 while(wCurrentETHAddress > TCP_ETH_RAM_BASE_ADDRESS + TCP_ETH_RAM_SIZE);
422 break;
423 #endif
424  
425 #if TCP_PIC_RAM_SIZE > 0
426 case TCP_PIC_RAM:
427 ptrBaseAddress = ptrCurrentPICAddress;
428 ptrCurrentPICAddress += sizeof(TCB) + wTXSize+1 + wRXSize+1;
429 // Do a sanity check to ensure that we aren't going to use memory that hasn't been allocated to us.
430 // If your code locks up right here, it means you've incorrectly allocated your TCP socket buffers in TCPIPConfig.h. See the TCP memory allocation section. More RAM needs to be allocated to the base memory mediums, or the individual sockets TX and RX FIFOS and socket quantiy needs to be shrunken.
431 while(ptrCurrentPICAddress > TCP_PIC_RAM_BASE_ADDRESS + TCP_PIC_RAM_SIZE);
432 break;
433 #endif
434  
435 #if TCP_SPI_RAM_SIZE > 0
436 case TCP_SPI_RAM:
437 ptrBaseAddress = wCurrentSPIAddress;
438 wCurrentSPIAddress += sizeof(TCB) + wTXSize+1 + wRXSize+1;
439 // Do a sanity check to ensure that we aren't going to use memory that hasn't been allocated to us.
440 // If your code locks up right here, it means you've incorrectly allocated your TCP socket buffers in TCPIPConfig.h. See the TCP memory allocation section. More RAM needs to be allocated to the base memory mediums, or the individual sockets TX and RX FIFOS and socket quantiy needs to be shrunken.
441 while(wCurrentSPIAddress > TCP_SPI_RAM_BASE_ADDRESS + TCP_SPI_RAM_SIZE);
442 break;
443 #endif
444  
445 default:
446 while(1); // Undefined allocation medium. Go fix your TCPIPConfig.h TCP memory allocations.
447 }
448  
449 MyTCBStub.vMemoryMedium = vMedium;
450 MyTCBStub.bufferTxStart = ptrBaseAddress + sizeof(TCB);
451 MyTCBStub.bufferRxStart = MyTCBStub.bufferTxStart + wTXSize + 1;
452 MyTCBStub.bufferEnd = MyTCBStub.bufferRxStart + wRXSize;
453 MyTCBStub.smState = TCP_CLOSED;
454 MyTCBStub.Flags.bServer = FALSE;
455 #if defined(STACK_USE_SSL)
456 MyTCBStub.sslStubID = SSL_INVALID_ID;
457 #endif
458  
459 SyncTCB();
460 MyTCB.vSocketPurpose = TCPSocketInitializer[i].vSocketPurpose;
461 CloseSocket();
462 }
463 }
464  
465 /****************************************************************************
466 Section:
467 Connection Management Functions
468 ***************************************************************************/
469  
470  
471 /*****************************************************************************
472 Function:
473 TCP_SOCKET TCPOpen(DWORD dwRemoteHost, BYTE vRemoteHostType, WORD wPort, BYTE vSocketPurpose)
474  
475 Summary:
476 Opens a TCP socket for listening or as a client.
477  
478 Description:
479 Provides a unified method for opening TCP sockets. This function can
480 open both client and server sockets. For client sockets, it can accept
481 a host name string to query in DNS, an IP address as a string, an IP
482 address in binary form, or a previously resolved NODE_INFO structure
483 containing the remote IP address and associated MAC address. When a
484 host name or IP address only is provided, the TCP module will
485 internally perform the necessary DNS and/or ARP resolution steps before
486 reporting that the TCP socket is connected (via a call to
487 TCPISConnected returning TRUE). Server sockets ignore this destination
488 parameter and listen only on the indicated port.
489  
490 The vSocketPurpose field allows sockets to be opened with varying
491 buffer size parameters and memory storage mediums. This field
492 corresponds to pre-defined sockets allocated in the
493 TCPSocketInitializer[] array in TCPIPConfig.h. The TCPIPConfig.h file
494 can be edited using the TCP/IP Configuration Wizard.
495  
496 Sockets are statically allocated on boot, but can be claimed with this
497 \function and freed using TCPDisconnect or TCPClose (for client
498 sockets). Server sockets can be freed using TCPClose only (calls to
499 TCPDisconnect will return server sockets to the listening state,
500 allowing reuse).
501  
502 Conditions:
503 TCP is initialized.
504  
505 Input:
506 dwRemoteHost - For client sockets only. Provide a pointer to a
507 null\-terminated string of the remote host name (ex\:
508 "www.microchip.com" or "192.168.1.123"), a literal
509 destination IP address (ex\: 0x7B01A8C0 or an IP_ADDR
510 data type), or a pointer to a NODE_INFO structure
511 with the remote IP address and remote node or gateway
512 MAC address specified. If a string is provided, note
513 that it must be statically allocated in memory and
514 cannot be modified or deallocated until
515 TCPIsConnected returns TRUE.<p />This parameter is
516 ignored for server sockets.
517 vRemoteHostType - Any one of the following flags to identify the
518 meaning of the dwRemoteHost parameter\:
519 * TCP_OPEN_SERVER &#45; Open a server socket and
520 ignore the dwRemoteHost parameter.
521 * TCP_OPEN_RAM_HOST &#45; Open a client socket and
522 connect it to a remote host who's name is stored as a
523 null terminated string in a RAM array. Ex\:
524 "www.microchip.com" or "192.168.0.123" (BYTE&#42;
525 type)
526 * TCP_OPEN_ROM_HOST &#45; Open a client socket and
527 connect it to a remote host who's name is stored as a
528 null terminated string in a literal string or ROM
529 array. Ex\: "www.microchip.com" or "192.168.0.123"
530 (ROM BYTE&#42; type)
531 * TCP_OPEN_IP_ADDRESS &#45; Open a client socket and
532 connect it to a remote IP address. Ex\: 0x7B01A8C0
533 for 192.168.1.123 (DWORD type). Note that the byte
534 ordering is big endian.
535 * TCP_OPEN_NODE_INFO &#45; Open a client socket and
536 connect it to a remote IP and MAC addresses pair
537 stored in a NODE_INFO structure. dwRemoteHost must be
538 a pointer to the NODE_INFO structure. This option is
539 provided for backwards compatibility with
540 applications built against prior stack versions that
541 only implemented the TCPConnect() function. It can
542 also be used to skip DNS and ARP resolution steps if
543 connecting to a remote node which you've already
544 connected to and have cached addresses for.
545 wPort - TCP port to listen on or connect to\:
546 * Client sockets &#45; the remote TCP port to which a
547 connection should be made. The local port for client
548 sockets will be automatically picked by the TCP
549 module.
550 * Server sockets &#45; the local TCP port on which to
551 listen for connections.
552 vSocketPurpose - Any of the TCP_PURPOSE_* constants defined in
553 TCPIPConfig.h or the TCPIPConfig utility (see
554 TCPSocketInitializer[] array).
555  
556 Return Values:
557 INVALID_SOCKET - No sockets of the specified type were available to be
558 opened.
559 Otherwise - A TCP_SOCKET handle. Save this handle and use it when
560 calling all other TCP APIs.
561  
562 Remarks:
563 This function replaces the old TCPConnect and TCPListen functions.
564  
565 If TCP_OPEN_RAM_HOST or TCP_OPEN_ROM_HOST are used for the destination
566 type, the DNS client module must also be enabled (STACK_USE_DNS must be
567 defined in TCPIPConfig.h).
568  
569 Example:
570 \ \
571 <code>
572 // Open a server socket
573 skt = TCPOpen(NULL, TCP_OPEN_SERVER, HTTP_PORT, TCP_PURPOSE_HTTP_SERVER);
574  
575 // Open a client socket to www.microchip.com
576 // The double cast here prevents compiler warnings
577 skt = TCPOpen((DWORD)(PTR_BASE)"www.microchip.com",
578 TCP_OPEN_ROM_HOST, 80, TCP_PURPOSE_DEFAULT);
579  
580 // Reopen a client socket without repeating DNS or ARP
581 SOCKET_INFO cache = TCPGetSocketInfo(skt); // Call with the old socket
582 skt = TCPOpen((DWORD)(PTR_BASE)&amp;cache.remote, TCP_OPEN_NODE_INFO,
583 cache.remotePort.Val, TCP_PURPOSE_DEFAULT);
584 </code>
585 *****************************************************************************/
586 TCP_SOCKET TCPOpen(DWORD dwRemoteHost, BYTE vRemoteHostType, WORD wPort, BYTE vSocketPurpose)
587 {
588 TCP_SOCKET hTCP;
589  
590 // Find an available socket that matches the specified socket type
591 for(hTCP = 0; hTCP < TCP_SOCKET_COUNT; hTCP++)
592 {
593 SyncTCBStub(hTCP);
594  
595 // Sockets that are in use will be in a non-closed state
596 if(MyTCBStub.smState != TCP_CLOSED)
597 continue;
598  
599 SyncTCB();
600  
601 // See if this socket matches the desired type
602 if(MyTCB.vSocketPurpose != vSocketPurpose)
603 continue;
604  
605 // Start out assuming worst case Maximum Segment Size (changes when MSS
606 // option is received from remote node)
607 MyTCB.wRemoteMSS = 536;
608  
609 // See if this is a server socket
610 if(vRemoteHostType == TCP_OPEN_SERVER)
611 {
612 MyTCB.localPort.Val = wPort;
613 MyTCBStub.Flags.bServer = TRUE;
614 MyTCBStub.smState = TCP_LISTEN;
615 MyTCBStub.remoteHash.Val = wPort;
616 #if defined(STACK_USE_SSL_SERVER)
617 MyTCB.localSSLPort.Val = 0;
618 #endif
619 }
620 // Handle all the client mode socket types
621 else
622 {
623 #if defined(STACK_CLIENT_MODE)
624 {
625 // Each new socket that is opened by this node, gets the
626 // next sequential local port number.
627 if(NextPort < LOCAL_PORT_START_NUMBER || NextPort > LOCAL_PORT_END_NUMBER)
628 NextPort = LOCAL_PORT_START_NUMBER;
629  
630 // Set the non-zero TCB fields
631 MyTCB.localPort.Val = NextPort++;
632 MyTCB.remotePort.Val = wPort;
633  
634 // Flag to start the DNS, ARP, SYN processes
635 MyTCBStub.eventTime = TickGet();
636 MyTCBStub.Flags.bTimerEnabled = 1;
637  
638 switch(vRemoteHostType)
639 {
640 #if defined(STACK_USE_DNS)
641 case TCP_OPEN_RAM_HOST:
642 case TCP_OPEN_ROM_HOST:
643 MyTCB.remote.dwRemoteHost = dwRemoteHost;
644 MyTCB.flags.bRemoteHostIsROM = (vRemoteHostType == TCP_OPEN_ROM_HOST);
645 MyTCBStub.smState = TCP_GET_DNS_MODULE;
646 break;
647 #endif
648  
649 case TCP_OPEN_IP_ADDRESS:
650 // dwRemoteHost is a literal IP address. This
651 // doesn't need DNS and can skip directly to the
652 // Gateway ARPing step.
653 MyTCBStub.remoteHash.Val = (((DWORD_VAL*)&dwRemoteHost)->w[1]+((DWORD_VAL*)&dwRemoteHost)->w[0] + wPort) ^ MyTCB.localPort.Val;
654 MyTCB.remote.niRemoteMACIP.IPAddr.Val = dwRemoteHost;
655 MyTCB.retryCount = 0;
656 MyTCB.retryInterval = (TICK_SECOND/4)/256;
657 MyTCBStub.smState = TCP_GATEWAY_SEND_ARP;
658 break;
659  
660 case TCP_OPEN_NODE_INFO:
661 MyTCBStub.remoteHash.Val = (((NODE_INFO*)(PTR_BASE)dwRemoteHost)->IPAddr.w[1]+((NODE_INFO*)(PTR_BASE)dwRemoteHost)->IPAddr.w[0] + wPort) ^ MyTCB.localPort.Val;
662 memcpy((void*)(BYTE*)&MyTCB.remote, (void*)(BYTE*)(PTR_BASE)dwRemoteHost, sizeof(NODE_INFO));
663 MyTCBStub.smState = TCP_SYN_SENT;
664 SendTCP(SYN, SENDTCP_RESET_TIMERS);
665 break;
666 }
667 }
668 #else
669 {
670 return INVALID_SOCKET;
671 }
672 #endif
673 }
674  
675 return hTCP;
676 }
677  
678 // If there is no socket available, return error.
679 return INVALID_SOCKET;
680 }
681  
682  
683 /*****************************************************************************
684 Function:
685 BOOL TCPWasReset(TCP_SOCKET hTCP)
686  
687 Summary:
688 Self-clearing semaphore inidicating socket reset.
689  
690 Description:
691 This function is a self-clearing semaphore indicating whether or not
692 a socket has been disconnected since the previous call. This function
693 works for all possible disconnections: a call to TCPDisconnect, a FIN
694 from the remote node, or an acknowledgement timeout caused by the loss
695 of a network link. It also returns TRUE after the first call to TCPInit.
696 Applications should use this function to reset their state machines.
697  
698 This function was added due to the possibility of an error when relying
699 on TCPIsConnected returing FALSE to check for a condition requiring a
700 state machine reset. If a socket is closed (due to a FIN ACK) and then
701 immediately reopened (due to a the arrival of a new SYN) in the same
702 cycle of the stack, calls to TCPIsConnected by the application will
703 never return FALSE even though the socket has been disconnected. This
704 can cause errors for protocols such as HTTP in which a client will
705 immediately open a new connection upon closing of a prior one. Relying
706 on this function instead allows applications to trap those conditions
707 and properly reset their internal state for the new connection.
708  
709 Precondition:
710 TCP is initialized.
711  
712 Parameters:
713 hTCP - The socket to check.
714  
715 Return Values:
716 TRUE - The socket has been disconnected since the previous call.
717 FALSE - The socket has not been disconnected since the previous call.
718 ***************************************************************************/
719 BOOL TCPWasReset(TCP_SOCKET hTCP)
720 {
721 SyncTCBStub(hTCP);
722  
723 if(MyTCBStub.Flags.bSocketReset)
724 {
725 MyTCBStub.Flags.bSocketReset = 0;
726 return TRUE;
727 }
728  
729 return FALSE;
730 }
731  
732  
733 /*****************************************************************************
734 Function:
735 BOOL TCPIsConnected(TCP_SOCKET hTCP)
736  
737 Summary:
738 Determines if a socket has an established connection.
739  
740 Description:
741 This function determines if a socket has an established connection to
742 a remote node. Call this function after calling TCPOpen to determine
743 when the connection is set up and ready for use. This function was
744 historically used to check for disconnections, but TCPWasReset is now a
745 more appropriate solution.
746  
747 Precondition:
748 TCP is initialized.
749  
750 Parameters:
751 hTCP - The socket to check.
752  
753 Return Values:
754 TRUE - The socket has an established connection to a remote node.
755 FALSE - The socket is not currently connected.
756  
757 Remarks:
758 A socket is said to be connected only if it is in the TCP_ESTABLISHED
759 state. Sockets in the process of opening or closing will return FALSE.
760 ***************************************************************************/
761 BOOL TCPIsConnected(TCP_SOCKET hTCP)
762 {
763 SyncTCBStub(hTCP);
764 return (MyTCBStub.smState == TCP_ESTABLISHED);
765 }
766  
767  
768 /*****************************************************************************
769 Function:
770 void TCPDisconnect(TCP_SOCKET hTCP)
771  
772 Summary:
773 Disconnects an open socket.
774  
775 Description:
776 This function closes a connection to a remote node by sending a FIN (if
777 currently connected).
778  
779 The function can be called a second time to force a socket closed by
780 sending a RST packet. This is useful when the application knows that
781 the remote node will not send an ACK (if it has crashed or lost its link),
782 or when the application needs to reuse the socket immediately regardless
783 of whether or not the remote node would like to transmit more data before
784 closing.
785  
786 For client mode sockets, upon return, the hTCP handle is relinquished to
787 the TCP/IP stack and must no longer be used by the application (except for
788 an immediate subsequent call to TCPDisconnect() to force a RST
789 transmission, if needed).
790  
791 For server mode sockets, upon return, the hTCP handle is NOT relinquished
792 to the TCP/IP stack. After closing, the socket returns to the listening
793 state allowing future connection requests to be serviced. This leaves the
794 hTCP handle in a valid state and must be retained for future operations on
795 the socket. If you want to close the server and relinquish the socket back
796 to the TCP/IP stack, call the TCPClose() API instead of TCPDisconnect().
797  
798 Precondition:
799 None
800  
801 Parameters:
802 hTCP - Handle of the socket to disconnect.
803  
804 Returns:
805 None
806  
807 Remarks:
808 If the socket is using SSL, a CLOSE_NOTIFY record will be transmitted
809 first to allow the SSL session to be resumed at a later time.
810 ***************************************************************************/
811 void TCPDisconnect(TCP_SOCKET hTCP)
812 {
813 SyncTCBStub(hTCP);
814  
815 // Delete all data in the RX FIFO
816 // In this stack's API, the application TCP handle is
817 // immediately invalid after calling this function, so there
818 // is no longer any way to receive data from the TCP RX FIFO,
819 // even though the data is still there. Leaving the data there
820 // could interfere with the remote node sending us a FIN if our
821 // RX window is zero
822 MyTCBStub.rxTail = MyTCBStub.rxHead;
823  
824 switch(MyTCBStub.smState)
825 {
826 #if defined(STACK_CLIENT_MODE) && defined(STACK_USE_DNS)
827 case TCP_DNS_RESOLVE:
828 DNSEndUsage(); // Release the DNS module, since the user is aborting
829 CloseSocket();
830 break;
831 #endif
832  
833 case TCP_GET_DNS_MODULE:
834 case TCP_GATEWAY_SEND_ARP:
835 case TCP_GATEWAY_GET_ARP:
836 case TCP_SYN_SENT:
837 CloseSocket();
838 break;
839  
840 case TCP_SYN_RECEIVED:
841 case TCP_ESTABLISHED:
842 #if defined(STACK_USE_SSL)
843 // When disconnecting SSL sockets, send a close_notify so we can resume later
844 if(MyTCBStub.sslStubID != SSL_INVALID_ID)
845 {
846 // Flush pending data and send close_notify
847 SSLTxRecord(hTCP, MyTCBStub.sslStubID, SSL_APPLICATION);
848 SSLTxMessage(hTCP, MyTCBStub.sslStubID, SSL_ALERT_CLOSE_NOTIFY);
849 }
850 #endif
851  
852 // Send the FIN. This is done in a loop to ensure that if we have
853 // more data wating in the TX FIFO than can be sent in a single
854 // packet (due to the remote Max Segment Size packet size limit),
855 // we will keep generating more packets until either all data gets
856 // transmitted or the remote node's receive window fills up.
857 do
858 {
859 SendTCP(FIN | ACK, SENDTCP_RESET_TIMERS);
860 if(MyTCB.remoteWindow == 0u)
861 break;
862 } while(MyTCBStub.txHead != MyTCB.txUnackedTail);
863  
864 MyTCBStub.smState = TCP_FIN_WAIT_1;
865 break;
866  
867 case TCP_CLOSE_WAIT:
868 // Send the FIN. This is done in a loop to ensure that if we have
869 // more data wating in the TX FIFO than can be sent in a single
870 // packet (due to the remote Max Segment Size packet size limit),
871 // we will keep generating more packets until either all data gets
872 // transmitted or the remote node's receive window fills up.
873 do
874 {
875 SendTCP(FIN | ACK, SENDTCP_RESET_TIMERS);
876 if(MyTCB.remoteWindow == 0u)
877 break;
878 } while(MyTCBStub.txHead != MyTCB.txUnackedTail);
879  
880 MyTCBStub.smState = TCP_LAST_ACK;
881 break;
882  
883 // These states are all already closed or don't need explicit disconnecting -- they will disconnect by themselves after a while
884 //case TCP_CLOSED:
885 //case TCP_LISTEN:
886 //case TCP_CLOSING:
887 //case TCP_TIME_WAIT:
888 // return;
889  
890 case TCP_CLOSED_BUT_RESERVED:
891 MyTCBStub.smState = TCP_CLOSED;
892 break;
893  
894 // These states will close themselves after some delay, however,
895 // this is handled so that the user can call TCPDisconnect()
896 // twice to immediately close a socket (using an RST) without
897 // having to get an ACK back from the remote node. This is
898 // great for instance when the application determines that
899 // the remote node has been physically disconnected and
900 // already knows that no ACK will be returned. Alternatively,
901 // if the application needs to immediately reuse the socket
902 // regardless of what the other node's state is in (half open).
903 case TCP_FIN_WAIT_1:
904 case TCP_FIN_WAIT_2:
905 case TCP_LAST_ACK:
906 default:
907 SendTCP(RST | ACK, 0);
908 CloseSocket();
909 break;
910 }
911 }
912  
913  
914 /*****************************************************************************
915 Function:
916 void TCPClose(TCP_SOCKET hTCP)
917  
918 Summary:
919 Disconnects an open socket and destroys the socket handle, including server
920 mode socket handles.
921  
922 Description:
923 Disconnects an open socket and destroys the socket handle, including server
924 mode socket handles. This function performs identically to the
925 TCPDisconnect() function, except that both client and server mode socket
926 handles are relinquished to the TCP/IP stack upon return.
927  
928 Precondition:
929 None
930  
931 Parameters:
932 hTCP - Handle to the socket to disconnect and close.
933  
934 Returns:
935 None
936 ***************************************************************************/
937 void TCPClose(TCP_SOCKET hTCP)
938 {
939 SyncTCBStub(hTCP);
940 MyTCBStub.Flags.bServer = FALSE;
941 TCPDisconnect(hTCP);
942 }
943  
944  
945 /*****************************************************************************
946 Function:
947 SOCKET_INFO* TCPGetRemoteInfo(TCP_SOCKET hTCP)
948  
949 Summary:
950 Obtains information about a currently open socket.
951  
952 Description:
953 Returns the SOCKET_INFO structure associated with this socket. This
954 contains the NODE_INFO structure with IP and MAC address (or gateway
955 MAC) and the remote port.
956  
957 Precondition:
958 TCP is initialized and the socket is connected.
959  
960 Parameters:
961 hTCP - The socket to check.
962  
963 Returns:
964 The SOCKET_INFO structure associated with this socket. This structure is
965 allocated statically by the function and is valid only until the next
966 time TCPGetRemoteInfo() is called.
967 ***************************************************************************/
968 SOCKET_INFO* TCPGetRemoteInfo(TCP_SOCKET hTCP)
969 {
970 static SOCKET_INFO RemoteInfo;
971  
972 SyncTCBStub(hTCP);
973 SyncTCB();
974 memcpy((void*)&RemoteInfo.remote, (void*)&MyTCB.remote, sizeof(NODE_INFO));
975 RemoteInfo.remotePort.Val = MyTCB.remotePort.Val;
976  
977 return &RemoteInfo;
978 }
979  
980  
981  
982 /****************************************************************************
983 Section:
984 Transmit Functions
985 ***************************************************************************/
986  
987 /*****************************************************************************
988 Function:
989 void TCPFlush(TCP_SOCKET hTCP)
990  
991 Summary:
992 Immediately transmits all pending TX data.
993  
994 Description:
995 This function immediately transmits all pending TX data with a PSH
996 flag. If this function is not called, data will automatically be sent
997 when either a) the TX buffer is half full or b) the
998 TCP_AUTO_TRANSMIT_TIMEOUT_VAL (default: 40ms) has elapsed.
999  
1000 Precondition:
1001 TCP is initialized and the socket is connected.
1002  
1003 Parameters:
1004 hTCP - The socket whose data is to be transmitted.
1005  
1006 Returns:
1007 None
1008  
1009 Remarks:
1010 SSL application data is automatically flushed, so this function has
1011 no effect for SSL sockets.
1012 ***************************************************************************/
1013 void TCPFlush(TCP_SOCKET hTCP)
1014 {
1015 SyncTCBStub(hTCP);
1016 SyncTCB();
1017  
1018 // NOTE: Pending SSL data will NOT be transferred here
1019  
1020 if(MyTCBStub.txHead != MyTCB.txUnackedTail)
1021 {
1022 // Send the TCP segment with all unacked bytes
1023 SendTCP(ACK, SENDTCP_RESET_TIMERS);
1024 }
1025 }
1026  
1027  
1028 /*****************************************************************************
1029 Function:
1030 WORD TCPIsPutReady(TCP_SOCKET hTCP)
1031  
1032 Summary:
1033 Determines how much free space is available in the TCP TX buffer.
1034  
1035 Description:
1036 Call this function to determine how many bytes can be written to the
1037 TCP TX buffer. If this function returns zero, the application must
1038 return to the main stack loop before continuing in order to transmit
1039 more data.
1040  
1041 Precondition:
1042 TCP is initialized.
1043  
1044 Parameters:
1045 hTCP - The socket to check.
1046  
1047 Returns:
1048 The number of bytes available to be written in the TCP TX buffer.
1049 ***************************************************************************/
1050 WORD TCPIsPutReady(TCP_SOCKET hTCP)
1051 {
1052 BYTE i;
1053  
1054 SyncTCBStub(hTCP);
1055  
1056 i = MyTCBStub.smState;
1057  
1058 // Unconnected sockets shouldn't be transmitting anything.
1059 if(!( (i == (BYTE)TCP_ESTABLISHED) || (i == (BYTE)TCP_CLOSE_WAIT) ))
1060 return 0;
1061  
1062 // Calculate the free space in this socket's TX FIFO
1063 #if defined(STACK_USE_SSL)
1064 if(MyTCBStub.sslStubID != SSL_INVALID_ID)
1065 {// Use sslTxHead as the head pointer when SSL is active
1066 WORD rem;
1067  
1068 // Find out raw free space
1069 if(MyTCBStub.sslTxHead >= MyTCBStub.txTail)
1070 rem = (MyTCBStub.bufferRxStart - MyTCBStub.bufferTxStart - 1) - (MyTCBStub.sslTxHead - MyTCBStub.txTail);
1071 else
1072 rem = MyTCBStub.txTail - MyTCBStub.sslTxHead - 1;
1073  
1074 // Reserve space for a new MAC and header
1075 if(rem > 22u)
1076 return rem - 22;
1077 else
1078 return 0;
1079 }
1080 #endif
1081  
1082 if(MyTCBStub.txHead >= MyTCBStub.txTail)
1083 return (MyTCBStub.bufferRxStart - MyTCBStub.bufferTxStart - 1) - (MyTCBStub.txHead - MyTCBStub.txTail);
1084 else
1085 return MyTCBStub.txTail - MyTCBStub.txHead - 1;
1086 }
1087  
1088  
1089 /*****************************************************************************
1090 Function:
1091 BOOL TCPPut(TCP_SOCKET hTCP, BYTE byte)
1092  
1093 Description:
1094 Writes a single byte to a TCP socket.
1095  
1096 Precondition:
1097 TCP is initialized.
1098  
1099 Parameters:
1100 hTCP - The socket to which data is to be written.
1101 byte - The byte to write.
1102  
1103 Return Values:
1104 TRUE - The byte was written to the transmit buffer.
1105 FALSE - The transmit buffer was full, or the socket is not connected.
1106 ***************************************************************************/
1107 BOOL TCPPut(TCP_SOCKET hTCP, BYTE byte)
1108 {
1109 WORD wFreeTXSpace;
1110  
1111 SyncTCBStub(hTCP);
1112  
1113 wFreeTXSpace = TCPIsPutReady(hTCP);
1114 if(wFreeTXSpace == 0u)
1115 return FALSE;
1116 else if(wFreeTXSpace == 1u) // About to run out of space, lets transmit so the remote node might send an ACK back faster
1117 TCPFlush(hTCP);
1118  
1119 // Send all current bytes if we are crossing half full
1120 // This is required to improve performance with the delayed
1121 // acknowledgement algorithm
1122 if((!MyTCBStub.Flags.bHalfFullFlush) && (wFreeTXSpace <= ((MyTCBStub.bufferRxStart-MyTCBStub.bufferTxStart)>>1)))
1123 {
1124 TCPFlush(hTCP);
1125 MyTCBStub.Flags.bHalfFullFlush = TRUE;
1126 }
1127  
1128 #if defined(STACK_USE_SSL)
1129 if(MyTCBStub.sslStubID != SSL_INVALID_ID)
1130 {
1131 TCPRAMCopy(MyTCBStub.sslTxHead, MyTCBStub.vMemoryMedium, (PTR_BASE)&byte, TCP_PIC_RAM, sizeof(byte));
1132 if(++MyTCBStub.sslTxHead >= MyTCBStub.bufferRxStart)
1133 MyTCBStub.sslTxHead = MyTCBStub.bufferTxStart;
1134 }
1135 else
1136 {
1137 TCPRAMCopy(MyTCBStub.txHead, MyTCBStub.vMemoryMedium, (PTR_BASE)&byte, TCP_PIC_RAM, sizeof(byte));
1138 if(++MyTCBStub.txHead >= MyTCBStub.bufferRxStart)
1139 MyTCBStub.txHead = MyTCBStub.bufferTxStart;
1140 }
1141 #else
1142 TCPRAMCopy(MyTCBStub.txHead, MyTCBStub.vMemoryMedium, (PTR_BASE)&byte, TCP_PIC_RAM, sizeof(byte));
1143 if(++MyTCBStub.txHead >= MyTCBStub.bufferRxStart)
1144 MyTCBStub.txHead = MyTCBStub.bufferTxStart;
1145 #endif
1146  
1147  
1148 // Send the last byte as a separate packet (likely will make the remote node send back ACK faster)
1149 if(wFreeTXSpace == 1u)
1150 {
1151 TCPFlush(hTCP);
1152 }
1153 // If not already enabled, start a timer so this data will
1154 // eventually get sent even if the application doens't call
1155 // TCPFlush()
1156 else if(!MyTCBStub.Flags.bTimer2Enabled)
1157 {
1158 MyTCBStub.Flags.bTimer2Enabled = TRUE;
1159 MyTCBStub.eventTime2 = (WORD)TickGetDiv256() + TCP_AUTO_TRANSMIT_TIMEOUT_VAL/256ull;
1160 }
1161  
1162 return TRUE;
1163 }
1164  
1165 /*****************************************************************************
1166 Function:
1167 WORD TCPPutArray(TCP_SOCKET hTCP, BYTE* data, WORD len)
1168  
1169 Description:
1170 Writes an array from RAM to a TCP socket.
1171  
1172 Precondition:
1173 TCP is initialized.
1174  
1175 Parameters:
1176 hTCP - The socket to which data is to be written.
1177 data - Pointer to the array to be written.
1178 len - Number of bytes to be written.
1179  
1180 Returns:
1181 The number of bytes written to the socket. If less than len, the
1182 buffer became full or the socket is not conected.
1183 ***************************************************************************/
1184 WORD TCPPutArray(TCP_SOCKET hTCP, BYTE* data, WORD len)
1185 {
1186 WORD wActualLen;
1187 WORD wFreeTXSpace;
1188 WORD wRightLen = 0;
1189  
1190 SyncTCBStub(hTCP);
1191  
1192 wFreeTXSpace = TCPIsPutReady(hTCP);
1193 if(wFreeTXSpace == 0u)
1194 {
1195 TCPFlush(hTCP);
1196 return 0;
1197 }
1198  
1199 wActualLen = wFreeTXSpace;
1200 if(wFreeTXSpace > len)
1201 wActualLen = len;
1202  
1203 // Send all current bytes if we are crossing half full
1204 // This is required to improve performance with the delayed
1205 // acknowledgement algorithm
1206 if((!MyTCBStub.Flags.bHalfFullFlush) && (wFreeTXSpace <= ((MyTCBStub.bufferRxStart-MyTCBStub.bufferTxStart)>>1)))
1207 {
1208 TCPFlush(hTCP);
1209 MyTCBStub.Flags.bHalfFullFlush = TRUE;
1210 }
1211  
1212 #if defined(STACK_USE_SSL)
1213 if(MyTCBStub.sslStubID != SSL_INVALID_ID)
1214 {
1215 // See if we need a two part put
1216 if(MyTCBStub.sslTxHead + wActualLen >= MyTCBStub.bufferRxStart)
1217 {
1218 wRightLen = MyTCBStub.bufferRxStart-MyTCBStub.sslTxHead;
1219 TCPRAMCopy(MyTCBStub.sslTxHead, MyTCBStub.vMemoryMedium, (PTR_BASE)data, TCP_PIC_RAM, wRightLen);
1220 data += wRightLen;
1221 wActualLen -= wRightLen;
1222 MyTCBStub.sslTxHead = MyTCBStub.bufferTxStart;
1223 }
1224  
1225 TCPRAMCopy(MyTCBStub.sslTxHead, MyTCBStub.vMemoryMedium, (PTR_BASE)data, TCP_PIC_RAM, wActualLen);
1226 MyTCBStub.sslTxHead += wActualLen;
1227 }
1228 else
1229 {
1230 // See if we need a two part put
1231 if(MyTCBStub.txHead + wActualLen >= MyTCBStub.bufferRxStart)
1232 {
1233 wRightLen = MyTCBStub.bufferRxStart-MyTCBStub.txHead;
1234 TCPRAMCopy(MyTCBStub.txHead, MyTCBStub.vMemoryMedium, (PTR_BASE)data, TCP_PIC_RAM, wRightLen);
1235 data += wRightLen;
1236 wActualLen -= wRightLen;
1237 MyTCBStub.txHead = MyTCBStub.bufferTxStart;
1238 }
1239  
1240 TCPRAMCopy(MyTCBStub.txHead, MyTCBStub.vMemoryMedium, (PTR_BASE)data, TCP_PIC_RAM, wActualLen);
1241 MyTCBStub.txHead += wActualLen;
1242 }
1243 #else
1244 // See if we need a two part put
1245 if(MyTCBStub.txHead + wActualLen >= MyTCBStub.bufferRxStart)
1246 {
1247 wRightLen = MyTCBStub.bufferRxStart-MyTCBStub.txHead;
1248 TCPRAMCopy(MyTCBStub.txHead, MyTCBStub.vMemoryMedium, (PTR_BASE)data, TCP_PIC_RAM, wRightLen);
1249 data += wRightLen;
1250 wActualLen -= wRightLen;
1251 MyTCBStub.txHead = MyTCBStub.bufferTxStart;
1252 }
1253  
1254 TCPRAMCopy(MyTCBStub.txHead, MyTCBStub.vMemoryMedium, (PTR_BASE)data, TCP_PIC_RAM, wActualLen);
1255 MyTCBStub.txHead += wActualLen;
1256 #endif
1257  
1258 // Send these bytes right now if we are out of TX buffer space
1259 if(wFreeTXSpace <= len)
1260 {
1261 TCPFlush(hTCP);
1262 }
1263 // If not already enabled, start a timer so this data will
1264 // eventually get sent even if the application doens't call
1265 // TCPFlush()
1266 else if(!MyTCBStub.Flags.bTimer2Enabled)
1267 {
1268 MyTCBStub.Flags.bTimer2Enabled = TRUE;
1269 MyTCBStub.eventTime2 = (WORD)TickGetDiv256() + TCP_AUTO_TRANSMIT_TIMEOUT_VAL/256ull;
1270 }
1271  
1272 return wActualLen + wRightLen;
1273 }
1274  
1275 /*****************************************************************************
1276 Function:
1277 WORD TCPPutROMArray(TCP_SOCKET hTCP, ROM BYTE* data, WORD len)
1278  
1279 Description:
1280 Writes an array from ROM to a TCP socket.
1281  
1282 Precondition:
1283 TCP is initialized.
1284  
1285 Parameters:
1286 hTCP - The socket to which data is to be written.
1287 data - Pointer to the array to be written.
1288 len - Number of bytes to be written.
1289  
1290 Returns:
1291 The number of bytes written to the socket. If less than len, the
1292 buffer became full or the socket is not conected.
1293  
1294 Remarks:
1295 This function is aliased to TCPPutArray on non-PIC18 platforms.
1296 ***************************************************************************/
1297 #if defined(__18CXX)
1298 WORD TCPPutROMArray(TCP_SOCKET hTCP, ROM BYTE* data, WORD len)
1299 {
1300 WORD wActualLen;
1301 WORD wFreeTXSpace;
1302 WORD wRightLen = 0;
1303  
1304 SyncTCBStub(hTCP);
1305  
1306 wFreeTXSpace = TCPIsPutReady(hTCP);
1307 if(wFreeTXSpace == 0u)
1308 {
1309 TCPFlush(hTCP);
1310 return 0;
1311 }
1312  
1313 // Send all current bytes if we are crossing half full
1314 // This is required to improve performance with the delayed
1315 // acknowledgement algorithm
1316 if((!MyTCBStub.Flags.bHalfFullFlush) && (wFreeTXSpace <= ((MyTCBStub.bufferRxStart-MyTCBStub.bufferTxStart)>>1)))
1317 {
1318 TCPFlush(hTCP);
1319 MyTCBStub.Flags.bHalfFullFlush = TRUE;
1320 }
1321  
1322 wActualLen = wFreeTXSpace;
1323 if(wFreeTXSpace > len)
1324 wActualLen = len;
1325  
1326 #if defined(STACK_USE_SSL)
1327 if(MyTCBStub.sslStubID != SSL_INVALID_ID)
1328 {
1329 // See if we need a two part put
1330 if(MyTCBStub.sslTxHead + wActualLen >= MyTCBStub.bufferRxStart)
1331 {
1332 wRightLen = MyTCBStub.bufferRxStart-MyTCBStub.sslTxHead;
1333 TCPRAMCopyROM(MyTCBStub.sslTxHead, MyTCBStub.vMemoryMedium, data, wRightLen);
1334 data += wRightLen;
1335 wActualLen -= wRightLen;
1336 MyTCBStub.sslTxHead = MyTCBStub.bufferTxStart;
1337 }
1338  
1339 TCPRAMCopyROM(MyTCBStub.sslTxHead, MyTCBStub.vMemoryMedium, data, wActualLen);
1340 MyTCBStub.sslTxHead += wActualLen;
1341 }
1342 else
1343 {
1344 // See if we need a two part put
1345 if(MyTCBStub.txHead + wActualLen >= MyTCBStub.bufferRxStart)
1346 {
1347 wRightLen = MyTCBStub.bufferRxStart-MyTCBStub.txHead;
1348 TCPRAMCopyROM(MyTCBStub.txHead, MyTCBStub.vMemoryMedium, data, wRightLen);
1349 data += wRightLen;
1350 wActualLen -= wRightLen;
1351 MyTCBStub.txHead = MyTCBStub.bufferTxStart;
1352 }
1353  
1354 TCPRAMCopyROM(MyTCBStub.txHead, MyTCBStub.vMemoryMedium, data, wActualLen);
1355 MyTCBStub.txHead += wActualLen;
1356 }
1357 #else
1358 // See if we need a two part put
1359 if(MyTCBStub.txHead + wActualLen >= MyTCBStub.bufferRxStart)
1360 {
1361 wRightLen = MyTCBStub.bufferRxStart-MyTCBStub.txHead;
1362 TCPRAMCopyROM(MyTCBStub.txHead, MyTCBStub.vMemoryMedium, data, wRightLen);
1363 data += wRightLen;
1364 wActualLen -= wRightLen;
1365 MyTCBStub.txHead = MyTCBStub.bufferTxStart;
1366 }
1367  
1368 TCPRAMCopyROM(MyTCBStub.txHead, MyTCBStub.vMemoryMedium, data, wActualLen);
1369 MyTCBStub.txHead += wActualLen;
1370 #endif
1371  
1372 // Send these bytes right now if we are out of TX buffer space
1373 if(wFreeTXSpace <= len)
1374 {
1375 TCPFlush(hTCP);
1376 }
1377 // If not already enabled, start a timer so this data will
1378 // eventually get sent even if the application doens't call
1379 // TCPFlush()
1380 else if(!MyTCBStub.Flags.bTimer2Enabled)
1381 {
1382 MyTCBStub.Flags.bTimer2Enabled = TRUE;
1383 MyTCBStub.eventTime2 = (WORD)TickGetDiv256() + TCP_AUTO_TRANSMIT_TIMEOUT_VAL/256ull;
1384 }
1385  
1386 return wActualLen + wRightLen;
1387 }
1388 #endif
1389  
1390 /*****************************************************************************
1391 Function:
1392 BYTE* TCPPutString(TCP_SOCKET hTCP, BYTE* data)
1393  
1394 Description:
1395 Writes a null-terminated string from RAM to a TCP socket. The
1396 null-terminator is not copied to the socket.
1397  
1398 Precondition:
1399 TCP is initialized.
1400  
1401 Parameters:
1402 hTCP - The socket to which data is to be written.
1403 data - Pointer to the string to be written.
1404  
1405 Returns:
1406 Pointer to the byte following the last byte written to the socket. If
1407 this pointer does not dereference to a NUL byte, the buffer became full
1408 or the socket is not connected.
1409  
1410 Remarks:
1411 The return value of this function differs from that of TCPPutArray. To
1412 write long strings in a single state, initialize the *data pointer to the
1413 first byte, then call this function repeatedly (breaking to the main
1414 stack loop after each call) until the return value dereferences to a NUL
1415 byte. Save the return value as the new starting *data pointer otherwise.
1416 ***************************************************************************/
1417 BYTE* TCPPutString(TCP_SOCKET hTCP, BYTE* data)
1418 {
1419 return data + TCPPutArray(hTCP, data, strlen((char*)data));
1420 }
1421  
1422 /*****************************************************************************
1423 Function:
1424 BYTE* TCPPutROMString(TCP_SOCKET hTCP, ROM BYTE* data)
1425  
1426 Description:
1427 Writes a null-terminated string from ROM to a TCP socket. The
1428 null-terminator is not copied to the socket.
1429  
1430 Precondition:
1431 TCP is initialized.
1432  
1433 Parameters:
1434 hTCP - The socket to which data is to be written.
1435 data - Pointer to the string to be written.
1436  
1437 Returns:
1438 Pointer to the byte following the last byte written to the socket. If
1439 this pointer does not dereference to a NUL byte, the buffer became full
1440 or the socket is not connected.
1441  
1442 Remarks:
1443 The return value of this function differs from that of TCPPutArray. To
1444 write long strings in a single state, initialize the *data pointer to the
1445 first byte, then call this function repeatedly (breaking to the main
1446 stack loop after each call) until the return value dereferences to a NUL
1447 byte. Save the return value as the new starting *data pointer otherwise.
1448  
1449 This function is aliased to TCPPutString on non-PIC18 platforms.
1450 ***************************************************************************/
1451 #if defined(__18CXX)
1452 ROM BYTE* TCPPutROMString(TCP_SOCKET hTCP, ROM BYTE* data)
1453 {
1454 return data + TCPPutROMArray(hTCP, data, strlenpgm((ROM char*)data));
1455 }
1456 #endif
1457  
1458 /*****************************************************************************
1459 Function:
1460 WORD TCPGetTxFIFOFull(TCP_SOCKET hTCP)
1461  
1462 Description:
1463 Determines how many bytes are pending in the TCP TX FIFO.
1464  
1465 Precondition:
1466 TCP is initialized.
1467  
1468 Parameters:
1469 hTCP - The socket to check.
1470  
1471 Returns:
1472 Number of bytes pending to be flushed in the TCP TX FIFO.
1473 ***************************************************************************/
1474 WORD TCPGetTxFIFOFull(TCP_SOCKET hTCP)
1475 {
1476 WORD wDataLen;
1477 WORD wFIFOSize;
1478  
1479 SyncTCBStub(hTCP);
1480  
1481 // Calculate total usable FIFO size
1482 wFIFOSize = MyTCBStub.bufferRxStart - MyTCBStub.bufferTxStart - 1;
1483  
1484 // Find out how many data bytes are free in the TX FIFO
1485 wDataLen = TCPIsPutReady(hTCP);
1486  
1487 return wFIFOSize - wDataLen;
1488 }
1489  
1490  
1491  
1492 /****************************************************************************
1493 Section:
1494 Receive Functions
1495 ***************************************************************************/
1496  
1497 /*****************************************************************************
1498 Function:
1499 void TCPDiscard(TCP_SOCKET hTCP)
1500  
1501 Description:
1502 Discards any pending data in the TCP RX FIFO.
1503  
1504 Precondition:
1505 TCP is initialized.
1506  
1507 Parameters:
1508 hTCP - The socket whose RX FIFO is to be cleared.
1509  
1510 Returns:
1511 None
1512 ***************************************************************************/
1513 void TCPDiscard(TCP_SOCKET hTCP)
1514 {
1515 if(TCPIsGetReady(hTCP))
1516 {
1517 SyncTCBStub(hTCP);
1518  
1519 // Delete all data in the RX buffer
1520 MyTCBStub.rxTail = MyTCBStub.rxHead;
1521  
1522 // Send a Window update message to the remote node
1523 SendTCP(ACK, SENDTCP_RESET_TIMERS);
1524 }
1525 }
1526  
1527  
1528 /*****************************************************************************
1529 Function:
1530 void WORD TCPIsGetReady(TCP_SOCKET hTCP)
1531  
1532 Summary:
1533 Determines how many bytes can be read from the TCP RX buffer.
1534  
1535 Description:
1536 Call this function to determine how many bytes can be read from the
1537 TCP RX buffer. If this function returns zero, the application must
1538 return to the main stack loop before continuing in order to wait for
1539 more data to arrive.
1540  
1541 Precondition:
1542 TCP is initialized.
1543  
1544 Parameters:
1545 hTCP - The socket to check.
1546  
1547 Returns:
1548 The number of bytes available to be read from the TCP RX buffer.
1549 ***************************************************************************/
1550 WORD TCPIsGetReady(TCP_SOCKET hTCP)
1551 {
1552 SyncTCBStub(hTCP);
1553  
1554 if(MyTCBStub.rxHead >= MyTCBStub.rxTail)
1555 return MyTCBStub.rxHead - MyTCBStub.rxTail;
1556 else
1557 return (MyTCBStub.bufferEnd - MyTCBStub.rxTail + 1) + (MyTCBStub.rxHead - MyTCBStub.bufferRxStart);
1558 }
1559  
1560  
1561 /*****************************************************************************
1562 Function:
1563 BOOL TCPGet(TCP_SOCKET hTCP, BYTE* byte)
1564  
1565 Description:
1566 Retrieves a single byte to a TCP socket.
1567  
1568 Precondition:
1569 TCP is initialized.
1570  
1571 Parameters:
1572 hTCP - The socket from which to read.
1573 byte - Pointer to location in which the read byte should be stored.
1574  
1575 Return Values:
1576 TRUE - A byte was read from the buffer.
1577 FALSE - The buffer was empty, or the socket is not connected.
1578 ***************************************************************************/
1579 BOOL TCPGet(TCP_SOCKET hTCP, BYTE* byte)
1580 {
1581 WORD wGetReadyCount;
1582  
1583 // See if there is any data which can be read
1584 wGetReadyCount = TCPIsGetReady(hTCP);
1585 if(wGetReadyCount == 0u)
1586 return FALSE;
1587  
1588 SyncTCBStub(hTCP);
1589  
1590 if(byte)
1591 TCPRAMCopy((PTR_BASE)byte, TCP_PIC_RAM, MyTCBStub.rxTail, MyTCBStub.vMemoryMedium, 1);
1592 if(++MyTCBStub.rxTail > MyTCBStub.bufferEnd)
1593 MyTCBStub.rxTail = MyTCBStub.bufferRxStart;
1594  
1595 // Send a window update if we've run out of data
1596 if(wGetReadyCount == 1u)
1597 {
1598 MyTCBStub.Flags.bTXASAPWithoutTimerReset = 1;
1599 }
1600 // If not already enabled, start a timer so a window
1601 // update will get sent to the remote node at some point
1602 else if(!MyTCBStub.Flags.bTimer2Enabled)
1603 {
1604 MyTCBStub.Flags.bTimer2Enabled = TRUE;
1605 MyTCBStub.eventTime2 = (WORD)TickGetDiv256() + TCP_WINDOW_UPDATE_TIMEOUT_VAL/256ull;
1606 }
1607  
1608  
1609 return TRUE;
1610 }
1611  
1612  
1613 /*****************************************************************************
1614 Function:
1615 WORD TCPGetArray(TCP_SOCKET hTCP, BYTE* buffer, WORD len)
1616  
1617 Description:
1618 Reads an array of data bytes from a TCP socket's receive FIFO. The data
1619 is removed from the FIFO in the process.
1620  
1621 Precondition:
1622 TCP is initialized.
1623  
1624 Parameters:
1625 hTCP - The socket from which data is to be read.
1626 buffer - Pointer to the array to store data that was read.
1627 len - Number of bytes to be read.
1628  
1629 Returns:
1630 The number of bytes read from the socket. If less than len, the
1631 RX FIFO buffer became empty or the socket is not conected.
1632 ***************************************************************************/
1633 WORD TCPGetArray(TCP_SOCKET hTCP, BYTE* buffer, WORD len)
1634 {
1635 WORD wGetReadyCount;
1636 WORD RightLen = 0;
1637  
1638 // See if there is any data which can be read
1639 wGetReadyCount = TCPIsGetReady(hTCP);
1640 if(wGetReadyCount == 0u)
1641 return 0x0000u;
1642  
1643 SyncTCBStub(hTCP);
1644  
1645 // Make sure we don't try to read more data than is available
1646 if(len > wGetReadyCount)
1647 len = wGetReadyCount;
1648  
1649 // See if we need a two part get
1650 if(MyTCBStub.rxTail + len > MyTCBStub.bufferEnd)
1651 {
1652 RightLen = MyTCBStub.bufferEnd - MyTCBStub.rxTail + 1;
1653 if(buffer)
1654 {
1655 TCPRAMCopy((PTR_BASE)buffer, TCP_PIC_RAM, MyTCBStub.rxTail, MyTCBStub.vMemoryMedium, RightLen);
1656 buffer += RightLen;
1657 }
1658 len -= RightLen;
1659 MyTCBStub.rxTail = MyTCBStub.bufferRxStart;
1660 }
1661  
1662 if(buffer)
1663 TCPRAMCopy((PTR_BASE)buffer, TCP_PIC_RAM, MyTCBStub.rxTail, MyTCBStub.vMemoryMedium, len);
1664 MyTCBStub.rxTail += len;
1665 len += RightLen;
1666  
1667 // Send a window update if we've run low on data
1668 if(wGetReadyCount - len <= len)
1669 {
1670 MyTCBStub.Flags.bTXASAPWithoutTimerReset = 1;
1671 }
1672 else if(!MyTCBStub.Flags.bTimer2Enabled)
1673 // If not already enabled, start a timer so a window
1674 // update will get sent to the remote node at some point
1675 {
1676 MyTCBStub.Flags.bTimer2Enabled = TRUE;
1677 MyTCBStub.eventTime2 = (WORD)TickGetDiv256() + TCP_WINDOW_UPDATE_TIMEOUT_VAL/256ull;
1678 }
1679  
1680 return len;
1681 }
1682  
1683  
1684 /*****************************************************************************
1685 Function:
1686 WORD TCPGetRxFIFOFree(TCP_SOCKET hTCP)
1687  
1688 Description:
1689 Determines how many bytes are free in the RX FIFO.
1690  
1691 Precondition:
1692 TCP is initialized.
1693  
1694 Parameters:
1695 hTCP - The socket to check.
1696  
1697 Returns:
1698 The number of bytes free in the TCP RX FIFO. If zero, no additional
1699 data can be received until the application removes some data using one
1700 of the TCPGet family functions.
1701 ***************************************************************************/
1702 WORD TCPGetRxFIFOFree(TCP_SOCKET hTCP)
1703 {
1704 WORD wDataLen;
1705 WORD wFIFOSize;
1706  
1707 SyncTCBStub(hTCP);
1708  
1709 // Calculate total usable FIFO size
1710 wFIFOSize = MyTCBStub.bufferEnd - MyTCBStub.bufferRxStart;
1711  
1712 #if defined(STACK_USE_SSL)
1713 {
1714 PTR_BASE SSLtemp = MyTCBStub.rxHead;
1715  
1716 // Move SSL pointer to determine full buffer size
1717 if(MyTCBStub.sslStubID != SSL_INVALID_ID)
1718 MyTCBStub.rxHead = MyTCBStub.sslRxHead;
1719  
1720 // Find out how many data bytes are actually in the RX FIFO
1721 wDataLen = TCPIsGetReady(hTCP);
1722  
1723 // Move SSL pointer back to proper location (if we changed it)
1724 MyTCBStub.rxHead = SSLtemp;
1725 }
1726 #else
1727 {
1728 // Find out how many data bytes are actually in the RX FIFO
1729 wDataLen = TCPIsGetReady(hTCP);
1730 }
1731 #endif
1732  
1733 // Perform the calculation
1734 return wFIFOSize - wDataLen;
1735 }
1736  
1737 /*****************************************************************************
1738 Function:
1739 WORD TCPPeekArray(TCP_SOCKET hTCP, BYTE *vBuffer, WORD wLen, WORD wStart)
1740  
1741 Summary:
1742 Reads a specified number of data bytes from the TCP RX FIFO without
1743 removing them from the buffer.
1744  
1745 Description:
1746 Reads a specified number of data bytes from the TCP RX FIFO without
1747 removing them from the buffer. No TCP control actions are taken as a
1748 result of this function (ex: no window update is sent to the remote node).
1749  
1750 Precondition:
1751 TCP is initialized.
1752  
1753 Parameters:
1754 hTCP - The socket to peak from (read without removing from stream).
1755 vBuffer - Destination to write the peeked data bytes.
1756 wLen - Length of bytes to peak from the RX FIFO and copy to vBuffer.
1757 wStart - Zero-indexed starting position within the FIFO to start peeking
1758 from.
1759  
1760 Return Values:
1761 Number of bytes actually peeked from the stream and copied to vBuffer.
1762 This value can be less than wLen if wStart + wLen is greater than the
1763 deepest possible character in the RX FIFO.
1764  
1765 Remarks:
1766 None
1767 ***************************************************************************/
1768 WORD TCPPeekArray(TCP_SOCKET hTCP, BYTE *vBuffer, WORD wLen, WORD wStart)
1769 {
1770 PTR_BASE ptrRead;
1771 WORD w;
1772 WORD wBytesUntilWrap;
1773  
1774 if(wLen == 0u)
1775 return 0u;
1776  
1777 SyncTCBStub(hTCP);
1778  
1779 // Find out how many bytes are in the RX FIFO and decrease read length
1780 // if the start offset + read length is beyond the end of the FIFO
1781 w = TCPIsGetReady(hTCP);
1782 if(wStart + wLen > w)
1783 wLen = w - wStart;
1784  
1785 // Find the read start location
1786 ptrRead = MyTCBStub.rxTail + wStart;
1787 if(ptrRead > MyTCBStub.bufferEnd)
1788 ptrRead -= MyTCBStub.bufferEnd - MyTCBStub.bufferRxStart + 1;
1789  
1790 // Calculate how many bytes can be read in a single go
1791 wBytesUntilWrap = MyTCBStub.bufferEnd - ptrRead + 1;
1792 if(wLen <= wBytesUntilWrap)
1793 {
1794 // Read all at once
1795 TCPRAMCopy((PTR_BASE)vBuffer, TCP_PIC_RAM, ptrRead, MyTCBStub.vMemoryMedium, wLen);
1796 }
1797 else
1798 {
1799 // Read all bytes up to the wrap position and then read remaining bytes
1800 // at the start of the buffer
1801 TCPRAMCopy((PTR_BASE)vBuffer, TCP_PIC_RAM, ptrRead, MyTCBStub.vMemoryMedium, wBytesUntilWrap);
1802 TCPRAMCopy((PTR_BASE)vBuffer+wBytesUntilWrap, TCP_PIC_RAM, MyTCBStub.bufferRxStart, MyTCBStub.vMemoryMedium, wLen - wBytesUntilWrap);
1803 }
1804  
1805 return wLen;
1806 }
1807  
1808 /*****************************************************************************
1809 Function:
1810 BYTE TCPPeek(TCP_SOCKET hTCP, WORD wStart)
1811  
1812 Summary:
1813 Peaks at one byte in the TCP RX FIFO without removing it from the buffer.
1814  
1815 Description:
1816 Peaks at one byte in the TCP RX FIFO without removing it from the buffer.
1817  
1818 Precondition:
1819 TCP is initialized.
1820  
1821 Parameters:
1822 hTCP - The socket to peak from (read without removing from stream).
1823 wStart - Zero-indexed starting position within the FIFO to peek from.
1824  
1825 Return Values:
1826 Byte peeked from the RX FIFO. If there is no data in the buffer or an
1827 illegal wStart starting offset is given, then an indeterminate value is
1828 returned. The caller must ensure that valid parameters are passed to avoid
1829 (i.e ensure that TCPIsGetReady() returns a number that is less than wStart
1830 before calling TCPPeek()).
1831  
1832 Remarks:
1833 Use the TCPPeekArray() function to read more than one byte. It will
1834 perform better than calling TCPPeek() in a loop.
1835 ***************************************************************************/
1836 BYTE TCPPeek(TCP_SOCKET hTCP, WORD wStart)
1837 {
1838 BYTE i;
1839  
1840 TCPPeekArray(hTCP, &i, 1, wStart);
1841 return i;
1842 }
1843  
1844  
1845 /****************************************************************************
1846 Section:
1847 Search Functions
1848 ***************************************************************************/
1849  
1850 /*****************************************************************************
1851 Function:
1852 WORD TCPFindArrayEx(TCP_SOCKET hTCP, BYTE* cFindArray, WORD wLen,
1853 WORD wStart, WORD wSearchLen, BOOL bTextCompare)
1854  
1855 Summary:
1856 Searches for a string in the TCP RX buffer.
1857  
1858 Description:
1859 This function finds the first occurrance of an array of bytes in the
1860 TCP RX buffer. It can be used by an application to abstract searches
1861 out of their own application code. For increased efficiency, the
1862 function is capable of limiting the scope of search to a specific
1863 range of bytes. It can also perform a case-insensitive search if
1864 required.
1865  
1866 For example, if the buffer contains "I love PIC MCUs!" and the search
1867 array is "love" with a length of 4, a value of 2 will be returned.
1868  
1869 Precondition:
1870 TCP is initialized.
1871  
1872 Parameters:
1873 hTCP - The socket to search within.
1874 cFindArray - The array of bytes to find in the buffer.
1875 wLen - Length of cFindArray.
1876 wStart - Zero-indexed starting position within the buffer.
1877 wSearchLen - Length from wStart to search in the buffer.
1878 bTextCompare - TRUE for case-insensitive text search, FALSE for binary search
1879  
1880 Return Values:
1881 0xFFFF - Search array not found
1882 Otherwise - Zero-indexed position of the first occurrance
1883  
1884 Remarks:
1885 Since this function usually must transfer data from external storage
1886 to internal RAM for comparison, its performance degrades significantly
1887 when the buffer is full and the array is not found. For better
1888 performance, try to search for characters that are expected to exist or
1889 limit the scope of the search as much as possible. The HTTP2 module,
1890 for example, uses this function to parse headers. However, it searches
1891 for newlines, then the separating colon, then reads the header name to
1892 RAM for final comparison. This has proven to be significantly faster
1893 than searching for full header name strings outright.
1894 ***************************************************************************/
1895 WORD TCPFindArrayEx(TCP_SOCKET hTCP, BYTE* cFindArray, WORD wLen, WORD wStart, WORD wSearchLen, BOOL bTextCompare)
1896 {
1897 PTR_BASE ptrRead;
1898 WORD wDataLen;
1899 WORD wBytesUntilWrap;
1900 PTR_BASE ptrLocation;
1901 WORD wLenStart;
1902 BYTE *cFindArrayStart;
1903 BYTE i, j, k;
1904 BOOL isFinding;
1905 BYTE buffer[32];
1906  
1907 if(wLen == 0u)
1908 return 0u;
1909  
1910 SyncTCBStub(hTCP);
1911  
1912 // Find out how many bytes are in the RX FIFO and return
1913 // immediately if we won't possibly find a match
1914 wDataLen = TCPIsGetReady(hTCP) - wStart;
1915 if(wDataLen < wLen)
1916 return 0xFFFFu;
1917 if(wSearchLen && (wDataLen > wSearchLen))
1918 wDataLen = wSearchLen;
1919  
1920 ptrLocation = MyTCBStub.rxTail + wStart;
1921 if(ptrLocation > MyTCBStub.bufferEnd)
1922 ptrLocation -= MyTCBStub.bufferEnd - MyTCBStub.bufferRxStart + 1;
1923 ptrRead = ptrLocation;
1924 wBytesUntilWrap = MyTCBStub.bufferEnd - ptrLocation + 1;
1925 ptrLocation = wStart;
1926 wLenStart = wLen;
1927 cFindArrayStart = cFindArray;
1928 j = *cFindArray++;
1929 isFinding = FALSE;
1930 if(bTextCompare)
1931 {
1932 if(j >= 'a' && j <= 'z')
1933 j += 'A'-'a';
1934 }
1935  
1936 // Search for the array
1937 while(1)
1938 {
1939 // Figure out how big of a chunk to read
1940 k = sizeof(buffer);
1941 if(k > wBytesUntilWrap)
1942 k = wBytesUntilWrap;
1943 if((WORD)k > wDataLen)
1944 k = wDataLen;
1945  
1946 // Read a chunk of data into the buffer
1947 TCPRAMCopy((PTR_BASE)buffer, TCP_PIC_RAM, ptrRead, MyTCBStub.vMemoryMedium, (WORD)k);
1948 ptrRead += k;
1949 wBytesUntilWrap -= k;
1950  
1951 if(wBytesUntilWrap == 0u)
1952 {
1953 ptrRead = MyTCBStub.bufferRxStart;
1954 wBytesUntilWrap = 0xFFFFu;
1955 }
1956  
1957 // Convert everything to uppercase
1958 if(bTextCompare)
1959 {
1960 for(i = 0; i < k; i++)
1961 {
1962 if(buffer[i] >= 'a' && buffer[i] <= 'z')
1963 buffer[i] += 'A'-'a';
1964  
1965 if(j == buffer[i])
1966 {
1967 if(--wLen == 0u)
1968 return ptrLocation-wLenStart + i + 1;
1969 j = *cFindArray++;
1970 isFinding = TRUE;
1971 if(j >= 'a' && j <= 'z')
1972 j += 'A'-'a';
1973 }
1974 else
1975 {
1976 wLen = wLenStart;
1977 if(isFinding)
1978 {
1979 cFindArray = cFindArrayStart;
1980 j = *cFindArray++;
1981 if(j >= 'a' && j <= 'z')
1982 j += 'A'-'a';
1983 isFinding = FALSE;
1984 }
1985 }
1986 }
1987 }
1988 else // Compare as is
1989 {
1990 for(i = 0; i < k; i++)
1991 {
1992 if(j == buffer[i])
1993 {
1994 if(--wLen == 0u)
1995 return ptrLocation-wLenStart + i + 1;
1996 j = *cFindArray++;
1997 isFinding = TRUE;
1998 }
1999 else
2000 {
2001 wLen = wLenStart;
2002 if(isFinding)
2003 {
2004 cFindArray = cFindArrayStart;
2005 j = *cFindArray++;
2006 isFinding = FALSE;
2007 }
2008 }
2009 }
2010 }
2011  
2012 // Check to see if it is impossible to find a match
2013 wDataLen -= k;
2014 if(wDataLen < wLen)
2015 return 0xFFFFu;
2016  
2017 ptrLocation += k;
2018 }
2019 }
2020  
2021 /*****************************************************************************
2022 Function:
2023 WORD TCPFindROMArrayEx(TCP_SOCKET hTCP, BYTE* cFindArray, WORD wLen,
2024 WORD wStart, WORD wSearchLen, BOOL bTextCompare)
2025  
2026 Summary:
2027 Searches for a ROM string in the TCP RX buffer.
2028  
2029 Description:
2030 This function finds the first occurrance of an array of bytes in the
2031 TCP RX buffer. It can be used by an application to abstract searches
2032 out of their own application code. For increased efficiency, the
2033 function is capable of limiting the scope of search to a specific
2034 range of bytes. It can also perform a case-insensitive search if
2035 required.
2036  
2037 For example, if the buffer contains "I love PIC MCUs!" and the search
2038 array is "love" with a length of 4, a value of 2 will be returned.
2039  
2040 Precondition:
2041 TCP is initialized.
2042  
2043 Parameters:
2044 hTCP - The socket to search within.
2045 cFindArray - The array of bytes to find in the buffer.
2046 wLen - Length of cFindArray.
2047 wStart - Zero-indexed starting position within the buffer.
2048 wSearchLen - Length from wStart to search in the buffer.
2049 bTextCompare - TRUE for case-insensitive text search, FALSE for binary search
2050  
2051 Return Values:
2052 0xFFFF - Search array not found
2053 Otherwise - Zero-indexed position of the first occurrance
2054  
2055 Remarks:
2056 Since this function usually must transfer data from external storage
2057 to internal RAM for comparison, its performance degrades significantly
2058 when the buffer is full and the array is not found. For better
2059 performance, try to search for characters that are expected to exist or
2060 limit the scope of the search as much as possible. The HTTP2 module,
2061 for example, uses this function to parse headers. However, it searches
2062 for newlines, then the separating colon, then reads the header name to
2063 RAM for final comparison. This has proven to be significantly faster
2064 than searching for full header name strings outright.
2065  
2066 This function is aliased to TCPFindArrayEx on non-PIC18 platforms.
2067 ***************************************************************************/
2068 #if defined(__18CXX)
2069 WORD TCPFindROMArrayEx(TCP_SOCKET hTCP, ROM BYTE* cFindArray, WORD wLen, WORD wStart, WORD wSearchLen, BOOL bTextCompare)
2070 {
2071 PTR_BASE ptrRead;
2072 WORD wDataLen;
2073 WORD wBytesUntilWrap;
2074 PTR_BASE ptrLocation;
2075 WORD wLenStart;
2076 ROM BYTE *cFindArrayStart;
2077 BYTE i, j, k;
2078 BOOL isFinding;
2079 BYTE buffer[32];
2080  
2081 if(wLen == 0u)
2082 return 0u;
2083  
2084 SyncTCBStub(hTCP);
2085  
2086 // Find out how many bytes are in the RX FIFO and return
2087 // immediately if we won't possibly find a match
2088 wDataLen = TCPIsGetReady(hTCP) - wStart;
2089 if(wDataLen < wLen)
2090 return 0xFFFFu;
2091 if(wSearchLen && (wDataLen > wSearchLen))
2092 wDataLen = wSearchLen;
2093  
2094 ptrLocation = MyTCBStub.rxTail + wStart;
2095 if(ptrLocation > MyTCBStub.bufferEnd)
2096 ptrLocation -= MyTCBStub.bufferEnd - MyTCBStub.bufferRxStart + 1;
2097 ptrRead = ptrLocation;
2098 wBytesUntilWrap = MyTCBStub.bufferEnd - ptrLocation + 1;
2099 ptrLocation = wStart;
2100 wLenStart = wLen;
2101 cFindArrayStart = cFindArray;
2102 j = *cFindArray++;
2103 isFinding = FALSE;
2104 if(bTextCompare)
2105 {
2106 if(j >= 'a' && j <= 'z')
2107 j += 'A'-'a';
2108 }
2109  
2110 // Search for the array
2111 while(1)
2112 {
2113 // Figure out how big of a chunk to read
2114 k = sizeof(buffer);
2115 if(k > wBytesUntilWrap)
2116 k = wBytesUntilWrap;
2117 if((WORD)k > wDataLen)
2118 k = wDataLen;
2119  
2120 // Read a chunk of data into the buffer
2121 TCPRAMCopy((PTR_BASE)buffer, TCP_PIC_RAM, ptrRead, MyTCBStub.vMemoryMedium, (WORD)k);
2122 ptrRead += k;
2123 wBytesUntilWrap -= k;
2124  
2125 if(wBytesUntilWrap == 0u)
2126 {
2127 ptrRead = MyTCBStub.bufferRxStart;
2128 wBytesUntilWrap = 0xFFFFu;
2129 }
2130  
2131 // Convert everything to uppercase
2132 if(bTextCompare)
2133 {
2134 for(i = 0; i < k; i++)
2135 {
2136 if(buffer[i] >= 'a' && buffer[i] <= 'z')
2137 buffer[i] += 'A'-'a';
2138  
2139 if(j == buffer[i])
2140 {
2141 if(--wLen == 0u)
2142 return ptrLocation-wLenStart + i + 1;
2143 j = *cFindArray++;
2144 isFinding = TRUE;
2145 if(j >= 'a' && j <= 'z')
2146 j += 'A'-'a';
2147 }
2148 else
2149 {
2150 wLen = wLenStart;
2151 if(isFinding)
2152 {
2153 cFindArray = cFindArrayStart;
2154 j = *cFindArray++;
2155 if(j >= 'a' && j <= 'z')
2156 j += 'A'-'a';
2157 isFinding = FALSE;
2158 }
2159 }
2160 }
2161 }
2162 else // Compare as is
2163 {
2164 for(i = 0; i < k; i++)
2165 {
2166 if(j == buffer[i])
2167 {
2168 if(--wLen == 0u)
2169 return ptrLocation-wLenStart + i + 1;
2170 j = *cFindArray++;
2171 isFinding = TRUE;
2172 }
2173 else
2174 {
2175 wLen = wLenStart;
2176 if(isFinding)
2177 {
2178 cFindArray = cFindArrayStart;
2179 j = *cFindArray++;
2180 isFinding = FALSE;
2181 }
2182 }
2183 }
2184 }
2185  
2186 // Check to see if it is impossible to find a match
2187 wDataLen -= k;
2188 if(wDataLen < wLen)
2189 return 0xFFFFu;
2190  
2191 ptrLocation += k;
2192 }
2193 }
2194 #endif
2195  
2196  
2197 /*****************************************************************************
2198 Function:
2199 WORD TCPFindEx(TCP_SOCKET hTCP, BYTE cFind,
2200 WORD wStart, WORD wSearchLen, BOOL bTextCompare)
2201  
2202 Summary:
2203 Searches for a byte in the TCP RX buffer.
2204  
2205 Description:
2206 This function finds the first occurrance of a byte in the TCP RX
2207 buffer. It can be used by an application to abstract searches
2208 out of their own application code. For increased efficiency, the
2209 function is capable of limiting the scope of search to a specific
2210 range of bytes. It can also perform a case-insensitive search if
2211 required.
2212  
2213 For example, if the buffer contains "I love PIC MCUs!" and the cFind
2214 byte is ' ', a value of 1 will be returned.
2215  
2216 Precondition:
2217 TCP is initialized.
2218  
2219 Parameters:
2220 hTCP - The socket to search within.
2221 cFind - The byte to find in the buffer.
2222 wStart - Zero-indexed starting position within the buffer.
2223 wSearchLen - Length from wStart to search in the buffer.
2224 bTextCompare - TRUE for case-insensitive text search, FALSE for binary search
2225  
2226 Return Values:
2227 0xFFFF - Search array not found
2228 Otherwise - Zero-indexed position of the first occurrance
2229  
2230 Remarks:
2231 Since this function usually must transfer data from external storage
2232 to internal RAM for comparison, its performance degrades significantly
2233 when the buffer is full and the array is not found. For better
2234 performance, try to search for characters that are expected to exist or
2235 limit the scope of the search as much as possible. The HTTP2 module,
2236 for example, uses this function to parse headers. However, it searches
2237 for newlines, then the separating colon, then reads the header name to
2238 RAM for final comparison. This has proven to be significantly faster
2239 than searching for full header name strings outright.
2240 ***************************************************************************/
2241 WORD TCPFindEx(TCP_SOCKET hTCP, BYTE cFind, WORD wStart, WORD wSearchLen, BOOL bTextCompare)
2242 {
2243 return TCPFindArrayEx(hTCP, &cFind, sizeof(cFind), wStart, wSearchLen, bTextCompare);
2244 }
2245  
2246  
2247  
2248 /****************************************************************************
2249 Section:
2250 Data Processing Functions
2251 ***************************************************************************/
2252  
2253 /*****************************************************************************
2254 Function:
2255 void TCPTick(void)
2256  
2257 Summary:
2258 Performs periodic TCP tasks.
2259  
2260 Description:
2261 This function performs any required periodic TCP tasks. Each
2262 socket's state machine is checked, and any elapsed timeout periods
2263 are handled.
2264  
2265 Precondition:
2266 TCP is initialized.
2267  
2268 Parameters:
2269 None
2270  
2271 Returns:
2272 None
2273 ***************************************************************************/
2274 void TCPTick(void)
2275 {
2276 TCP_SOCKET hTCP;
2277 BOOL bRetransmit;
2278 BOOL bCloseSocket;
2279 BYTE vFlags;
2280 WORD w;
2281  
2282 // Periodically all "not closed" sockets must perform timed operations
2283 for(hTCP = 0; hTCP < TCP_SOCKET_COUNT; hTCP++)
2284 {
2285 SyncTCBStub(hTCP);
2286  
2287 // Handle any SSL Processing and Message Transmission
2288 #if defined(STACK_USE_SSL)
2289 if(MyTCBStub.sslStubID != SSL_INVALID_ID)
2290 {
2291 // Handle any periodic tasks, such as RSA operations
2292 SSLPeriodic(hTCP, MyTCBStub.sslStubID);
2293  
2294 // If unsent data is waiting, transmit it as an application record
2295 if(MyTCBStub.sslTxHead != MyTCBStub.txHead && TCPSSLGetPendingTxSize(hTCP) != 0u)
2296 SSLTxRecord(hTCP, MyTCBStub.sslStubID, SSL_APPLICATION);
2297  
2298 // If an SSL message is requested, send it now
2299 if(MyTCBStub.sslReqMessage != SSL_NO_MESSAGE)
2300 SSLTxMessage(hTCP, MyTCBStub.sslStubID, MyTCBStub.sslReqMessage);
2301 }
2302 #endif
2303  
2304 vFlags = 0x00;
2305 bRetransmit = FALSE;
2306 bCloseSocket = FALSE;
2307  
2308 // Transmit ASAP data if the medium is available
2309 if(MyTCBStub.Flags.bTXASAP || MyTCBStub.Flags.bTXASAPWithoutTimerReset)
2310 {
2311 if(MACIsTxReady())
2312 {
2313 vFlags = ACK;
2314 bRetransmit = MyTCBStub.Flags.bTXASAPWithoutTimerReset;
2315 }
2316 }
2317  
2318 // Perform any needed window updates and data transmissions
2319 if(MyTCBStub.Flags.bTimer2Enabled)
2320 {
2321 // See if the timeout has occured, and we need to send a new window update and pending data
2322 if((SHORT)(MyTCBStub.eventTime2 - (WORD)TickGetDiv256()) <= (SHORT)0)
2323 vFlags = ACK;
2324 }
2325  
2326 // Process Delayed ACKnowledgement timer
2327 if(MyTCBStub.Flags.bDelayedACKTimerEnabled)
2328 {
2329 // See if the timeout has occured and delayed ACK needs to be sent
2330 if((SHORT)(MyTCBStub.OverlappedTimers.delayedACKTime - (WORD)TickGetDiv256()) <= (SHORT)0)
2331 vFlags = ACK;
2332 }
2333  
2334 // Process TCP_CLOSE_WAIT timer
2335 if(MyTCBStub.smState == TCP_CLOSE_WAIT)
2336 {
2337 // Automatically close the socket on our end if the application
2338 // fails to call TCPDisconnect() is a reasonable amount of time.
2339 if((SHORT)(MyTCBStub.OverlappedTimers.closeWaitTime - (WORD)TickGetDiv256()) <= (SHORT)0)
2340 {
2341 vFlags = FIN | ACK;
2342 MyTCBStub.smState = TCP_LAST_ACK;
2343 }
2344 }
2345  
2346 // Process listening server sockets that might have a SYN waiting in the SYNQueue[]
2347 #if TCP_SYN_QUEUE_MAX_ENTRIES
2348 if(MyTCBStub.smState == TCP_LISTEN)
2349 {
2350 for(w = 0; w < TCP_SYN_QUEUE_MAX_ENTRIES; w++)
2351 {
2352 // Abort search if there are no more valid records
2353 if(SYNQueue[w].wDestPort == 0u)
2354 break;
2355  
2356 // Stop searching if this SYN queue entry can be used by this socket
2357 #if defined(STACK_USE_SSL_SERVER)
2358 if(SYNQueue[w].wDestPort == MyTCBStub.remoteHash.Val || SYNQueue[w].wDestPort == MyTCBStub.sslTxHead)
2359 #else
2360 if(SYNQueue[w].wDestPort == MyTCBStub.remoteHash.Val)
2361 #endif
2362 {
2363 // Set up our socket and generate a reponse SYN+ACK packet
2364 SyncTCB();
2365  
2366 #if defined(STACK_USE_SSL_SERVER)
2367 // If this matches the SSL port, make sure that can be configured
2368 // before continuing. If not, break and leave this in the queue
2369 if(SYNQueue[w].wDestPort == MyTCBStub.sslTxHead && !TCPStartSSLServer(hTCP))
2370 break;
2371 #endif
2372  
2373 memcpy((void*)&MyTCB.remote.niRemoteMACIP, (void*)&SYNQueue[w].niSourceAddress, sizeof(NODE_INFO));
2374 MyTCB.remotePort.Val = SYNQueue[w].wSourcePort;
2375 MyTCB.RemoteSEQ = SYNQueue[w].dwSourceSEQ + 1;
2376 MyTCBStub.remoteHash.Val = (MyTCB.remote.niRemoteMACIP.IPAddr.w[1] + MyTCB.remote.niRemoteMACIP.IPAddr.w[0] + MyTCB.remotePort.Val) ^ MyTCB.localPort.Val;
2377 vFlags = SYN | ACK;
2378 MyTCBStub.smState = TCP_SYN_RECEIVED;
2379  
2380 // Delete this SYN from the SYNQueue and compact the SYNQueue[] array
2381 TCPRAMCopy((PTR_BASE)&SYNQueue[w], TCP_PIC_RAM, (PTR_BASE)&SYNQueue[w+1], TCP_PIC_RAM, (TCP_SYN_QUEUE_MAX_ENTRIES-1u-w)*sizeof(TCP_SYN_QUEUE));
2382 SYNQueue[TCP_SYN_QUEUE_MAX_ENTRIES-1].wDestPort = 0u;
2383  
2384 break;
2385 }
2386 }
2387 }
2388 #endif
2389  
2390 if(vFlags)
2391 SendTCP(vFlags, bRetransmit ? 0 : SENDTCP_RESET_TIMERS);
2392  
2393 // The TCP_CLOSED, TCP_LISTEN, and sometimes the TCP_ESTABLISHED
2394 // state don't need any timeout events, so see if the timer is enabled
2395 if(!MyTCBStub.Flags.bTimerEnabled)
2396 {
2397 #if defined(TCP_KEEP_ALIVE_TIMEOUT)
2398 // Only the established state has any use for keep-alives
2399 if(MyTCBStub.smState == TCP_ESTABLISHED)
2400 {
2401 // If timeout has not occured, do not do anything.
2402 if((LONG)(TickGet() - MyTCBStub.eventTime) < (LONG)0)
2403 continue;
2404  
2405 // If timeout has occured and the connection appears to be dead (no
2406 // responses from remote node at all), close the connection so the
2407 // application doesn't sit around indefinitely with a useless socket
2408 // that it thinks is still open
2409 if(MyTCBStub.Flags.vUnackedKeepalives == TCP_MAX_UNACKED_KEEP_ALIVES)
2410 {
2411 vFlags = MyTCBStub.Flags.bServer;
2412  
2413 // Force an immediate FIN and RST transmission
2414 // Double calling TCPDisconnect() will also place us
2415 // back in the listening state immediately if a server socket.
2416 TCPDisconnect(hTCP);
2417 TCPDisconnect(hTCP);
2418  
2419 // Prevent client mode sockets from getting reused by other applications.
2420 // The application must call TCPDisconnect() with the handle to free this
2421 // socket (and the handle associated with it)
2422 if(!vFlags)
2423 MyTCBStub.smState = TCP_CLOSED_BUT_RESERVED;
2424  
2425 continue;
2426 }
2427  
2428 // Otherwise, if a timeout occured, simply send a keep-alive packet
2429 SyncTCB();
2430 SendTCP(ACK, SENDTCP_KEEP_ALIVE);
2431 MyTCBStub.eventTime = TickGet() + TCP_KEEP_ALIVE_TIMEOUT;
2432 }
2433 #endif
2434 continue;
2435 }
2436  
2437 // If timeout has not occured, do not do anything.
2438 if((LONG)(TickGet() - MyTCBStub.eventTime) < (LONG)0)
2439 continue;
2440  
2441 // Load up extended TCB information
2442 SyncTCB();
2443  
2444 // A timeout has occured. Respond to this timeout condition
2445 // depending on what state this socket is in.
2446 switch(MyTCBStub.smState)
2447 {
2448 #if defined(STACK_CLIENT_MODE)
2449 #if defined(STACK_USE_DNS)
2450 case TCP_GET_DNS_MODULE:
2451 if(DNSBeginUsage())
2452 {
2453 MyTCBStub.smState = TCP_DNS_RESOLVE;
2454 if(MyTCB.flags.bRemoteHostIsROM)
2455 DNSResolveROM((ROM BYTE*)(ROM_PTR_BASE)MyTCB.remote.dwRemoteHost, DNS_TYPE_A);
2456 else
2457 DNSResolve((BYTE*)(PTR_BASE)MyTCB.remote.dwRemoteHost, DNS_TYPE_A);
2458 }
2459 break;
2460  
2461 case TCP_DNS_RESOLVE:
2462 {
2463 IP_ADDR ipResolvedDNSIP;
2464  
2465 // See if DNS resolution has finished. Note that if the DNS
2466 // fails, the &ipResolvedDNSIP will be written with 0x00000000.
2467 // MyTCB.remote.dwRemoteHost is unioned with
2468 // MyTCB.remote.niRemoteMACIP.IPAddr, so we can't directly write
2469 // the DNS result into MyTCB.remote.niRemoteMACIP.IPAddr. We
2470 // must copy it over only if the DNS is resolution step was
2471 // successful.
2472 if(DNSIsResolved(&ipResolvedDNSIP))
2473 {
2474 if(DNSEndUsage())
2475 {
2476 MyTCB.remote.niRemoteMACIP.IPAddr.Val = ipResolvedDNSIP.Val;
2477 MyTCBStub.smState = TCP_GATEWAY_SEND_ARP;
2478 MyTCBStub.remoteHash.Val = (MyTCB.remote.niRemoteMACIP.IPAddr.w[1]+MyTCB.remote.niRemoteMACIP.IPAddr.w[0] + MyTCB.remotePort.Val) ^ MyTCB.localPort.Val;
2479 MyTCB.retryCount = 0;
2480 MyTCB.retryInterval = (TICK_SECOND/4)/256;
2481 }
2482 else
2483 {
2484 MyTCBStub.eventTime = TickGet() + 10*TICK_SECOND;
2485 MyTCBStub.smState = TCP_GET_DNS_MODULE;
2486 }
2487 }
2488 break;
2489 }
2490 #endif // #if defined(STACK_USE_DNS)
2491  
2492 case TCP_GATEWAY_SEND_ARP:
2493 // Obtain the MAC address associated with the server's IP address (either direct MAC address on same subnet, or the MAC address of the Gateway machine)
2494 MyTCBStub.eventTime2 = (WORD)TickGetDiv256();
2495 ARPResolve(&MyTCB.remote.niRemoteMACIP.IPAddr);
2496 MyTCBStub.smState = TCP_GATEWAY_GET_ARP;
2497 break;
2498  
2499 case TCP_GATEWAY_GET_ARP:
2500 // Wait for the MAC address to finish being obtained
2501 if(!ARPIsResolved(&MyTCB.remote.niRemoteMACIP.IPAddr, &MyTCB.remote.niRemoteMACIP.MACAddr))
2502 {
2503 // Time out if too much time is spent in this state
2504 // Note that this will continuously send out ARP
2505 // requests for an infinite time if the Gateway
2506 // never responds
2507 if((WORD)TickGetDiv256() - MyTCBStub.eventTime2 > (WORD)MyTCB.retryInterval)
2508 {
2509 // Exponentially increase timeout until we reach 6 attempts then stay constant
2510 if(MyTCB.retryCount < 6u)
2511 {
2512 MyTCB.retryCount++;
2513 MyTCB.retryInterval <<= 1;
2514 }
2515  
2516 // Retransmit ARP request
2517 MyTCBStub.smState = TCP_GATEWAY_SEND_ARP;
2518 }
2519 break;
2520 }
2521  
2522 // Send out SYN connection request to remote node
2523 // This automatically disables the Timer from
2524 // continuously firing for this socket
2525 vFlags = SYN;
2526 bRetransmit = FALSE;
2527 MyTCBStub.smState = TCP_SYN_SENT;
2528 break;
2529 #endif // #if defined(STACK_CLIENT_MODE)
2530  
2531 case TCP_SYN_SENT:
2532 // Keep sending SYN until we hear from remote node.
2533 // This may be for infinite time, in that case
2534 // caller must detect it and do something.
2535 vFlags = SYN;
2536 bRetransmit = TRUE;
2537 break;
2538  
2539 case TCP_SYN_RECEIVED:
2540 // We must receive ACK before timeout expires.
2541 // If not, resend SYN+ACK.
2542 // Abort, if maximum attempts counts are reached.
2543 if(MyTCB.retryCount < TCP_MAX_SYN_RETRIES)
2544 {
2545 vFlags = SYN | ACK;
2546 bRetransmit = TRUE;
2547 }
2548 else
2549 {
2550 if(MyTCBStub.Flags.bServer)
2551 {
2552 vFlags = RST | ACK;
2553 bCloseSocket = TRUE;
2554 }
2555 else
2556 {
2557 vFlags = SYN;
2558 }
2559 }
2560 break;
2561  
2562 case TCP_ESTABLISHED:
2563 case TCP_CLOSE_WAIT:
2564 // Retransmit any unacknowledged data
2565 if(MyTCB.retryCount < TCP_MAX_RETRIES)
2566 {
2567 vFlags = ACK;
2568 bRetransmit = TRUE;
2569 }
2570 else
2571 {
2572 // No response back for too long, close connection
2573 // This could happen, for instance, if the communication
2574 // medium was lost
2575 MyTCBStub.smState = TCP_FIN_WAIT_1;
2576 vFlags = FIN | ACK;
2577 }
2578 break;
2579  
2580 case TCP_FIN_WAIT_1:
2581 if(MyTCB.retryCount < TCP_MAX_RETRIES)
2582 {
2583 // Send another FIN
2584 vFlags = FIN | ACK;
2585 bRetransmit = TRUE;
2586 }
2587 else
2588 {
2589 // Close on our own, we can't seem to communicate
2590 // with the remote node anymore
2591 vFlags = RST | ACK;
2592 bCloseSocket = TRUE;
2593 }
2594 break;
2595  
2596 case TCP_FIN_WAIT_2:
2597 // Close on our own, we can't seem to communicate
2598 // with the remote node anymore
2599 vFlags = RST | ACK;
2600 bCloseSocket = TRUE;
2601 break;
2602  
2603 case TCP_CLOSING:
2604 if(MyTCB.retryCount < TCP_MAX_RETRIES)
2605 {
2606 // Send another ACK+FIN (the FIN is retransmitted
2607 // automatically since it hasn't been acknowledged by
2608 // the remote node yet)
2609 vFlags = ACK;
2610 bRetransmit = TRUE;
2611 }
2612 else
2613 {
2614 // Close on our own, we can't seem to communicate
2615 // with the remote node anymore
2616 vFlags = RST | ACK;
2617 bCloseSocket = TRUE;
2618 }
2619 break;
2620  
2621 // case TCP_TIME_WAIT:
2622 // // Wait around for a while (2MSL) and then goto closed state
2623 // bCloseSocket = TRUE;
2624 // break;
2625 //
2626  
2627 case TCP_LAST_ACK:
2628 // Send some more FINs or close anyway
2629 if(MyTCB.retryCount < TCP_MAX_RETRIES)
2630 {
2631 vFlags = FIN | ACK;
2632 bRetransmit = TRUE;
2633 }
2634 else
2635 {
2636 vFlags = RST | ACK;
2637 bCloseSocket = TRUE;
2638 }
2639 break;
2640  
2641 default:
2642 break;
2643 }
2644  
2645 if(vFlags)
2646 {
2647 if(bRetransmit)
2648 {
2649 // Set the appropriate retry time
2650 MyTCB.retryCount++;
2651 MyTCB.retryInterval <<= 1;
2652  
2653 // Transmit all unacknowledged data over again
2654 // Roll back unacknowledged TX tail pointer to cause retransmit to occur
2655 MyTCB.MySEQ -= (LONG)(SHORT)(MyTCB.txUnackedTail - MyTCBStub.txTail);
2656 if(MyTCB.txUnackedTail < MyTCBStub.txTail)
2657 MyTCB.MySEQ -= (LONG)(SHORT)(MyTCBStub.bufferRxStart - MyTCBStub.bufferTxStart);
2658 MyTCB.txUnackedTail = MyTCBStub.txTail;
2659 SendTCP(vFlags, 0);
2660 }
2661 else
2662 SendTCP(vFlags, SENDTCP_RESET_TIMERS);
2663  
2664 }
2665  
2666 if(bCloseSocket)
2667 CloseSocket();
2668 }
2669  
2670  
2671 #if TCP_SYN_QUEUE_MAX_ENTRIES
2672 // Process SYN Queue entry timeouts
2673 for(w = 0; w < TCP_SYN_QUEUE_MAX_ENTRIES; w++)
2674 {
2675 // Abort search if there are no more valid records
2676 if(SYNQueue[w].wDestPort == 0u)
2677 break;
2678  
2679 // See if this SYN has timed out
2680 if((WORD)TickGetDiv256() - SYNQueue[w].wTimestamp > (WORD)(TCP_SYN_QUEUE_TIMEOUT/256ull))
2681 {
2682 // Delete this SYN from the SYNQueue and compact the SYNQueue[] array
2683 TCPRAMCopy((PTR_BASE)&SYNQueue[w], TCP_PIC_RAM, (PTR_BASE)&SYNQueue[w+1], TCP_PIC_RAM, (TCP_SYN_QUEUE_MAX_ENTRIES-1u-w)*sizeof(TCP_SYN_QUEUE));
2684 SYNQueue[TCP_SYN_QUEUE_MAX_ENTRIES-1].wDestPort = 0u;
2685  
2686 // Since we deleted an entry, we need to roll back one
2687 // index so next loop will process the correct record
2688 w--;
2689 }
2690 }
2691 #endif
2692 }
2693  
2694  
2695 /*****************************************************************************
2696 Function:
2697 BOOL TCPProcess(NODE_INFO* remote, IP_ADDR* localIP, WORD len)
2698  
2699 Summary:
2700 Handles incoming TCP segments.
2701  
2702 Description:
2703 This function handles incoming TCP segments. When a segment arrives, it
2704 is compared to open sockets using a hash of the remote port and IP.
2705 On a match, the data is passed to HandleTCPSeg for further processing.
2706  
2707 Precondition:
2708 TCP is initialized and a TCP segment is ready in the MAC buffer.
2709  
2710 Parameters:
2711 remote - Remote NODE_INFO structure
2712 localIP - This stack's IP address (for header checking)
2713 len - Total length of the waiting TCP segment
2714  
2715 Return Values:
2716 TRUE - the segment was properly handled.
2717 FALSE - otherwise
2718 ***************************************************************************/
2719 BOOL TCPProcess(NODE_INFO* remote, IP_ADDR* localIP, WORD len)
2720 {
2721 TCP_HEADER TCPHeader;
2722 PSEUDO_HEADER pseudoHeader;
2723 WORD_VAL checksum1;
2724 WORD_VAL checksum2;
2725 BYTE optionsSize;
2726  
2727 // Calculate IP pseudoheader checksum.
2728 pseudoHeader.SourceAddress = remote->IPAddr;
2729 pseudoHeader.DestAddress = *localIP;
2730 pseudoHeader.Zero = 0x0;
2731 pseudoHeader.Protocol = IP_PROT_TCP;
2732 pseudoHeader.Length = len;
2733  
2734 SwapPseudoHeader(pseudoHeader);
2735  
2736 checksum1.Val = ~CalcIPChecksum((BYTE*)&pseudoHeader,
2737 sizeof(pseudoHeader));
2738  
2739 // Now calculate TCP packet checksum in NIC RAM - should match
2740 // pesudo header checksum
2741 checksum2.Val = CalcIPBufferChecksum(len);
2742  
2743 // Compare checksums.
2744 if(checksum1.Val != checksum2.Val)
2745 {
2746 MACDiscardRx();
2747 return TRUE;
2748 }
2749  
2750 #if defined(DEBUG_GENERATE_RX_LOSS)
2751 // Throw RX packets away randomly
2752 if(rand() > DEBUG_GENERATE_RX_LOSS)
2753 {
2754 MACDiscardRx();
2755 return TRUE;
2756 }
2757 #endif
2758  
2759 // Retrieve TCP header.
2760 IPSetRxBuffer(0);
2761 MACGetArray((BYTE*)&TCPHeader, sizeof(TCPHeader));
2762 SwapTCPHeader(&TCPHeader);
2763  
2764  
2765 // Skip over options to retrieve data bytes
2766 optionsSize = (BYTE)((TCPHeader.DataOffset.Val << 2)-
2767 sizeof(TCPHeader));
2768 len = len - optionsSize - sizeof(TCPHeader);
2769  
2770 // Find matching socket.
2771 if(FindMatchingSocket(&TCPHeader, remote))
2772 {
2773 #if defined(STACK_USE_SSL)
2774 PTR_BASE prevRxHead;
2775 // For SSL connections, show HandleTCPSeg() the full data buffer
2776 prevRxHead = MyTCBStub.rxHead;
2777 if(MyTCBStub.sslStubID != SSL_INVALID_ID)
2778 MyTCBStub.rxHead = MyTCBStub.sslRxHead;
2779 #endif
2780  
2781 HandleTCPSeg(&TCPHeader, len);
2782  
2783 #if defined(STACK_USE_SSL)
2784 if(MyTCBStub.sslStubID != SSL_INVALID_ID)
2785 {
2786 // Restore the buffer state
2787 MyTCBStub.sslRxHead = MyTCBStub.rxHead;
2788 MyTCBStub.rxHead = prevRxHead;
2789  
2790 // Process the new SSL data, using the currently loaded stub
2791 TCPSSLHandleIncoming(hCurrentTCP);
2792 }
2793 #endif
2794 }
2795 // else
2796 // {
2797 // // NOTE: RFC 793 specifies that if the socket is closed and a segment
2798 // // arrives, we should send back a RST if the RST bit in the incoming
2799 // // packet is not set. Instead, we will just silently ignore such a
2800 // // packet since this is what firewalls do on purpose to enhance
2801 // // security.
2802 // //if(!TCPHeader.Flags.bits.flagRST)
2803 // // SendTCP(RST, SENDTCP_RESET_TIMERS);
2804 // }
2805  
2806 // Finished with this packet, discard it and free the Ethernet RAM for new packets
2807 MACDiscardRx();
2808  
2809 return TRUE;
2810 }
2811  
2812  
2813 /*****************************************************************************
2814 Function:
2815 static void SendTCP(BYTE vTCPFlags, BYTE vSendFlags)
2816  
2817 Summary:
2818 Transmits a TPC segment.
2819  
2820 Description:
2821 This function assembles and transmits a TCP segment, including any
2822 pending data. It also supports retransmissions, keep-alives, and
2823 other packet types.
2824  
2825 Precondition:
2826 TCP is initialized.
2827  
2828 Parameters:
2829 vTCPFlags - Additional TCP flags to include
2830 vSendFlags - Any combinations of SENDTCP_* constants to modify the
2831 transmit behavior or contents.
2832  
2833 Returns:
2834 None
2835 ***************************************************************************/
2836 static void SendTCP(BYTE vTCPFlags, BYTE vSendFlags)
2837 {
2838 WORD_VAL wVal;
2839 TCP_HEADER header;
2840 TCP_OPTIONS options;
2841 PSEUDO_HEADER pseudoHeader;
2842 WORD len;
2843 WORD wEffectiveWindow;
2844  
2845 SyncTCB();
2846  
2847 // FINs must be handled specially
2848 if(vTCPFlags & FIN)
2849 {
2850 MyTCBStub.Flags.bTXFIN = 1;
2851 vTCPFlags &= ~FIN;
2852 }
2853  
2854 // Status will now be synched, disable automatic future
2855 // status transmissions
2856 MyTCBStub.Flags.bTimer2Enabled = 0;
2857 MyTCBStub.Flags.bDelayedACKTimerEnabled = 0;
2858 MyTCBStub.Flags.bOneSegmentReceived = 0;
2859 MyTCBStub.Flags.bTXASAP = 0;
2860 MyTCBStub.Flags.bTXASAPWithoutTimerReset = 0;
2861 MyTCBStub.Flags.bHalfFullFlush = 0;
2862  
2863 // Make sure that we can write to the MAC transmit area
2864 while(!IPIsTxReady());
2865  
2866 // Put all socket application data in the TX space
2867 if(vTCPFlags & (SYN | RST))
2868 {
2869 // Don't put any data in SYN and RST messages
2870 len = 0;
2871 }
2872 else
2873 {
2874 // Begin copying any application data over to the TX space
2875 if(MyTCBStub.txHead == MyTCB.txUnackedTail)
2876 {
2877 // All caught up on data TX, no real data for this packet
2878 len = 0;
2879  
2880 // If we are to transmit a FIN, make sure we can put one in this packet
2881 if(MyTCBStub.Flags.bTXFIN)
2882 {
2883 if(MyTCB.remoteWindow)
2884 vTCPFlags |= FIN;
2885 }
2886 }
2887 else if(MyTCBStub.txHead > MyTCB.txUnackedTail)
2888 {
2889 len = MyTCBStub.txHead - MyTCB.txUnackedTail;
2890 wEffectiveWindow = MyTCB.remoteWindow;
2891 if(MyTCB.txUnackedTail >= MyTCBStub.txTail)
2892 wEffectiveWindow -= MyTCB.txUnackedTail - MyTCBStub.txTail;
2893 else
2894 wEffectiveWindow -= (MyTCBStub.bufferRxStart - MyTCBStub.bufferTxStart) - (MyTCBStub.txTail - MyTCB.txUnackedTail);
2895  
2896 if(len > wEffectiveWindow)
2897 len = wEffectiveWindow;
2898  
2899 if(len > MyTCB.wRemoteMSS)
2900 {
2901 len = MyTCB.wRemoteMSS;
2902 MyTCBStub.Flags.bTXASAPWithoutTimerReset = 1;
2903 }
2904  
2905 // If we are to transmit a FIN, make sure we can put one in this packet
2906 if(MyTCBStub.Flags.bTXFIN)
2907 {
2908 if((len != wEffectiveWindow) && (len != MyTCB.wRemoteMSS))
2909 vTCPFlags |= FIN;
2910 }
2911  
2912 // Copy application data into the raw TX buffer
2913 TCPRAMCopy(BASE_TX_ADDR+sizeof(ETHER_HEADER)+sizeof(IP_HEADER)+sizeof(TCP_HEADER), TCP_ETH_RAM, MyTCB.txUnackedTail, MyTCBStub.vMemoryMedium, len);
2914 MyTCB.txUnackedTail += len;
2915 }
2916 else
2917 {
2918 pseudoHeader.Length = MyTCBStub.bufferRxStart - MyTCB.txUnackedTail;
2919 len = pseudoHeader.Length + MyTCBStub.txHead - MyTCBStub.bufferTxStart;
2920  
2921 wEffectiveWindow = MyTCB.remoteWindow;
2922 if(MyTCB.txUnackedTail >= MyTCBStub.txTail)
2923 wEffectiveWindow -= MyTCB.txUnackedTail - MyTCBStub.txTail;
2924 else
2925 wEffectiveWindow -= (MyTCBStub.bufferRxStart - MyTCBStub.bufferTxStart) - (MyTCBStub.txTail - MyTCB.txUnackedTail);
2926  
2927 if(len > wEffectiveWindow)
2928 len = wEffectiveWindow;
2929  
2930 if(len > MyTCB.wRemoteMSS)
2931 {
2932 len = MyTCB.wRemoteMSS;
2933 MyTCBStub.Flags.bTXASAPWithoutTimerReset = 1;
2934 }
2935  
2936 // If we are to transmit a FIN, make sure we can put one in this packet
2937 if(MyTCBStub.Flags.bTXFIN)
2938 {
2939 if((len != wEffectiveWindow) && (len != MyTCB.wRemoteMSS))
2940 vTCPFlags |= FIN;
2941 }
2942  
2943 if(pseudoHeader.Length > len)
2944 pseudoHeader.Length = len;
2945  
2946 // Copy application data into the raw TX buffer
2947 TCPRAMCopy(BASE_TX_ADDR+sizeof(ETHER_HEADER)+sizeof(IP_HEADER)+sizeof(TCP_HEADER), TCP_ETH_RAM, MyTCB.txUnackedTail, MyTCBStub.vMemoryMedium, pseudoHeader.Length);
2948 pseudoHeader.Length = len - pseudoHeader.Length;
2949  
2950 // Copy any left over chunks of application data over
2951 if(pseudoHeader.Length)
2952 {
2953 TCPRAMCopy(BASE_TX_ADDR+sizeof(ETHER_HEADER)+sizeof(IP_HEADER)+sizeof(TCP_HEADER)+(MyTCBStub.bufferRxStart-MyTCB.txUnackedTail), TCP_ETH_RAM, MyTCBStub.bufferTxStart, MyTCBStub.vMemoryMedium, pseudoHeader.Length);
2954 }
2955  
2956 MyTCB.txUnackedTail += len;
2957 if(MyTCB.txUnackedTail >= MyTCBStub.bufferRxStart)
2958 MyTCB.txUnackedTail -= MyTCBStub.bufferRxStart-MyTCBStub.bufferTxStart;
2959 }
2960 }
2961  
2962 // Ensure that all packets with data of some kind are
2963 // retransmitted by TCPTick() until acknowledged
2964 // Pure ACK packets with no data are not ACKed back in TCP
2965 if(len || (vTCPFlags & (SYN | FIN)))
2966 {
2967 // Push (PSH) all data for enhanced responsiveness on
2968 // the remote end, especially with GUIs
2969 if(len)
2970 vTCPFlags |= PSH;
2971  
2972 if(vSendFlags & SENDTCP_RESET_TIMERS)
2973 {
2974 MyTCB.retryCount = 0;
2975 MyTCB.retryInterval = TCP_START_TIMEOUT_VAL;
2976 }
2977  
2978 MyTCBStub.eventTime = TickGet() + MyTCB.retryInterval;
2979 MyTCBStub.Flags.bTimerEnabled = 1;
2980 }
2981 else if(vSendFlags & SENDTCP_KEEP_ALIVE)
2982 {
2983 // Increment Keep Alive TX counter to handle disconnection if not response is returned
2984 MyTCBStub.Flags.vUnackedKeepalives++;
2985  
2986 // Generate a dummy byte
2987 MyTCB.MySEQ -= 1;
2988 len = 1;
2989 }
2990 else if(MyTCBStub.Flags.bTimerEnabled)
2991 {
2992 // If we have data to transmit, but the remote RX window is zero,
2993 // so we aren't transmitting any right now then make sure to not
2994 // extend the retry counter or timer. This will stall our TX
2995 // with a periodic ACK sent to the remote node.
2996 if(!(vSendFlags & SENDTCP_RESET_TIMERS))
2997 {
2998 // Roll back retry counters since we can't send anything,
2999 // but only if we incremented it in the first place
3000 if(MyTCB.retryCount)
3001 {
3002 MyTCB.retryCount--;
3003 MyTCB.retryInterval >>= 1;
3004 }
3005 }
3006  
3007 MyTCBStub.eventTime = TickGet() + MyTCB.retryInterval;
3008 }
3009  
3010  
3011 header.SourcePort = MyTCB.localPort.Val;
3012 header.DestPort = MyTCB.remotePort.Val;
3013 header.SeqNumber = MyTCB.MySEQ;
3014 header.AckNumber = MyTCB.RemoteSEQ;
3015 header.Flags.bits.Reserved2 = 0;
3016 header.DataOffset.Reserved3 = 0;
3017 header.Flags.byte = vTCPFlags;
3018 header.UrgentPointer = 0;
3019  
3020 // Update our send sequence number and ensure retransmissions
3021 // of SYNs and FINs use the right sequence number
3022 MyTCB.MySEQ += (DWORD)len;
3023 if(vTCPFlags & SYN)
3024 {
3025 // SEG.ACK needs to be zero for the first SYN packet for compatibility
3026 // with certain paranoid TCP/IP stacks, even though the ACK flag isn't
3027 // set (indicating that the AckNumber field is unused).
3028 if(!(vTCPFlags & ACK))
3029 header.AckNumber = 0x00000000;
3030  
3031 if(MyTCB.flags.bSYNSent)
3032 header.SeqNumber--;
3033 else
3034 {
3035 MyTCB.MySEQ++;
3036 MyTCB.flags.bSYNSent = 1;
3037 }
3038 }
3039 if(vTCPFlags & FIN)
3040 {
3041 if(MyTCB.flags.bFINSent)
3042 header.SeqNumber--;
3043 else
3044 {
3045 MyTCB.MySEQ++;
3046 MyTCB.flags.bFINSent = 1;
3047 }
3048 }
3049  
3050 // Calculate the amount of free space in the RX buffer area of this socket
3051 if(MyTCBStub.rxHead >= MyTCBStub.rxTail)
3052 header.Window = (MyTCBStub.bufferEnd - MyTCBStub.bufferRxStart) - (MyTCBStub.rxHead - MyTCBStub.rxTail);
3053 else
3054 header.Window = MyTCBStub.rxTail - MyTCBStub.rxHead - 1;
3055  
3056 // Calculate the amount of free space in the MAC RX buffer area and adjust window if needed
3057 wVal.Val = MACGetFreeRxSize()-64;
3058 if((SHORT)wVal.Val < (SHORT)0)
3059 wVal.Val = 0;
3060 // Force the remote node to throttle back if we are running low on general RX buffer space
3061 if(header.Window > wVal.Val)
3062 header.Window = wVal.Val;
3063  
3064 SwapTCPHeader(&header);
3065  
3066  
3067 len += sizeof(header);
3068 header.DataOffset.Val = sizeof(header) >> 2;
3069  
3070 // Insert the MSS (Maximum Segment Size) TCP option if this is SYN packet
3071 if(vTCPFlags & SYN)
3072 {
3073 len += sizeof(options);
3074 options.Kind = TCP_OPTIONS_MAX_SEG_SIZE;
3075 options.Length = 0x04;
3076  
3077 // Load MSS and swap to big endian
3078 options.MaxSegSize.Val = (((TCP_MAX_SEG_SIZE_RX-4)&0x00FF)<<8) | (((TCP_MAX_SEG_SIZE_RX-4)&0xFF00)>>8);
3079  
3080 header.DataOffset.Val += sizeof(options) >> 2;
3081 }
3082  
3083 // Calculate IP pseudoheader checksum.
3084 pseudoHeader.SourceAddress = AppConfig.MyIPAddr;
3085 pseudoHeader.DestAddress = MyTCB.remote.niRemoteMACIP.IPAddr;
3086 pseudoHeader.Zero = 0x0;
3087 pseudoHeader.Protocol = IP_PROT_TCP;
3088 pseudoHeader.Length = len;
3089 SwapPseudoHeader(pseudoHeader);
3090 header.Checksum = ~CalcIPChecksum((BYTE*)&pseudoHeader, sizeof(pseudoHeader));
3091  
3092 // Write IP header
3093 MACSetWritePtr(BASE_TX_ADDR + sizeof(ETHER_HEADER));
3094 IPPutHeader(&MyTCB.remote.niRemoteMACIP, IP_PROT_TCP, len);
3095 MACPutArray((BYTE*)&header, sizeof(header));
3096 if(vTCPFlags & SYN)
3097 MACPutArray((BYTE*)&options, sizeof(options));
3098  
3099 // Update the TCP checksum
3100 MACSetReadPtr(BASE_TX_ADDR + sizeof(ETHER_HEADER) + sizeof(IP_HEADER));
3101 wVal.Val = CalcIPBufferChecksum(len);
3102 #if defined(DEBUG_GENERATE_TX_LOSS)
3103 // Damage TCP checksums on TX packets randomly
3104 if(rand() > DEBUG_GENERATE_TX_LOSS)
3105 {
3106 wVal.Val++;
3107 }
3108 #endif
3109 MACSetWritePtr(BASE_TX_ADDR + sizeof(ETHER_HEADER) + sizeof(IP_HEADER) + 16);
3110 MACPutArray((BYTE*)&wVal, sizeof(WORD));
3111  
3112 // Physically start the packet transmission over the network
3113 MACFlush();
3114 }
3115  
3116 /*****************************************************************************
3117 Function:
3118 static BOOL FindMatchingSocket(TCP_HEADER* h, NODE_INFO* remote)
3119  
3120 Summary:
3121 Finds a suitable socket for a TCP segment.
3122  
3123 Description:
3124 This function searches through the sockets and attempts to match one with
3125 a given TCP header and NODE_INFO structure. If a socket is found, its
3126 index is saved in hCurrentTCP and the associated MyTCBStub and MyTCB are
3127 loaded. Otherwise, INVALID_SOCKET is placed in hCurrentTCP.
3128  
3129 Precondition:
3130 TCP is initialized.
3131  
3132 Parameters:
3133 h - TCP header to be matched against
3134 remote - The remote node who sent this header
3135  
3136 Return Values:
3137 TRUE - A match was found and is loaded in hCurrentTCP
3138 FALSE - No suitable socket was found and hCurrentTCP is INVALID_SOCKET
3139 ***************************************************************************/
3140 static BOOL FindMatchingSocket(TCP_HEADER* h, NODE_INFO* remote)
3141 {
3142 TCP_SOCKET hTCP;
3143 TCP_SOCKET partialMatch;
3144 WORD hash;
3145  
3146 // Prevent connections on invalid port 0
3147 if(h->DestPort == 0u)
3148 return FALSE;
3149  
3150 partialMatch = INVALID_SOCKET;
3151 hash = (remote->IPAddr.w[1]+remote->IPAddr.w[0] + h->SourcePort) ^ h->DestPort;
3152  
3153 // Loop through all sockets looking for a socket that is expecting this
3154 // packet or can handle it.
3155 for(hTCP = 0; hTCP < TCP_SOCKET_COUNT; hTCP++ )
3156 {
3157 SyncTCBStub(hTCP);
3158  
3159 if(MyTCBStub.smState == TCP_CLOSED)
3160 {
3161 continue;
3162 }
3163 else if(MyTCBStub.smState == TCP_LISTEN)
3164 {// For listening ports, check if this is the correct port
3165 if(MyTCBStub.remoteHash.Val == h->DestPort)
3166 partialMatch = hTCP;
3167  
3168 #if defined(STACK_USE_SSL_SERVER)
3169 // Check the SSL port as well for SSL Servers
3170 // 0 is defined as an invalid port number
3171 if(MyTCBStub.sslTxHead == h->DestPort)
3172 partialMatch = hTCP;
3173 #endif
3174  
3175 continue;
3176 }
3177 else if(MyTCBStub.remoteHash.Val != hash)
3178 {// Ignore if the hash doesn't match
3179 continue;
3180 }
3181  
3182 SyncTCB();
3183 if( h->DestPort == MyTCB.localPort.Val &&
3184 h->SourcePort == MyTCB.remotePort.Val &&
3185 remote->IPAddr.Val == MyTCB.remote.niRemoteMACIP.IPAddr.Val)
3186 {
3187 return TRUE;
3188 }
3189 }
3190  
3191  
3192 // If there is a partial match, then a listening socket is currently
3193 // available. Set up the extended TCB with the info needed
3194 // to establish a connection and return this socket to the
3195 // caller.
3196 if(partialMatch != INVALID_SOCKET)
3197 {
3198 SyncTCBStub(partialMatch);
3199 SyncTCB();
3200  
3201 // For SSL ports, begin the SSL Handshake
3202 #if defined(STACK_USE_SSL_SERVER)
3203 if(MyTCBStub.sslTxHead == h->DestPort)
3204 {
3205 // Try to start an SSL session. If no stubs are available,
3206 // we can't service this request right now, so ignore it.
3207 if(!TCPStartSSLServer(partialMatch))
3208 partialMatch = INVALID_SOCKET;
3209 }
3210 #endif
3211  
3212 // Make sure the above check didn't fail (this is unfortunately
3213 // redundant for non-SSL sockets). Otherwise, fall out to below
3214 // and add to the SYN queue.
3215 if(partialMatch != INVALID_SOCKET)
3216 {
3217 MyTCBStub.remoteHash.Val = hash;
3218  
3219 memcpy((void*)&MyTCB.remote, (void*)remote, sizeof(NODE_INFO));
3220 MyTCB.remotePort.Val = h->SourcePort;
3221 MyTCB.localPort.Val = h->DestPort;
3222 MyTCB.txUnackedTail = MyTCBStub.bufferTxStart;
3223  
3224 // All done, and we have a match
3225 return TRUE;
3226 }
3227 }
3228  
3229 // No available sockets are listening on this port. (Or, for
3230 // SSL requests, perhaps no SSL sessions were available. However,
3231 // there may be a server socket which is currently busy but
3232 // could handle this packet, so we should check.
3233 #if TCP_SYN_QUEUE_MAX_ENTRIES
3234 {
3235 WORD wQueueInsertPos;
3236  
3237 // See if this is a SYN packet
3238 if(!h->Flags.bits.flagSYN)
3239 return FALSE;
3240  
3241 // See if there is space in our SYN queue
3242 if(SYNQueue[TCP_SYN_QUEUE_MAX_ENTRIES-1].wDestPort)
3243 return FALSE;
3244  
3245 // See if we have this SYN already in our SYN queue.
3246 // If not already in the queue, find out where we
3247 // should insert this SYN to the queue
3248 for(wQueueInsertPos = 0; wQueueInsertPos < TCP_SYN_QUEUE_MAX_ENTRIES; wQueueInsertPos++)
3249 {
3250 // Exit loop if we found a free record
3251 if(SYNQueue[wQueueInsertPos].wDestPort == 0u)
3252 break;
3253  
3254 // Check if this SYN packet is already in the SYN queue
3255 if(SYNQueue[wQueueInsertPos].wDestPort != h->DestPort)
3256 continue;
3257 if(SYNQueue[wQueueInsertPos].wSourcePort != h->SourcePort)
3258 continue;
3259 if(SYNQueue[wQueueInsertPos].niSourceAddress.IPAddr.Val != remote->IPAddr.Val)
3260 continue;
3261  
3262 // SYN matches SYN queue entry. Update timestamp and do nothing.
3263 SYNQueue[wQueueInsertPos].wTimestamp = TickGetDiv256();
3264 return FALSE;
3265 }
3266  
3267 // Check to see if we have any server sockets which
3268 // are currently connected, but could handle this SYN
3269 // request at a later time if the client disconnects.
3270 for(hTCP = 0; hTCP < TCP_SOCKET_COUNT; hTCP++)
3271 {
3272 SyncTCBStub(hTCP);
3273 if(!MyTCBStub.Flags.bServer)
3274 continue;
3275  
3276 SyncTCB();
3277 #if defined(STACK_USE_SSL_SERVER)
3278 if((MyTCB.localPort.Val != h->DestPort) && (MyTCB.localSSLPort.Val != h->DestPort))
3279 #else
3280 if(MyTCB.localPort.Val != h->DestPort)
3281 #endif
3282 continue;
3283  
3284 // Generate the SYN queue entry
3285 memcpy((void*)&SYNQueue[wQueueInsertPos].niSourceAddress, (void*)remote, sizeof(NODE_INFO));
3286 SYNQueue[wQueueInsertPos].wSourcePort = h->SourcePort;
3287 SYNQueue[wQueueInsertPos].dwSourceSEQ = h->SeqNumber;
3288 SYNQueue[wQueueInsertPos].wDestPort = h->DestPort;
3289 SYNQueue[wQueueInsertPos].wTimestamp = TickGetDiv256();
3290  
3291 return FALSE;
3292 }
3293 }
3294 #endif
3295  
3296 return FALSE;
3297  
3298 }
3299  
3300  
3301  
3302 /*****************************************************************************
3303 Function:
3304 static void SwapTCPHeader(TCP_HEADER* header)
3305  
3306 Summary:
3307 Swaps endian-ness of a TCP header.
3308  
3309 Description:
3310 This function swaps the endian-ness of a given TCP header for comparison.
3311  
3312 Precondition:
3313 None
3314  
3315 Parameters:
3316 header - The TCP header that is to be swapped
3317  
3318 Returns:
3319 None
3320 ***************************************************************************/
3321 static void SwapTCPHeader(TCP_HEADER* header)
3322 {
3323 header->SourcePort = swaps(header->SourcePort);
3324 header->DestPort = swaps(header->DestPort);
3325 header->SeqNumber = swapl(header->SeqNumber);
3326 header->AckNumber = swapl(header->AckNumber);
3327 header->Window = swaps(header->Window);
3328 header->Checksum = swaps(header->Checksum);
3329 header->UrgentPointer = swaps(header->UrgentPointer);
3330 }
3331  
3332  
3333  
3334 /*****************************************************************************
3335 Function:
3336 static void CloseSocket(void)
3337  
3338 Summary:
3339 Closes a TCP socket.
3340  
3341 Description:
3342 This function closes a TCP socket. All socket state information is
3343 reset, and any buffered bytes are discarded. The socket is no longer
3344 accessible by the application after this point.
3345  
3346 Precondition:
3347 The TCPStub corresponding to the socket to be closed is synced.
3348  
3349 Parameters:
3350 None
3351  
3352 Returns:
3353 None
3354 ***************************************************************************/
3355 static void CloseSocket(void)
3356 {
3357 SyncTCB();
3358  
3359 MyTCBStub.remoteHash.Val = MyTCB.localPort.Val;
3360 MyTCBStub.txHead = MyTCBStub.bufferTxStart;
3361 MyTCBStub.txTail = MyTCBStub.bufferTxStart;
3362 MyTCBStub.rxHead = MyTCBStub.bufferRxStart;
3363 MyTCBStub.rxTail = MyTCBStub.bufferRxStart;
3364 MyTCBStub.smState = MyTCBStub.Flags.bServer ? TCP_LISTEN : TCP_CLOSED;
3365 MyTCBStub.Flags.vUnackedKeepalives = 0;
3366 MyTCBStub.Flags.bTimerEnabled = 0;
3367 MyTCBStub.Flags.bTimer2Enabled = 0;
3368 MyTCBStub.Flags.bDelayedACKTimerEnabled = 0;
3369 MyTCBStub.Flags.bOneSegmentReceived = 0;
3370 MyTCBStub.Flags.bHalfFullFlush = 0;
3371 MyTCBStub.Flags.bTXASAP = 0;
3372 MyTCBStub.Flags.bTXASAPWithoutTimerReset = 0;
3373 MyTCBStub.Flags.bTXFIN = 0;
3374 MyTCBStub.Flags.bSocketReset = 1;
3375  
3376 #if defined(STACK_USE_SSL)
3377 // If SSL is active, then we need to close it
3378 if(MyTCBStub.sslStubID != SSL_INVALID_ID)
3379 {
3380 SSLTerminate(MyTCBStub.sslStubID);
3381 MyTCBStub.sslStubID = SSL_INVALID_ID;
3382  
3383 // Swap the SSL port and local port back to proper values
3384 MyTCBStub.remoteHash.Val = MyTCB.localSSLPort.Val;
3385 MyTCB.localSSLPort.Val = MyTCB.localPort.Val;
3386 MyTCB.localPort.Val = MyTCBStub.remoteHash.Val;
3387 }
3388  
3389 // Reset the SSL buffer pointers
3390 MyTCBStub.sslRxHead = MyTCBStub.bufferRxStart;
3391 MyTCBStub.sslTxHead = MyTCBStub.bufferTxStart;
3392 #endif
3393  
3394 #if defined(STACK_USE_SSL_SERVER)
3395 MyTCBStub.sslTxHead = MyTCB.localSSLPort.Val;
3396 #endif
3397  
3398 MyTCB.flags.bFINSent = 0;
3399 MyTCB.flags.bSYNSent = 0;
3400 MyTCB.flags.bRXNoneACKed1 = 0;
3401 MyTCB.flags.bRXNoneACKed2 = 0;
3402 MyTCB.txUnackedTail = MyTCBStub.bufferTxStart;
3403 ((DWORD_VAL*)(&MyTCB.MySEQ))->w[0] = rand();
3404 ((DWORD_VAL*)(&MyTCB.MySEQ))->w[1] = rand();
3405 MyTCB.sHoleSize = -1;
3406 MyTCB.remoteWindow = 1;
3407 }
3408  
3409  
3410 /*****************************************************************************
3411 Function:
3412 static WORD GetMaxSegSizeOption(void)
3413  
3414 Summary:
3415 Obtains the Maximum Segment Size (MSS) TCP Option out of the TCP header
3416 for the current socket.
3417  
3418 Description:
3419 Parses the current TCP packet header and extracts the Maximum Segment Size
3420 option.
3421  
3422 Precondition:
3423 Must be called while a TCP packet is present and being processed via
3424 HandleTCPSeg() and only if the the TCP SYN flag is set.
3425  
3426 Parameters:
3427 None
3428  
3429 Returns:
3430 Maximum segment size option value. If illegal or not present, a failsafe
3431 value of 536 is returned. If the option is larger than the
3432 TCP_MAX_SEG_SIZE_TX upper limit, then TCP_MAX_SEG_SIZE_TX is returned.
3433  
3434 Remarks:
3435 The internal MAC Read Pointer is moved but not restored.
3436 ***************************************************************************/
3437 static WORD GetMaxSegSizeOption(void)
3438 {
3439 BYTE vOptionsBytes;
3440 BYTE vOption;
3441 WORD wMSS;
3442  
3443 // Find out how many options bytes are in this packet.
3444 IPSetRxBuffer(2+2+4+4); // Seek to data offset field, skipping Source port (2), Destination port (2), Sequence number (4), and Acknowledgement number (4)
3445 vOptionsBytes = MACGet();
3446 vOptionsBytes = ((vOptionsBytes&0xF0)>>2) - sizeof(TCP_HEADER);
3447  
3448 // Return minimum Maximum Segment Size value of 536 bytes if none are
3449 // present
3450 if(vOptionsBytes == 0u)
3451 return 536;
3452  
3453 // Seek to beginning of options
3454 MACGetArray(NULL, 7);
3455  
3456 // Search for the Maximum Segment Size option
3457 while(vOptionsBytes--)
3458 {
3459 vOption = MACGet();
3460  
3461 if(vOption == 0u) // End of Options list
3462 break;
3463  
3464 if(vOption == 1u) // NOP option
3465 continue;
3466  
3467 if(vOption == 2u) // Maximum Segment Size option
3468 {
3469 if(vOptionsBytes < 3u)
3470 break;
3471  
3472 wMSS = 0;
3473  
3474 // Get option length
3475 vOption = MACGet();
3476 if(vOption == 4u)
3477 {// Retrieve MSS and swap value to little endian
3478 ((BYTE*)&wMSS)[1] = MACGet();
3479 ((BYTE*)&wMSS)[0] = MACGet();
3480 }
3481  
3482 if(wMSS < 536u)
3483 break;
3484 if(wMSS > TCP_MAX_SEG_SIZE_TX)
3485 return TCP_MAX_SEG_SIZE_TX;
3486 else
3487 return wMSS;
3488 }
3489 else
3490 { // Assume this is a multi byte option and throw it way
3491 if(vOptionsBytes < 2u)
3492 break;
3493 vOption = MACGet();
3494 if(vOptionsBytes < vOption)
3495 break;
3496 MACGetArray(NULL, vOption);
3497 vOptionsBytes -= vOption;
3498 }
3499  
3500 }
3501  
3502 // Did not find MSS option, return worst case default
3503 return 536;
3504 }
3505  
3506 /*****************************************************************************
3507 Function:
3508 static void HandleTCPSeg(TCP_HEADER* h, WORD len)
3509  
3510 Summary:
3511 Processes an incoming TCP segment.
3512  
3513 Description:
3514 Once an incoming segment has been matched to a socket, this function
3515 performs the necessary processing with the data. Depending on the
3516 segment and the state, this may include copying data to the TCP buffer,
3517 re-assembling out-of order packets, continuing an initialization or
3518 closing handshake, or closing the socket altogether.
3519  
3520 Precondition:
3521 TCP is initialized and the current TCP stub is already synced.
3522  
3523 Parameters:
3524 h - The TCP header for this packet
3525 len - The total buffer length of this segment
3526  
3527 Returns:
3528 None
3529 ***************************************************************************/
3530 static void HandleTCPSeg(TCP_HEADER* h, WORD len)
3531 {
3532 DWORD dwTemp;
3533 PTR_BASE wTemp;
3534 LONG lMissingBytes;
3535 WORD wMissingBytes;
3536 WORD wFreeSpace;
3537 BYTE localHeaderFlags;
3538 DWORD localAckNumber;
3539 DWORD localSeqNumber;
3540 WORD wSegmentLength;
3541 BOOL bSegmentAcceptable;
3542  
3543 // Cache a few variables in local RAM.
3544 // PIC18s take a fair amount of code and execution time to
3545 // dereference pointers frequently.
3546 localHeaderFlags = h->Flags.byte;
3547 localAckNumber = h->AckNumber;
3548 localSeqNumber = h->SeqNumber;
3549  
3550 // We received a packet, reset the keep alive timer and count
3551 #if defined(TCP_KEEP_ALIVE_TIMEOUT)
3552 MyTCBStub.Flags.vUnackedKeepalives = 0;
3553 if(!MyTCBStub.Flags.bTimerEnabled)
3554 MyTCBStub.eventTime = TickGet() + TCP_KEEP_ALIVE_TIMEOUT;
3555 #endif
3556  
3557 // Handle TCP_LISTEN and TCP_SYN_SENT states
3558 // Both of these states will return, so code following this
3559 // state machine need not check explicitly for these two
3560 // states.
3561 switch(MyTCBStub.smState)
3562 {
3563 case TCP_LISTEN:
3564 // First: check RST flag
3565 if(localHeaderFlags & RST)
3566 {
3567 CloseSocket(); // Unbind remote IP address/port info
3568 return;
3569 }
3570  
3571 // Second: check ACK flag, which would be invalid
3572 if(localHeaderFlags & ACK)
3573 {
3574 // Use a believable sequence number and reset the remote node
3575 MyTCB.MySEQ = localAckNumber;
3576 SendTCP(RST, 0);
3577 CloseSocket(); // Unbind remote IP address/port info
3578 return;
3579 }
3580  
3581 // Third: check for SYN flag, which is what we're looking for
3582 if(localHeaderFlags & SYN)
3583 {
3584 // We now have a sequence number for the remote node
3585 MyTCB.RemoteSEQ = localSeqNumber + 1;
3586  
3587 // Get MSS option
3588 MyTCB.wRemoteMSS = GetMaxSegSizeOption();
3589  
3590 // Set Initial Send Sequence (ISS) number
3591 // Nothing to do on this step... ISS already set in CloseSocket()
3592  
3593 // Respond with SYN + ACK
3594 SendTCP(SYN | ACK, SENDTCP_RESET_TIMERS);
3595 MyTCBStub.smState = TCP_SYN_RECEIVED;
3596 }
3597 else
3598 {
3599 CloseSocket(); // Unbind remote IP address/port info
3600 }
3601  
3602 // Fourth: check for other text and control
3603 // Nothing to do since we don't support this
3604 return;
3605  
3606 case TCP_SYN_SENT:
3607 // Second: check the RST bit
3608 // This is out of order because this stack has no API for
3609 // notifying the application that the connection seems to
3610 // be failing. Instead, the application must time out and
3611 // the stack will just keep trying in the mean time.
3612 if(localHeaderFlags & RST)
3613 return;
3614  
3615 // First: check ACK bit
3616 if(localHeaderFlags & ACK)
3617 {
3618 if(localAckNumber != MyTCB.MySEQ)
3619 {
3620 // Send a RST packet with SEQ = SEG.ACK, but retain our SEQ
3621 // number for arivial of any other SYN+ACK packets
3622 localSeqNumber = MyTCB.MySEQ; // Save our original SEQ number
3623 MyTCB.MySEQ = localAckNumber; // Set SEQ = SEG.ACK
3624 SendTCP(RST, SENDTCP_RESET_TIMERS); // Send the RST
3625 MyTCB.MySEQ = localSeqNumber; // Restore original SEQ number
3626 return;
3627 }
3628 }
3629  
3630 // Third: check the security and precedence
3631 // No such feature in this stack. We want to accept all connections.
3632  
3633 // Fourth: check the SYN bit
3634 if(localHeaderFlags & SYN)
3635 {
3636 // We now have an initial sequence number and window size
3637 MyTCB.RemoteSEQ = localSeqNumber + 1;
3638 MyTCB.remoteWindow = h->Window;
3639  
3640 // Get MSS option
3641 MyTCB.wRemoteMSS = GetMaxSegSizeOption();
3642  
3643 if(localHeaderFlags & ACK)
3644 {
3645 SendTCP(ACK, SENDTCP_RESET_TIMERS);
3646 MyTCBStub.smState = TCP_ESTABLISHED;
3647 // Set up keep-alive timer
3648 #if defined(TCP_KEEP_ALIVE_TIMEOUT)
3649 MyTCBStub.eventTime = TickGet() + TCP_KEEP_ALIVE_TIMEOUT;
3650 #endif
3651 MyTCBStub.Flags.bTimerEnabled = 0;
3652 }
3653 else
3654 {
3655 SendTCP(SYN | ACK, SENDTCP_RESET_TIMERS);
3656 MyTCBStub.smState = TCP_SYN_RECEIVED;
3657 }
3658 }
3659  
3660 // Fifth: drop the segment if neither SYN or RST is set
3661 return;
3662  
3663 default:
3664 break;
3665 }
3666  
3667 //
3668 // First: check the sequence number
3669 //
3670 wSegmentLength = len;
3671 if(localHeaderFlags & FIN)
3672 wSegmentLength++;
3673 if(localHeaderFlags & SYN)
3674 wSegmentLength++;
3675  
3676 // Calculate the RX FIFO space
3677 if(MyTCBStub.rxHead >= MyTCBStub.rxTail)
3678 wFreeSpace = (MyTCBStub.bufferEnd - MyTCBStub.bufferRxStart) - (MyTCBStub.rxHead - MyTCBStub.rxTail);
3679 else
3680 wFreeSpace = MyTCBStub.rxTail - MyTCBStub.rxHead - 1;
3681  
3682 // Calculate the number of bytes ahead of our head pointer this segment skips
3683 lMissingBytes = localSeqNumber - MyTCB.RemoteSEQ;
3684 wMissingBytes = (WORD)lMissingBytes;
3685  
3686 // Run TCP acceptability tests to verify that this packet has a valid sequence number
3687 bSegmentAcceptable = FALSE;
3688 if(wSegmentLength)
3689 {
3690 // Check to see if we have free space, and if so, if any of the data falls within the freespace
3691 if(wFreeSpace)
3692 {
3693 // RCV.NXT =< SEG.SEQ < RCV.NXT+RCV.WND
3694 if((lMissingBytes >= (LONG)0) && (wFreeSpace > (DWORD)lMissingBytes))
3695 bSegmentAcceptable = TRUE;
3696 else
3697 {
3698 // RCV.NXT =< SEG.SEQ+SEG.LEN-1 < RCV.NXT+RCV.WND
3699 if((lMissingBytes + (LONG)wSegmentLength > (LONG)0) && (lMissingBytes <= (LONG)(SHORT)(wFreeSpace - wSegmentLength)))
3700 bSegmentAcceptable = TRUE;
3701 }
3702  
3703 if((lMissingBytes < (LONG)wFreeSpace) && ((SHORT)wMissingBytes + (SHORT)wSegmentLength > (SHORT)0))
3704 bSegmentAcceptable = TRUE;
3705 }
3706 // Segments with data are not acceptable if we have no free space
3707 }
3708 else
3709 {
3710 // Zero length packets are acceptable if they fall within our free space window
3711 // SEG.SEQ = RCV.NXT
3712 if(lMissingBytes == 0)
3713 {
3714 bSegmentAcceptable = TRUE;
3715 }
3716 else
3717 {
3718 // RCV.NXT =< SEG.SEQ < RCV.NXT+RCV.WND
3719 if((lMissingBytes >= (LONG)0) && (wFreeSpace > (DWORD)lMissingBytes))
3720 bSegmentAcceptable = TRUE;
3721 }
3722 }
3723  
3724 if(!bSegmentAcceptable)
3725 {
3726 // Unacceptable segment, drop it and respond appropriately
3727 if(!(localHeaderFlags & RST))
3728 SendTCP(ACK, SENDTCP_RESET_TIMERS);
3729 return;
3730 }
3731  
3732  
3733 //
3734 // Second: check the RST bit
3735 //
3736 //
3737 // Fourth: check the SYN bit
3738 //
3739 // Note, that since the third step is not implemented, we can
3740 // combine this second and fourth step into a single operation.
3741 if(localHeaderFlags & (RST | SYN))
3742 {
3743 CloseSocket();
3744 return;
3745 }
3746  
3747 //
3748 // Third: check the security and precedence
3749 //
3750 // Feature not supported. Let's process this segment.
3751  
3752 //
3753 // Fifth: check the ACK bit
3754 //
3755 if(!(localHeaderFlags & ACK))
3756 return;
3757  
3758 switch(MyTCBStub.smState)
3759 {
3760 case TCP_SYN_RECEIVED:
3761 if(localAckNumber != MyTCB.MySEQ)
3762 {
3763 // Send a RST packet with SEQ = SEG.ACK, but retain our SEQ
3764 // number for arivial of any other correct packets
3765 localSeqNumber = MyTCB.MySEQ; // Save our original SEQ number
3766 MyTCB.MySEQ = localAckNumber; // Set SEQ = SEG.ACK
3767 SendTCP(RST, SENDTCP_RESET_TIMERS); // Send the RST
3768 MyTCB.MySEQ = localSeqNumber; // Restore original SEQ number
3769 return;
3770 }
3771 MyTCBStub.smState = TCP_ESTABLISHED;
3772 // No break
3773  
3774 case TCP_ESTABLISHED:
3775 case TCP_FIN_WAIT_1:
3776 case TCP_FIN_WAIT_2:
3777 case TCP_CLOSE_WAIT:
3778 case TCP_CLOSING:
3779 // Calculate what the highest possible SEQ number in our TX FIFO is
3780 wTemp = MyTCBStub.txHead - MyTCB.txUnackedTail;
3781 if((SHORT)wTemp < (SHORT)0)
3782 wTemp += MyTCBStub.bufferRxStart - MyTCBStub.bufferTxStart;
3783 dwTemp = MyTCB.MySEQ + (DWORD)wTemp;
3784  
3785 // Drop the packet if it ACKs something we haven't sent
3786 if((LONG)(dwTemp - localAckNumber) < (LONG)0)
3787 {
3788 SendTCP(ACK, 0);
3789 return;
3790 }
3791  
3792 // Throw away all ACKnowledged TX data:
3793 // Calculate what the last acknowledged sequence number was (ignoring any FINs we sent)
3794 dwTemp = MyTCB.MySEQ - (LONG)(SHORT)(MyTCB.txUnackedTail - MyTCBStub.txTail);
3795 if(MyTCB.txUnackedTail < MyTCBStub.txTail)
3796 dwTemp -= MyTCBStub.bufferRxStart - MyTCBStub.bufferTxStart;
3797  
3798 // Calcluate how many bytes were ACKed with this packet
3799 dwTemp = localAckNumber - dwTemp;
3800 if(((LONG)(dwTemp) > (LONG)0) && (dwTemp <= MyTCBStub.bufferRxStart - MyTCBStub.bufferTxStart))
3801 {
3802 MyTCB.flags.bRXNoneACKed1 = 0;
3803 MyTCB.flags.bRXNoneACKed2 = 0;
3804 MyTCBStub.Flags.bHalfFullFlush = FALSE;
3805  
3806 // Bytes ACKed, free up the TX FIFO space
3807 wTemp = MyTCBStub.txTail;
3808 MyTCBStub.txTail += dwTemp;
3809 if(MyTCB.txUnackedTail >= wTemp)
3810 {
3811 if(MyTCB.txUnackedTail < MyTCBStub.txTail)
3812 {
3813 MyTCB.MySEQ += MyTCBStub.txTail - MyTCB.txUnackedTail;
3814 MyTCB.txUnackedTail = MyTCBStub.txTail;
3815 }
3816 }
3817 else
3818 {
3819 wTemp = MyTCB.txUnackedTail + (MyTCBStub.bufferRxStart - MyTCBStub.bufferTxStart);
3820 if(wTemp < MyTCBStub.txTail)
3821 {
3822 MyTCB.MySEQ += MyTCBStub.txTail - wTemp;
3823 MyTCB.txUnackedTail = MyTCBStub.txTail;
3824 }
3825 }
3826 if(MyTCBStub.txTail >= MyTCBStub.bufferRxStart)
3827 MyTCBStub.txTail -= MyTCBStub.bufferRxStart - MyTCBStub.bufferTxStart;
3828 if(MyTCB.txUnackedTail >= MyTCBStub.bufferRxStart)
3829 MyTCB.txUnackedTail -= MyTCBStub.bufferRxStart - MyTCBStub.bufferTxStart;
3830 }
3831 else
3832 {
3833 // See if we have outstanding TX data that is waiting for an ACK
3834 if(MyTCBStub.txTail != MyTCB.txUnackedTail)
3835 {
3836 if(MyTCB.flags.bRXNoneACKed1)
3837 {
3838 if(MyTCB.flags.bRXNoneACKed2)
3839 {
3840 // Set up to perform a fast retransmission
3841 // Roll back unacknowledged TX tail pointer to cause retransmit to occur
3842 MyTCB.MySEQ -= (LONG)(SHORT)(MyTCB.txUnackedTail - MyTCBStub.txTail);
3843 if(MyTCB.txUnackedTail < MyTCBStub.txTail)
3844 MyTCB.MySEQ -= (LONG)(SHORT)(MyTCBStub.bufferRxStart - MyTCBStub.bufferTxStart);
3845 MyTCB.txUnackedTail = MyTCBStub.txTail;
3846 MyTCBStub.Flags.bTXASAPWithoutTimerReset = 1;
3847 }
3848 MyTCB.flags.bRXNoneACKed2 = 1;
3849 }
3850 MyTCB.flags.bRXNoneACKed1 = 1;
3851 }
3852 }
3853  
3854 // No need to keep our retransmit timer going if we have nothing that needs ACKing anymore
3855 if(MyTCBStub.txTail == MyTCBStub.txHead)
3856 {
3857 // Make sure there isn't a "FIN byte in our TX FIFO"
3858 if(MyTCBStub.Flags.bTXFIN == 0u)
3859 {
3860 // Convert retransmission timer to keep-alive timer
3861 #if defined(TCP_KEEP_ALIVE_TIMEOUT)
3862 MyTCBStub.eventTime = TickGet() + TCP_KEEP_ALIVE_TIMEOUT;
3863 #endif
3864 MyTCBStub.Flags.bTimerEnabled = 0;
3865 }
3866 else
3867 {
3868 // "Throw away" FIN byte from our TX FIFO if it has been ACKed
3869 if(MyTCB.MySEQ == localAckNumber)
3870 {
3871 MyTCBStub.Flags.bTimerEnabled = 0;
3872 MyTCBStub.Flags.bTXFIN = 0;
3873 MyTCB.flags.bFINSent = 0;
3874 }
3875 }
3876 }
3877  
3878 // Update the local stored copy of the RemoteWindow
3879 // If previously we had a zero window, and now we don't
3880 // immediately send whatever was pending
3881 if((MyTCB.remoteWindow == 0u) && h->Window)
3882 MyTCBStub.Flags.bTXASAP = 1;
3883 MyTCB.remoteWindow = h->Window;
3884  
3885 // A couple of states must do all of the TCP_ESTABLISHED stuff, but also a little more
3886 if(MyTCBStub.smState == TCP_FIN_WAIT_1)
3887 {
3888 // Check to see if our FIN has been ACKnowledged
3889 if(MyTCB.MySEQ == localAckNumber)
3890 {
3891 // Reset our timer for forced closure if the remote node
3892 // doesn't send us a FIN in a timely manner.
3893 MyTCBStub.eventTime = TickGet() + TCP_FIN_WAIT_2_TIMEOUT;
3894 MyTCBStub.Flags.bTimerEnabled = 1;
3895 MyTCBStub.smState = TCP_FIN_WAIT_2;
3896 }
3897 }
3898 else if(MyTCBStub.smState == TCP_FIN_WAIT_2)
3899 {
3900 // RFC noncompliance:
3901 // The remote node should not keep sending us data
3902 // indefinitely after we send a FIN to it.
3903 // However, some bad stacks may still keep sending
3904 // us data indefinitely after ACKing our FIN. To
3905 // prevent this from locking up our socket, let's
3906 // send a RST right now and close forcefully on
3907 // our side.
3908 if(!(localHeaderFlags & FIN))
3909 {
3910 MyTCB.MySEQ = localAckNumber; // Set SEQ = SEG.ACK
3911 SendTCP(RST | ACK, 0);
3912 CloseSocket();
3913 return;
3914 }
3915 }
3916 else if(MyTCBStub.smState == TCP_CLOSING)
3917 {
3918 // Check to see if our FIN has been ACKnowledged
3919 if(MyTCB.MySEQ == localAckNumber)
3920 {
3921 // RFC not recommended: We should be going to
3922 // the TCP_TIME_WAIT state right here and
3923 // starting a 2MSL timer, but since we have so
3924 // few precious sockets, we can't afford to
3925 // leave a socket waiting around doing nothing
3926 // for a long time. If the remote node does
3927 // not recieve this ACK, it'll have to figure
3928 // out on it's own that the connection is now
3929 // closed.
3930 CloseSocket();
3931 }
3932  
3933 return;
3934 }
3935  
3936 break;
3937  
3938 case TCP_LAST_ACK:
3939 // Check to see if our FIN has been ACKnowledged
3940 if(MyTCB.MySEQ == localAckNumber)
3941 CloseSocket();
3942 return;
3943  
3944 // case TCP_TIME_WAIT:
3945 // // Nothing is supposed to arrive here. If it does, reset the quiet timer.
3946 // SendTCP(ACK, SENDTCP_RESET_TIMERS);
3947 // return;
3948  
3949 default:
3950 break;
3951 }
3952  
3953 //
3954 // Sixth: Check the URG bit
3955 //
3956 // Urgent packets are not supported in this stack, so we
3957 // will throw them away instead
3958 if(localHeaderFlags & URG)
3959 return;
3960  
3961 //
3962 // Seventh: Process the segment text
3963 //
3964 // Throw data away if in a state that doesn't accept data
3965 if(MyTCBStub.smState == TCP_CLOSE_WAIT)
3966 return;
3967 if(MyTCBStub.smState == TCP_CLOSING)
3968 return;
3969 if(MyTCBStub.smState == TCP_LAST_ACK)
3970 return;
3971 // if(MyTCBStub.smState == TCP_TIME_WAIT)
3972 // return;
3973  
3974 // Copy any valid segment data into our RX FIFO, if any
3975 if(len)
3976 {
3977 // See if there are bytes we must skip
3978 if((SHORT)wMissingBytes <= 0)
3979 {
3980 // Position packet read pointer to start of useful data area.
3981 IPSetRxBuffer((h->DataOffset.Val << 2) - wMissingBytes);
3982 len += wMissingBytes;
3983  
3984 // Truncate packets that would overflow our TCP RX FIFO
3985 // and request a retransmit by sending a duplicate ACK
3986 if(len > wFreeSpace)
3987 len = wFreeSpace;
3988  
3989 MyTCB.RemoteSEQ += (DWORD)len;
3990  
3991 // Copy the application data from the packet into the socket RX FIFO
3992 // See if we need a two part copy (spans bufferEnd->bufferRxStart)
3993 if(MyTCBStub.rxHead + len > MyTCBStub.bufferEnd)
3994 {
3995 wTemp = MyTCBStub.bufferEnd - MyTCBStub.rxHead + 1;
3996 TCPRAMCopy(MyTCBStub.rxHead, MyTCBStub.vMemoryMedium, (PTR_BASE)-1, TCP_ETH_RAM, wTemp);
3997 TCPRAMCopy(MyTCBStub.bufferRxStart, MyTCBStub.vMemoryMedium, (PTR_BASE)-1, TCP_ETH_RAM, len - wTemp);
3998 MyTCBStub.rxHead = MyTCBStub.bufferRxStart + (len - wTemp);
3999 }
4000 else
4001 {
4002 TCPRAMCopy(MyTCBStub.rxHead, MyTCBStub.vMemoryMedium, (PTR_BASE)-1, TCP_ETH_RAM, len);
4003 MyTCBStub.rxHead += len;
4004 }
4005  
4006 // See if we have a hole and other data waiting already in the RX FIFO
4007 if(MyTCB.sHoleSize != -1)
4008 {
4009 MyTCB.sHoleSize -= len;
4010 wTemp = MyTCB.wFutureDataSize + MyTCB.sHoleSize;
4011  
4012 // See if we just closed up a hole, and if so, advance head pointer
4013 if((SHORT)wTemp < (SHORT)0)
4014 {
4015 MyTCB.sHoleSize = -1;
4016 }
4017 else if(MyTCB.sHoleSize <= 0)
4018 {
4019 MyTCB.RemoteSEQ += wTemp;
4020 MyTCBStub.rxHead += wTemp;
4021 if(MyTCBStub.rxHead > MyTCBStub.bufferEnd)
4022 MyTCBStub.rxHead -= MyTCBStub.bufferEnd - MyTCBStub.bufferRxStart + 1;
4023 MyTCB.sHoleSize = -1;
4024 }
4025 }
4026 } // This packet is out of order or we lost a packet, see if we can generate a hole to accomodate it
4027 else if((SHORT)wMissingBytes > 0)
4028 {
4029 // Truncate packets that would overflow our TCP RX FIFO
4030 if(len + wMissingBytes > wFreeSpace)
4031 len = wFreeSpace - wMissingBytes;
4032  
4033 // Position packet read pointer to start of useful data area.
4034 IPSetRxBuffer(h->DataOffset.Val << 2);
4035  
4036 // See if we need a two part copy (spans bufferEnd->bufferRxStart)
4037 if(MyTCBStub.rxHead + wMissingBytes + len > MyTCBStub.bufferEnd)
4038 {
4039 // Calculate number of data bytes to copy before wraparound
4040 wTemp = MyTCBStub.bufferEnd - MyTCBStub.rxHead + 1 - wMissingBytes;
4041 if((SHORT)wTemp >= 0)
4042 {
4043 TCPRAMCopy(MyTCBStub.rxHead + wMissingBytes, MyTCBStub.vMemoryMedium, (PTR_BASE)-1, TCP_ETH_RAM, wTemp);
4044 TCPRAMCopy(MyTCBStub.bufferRxStart, MyTCBStub.vMemoryMedium, (PTR_BASE)-1, TCP_ETH_RAM, len - wTemp);
4045 }
4046 else
4047 {
4048 TCPRAMCopy(MyTCBStub.rxHead + wMissingBytes - (MyTCBStub.bufferEnd - MyTCBStub.bufferRxStart + 1), MyTCBStub.vMemoryMedium, (PTR_BASE)-1, TCP_ETH_RAM, len);
4049 }
4050 }
4051 else
4052 {
4053 TCPRAMCopy(MyTCBStub.rxHead + wMissingBytes, MyTCBStub.vMemoryMedium, (PTR_BASE)-1, TCP_ETH_RAM, len);
4054 }
4055  
4056 // Record the hole is here
4057 if(MyTCB.sHoleSize == -1)
4058 {
4059 MyTCB.sHoleSize = wMissingBytes;
4060 MyTCB.wFutureDataSize = len;
4061 }
4062 else
4063 {
4064 // We already have a hole, see if we can shrink the hole
4065 // or extend the future data size
4066 if(wMissingBytes < (WORD)MyTCB.sHoleSize)
4067 {
4068 if((wMissingBytes + len > (WORD)MyTCB.sHoleSize + MyTCB.wFutureDataSize) || (wMissingBytes + len < (WORD)MyTCB.sHoleSize))
4069 MyTCB.wFutureDataSize = len;
4070 else
4071 MyTCB.wFutureDataSize = (WORD)MyTCB.sHoleSize + MyTCB.wFutureDataSize - wMissingBytes;
4072 MyTCB.sHoleSize = wMissingBytes;
4073 }
4074 else if(wMissingBytes + len > (WORD)MyTCB.sHoleSize + MyTCB.wFutureDataSize)
4075 {
4076 // Make sure that there isn't a second hole between
4077 // our future data and this TCP segment's future data
4078 if(wMissingBytes <= (WORD)MyTCB.sHoleSize + MyTCB.wFutureDataSize)
4079 MyTCB.wFutureDataSize += wMissingBytes + len - (WORD)MyTCB.sHoleSize - MyTCB.wFutureDataSize;
4080 }
4081  
4082 }
4083 }
4084 }
4085  
4086 // Send back an ACK of the data (+SYN | FIN) we just received,
4087 // if any. To minimize bandwidth waste, we are implementing
4088 // the delayed acknowledgement algorithm here, only sending
4089 // back an immediate ACK if this is the second segment received.
4090 // Otherwise, a 200ms timer will cause the ACK to be transmitted.
4091 if(wSegmentLength)
4092 {
4093 // For non-established sockets, let's delete all data in
4094 // the RX buffer immediately after receiving it. This is
4095 // not really how TCP was intended to operate since a
4096 // socket cannot receive any response after it sends a FIN,
4097 // but our TCP application API doesn't readily accomodate
4098 // receiving data after calling TCPDisconnect(), which
4099 // invalidates the application TCP handle. By deleting all
4100 // data, we'll ensure that the RX window is nonzero and
4101 // the remote node will be able to send us a FIN response,
4102 // which needs an RX window of at least 1.
4103 if(MyTCBStub.smState != TCP_ESTABLISHED)
4104 MyTCBStub.rxTail = MyTCBStub.rxHead;
4105  
4106 if(MyTCBStub.Flags.bOneSegmentReceived)
4107 {
4108 SendTCP(ACK, SENDTCP_RESET_TIMERS);
4109 SyncTCB();
4110 // bOneSegmentReceived is cleared in SendTCP(), so no need here
4111 }
4112 else
4113 {
4114 MyTCBStub.Flags.bOneSegmentReceived = TRUE;
4115  
4116 // Do not send an ACK immediately back. Instead, we will
4117 // perform delayed acknowledgements. To do this, we will
4118 // just start a timer
4119 if(!MyTCBStub.Flags.bDelayedACKTimerEnabled)
4120 {
4121 MyTCBStub.Flags.bDelayedACKTimerEnabled = 1;
4122 MyTCBStub.OverlappedTimers.delayedACKTime = (WORD)TickGetDiv256() + (WORD)((TCP_DELAYED_ACK_TIMEOUT)>>8);
4123 }
4124 }
4125 }
4126  
4127 //
4128 // Eighth: check the FIN bit
4129 //
4130 if(localHeaderFlags & FIN)
4131 {
4132 // Note: Since we don't have a good means of storing "FIN bytes"
4133 // in our TCP RX FIFO, we must ensure that FINs are processed
4134 // in-order.
4135 if(MyTCB.RemoteSEQ + 1 == localSeqNumber + (DWORD)wSegmentLength)
4136 {
4137 // FINs are treated as one byte of data for ACK sequencing
4138 MyTCB.RemoteSEQ++;
4139  
4140 switch(MyTCBStub.smState)
4141 {
4142 case TCP_SYN_RECEIVED:
4143 // RFC in exact: Our API has no need for the user
4144 // to explicitly close a socket that never really
4145 // got opened fully in the first place, so just
4146 // transmit a FIN automatically and jump to
4147 // TCP_LAST_ACK
4148 MyTCBStub.smState = TCP_LAST_ACK;
4149 SendTCP(FIN | ACK, SENDTCP_RESET_TIMERS);
4150 return;
4151  
4152 case TCP_ESTABLISHED:
4153 // Go to TCP_CLOSE_WAIT state
4154 MyTCBStub.smState = TCP_CLOSE_WAIT;
4155  
4156 // For legacy applications that don't call
4157 // TCPDisconnect() as needed and expect the TCP/IP
4158 // Stack to automatically close sockets when the
4159 // remote node sends a FIN, let's start a timer so
4160 // that we will eventually close the socket automatically
4161 MyTCBStub.OverlappedTimers.closeWaitTime = (WORD)TickGetDiv256() + (WORD)((TCP_CLOSE_WAIT_TIMEOUT)>>8);
4162 break;
4163  
4164 case TCP_FIN_WAIT_1:
4165 if(MyTCB.MySEQ == localAckNumber)
4166 {
4167 // RFC not recommended: We should be going to
4168 // the TCP_TIME_WAIT state right here and
4169 // starting a 2MSL timer, but since we have so
4170 // few precious sockets, we can't afford to
4171 // leave a socket waiting around doing nothing
4172 // for a long time. If the remote node does
4173 // not recieve this ACK, it'll have to figure
4174 // out on it's own that the connection is now
4175 // closed.
4176 SendTCP(ACK, 0);
4177 CloseSocket();
4178 return;
4179 }
4180 else
4181 {
4182 MyTCBStub.smState = TCP_CLOSING;
4183 }
4184 break;
4185  
4186 case TCP_FIN_WAIT_2:
4187 // RFC not recommended: We should be going to
4188 // the TCP_TIME_WAIT state right here and
4189 // starting a 2MSL timer, but since we have so
4190 // few precious sockets, we can't afford to
4191 // leave a socket waiting around doing nothing
4192 // for a long time. If the remote node does
4193 // not recieve this ACK, it'll have to figure
4194 // out on it's own that the connection is now
4195 // closed.
4196 SendTCP(ACK, 0);
4197 CloseSocket();
4198 return;
4199  
4200 default:
4201 break;
4202 }
4203  
4204 // Acknowledge receipt of FIN
4205 SendTCP(ACK, SENDTCP_RESET_TIMERS);
4206 }
4207 }
4208 }
4209  
4210 /****************************************************************************
4211 Section:
4212 Buffer Management Functions
4213 ***************************************************************************/
4214  
4215 /*****************************************************************************
4216 Function:
4217 BOOL TCPAdjustFIFOSize(TCP_SOCKET hTCP, WORD wMinRXSize,
4218 WORD wMinTXSize, BYTE vFlags)
4219  
4220 Summary:
4221 Adjusts the relative sizes of the RX and TX buffers.
4222  
4223 Description:
4224 This function can be used to adjust the relative sizes of the RX and
4225 TX FIFO depending on the immediate needs of an application. Since a
4226 larger FIFO can allow more data to be sent in a given packet, adjusting
4227 the relative sizes on the fly can allow for optimal transmission speed
4228 for one-sided application protocols. For example, HTTP typically
4229 begins by receiving large amounts of data from the client, then switches
4230 to serving large amounts of data back. Adjusting the FIFO at these
4231 points can increase performance substantially. Once the FIFO is
4232 adjusted, a window update is sent.
4233  
4234 If neither or both of TCP_ADJUST_GIVE_REST_TO_TX and
4235 TCP_ADJUST_GIVE_REST_TO_RX are set, the function distributes the
4236 remaining space equally.
4237  
4238 Received data can be preserved as long as the buffer is expanding and
4239 has not wrapped.
4240  
4241 Precondition:
4242 TCP is initialized.
4243  
4244 Parameters:
4245 hTCP - The socket to be adjusted
4246 wMinRXSize - Minimum number of byte for the RX FIFO
4247 wMinTXSize - Minimum number of bytes for the RX FIFO
4248 vFlags - Any combination of TCP_ADJUST_GIVE_REST_TO_RX,
4249 TCP_ADJUST_GIVE_REST_TO_TX, TCP_ADJUST_PRESERVE_RX.
4250 TCP_ADJUST_PRESERVE_TX is not currently supported.
4251  
4252 Return Values:
4253 TRUE - The FIFOs were adjusted successfully
4254 FALSE - Minimum RX, Minimum TX, or flags couldn't be accommodated and
4255 therefore the socket was left unchanged.
4256  
4257 Side Effects:
4258 Any unacknowledged or untransmitted data in the TX FIFO is always
4259 deleted.
4260  
4261 Remarks:
4262 At least one byte must always be allocated to the RX buffer so that
4263 a FIN can be received. The function automatically corrects for this.
4264 ***************************************************************************/
4265 BOOL TCPAdjustFIFOSize(TCP_SOCKET hTCP, WORD wMinRXSize, WORD wMinTXSize, BYTE vFlags)
4266 {
4267 PTR_BASE ptrTemp, ptrHead;
4268 WORD wTXAllocation;
4269  
4270 // Load up info on this socket
4271 SyncTCBStub(hTCP);
4272  
4273 // RX has to be at least 1 byte to receive SYN and FIN bytes
4274 // from the remote node, even if they aren't stored in the RX FIFO
4275 if(wMinRXSize == 0u)
4276 wMinRXSize = 1;
4277  
4278 // SSL connections need to be able to send or receive at least
4279 // a full Alert record, MAC, and FIN
4280 #if defined(STACK_USE_SSL)
4281 if(TCPIsSSL(hTCP) && wMinRXSize < 25u)
4282 wMinRXSize = 25;
4283 if(TCPIsSSL(hTCP) && wMinTXSize < 25u)
4284 wMinTXSize = 25;
4285 #endif
4286  
4287 // Make sure space is available for minimums
4288 ptrTemp = MyTCBStub.bufferEnd - MyTCBStub.bufferTxStart - 1;
4289 if(wMinRXSize + wMinTXSize > ptrTemp)
4290 return FALSE;
4291  
4292 SyncTCB();
4293  
4294 // Set both allocation flags if none set
4295 if(!(vFlags & (TCP_ADJUST_GIVE_REST_TO_TX | TCP_ADJUST_GIVE_REST_TO_RX)))
4296 vFlags |= TCP_ADJUST_GIVE_REST_TO_TX | TCP_ADJUST_GIVE_REST_TO_RX;
4297  
4298  
4299 // Allocate minimums
4300 wTXAllocation = wMinTXSize;
4301 ptrTemp -= wMinRXSize + wMinTXSize;
4302  
4303 // Allocate extra
4304 if(vFlags & TCP_ADJUST_GIVE_REST_TO_TX)
4305 {
4306 if(vFlags & TCP_ADJUST_GIVE_REST_TO_RX)
4307 {
4308 // Do a 50%/50% split with any odd byte always going to the RX FIFO
4309 wTXAllocation += ptrTemp>>1;
4310 }
4311 else
4312 {
4313 wTXAllocation += ptrTemp;
4314 }
4315 }
4316  
4317 // Calculate new bufferRxStart pointer
4318 ptrTemp = MyTCBStub.bufferTxStart + wTXAllocation + 1;
4319  
4320 // Find the head pointer to use
4321 ptrHead = MyTCBStub.rxHead;
4322 #if defined(STACK_USE_SSL)
4323 if(TCPIsSSL(hTCP))
4324 ptrHead = MyTCBStub.sslRxHead;
4325 #endif
4326  
4327 // If there's out-of-order data pending, adjust the head pointer to compensate
4328 if(MyTCB.sHoleSize != -1)
4329 {
4330 ptrHead += MyTCB.sHoleSize + MyTCB.wFutureDataSize;
4331 if(ptrHead > MyTCBStub.bufferEnd)
4332 ptrHead -= MyTCBStub.bufferEnd - MyTCBStub.bufferRxStart + 1;
4333 }
4334  
4335 // Determine if resizing will lose any RX data
4336 if(MyTCBStub.rxTail < ptrHead)
4337 {
4338 if(ptrTemp > MyTCBStub.rxTail)
4339 {
4340 if(vFlags & TCP_ADJUST_PRESERVE_RX)
4341 return FALSE;
4342 else
4343 {
4344 MyTCBStub.rxTail = ptrTemp;
4345 MyTCBStub.rxHead = ptrTemp;
4346  
4347 #if defined(STACK_USE_SSL)
4348 MyTCBStub.sslRxHead = ptrTemp;
4349 #endif
4350 }
4351 }
4352 }
4353 else if(MyTCBStub.rxTail > ptrHead)
4354 {
4355 if(ptrTemp > MyTCBStub.bufferRxStart)
4356 {
4357 if(vFlags & TCP_ADJUST_PRESERVE_RX)
4358 return FALSE;
4359 else
4360 {
4361 MyTCBStub.rxTail = ptrTemp;
4362 MyTCBStub.rxHead = ptrTemp;
4363  
4364 #if defined(STACK_USE_SSL)
4365 MyTCBStub.sslRxHead = ptrTemp;
4366 #endif
4367 }
4368 }
4369 }
4370 else
4371 {
4372 // No data to preserve, but we may need to move
4373 // the pointers to stay in the RX space
4374 MyTCBStub.rxTail = ptrTemp;
4375 MyTCBStub.rxHead = ptrTemp;
4376  
4377 #if defined(STACK_USE_SSL)
4378 MyTCBStub.sslRxHead = ptrTemp;
4379 #endif
4380 }
4381  
4382 // If we need to preserve data that wrapped in the ring, we must copy
4383 if(ptrHead < MyTCBStub.rxTail && (vFlags & TCP_ADJUST_PRESERVE_RX))
4384 {
4385 TCPRAMCopy(ptrTemp, MyTCBStub.vMemoryMedium,
4386 MyTCBStub.bufferRxStart, MyTCBStub.vMemoryMedium,
4387 ptrHead - MyTCBStub.bufferRxStart);
4388  
4389 // Move the pointers if they were in front of the tail
4390 #if defined(STACK_USE_SSL)
4391 if(TCPIsSSL(hTCP) && MyTCBStub.sslRxHead < MyTCBStub.rxTail)
4392 MyTCBStub.sslRxHead -= MyTCBStub.bufferRxStart - ptrTemp;
4393 #endif
4394 if(MyTCBStub.rxHead < MyTCBStub.rxTail)
4395 MyTCBStub.rxHead -= MyTCBStub.bufferRxStart - ptrTemp;
4396 }
4397  
4398 // Move the RX buffer pointer - it's the one that divides the two
4399 MyTCBStub.bufferRxStart = ptrTemp;
4400  
4401 // Empty the TX buffer
4402 MyTCB.txUnackedTail = MyTCBStub.bufferTxStart;
4403 MyTCBStub.txTail = MyTCBStub.bufferTxStart;
4404 MyTCBStub.txHead = MyTCBStub.bufferTxStart;
4405  
4406 #if defined(STACK_USE_SSL)
4407 if(TCPIsSSL(hTCP))
4408 MyTCBStub.sslTxHead = MyTCBStub.txHead + 5;
4409 #endif
4410  
4411 // Send a window update to notify remote node of change
4412 if(MyTCBStub.smState == TCP_ESTABLISHED)
4413 SendTCP(ACK, SENDTCP_RESET_TIMERS);
4414  
4415 return TRUE;
4416  
4417 }
4418  
4419 /*****************************************************************************
4420 Function:
4421 static void TCPRAMCopy(PTR_BASE ptrDest, BYTE vDestType, PTR_BASE ptrSource,
4422 BYTE vSourceType, WORD wLength)
4423  
4424 Summary:
4425 Copies data to/from various memory mediums.
4426  
4427 Description:
4428 This function copies data between memory mediums (PIC RAM, SPI
4429 RAM, and Ethernet buffer RAM).
4430  
4431 Precondition:
4432 TCP is initialized.
4433  
4434 Parameters:
4435 ptrDest - Address to write to
4436 vDestType - Destination meidum (TCP_PIC_RAM, TCP_ETH_RAM, TCP_SPI_RAM)
4437 ptrSource - Address to copy from
4438 vSourceType - Source medium (TCP_PIC_RAM, TCP_ETH_RAM, or TCP_SPI_RAM)
4439 wLength - Number of bytes to copy
4440  
4441 Returns:
4442 None
4443  
4444 Remarks:
4445 Copying to a destination region that overlaps with the source address
4446 is supported only if the destination start address is at a lower memory
4447 address (closer to 0x0000) than the source pointer. However, if they do
4448 overlap there must be at least 4 bytes of non-overlap to ensure correct
4449 results due to hardware DMA requirements.
4450 ***************************************************************************/
4451 static void TCPRAMCopy(PTR_BASE ptrDest, BYTE vDestType, PTR_BASE ptrSource, BYTE vSourceType, WORD wLength)
4452 {
4453 #if defined(SPIRAM_CS_TRIS)
4454 BYTE vBuffer[16];
4455 WORD w;
4456 #endif
4457  
4458 switch(vSourceType)
4459 {
4460 case TCP_PIC_RAM:
4461 switch(vDestType)
4462 {
4463 case TCP_PIC_RAM:
4464 memcpy((void*)(BYTE*)ptrDest, (void*)(BYTE*)ptrSource, wLength);
4465 break;
4466  
4467 case TCP_ETH_RAM:
4468 if(ptrDest!=(PTR_BASE)-1)
4469 MACSetWritePtr(ptrDest);
4470 MACPutArray((BYTE*)ptrSource, wLength);
4471 break;
4472  
4473 #if defined(SPIRAM_CS_TRIS)
4474 case TCP_SPI_RAM:
4475 SPIRAMPutArray(ptrDest, (BYTE*)ptrSource, wLength);
4476 break;
4477 #endif
4478 }
4479 break;
4480  
4481 case TCP_ETH_RAM:
4482 switch(vDestType)
4483 {
4484 case TCP_PIC_RAM:
4485 if(ptrSource!=(PTR_BASE)-1)
4486 MACSetReadPtr(ptrSource);
4487 MACGetArray((BYTE*)ptrDest, wLength);
4488 break;
4489  
4490 case TCP_ETH_RAM:
4491 MACMemCopyAsync(ptrDest, ptrSource, wLength);
4492 while(!MACIsMemCopyDone());
4493 break;
4494  
4495 #if defined(SPIRAM_CS_TRIS)
4496 case TCP_SPI_RAM:
4497 if(ptrSource!=(PTR_BASE)-1)
4498 MACSetReadPtr(ptrSource);
4499 w = sizeof(vBuffer);
4500 while(wLength)
4501 {
4502 if(w > wLength)
4503 w = wLength;
4504  
4505 // Read and write a chunk
4506 MACGetArray(vBuffer, w);
4507 SPIRAMPutArray(ptrDest, vBuffer, w);
4508 ptrDest += w;
4509 wLength -= w;
4510 }
4511 break;
4512 #endif
4513 }
4514 break;
4515  
4516 #if defined(SPIRAM_CS_TRIS)
4517 case TCP_SPI_RAM:
4518 switch(vDestType)
4519 {
4520 case TCP_PIC_RAM:
4521 SPIRAMGetArray(ptrSource, (BYTE*)ptrDest, wLength);
4522 break;
4523  
4524 case TCP_ETH_RAM:
4525 if(ptrDest!=(PTR_BASE)-1)
4526 MACSetWritePtr(ptrDest);
4527 w = sizeof(vBuffer);
4528 while(wLength)
4529 {
4530 if(w > wLength)
4531 w = wLength;
4532  
4533 // Read and write a chunk
4534 SPIRAMGetArray(ptrSource, vBuffer, w);
4535 ptrSource += w;
4536 MACPutArray(vBuffer, w);
4537 wLength -= w;
4538 }
4539 break;
4540  
4541 case TCP_SPI_RAM:
4542 // Copy all of the data over in chunks
4543 w = sizeof(vBuffer);
4544 while(wLength)
4545 {
4546 if(w > wLength)
4547 w = wLength;
4548  
4549 SPIRAMGetArray(ptrSource, vBuffer, w);
4550 SPIRAMPutArray(ptrDest, vBuffer, w);
4551 ptrSource += w;
4552 ptrDest += w;
4553 wLength -= w;
4554 }
4555 break;
4556 }
4557 break;
4558 #endif
4559 }
4560 }
4561  
4562 /*****************************************************************************
4563 Function:
4564 static void TCPRAMCopyROM(PTR_BASE wDest, BYTE wDestType, ROM BYTE* wSource,
4565 WORD wLength)
4566  
4567 Summary:
4568 Copies data to/from various memory mediums.
4569  
4570 Description:
4571 This function copies data between memory mediums (PIC RAM, SPI
4572 RAM, and Ethernet buffer RAM). This function is to be used when
4573 copying from ROM.
4574  
4575 Precondition:
4576 TCP is initialized.
4577  
4578 Parameters:
4579 wDest - Address to write to
4580 wDestType - Destination meidum (TCP_PIC_RAM, TCP_ETH_RAM, TCP_SPI_RAM)
4581 wSource - Address to copy from
4582 wLength - Number of bytes to copy
4583  
4584 Returns:
4585 None
4586  
4587 Remarks:
4588 Copying to a destination region that overlaps with the source address
4589 is supported only if the destination start address is at a lower memory
4590 address (closer to 0x0000) than the source pointer.
4591  
4592 This function is aliased to TCPRAMCopy on non-PIC18 platforms.
4593 ***************************************************************************/
4594 #if defined(__18CXX)
4595 static void TCPRAMCopyROM(PTR_BASE wDest, BYTE wDestType, ROM BYTE* wSource, WORD wLength)
4596 {
4597 BYTE vBuffer[16];
4598 WORD w;
4599  
4600 switch(wDestType)
4601 {
4602 case TCP_PIC_RAM:
4603 memcpypgm2ram((void*)(BYTE*)wDest, (ROM void*)wSource, wLength);
4604 break;
4605  
4606 case TCP_ETH_RAM:
4607 if(wDest!=(PTR_BASE)-1)
4608 MACSetWritePtr(wDest);
4609 w = sizeof(vBuffer);
4610 while(wLength)
4611 {
4612 if(w > wLength)
4613 w = wLength;
4614  
4615 // Read and write a chunk
4616 memcpypgm2ram(vBuffer, (ROM void*)wSource, w);
4617 MACPutArray(vBuffer, w);
4618 wSource += w;
4619 wLength -= w;
4620 }
4621 break;
4622  
4623 #if defined(SPIRAM_CS_TRIS)
4624 case TCP_SPI_RAM:
4625 w = sizeof(vBuffer);
4626 while(wLength)
4627 {
4628 if(w > wLength)
4629 w = wLength;
4630  
4631 // Read and write a chunk
4632 memcpypgm2ram(vBuffer, (ROM void*)wSource, w);
4633 SPIRAMPutArray(wDest, vBuffer, w);
4634 wDest += w;
4635 wSource += w;
4636 wLength -= w;
4637 }
4638 break;
4639 #endif
4640 }
4641 }
4642 #endif
4643  
4644 /****************************************************************************
4645 Section:
4646 SSL Functions
4647 ***************************************************************************/
4648  
4649 /*****************************************************************************
4650 Function:
4651 BOOL TCPStartSSLClient(TCP_SOCKET hTCP, BYTE* host)
4652  
4653 Summary:
4654 Begins an SSL client session.
4655  
4656 Description:
4657 This function escalates the current connection to an SSL secured
4658 connection by initiating an SSL client handshake.
4659  
4660 Precondition:
4661 TCP is initialized and hTCP is already connected.
4662  
4663 Parameters:
4664 hTCP - TCP connection to secure
4665 host - Expected host name on certificate (currently ignored)
4666  
4667 Return Values:
4668 TRUE - an SSL connection was initiated
4669 FALSE - Insufficient SSL resources (stubs) were available
4670  
4671 Remarks:
4672 The host parameter is currently ignored and is not validated.
4673 ***************************************************************************/
4674 #if defined(STACK_USE_SSL_CLIENT)
4675 BOOL TCPStartSSLClient(TCP_SOCKET hTCP, BYTE* host)
4676 {
4677 BYTE i;
4678  
4679 SyncTCBStub(hTCP);
4680  
4681 // Make sure SSL is not established already
4682 if(MyTCBStub.sslStubID != SSL_INVALID_ID)
4683 return FALSE;
4684  
4685 // Try to start the session
4686 MyTCBStub.sslStubID = SSLStartSession(hTCP, NULL, 0);
4687  
4688 // Make sure a session stub was obtained
4689 if(MyTCBStub.sslStubID == SSL_INVALID_ID)
4690 return FALSE;
4691  
4692 // Mark connection as handshaking and return
4693 MyTCBStub.sslReqMessage = SSL_CLIENT_HELLO;
4694 MyTCBStub.sslRxHead = MyTCBStub.rxHead;
4695 MyTCBStub.sslTxHead = MyTCBStub.txHead;
4696 MyTCBStub.Flags.bSSLHandshaking = 1;
4697 for(i = 0; i < 5u; i++)
4698 {// Skip first 5 bytes in TX for the record header
4699 if(++MyTCBStub.sslTxHead >= MyTCBStub.bufferRxStart)
4700 MyTCBStub.sslTxHead = MyTCBStub.bufferTxStart;
4701 }
4702 return TRUE;
4703 }
4704 #endif // SSL Client
4705  
4706 /*****************************************************************************
4707 Function:
4708 BOOL TCPStartSSLClientEx(TCP_SOCKET hTCP, BYTE* host, BYTE * buffer, BYTE suppDataType)
4709  
4710 Summary:
4711 Begins an SSL client session.
4712  
4713 Description:
4714 This function escalates the current connection to an SSL secured
4715 connection by initiating an SSL client handshake.
4716  
4717 Precondition:
4718 TCP is initialized and hTCP is already connected.
4719  
4720 Parameters:
4721 hTCP - TCP connection to secure
4722 host - Expected host name on certificate (currently ignored)
4723 buffer - Buffer for supplementary data return
4724 suppDataType - Type of supplementary data to copy
4725  
4726 Return Values:
4727 TRUE - an SSL connection was initiated
4728 FALSE - Insufficient SSL resources (stubs) were available
4729  
4730 Remarks:
4731 The host parameter is currently ignored and is not validated.
4732 ***************************************************************************/
4733 #if defined(STACK_USE_SSL_CLIENT)
4734 BOOL TCPStartSSLClientEx(TCP_SOCKET hTCP, BYTE* host, void * buffer, BYTE suppDataType)
4735 {
4736 BYTE i;
4737  
4738 SyncTCBStub(hTCP);
4739  
4740 // Make sure SSL is not established already
4741 if(MyTCBStub.sslStubID != SSL_INVALID_ID)
4742 return FALSE;
4743  
4744 // Try to start the session
4745 MyTCBStub.sslStubID = SSLStartSession(hTCP, buffer, suppDataType);
4746  
4747 // Make sure a session stub was obtained
4748 if(MyTCBStub.sslStubID == SSL_INVALID_ID)
4749 return FALSE;
4750  
4751 // Mark connection as handshaking and return
4752 MyTCBStub.sslReqMessage = SSL_CLIENT_HELLO;
4753 MyTCBStub.sslRxHead = MyTCBStub.rxHead;
4754 MyTCBStub.sslTxHead = MyTCBStub.txHead;
4755 MyTCBStub.Flags.bSSLHandshaking = 1;
4756 for(i = 0; i < 5u; i++)
4757 {// Skip first 5 bytes in TX for the record header
4758 if(++MyTCBStub.sslTxHead >= MyTCBStub.bufferRxStart)
4759 MyTCBStub.sslTxHead = MyTCBStub.bufferTxStart;
4760 }
4761 return TRUE;
4762 }
4763 #endif // SSL Client
4764  
4765 /*****************************************************************************
4766 Function:
4767 BOOL TCPStartSSLServer(TCP_SOCKET hTCP)
4768  
4769 Summary:
4770 Begins an SSL server session.
4771  
4772 Description:
4773 This function sets up an SSL server session when a new connection is
4774 established on an SSL port.
4775  
4776 Precondition:
4777 TCP is initialized and hTCP is already connected.
4778  
4779 Parameters:
4780 hTCP - TCP connection to secure
4781  
4782 Return Values:
4783 TRUE - an SSL connection was initiated
4784 FALSE - Insufficient SSL resources (stubs) were available
4785 ***************************************************************************/
4786 #if defined(STACK_USE_SSL_SERVER)
4787 BOOL TCPStartSSLServer(TCP_SOCKET hTCP)
4788 {
4789 BYTE i;
4790  
4791 SyncTCBStub(hTCP);
4792 SyncTCB();
4793  
4794 // Make sure SSL is not established already
4795 if(MyTCBStub.sslStubID != SSL_INVALID_ID)
4796 return TRUE;
4797  
4798 // Try to start the session
4799 MyTCBStub.sslStubID = SSLStartSession(hTCP, NULL, 0);
4800  
4801 // Make sure a session stub was obtained
4802 if(MyTCBStub.sslStubID == SSL_INVALID_ID)
4803 return FALSE;
4804  
4805 // Swap the localPort and localSSLPort
4806 MyTCBStub.remoteHash.Val = MyTCB.localPort.Val;
4807 MyTCB.localPort.Val = MyTCB.localSSLPort.Val;
4808 MyTCB.localSSLPort.Val = MyTCBStub.remoteHash.Val;
4809  
4810 // Mark connection as handshaking and return
4811 MyTCBStub.sslReqMessage = SSL_NO_MESSAGE;
4812 MyTCBStub.sslRxHead = MyTCBStub.rxHead;
4813 MyTCBStub.sslTxHead = MyTCBStub.txHead;
4814 MyTCBStub.Flags.bSSLHandshaking = 1;
4815 for(i = 0; i < 5u; i++)
4816 {// Skip first 5 bytes in TX for the record header
4817 if(++MyTCBStub.sslTxHead >= MyTCBStub.bufferRxStart)
4818 MyTCBStub.sslTxHead = MyTCBStub.bufferTxStart;
4819 }
4820 return TRUE;
4821 }
4822 #endif // SSL Client
4823  
4824 /*****************************************************************************
4825 Function:
4826 BOOL TCPAddSSLListener(TCP_SOCKET hTCP, WORD port)
4827  
4828 Summary:
4829 Listens for SSL connection on a specific port.
4830  
4831 Description:
4832 This function adds an additional listening port to a TCP connection.
4833 Connections made on this alternate port will be secured via SSL.
4834  
4835 Precondition:
4836 TCP is initialized and hTCP is listening.
4837  
4838 Parameters:
4839 hTCP - TCP connection to secure
4840 port - SSL port to listen on
4841  
4842 Return Values:
4843 TRUE - SSL port was added.
4844 FALSE - The socket was not a listening socket.
4845 ***************************************************************************/
4846 #if defined(STACK_USE_SSL_SERVER)
4847 BOOL TCPAddSSLListener(TCP_SOCKET hTCP, WORD port)
4848 {
4849 SyncTCBStub(hTCP);
4850  
4851 if(MyTCBStub.smState != TCP_LISTEN)
4852 return FALSE;
4853  
4854 SyncTCB();
4855  
4856 MyTCB.localSSLPort.Val = port;
4857 MyTCBStub.sslTxHead = port;
4858  
4859 return TRUE;
4860 }
4861 #endif // SSL Server
4862  
4863 /*****************************************************************************
4864 Function:
4865 BOOL TCPRequestSSLMessage(TCP_SOCKET hTCP, BYTE msg)
4866  
4867 Summary:
4868 Requests an SSL message to be transmitted.
4869  
4870 Description:
4871 This function is called to request that a specific SSL message be
4872 transmitted. This message should only be called by the SSL module.
4873  
4874 Precondition:
4875 TCP is initialized.
4876  
4877 Parameters:
4878 hTCP - TCP connection to use
4879 msg - One of the SSL_MESSAGE types to transmit.
4880  
4881 Return Values:
4882 TRUE - The message was requested.
4883 FALSE - Another message is already pending transmission.
4884 ***************************************************************************/
4885 #if defined(STACK_USE_SSL)
4886 BOOL TCPRequestSSLMessage(TCP_SOCKET hTCP, BYTE msg)
4887 {
4888 SyncTCBStub(hTCP);
4889  
4890 if(msg == SSL_NO_MESSAGE || MyTCBStub.sslReqMessage == SSL_NO_MESSAGE)
4891 {
4892 MyTCBStub.sslReqMessage = msg;
4893 return TRUE;
4894 }
4895  
4896 return FALSE;
4897 }
4898 #endif // SSL
4899  
4900 /*****************************************************************************
4901 Function:
4902 BOOL TCPSSLIsHandshaking(TCP_SOCKET hTCP)
4903  
4904 Summary:
4905 Determines if an SSL session is still handshaking.
4906  
4907 Description:
4908 Call this function after calling TCPStartSSLClient until FALSE is
4909 returned. Then your application may continue with its normal data
4910 transfer (which is now secured).
4911  
4912 Precondition:
4913 TCP is initialized and hTCP is connected.
4914  
4915 Parameters:
4916 hTCP - TCP connection to check
4917  
4918 Return Values:
4919 TRUE - SSL handshake is still progressing
4920 FALSE - SSL handshake has completed
4921 ***************************************************************************/
4922 #if defined(STACK_USE_SSL)
4923 BOOL TCPSSLIsHandshaking(TCP_SOCKET hTCP)
4924 {
4925 SyncTCBStub(hTCP);
4926 return MyTCBStub.Flags.bSSLHandshaking;
4927 }
4928 #endif // SSL
4929  
4930 /*****************************************************************************
4931 Function:
4932 BOOL TCPIsSSL(TCP_SOCKET hTCP)
4933  
4934 Summary:
4935 Determines if a TCP connection is secured with SSL.
4936  
4937 Description:
4938 Call this function to determine whether or not a TCP connection is
4939 secured with SSL.
4940  
4941 Precondition:
4942 TCP is initialized and hTCP is connected.
4943  
4944 Parameters:
4945 hTCP - TCP connection to check
4946  
4947 Return Values:
4948 TRUE - Connection is secured via SSL
4949 FALSE - Connection is not secured
4950 ***************************************************************************/
4951 #if defined(STACK_USE_SSL)
4952 BOOL TCPIsSSL(TCP_SOCKET hTCP)
4953 {
4954 SyncTCBStub(hTCP);
4955  
4956 if(MyTCBStub.sslStubID == SSL_INVALID_ID)
4957 return FALSE;
4958  
4959 return TRUE;
4960 }
4961 #endif // SSL
4962  
4963 /*****************************************************************************
4964 Function:
4965 void TCPSSLHandshakeComplete(TCP_SOCKET hTCP)
4966  
4967 Summary:
4968 Clears the SSL handshake flag.
4969  
4970 Description:
4971 This function clears the flag indicating that an SSL handshake is
4972 complete.
4973  
4974 Precondition:
4975 TCP is initialized and hTCP is connected.
4976  
4977 Parameters:
4978 hTCP - TCP connection to set
4979  
4980 Returns:
4981 None
4982  
4983 Remarks:
4984 This function should never be called by an application. It is used
4985 only by the SSL module itself.
4986 ***************************************************************************/
4987 #if defined(STACK_USE_SSL)
4988 void TCPSSLHandshakeComplete(TCP_SOCKET hTCP)
4989 {
4990 SyncTCBStub(hTCP);
4991 MyTCBStub.Flags.bSSLHandshaking = 0;
4992 }
4993 #endif // SSL
4994  
4995 /*****************************************************************************
4996 Function:
4997 void TCPSSLDecryptMAC(TCP_SOCKET hTCP, ARCFOUR_CTX* ctx, WORD len)
4998  
4999 Summary:
5000 Decrypts and MACs data arriving via SSL.
5001  
5002 Description:
5003 This function decrypts data in the TCP buffer and calculates the MAC over
5004 the data. All data is left in the exact same location in the TCP buffer.
5005 It is called to help process incoming SSL records.
5006  
5007 Precondition:
5008 TCP is initialized, hTCP is connected, and ctx's Sbox is loaded.
5009  
5010 Parameters:
5011 hTCP - TCP connection to decrypt in
5012 ctx - ARCFOUR encryption context to use
5013 len - Number of bytes to crypt
5014 inPlace - TRUE to write back in place, FALSE to write at end of
5015 currently visible data.
5016  
5017 Returns:
5018 None
5019  
5020 Remarks:
5021 This function should never be called by an application. It is used
5022 only by the SSL module itself.
5023 ***************************************************************************/
5024 #if defined(STACK_USE_SSL)
5025 void TCPSSLDecryptMAC(TCP_SOCKET hTCP, ARCFOUR_CTX* ctx, WORD len)
5026 {
5027 PTR_BASE wSrc, wDest, wBlockLen, wTemp;
5028 BYTE buffer[32];
5029  
5030 // Set up the pointers
5031 SyncTCBStub(hTCP);
5032 wSrc = MyTCBStub.rxTail;
5033 wDest = wSrc;
5034  
5035 // Handle 32 bytes at a time
5036 while(len)
5037 {
5038 // Determine how many bytes we can read
5039 wBlockLen = sizeof(buffer);
5040 if(wBlockLen > len) // Don't do more than we should
5041 wBlockLen = len;
5042  
5043 // Read those bytes to a buffer
5044 if(wSrc + wBlockLen > MyTCBStub.bufferEnd)
5045 {// Two part read
5046 wTemp = MyTCBStub.bufferEnd - wSrc + 1;
5047 TCPRAMCopy((PTR_BASE)buffer, TCP_PIC_RAM, wSrc, MyTCBStub.vMemoryMedium, wTemp);
5048 TCPRAMCopy((PTR_BASE)buffer+wTemp, TCP_PIC_RAM, MyTCBStub.bufferRxStart, MyTCBStub.vMemoryMedium, wBlockLen - wTemp);
5049 wSrc = MyTCBStub.bufferRxStart + wBlockLen - wTemp;
5050 }
5051 else
5052 {
5053 TCPRAMCopy((PTR_BASE)buffer, TCP_PIC_RAM, wSrc, MyTCBStub.vMemoryMedium, wBlockLen);
5054 wSrc += wBlockLen;
5055 }
5056  
5057 // Decrypt and hash
5058 ARCFOURCrypt(ctx, buffer, wBlockLen);
5059 SSLMACAdd(buffer, wBlockLen);
5060  
5061 // Write decrypted bytes back
5062 if(wDest + wBlockLen > MyTCBStub.bufferEnd)
5063 {// Two part write
5064 wTemp = MyTCBStub.bufferEnd - wDest + 1;
5065 TCPRAMCopy(wDest, MyTCBStub.vMemoryMedium, (PTR_BASE)buffer, TCP_PIC_RAM, wTemp);
5066 TCPRAMCopy(MyTCBStub.bufferRxStart, MyTCBStub.vMemoryMedium, (PTR_BASE)buffer+wTemp, TCP_PIC_RAM, wBlockLen - wTemp);
5067 wDest = MyTCBStub.bufferRxStart + wBlockLen - wTemp;
5068 }
5069 else
5070 {
5071 TCPRAMCopy(wDest, MyTCBStub.vMemoryMedium, (PTR_BASE)buffer, TCP_PIC_RAM, wBlockLen);
5072 wDest += wBlockLen;
5073 }
5074  
5075 // Update the length remaining
5076 len -= wBlockLen;
5077 }
5078 }
5079 #endif // SSL
5080  
5081 /*****************************************************************************
5082 Function:
5083 void TCPSSLInPlaceMACEncrypt(TCP_SOCKET hTCP, ARCFOUR_CTX* ctx,
5084 BYTE* MACSecret, WORD len)
5085  
5086 Summary:
5087 Encrypts and MACs data in place in the TCP TX buffer.
5088  
5089 Description:
5090 This function encrypts data in the TCP buffer while calcuating a MAC.
5091 When encryption is finished, the MAC is appended to the buffer and
5092 the record will be ready to transmit.
5093  
5094 Precondition:
5095 TCP is initialized, hTCP is connected, and ctx's Sbox is loaded.
5096  
5097 Parameters:
5098 hTCP - TCP connection to encrypt in
5099 ctx - ARCFOUR encryption context to use
5100 MACSecret - MAC encryption secret to use
5101 len - Number of bytes to crypt
5102  
5103 Returns:
5104 None
5105  
5106 Remarks:
5107 This function should never be called by an application. It is used
5108 only by the SSL module itself.
5109 ***************************************************************************/
5110 #if defined(STACK_USE_SSL)
5111 void TCPSSLInPlaceMACEncrypt(TCP_SOCKET hTCP, ARCFOUR_CTX* ctx, BYTE* MACSecret, WORD len)
5112 {
5113 PTR_BASE pos;
5114 WORD blockLen;
5115 BYTE buffer[32];
5116  
5117 // Set up the pointers
5118 SyncTCBStub(hTCP);
5119 pos = MyTCBStub.txHead;
5120 for(blockLen = 0; blockLen < 5u; blockLen++)
5121 {// Skips first 5 bytes for the header
5122 if(++pos >= MyTCBStub.bufferRxStart)
5123 pos = MyTCBStub.bufferTxStart;
5124 }
5125  
5126 // Handle 32 bytes at a time
5127 while(len)
5128 {
5129 // Determine how many bytes we can read
5130 blockLen = sizeof(buffer);
5131 if(blockLen > len) // Don't do more than we should
5132 blockLen = len;
5133 if(blockLen > MyTCBStub.bufferRxStart - pos) // Don't pass the end
5134 blockLen = MyTCBStub.bufferRxStart - pos;
5135  
5136 // Read those bytes to a buffer
5137 TCPRAMCopy((PTR_BASE)buffer, TCP_PIC_RAM, pos, MyTCBStub.vMemoryMedium, blockLen);
5138  
5139 // Hash and encrypt
5140 SSLMACAdd(buffer, blockLen);
5141 ARCFOURCrypt(ctx, buffer, blockLen);
5142  
5143 // Put them back
5144 TCPRAMCopy(pos, MyTCBStub.vMemoryMedium, (PTR_BASE)buffer, TCP_PIC_RAM, blockLen);
5145  
5146 // Update the pointers
5147 pos += blockLen;
5148 len -= blockLen;
5149 if(pos >= MyTCBStub.bufferRxStart)
5150 pos = MyTCBStub.bufferTxStart;
5151 }
5152  
5153 // Calculate and add the MAC
5154 SSLMACCalc(MACSecret, buffer);
5155 ARCFOURCrypt(ctx, buffer, 16);
5156  
5157 // Write the MAC to the TX FIFO
5158 // Can't use TCPPutArray here because TCPIsPutReady() saves 16 bytes for the MAC
5159 // TCPPut* functions use this to prevent writing too much data. Therefore, the
5160 // functionality is duplicated here.
5161  
5162 len = 16;
5163 blockLen = 0;
5164 // See if we need a two part put
5165 if(MyTCBStub.sslTxHead + len >= MyTCBStub.bufferRxStart)
5166 {
5167 blockLen = MyTCBStub.bufferRxStart-MyTCBStub.sslTxHead;
5168 TCPRAMCopy(MyTCBStub.sslTxHead, MyTCBStub.vMemoryMedium, (PTR_BASE)buffer, TCP_PIC_RAM, blockLen);
5169 len -= blockLen;
5170 MyTCBStub.sslTxHead = MyTCBStub.bufferTxStart;
5171 }
5172  
5173 TCPRAMCopy(MyTCBStub.sslTxHead, MyTCBStub.vMemoryMedium, (PTR_BASE)&buffer[blockLen], TCP_PIC_RAM, len);
5174 MyTCBStub.sslTxHead += len;
5175  
5176 }
5177 #endif // SSL
5178  
5179 /*****************************************************************************
5180 Function:
5181 void TCPSSLPutRecordHeader(TCP_SOCKET hTCP, BYTE* hdr, BOOL recDone)
5182  
5183 Summary:
5184 Writes an SSL record header and sends an SSL record.
5185  
5186 Description:
5187 This function writes an SSL record header to the pending TCP SSL data,
5188 then indicates that the data is ready to be sent by moving the txHead
5189 pointer.
5190  
5191 If the record is complete, set recDone to TRUE. The sslTxHead
5192 pointer will be moved forward 5 bytes to leave space for a future
5193 record header. If the record is only partially sent, use FALSE and
5194 to leave the pointer where it is so that more data can be added
5195 to the record. Partial records can only be used for the
5196 SERVER_CERTIFICATE handshake message.
5197  
5198 Precondition:
5199 TCP is initialized, and hTCP is connected with an active SSL session.
5200  
5201 Parameters:
5202 hTCP - TCP connection to write the header and transmit with
5203 hdr - Record header (5 bytes) to send or NULL to just
5204 move the pointerctx
5205 recDone - TRUE if the record is done, FALSE otherwise
5206  
5207 Returns:
5208 None
5209  
5210 Remarks:
5211 This function should never be called by an application. It is used
5212 only by the SSL module itself.
5213 ***************************************************************************/
5214 #if defined(STACK_USE_SSL)
5215 void TCPSSLPutRecordHeader(TCP_SOCKET hTCP, BYTE* hdr, BOOL recDone)
5216 {
5217 BYTE i;
5218  
5219 // Set up the pointers
5220 SyncTCBStub(hTCP);
5221  
5222 // Write the header if needed
5223 if(hdr)
5224 {// This is a new record, so insert the header
5225 for(i = 0; i < 5u; i++)
5226 {
5227 TCPRAMCopy(MyTCBStub.txHead, MyTCBStub.vMemoryMedium, (PTR_BASE)hdr+i, TCP_PIC_RAM, sizeof(BYTE));
5228 if(++MyTCBStub.txHead >= MyTCBStub.bufferRxStart)
5229 MyTCBStub.txHead = MyTCBStub.bufferTxStart;
5230 }
5231 }
5232  
5233 // Move the txHead pointer to indicate what data is ready
5234 // Also, flush just the header, then all the data. This shotguns two
5235 // packets down the line, therefore causing immediate ACKs by the
5236 // remote node. Reconnect handshakes are as much as 60% faster now.
5237 TCPFlush(hTCP);
5238 MyTCBStub.txHead = MyTCBStub.sslTxHead;
5239 TCPFlush(hTCP);
5240  
5241 // If this record is done, move the sslTxHead forward
5242 // to accomodate the next record header
5243 if(recDone)
5244 {
5245 for(i = 0; i < 5u; i++)
5246 {// Skip first 5 bytes in TX for the record header
5247 if(++MyTCBStub.sslTxHead >= MyTCBStub.bufferRxStart)
5248 MyTCBStub.sslTxHead = MyTCBStub.bufferTxStart;
5249 }
5250 }
5251 }
5252 #endif // SSL
5253  
5254 /*****************************************************************************
5255 Function:
5256 WORD TCPSSLGetPendingTxSize(TCP_SOCKET hTCP)
5257  
5258 Summary:
5259 Determines how many bytes are pending for a future SSL record.
5260  
5261 Description:
5262 This function determines how many bytes are pending for a future SSL
5263 record.
5264  
5265 Precondition:
5266 TCP is initialized, and hTCP is connected with an active SSL connection.
5267  
5268 Parameters:
5269 hTCP - TCP connection to check
5270  
5271 Returns:
5272 None
5273 ***************************************************************************/
5274 #if defined(STACK_USE_SSL)
5275 WORD TCPSSLGetPendingTxSize(TCP_SOCKET hTCP)
5276 {
5277 SyncTCBStub(hTCP);
5278  
5279 // Non-SSL connections have no pending SSL data
5280 //if(MyTCBStub.sslStubID == SSL_INVALID_ID)
5281 // return 0;
5282  
5283 // Determine how many bytes are waiting to be written in this record
5284 if(MyTCBStub.sslTxHead > MyTCBStub.txHead)
5285 return MyTCBStub.sslTxHead - MyTCBStub.txHead - 5;
5286 else
5287 return (MyTCBStub.bufferRxStart - MyTCBStub.bufferTxStart - 1) - (MyTCBStub.txHead - MyTCBStub.sslTxHead - 1) - 5;
5288 }
5289 #endif
5290  
5291  
5292 /*****************************************************************************
5293 Function:
5294 void TCPSSLHandleIncoming(TCP_SOCKET hTCP)
5295  
5296 Summary:
5297 Hands newly arrive TCP data to the SSL module for processing.
5298  
5299 Description:
5300 This function processes incoming TCP data as an SSL record and
5301 performs any necessary repositioning and decrypting.
5302  
5303 Precondition:
5304 TCP is initialized, and hTCP is connected with an active SSL session.
5305  
5306 Parameters:
5307 hTCP - TCP connection to handle incoming data on
5308  
5309 Returns:
5310 None
5311  
5312 Remarks:
5313 This function should never be called by an application. It is used
5314 only by the SSL module itself.
5315 ***************************************************************************/
5316 #if defined(STACK_USE_SSL)
5317 void TCPSSLHandleIncoming(TCP_SOCKET hTCP)
5318 {
5319 PTR_BASE prevRxTail, nextRxHead, startRxTail, wSrc, wDest;
5320 WORD wToMove, wLen, wSSLBytesThatPoofed, wDecryptedBytes;
5321  
5322 // Sync the stub
5323 SyncTCBStub(hTCP);
5324  
5325 // If new data is waiting
5326 if(MyTCBStub.sslRxHead != MyTCBStub.rxHead)
5327 {
5328 // Reconfigure pointers for SSL use
5329 prevRxTail = MyTCBStub.rxTail;
5330 nextRxHead = MyTCBStub.rxHead;
5331 MyTCBStub.rxTail = MyTCBStub.rxHead;
5332 MyTCBStub.rxHead = MyTCBStub.sslRxHead;
5333  
5334 do
5335 {
5336 startRxTail = MyTCBStub.rxTail;
5337  
5338 // Handle incoming data. This function performs deframing of the
5339 // SSL records, decryption, and MAC verification.
5340 wSSLBytesThatPoofed = TCPIsGetReady(hTCP);
5341 wDecryptedBytes = SSLRxRecord(hTCP, MyTCBStub.sslStubID);
5342 wSSLBytesThatPoofed -= TCPIsGetReady(hTCP);
5343  
5344 // Now need to move data to fill the SSL header/MAC/padding hole,
5345 // if there is one
5346 if(wSSLBytesThatPoofed)
5347 {
5348 // Sync the TCP so we can see if there is a TCP hole
5349 SyncTCB();
5350  
5351 // Calculate how big the SSL hole is
5352 if(MyTCB.sHoleSize == -1)
5353 {// Just need to move pending SSL data
5354 wToMove = TCPIsGetReady(hTCP);
5355 }
5356 else
5357 {// A TCP hole exists, so move all data
5358 wToMove = TCPIsGetReady(hTCP) + MyTCB.sHoleSize + MyTCB.wFutureDataSize;
5359 }
5360  
5361 // Start with the destination as the startRxTail and source as current rxTail
5362 wDest = startRxTail;
5363 wSrc = MyTCBStub.rxTail;
5364  
5365 // If data exists between the end of the buffer and
5366 // the destination, then move it forward
5367 if(wSrc > wDest)
5368 {
5369 wLen = MyTCBStub.bufferEnd - wSrc + 1;
5370 if(wLen > wToMove)
5371 wLen = wToMove;
5372 TCPRAMCopy(wDest, MyTCBStub.vMemoryMedium,
5373 wSrc, MyTCBStub.vMemoryMedium, wLen);
5374 wDest += wLen;
5375 wSrc = MyTCBStub.bufferRxStart;
5376 wToMove -= wLen;
5377 }
5378  
5379 // If data remains to be moved, fill in to end of buffer
5380 if(wToMove)
5381 {
5382 wLen = MyTCBStub.bufferEnd - wDest + 1;
5383 if(wLen > wToMove)
5384 wLen = wToMove;
5385 TCPRAMCopy(wDest, MyTCBStub.vMemoryMedium,
5386 wSrc, MyTCBStub.vMemoryMedium, wLen);
5387 wDest = MyTCBStub.bufferRxStart;
5388 wSrc += wLen;
5389 wToMove -= wLen;
5390 }
5391  
5392 // If data still remains, copy from from front + len to front
5393 if(wToMove)
5394 {
5395 TCPRAMCopy(wDest, MyTCBStub.vMemoryMedium,
5396 wSrc, MyTCBStub.vMemoryMedium, wToMove);
5397 }
5398  
5399 // Since bytes poofed, we need to move the head pointers
5400 // backwards by an equal amount.
5401 MyTCBStub.rxHead -= wSSLBytesThatPoofed;
5402 if(MyTCBStub.rxHead < MyTCBStub.bufferRxStart)
5403 MyTCBStub.rxHead += MyTCBStub.bufferEnd - MyTCBStub.bufferRxStart + 1;
5404 MyTCBStub.sslRxHead = MyTCBStub.rxHead;
5405 }
5406  
5407 // Move tail pointer forward by the number of decrypted bytes ready
5408 // for the application (but not poofed bytes)
5409 MyTCBStub.rxTail = startRxTail + wDecryptedBytes;
5410 if(MyTCBStub.rxTail > MyTCBStub.bufferEnd)
5411 MyTCBStub.rxTail -= MyTCBStub.bufferEnd - MyTCBStub.bufferRxStart + 1;
5412 nextRxHead += wDecryptedBytes;
5413  
5414 // Loop until SSLRxRecord() runs out of data and stops doing
5415 // anything
5416 } while(wSSLBytesThatPoofed || (startRxTail != MyTCBStub.rxTail));
5417  
5418 // Restore TCP buffer pointers to point to the decrypted application data
5419 // only
5420 if(nextRxHead > MyTCBStub.bufferEnd)
5421 nextRxHead -= MyTCBStub.bufferEnd - MyTCBStub.bufferRxStart + 1;
5422 MyTCBStub.rxTail = prevRxTail;
5423 MyTCBStub.rxHead = nextRxHead;
5424 }
5425 }
5426 #endif
5427  
5428  
5429 #endif //#if defined(STACK_USE_TCP)
{BLAME END}
{FOOTER START}

Powered by WebSVN v2.8.3