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 - Open a server socket and |
||
520 | ignore the dwRemoteHost parameter. |
||
521 | * TCP_OPEN_RAM_HOST - 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* |
||
525 | type) |
||
526 | * TCP_OPEN_ROM_HOST - 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* type) |
||
531 | * TCP_OPEN_IP_ADDRESS - 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 - 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 - 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 - 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)&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) |
Powered by WebSVN v2.8.3