]> begriffs open source - freertos/blob - FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_TCP_IP.c
Added +TCP code to main repo.
[freertos] / FreeRTOS-Plus / Source / FreeRTOS-Plus-TCP / FreeRTOS_TCP_IP.c
1 /*\r
2  * FreeRTOS+TCP Labs Build 160919 (C) 2016 Real Time Engineers ltd.\r
3  * Authors include Hein Tibosch and Richard Barry\r
4  *\r
5  *******************************************************************************\r
6  ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***\r
7  ***                                                                         ***\r
8  ***                                                                         ***\r
9  ***   FREERTOS+TCP IS STILL IN THE LAB (mainly because the FTP and HTTP     ***\r
10  ***   demos have a dependency on FreeRTOS+FAT, which is only in the Labs    ***\r
11  ***   download):                                                            ***\r
12  ***                                                                         ***\r
13  ***   FreeRTOS+TCP is functional and has been used in commercial products   ***\r
14  ***   for some time.  Be aware however that we are still refining its       ***\r
15  ***   design, the source code does not yet quite conform to the strict      ***\r
16  ***   coding and style standards mandated by Real Time Engineers ltd., and  ***\r
17  ***   the documentation and testing is not necessarily complete.            ***\r
18  ***                                                                         ***\r
19  ***   PLEASE REPORT EXPERIENCES USING THE SUPPORT RESOURCES FOUND ON THE    ***\r
20  ***   URL: http://www.FreeRTOS.org/contact  Active early adopters may, at   ***\r
21  ***   the sole discretion of Real Time Engineers Ltd., be offered versions  ***\r
22  ***   under a license other than that described below.                      ***\r
23  ***                                                                         ***\r
24  ***                                                                         ***\r
25  ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***\r
26  *******************************************************************************\r
27  *\r
28  * FreeRTOS+TCP can be used under two different free open source licenses.  The\r
29  * license that applies is dependent on the processor on which FreeRTOS+TCP is\r
30  * executed, as follows:\r
31  *\r
32  * If FreeRTOS+TCP is executed on one of the processors listed under the Special\r
33  * License Arrangements heading of the FreeRTOS+TCP license information web\r
34  * page, then it can be used under the terms of the FreeRTOS Open Source\r
35  * License.  If FreeRTOS+TCP is used on any other processor, then it can be used\r
36  * under the terms of the GNU General Public License V2.  Links to the relevant\r
37  * licenses follow:\r
38  *\r
39  * The FreeRTOS+TCP License Information Page: http://www.FreeRTOS.org/tcp_license\r
40  * The FreeRTOS Open Source License: http://www.FreeRTOS.org/license\r
41  * The GNU General Public License Version 2: http://www.FreeRTOS.org/gpl-2.0.txt\r
42  *\r
43  * FreeRTOS+TCP is distributed in the hope that it will be useful.  You cannot\r
44  * use FreeRTOS+TCP unless you agree that you use the software 'as is'.\r
45  * FreeRTOS+TCP is provided WITHOUT ANY WARRANTY; without even the implied\r
46  * warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR\r
47  * PURPOSE. Real Time Engineers Ltd. disclaims all conditions and terms, be they\r
48  * implied, expressed, or statutory.\r
49  *\r
50  * 1 tab == 4 spaces!\r
51  *\r
52  * http://www.FreeRTOS.org\r
53  * http://www.FreeRTOS.org/plus\r
54  * http://www.FreeRTOS.org/labs\r
55  *\r
56  */\r
57 \r
58 /*\r
59  * FreeRTOS_TCP_IP.c\r
60  * Module which handles the TCP connections for FreeRTOS+TCP.\r
61  * It depends on  FreeRTOS_TCP_WIN.c, which handles the TCP windowing\r
62  * schemes.\r
63  *\r
64  * Endianness: in this module all ports and IP addresses are stored in\r
65  * host byte-order, except fields in the IP-packets\r
66  */\r
67 \r
68 /* Standard includes. */\r
69 #include <stdint.h>\r
70 #include <stdio.h>\r
71 \r
72 /* FreeRTOS includes. */\r
73 #include "FreeRTOS.h"\r
74 #include "task.h"\r
75 #include "queue.h"\r
76 #include "semphr.h"\r
77 \r
78 /* FreeRTOS+TCP includes. */\r
79 #include "FreeRTOS_IP.h"\r
80 #include "FreeRTOS_Sockets.h"\r
81 #include "FreeRTOS_IP_Private.h"\r
82 #include "FreeRTOS_UDP_IP.h"\r
83 #include "FreeRTOS_TCP_IP.h"\r
84 #include "FreeRTOS_DHCP.h"\r
85 #include "NetworkInterface.h"\r
86 #include "NetworkBufferManagement.h"\r
87 #include "FreeRTOS_ARP.h"\r
88 #include "FreeRTOS_TCP_WIN.h"\r
89 \r
90 \r
91 /* Just make sure the contents doesn't get compiled if TCP is not enabled. */\r
92 #if ipconfigUSE_TCP == 1\r
93 \r
94 /* This compile-time test was moved to here because some macro's\r
95 were unknown within 'FreeRTOSIPConfigDefaults.h'.  It tests whether\r
96 the defined MTU size can contain at ;east a complete TCP packet. */\r
97 \r
98 #if ( ( ipconfigTCP_MSS + ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER ) > ipconfigNETWORK_MTU )\r
99         #error The ipconfigTCP_MSS setting in FreeRTOSIPConfig.h is too large.\r
100 #endif\r
101 \r
102 /*\r
103  * The meaning of the TCP flags:\r
104  */\r
105 #define ipTCP_FLAG_FIN                  0x0001u /* No more data from sender */\r
106 #define ipTCP_FLAG_SYN                  0x0002u /* Synchronize sequence numbers */\r
107 #define ipTCP_FLAG_RST                  0x0004u /* Reset the connection */\r
108 #define ipTCP_FLAG_PSH                  0x0008u /* Push function: please push buffered data to the recv application */\r
109 #define ipTCP_FLAG_ACK                  0x0010u /* Acknowledgment field is significant */\r
110 #define ipTCP_FLAG_URG                  0x0020u /* Urgent pointer field is significant */\r
111 #define ipTCP_FLAG_ECN                  0x0040u /* ECN-Echo */\r
112 #define ipTCP_FLAG_CWR                  0x0080u /* Congestion Window Reduced */\r
113 #define ipTCP_FLAG_NS                   0x0100u /* ECN-nonce concealment protection */\r
114 #define ipTCP_FLAG_RSV                  0x0E00u /* Reserved, keep 0 */\r
115 \r
116 /* A mask to filter all protocol flags. */\r
117 #define ipTCP_FLAG_CTRL                 0x001Fu\r
118 \r
119 /*\r
120  * A few values of the TCP options:\r
121  */\r
122 #define TCP_OPT_END                             0u   /* End of TCP options list */\r
123 #define TCP_OPT_NOOP                    1u   /* "No-operation" TCP option */\r
124 #define TCP_OPT_MSS                             2u   /* Maximum segment size TCP option */\r
125 #define TCP_OPT_WSOPT                   3u   /* TCP Window Scale Option (3-byte long) */\r
126 #define TCP_OPT_SACK_P                  4u   /* Advertize that SACK is permitted */\r
127 #define TCP_OPT_SACK_A                  5u   /* SACK option with first/last */\r
128 #define TCP_OPT_TIMESTAMP               8u   /* Time-stamp option */\r
129 \r
130 #define TCP_OPT_MSS_LEN                 4u   /* Length of TCP MSS option. */\r
131 #define TCP_OPT_WSOPT_LEN               3u   /* Length of TCP WSOPT option. */\r
132 \r
133 #define TCP_OPT_TIMESTAMP_LEN   10      /* fixed length of the time-stamp option */\r
134 \r
135 #ifndef ipconfigTCP_ACK_EARLIER_PACKET\r
136         #define ipconfigTCP_ACK_EARLIER_PACKET          1\r
137 #endif\r
138 \r
139 /*\r
140  * The macro NOW_CONNECTED() is use to determine if the connection makes a\r
141  * transition from connected to non-connected and vice versa.\r
142  * NOW_CONNECTED() returns true when the status has one of these values:\r
143  * eESTABLISHED, eFIN_WAIT_1, eFIN_WAIT_2, eCLOSING, eLAST_ACK, eTIME_WAIT\r
144  * Technically the connection status is closed earlier, but the library wants\r
145  * to prevent that the socket will be deleted before the last ACK has been\r
146  * and thus causing a 'RST' packet on either side.\r
147  */\r
148 #define NOW_CONNECTED( status )\\r
149         ( ( status >= eESTABLISHED ) && ( status != eCLOSE_WAIT ) )\r
150 \r
151 /*\r
152  * The highest 4 bits in the TCP offset byte indicate the total length of the\r
153  * TCP header, divided by 4.\r
154  */\r
155 #define VALID_BITS_IN_TCP_OFFSET_BYTE           ( 0xF0u )\r
156 \r
157 /*\r
158  * Acknowledgements to TCP data packets may be delayed as long as more is being expected.\r
159  * A normal delay would be 200ms.  Here a much shorter delay of 20 ms is being used to\r
160  * gain performance.\r
161  */\r
162 #define DELAYED_ACK_SHORT_DELAY_MS                      ( 2 )\r
163 #define DELAYED_ACK_LONGER_DELAY_MS                     ( 20 )\r
164 \r
165 /*\r
166  * The MSS (Maximum Segment Size) will be taken as large as possible. However, packets with\r
167  * an MSS of 1460 bytes won't be transported through the internet.  The MSS will be reduced\r
168  * to 1400 bytes.\r
169  */\r
170 #define REDUCED_MSS_THROUGH_INTERNET            ( 1400 )\r
171 \r
172 /*\r
173  * Each time a new TCP connection is being made, a new Initial Sequence Number shall be used.\r
174  * The variable 'ulNextInitialSequenceNumber' will be incremented with a recommended value\r
175  * of 0x102.\r
176  */\r
177 #define INITIAL_SEQUENCE_NUMBER_INCREMENT               ( 0x102UL )\r
178 \r
179 /*\r
180  * When there are no TCP options, the TCP offset equals 20 bytes, which is stored as\r
181  * the number 5 (words) in the higher niblle of the TCP-offset byte.\r
182  */\r
183 #define TCP_OFFSET_LENGTH_BITS                  ( 0xf0u )\r
184 #define TCP_OFFSET_STANDARD_LENGTH              ( 0x50u )\r
185 \r
186 /*\r
187  * Each TCP socket is checked regularly to see if it can send data packets.\r
188  * By default, the maximum number of packets sent during one check is limited to 8.\r
189  * This amount may be further limited by setting the socket's TX window size.\r
190  */\r
191 #if( !defined( SEND_REPEATED_COUNT ) )\r
192         #define SEND_REPEATED_COUNT             ( 8 )\r
193 #endif /* !defined( SEND_REPEATED_COUNT ) */\r
194 \r
195 /*\r
196  * Define a maximum perdiod of time (ms) to leave a TCP-socket unattended.\r
197  * When a TCP timer expires, retries and keep-alive messages will be checked.\r
198  */\r
199 #ifndef tcpMAXIMUM_TCP_WAKEUP_TIME_MS\r
200         #define tcpMAXIMUM_TCP_WAKEUP_TIME_MS           20000u\r
201 #endif\r
202 \r
203 /*\r
204  * The names of the different TCP states may be useful in logging.\r
205  */\r
206 #if( ( ipconfigHAS_DEBUG_PRINTF != 0 ) || ( ipconfigHAS_PRINTF != 0 ) )\r
207         static const char *pcStateNames[] = {\r
208                 "eCLOSED",\r
209                 "eTCP_LISTEN",\r
210                 "eCONNECT_SYN",\r
211                 "eSYN_FIRST",\r
212                 "eSYN_RECEIVED",\r
213                 "eESTABLISHED",\r
214                 "eFIN_WAIT_1",\r
215                 "eFIN_WAIT_2",\r
216                 "eCLOSE_WAIT",\r
217                 "eCLOSING",\r
218                 "eLAST_ACK",\r
219                 "eTIME_WAIT",\r
220                 "eUNKNOWN",\r
221 };\r
222 #endif /* ( ipconfigHAS_DEBUG_PRINTF != 0 ) || ( ipconfigHAS_PRINTF != 0 ) */\r
223 \r
224 /*\r
225  * Returns true if the socket must be checked.  Non-active sockets are waiting\r
226  * for user action, either connect() or close().\r
227  */\r
228 static BaseType_t prvTCPSocketIsActive( UBaseType_t uxStatus );\r
229 \r
230 /*\r
231  * Either sends a SYN or calls prvTCPSendRepeated (for regular messages).\r
232  */\r
233 static int32_t prvTCPSendPacket( FreeRTOS_Socket_t *pxSocket );\r
234 \r
235 /*\r
236  * Try to send a series of messages.\r
237  */\r
238 static int32_t prvTCPSendRepeated( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer );\r
239 \r
240 /*\r
241  * Return or send a packet to the other party.\r
242  */\r
243 static void prvTCPReturnPacket( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer,\r
244         uint32_t ulLen, BaseType_t xReleaseAfterSend );\r
245 \r
246 /*\r
247  * Initialise the data structures which keep track of the TCP windowing system.\r
248  */\r
249 static void prvTCPCreateWindow( FreeRTOS_Socket_t *pxSocket );\r
250 \r
251 /*\r
252  * Let ARP look-up the MAC-address of the peer and initialise the first SYN\r
253  * packet.\r
254  */\r
255 static BaseType_t prvTCPPrepareConnect( FreeRTOS_Socket_t *pxSocket );\r
256 \r
257 #if( ipconfigHAS_DEBUG_PRINTF != 0 )\r
258         /*\r
259          * For logging and debugging: make a string showing the TCP flags.\r
260          */\r
261         static const char *prvTCPFlagMeaning( UBaseType_t xFlags);\r
262 #endif /* ipconfigHAS_DEBUG_PRINTF != 0 */\r
263 \r
264 /*\r
265  * Parse the TCP option(s) received, if present.\r
266  */\r
267 static void prvCheckOptions( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer );\r
268 \r
269 /*\r
270  * Set the initial properties in the options fields, like the preferred\r
271  * value of MSS and whether SACK allowed.  Will be transmitted in the state\r
272  * 'eCONNECT_SYN'.\r
273  */\r
274 static UBaseType_t prvSetSynAckOptions( FreeRTOS_Socket_t *pxSocket, TCPPacket_t * pxTCPPacket );\r
275 \r
276 /*\r
277  * For anti-hang protection and TCP keep-alive messages.  Called in two places:\r
278  * after receiving a packet and after a state change.  The socket's alive timer\r
279  * may be reset.\r
280  */\r
281 static void prvTCPTouchSocket( FreeRTOS_Socket_t *pxSocket );\r
282 \r
283 /*\r
284  * Prepare an outgoing message, if anything has to be sent.\r
285  */\r
286 static int32_t prvTCPPrepareSend( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer, UBaseType_t uxOptionsLength );\r
287 \r
288 /*\r
289  * Calculate when this socket needs to be checked to do (re-)transmissions.\r
290  */\r
291 static TickType_t prvTCPNextTimeout( FreeRTOS_Socket_t *pxSocket );\r
292 \r
293 /*\r
294  * The API FreeRTOS_send() adds data to the TX stream.  Add\r
295  * this data to the windowing system to it can be transmitted.\r
296  */\r
297 static void prvTCPAddTxData( FreeRTOS_Socket_t *pxSocket );\r
298 \r
299 /*\r
300  *  Called to handle the closure of a TCP connection.\r
301  */\r
302 static BaseType_t prvTCPHandleFin( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer );\r
303 \r
304 #if(    ipconfigUSE_TCP_TIMESTAMPS == 1 )\r
305         static UBaseType_t prvTCPSetTimeStamp( BaseType_t lOffset, FreeRTOS_Socket_t *pxSocket, TCPHeader_t *pxTCPHeader );\r
306 #endif\r
307 \r
308 /*\r
309  * Called from prvTCPHandleState().  Find the TCP payload data and check and\r
310  * return its length.\r
311  */\r
312 static BaseType_t prvCheckRxData( NetworkBufferDescriptor_t *pxNetworkBuffer, uint8_t **ppucRecvData );\r
313 \r
314 /*\r
315  * Called from prvTCPHandleState().  Check if the payload data may be accepted.\r
316  * If so, it will be added to the socket's reception queue.\r
317  */\r
318 static BaseType_t prvStoreRxData( FreeRTOS_Socket_t *pxSocket, uint8_t *pucRecvData,\r
319         NetworkBufferDescriptor_t *pxNetworkBuffer, uint32_t ulReceiveLength );\r
320 \r
321 /*\r
322  * Set the TCP options (if any) for the outgoing packet.\r
323  */\r
324 static UBaseType_t prvSetOptions( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer );\r
325 \r
326 /*\r
327  * Called from prvTCPHandleState() as long as the TCP status is eSYN_RECEIVED to\r
328  * eCONNECT_SYN.\r
329  */\r
330 static BaseType_t prvHandleSynReceived( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer,\r
331         uint32_t ulReceiveLength, UBaseType_t uxOptionsLength );\r
332 \r
333 /*\r
334  * Called from prvTCPHandleState() as long as the TCP status is eESTABLISHED.\r
335  */\r
336 static BaseType_t prvHandleEstablished( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer,\r
337         uint32_t ulReceiveLength, UBaseType_t uxOptionsLength );\r
338 \r
339 /*\r
340  * Called from prvTCPHandleState().  There is data to be sent.\r
341  * If ipconfigUSE_TCP_WIN is defined, and if only an ACK must be sent, it will\r
342  * be checked if it would better be postponed for efficiency.\r
343  */\r
344 static BaseType_t prvSendData( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer,\r
345         uint32_t ulReceiveLength, BaseType_t xSendLength );\r
346 \r
347 /*\r
348  * The heart of all: check incoming packet for valid data and acks and do what\r
349  * is necessary in each state.\r
350  */\r
351 static BaseType_t prvTCPHandleState( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer );\r
352 \r
353 /*\r
354  * Reply to a peer with the RST flag on, in case a packet can not be handled.\r
355  */\r
356 static BaseType_t prvTCPSendReset( NetworkBufferDescriptor_t *pxNetworkBuffer );\r
357 \r
358 /*\r
359  * Set the initial value for MSS (Maximum Segment Size) to be used.\r
360  */\r
361 static void prvSocketSetMSS( FreeRTOS_Socket_t *pxSocket );\r
362 \r
363 /*\r
364  * Return either a newly created socket, or the current socket in a connected\r
365  * state (depends on the 'bReuseSocket' flag).\r
366  */\r
367 static FreeRTOS_Socket_t *prvHandleListen( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer );\r
368 \r
369 /*\r
370  * After a listening socket receives a new connection, it may duplicate itself.\r
371  * The copying takes place in prvTCPSocketCopy.\r
372  */\r
373 static BaseType_t prvTCPSocketCopy( FreeRTOS_Socket_t *pxNewSocket, FreeRTOS_Socket_t *pxSocket );\r
374 \r
375 /*\r
376  * prvTCPStatusAgeCheck() will see if the socket has been in a non-connected\r
377  * state for too long.  If so, the socket will be closed, and -1 will be\r
378  * returned.\r
379  */\r
380 #if( ipconfigTCP_HANG_PROTECTION == 1 )\r
381         static BaseType_t prvTCPStatusAgeCheck( FreeRTOS_Socket_t *pxSocket );\r
382 #endif\r
383 \r
384 static NetworkBufferDescriptor_t *prvTCPBufferResize( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer,\r
385         int32_t lDataLen, UBaseType_t uxOptionsLength );\r
386 \r
387 #if( ( ipconfigHAS_DEBUG_PRINTF != 0 ) || ( ipconfigHAS_PRINTF != 0 ) )\r
388         const char *FreeRTOS_GetTCPStateName( UBaseType_t ulState );\r
389 #endif\r
390 \r
391 #if( ipconfigUSE_TCP_WIN != 0 )\r
392         static uint8_t prvWinScaleFactor( FreeRTOS_Socket_t *pxSocket );\r
393 #endif\r
394 \r
395 /*-----------------------------------------------------------*/\r
396 \r
397 /* Initial Sequence Number, i.e. the next initial sequence number that will be\r
398 used when a new connection is opened.  The value should be randomized to prevent\r
399 attacks from outside (spoofing). */\r
400 uint32_t ulNextInitialSequenceNumber = 0ul;\r
401 \r
402 /*-----------------------------------------------------------*/\r
403 \r
404 /* prvTCPSocketIsActive() returns true if the socket must be checked.\r
405  * Non-active sockets are waiting for user action, either connect()\r
406  * or close(). */\r
407 static BaseType_t prvTCPSocketIsActive( UBaseType_t uxStatus )\r
408 {\r
409         switch( uxStatus )\r
410         {\r
411         case eCLOSED:\r
412         case eCLOSE_WAIT:\r
413         case eFIN_WAIT_2:\r
414         case eCLOSING:\r
415         case eTIME_WAIT:\r
416                 return pdFALSE;\r
417         default:\r
418                 return pdTRUE;\r
419         }\r
420 }\r
421 /*-----------------------------------------------------------*/\r
422 \r
423 #if( ipconfigTCP_HANG_PROTECTION == 1 )\r
424 \r
425         static BaseType_t prvTCPStatusAgeCheck( FreeRTOS_Socket_t *pxSocket )\r
426         {\r
427         BaseType_t xResult;\r
428                 switch( pxSocket->u.xTCP.ucTCPState )\r
429                 {\r
430                 case eESTABLISHED:\r
431                         /* If the 'ipconfigTCP_KEEP_ALIVE' option is enabled, sockets in\r
432                         state ESTABLISHED can be protected using keep-alive messages. */\r
433                         xResult = pdFALSE;\r
434                         break;\r
435                 case eCLOSED:\r
436                 case eTCP_LISTEN:\r
437                 case eCLOSE_WAIT:\r
438                         /* These 3 states may last for ever, up to the owner. */\r
439                         xResult = pdFALSE;\r
440                         break;\r
441                 default:\r
442                         /* All other (non-connected) states will get anti-hanging\r
443                         protection. */\r
444                         xResult = pdTRUE;\r
445                         break;\r
446                 }\r
447                 if( xResult != pdFALSE )\r
448                 {\r
449                         /* How much time has past since the last active moment which is\r
450                         defined as A) a state change or B) a packet has arrived. */\r
451                         TickType_t xAge = xTaskGetTickCount( ) - pxSocket->u.xTCP.xLastActTime;\r
452 \r
453                         /* ipconfigTCP_HANG_PROTECTION_TIME is in units of seconds. */\r
454                         if( xAge > ( ipconfigTCP_HANG_PROTECTION_TIME * configTICK_RATE_HZ ) )\r
455                         {\r
456                                 #if( ipconfigHAS_DEBUG_PRINTF == 1 )\r
457                                 {\r
458                                         FreeRTOS_debug_printf( ( "Inactive socket closed: port %u rem %lxip:%u status %s\n",\r
459                                                 pxSocket->usLocalPort,\r
460                                                 pxSocket->u.xTCP.ulRemoteIP,\r
461                                                 pxSocket->u.xTCP.usRemotePort,\r
462                                                 FreeRTOS_GetTCPStateName( ( UBaseType_t ) pxSocket->u.xTCP.ucTCPState ) ) );\r
463                                 }\r
464                                 #endif /* ipconfigHAS_DEBUG_PRINTF */\r
465 \r
466                                 /* Move to eCLOSE_WAIT, user may close the socket. */\r
467                                 vTCPStateChange( pxSocket, eCLOSE_WAIT );\r
468 \r
469                                 /* When 'bPassQueued' true, this socket is an orphan until it\r
470                                 gets connected. */\r
471                                 if( pxSocket->u.xTCP.bits.bPassQueued != pdFALSE_UNSIGNED )\r
472                                 {\r
473                                         if( pxSocket->u.xTCP.bits.bReuseSocket == pdFALSE_UNSIGNED )\r
474                                         {\r
475                                                 /* As it did not get connected, and the user can never\r
476                                                 accept() it anymore, it will be deleted now.  Called from\r
477                                                 the IP-task, so it's safe to call the internal Close\r
478                                                 function: vSocketClose(). */\r
479                                                 vSocketClose( pxSocket );\r
480                                         }\r
481                                         /* Return a negative value to tell to inform the caller\r
482                                         xTCPTimerCheck()\r
483                                         that the socket got closed and may not be accessed anymore. */\r
484                                         xResult = -1;\r
485                                 }\r
486                         }\r
487                 }\r
488                 return xResult;\r
489         }\r
490         /*-----------------------------------------------------------*/\r
491 \r
492 #endif\r
493 \r
494 /*\r
495  * As soon as a TCP socket timer expires, this function xTCPSocketCheck\r
496  * will be called (from xTCPTimerCheck)\r
497  * It can send a delayed ACK or new data\r
498  * Sequence of calling (normally) :\r
499  * IP-Task:\r
500  *              xTCPTimerCheck()                                // Check all sockets ( declared in FreeRTOS_Sockets.c )\r
501  *              xTCPSocketCheck()                               // Either send a delayed ACK or call prvTCPSendPacket()\r
502  *              prvTCPSendPacket()                              // Either send a SYN or call prvTCPSendRepeated ( regular messages )\r
503  *              prvTCPSendRepeated()                    // Send at most 8 messages on a row\r
504  *                      prvTCPReturnPacket()            // Prepare for returning\r
505  *                      xNetworkInterfaceOutput()       // Sends data to the NIC ( declared in portable/NetworkInterface/xxx )\r
506  */\r
507 BaseType_t xTCPSocketCheck( FreeRTOS_Socket_t *pxSocket )\r
508 {\r
509 BaseType_t xResult = 0;\r
510 BaseType_t xReady = pdFALSE;\r
511 \r
512         if( ( pxSocket->u.xTCP.ucTCPState >= eESTABLISHED ) && ( pxSocket->u.xTCP.txStream != NULL ) )\r
513         {\r
514                 /* The API FreeRTOS_send() might have added data to the TX stream.  Add\r
515                 this data to the windowing system so it can be transmitted. */\r
516                 prvTCPAddTxData( pxSocket );\r
517         }\r
518 \r
519         #if( ipconfigUSE_TCP_WIN == 1 )\r
520         {\r
521                 if( pxSocket->u.xTCP.pxAckMessage != NULL )\r
522                 {\r
523                         /* The first task of this regular socket check is to send-out delayed\r
524                         ACK's. */\r
525                         if( pxSocket->u.xTCP.bits.bUserShutdown == pdFALSE_UNSIGNED )\r
526                         {\r
527                                 /* Earlier data was received but not yet acknowledged.  This\r
528                                 function is called when the TCP timer for the socket expires, the\r
529                                 ACK may be sent now. */\r
530                                 if( pxSocket->u.xTCP.ucTCPState != eCLOSED )\r
531                                 {\r
532                                         if( xTCPWindowLoggingLevel > 1 && ipconfigTCP_MAY_LOG_PORT( pxSocket->usLocalPort ) )\r
533                                         {\r
534                                                 FreeRTOS_debug_printf( ( "Send[%u->%u] del ACK %lu SEQ %lu (len %u)\n",\r
535                                                         pxSocket->usLocalPort,\r
536                                                         pxSocket->u.xTCP.usRemotePort,\r
537                                                         pxSocket->u.xTCP.xTCPWindow.rx.ulCurrentSequenceNumber - pxSocket->u.xTCP.xTCPWindow.rx.ulFirstSequenceNumber,\r
538                                                         pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber   - pxSocket->u.xTCP.xTCPWindow.tx.ulFirstSequenceNumber,\r
539                                                         ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER ) );\r
540                                         }\r
541 \r
542                                         prvTCPReturnPacket( pxSocket, pxSocket->u.xTCP.pxAckMessage, ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER, ipconfigZERO_COPY_TX_DRIVER );\r
543 \r
544                                         #if( ipconfigZERO_COPY_TX_DRIVER != 0 )\r
545                                         {\r
546                                                 /* The ownership has been passed to the SEND routine,\r
547                                                 clear the pointer to it. */\r
548                                                 pxSocket->u.xTCP.pxAckMessage = NULL;\r
549                                         }\r
550                                         #endif /* ipconfigZERO_COPY_TX_DRIVER */\r
551                                 }\r
552                                 if( prvTCPNextTimeout( pxSocket ) > 1 )\r
553                                 {\r
554                                         /* Tell the code below that this function is ready. */\r
555                                         xReady = pdTRUE;\r
556                                 }\r
557                         }\r
558                         else\r
559                         {\r
560                                 /* The user wants to perform an active shutdown(), skip sending\r
561                                 the     delayed ACK.  The function prvTCPSendPacket() will send the\r
562                                 FIN     along with the ACK's. */\r
563                         }\r
564 \r
565                         if( pxSocket->u.xTCP.pxAckMessage != NULL )\r
566                         {\r
567                                 vReleaseNetworkBufferAndDescriptor( pxSocket->u.xTCP.pxAckMessage );\r
568                                 pxSocket->u.xTCP.pxAckMessage = NULL;\r
569                         }\r
570                 }\r
571         }\r
572         #endif /* ipconfigUSE_TCP_WIN */\r
573 \r
574         if( xReady == pdFALSE )\r
575         {\r
576                 /* The second task of this regular socket check is sending out data. */\r
577                 if( ( pxSocket->u.xTCP.ucTCPState >= eESTABLISHED ) ||\r
578                         ( pxSocket->u.xTCP.ucTCPState == eCONNECT_SYN ) )\r
579                 {\r
580                         prvTCPSendPacket( pxSocket );\r
581                 }\r
582 \r
583                 /* Set the time-out for the next wakeup for this socket. */\r
584                 prvTCPNextTimeout( pxSocket );\r
585 \r
586                 #if( ipconfigTCP_HANG_PROTECTION == 1 )\r
587                 {\r
588                         /* In all (non-connected) states in which keep-alive messages can not be sent\r
589                         the anti-hang protocol will close sockets that are 'hanging'. */\r
590                         xResult = prvTCPStatusAgeCheck( pxSocket );\r
591                 }\r
592                 #endif\r
593         }\r
594 \r
595         return xResult;\r
596 }\r
597 /*-----------------------------------------------------------*/\r
598 \r
599 /*\r
600  * prvTCPSendPacket() will be called when the socket time-out has been reached.\r
601  * It is only called by xTCPSocketCheck().\r
602  */\r
603 static int32_t prvTCPSendPacket( FreeRTOS_Socket_t *pxSocket )\r
604 {\r
605 int32_t lResult = 0;\r
606 UBaseType_t uxOptionsLength;\r
607 TCPPacket_t *pxTCPPacket;\r
608 NetworkBufferDescriptor_t *pxNetworkBuffer;\r
609 \r
610         if( pxSocket->u.xTCP.ucTCPState != eCONNECT_SYN )\r
611         {\r
612                 /* The connection is in a state other than SYN. */\r
613                 pxNetworkBuffer = NULL;\r
614 \r
615                 /* prvTCPSendRepeated() will only create a network buffer if necessary,\r
616                 i.e. when data must be sent to the peer. */\r
617                 lResult = prvTCPSendRepeated( pxSocket, &pxNetworkBuffer );\r
618 \r
619                 if( pxNetworkBuffer != NULL )\r
620                 {\r
621                         vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );\r
622                 }\r
623         }\r
624         else\r
625         {\r
626                 if( pxSocket->u.xTCP.ucRepCount >= 3u )\r
627                 {\r
628                         /* The connection is in the SYN status. The packet will be repeated\r
629                         to most 3 times.  When there is no response, the socket get the\r
630                         status 'eCLOSE_WAIT'. */\r
631                         FreeRTOS_debug_printf( ( "Connect: giving up %lxip:%u\n",\r
632                                 pxSocket->u.xTCP.ulRemoteIP,            /* IP address of remote machine. */\r
633                                 pxSocket->u.xTCP.usRemotePort ) );      /* Port on remote machine. */\r
634                         vTCPStateChange( pxSocket, eCLOSE_WAIT );\r
635                 }\r
636                 else if( ( pxSocket->u.xTCP.bits.bConnPrepared != pdFALSE_UNSIGNED ) || ( prvTCPPrepareConnect( pxSocket ) == pdTRUE ) )\r
637                 {\r
638                         /* Or else, if the connection has been prepared, or can be prepared\r
639                         now, proceed to send the packet with the SYN flag.\r
640                         prvTCPPrepareConnect() prepares 'xPacket' and returns pdTRUE if\r
641                         the Ethernet address of the peer or the gateway is found. */\r
642                         pxTCPPacket = ( TCPPacket_t * )pxSocket->u.xTCP.xPacket.u.ucLastPacket;\r
643 \r
644                         #if( ipconfigUSE_TCP_TIMESTAMPS == 1 )\r
645                         {\r
646                                 /* When TCP time stamps are enabled, but they will only be applied\r
647                                 if the peer is outside the netmask, usually on the internet.\r
648                                 Packages sent on a LAN are usually too big to carry time stamps. */\r
649                                 if( ( ( pxSocket->u.xTCP.ulRemoteIP ^ FreeRTOS_ntohl( *ipLOCAL_IP_ADDRESS_POINTER ) ) & xNetworkAddressing.ulNetMask ) != 0ul )\r
650                                 {\r
651                                         pxSocket->u.xTCP.xTCPWindow.u.bits.bTimeStamps = pdTRUE_UNSIGNED;\r
652                                 }\r
653                         }\r
654                         #endif\r
655 \r
656                         /* About to send a SYN packet.  Call prvSetSynAckOptions() to set\r
657                         the proper options: The size of MSS and whether SACK's are\r
658                         allowed. */\r
659                         uxOptionsLength = prvSetSynAckOptions( pxSocket, pxTCPPacket );\r
660 \r
661                         /* Return the number of bytes to be sent. */\r
662                         lResult = ( BaseType_t ) ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength );\r
663 \r
664                         /* Set the TCP offset field:  ipSIZE_OF_TCP_HEADER equals 20 and\r
665                         uxOptionsLength is always a multiple of 4.  The complete expression\r
666                         would be:\r
667                         ucTCPOffset = ( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) / 4 ) << 4 */\r
668                         pxTCPPacket->xTCPHeader.ucTCPOffset = ( uint8_t )( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 );\r
669 \r
670                         /* Repeat Count is used for a connecting socket, to limit the number\r
671                         of tries. */\r
672                         pxSocket->u.xTCP.ucRepCount++;\r
673 \r
674                         /* Send the SYN message to make a connection.  The messages is\r
675                         stored in the socket field 'xPacket'.  It will be wrapped in a\r
676                         pseudo network buffer descriptor before it will be sent. */\r
677                         prvTCPReturnPacket( pxSocket, NULL, ( uint32_t ) lResult, pdFALSE );\r
678                 }\r
679         }\r
680 \r
681         /* Return the total number of bytes sent. */\r
682         return lResult;\r
683 }\r
684 /*-----------------------------------------------------------*/\r
685 \r
686 /*\r
687  * prvTCPSendRepeated will try to send a series of messages, as long as there is\r
688  * data to be sent and as long as the transmit window isn't full.\r
689  */\r
690 static int32_t prvTCPSendRepeated( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer )\r
691 {\r
692 UBaseType_t uxIndex;\r
693 int32_t lResult = 0;\r
694 UBaseType_t uxOptionsLength = 0u;\r
695 int32_t xSendLength;\r
696 \r
697         for( uxIndex = 0u; uxIndex < ( UBaseType_t ) SEND_REPEATED_COUNT; uxIndex++ )\r
698         {\r
699                 /* prvTCPPrepareSend() might allocate a network buffer if there is data\r
700                 to be sent. */\r
701                 xSendLength = prvTCPPrepareSend( pxSocket, ppxNetworkBuffer, uxOptionsLength );\r
702                 if( xSendLength <= 0 )\r
703                 {\r
704                         break;\r
705                 }\r
706 \r
707                 /* And return the packet to the peer. */\r
708                 prvTCPReturnPacket( pxSocket, *ppxNetworkBuffer, ( uint32_t ) xSendLength, ipconfigZERO_COPY_TX_DRIVER );\r
709 \r
710                 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )\r
711                 {\r
712                         *ppxNetworkBuffer = NULL;\r
713                 }\r
714                 #endif /* ipconfigZERO_COPY_TX_DRIVER */\r
715 \r
716                 lResult += xSendLength;\r
717         }\r
718 \r
719         /* Return the total number of bytes sent. */\r
720         return lResult;\r
721 }\r
722 /*-----------------------------------------------------------*/\r
723 \r
724 /*\r
725  * Return (or send) a packet the the peer.  The data is stored in pxBuffer,\r
726  * which may either point to a real network buffer or to a TCP socket field\r
727  * called 'xTCP.xPacket'.   A temporary xNetworkBuffer will be used to pass\r
728  * the data to the NIC.\r
729  */\r
730 static void prvTCPReturnPacket( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer, uint32_t ulLen, BaseType_t xReleaseAfterSend )\r
731 {\r
732 TCPPacket_t * pxTCPPacket;\r
733 IPHeader_t *pxIPHeader;\r
734 EthernetHeader_t *pxEthernetHeader;\r
735 uint32_t ulFrontSpace, ulSpace, ulSourceAddress, ulWinSize;\r
736 TCPWindow_t *pxTCPWindow;\r
737 NetworkBufferDescriptor_t xTempBuffer;\r
738 /* For sending, a pseudo network buffer will be used, as explained above. */\r
739 \r
740         if( pxNetworkBuffer == NULL )\r
741         {\r
742                 memset( &xTempBuffer, '\0', sizeof( xTempBuffer ) );\r
743                 pxNetworkBuffer = &xTempBuffer;\r
744 \r
745                 xTempBuffer.pucEthernetBuffer = pxSocket->u.xTCP.xPacket.u.ucLastPacket;\r
746                 xTempBuffer.xDataLength = sizeof( pxSocket->u.xTCP.xPacket.u.ucLastPacket );\r
747         }\r
748 \r
749         #if( ipconfigZERO_COPY_TX_DRIVER != 0 )\r
750         {\r
751                 if( xReleaseAfterSend == pdFALSE )\r
752                 {\r
753                         pxNetworkBuffer = pxDuplicateNetworkBufferWithDescriptor( pxNetworkBuffer, ( BaseType_t ) pxNetworkBuffer->xDataLength );\r
754                         if( pxNetworkBuffer == NULL )\r
755                         {\r
756                                 FreeRTOS_debug_printf( ( "prvTCPReturnPacket: duplicate failed\n" ) );\r
757                         }\r
758                         xReleaseAfterSend = pdTRUE;\r
759                 }\r
760         }\r
761         #endif /* ipconfigZERO_COPY_TX_DRIVER */\r
762 \r
763         if( pxNetworkBuffer != NULL )\r
764         {\r
765                 pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );\r
766                 pxIPHeader = &pxTCPPacket->xIPHeader;\r
767                 pxEthernetHeader = &pxTCPPacket->xEthernetHeader;\r
768 \r
769                 /* Fill the packet, using hton translations. */\r
770                 if( pxSocket != NULL )\r
771                 {\r
772                         /* Calculate the space in the RX buffer in order to advertise the\r
773                         size of this socket's reception window. */\r
774                         pxTCPWindow = &( pxSocket->u.xTCP.xTCPWindow );\r
775 \r
776                         if( pxSocket->u.xTCP.rxStream != NULL )\r
777                         {\r
778                                 /* An RX stream was created already, see how much space is\r
779                                 available. */\r
780                                 ulFrontSpace = ( uint32_t ) uxStreamBufferFrontSpace( pxSocket->u.xTCP.rxStream );\r
781                         }\r
782                         else\r
783                         {\r
784                                 /* No RX stream has been created, the full stream size is\r
785                                 available. */\r
786                                 ulFrontSpace = ( uint32_t ) pxSocket->u.xTCP.uxRxStreamSize;\r
787                         }\r
788 \r
789                         /* Take the minimum of the RX buffer space and the RX window size. */\r
790                         ulSpace = FreeRTOS_min_uint32( pxSocket->u.xTCP.ulRxCurWinSize, pxTCPWindow->xSize.ulRxWindowLength );\r
791 \r
792                         if( ( pxSocket->u.xTCP.bits.bLowWater != pdFALSE_UNSIGNED ) || ( pxSocket->u.xTCP.bits.bRxStopped != pdFALSE_UNSIGNED ) )\r
793                         {\r
794                                 /* The low-water mark was reached, meaning there was little\r
795                                 space left.  The socket will wait until the application has read\r
796                                 or flushed the incoming data, and 'zero-window' will be\r
797                                 advertised. */\r
798                                 ulSpace = 0u;\r
799                         }\r
800 \r
801                         /* If possible, advertise an RX window size of at least 1 MSS, otherwise\r
802                         the peer might start 'zero window probing', i.e. sending small packets\r
803                         (1, 2, 4, 8... bytes). */\r
804                         if( ( ulSpace < pxSocket->u.xTCP.usCurMSS ) && ( ulFrontSpace >= pxSocket->u.xTCP.usCurMSS ) )\r
805                         {\r
806                                 ulSpace = pxSocket->u.xTCP.usCurMSS;\r
807                         }\r
808 \r
809                         /* Avoid overflow of the 16-bit win field. */\r
810                         #if( ipconfigUSE_TCP_WIN != 0 )\r
811                         {\r
812                                 ulWinSize = ( ulSpace >> pxSocket->u.xTCP.ucMyWinScaleFactor );\r
813                         }\r
814                         #else\r
815                         {\r
816                                 ulWinSize = ulSpace;\r
817                         }\r
818                         #endif\r
819                         if( ulWinSize > 0xfffcUL )\r
820                         {\r
821                                 ulWinSize = 0xfffcUL;\r
822                         }\r
823 \r
824                         pxTCPPacket->xTCPHeader.usWindow = FreeRTOS_htons( ( uint16_t ) ulWinSize );\r
825 \r
826                         #if( ipconfigHAS_DEBUG_PRINTF != 0 )\r
827                         {\r
828                                 if( ipconfigTCP_MAY_LOG_PORT( pxSocket->usLocalPort ) != pdFALSE )\r
829                                 {\r
830                                         if( ( xTCPWindowLoggingLevel != 0 ) && ( pxSocket->u.xTCP.bits.bWinChange != pdFALSE_UNSIGNED ) )\r
831                                         {\r
832                                         size_t uxFrontSpace;\r
833 \r
834                                                 if(pxSocket->u.xTCP.rxStream != NULL)\r
835                                                 {\r
836                                                         uxFrontSpace =  uxStreamBufferFrontSpace( pxSocket->u.xTCP.rxStream ) ;\r
837                                                 }\r
838                                                 else\r
839                                                 {\r
840                                                         uxFrontSpace = 0u;\r
841                                                 }\r
842 \r
843                                                 FreeRTOS_debug_printf( ( "%s: %lxip:%u: [%lu < %lu] winSize %ld\n",\r
844                                                 pxSocket->u.xTCP.bits.bLowWater ? "STOP" : "GO ",\r
845                                                         pxSocket->u.xTCP.ulRemoteIP,\r
846                                                         pxSocket->u.xTCP.usRemotePort,\r
847                                                         pxSocket->u.xTCP.bits.bLowWater ? pxSocket->u.xTCP.uxLittleSpace : uxFrontSpace, pxSocket->u.xTCP.uxEnoughSpace,\r
848                                                         (int32_t) ( pxTCPWindow->rx.ulHighestSequenceNumber - pxTCPWindow->rx.ulCurrentSequenceNumber ) ) );\r
849                                         }\r
850                                 }\r
851                         }\r
852                         #endif /* ipconfigHAS_DEBUG_PRINTF != 0 */\r
853 \r
854                         /* The new window size has been advertised, switch off the flag. */\r
855                         pxSocket->u.xTCP.bits.bWinChange = pdFALSE_UNSIGNED;\r
856 \r
857                         /* Later on, when deciding to delay an ACK, a precise estimate is needed\r
858                         of the free RX space.  At this moment, 'ulHighestRxAllowed' would be the\r
859                         highest sequence number minus 1 that the socket will accept. */\r
860                         pxSocket->u.xTCP.ulHighestRxAllowed = pxTCPWindow->rx.ulCurrentSequenceNumber + ulSpace;\r
861 \r
862                         #if( ipconfigTCP_KEEP_ALIVE == 1 )\r
863                                 if( pxSocket->u.xTCP.bits.bSendKeepAlive != pdFALSE_UNSIGNED )\r
864                                 {\r
865                                         /* Sending a keep-alive packet, send the current sequence number\r
866                                         minus 1, which will     be recognised as a keep-alive packet an\r
867                                         responded to by acknowledging the last byte. */\r
868                                         pxSocket->u.xTCP.bits.bSendKeepAlive = pdFALSE_UNSIGNED;\r
869                                         pxSocket->u.xTCP.bits.bWaitKeepAlive = pdTRUE_UNSIGNED;\r
870 \r
871                                         pxTCPPacket->xTCPHeader.ulSequenceNumber = pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber - 1UL;\r
872                                         pxTCPPacket->xTCPHeader.ulSequenceNumber = FreeRTOS_htonl( pxTCPPacket->xTCPHeader.ulSequenceNumber );\r
873                                 }\r
874                                 else\r
875                         #endif\r
876                         {\r
877                                 pxTCPPacket->xTCPHeader.ulSequenceNumber = FreeRTOS_htonl( pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber );\r
878 \r
879                                 if( ( pxTCPPacket->xTCPHeader.ucTCPFlags & ( uint8_t ) ipTCP_FLAG_FIN ) != 0u )\r
880                                 {\r
881                                         /* Suppress FIN in case this packet carries earlier data to be\r
882                                         retransmitted. */\r
883                                         uint32_t ulDataLen = ( uint32_t ) ( ulLen - ( ipSIZE_OF_TCP_HEADER + ipSIZE_OF_IPv4_HEADER ) );\r
884                                         if( ( pxTCPWindow->ulOurSequenceNumber + ulDataLen ) != pxTCPWindow->tx.ulFINSequenceNumber )\r
885                                         {\r
886                                                 pxTCPPacket->xTCPHeader.ucTCPFlags &= ( ( uint8_t ) ~ipTCP_FLAG_FIN );\r
887                                                 FreeRTOS_debug_printf( ( "Suppress FIN for %lu + %lu < %lu\n",\r
888                                                         pxTCPWindow->ulOurSequenceNumber - pxTCPWindow->tx.ulFirstSequenceNumber,\r
889                                                         ulDataLen,\r
890                                                         pxTCPWindow->tx.ulFINSequenceNumber - pxTCPWindow->tx.ulFirstSequenceNumber ) );\r
891                                         }\r
892                                 }\r
893                         }\r
894 \r
895                         /* Tell which sequence number is expected next time */\r
896                         pxTCPPacket->xTCPHeader.ulAckNr = FreeRTOS_htonl( pxTCPWindow->rx.ulCurrentSequenceNumber );\r
897                 }\r
898                 else\r
899                 {\r
900                         /* Sending data without a socket, probably replying with a RST flag\r
901                         Just swap the two sequence numbers. */\r
902                         vFlip_32( pxTCPPacket->xTCPHeader.ulSequenceNumber, pxTCPPacket->xTCPHeader.ulAckNr );\r
903                 }\r
904 \r
905                 pxIPHeader->ucTimeToLive           = ( uint8_t ) ipconfigTCP_TIME_TO_LIVE;\r
906                 pxIPHeader->usLength               = FreeRTOS_htons( ulLen );\r
907                 if( ( pxSocket == NULL ) || ( *ipLOCAL_IP_ADDRESS_POINTER == 0ul ) )\r
908                 {\r
909                         /* When pxSocket is NULL, this function is called by prvTCPSendReset()\r
910                         and the IP-addresses must be swapped.\r
911                         Also swap the IP-addresses in case the IP-tack doesn't have an\r
912                         IP-address yet, i.e. when ( *ipLOCAL_IP_ADDRESS_POINTER == 0ul ). */\r
913                         ulSourceAddress = pxIPHeader->ulDestinationIPAddress;\r
914                 }\r
915                 else\r
916                 {\r
917                         ulSourceAddress = *ipLOCAL_IP_ADDRESS_POINTER;\r
918                 }\r
919                 pxIPHeader->ulDestinationIPAddress = pxIPHeader->ulSourceIPAddress;\r
920                 pxIPHeader->ulSourceIPAddress = ulSourceAddress;\r
921                 vFlip_16( pxTCPPacket->xTCPHeader.usSourcePort, pxTCPPacket->xTCPHeader.usDestinationPort );\r
922 \r
923                 /* Just an increasing number. */\r
924                 pxIPHeader->usIdentification = FreeRTOS_htons( usPacketIdentifier );\r
925                 usPacketIdentifier++;\r
926                 pxIPHeader->usFragmentOffset = 0u;\r
927 \r
928                 #if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 0 )\r
929                 {\r
930                         /* calculate the IP header checksum, in case the driver won't do that. */\r
931                         pxIPHeader->usHeaderChecksum = 0x00u;\r
932                         pxIPHeader->usHeaderChecksum = usGenerateChecksum( 0u, ( uint8_t * ) &( pxIPHeader->ucVersionHeaderLength ), ipSIZE_OF_IPv4_HEADER );\r
933                         pxIPHeader->usHeaderChecksum = ~FreeRTOS_htons( pxIPHeader->usHeaderChecksum );\r
934 \r
935                         /* calculate the TCP checksum for an outgoing packet. */\r
936                         usGenerateProtocolChecksum( (uint8_t*)pxTCPPacket, pdTRUE );\r
937 \r
938                         /* A calculated checksum of 0 must be inverted as 0 means the checksum\r
939                         is disabled. */\r
940                         if( pxTCPPacket->xTCPHeader.usChecksum == 0x00u )\r
941                         {\r
942                                 pxTCPPacket->xTCPHeader.usChecksum = 0xffffU;\r
943                         }\r
944                 }\r
945                 #endif\r
946 \r
947                 #if( ipconfigUSE_LINKED_RX_MESSAGES != 0 )\r
948                 {\r
949                         pxNetworkBuffer->pxNextBuffer = NULL;\r
950                 }\r
951                 #endif\r
952 \r
953                 /* Important: tell NIC driver how many bytes must be sent. */\r
954                 pxNetworkBuffer->xDataLength = ulLen + ipSIZE_OF_ETH_HEADER;\r
955 \r
956                 /* Fill in the destination MAC addresses. */\r
957                 memcpy( ( void * ) &( pxEthernetHeader->xDestinationAddress ), ( void * ) &( pxEthernetHeader->xSourceAddress ),\r
958                         sizeof( pxEthernetHeader->xDestinationAddress ) );\r
959 \r
960                 /* The source MAC addresses is fixed to 'ipLOCAL_MAC_ADDRESS'. */\r
961                 memcpy( ( void * ) &( pxEthernetHeader->xSourceAddress ), ( void * ) ipLOCAL_MAC_ADDRESS, ( size_t ) ipMAC_ADDRESS_LENGTH_BYTES );\r
962 \r
963                 #if defined( ipconfigETHERNET_MINIMUM_PACKET_BYTES )\r
964                 {\r
965                         if( pxNetworkBuffer->xDataLength < ( size_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES )\r
966                         {\r
967                         BaseType_t xIndex;\r
968 \r
969                                 for( xIndex = ( BaseType_t ) pxNetworkBuffer->xDataLength; xIndex < ( BaseType_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES; xIndex++ )\r
970                                 {\r
971                                         pxNetworkBuffer->pucEthernetBuffer[ xIndex ] = 0u;\r
972                                 }\r
973                                 pxNetworkBuffer->xDataLength = ( size_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES;\r
974                         }\r
975                 }\r
976                 #endif\r
977 \r
978                 /* Send! */\r
979                 xNetworkInterfaceOutput( pxNetworkBuffer, xReleaseAfterSend );\r
980 \r
981                 if( xReleaseAfterSend == pdFALSE )\r
982                 {\r
983                         /* Swap-back some fields, as pxBuffer probably points to a socket field\r
984                         containing the packet header. */\r
985                         vFlip_16( pxTCPPacket->xTCPHeader.usSourcePort, pxTCPPacket->xTCPHeader.usDestinationPort);\r
986                         pxTCPPacket->xIPHeader.ulSourceIPAddress = pxTCPPacket->xIPHeader.ulDestinationIPAddress;\r
987                         memcpy( pxEthernetHeader->xSourceAddress.ucBytes, pxEthernetHeader->xDestinationAddress.ucBytes, ( size_t ) ipMAC_ADDRESS_LENGTH_BYTES );\r
988                 }\r
989                 else\r
990                 {\r
991                         /* Nothing to do: the buffer has been passed to DMA and will be released after use */\r
992                 }\r
993         } /* if( pxNetworkBuffer != NULL ) */\r
994 }\r
995 /*-----------------------------------------------------------*/\r
996 \r
997 /*\r
998  * The SYN event is very important: the sequence numbers, which have a kind of\r
999  * random starting value, are being synchronised.  The sliding window manager\r
1000  * (in FreeRTOS_TCP_WIN.c) needs to know them, along with the Maximum Segment\r
1001  * Size (MSS) in use.\r
1002  */\r
1003 static void prvTCPCreateWindow( FreeRTOS_Socket_t *pxSocket )\r
1004 {\r
1005         if( xTCPWindowLoggingLevel )\r
1006                 FreeRTOS_debug_printf( ( "Limits (using): TCP Win size %lu Water %lu <= %lu <= %lu\n",\r
1007                         pxSocket->u.xTCP.uxRxWinSize * ipconfigTCP_MSS,\r
1008                         pxSocket->u.xTCP.uxLittleSpace ,\r
1009                         pxSocket->u.xTCP.uxEnoughSpace,\r
1010                         pxSocket->u.xTCP.uxRxStreamSize ) );\r
1011         vTCPWindowCreate(\r
1012                 &pxSocket->u.xTCP.xTCPWindow,\r
1013                 ipconfigTCP_MSS * pxSocket->u.xTCP.uxRxWinSize,\r
1014                 ipconfigTCP_MSS * pxSocket->u.xTCP.uxTxWinSize,\r
1015                 pxSocket->u.xTCP.xTCPWindow.rx.ulCurrentSequenceNumber,\r
1016                 pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber,\r
1017                 ( uint32_t ) pxSocket->u.xTCP.usInitMSS );\r
1018 }\r
1019 /*-----------------------------------------------------------*/\r
1020 \r
1021 /*\r
1022  * Connecting sockets have a special state: eCONNECT_SYN.  In this phase,\r
1023  * the Ethernet address of the target will be found using ARP.  In case the\r
1024  * target IP address is not within the netmask, the hardware address of the\r
1025  * gateway will be used.\r
1026  */\r
1027 static BaseType_t prvTCPPrepareConnect( FreeRTOS_Socket_t *pxSocket )\r
1028 {\r
1029 TCPPacket_t *pxTCPPacket;\r
1030 IPHeader_t *pxIPHeader;\r
1031 eARPLookupResult_t eReturned;\r
1032 uint32_t ulRemoteIP;\r
1033 MACAddress_t xEthAddress;\r
1034 BaseType_t xReturn = pdTRUE;\r
1035 \r
1036         #if( ipconfigHAS_PRINTF != 0 )\r
1037         {\r
1038                 /* Only necessary for nicer logging. */\r
1039                 memset( xEthAddress.ucBytes, '\0', sizeof( xEthAddress.ucBytes ) );\r
1040         }\r
1041         #endif /* ipconfigHAS_PRINTF != 0 */\r
1042 \r
1043         ulRemoteIP = FreeRTOS_htonl( pxSocket->u.xTCP.ulRemoteIP );\r
1044 \r
1045         /* Determine the ARP cache status for the requested IP address. */\r
1046         eReturned = eARPGetCacheEntry( &( ulRemoteIP ), &( xEthAddress ) );\r
1047 \r
1048         switch( eReturned )\r
1049         {\r
1050                 case eARPCacheHit:              /* An ARP table lookup found a valid entry. */\r
1051                         break;                          /* We can now prepare the SYN packet. */\r
1052                 case eARPCacheMiss:             /* An ARP table lookup did not find a valid entry. */\r
1053                 case eCantSendPacket:   /* There is no IP address, or an ARP is still in progress. */\r
1054                 default:\r
1055                         /* Count the number of times it couldn't find the ARP address. */\r
1056                         pxSocket->u.xTCP.ucRepCount++;\r
1057         \r
1058                         FreeRTOS_debug_printf( ( "ARP for %lxip (using %lxip): rc=%d %02X:%02X:%02X %02X:%02X:%02X\n",\r
1059                                 pxSocket->u.xTCP.ulRemoteIP,\r
1060                                 FreeRTOS_htonl( ulRemoteIP ),\r
1061                                 eReturned,\r
1062                                 xEthAddress.ucBytes[ 0 ],\r
1063                                 xEthAddress.ucBytes[ 1 ],\r
1064                                 xEthAddress.ucBytes[ 2 ],\r
1065                                 xEthAddress.ucBytes[ 3 ],\r
1066                                 xEthAddress.ucBytes[ 4 ],\r
1067                                 xEthAddress.ucBytes[ 5 ] ) );\r
1068         \r
1069                         /* And issue a (new) ARP request */\r
1070                         FreeRTOS_OutputARPRequest( ulRemoteIP );\r
1071         \r
1072                         xReturn = pdFALSE;\r
1073                         break;\r
1074         }\r
1075 \r
1076         if( xReturn != pdFALSE )\r
1077         {\r
1078                 /* The MAC-address of the peer (or gateway) has been found,\r
1079                 now prepare the initial TCP packet and some fields in the socket. */\r
1080                 pxTCPPacket = ( TCPPacket_t * )pxSocket->u.xTCP.xPacket.u.ucLastPacket;\r
1081                 pxIPHeader = &pxTCPPacket->xIPHeader;\r
1082 \r
1083                 /* Reset the retry counter to zero... */\r
1084                 pxSocket->u.xTCP.ucRepCount = 0u;\r
1085 \r
1086                 /* ...and remember that the connect/SYN data are prepared. */\r
1087                 pxSocket->u.xTCP.bits.bConnPrepared = pdTRUE_UNSIGNED;\r
1088 \r
1089                 /* Now that the Ethernet address is known, the initial packet can be\r
1090                 prepared. */\r
1091                 memset( pxSocket->u.xTCP.xPacket.u.ucLastPacket, '\0', sizeof( pxSocket->u.xTCP.xPacket.u.ucLastPacket ) );\r
1092 \r
1093                 /* Write the Ethernet address in Source, because it will be swapped by\r
1094                 prvTCPReturnPacket(). */\r
1095                 memcpy( &pxTCPPacket->xEthernetHeader.xSourceAddress, &xEthAddress, sizeof( xEthAddress ) );\r
1096 \r
1097                 /* 'ipIPv4_FRAME_TYPE' is already in network-byte-order. */\r
1098                 pxTCPPacket->xEthernetHeader.usFrameType = ipIPv4_FRAME_TYPE;\r
1099 \r
1100                 pxIPHeader->ucVersionHeaderLength = 0x45u;\r
1101                 pxIPHeader->usLength = FreeRTOS_htons( sizeof( TCPPacket_t ) - sizeof( pxTCPPacket->xEthernetHeader ) );\r
1102                 pxIPHeader->ucTimeToLive = ( uint8_t ) ipconfigTCP_TIME_TO_LIVE;\r
1103 \r
1104                 pxIPHeader->ucProtocol = ( uint8_t ) ipPROTOCOL_TCP;\r
1105 \r
1106                 /* Addresses and ports will be stored swapped because prvTCPReturnPacket\r
1107                 will swap them back while replying. */\r
1108                 pxIPHeader->ulDestinationIPAddress = *ipLOCAL_IP_ADDRESS_POINTER;\r
1109                 pxIPHeader->ulSourceIPAddress = FreeRTOS_htonl( pxSocket->u.xTCP.ulRemoteIP );\r
1110 \r
1111                 pxTCPPacket->xTCPHeader.usSourcePort = FreeRTOS_htons( pxSocket->u.xTCP.usRemotePort );\r
1112                 pxTCPPacket->xTCPHeader.usDestinationPort = FreeRTOS_htons( pxSocket->usLocalPort );\r
1113 \r
1114                 /* We are actively connecting, so the peer's Initial Sequence Number (ISN)\r
1115                 isn't known yet. */\r
1116                 pxSocket->u.xTCP.xTCPWindow.rx.ulCurrentSequenceNumber = 0ul;\r
1117 \r
1118                 /* Start with ISN (Initial Sequence Number). */\r
1119                 pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber = ulNextInitialSequenceNumber;\r
1120 \r
1121                 /* And increment it with 268 for the next new connection, which is\r
1122                 recommended value. */\r
1123                 ulNextInitialSequenceNumber += 0x102UL;\r
1124 \r
1125                 /* The TCP header size is 20 bytes, divided by 4 equals 5, which is put in\r
1126                 the high nibble of the TCP offset field. */\r
1127                 pxTCPPacket->xTCPHeader.ucTCPOffset = 0x50u;\r
1128 \r
1129                 /* Only set the SYN flag. */\r
1130                 pxTCPPacket->xTCPHeader.ucTCPFlags = ipTCP_FLAG_SYN;\r
1131 \r
1132                 /* Set the values of usInitMSS / usCurMSS for this socket. */\r
1133                 prvSocketSetMSS( pxSocket );\r
1134 \r
1135                 /* For now this is also the advertised window size. */\r
1136                 pxSocket->u.xTCP.ulRxCurWinSize = pxSocket->u.xTCP.usInitMSS;\r
1137 \r
1138                 /* The initial sequence numbers at our side are known.  Later\r
1139                 vTCPWindowInit() will be called to fill in the peer's sequence numbers, but\r
1140                 first wait for a SYN+ACK reply. */\r
1141                 prvTCPCreateWindow( pxSocket );\r
1142         }\r
1143 \r
1144         return xReturn;\r
1145 }\r
1146 /*-----------------------------------------------------------*/\r
1147 \r
1148 /* For logging and debugging: make a string showing the TCP flags\r
1149 */\r
1150 #if( ipconfigHAS_DEBUG_PRINTF != 0 )\r
1151 \r
1152         static const char *prvTCPFlagMeaning( UBaseType_t xFlags)\r
1153         {\r
1154                 static char retString[10];\r
1155                 snprintf(retString, sizeof( retString ), "%c%c%c%c%c%c%c%c%c",\r
1156                         ( xFlags & ipTCP_FLAG_FIN )  ? 'F' : '.',       /* 0x0001: No more data from sender */\r
1157                         ( xFlags & ipTCP_FLAG_SYN )  ? 'S' : '.',       /* 0x0002: Synchronize sequence numbers */\r
1158                         ( xFlags & ipTCP_FLAG_RST )  ? 'R' : '.',       /* 0x0004: Reset the connection */\r
1159                         ( xFlags & ipTCP_FLAG_PSH )  ? 'P' : '.',       /* 0x0008: Push function: please push buffered data to the recv application */\r
1160                         ( xFlags & ipTCP_FLAG_ACK )  ? 'A' : '.',       /* 0x0010: Acknowledgment field is significant */\r
1161                         ( xFlags & ipTCP_FLAG_URG )  ? 'U' : '.',       /* 0x0020: Urgent pointer field is significant */\r
1162                         ( xFlags & ipTCP_FLAG_ECN )  ? 'E' : '.',       /* 0x0040: ECN-Echo */\r
1163                         ( xFlags & ipTCP_FLAG_CWR )  ? 'C' : '.',       /* 0x0080: Congestion Window Reduced */\r
1164                         ( xFlags & ipTCP_FLAG_NS )   ? 'N' : '.');      /* 0x0100: ECN-nonce concealment protection */\r
1165                 return retString;\r
1166         }\r
1167         /*-----------------------------------------------------------*/\r
1168 \r
1169 #endif /* ipconfigHAS_DEBUG_PRINTF */\r
1170 \r
1171 /*\r
1172  * Parse the TCP option(s) received, if present.  It has already been verified\r
1173  * that: ((pxTCPHeader->ucTCPOffset & 0xf0) > 0x50), meaning that the TP header\r
1174  * is longer than the usual 20 (5 x 4) bytes.\r
1175  */\r
1176 static void prvCheckOptions( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer )\r
1177 {\r
1178 TCPPacket_t * pxTCPPacket;\r
1179 TCPHeader_t * pxTCPHeader;\r
1180 const unsigned char *pucPtr;\r
1181 const unsigned char *pucLast;\r
1182 TCPWindow_t *pxTCPWindow;\r
1183 UBaseType_t uxNewMSS;\r
1184 \r
1185         pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );\r
1186         pxTCPHeader = &pxTCPPacket->xTCPHeader;\r
1187 \r
1188         /* A character pointer to iterate through the option data */\r
1189         pucPtr = pxTCPHeader->ucOptdata;\r
1190         pucLast = pucPtr + (((pxTCPHeader->ucTCPOffset >> 4) - 5) << 2);\r
1191         pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow;\r
1192 \r
1193         /* The comparison with pucLast is only necessary in case the option data are\r
1194         corrupted, we don't like to run into invalid memory and crash. */\r
1195         while( pucPtr < pucLast )\r
1196         {\r
1197                 if( pucPtr[ 0 ] == TCP_OPT_END )\r
1198                 {\r
1199                         /* End of options. */\r
1200                         return;\r
1201                 }\r
1202                 if( pucPtr[ 0 ] == TCP_OPT_NOOP)\r
1203                 {\r
1204                         pucPtr++;\r
1205 \r
1206                         /* NOP option, inserted to make the length a multiple of 4. */\r
1207                 }\r
1208 #if( ipconfigUSE_TCP_WIN != 0 )\r
1209                 else if( ( pucPtr[ 0 ] == TCP_OPT_WSOPT ) && ( pucPtr[ 1 ] == TCP_OPT_WSOPT_LEN ) )\r
1210                 {\r
1211                         pxSocket->u.xTCP.ucPeerWinScaleFactor = pucPtr[ 2 ];\r
1212                         pxSocket->u.xTCP.bits.bWinScaling = pdTRUE_UNSIGNED;\r
1213                         pucPtr += TCP_OPT_WSOPT_LEN;\r
1214                 }\r
1215 #endif  /* ipconfigUSE_TCP_WIN */\r
1216                 else if( ( pucPtr[ 0 ] == TCP_OPT_MSS ) && ( pucPtr[ 1 ] == TCP_OPT_MSS_LEN ) )\r
1217                 {\r
1218                         /* An MSS option with the correct option length.  FreeRTOS_htons()\r
1219                         is not needed here because usChar2u16() already returns a host\r
1220                         endian number. */\r
1221                         uxNewMSS = usChar2u16( pucPtr + 2 );\r
1222 \r
1223                         if( pxSocket->u.xTCP.usInitMSS != uxNewMSS )\r
1224                         {\r
1225                                 FreeRTOS_debug_printf( ( "MSS change %u -> %lu\n", pxSocket->u.xTCP.usInitMSS, uxNewMSS ) );\r
1226                         }\r
1227 \r
1228                         if( pxSocket->u.xTCP.usInitMSS > uxNewMSS )\r
1229                         {\r
1230                                 /* our MSS was bigger than the MSS of the other party: adapt it. */\r
1231                                 pxSocket->u.xTCP.bits.bMssChange = pdTRUE_UNSIGNED;\r
1232                                 if( ( pxTCPWindow != NULL ) && ( pxSocket->u.xTCP.usCurMSS > uxNewMSS ) )\r
1233                                 {\r
1234                                         /* The peer advertises a smaller MSS than this socket was\r
1235                                         using.  Use that as well. */\r
1236                                         FreeRTOS_debug_printf( ( "Change mss %d => %lu\n", pxSocket->u.xTCP.usCurMSS, uxNewMSS ) );\r
1237                                         pxSocket->u.xTCP.usCurMSS = ( uint16_t ) uxNewMSS;\r
1238                                 }\r
1239                                 pxTCPWindow->xSize.ulRxWindowLength = ( ( uint32_t ) uxNewMSS ) * ( pxTCPWindow->xSize.ulRxWindowLength / ( ( uint32_t ) uxNewMSS ) );\r
1240                                 pxTCPWindow->usMSSInit = ( uint16_t ) uxNewMSS;\r
1241                                 pxTCPWindow->usMSS = ( uint16_t ) uxNewMSS;\r
1242                                 pxSocket->u.xTCP.usInitMSS = ( uint16_t ) uxNewMSS;\r
1243                                 pxSocket->u.xTCP.usCurMSS = ( uint16_t ) uxNewMSS;\r
1244                         }\r
1245 \r
1246                         #if( ipconfigUSE_TCP_WIN != 1 )\r
1247                                 /* Without scaled windows, MSS is the only interesting option. */\r
1248                                 break;\r
1249                         #else\r
1250                                 /* Or else we continue to check another option: selective ACK. */\r
1251                                 pucPtr += TCP_OPT_MSS_LEN;\r
1252                         #endif  /* ipconfigUSE_TCP_WIN != 1 */\r
1253                 }\r
1254                 else\r
1255                 {\r
1256                         /* All other options have a length field, so that we easily\r
1257                         can skip past them. */\r
1258                         int len = ( int )pucPtr[ 1 ];\r
1259                         if( len == 0 )\r
1260                         {\r
1261                                 /* If the length field is zero, the options are malformed\r
1262                                 and we don't process them further. */\r
1263                                 break;\r
1264                         }\r
1265 \r
1266                         #if( ipconfigUSE_TCP_WIN == 1 )\r
1267                         {\r
1268                                 /* Selective ACK: the peer has received a packet but it is missing earlier\r
1269                                 packets.  At least this packet does not need retransmission anymore\r
1270                                 ulTCPWindowTxSack( ) takes care of this administration. */\r
1271                                 if( pucPtr[0] == TCP_OPT_SACK_A )\r
1272                                 {\r
1273                                         len -= 2;\r
1274                                         pucPtr += 2;\r
1275 \r
1276                                         while( len >= 8 )\r
1277                                         {\r
1278                                         uint32_t ulFirst = ulChar2u32( pucPtr );\r
1279                                         uint32_t ulLast  = ulChar2u32( pucPtr + 4 );\r
1280                                         uint32_t ulCount = ulTCPWindowTxSack( &pxSocket->u.xTCP.xTCPWindow, ulFirst, ulLast );\r
1281                                                 /* ulTCPWindowTxSack( ) returns the number of bytes which have been acked\r
1282                                                 starting from the head position.\r
1283                                                 Advance the tail pointer in txStream. */\r
1284                                                 if( ( pxSocket->u.xTCP.txStream  != NULL ) && ( ulCount > 0 ) )\r
1285                                                 {\r
1286                                                         /* Just advancing the tail index, 'ulCount' bytes have been confirmed. */\r
1287                                                         uxStreamBufferGet( pxSocket->u.xTCP.txStream, 0, NULL, ( size_t ) ulCount, pdFALSE );\r
1288                                                         pxSocket->xEventBits |= eSOCKET_SEND;\r
1289 \r
1290                                                         #if ipconfigSUPPORT_SELECT_FUNCTION == 1\r
1291                                                         {\r
1292                                                                 if( pxSocket->xSelectBits & eSELECT_WRITE )\r
1293                                                                 {\r
1294                                                                         /* The field 'xEventBits' is used to store regular socket events (at most 8),\r
1295                                                                         as well as 'select events', which will be left-shifted */\r
1296                                                                         pxSocket->xEventBits |= ( eSELECT_WRITE << SOCKET_EVENT_BIT_COUNT );\r
1297                                                                 }\r
1298                                                         }\r
1299                                                         #endif\r
1300 \r
1301                                                         /* In case the socket owner has installed an OnSent handler,\r
1302                                                         call it now. */\r
1303                                                         #if( ipconfigUSE_CALLBACKS == 1 )\r
1304                                                         {\r
1305                                                                 if( ipconfigIS_VALID_PROG_ADDRESS( pxSocket->u.xTCP.pxHandleSent ) )\r
1306                                                                 {\r
1307                                                                         pxSocket->u.xTCP.pxHandleSent( (Socket_t *)pxSocket, ulCount );\r
1308                                                                 }\r
1309                                                         }\r
1310                                                         #endif /* ipconfigUSE_CALLBACKS == 1  */\r
1311                                                 }\r
1312                                                 pucPtr += 8;\r
1313                                                 len -= 8;\r
1314                                         }\r
1315                                         /* len should be 0 by now. */\r
1316                                 }\r
1317                                 #if     ipconfigUSE_TCP_TIMESTAMPS == 1\r
1318                                         else if( pucPtr[0] == TCP_OPT_TIMESTAMP )\r
1319                                         {\r
1320                                                 len -= 2;       /* Skip option and length byte. */\r
1321                                                 pucPtr += 2;\r
1322                                                 pxSocket->u.xTCP.xTCPWindow.u.bits.bTimeStamps = pdTRUE_UNSIGNED;\r
1323                                                 pxSocket->u.xTCP.xTCPWindow.rx.ulTimeStamp = ulChar2u32( pucPtr );\r
1324                                                 pxSocket->u.xTCP.xTCPWindow.tx.ulTimeStamp = ulChar2u32( pucPtr + 4 );\r
1325                                         }\r
1326                                 #endif  /* ipconfigUSE_TCP_TIMESTAMPS == 1 */\r
1327                         }\r
1328                         #endif  /* ipconfigUSE_TCP_WIN == 1 */\r
1329 \r
1330                         pucPtr += len;\r
1331                 }\r
1332         }\r
1333 }\r
1334 /*-----------------------------------------------------------*/\r
1335 \r
1336 #if( ipconfigUSE_TCP_WIN != 0 )\r
1337 \r
1338         static uint8_t prvWinScaleFactor( FreeRTOS_Socket_t *pxSocket )\r
1339         {\r
1340         size_t uxWinSize;\r
1341         uint8_t ucFactor;\r
1342 \r
1343                 /* 'xTCP.uxRxWinSize' is the size of the reception window in units of MSS. */\r
1344                 uxWinSize = pxSocket->u.xTCP.uxRxWinSize * ( size_t ) pxSocket->u.xTCP.usInitMSS;\r
1345                 ucFactor = 0u;\r
1346                 while( uxWinSize > 0xfffful )\r
1347                 {\r
1348                         /* Divide by two and increase the binary factor by 1. */\r
1349                         uxWinSize >>= 1;\r
1350                         ucFactor++;\r
1351                 }\r
1352 \r
1353                 FreeRTOS_debug_printf( ( "prvWinScaleFactor: uxRxWinSize %lu MSS %lu Factor %u\n",\r
1354                         pxSocket->u.xTCP.uxRxWinSize,\r
1355                         pxSocket->u.xTCP.usInitMSS,\r
1356                         ucFactor ) );\r
1357 \r
1358                 return ucFactor;\r
1359         }\r
1360 \r
1361 #endif\r
1362 /*-----------------------------------------------------------*/\r
1363 \r
1364 /*\r
1365  * When opening a TCP connection, while SYN's are being sent, the  parties may\r
1366  * communicate what MSS (Maximum Segment Size) they intend to use.   MSS is the\r
1367  * nett size of the payload, always smaller than MTU.\r
1368 */\r
1369 static UBaseType_t prvSetSynAckOptions( FreeRTOS_Socket_t *pxSocket, TCPPacket_t * pxTCPPacket )\r
1370 {\r
1371 TCPHeader_t *pxTCPHeader = &pxTCPPacket->xTCPHeader;\r
1372 uint16_t usMSS = pxSocket->u.xTCP.usInitMSS;\r
1373 UBaseType_t uxOptionsLength;\r
1374 \r
1375         /* We send out the TCP Maximum Segment Size option with our SYN[+ACK]. */\r
1376 \r
1377         pxTCPHeader->ucOptdata[ 0 ] = ( uint8_t ) TCP_OPT_MSS;\r
1378         pxTCPHeader->ucOptdata[ 1 ] = ( uint8_t ) TCP_OPT_MSS_LEN;\r
1379         pxTCPHeader->ucOptdata[ 2 ] = ( uint8_t ) ( usMSS >> 8 );\r
1380         pxTCPHeader->ucOptdata[ 3 ] = ( uint8_t ) ( usMSS & 0xffu );\r
1381 \r
1382         #if( ipconfigUSE_TCP_WIN != 0 )\r
1383         {\r
1384                 pxSocket->u.xTCP.ucMyWinScaleFactor = prvWinScaleFactor( pxSocket );\r
1385 \r
1386                 pxTCPHeader->ucOptdata[ 4 ] = TCP_OPT_NOOP;\r
1387                 pxTCPHeader->ucOptdata[ 5 ] = ( uint8_t ) ( TCP_OPT_WSOPT );\r
1388                 pxTCPHeader->ucOptdata[ 6 ] = ( uint8_t ) ( TCP_OPT_WSOPT_LEN );\r
1389                 pxTCPHeader->ucOptdata[ 7 ] = ( uint8_t ) pxSocket->u.xTCP.ucMyWinScaleFactor;\r
1390                 uxOptionsLength = 8u;\r
1391         }\r
1392         #else\r
1393         {\r
1394                 uxOptionsLength = 4u;\r
1395         }\r
1396         #endif\r
1397 \r
1398         #if( ipconfigUSE_TCP_WIN == 0 )\r
1399         {\r
1400                 return uxOptionsLength;\r
1401         }\r
1402         #else\r
1403         {\r
1404                 #if( ipconfigUSE_TCP_TIMESTAMPS == 1 )\r
1405                         if( pxSocket->u.xTCP.xTCPWindow.u.bits.bTimeStamps )\r
1406                         {\r
1407                                 uxOptionsLength += prvTCPSetTimeStamp( uxOptionsLength, pxSocket, &pxTCPPacket->xTCPHeader );\r
1408                                 pxTCPHeader->ucOptdata[ uxOptionsLength + 0 ] = TCP_OPT_SACK_P; /* 4: Sack-Permitted Option. */\r
1409                                 pxTCPHeader->ucOptdata[ uxOptionsLength + 1 ] = 2u;\r
1410                                 uxOptionsLength += 2u;\r
1411                         }\r
1412                         else\r
1413                 #endif\r
1414                 {\r
1415                         pxTCPHeader->ucOptdata[ uxOptionsLength + 0 ] = TCP_OPT_NOOP;\r
1416                         pxTCPHeader->ucOptdata[ uxOptionsLength + 1 ] = TCP_OPT_NOOP;\r
1417                         pxTCPHeader->ucOptdata[ uxOptionsLength + 2 ] = TCP_OPT_SACK_P; /* 4: Sack-Permitted Option. */\r
1418                         pxTCPHeader->ucOptdata[ uxOptionsLength + 3 ] = 2;      /* 2: length of this option. */\r
1419                         uxOptionsLength += 4u;\r
1420                 }\r
1421                 return uxOptionsLength; /* bytes, not words. */\r
1422         }\r
1423         #endif  /* ipconfigUSE_TCP_WIN == 0 */\r
1424 }\r
1425 \r
1426 /*\r
1427  * For anti-hanging protection and TCP keep-alive messages.  Called in two\r
1428  * places: after receiving a packet and after a state change.  The socket's\r
1429  * alive timer may be reset.\r
1430  */\r
1431 static void prvTCPTouchSocket( FreeRTOS_Socket_t *pxSocket )\r
1432 {\r
1433         #if( ipconfigTCP_HANG_PROTECTION == 1 )\r
1434         {\r
1435                 pxSocket->u.xTCP.xLastActTime = xTaskGetTickCount( );\r
1436         }\r
1437         #endif\r
1438 \r
1439         #if( ipconfigTCP_KEEP_ALIVE == 1 )\r
1440         {\r
1441                 pxSocket->u.xTCP.bits.bWaitKeepAlive = pdFALSE_UNSIGNED;\r
1442                 pxSocket->u.xTCP.bits.bSendKeepAlive = pdFALSE_UNSIGNED;\r
1443                 pxSocket->u.xTCP.ucKeepRepCount = 0u;\r
1444                 pxSocket->u.xTCP.xLastAliveTime = xTaskGetTickCount();\r
1445         }\r
1446         #endif\r
1447 \r
1448         ( void ) pxSocket;\r
1449 }\r
1450 /*-----------------------------------------------------------*/\r
1451 \r
1452 /*\r
1453  * Changing to a new state. Centralised here to do specific actions such as\r
1454  * resetting the alive timer, calling the user's OnConnect handler to notify\r
1455  * that a socket has got (dis)connected, and setting bit to unblock a call to\r
1456  * FreeRTOS_select()\r
1457  */\r
1458 void vTCPStateChange( FreeRTOS_Socket_t *pxSocket, enum eTCP_STATE eTCPState )\r
1459 {\r
1460 FreeRTOS_Socket_t *xParent = NULL;\r
1461 BaseType_t bBefore = ( BaseType_t ) NOW_CONNECTED( pxSocket->u.xTCP.ucTCPState );       /* Was it connected ? */\r
1462 BaseType_t bAfter  = ( BaseType_t ) NOW_CONNECTED( eTCPState );                                         /* Is it connected now ? */\r
1463 #if( ipconfigHAS_DEBUG_PRINTF != 0 )\r
1464         BaseType_t xPreviousState = ( BaseType_t ) pxSocket->u.xTCP.ucTCPState;\r
1465 #endif\r
1466 #if( ipconfigUSE_CALLBACKS == 1 )\r
1467         FreeRTOS_Socket_t *xConnected = NULL;\r
1468 #endif\r
1469 \r
1470         /* Has the connected status changed? */\r
1471         if( bBefore != bAfter )\r
1472         {\r
1473                 /* Is the socket connected now ? */\r
1474                 if( bAfter != pdFALSE )\r
1475                 {\r
1476                         /* if bPassQueued is true, this socket is an orphan until it gets connected. */\r
1477                         if( pxSocket->u.xTCP.bits.bPassQueued != pdFALSE_UNSIGNED )\r
1478                         {\r
1479                                 /* Now that it is connected, find it's parent. */\r
1480                                 if( pxSocket->u.xTCP.bits.bReuseSocket != pdFALSE_UNSIGNED )\r
1481                                 {\r
1482                                         xParent = pxSocket;\r
1483                                 }\r
1484                                 else\r
1485                                 {\r
1486                                         xParent = pxSocket->u.xTCP.pxPeerSocket;\r
1487                                         configASSERT( xParent != NULL );\r
1488                                 }\r
1489                                 if( xParent != NULL )\r
1490                                 {\r
1491                                         if( xParent->u.xTCP.pxPeerSocket == NULL )\r
1492                                         {\r
1493                                                 xParent->u.xTCP.pxPeerSocket = pxSocket;\r
1494                                         }\r
1495 \r
1496                                         xParent->xEventBits |= eSOCKET_ACCEPT;\r
1497 \r
1498                                         #if( ipconfigSUPPORT_SELECT_FUNCTION == 1 )\r
1499                                         {\r
1500                                                 /* Library support FreeRTOS_select().  Receiving a new\r
1501                                                 connection is being translated as a READ event. */\r
1502                                                 if( ( xParent->xSelectBits & eSELECT_READ ) != 0 )\r
1503                                                 {\r
1504                                                         xParent->xEventBits |= ( eSELECT_READ << SOCKET_EVENT_BIT_COUNT );\r
1505                                                 }\r
1506                                         }\r
1507                                         #endif\r
1508 \r
1509                                         #if( ipconfigUSE_CALLBACKS == 1 )\r
1510                                         {\r
1511                                                 if( ( ipconfigIS_VALID_PROG_ADDRESS( xParent->u.xTCP.pxHandleConnected ) != pdFALSE ) &&\r
1512                                                         ( xParent->u.xTCP.bits.bReuseSocket == pdFALSE_UNSIGNED ) )\r
1513                                                 {\r
1514                                                         /* The listening socket does not become connected itself, in stead\r
1515                                                         a child socket is created.\r
1516                                                         Postpone a call the OnConnect event until the end of this function. */\r
1517                                                         xConnected = xParent;\r
1518                                                 }\r
1519                                         }\r
1520                                         #endif\r
1521                                 }\r
1522 \r
1523                                 /* Don't need to access the parent socket anymore, so the\r
1524                                 reference 'pxPeerSocket' may be cleared. */\r
1525                                 pxSocket->u.xTCP.pxPeerSocket = NULL;\r
1526                                 pxSocket->u.xTCP.bits.bPassQueued = pdFALSE_UNSIGNED;\r
1527 \r
1528                                 /* When true, this socket may be returned in a call to accept(). */\r
1529                                 pxSocket->u.xTCP.bits.bPassAccept = pdTRUE_UNSIGNED;\r
1530                         }\r
1531                         else\r
1532                         {\r
1533                                 pxSocket->xEventBits |= eSOCKET_CONNECT;\r
1534 \r
1535                                 #if( ipconfigSUPPORT_SELECT_FUNCTION == 1 )\r
1536                                 {\r
1537                                         if( pxSocket->xSelectBits & eSELECT_WRITE )\r
1538                                         {\r
1539                                                 pxSocket->xEventBits |= ( eSELECT_WRITE << SOCKET_EVENT_BIT_COUNT );\r
1540                                         }\r
1541                                 }\r
1542                                 #endif\r
1543                         }\r
1544                 }\r
1545                 else  /* bAfter == pdFALSE, connection is closed. */\r
1546                 {\r
1547                         /* Notify/wake-up the socket-owner by setting a semaphore. */\r
1548                         pxSocket->xEventBits |= eSOCKET_CLOSED;\r
1549 \r
1550                         #if( ipconfigSUPPORT_SELECT_FUNCTION == 1 )\r
1551                         {\r
1552                                 if( ( pxSocket->xSelectBits & eSELECT_EXCEPT ) != 0 )\r
1553                                 {\r
1554                                         pxSocket->xEventBits |= ( eSELECT_EXCEPT << SOCKET_EVENT_BIT_COUNT );\r
1555                                 }\r
1556                         }\r
1557                         #endif\r
1558                 }\r
1559                 #if( ipconfigUSE_CALLBACKS == 1 )\r
1560                 {\r
1561                         if( ( ipconfigIS_VALID_PROG_ADDRESS( pxSocket->u.xTCP.pxHandleConnected ) != pdFALSE ) && ( xConnected == NULL ) )\r
1562                         {\r
1563                                 /* The 'connected' state has changed, call the user handler. */\r
1564                                 xConnected = pxSocket;\r
1565                         }\r
1566                 }\r
1567                 #endif /* ipconfigUSE_CALLBACKS */\r
1568 \r
1569                 if( prvTCPSocketIsActive( ( UBaseType_t ) pxSocket->u.xTCP.ucTCPState ) == pdFALSE )\r
1570                 {\r
1571                         /* Now the socket isn't in an active state anymore so it\r
1572                         won't need further attention of the IP-task.\r
1573                         Setting time-out to zero means that the socket won't get checked during\r
1574                         timer events. */\r
1575                         pxSocket->u.xTCP.usTimeout = 0u;\r
1576                 }\r
1577         }\r
1578         else\r
1579         {\r
1580                 if( eTCPState == eCLOSED )\r
1581                 {\r
1582                         /* Socket goes to status eCLOSED because of a RST.\r
1583                         When nobody owns the socket yet, delete it. */\r
1584                         if( ( pxSocket->u.xTCP.bits.bPassQueued != pdFALSE_UNSIGNED ) ||\r
1585                                 ( pxSocket->u.xTCP.bits.bPassAccept != pdFALSE_UNSIGNED ) )\r
1586                         {\r
1587                                 FreeRTOS_debug_printf( ( "vTCPStateChange: Closing socket\n" ) );\r
1588                                 if( pxSocket->u.xTCP.bits.bReuseSocket == pdFALSE_UNSIGNED )\r
1589                                 {\r
1590                                         FreeRTOS_closesocket( pxSocket );\r
1591                                 }\r
1592                         }\r
1593                 }\r
1594         }\r
1595 \r
1596         /* Fill in the new state. */\r
1597         pxSocket->u.xTCP.ucTCPState = ( uint8_t ) eTCPState;\r
1598 \r
1599         /* Touch the alive timers because moving to another state. */\r
1600         prvTCPTouchSocket( pxSocket );\r
1601 \r
1602         #if( ipconfigHAS_DEBUG_PRINTF == 1 )\r
1603         {\r
1604         if( ( xTCPWindowLoggingLevel >= 0 ) && ( ipconfigTCP_MAY_LOG_PORT( pxSocket->usLocalPort ) != pdFALSE ) )\r
1605                 FreeRTOS_debug_printf( ( "Socket %d -> %lxip:%u State %s->%s\n",\r
1606                         pxSocket->usLocalPort,\r
1607                         pxSocket->u.xTCP.ulRemoteIP,\r
1608                         pxSocket->u.xTCP.usRemotePort,\r
1609                         FreeRTOS_GetTCPStateName( ( UBaseType_t ) xPreviousState ),\r
1610                         FreeRTOS_GetTCPStateName( ( UBaseType_t ) eTCPState ) ) );\r
1611         }\r
1612         #endif /* ipconfigHAS_DEBUG_PRINTF */\r
1613 \r
1614         #if( ipconfigUSE_CALLBACKS == 1 )\r
1615         {\r
1616                 if( xConnected != NULL )\r
1617                 {\r
1618                         /* The 'connected' state has changed, call the OnConnect handler of the parent. */\r
1619                         xConnected->u.xTCP.pxHandleConnected( ( Socket_t * ) xConnected, bAfter );\r
1620                 }\r
1621         }\r
1622         #endif\r
1623         if( xParent != NULL )\r
1624         {\r
1625                 vSocketWakeUpUser( xParent );\r
1626         }\r
1627 }\r
1628 /*-----------------------------------------------------------*/\r
1629 \r
1630 static NetworkBufferDescriptor_t *prvTCPBufferResize( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer,\r
1631         int32_t lDataLen, UBaseType_t uxOptionsLength )\r
1632 {\r
1633 NetworkBufferDescriptor_t *pxReturn;\r
1634 int32_t lNeeded;\r
1635 BaseType_t xResize;\r
1636 \r
1637         if( xBufferAllocFixedSize != pdFALSE )\r
1638         {\r
1639                 /* Network buffers are created with a fixed size and can hold the largest\r
1640                 MTU. */\r
1641                 lNeeded = ( int32_t ) ipTOTAL_ETHERNET_FRAME_SIZE;\r
1642                 /* and therefore, the buffer won't be too small.\r
1643                 Only ask for a new network buffer in case none was supplied. */\r
1644                 xResize = ( pxNetworkBuffer == NULL );\r
1645         }\r
1646         else\r
1647         {\r
1648                 /* Network buffers are created with a variable size. See if it must\r
1649                 grow. */\r
1650                 lNeeded = FreeRTOS_max_int32( ( int32_t ) sizeof( pxSocket->u.xTCP.xPacket.u.ucLastPacket ),\r
1651                         ( int32_t ) ( ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength ) + lDataLen );\r
1652                 /* In case we were called from a TCP timer event, a buffer must be\r
1653                 created.  Otherwise, test 'xDataLength' of the provided buffer. */\r
1654                 if( ( pxNetworkBuffer == NULL ) || ( pxNetworkBuffer->xDataLength < (size_t)lNeeded ) )\r
1655                 {\r
1656                         xResize = pdTRUE;\r
1657                 }\r
1658                 else\r
1659                 {\r
1660                         xResize = pdFALSE;\r
1661                 }\r
1662         }\r
1663 \r
1664         if( xResize != pdFALSE )\r
1665         {\r
1666                 /* The caller didn't provide a network buffer or the provided buffer is\r
1667                 too small.  As we must send-out a data packet, a buffer will be created\r
1668                 here. */\r
1669                 pxReturn = pxGetNetworkBufferWithDescriptor( ( uint32_t ) lNeeded, 0u );\r
1670 \r
1671                 if( pxReturn != NULL )\r
1672                 {\r
1673                         /* Copy the existing data to the new created buffer. */\r
1674                         if( pxNetworkBuffer )\r
1675                         {\r
1676                                 /* Either from the previous buffer... */\r
1677                                 memcpy( pxReturn->pucEthernetBuffer, pxNetworkBuffer->pucEthernetBuffer, pxNetworkBuffer->xDataLength );\r
1678 \r
1679                                 /* ...and release it. */\r
1680                                 vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );\r
1681                         }\r
1682                         else\r
1683                         {\r
1684                                 /* Or from the socket field 'xTCP.xPacket'. */\r
1685                                 memcpy( pxReturn->pucEthernetBuffer, pxSocket->u.xTCP.xPacket.u.ucLastPacket, sizeof( pxSocket->u.xTCP.xPacket.u.ucLastPacket ) );\r
1686                         }\r
1687                 }\r
1688         }\r
1689         else\r
1690         {\r
1691                 /* xResize is false, the network buffer provided was big enough. */\r
1692                 pxReturn = pxNetworkBuffer;\r
1693 \r
1694                 /* Thanks to Andrey Ivanov from swissEmbedded for reporting that the\r
1695                 xDataLength member must get the correct length too! */\r
1696                 pxNetworkBuffer->xDataLength = ( size_t ) ( ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength ) + ( size_t ) lDataLen;\r
1697         }\r
1698 \r
1699         return pxReturn;\r
1700 }\r
1701 /*-----------------------------------------------------------*/\r
1702 \r
1703 /*\r
1704  * Prepare an outgoing message, in case anything has to be sent.\r
1705  */\r
1706 static int32_t prvTCPPrepareSend( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer, UBaseType_t uxOptionsLength )\r
1707 {\r
1708 int32_t lDataLen;\r
1709 uint8_t *pucEthernetBuffer, *pucSendData;\r
1710 TCPPacket_t *pxTCPPacket;\r
1711 size_t uxOffset;\r
1712 uint32_t ulDataGot, ulDistance;\r
1713 TCPWindow_t *pxTCPWindow;\r
1714 NetworkBufferDescriptor_t *pxNewBuffer;\r
1715 int32_t lStreamPos;\r
1716 \r
1717         if( ( *ppxNetworkBuffer ) != NULL )\r
1718         {\r
1719                 /* A network buffer descriptor was already supplied */\r
1720                 pucEthernetBuffer = ( *ppxNetworkBuffer )->pucEthernetBuffer;\r
1721         }\r
1722         else\r
1723         {\r
1724                 /* For now let it point to the last packet header */\r
1725                 pucEthernetBuffer = pxSocket->u.xTCP.xPacket.u.ucLastPacket;\r
1726         }\r
1727 \r
1728         pxTCPPacket = ( TCPPacket_t * ) pucEthernetBuffer;\r
1729         pxTCPWindow = &( pxSocket->u.xTCP.xTCPWindow );\r
1730         lDataLen = 0;\r
1731         lStreamPos = 0;\r
1732         pxTCPPacket->xTCPHeader.ucTCPFlags |= ipTCP_FLAG_ACK;\r
1733 \r
1734         if( pxSocket->u.xTCP.txStream != NULL )\r
1735         {\r
1736                 /* ulTCPWindowTxGet will return the amount of data which may be sent\r
1737                 along with the position in the txStream.\r
1738                 Why check for MSS > 1 ?\r
1739                 Because some TCP-stacks (like uIP) use it for flow-control. */\r
1740                 if( pxSocket->u.xTCP.usCurMSS > 1u )\r
1741                 {\r
1742                         lDataLen = ( int32_t ) ulTCPWindowTxGet( pxTCPWindow, pxSocket->u.xTCP.ulWindowSize, &lStreamPos );\r
1743                 }\r
1744 \r
1745                 if( lDataLen > 0 )\r
1746                 {\r
1747                         /* Check if the current network buffer is big enough, if not,\r
1748                         resize it. */\r
1749                         pxNewBuffer = prvTCPBufferResize( pxSocket, *ppxNetworkBuffer, lDataLen, uxOptionsLength );\r
1750 \r
1751                         if( pxNewBuffer != NULL )\r
1752                         {\r
1753                                 *ppxNetworkBuffer = pxNewBuffer;\r
1754                                 pucEthernetBuffer = pxNewBuffer->pucEthernetBuffer;\r
1755                                 pxTCPPacket = ( TCPPacket_t * ) ( pucEthernetBuffer );\r
1756 \r
1757                                 pucSendData = pucEthernetBuffer + ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength;\r
1758 \r
1759                                 /* Translate the position in txStream to an offset from the tail\r
1760                                 marker. */\r
1761                                 uxOffset = uxStreamBufferDistance( pxSocket->u.xTCP.txStream, pxSocket->u.xTCP.txStream->uxTail, ( size_t ) lStreamPos );\r
1762 \r
1763                                 /* Here data is copied from the txStream in 'peek' mode.  Only\r
1764                                 when the packets are acked, the tail marker will be updated. */\r
1765                                 ulDataGot = ( uint32_t ) uxStreamBufferGet( pxSocket->u.xTCP.txStream, uxOffset, pucSendData, ( size_t ) lDataLen, pdTRUE );\r
1766 \r
1767                                 #if( ipconfigHAS_DEBUG_PRINTF != 0 )\r
1768                                 {\r
1769                                         if( ulDataGot != ( uint32_t ) lDataLen )\r
1770                                         {\r
1771                                                 FreeRTOS_debug_printf( ( "uxStreamBufferGet: pos %lu offs %lu only %lu != %lu\n",\r
1772                                                         lStreamPos, uxOffset, ulDataGot, lDataLen ) );\r
1773                                         }\r
1774                                 }\r
1775                                 #endif\r
1776 \r
1777                                 /* If the owner of the socket requests a closure, add the FIN\r
1778                                 flag to the last packet. */\r
1779                                 if( ( pxSocket->u.xTCP.bits.bCloseRequested != pdFALSE_UNSIGNED ) && ( pxSocket->u.xTCP.bits.bFinSent == pdFALSE_UNSIGNED ) )\r
1780                                 {\r
1781                                         ulDistance = ( uint32_t ) uxStreamBufferDistance( pxSocket->u.xTCP.txStream, ( size_t ) lStreamPos, pxSocket->u.xTCP.txStream->uxHead );\r
1782 \r
1783                                         if( ulDistance == ulDataGot )\r
1784                                         {\r
1785                                                 #if (ipconfigHAS_DEBUG_PRINTF == 1)\r
1786                                                 {\r
1787                                                 /* the order of volatile accesses is undefined\r
1788                                                         so such workaround */\r
1789                                                         size_t uxHead = pxSocket->u.xTCP.txStream->uxHead;\r
1790                                                         size_t uxMid = pxSocket->u.xTCP.txStream->uxMid;\r
1791                                                         size_t uxTail = pxSocket->u.xTCP.txStream->uxTail;\r
1792 \r
1793                                                         FreeRTOS_debug_printf( ( "CheckClose %lu <= %lu (%lu <= %lu <= %lu)\n", ulDataGot, ulDistance,\r
1794                                                                 uxTail, uxMid, uxHead ) );\r
1795                                                 }\r
1796                                                 #endif\r
1797                                                 /* Although the socket sends a FIN, it will stay in\r
1798                                                 ESTABLISHED until all current data has been received or\r
1799                                                 delivered. */\r
1800                                                 pxTCPPacket->xTCPHeader.ucTCPFlags |= ipTCP_FLAG_FIN;\r
1801                                                 pxTCPWindow->tx.ulFINSequenceNumber = pxTCPWindow->ulOurSequenceNumber + ( uint32_t ) lDataLen;\r
1802                                                 pxSocket->u.xTCP.bits.bFinSent = pdTRUE_UNSIGNED;\r
1803                                         }\r
1804                                 }\r
1805                         }\r
1806                         else\r
1807                         {\r
1808                                 lDataLen = -1;\r
1809                         }\r
1810                 }\r
1811         }\r
1812 \r
1813         if( ( lDataLen >= 0 ) && ( pxSocket->u.xTCP.ucTCPState == eESTABLISHED ) )\r
1814         {\r
1815                 /* See if the socket owner wants to shutdown this connection. */\r
1816                 if( ( pxSocket->u.xTCP.bits.bUserShutdown != pdFALSE_UNSIGNED ) &&\r
1817                         ( xTCPWindowTxDone( pxTCPWindow ) != pdFALSE ) )\r
1818                 {\r
1819                         pxSocket->u.xTCP.bits.bUserShutdown = pdFALSE_UNSIGNED;\r
1820                         pxTCPPacket->xTCPHeader.ucTCPFlags |= ipTCP_FLAG_FIN;\r
1821                         pxSocket->u.xTCP.bits.bFinSent = pdTRUE_UNSIGNED;\r
1822                         pxSocket->u.xTCP.bits.bWinChange = pdTRUE_UNSIGNED;\r
1823                         pxTCPWindow->tx.ulFINSequenceNumber = pxTCPWindow->tx.ulCurrentSequenceNumber;\r
1824                         vTCPStateChange( pxSocket, eFIN_WAIT_1 );\r
1825                 }\r
1826 \r
1827                 #if( ipconfigTCP_KEEP_ALIVE != 0 )\r
1828                 {\r
1829                         if( pxSocket->u.xTCP.ucKeepRepCount > 3u )\r
1830                         {\r
1831                                 FreeRTOS_debug_printf( ( "keep-alive: giving up %lxip:%u\n",\r
1832                                         pxSocket->u.xTCP.ulRemoteIP,                    /* IP address of remote machine. */\r
1833                                         pxSocket->u.xTCP.usRemotePort ) );      /* Port on remote machine. */\r
1834                                 vTCPStateChange( pxSocket, eCLOSE_WAIT );\r
1835                                 lDataLen = -1;\r
1836                         }\r
1837                         if( ( lDataLen == 0 ) && ( pxSocket->u.xTCP.bits.bWinChange == pdFALSE_UNSIGNED ) )\r
1838                         {\r
1839                                 /* If there is no data to be sent, and no window-update message,\r
1840                                 we might want to send a keep-alive message. */\r
1841                                 TickType_t xAge = xTaskGetTickCount( ) - pxSocket->u.xTCP.xLastAliveTime;\r
1842                                 TickType_t xMax;\r
1843                                 xMax = ( ( TickType_t ) ipconfigTCP_KEEP_ALIVE_INTERVAL * configTICK_RATE_HZ );\r
1844                                 if( pxSocket->u.xTCP.ucKeepRepCount )\r
1845                                 {\r
1846                                         xMax = ( 3u * configTICK_RATE_HZ );\r
1847                                 }\r
1848                                 if( xAge > xMax )\r
1849                                 {\r
1850                                         pxSocket->u.xTCP.xLastAliveTime = xTaskGetTickCount( );\r
1851                                         if( xTCPWindowLoggingLevel )\r
1852                                                 FreeRTOS_debug_printf( ( "keep-alive: %lxip:%u count %u\n",\r
1853                                                         pxSocket->u.xTCP.ulRemoteIP,\r
1854                                                         pxSocket->u.xTCP.usRemotePort,\r
1855                                                         pxSocket->u.xTCP.ucKeepRepCount ) );\r
1856                                         pxSocket->u.xTCP.bits.bSendKeepAlive = pdTRUE_UNSIGNED;\r
1857                                         pxSocket->u.xTCP.usTimeout = ( ( uint16_t ) pdMS_TO_TICKS( 2500 ) );\r
1858                                         pxSocket->u.xTCP.ucKeepRepCount++;\r
1859                                 }\r
1860                         }\r
1861                 }\r
1862                 #endif /* ipconfigTCP_KEEP_ALIVE */\r
1863         }\r
1864 \r
1865         /* Anything to send, a change of the advertised window size, or maybe send a\r
1866         keep-alive message? */\r
1867         if( ( lDataLen > 0 ) ||\r
1868                 ( pxSocket->u.xTCP.bits.bWinChange != pdFALSE_UNSIGNED ) ||\r
1869                 ( pxSocket->u.xTCP.bits.bSendKeepAlive != pdFALSE_UNSIGNED ) )\r
1870         {\r
1871                 pxTCPPacket->xTCPHeader.ucTCPFlags &= ( ( uint8_t ) ~ipTCP_FLAG_PSH );\r
1872                 pxTCPPacket->xTCPHeader.ucTCPOffset = ( uint8_t )( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 );\r
1873 \r
1874                 pxTCPPacket->xTCPHeader.ucTCPFlags |= ( uint8_t ) ipTCP_FLAG_ACK;\r
1875 \r
1876                 if( lDataLen != 0l )\r
1877                 {\r
1878                         pxTCPPacket->xTCPHeader.ucTCPFlags |= ( uint8_t ) ipTCP_FLAG_PSH;\r
1879                 }\r
1880 \r
1881                 #if     ipconfigUSE_TCP_TIMESTAMPS == 1\r
1882                 {\r
1883                         if( uxOptionsLength == 0u )\r
1884                         {\r
1885                                 if( pxSocket->u.xTCP.xTCPWindow.u.bits.bTimeStamps )\r
1886                                 {\r
1887                                         TCPPacket_t * pxTCPPacket = ( TCPPacket_t * ) ( pucEthernetBuffer );\r
1888                                         uxOptionsLength = prvTCPSetTimeStamp( 0, pxSocket, &pxTCPPacket->xTCPHeader );\r
1889                                 }\r
1890                         }\r
1891                 }\r
1892                 #endif\r
1893 \r
1894                 lDataLen += ( int32_t ) ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength );\r
1895         }\r
1896 \r
1897         return lDataLen;\r
1898 }\r
1899 /*-----------------------------------------------------------*/\r
1900 \r
1901 /*\r
1902  * Calculate after how much time this socket needs to be checked again.\r
1903  */\r
1904 static TickType_t prvTCPNextTimeout ( FreeRTOS_Socket_t *pxSocket )\r
1905 {\r
1906 TickType_t ulDelayMs = ( TickType_t ) tcpMAXIMUM_TCP_WAKEUP_TIME_MS;\r
1907 \r
1908         if( pxSocket->u.xTCP.ucTCPState == eCONNECT_SYN )\r
1909         {\r
1910                 /* The socket is actively connecting to a peer. */\r
1911                 if( pxSocket->u.xTCP.bits.bConnPrepared )\r
1912                 {\r
1913                         /* Ethernet address has been found, use progressive timeout for\r
1914                         active connect(). */\r
1915                         if( pxSocket->u.xTCP.ucRepCount < 3u )\r
1916                         {\r
1917                                 ulDelayMs = ( 3000UL << ( pxSocket->u.xTCP.ucRepCount - 1u ) );\r
1918                         }\r
1919                         else\r
1920                         {\r
1921                                 ulDelayMs = 11000UL;\r
1922                         }\r
1923                 }\r
1924                 else\r
1925                 {\r
1926                         /* Still in the ARP phase: check every half second. */\r
1927                         ulDelayMs = 500UL;\r
1928                 }\r
1929 \r
1930                 FreeRTOS_debug_printf( ( "Connect[%lxip:%u]: next timeout %u: %lu ms\n",\r
1931                         pxSocket->u.xTCP.ulRemoteIP, pxSocket->u.xTCP.usRemotePort,\r
1932                         pxSocket->u.xTCP.ucRepCount, ulDelayMs ) );\r
1933                 pxSocket->u.xTCP.usTimeout = ( uint16_t )pdMS_TO_MIN_TICKS( ulDelayMs );\r
1934         }\r
1935         else if( pxSocket->u.xTCP.usTimeout == 0u )\r
1936         {\r
1937                 /* Let the sliding window mechanism decide what time-out is appropriate. */\r
1938                 BaseType_t xResult = xTCPWindowTxHasData( &pxSocket->u.xTCP.xTCPWindow, pxSocket->u.xTCP.ulWindowSize, &ulDelayMs );\r
1939                 if( ulDelayMs == 0u )\r
1940                 {\r
1941                         if( xResult != ( BaseType_t )0 )\r
1942                         {\r
1943                                 ulDelayMs = 1UL;\r
1944                         }\r
1945                         else\r
1946                         {\r
1947                                 ulDelayMs = tcpMAXIMUM_TCP_WAKEUP_TIME_MS;\r
1948                         }\r
1949                 }\r
1950                 else\r
1951                 {\r
1952                         /* ulDelayMs contains the time to wait before a re-transmission. */\r
1953                 }\r
1954                 pxSocket->u.xTCP.usTimeout = ( uint16_t )pdMS_TO_MIN_TICKS( ulDelayMs );\r
1955         }\r
1956         else\r
1957         {\r
1958                 /* field '.usTimeout' has already been set (by the\r
1959                 keep-alive/delayed-ACK mechanism). */\r
1960         }\r
1961 \r
1962         /* Return the number of clock ticks before the timer expires. */\r
1963         return ( TickType_t ) pxSocket->u.xTCP.usTimeout;\r
1964 }\r
1965 /*-----------------------------------------------------------*/\r
1966 \r
1967 static void prvTCPAddTxData( FreeRTOS_Socket_t *pxSocket )\r
1968 {\r
1969 int32_t lCount, lLength;\r
1970 \r
1971         /* A txStream has been created already, see if the socket has new data for\r
1972         the sliding window.\r
1973 \r
1974         uxStreamBufferMidSpace() returns the distance between rxHead and rxMid.  It\r
1975         contains new Tx data which has not been passed to the sliding window yet.\r
1976         The oldest data not-yet-confirmed can be found at rxTail. */\r
1977         lLength = ( int32_t ) uxStreamBufferMidSpace( pxSocket->u.xTCP.txStream );\r
1978 \r
1979         if( lLength > 0 )\r
1980         {\r
1981                 /* All data between txMid and rxHead will now be passed to the sliding\r
1982                 window manager, so it can start transmitting them.\r
1983 \r
1984                 Hand over the new data to the sliding window handler.  It will be\r
1985                 split-up in chunks of 1460 bytes each (or less, depending on\r
1986                 ipconfigTCP_MSS). */\r
1987                 lCount = lTCPWindowTxAdd(       &pxSocket->u.xTCP.xTCPWindow,\r
1988                                                                 ( uint32_t ) lLength,\r
1989                                                                 ( int32_t ) pxSocket->u.xTCP.txStream->uxMid,\r
1990                                                                 ( int32_t ) pxSocket->u.xTCP.txStream->LENGTH );\r
1991 \r
1992                 /* Move the rxMid pointer forward up to rxHead. */\r
1993                 if( lCount > 0 )\r
1994                 {\r
1995                         vStreamBufferMoveMid( pxSocket->u.xTCP.txStream, ( size_t ) lCount );\r
1996                 }\r
1997         }\r
1998 }\r
1999 /*-----------------------------------------------------------*/\r
2000 \r
2001 /*\r
2002  * prvTCPHandleFin() will be called to handle socket closure\r
2003  * The Closure starts when either a FIN has been received and accepted,\r
2004  * Or when the socket has sent a FIN flag to the peer\r
2005  * Before being called, it has been checked that both reception and transmission\r
2006  * are complete.\r
2007  */\r
2008 static BaseType_t prvTCPHandleFin( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer )\r
2009 {\r
2010 TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );\r
2011 TCPHeader_t *pxTCPHeader = &pxTCPPacket->xTCPHeader;\r
2012 uint8_t ucTCPFlags = pxTCPHeader->ucTCPFlags;\r
2013 TCPWindow_t *pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow;\r
2014 BaseType_t xSendLength = 0;\r
2015 uint32_t ulAckNr = FreeRTOS_ntohl( pxTCPHeader->ulAckNr );\r
2016 \r
2017         if( ( ucTCPFlags & ipTCP_FLAG_FIN ) != 0u )\r
2018         {\r
2019                 pxTCPWindow->rx.ulCurrentSequenceNumber = pxTCPWindow->rx.ulFINSequenceNumber + 1u;\r
2020         }\r
2021         if( pxSocket->u.xTCP.bits.bFinSent == pdFALSE_UNSIGNED )\r
2022         {\r
2023                 /* We haven't yet replied with a FIN, do so now. */\r
2024                 pxTCPWindow->tx.ulFINSequenceNumber = pxTCPWindow->tx.ulCurrentSequenceNumber;\r
2025                 pxSocket->u.xTCP.bits.bFinSent = pdTRUE_UNSIGNED;\r
2026         }\r
2027         else\r
2028         {\r
2029                 /* We did send a FIN already, see if it's ACK'd. */\r
2030                 if( ulAckNr == pxTCPWindow->tx.ulFINSequenceNumber + 1u )\r
2031                 {\r
2032                         pxSocket->u.xTCP.bits.bFinAcked = pdTRUE_UNSIGNED;\r
2033                 }\r
2034         }\r
2035 \r
2036         if( pxSocket->u.xTCP.bits.bFinAcked == pdFALSE_UNSIGNED )\r
2037         {\r
2038                 pxTCPWindow->tx.ulCurrentSequenceNumber = pxTCPWindow->tx.ulFINSequenceNumber;\r
2039                 pxTCPHeader->ucTCPFlags = ipTCP_FLAG_ACK | ipTCP_FLAG_FIN;\r
2040 \r
2041                 /* And wait for the final ACK. */\r
2042                 vTCPStateChange( pxSocket, eLAST_ACK );\r
2043         }\r
2044         else\r
2045         {\r
2046                 /* Our FIN has been ACK'd, the outgoing sequence number is now fixed. */\r
2047                 pxTCPWindow->tx.ulCurrentSequenceNumber = pxTCPWindow->tx.ulFINSequenceNumber + 1u;\r
2048                 if( pxSocket->u.xTCP.bits.bFinRecv == pdFALSE_UNSIGNED )\r
2049                 {\r
2050                         /* We have sent out a FIN but the peer hasn't replied with a FIN\r
2051                         yet. Do nothing for the moment. */\r
2052                         pxTCPHeader->ucTCPFlags = 0u;\r
2053                 }\r
2054                 else\r
2055                 {\r
2056                         if( pxSocket->u.xTCP.bits.bFinLast == pdFALSE_UNSIGNED )\r
2057                         {\r
2058                                 /* This is the third of the three-way hand shake: the last\r
2059                                 ACK. */\r
2060                                 pxTCPHeader->ucTCPFlags = ipTCP_FLAG_ACK;\r
2061                         }\r
2062                         else\r
2063                         {\r
2064                                 /* The other party started the closure, so we just wait for the\r
2065                                 last ACK. */\r
2066                                 pxTCPHeader->ucTCPFlags = 0u;\r
2067                         }\r
2068 \r
2069                         /* And wait for the user to close this socket. */\r
2070                         vTCPStateChange( pxSocket, eCLOSE_WAIT );\r
2071                 }\r
2072         }\r
2073 \r
2074         pxTCPWindow->ulOurSequenceNumber = pxTCPWindow->tx.ulCurrentSequenceNumber;\r
2075 \r
2076         if( pxTCPHeader->ucTCPFlags != 0u )\r
2077         {\r
2078                 xSendLength = ( BaseType_t ) ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + pxTCPWindow->ucOptionLength );\r
2079         }\r
2080 \r
2081         pxTCPHeader->ucTCPOffset = ( uint8_t ) ( ( ipSIZE_OF_TCP_HEADER + pxTCPWindow->ucOptionLength ) << 2 );\r
2082 \r
2083         if( xTCPWindowLoggingLevel != 0 )\r
2084         {\r
2085                 FreeRTOS_debug_printf( ( "TCP: send FIN+ACK (ack %lu, cur/nxt %lu/%lu) ourSeqNr %lu | Rx %lu\n",\r
2086                         ulAckNr - pxTCPWindow->tx.ulFirstSequenceNumber,\r
2087                         pxTCPWindow->tx.ulCurrentSequenceNumber - pxTCPWindow->tx.ulFirstSequenceNumber,\r
2088                         pxTCPWindow->ulNextTxSequenceNumber - pxTCPWindow->tx.ulFirstSequenceNumber,\r
2089                         pxTCPWindow->ulOurSequenceNumber - pxTCPWindow->tx.ulFirstSequenceNumber,\r
2090                         pxTCPWindow->rx.ulCurrentSequenceNumber - pxTCPWindow->rx.ulFirstSequenceNumber ) );\r
2091         }\r
2092 \r
2093         return xSendLength;\r
2094 }\r
2095 /*-----------------------------------------------------------*/\r
2096 \r
2097 #if     ipconfigUSE_TCP_TIMESTAMPS == 1\r
2098 \r
2099         static UBaseType_t prvTCPSetTimeStamp( BaseType_t lOffset, FreeRTOS_Socket_t *pxSocket, TCPHeader_t *pxTCPHeader )\r
2100         {\r
2101         uint32_t ulTimes[2];\r
2102         uint8_t *ucOptdata = &( pxTCPHeader->ucOptdata[ lOffset ] );\r
2103 \r
2104                 ulTimes[0]   = ( xTaskGetTickCount ( ) * 1000u ) / configTICK_RATE_HZ;\r
2105                 ulTimes[0]   = FreeRTOS_htonl( ulTimes[0] );\r
2106                 ulTimes[1]   = FreeRTOS_htonl( pxSocket->u.xTCP.xTCPWindow.rx.ulTimeStamp );\r
2107                 ucOptdata[0] = ( uint8_t ) TCP_OPT_TIMESTAMP;\r
2108                 ucOptdata[1] = ( uint8_t ) TCP_OPT_TIMESTAMP_LEN;\r
2109                 memcpy( &(ucOptdata[2] ), ulTimes, 8u );\r
2110                 ucOptdata[10] = ( uint8_t ) TCP_OPT_NOOP;\r
2111                 ucOptdata[11] = ( uint8_t ) TCP_OPT_NOOP;\r
2112                 /* Do not return the same timestamps 2 times. */\r
2113                 pxSocket->u.xTCP.xTCPWindow.rx.ulTimeStamp = 0ul;\r
2114                 return 12u;\r
2115         }\r
2116 \r
2117 #endif\r
2118 /*-----------------------------------------------------------*/\r
2119 \r
2120 /*\r
2121  * prvCheckRxData(): called from prvTCPHandleState()\r
2122  *\r
2123  * The first thing that will be done is find the TCP payload data\r
2124  * and check the length of this data.\r
2125  */\r
2126 static BaseType_t prvCheckRxData( NetworkBufferDescriptor_t *pxNetworkBuffer, uint8_t **ppucRecvData )\r
2127 {\r
2128 TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );\r
2129 TCPHeader_t *pxTCPHeader = &( pxTCPPacket->xTCPHeader );\r
2130 int32_t lLength, lTCPHeaderLength, lReceiveLength, lUrgentLength;\r
2131 \r
2132         /* Determine the length and the offset of the user-data sent to this\r
2133         node.\r
2134 \r
2135         The size of the TCP header is given in a multiple of 4-byte words (single\r
2136         byte, needs no ntoh() translation).  A shift-right 2: is the same as\r
2137         (offset >> 4) * 4. */\r
2138     lTCPHeaderLength = ( BaseType_t ) ( ( pxTCPHeader->ucTCPOffset & VALID_BITS_IN_TCP_OFFSET_BYTE ) >> 2 );\r
2139 \r
2140         /* Let pucRecvData point to the first byte received. */\r
2141         *ppucRecvData = pxNetworkBuffer->pucEthernetBuffer + ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv4_HEADER + lTCPHeaderLength;\r
2142 \r
2143         /* Calculate lReceiveLength - the length of the TCP data received.  This is\r
2144         equal to the total packet length minus:\r
2145         ( LinkLayer length (14) + IP header length (20) + size of TCP header(20 +) ).*/\r
2146         lReceiveLength = ( ( int32_t ) pxNetworkBuffer->xDataLength ) - ( int32_t ) ipSIZE_OF_ETH_HEADER;\r
2147         lLength =  ( int32_t )FreeRTOS_htons( pxTCPPacket->xIPHeader.usLength );\r
2148 \r
2149         if( lReceiveLength > lLength )\r
2150         {\r
2151                 /* More bytes were received than the reported length, often because of\r
2152                 padding bytes at the end. */\r
2153                 lReceiveLength = lLength;\r
2154         }\r
2155 \r
2156         /* Subtract the size of the TCP and IP headers and the actual data size is\r
2157         known. */\r
2158         if( lReceiveLength > ( lTCPHeaderLength + ( int32_t ) ipSIZE_OF_IPv4_HEADER ) )\r
2159         {\r
2160                 lReceiveLength -= ( lTCPHeaderLength + ( int32_t ) ipSIZE_OF_IPv4_HEADER );\r
2161         }\r
2162         else\r
2163         {\r
2164                 lReceiveLength = 0;\r
2165         }\r
2166 \r
2167         /* Urgent Pointer:\r
2168         This field communicates the current value of the urgent pointer as a\r
2169         positive offset from the sequence number in this segment.  The urgent\r
2170         pointer points to the sequence number of the octet following the urgent\r
2171         data.  This field is only be interpreted in segments with the URG control\r
2172         bit set. */\r
2173         if( ( pxTCPHeader->ucTCPFlags & ipTCP_FLAG_URG ) != 0u )\r
2174         {\r
2175                 /* Although we ignore the urgent data, we have to skip it. */\r
2176                 lUrgentLength = ( int32_t ) FreeRTOS_htons( pxTCPHeader->usUrgent );\r
2177                 *ppucRecvData += lUrgentLength;\r
2178                 lReceiveLength -= FreeRTOS_min_int32( lReceiveLength, lUrgentLength );\r
2179         }\r
2180 \r
2181         return ( BaseType_t ) lReceiveLength;\r
2182 }\r
2183 /*-----------------------------------------------------------*/\r
2184 \r
2185 /*\r
2186  * prvStoreRxData(): called from prvTCPHandleState()\r
2187  *\r
2188  * The second thing is to do is check if the payload data may be accepted\r
2189  * If so, they will be added to the reception queue.\r
2190  */\r
2191 static BaseType_t prvStoreRxData( FreeRTOS_Socket_t *pxSocket, uint8_t *pucRecvData,\r
2192         NetworkBufferDescriptor_t *pxNetworkBuffer, uint32_t ulReceiveLength )\r
2193 {\r
2194 TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );\r
2195 TCPHeader_t *pxTCPHeader = &pxTCPPacket->xTCPHeader;\r
2196 TCPWindow_t *pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow;\r
2197 uint32_t ulSequenceNumber, ulSpace;\r
2198 int32_t lOffset, lStored;\r
2199 BaseType_t xResult = 0;\r
2200 \r
2201         ulSequenceNumber = FreeRTOS_ntohl( pxTCPHeader->ulSequenceNumber );\r
2202 \r
2203         if( ( ulReceiveLength > 0u ) && ( pxSocket->u.xTCP.ucTCPState >= eSYN_RECEIVED ) )\r
2204         {\r
2205                 /* See if way may accept the data contents and forward it to the socket\r
2206                 owner.\r
2207 \r
2208                 If it can't be "accept"ed it may have to be stored and send a selective\r
2209                 ack (SACK) option to confirm it.  In that case, xTCPWindowRxStore() will be\r
2210                 called later to store an out-of-order packet (in case lOffset is\r
2211                 negative). */\r
2212                 if ( pxSocket->u.xTCP.rxStream )\r
2213                 {\r
2214                         ulSpace = ( uint32_t )uxStreamBufferGetSpace ( pxSocket->u.xTCP.rxStream );\r
2215                 }\r
2216                 else\r
2217                 {\r
2218                         ulSpace = ( uint32_t )pxSocket->u.xTCP.uxRxStreamSize;\r
2219                 }\r
2220 \r
2221                 lOffset = lTCPWindowRxCheck( pxTCPWindow, ulSequenceNumber, ulReceiveLength, ulSpace );\r
2222 \r
2223                 if( lOffset >= 0 )\r
2224                 {\r
2225                         /* New data has arrived and may be made available to the user.  See\r
2226                         if the head marker in rxStream may be advanced, only if lOffset == 0.\r
2227                         In case the low-water mark is reached, bLowWater will be set\r
2228                         "low-water" here stands for "little space". */\r
2229                         lStored = lTCPAddRxdata( pxSocket, ( uint32_t ) lOffset, pucRecvData, ulReceiveLength );\r
2230 \r
2231                         if( lStored != ( int32_t ) ulReceiveLength )\r
2232                         {\r
2233                                 FreeRTOS_debug_printf( ( "lTCPAddRxdata: stored %ld / %lu bytes??\n", lStored, ulReceiveLength ) );\r
2234 \r
2235                                 /* Received data could not be stored.  The socket's flag\r
2236                                 bMallocError has been set.  The socket now has the status\r
2237                                 eCLOSE_WAIT and a RST packet will be sent back. */\r
2238                                 prvTCPSendReset( pxNetworkBuffer );\r
2239                                 xResult = -1;\r
2240                         }\r
2241                 }\r
2242 \r
2243                 /* After a missing packet has come in, higher packets may be passed to\r
2244                 the user. */\r
2245                 #if( ipconfigUSE_TCP_WIN == 1 )\r
2246                 {\r
2247                         /* Now lTCPAddRxdata() will move the rxHead pointer forward\r
2248                         so data becomes available to the user immediately\r
2249                         In case the low-water mark is reached, bLowWater will be set. */\r
2250                         if( ( xResult == 0 ) && ( pxTCPWindow->ulUserDataLength > 0 ) )\r
2251                         {\r
2252                                 lTCPAddRxdata( pxSocket, 0ul, NULL, pxTCPWindow->ulUserDataLength );\r
2253                                 pxTCPWindow->ulUserDataLength = 0;\r
2254                         }\r
2255                 }\r
2256                 #endif /* ipconfigUSE_TCP_WIN */\r
2257         }\r
2258         else\r
2259         {\r
2260                 pxTCPWindow->ucOptionLength = 0u;\r
2261         }\r
2262 \r
2263         return xResult;\r
2264 }\r
2265 /*-----------------------------------------------------------*/\r
2266 \r
2267 /* Set the TCP options (if any) for the outgoing packet. */\r
2268 static UBaseType_t prvSetOptions( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer )\r
2269 {\r
2270 TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );\r
2271 TCPHeader_t *pxTCPHeader = &pxTCPPacket->xTCPHeader;\r
2272 TCPWindow_t *pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow;\r
2273 UBaseType_t uxOptionsLength = pxTCPWindow->ucOptionLength;\r
2274 \r
2275         #if(    ipconfigUSE_TCP_WIN == 1 )\r
2276                 if( uxOptionsLength != 0u )\r
2277                 {\r
2278                         /* TCP options must be sent because a packet which is out-of-order\r
2279                         was received. */\r
2280                         if( xTCPWindowLoggingLevel >= 0 )\r
2281                                 FreeRTOS_debug_printf( ( "SACK[%d,%d]: optlen %lu sending %lu - %lu\n",\r
2282                                         pxSocket->usLocalPort,\r
2283                                         pxSocket->u.xTCP.usRemotePort,\r
2284                                         uxOptionsLength,\r
2285                                         FreeRTOS_ntohl( pxTCPWindow->ulOptionsData[ 1 ] ) - pxSocket->u.xTCP.xTCPWindow.rx.ulFirstSequenceNumber,\r
2286                                         FreeRTOS_ntohl( pxTCPWindow->ulOptionsData[ 2 ] ) - pxSocket->u.xTCP.xTCPWindow.rx.ulFirstSequenceNumber ) );\r
2287                         memcpy( pxTCPHeader->ucOptdata, pxTCPWindow->ulOptionsData, ( size_t ) uxOptionsLength );\r
2288 \r
2289                         /* The header length divided by 4, goes into the higher nibble,\r
2290                         effectively a shift-left 2. */\r
2291                         pxTCPHeader->ucTCPOffset = ( uint8_t )( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 );\r
2292                 }\r
2293                 else\r
2294         #endif  /* ipconfigUSE_TCP_WIN */\r
2295         if( ( pxSocket->u.xTCP.ucTCPState >= eESTABLISHED ) && ( pxSocket->u.xTCP.bits.bMssChange != pdFALSE_UNSIGNED ) )\r
2296         {\r
2297                 /* TCP options must be sent because the MSS has changed. */\r
2298                 pxSocket->u.xTCP.bits.bMssChange = pdFALSE_UNSIGNED;\r
2299                 if( xTCPWindowLoggingLevel >= 0 )\r
2300                 {\r
2301                         FreeRTOS_debug_printf( ( "MSS: sending %d\n", pxSocket->u.xTCP.usCurMSS ) );\r
2302                 }\r
2303 \r
2304                 pxTCPHeader->ucOptdata[ 0 ] = TCP_OPT_MSS;\r
2305                 pxTCPHeader->ucOptdata[ 1 ] = TCP_OPT_MSS_LEN;\r
2306                 pxTCPHeader->ucOptdata[ 2 ] = ( uint8_t ) ( ( pxSocket->u.xTCP.usCurMSS ) >> 8 );\r
2307                 pxTCPHeader->ucOptdata[ 3 ] = ( uint8_t ) ( ( pxSocket->u.xTCP.usCurMSS ) & 0xffu );\r
2308                 uxOptionsLength = 4u;\r
2309                 pxTCPHeader->ucTCPOffset = ( uint8_t )( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 );\r
2310         }\r
2311 \r
2312         #if(    ipconfigUSE_TCP_TIMESTAMPS == 1 )\r
2313         {\r
2314                 if( pxSocket->u.xTCP.xTCPWindow.u.bits.bTimeStamps )\r
2315                 {\r
2316                         uxOptionsLength += prvTCPSetTimeStamp( uxOptionsLength, pxSocket, pxTCPHeader );\r
2317                 }\r
2318         }\r
2319         #endif  /* ipconfigUSE_TCP_TIMESTAMPS == 1 */\r
2320 \r
2321         return uxOptionsLength;\r
2322 }\r
2323 /*-----------------------------------------------------------*/\r
2324 \r
2325 /*\r
2326  * prvHandleSynReceived(): called from prvTCPHandleState()\r
2327  *\r
2328  * Called from the states: eSYN_RECEIVED and eCONNECT_SYN\r
2329  * If the flags received are correct, the socket will move to eESTABLISHED.\r
2330  */\r
2331 static BaseType_t prvHandleSynReceived( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer,\r
2332         uint32_t ulReceiveLength, UBaseType_t uxOptionsLength )\r
2333 {\r
2334 TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( (*ppxNetworkBuffer)->pucEthernetBuffer );\r
2335 TCPHeader_t *pxTCPHeader = &pxTCPPacket->xTCPHeader;\r
2336 TCPWindow_t *pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow;\r
2337 uint8_t ucTCPFlags = pxTCPHeader->ucTCPFlags;\r
2338 uint32_t ulSequenceNumber = FreeRTOS_ntohl( pxTCPHeader->ulSequenceNumber );\r
2339 BaseType_t xSendLength = 0;\r
2340 \r
2341         /* Either expect a ACK or a SYN+ACK. */\r
2342         uint16_t usExpect = ( uint16_t ) ipTCP_FLAG_ACK;\r
2343         if( pxSocket->u.xTCP.ucTCPState == eCONNECT_SYN )\r
2344         {\r
2345                 usExpect |= ( uint16_t ) ipTCP_FLAG_SYN;\r
2346         }\r
2347 \r
2348         if( ( ucTCPFlags & 0x17u ) != usExpect )\r
2349         {\r
2350                 /* eSYN_RECEIVED: flags 0010 expected, not 0002. */\r
2351                 /* eSYN_RECEIVED: flags ACK  expected, not SYN. */\r
2352                 FreeRTOS_debug_printf( ( "%s: flags %04X expected, not %04X\n",\r
2353                         pxSocket->u.xTCP.ucTCPState == eSYN_RECEIVED ? "eSYN_RECEIVED" : "eCONNECT_SYN",\r
2354                         usExpect, ucTCPFlags ) );\r
2355                 vTCPStateChange( pxSocket, eCLOSE_WAIT );\r
2356                 pxTCPHeader->ucTCPFlags |= ipTCP_FLAG_RST;\r
2357                 xSendLength = ( BaseType_t ) ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength );\r
2358                 pxTCPHeader->ucTCPOffset = ( uint8_t )( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 );\r
2359         }\r
2360         else\r
2361         {\r
2362                 pxTCPWindow->usPeerPortNumber = pxSocket->u.xTCP.usRemotePort;\r
2363                 pxTCPWindow->usOurPortNumber = pxSocket->usLocalPort;\r
2364 \r
2365                 if( pxSocket->u.xTCP.ucTCPState == eCONNECT_SYN )\r
2366                 {\r
2367                         TCPPacket_t *pxLastTCPPacket = ( TCPPacket_t * ) ( pxSocket->u.xTCP.xPacket.u.ucLastPacket );\r
2368 \r
2369                         /* Clear the SYN flag in lastPacket. */\r
2370                         pxLastTCPPacket->xTCPHeader.ucTCPFlags = ipTCP_FLAG_ACK;\r
2371 \r
2372                         /* This socket was the one connecting actively so now perofmr the\r
2373                         synchronisation. */\r
2374                         vTCPWindowInit( &pxSocket->u.xTCP.xTCPWindow,\r
2375                                 ulSequenceNumber, pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber, ( uint32_t ) pxSocket->u.xTCP.usCurMSS );\r
2376                         pxTCPWindow->rx.ulCurrentSequenceNumber = pxTCPWindow->rx.ulHighestSequenceNumber = ulSequenceNumber + 1u;\r
2377                         pxTCPWindow->tx.ulCurrentSequenceNumber++; /* because we send a TCP_SYN [ | TCP_ACK ]; */\r
2378                         pxTCPWindow->ulNextTxSequenceNumber++;\r
2379                 }\r
2380                 else if( ulReceiveLength == 0u )\r
2381                 {\r
2382                         pxTCPWindow->rx.ulCurrentSequenceNumber = ulSequenceNumber;\r
2383                 }\r
2384 \r
2385                 /* The SYN+ACK has been confirmed, increase the next sequence number by\r
2386                 1. */\r
2387                 pxTCPWindow->ulOurSequenceNumber = pxTCPWindow->tx.ulFirstSequenceNumber + 1u;\r
2388 \r
2389                 #if( ipconfigUSE_TCP_WIN == 1 )\r
2390                 {\r
2391                         FreeRTOS_debug_printf( ( "TCP: %s %d => %lxip:%d set ESTAB (scaling %u)\n",\r
2392                                 pxSocket->u.xTCP.ucTCPState == eCONNECT_SYN ? "active" : "passive",\r
2393                                 pxSocket->usLocalPort,\r
2394                                 pxSocket->u.xTCP.ulRemoteIP,\r
2395                                 pxSocket->u.xTCP.usRemotePort,\r
2396                                 ( unsigned ) pxSocket->u.xTCP.bits.bWinScaling ) );\r
2397                 }\r
2398                 #endif /* ipconfigUSE_TCP_WIN */\r
2399 \r
2400                 if( ( pxSocket->u.xTCP.ucTCPState == eCONNECT_SYN ) || ( ulReceiveLength != 0u ) )\r
2401                 {\r
2402                         pxTCPHeader->ucTCPFlags = ipTCP_FLAG_ACK;\r
2403                         xSendLength = ( BaseType_t ) ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength );\r
2404                         pxTCPHeader->ucTCPOffset = ( uint8_t ) ( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 );\r
2405                 }\r
2406                 #if( ipconfigUSE_TCP_WIN != 0 )\r
2407                 {\r
2408                         if( pxSocket->u.xTCP.bits.bWinScaling == pdFALSE_UNSIGNED )\r
2409                         {\r
2410                                 /* The other party did not send a scaling factor.\r
2411                                 A shifting factor in this side must be canceled. */\r
2412                                 pxSocket->u.xTCP.ucMyWinScaleFactor = 0;\r
2413                                 pxSocket->u.xTCP.ucPeerWinScaleFactor = 0;\r
2414                         }\r
2415                 }\r
2416                 #endif /* ipconfigUSE_TCP_WIN */\r
2417                 /* This was the third step of connecting: SYN, SYN+ACK, ACK     so now the\r
2418                 connection is established. */\r
2419                 vTCPStateChange( pxSocket, eESTABLISHED );\r
2420         }\r
2421 \r
2422         return xSendLength;\r
2423 }\r
2424 /*-----------------------------------------------------------*/\r
2425 \r
2426 /*\r
2427  * prvHandleEstablished(): called from prvTCPHandleState()\r
2428  *\r
2429  * Called if the status is eESTABLISHED.  Data reception has been handled\r
2430  * earlier.  Here the ACK's from peer will be checked, and if a FIN is received,\r
2431  * the code will check if it may be accepted, i.e. if all expected data has been\r
2432  * completely received.\r
2433  */\r
2434 static BaseType_t prvHandleEstablished( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer,\r
2435         uint32_t ulReceiveLength, UBaseType_t uxOptionsLength )\r
2436 {\r
2437 TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( (*ppxNetworkBuffer)->pucEthernetBuffer );\r
2438 TCPHeader_t *pxTCPHeader = &pxTCPPacket->xTCPHeader;\r
2439 TCPWindow_t *pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow;\r
2440 uint8_t ucTCPFlags = pxTCPHeader->ucTCPFlags;\r
2441 uint32_t ulSequenceNumber = FreeRTOS_ntohl( pxTCPHeader->ulSequenceNumber ), ulCount;\r
2442 BaseType_t xSendLength = 0, xMayClose = pdFALSE, bRxComplete, bTxDone;\r
2443 int32_t lDistance, lSendResult;\r
2444 \r
2445         /* Remember the window size the peer is advertising. */\r
2446         pxSocket->u.xTCP.ulWindowSize = FreeRTOS_ntohs( pxTCPHeader->usWindow );\r
2447         #if( ipconfigUSE_TCP_WIN != 0 )\r
2448         {\r
2449                 pxSocket->u.xTCP.ulWindowSize =\r
2450                         ( pxSocket->u.xTCP.ulWindowSize << pxSocket->u.xTCP.ucPeerWinScaleFactor );\r
2451         }\r
2452         #endif\r
2453 \r
2454         if( ( ucTCPFlags & ( uint8_t ) ipTCP_FLAG_ACK ) != 0u )\r
2455         {\r
2456                 ulCount = ulTCPWindowTxAck( pxTCPWindow, FreeRTOS_ntohl( pxTCPPacket->xTCPHeader.ulAckNr ) );\r
2457 \r
2458                 /* ulTCPWindowTxAck() returns the number of bytes which have been acked,\r
2459                 starting at 'tx.ulCurrentSequenceNumber'.  Advance the tail pointer in\r
2460                 txStream. */\r
2461                 if( ( pxSocket->u.xTCP.txStream != NULL ) && ( ulCount > 0u ) )\r
2462                 {\r
2463                         /* Just advancing the tail index, 'ulCount' bytes have been\r
2464                         confirmed, and because there is new space in the txStream, the\r
2465                         user/owner should be woken up. */\r
2466                         /* _HT_ : only in case the socket's waiting? */\r
2467                         if( uxStreamBufferGet( pxSocket->u.xTCP.txStream, 0u, NULL, ( size_t ) ulCount, pdFALSE ) != 0u )\r
2468                         {\r
2469                                 pxSocket->xEventBits |= eSOCKET_SEND;\r
2470 \r
2471                                 #if ipconfigSUPPORT_SELECT_FUNCTION == 1\r
2472                                 {\r
2473                                         if( ( pxSocket->xSelectBits & eSELECT_WRITE ) != 0 )\r
2474                                         {\r
2475                                                 pxSocket->xEventBits |= ( eSELECT_WRITE << SOCKET_EVENT_BIT_COUNT );\r
2476                                         }\r
2477                                 }\r
2478                                 #endif\r
2479                                 /* In case the socket owner has installed an OnSent handler,\r
2480                                 call it now. */\r
2481                                 #if( ipconfigUSE_CALLBACKS == 1 )\r
2482                                 {\r
2483                                         if( ipconfigIS_VALID_PROG_ADDRESS( pxSocket->u.xTCP.pxHandleSent ) )\r
2484                                         {\r
2485                                                 pxSocket->u.xTCP.pxHandleSent( (Socket_t *)pxSocket, ulCount );\r
2486                                         }\r
2487                                 }\r
2488                                 #endif /* ipconfigUSE_CALLBACKS == 1  */\r
2489                         }\r
2490                 }\r
2491         }\r
2492 \r
2493         /* If this socket has a stream for transmission, add the data to the\r
2494         outgoing segment(s). */\r
2495         if( pxSocket->u.xTCP.txStream != NULL )\r
2496         {\r
2497                 prvTCPAddTxData( pxSocket );\r
2498         }\r
2499 \r
2500         pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber = pxTCPWindow->tx.ulCurrentSequenceNumber;\r
2501 \r
2502         if( ( pxSocket->u.xTCP.bits.bFinAccepted != pdFALSE_UNSIGNED ) || ( ( ucTCPFlags & ( uint8_t ) ipTCP_FLAG_FIN ) != 0u ) )\r
2503         {\r
2504                 /* Peer is requesting to stop, see if we're really finished. */\r
2505                 xMayClose = pdTRUE;\r
2506 \r
2507                 /* Checks are only necessary if we haven't sent a FIN yet. */\r
2508                 if( pxSocket->u.xTCP.bits.bFinSent == pdFALSE_UNSIGNED )\r
2509                 {\r
2510                         /* xTCPWindowTxDone returns true when all Tx queues are empty. */\r
2511                         bRxComplete = xTCPWindowRxEmpty( pxTCPWindow );\r
2512                         bTxDone     = xTCPWindowTxDone( pxTCPWindow );\r
2513 \r
2514                         if( ( bRxComplete == 0 ) || ( bTxDone == 0 ) )\r
2515                         {\r
2516                                 /* Refusing FIN: Rx incomp 1 optlen 4 tx done 1. */\r
2517                                 FreeRTOS_debug_printf( ( "Refusing FIN[%u,%u]: RxCompl %lu tx done %ld\n",\r
2518                                         pxSocket->usLocalPort,\r
2519                                         pxSocket->u.xTCP.usRemotePort,\r
2520                                         bRxComplete, bTxDone ) );\r
2521                                 xMayClose = pdFALSE;\r
2522                         }\r
2523                         else\r
2524                         {\r
2525                                 lDistance = ( int32_t ) ( ulSequenceNumber + ulReceiveLength - pxTCPWindow->rx.ulCurrentSequenceNumber );\r
2526 \r
2527                                 if( lDistance > 1 )\r
2528                                 {\r
2529                                         FreeRTOS_debug_printf( ( "Refusing FIN: Rx not complete %ld (cur %lu high %lu)\n",\r
2530                                                 lDistance, pxTCPWindow->rx.ulCurrentSequenceNumber - pxTCPWindow->rx.ulFirstSequenceNumber,\r
2531                                                 pxTCPWindow->rx.ulHighestSequenceNumber - pxTCPWindow->rx.ulFirstSequenceNumber ) );\r
2532 \r
2533                                         xMayClose = pdFALSE;\r
2534                                 }\r
2535                         }\r
2536                 }\r
2537 \r
2538                 if( xTCPWindowLoggingLevel > 0 )\r
2539                 {\r
2540                         FreeRTOS_debug_printf( ( "TCP: FIN received, mayClose = %ld (Rx %lu Len %ld, Tx %lu)\n",\r
2541                                 xMayClose, ulSequenceNumber - pxSocket->u.xTCP.xTCPWindow.rx.ulFirstSequenceNumber, ulReceiveLength,\r
2542                                 pxTCPWindow->tx.ulCurrentSequenceNumber - pxSocket->u.xTCP.xTCPWindow.tx.ulFirstSequenceNumber ) );\r
2543                 }\r
2544 \r
2545                 if( xMayClose != pdFALSE )\r
2546                 {\r
2547                         pxSocket->u.xTCP.bits.bFinAccepted = pdTRUE_UNSIGNED;\r
2548                         xSendLength = prvTCPHandleFin( pxSocket, *ppxNetworkBuffer );\r
2549                 }\r
2550         }\r
2551 \r
2552         if( xMayClose == pdFALSE )\r
2553         {\r
2554                 pxTCPHeader->ucTCPFlags = ipTCP_FLAG_ACK;\r
2555 \r
2556                 if( ulReceiveLength != 0u )\r
2557                 {\r
2558                         xSendLength = ( BaseType_t ) ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength );\r
2559                         /* TCP-offsett equals '( ( length / 4 ) << 4 )', resulting in a shift-left 2 */\r
2560                         pxTCPHeader->ucTCPOffset = ( uint8_t )( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 );\r
2561 \r
2562                         if( pxSocket->u.xTCP.bits.bFinSent != pdFALSE_UNSIGNED )\r
2563                         {\r
2564                                 pxTCPWindow->tx.ulCurrentSequenceNumber = pxTCPWindow->tx.ulFINSequenceNumber;\r
2565                         }\r
2566                 }\r
2567 \r
2568                 /* Now get data to be transmitted. */\r
2569                 /* _HT_ patch: since the MTU has be fixed at 1500 in stead of 1526, TCP\r
2570                 can not send-out both TCP options and also a full packet. Sending\r
2571                 options (SACK) is always more urgent than sending data, which can be\r
2572                 sent later. */\r
2573                 if( uxOptionsLength == 0u )\r
2574                 {\r
2575                         /* prvTCPPrepareSend might allocate a bigger network buffer, if\r
2576                         necessary. */\r
2577                         lSendResult = prvTCPPrepareSend( pxSocket, ppxNetworkBuffer, uxOptionsLength );\r
2578                         if( lSendResult > 0 )\r
2579                         {\r
2580                                 xSendLength = ( BaseType_t ) lSendResult;\r
2581                         }\r
2582                 }\r
2583         }\r
2584 \r
2585         return xSendLength;\r
2586 }\r
2587 /*-----------------------------------------------------------*/\r
2588 \r
2589 /*\r
2590  * Called from prvTCPHandleState().  There is data to be sent.  If\r
2591  * ipconfigUSE_TCP_WIN is defined, and if only an ACK must be sent, it will be\r
2592  * checked if it would better be postponed for efficiency.\r
2593  */\r
2594 static BaseType_t prvSendData( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer,\r
2595         uint32_t ulReceiveLength, BaseType_t xSendLength )\r
2596 {\r
2597 TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( (*ppxNetworkBuffer)->pucEthernetBuffer );\r
2598 TCPHeader_t *pxTCPHeader = &pxTCPPacket->xTCPHeader;\r
2599 TCPWindow_t *pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow;\r
2600 /* Find out what window size we may advertised. */\r
2601 uint32_t ulFrontSpace;\r
2602 int32_t lRxSpace;\r
2603 #if( ipconfigUSE_TCP_WIN == 1 )\r
2604         #if( ipconfigTCP_ACK_EARLIER_PACKET == 0 )\r
2605                 const int32_t lMinLength = 0;\r
2606         #else\r
2607                 int32_t lMinLength;\r
2608         #endif\r
2609 #endif\r
2610         pxSocket->u.xTCP.ulRxCurWinSize = pxTCPWindow->xSize.ulRxWindowLength -\r
2611                                                                          ( pxTCPWindow->rx.ulHighestSequenceNumber - pxTCPWindow->rx.ulCurrentSequenceNumber );\r
2612 \r
2613         /* Free space in rxStream. */\r
2614         if( pxSocket->u.xTCP.rxStream != NULL )\r
2615         {\r
2616                 ulFrontSpace = ( uint32_t ) uxStreamBufferFrontSpace( pxSocket->u.xTCP.rxStream );\r
2617         }\r
2618         else\r
2619         {\r
2620                 ulFrontSpace = ( uint32_t ) pxSocket->u.xTCP.uxRxStreamSize;\r
2621         }\r
2622 \r
2623         pxSocket->u.xTCP.ulRxCurWinSize = FreeRTOS_min_uint32( ulFrontSpace, pxSocket->u.xTCP.ulRxCurWinSize );\r
2624 \r
2625         /* Set the time-out field, so that we'll be called by the IP-task in case no\r
2626         next message will be received. */\r
2627         lRxSpace = (int32_t)( pxSocket->u.xTCP.ulHighestRxAllowed - pxTCPWindow->rx.ulCurrentSequenceNumber );\r
2628         #if ipconfigUSE_TCP_WIN == 1\r
2629         {\r
2630 \r
2631                 #if( ipconfigTCP_ACK_EARLIER_PACKET != 0 )\r
2632                 {\r
2633                         lMinLength = ( ( int32_t ) 2 ) * ( ( int32_t ) pxSocket->u.xTCP.usCurMSS );\r
2634                 }\r
2635                 #endif /* ipconfigTCP_ACK_EARLIER_PACKET */\r
2636 \r
2637                 /* In case we're receiving data continuously, we might postpone sending\r
2638                 an ACK to gain performance. */\r
2639                 if( ( ulReceiveLength > 0 ) &&                                                  /* Data was sent to this socket. */\r
2640                         ( lRxSpace >= lMinLength ) &&                                           /* There is Rx space for more data. */\r
2641                         ( pxSocket->u.xTCP.bits.bFinSent == pdFALSE_UNSIGNED ) &&       /* Not in a closure phase. */\r
2642                         ( xSendLength == ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER ) ) && /* No Tx data or options to be sent. */\r
2643                         ( pxSocket->u.xTCP.ucTCPState == eESTABLISHED ) &&      /* Connection established. */\r
2644                         ( pxTCPHeader->ucTCPFlags == ipTCP_FLAG_ACK ) )         /* There are no other flags than an ACK. */\r
2645                 {\r
2646                         if( pxSocket->u.xTCP.pxAckMessage != *ppxNetworkBuffer )\r
2647                         {\r
2648                                 /* There was still a delayed in queue, delete it. */\r
2649                                 if( pxSocket->u.xTCP.pxAckMessage != 0 )\r
2650                                 {\r
2651                                         vReleaseNetworkBufferAndDescriptor( pxSocket->u.xTCP.pxAckMessage );\r
2652                                 }\r
2653 \r
2654                                 pxSocket->u.xTCP.pxAckMessage = *ppxNetworkBuffer;\r
2655                         }\r
2656                         if( ( ulReceiveLength < ( uint32_t ) pxSocket->u.xTCP.usCurMSS ) ||     /* Received a small message. */\r
2657                                 ( lRxSpace < ( int32_t ) ( 2U * pxSocket->u.xTCP.usCurMSS ) ) ) /* There are less than 2 x MSS space in the Rx buffer. */\r
2658                         {\r
2659                                 pxSocket->u.xTCP.usTimeout = ( uint16_t ) pdMS_TO_MIN_TICKS( DELAYED_ACK_SHORT_DELAY_MS );\r
2660                         }\r
2661                         else\r
2662                         {\r
2663                                 /* Normally a delayed ACK should wait 200 ms for a next incoming\r
2664                                 packet.  Only wait 20 ms here to gain performance.  A slow ACK\r
2665                                 for full-size message. */\r
2666                                 pxSocket->u.xTCP.usTimeout = ( uint16_t ) pdMS_TO_MIN_TICKS( DELAYED_ACK_LONGER_DELAY_MS );\r
2667                         }\r
2668 \r
2669                         if( ( xTCPWindowLoggingLevel > 1 ) && ( ipconfigTCP_MAY_LOG_PORT( pxSocket->usLocalPort ) != pdFALSE ) )\r
2670                         {\r
2671                                 FreeRTOS_debug_printf( ( "Send[%u->%u] del ACK %lu SEQ %lu (len %lu) tmout %u d %lu\n",\r
2672                                         pxSocket->usLocalPort,\r
2673                                         pxSocket->u.xTCP.usRemotePort,\r
2674                                         pxTCPWindow->rx.ulCurrentSequenceNumber - pxTCPWindow->rx.ulFirstSequenceNumber,\r
2675                                         pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber - pxTCPWindow->tx.ulFirstSequenceNumber,\r
2676                                         xSendLength,\r
2677                                         pxSocket->u.xTCP.usTimeout, lRxSpace ) );\r
2678                         }\r
2679 \r
2680                         *ppxNetworkBuffer = NULL;\r
2681                         xSendLength = 0;\r
2682                 }\r
2683                 else if( pxSocket->u.xTCP.pxAckMessage != NULL )\r
2684                 {\r
2685                         /* As an ACK is not being delayed, remove any earlier delayed ACK\r
2686                         message. */\r
2687                         if( pxSocket->u.xTCP.pxAckMessage != *ppxNetworkBuffer )\r
2688                         {\r
2689                                 vReleaseNetworkBufferAndDescriptor( pxSocket->u.xTCP.pxAckMessage );\r
2690                         }\r
2691 \r
2692                         pxSocket->u.xTCP.pxAckMessage = NULL;\r
2693                 }\r
2694         }\r
2695         #else\r
2696         {\r
2697                 /* Remove compiler warnings. */\r
2698                 ( void ) ulReceiveLength;\r
2699                 ( void ) pxTCPHeader;\r
2700                 ( void ) lRxSpace;\r
2701         }\r
2702         #endif /* ipconfigUSE_TCP_WIN */\r
2703 \r
2704         if( xSendLength != 0 )\r
2705         {\r
2706                 if( ( xTCPWindowLoggingLevel > 1 ) && ( ipconfigTCP_MAY_LOG_PORT( pxSocket->usLocalPort ) != pdFALSE ) )\r
2707                 {\r
2708                         FreeRTOS_debug_printf( ( "Send[%u->%u] imm ACK %lu SEQ %lu (len %lu)\n",\r
2709                                 pxSocket->usLocalPort,\r
2710                                 pxSocket->u.xTCP.usRemotePort,\r
2711                                 pxTCPWindow->rx.ulCurrentSequenceNumber - pxTCPWindow->rx.ulFirstSequenceNumber,\r
2712                                 pxTCPWindow->ulOurSequenceNumber - pxTCPWindow->tx.ulFirstSequenceNumber,\r
2713                                 xSendLength ) );\r
2714                 }\r
2715 \r
2716                 /* Set the parameter 'xReleaseAfterSend' to the value of\r
2717                 ipconfigZERO_COPY_TX_DRIVER. */\r
2718                 prvTCPReturnPacket( pxSocket, *ppxNetworkBuffer, ( uint32_t ) xSendLength, ipconfigZERO_COPY_TX_DRIVER );\r
2719                 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )\r
2720                 {\r
2721                         /* The driver has taken ownership of the Network Buffer. */\r
2722                         *ppxNetworkBuffer = NULL;\r
2723                 }\r
2724                 #endif\r
2725         }\r
2726 \r
2727         return xSendLength;\r
2728 }\r
2729 /*-----------------------------------------------------------*/\r
2730 \r
2731 /*\r
2732  * prvTCPHandleState()\r
2733  * is the most important function of this TCP stack\r
2734  * We've tried to keep it (relatively short) by putting a lot of code in\r
2735  * the static functions above:\r
2736  *\r
2737  *              prvCheckRxData()\r
2738  *              prvStoreRxData()\r
2739  *              prvSetOptions()\r
2740  *              prvHandleSynReceived()\r
2741  *              prvHandleEstablished()\r
2742  *              prvSendData()\r
2743  *\r
2744  * As these functions are declared static, and they're called from one location\r
2745  * only, most compilers will inline them, thus avoiding a call and return.\r
2746  */\r
2747 static BaseType_t prvTCPHandleState( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer )\r
2748 {\r
2749 TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( (*ppxNetworkBuffer)->pucEthernetBuffer );\r
2750 TCPHeader_t *pxTCPHeader = &( pxTCPPacket->xTCPHeader );\r
2751 BaseType_t xSendLength = 0;\r
2752 uint32_t ulReceiveLength;       /* Number of bytes contained in the TCP message. */\r
2753 uint8_t *pucRecvData;\r
2754 uint32_t ulSequenceNumber = FreeRTOS_ntohl (pxTCPHeader->ulSequenceNumber);\r
2755 \r
2756         /* uxOptionsLength: the size of the options to be sent (always a multiple of\r
2757         4 bytes)\r
2758         1. in the SYN phase, we shall communicate the MSS\r
2759         2. in case of a SACK, Selective ACK, ack a segment which comes in\r
2760         out-of-order. */\r
2761 UBaseType_t uxOptionsLength = 0u;\r
2762 uint8_t ucTCPFlags = pxTCPHeader->ucTCPFlags;\r
2763 TCPWindow_t *pxTCPWindow = &( pxSocket->u.xTCP.xTCPWindow );\r
2764 \r
2765         /* First get the length and the position of the received data, if any.\r
2766         pucRecvData will point to the first byte of the TCP payload. */\r
2767         ulReceiveLength = ( uint32_t ) prvCheckRxData( *ppxNetworkBuffer, &pucRecvData );\r
2768 \r
2769         if( pxSocket->u.xTCP.ucTCPState >= eESTABLISHED )\r
2770         {\r
2771                 if ( pxTCPWindow->rx.ulCurrentSequenceNumber == ulSequenceNumber + 1u )\r
2772                 {\r
2773                         /* This is most probably a keep-alive message from peer.  Setting\r
2774                         'bWinChange' doesn't cause a window-size-change, the flag is used\r
2775                         here to force sending an immediate ACK. */\r
2776                         pxSocket->u.xTCP.bits.bWinChange = pdTRUE_UNSIGNED;\r
2777                 }\r
2778         }\r
2779 \r
2780         /* Keep track of the highest sequence number that might be expected within\r
2781         this connection. */\r
2782         if( ( ( int32_t ) ( ulSequenceNumber + ulReceiveLength - pxTCPWindow->rx.ulHighestSequenceNumber ) ) > 0 )\r
2783         {\r
2784                 pxTCPWindow->rx.ulHighestSequenceNumber = ulSequenceNumber + ulReceiveLength;\r
2785         }\r
2786 \r
2787         /* Storing data may result in a fatal error if malloc() fails. */\r
2788         if( prvStoreRxData( pxSocket, pucRecvData, *ppxNetworkBuffer, ulReceiveLength ) < 0 )\r
2789         {\r
2790                 xSendLength = -1;\r
2791         }\r
2792         else\r
2793         {\r
2794                 uxOptionsLength = prvSetOptions( pxSocket, *ppxNetworkBuffer );\r
2795 \r
2796                 if( ( pxSocket->u.xTCP.ucTCPState == eSYN_RECEIVED ) && ( ( ucTCPFlags & ipTCP_FLAG_CTRL ) == ipTCP_FLAG_SYN ) )\r
2797                 {\r
2798                         FreeRTOS_debug_printf( ( "eSYN_RECEIVED: ACK expected, not SYN: peer missed our SYN+ACK\n" ) );\r
2799 \r
2800                         /* In eSYN_RECEIVED a simple ACK is expected, but apparently the\r
2801                         'SYN+ACK' didn't arrive.  Step back to the previous state in which\r
2802                         a first incoming SYN is handled.  The SYN was counted already so\r
2803                         decrease it first. */\r
2804                         vTCPStateChange( pxSocket, eSYN_FIRST );\r
2805                 }\r
2806 \r
2807                 if( ( ( ucTCPFlags & ipTCP_FLAG_FIN ) != 0u ) && ( pxSocket->u.xTCP.bits.bFinRecv == pdFALSE_UNSIGNED ) )\r
2808                 {\r
2809                         /* It's the first time a FIN has been received, remember its\r
2810                         sequence number. */\r
2811                         pxTCPWindow->rx.ulFINSequenceNumber = ulSequenceNumber + ulReceiveLength;\r
2812                         pxSocket->u.xTCP.bits.bFinRecv = pdTRUE_UNSIGNED;\r
2813 \r
2814                         /* Was peer the first one to send a FIN? */\r
2815                         if( pxSocket->u.xTCP.bits.bFinSent == pdFALSE_UNSIGNED )\r
2816                         {\r
2817                                 /* If so, don't send the-last-ACK. */\r
2818                                 pxSocket->u.xTCP.bits.bFinLast = pdTRUE_UNSIGNED;\r
2819                         }\r
2820                 }\r
2821 \r
2822                 switch (pxSocket->u.xTCP.ucTCPState)\r
2823                 {\r
2824                 case eCLOSED:           /* (server + client) no connection state at all. */\r
2825                         /* Nothing to do for a closed socket, except waiting for the\r
2826                         owner. */\r
2827                         break;\r
2828 \r
2829                 case eTCP_LISTEN:       /* (server) waiting for a connection request from\r
2830                                                         any remote TCP and port. */\r
2831                         /* The listen state was handled in xProcessReceivedTCPPacket().\r
2832                         Should not come here. */\r
2833                         break;\r
2834 \r
2835                 case eSYN_FIRST:        /* (server) Just received a SYN request for a server\r
2836                                                         socket. */\r
2837                         {\r
2838                                 /* A new socket has been created, reply with a SYN+ACK.\r
2839                                 Acknowledge with seq+1 because the SYN is seen as pseudo data\r
2840                                 with len = 1. */\r
2841                                 uxOptionsLength = prvSetSynAckOptions( pxSocket, pxTCPPacket );\r
2842                                 pxTCPHeader->ucTCPFlags = ipTCP_FLAG_SYN | ipTCP_FLAG_ACK;\r
2843 \r
2844                                 xSendLength = ( BaseType_t ) ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength );\r
2845 \r
2846                                 /* Set the TCP offset field:  ipSIZE_OF_TCP_HEADER equals 20 and\r
2847                                 uxOptionsLength is a multiple of 4.  The complete expression is:\r
2848                                 ucTCPOffset = ( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) / 4 ) << 4 */\r
2849                                 pxTCPHeader->ucTCPOffset = ( uint8_t )( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 );\r
2850                                 vTCPStateChange( pxSocket, eSYN_RECEIVED );\r
2851 \r
2852                                 pxTCPWindow->rx.ulCurrentSequenceNumber = pxTCPWindow->rx.ulHighestSequenceNumber = ulSequenceNumber + 1u;\r
2853                                 pxTCPWindow->tx.ulCurrentSequenceNumber = pxTCPWindow->ulNextTxSequenceNumber = pxTCPWindow->tx.ulFirstSequenceNumber + 1u; /* because we send a TCP_SYN. */\r
2854                         }\r
2855                         break;\r
2856 \r
2857                 case eCONNECT_SYN:      /* (client) also called SYN_SENT: we've just send a\r
2858                                                         SYN, expect     a SYN+ACK and send a ACK now. */\r
2859                         /* Fall through */\r
2860                 case eSYN_RECEIVED:     /* (server) we've had a SYN, replied with SYN+SCK\r
2861                                                         expect a ACK and do nothing. */\r
2862                         xSendLength = prvHandleSynReceived( pxSocket, ppxNetworkBuffer, ulReceiveLength, uxOptionsLength );\r
2863                         break;\r
2864 \r
2865                 case eESTABLISHED:      /* (server + client) an open connection, data\r
2866                                                         received can be delivered to the user. The normal\r
2867                                                         state for the data transfer phase of the connection\r
2868                                                         The closing states are also handled here with the\r
2869                                                         use of some flags. */\r
2870                         xSendLength = prvHandleEstablished( pxSocket, ppxNetworkBuffer, ulReceiveLength, uxOptionsLength );\r
2871                         break;\r
2872 \r
2873                 case eLAST_ACK:         /* (server + client) waiting for an acknowledgement\r
2874                                                         of the connection termination request previously\r
2875                                                         sent to the remote TCP (which includes an\r
2876                                                         acknowledgement of its connection termination\r
2877                                                         request). */\r
2878                         /* Fall through */\r
2879                 case eFIN_WAIT_1:       /* (server + client) waiting for a connection termination request from the remote TCP,\r
2880                                                          * or an acknowledgement of the connection termination request previously sent. */\r
2881                         /* Fall through */\r
2882                 case eFIN_WAIT_2:       /* (server + client) waiting for a connection termination request from the remote TCP. */\r
2883                         xSendLength = prvTCPHandleFin( pxSocket, *ppxNetworkBuffer );\r
2884                         break;\r
2885 \r
2886                 case eCLOSE_WAIT:       /* (server + client) waiting for a connection\r
2887                                                         termination request from the local user.  Nothing to\r
2888                                                         do, connection is closed, wait for owner to close\r
2889                                                         this socket. */\r
2890                         break;\r
2891 \r
2892                 case eCLOSING:          /* (server + client) waiting for a connection\r
2893                                                         termination request acknowledgement from the remote\r
2894                                                         TCP. */\r
2895                         break;\r
2896 \r
2897                 case eTIME_WAIT:        /* (either server or client) waiting for enough time\r
2898                                                         to pass to be sure the remote TCP received the\r
2899                                                         acknowledgement of its connection termination\r
2900                                                         request. [According to RFC 793 a connection can stay\r
2901                                                         in TIME-WAIT for a maximum of four minutes known as\r
2902                                                         a MSL (maximum segment lifetime).]  These states are\r
2903                                                         implemented implicitly by settings flags like\r
2904                                                         'bFinSent', 'bFinRecv', and 'bFinAcked'. */\r
2905                         break;\r
2906                 default:\r
2907                         break;\r
2908                 }\r
2909         }\r
2910 \r
2911         if( xSendLength > 0 )\r
2912         {\r
2913                 xSendLength = prvSendData( pxSocket, ppxNetworkBuffer, ulReceiveLength, xSendLength );\r
2914         }\r
2915 \r
2916         return xSendLength;\r
2917 }\r
2918 /*-----------------------------------------------------------*/\r
2919 \r
2920 static BaseType_t prvTCPSendReset( NetworkBufferDescriptor_t *pxNetworkBuffer )\r
2921 {\r
2922         #if( ipconfigIGNORE_UNKNOWN_PACKETS == 0 )\r
2923         {\r
2924         TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );\r
2925         const BaseType_t xSendLength = ( BaseType_t ) ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + 0u );    /* Plus 0 options. */\r
2926 \r
2927                 pxTCPPacket->xTCPHeader.ucTCPFlags = ipTCP_FLAG_ACK | ipTCP_FLAG_RST;\r
2928                 pxTCPPacket->xTCPHeader.ucTCPOffset = ( ipSIZE_OF_TCP_HEADER + 0u ) << 2;\r
2929 \r
2930                 prvTCPReturnPacket( NULL, pxNetworkBuffer, ( uint32_t ) xSendLength, pdFALSE );\r
2931         }\r
2932         #endif /* !ipconfigIGNORE_UNKNOWN_PACKETS */\r
2933 \r
2934         /* Remove compiler warnings if ipconfigIGNORE_UNKNOWN_PACKETS == 1. */\r
2935         ( void ) pxNetworkBuffer;\r
2936 \r
2937         /* The packet was not consumed. */\r
2938         return pdFAIL;\r
2939 }\r
2940 /*-----------------------------------------------------------*/\r
2941 \r
2942 static void prvSocketSetMSS( FreeRTOS_Socket_t *pxSocket )\r
2943 {\r
2944 uint32_t ulMSS = ipconfigTCP_MSS;\r
2945 \r
2946         if( ( ( FreeRTOS_ntohl( pxSocket->u.xTCP.ulRemoteIP ) ^ *ipLOCAL_IP_ADDRESS_POINTER ) & xNetworkAddressing.ulNetMask ) != 0ul )\r
2947         {\r
2948                 /* Data for this peer will pass through a router, and maybe through\r
2949                 the internet.  Limit the MSS to 1400 bytes or less. */\r
2950                 ulMSS = FreeRTOS_min_uint32( ( uint32_t ) REDUCED_MSS_THROUGH_INTERNET, ulMSS );\r
2951         }\r
2952 \r
2953         FreeRTOS_debug_printf( ( "prvSocketSetMSS: %lu bytes for %lxip:%u\n", ulMSS, pxSocket->u.xTCP.ulRemoteIP, pxSocket->u.xTCP.usRemotePort ) );\r
2954 \r
2955         pxSocket->u.xTCP.usInitMSS = pxSocket->u.xTCP.usCurMSS = ( uint16_t ) ulMSS;\r
2956 }\r
2957 /*-----------------------------------------------------------*/\r
2958 \r
2959 /*\r
2960  *      FreeRTOS_TCP_IP has only 2 public functions, this is the second one:\r
2961  *      xProcessReceivedTCPPacket()\r
2962  *              prvTCPHandleState()\r
2963  *                      prvTCPPrepareSend()\r
2964  *                              prvTCPReturnPacket()\r
2965  *                              xNetworkInterfaceOutput()       // Sends data to the NIC\r
2966  *              prvTCPSendRepeated()\r
2967  *                      prvTCPReturnPacket()            // Prepare for returning\r
2968  *                      xNetworkInterfaceOutput()       // Sends data to the NIC\r
2969 */\r
2970 BaseType_t xProcessReceivedTCPPacket( NetworkBufferDescriptor_t *pxNetworkBuffer )\r
2971 {\r
2972 FreeRTOS_Socket_t *pxSocket;\r
2973 TCPPacket_t * pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );\r
2974 uint16_t ucTCPFlags = pxTCPPacket->xTCPHeader.ucTCPFlags;\r
2975 uint32_t ulLocalIP = FreeRTOS_htonl( pxTCPPacket->xIPHeader.ulDestinationIPAddress );\r
2976 uint16_t xLocalPort = FreeRTOS_htons( pxTCPPacket->xTCPHeader.usDestinationPort );\r
2977 uint32_t ulRemoteIP = FreeRTOS_htonl( pxTCPPacket->xIPHeader.ulSourceIPAddress );\r
2978 uint16_t xRemotePort = FreeRTOS_htons( pxTCPPacket->xTCPHeader.usSourcePort );\r
2979 BaseType_t xResult = pdPASS;\r
2980 \r
2981         /* Find the destination socket, and if not found: return a socket listing to\r
2982         the destination PORT. */\r
2983         pxSocket = ( FreeRTOS_Socket_t * ) pxTCPSocketLookup( ulLocalIP, xLocalPort, ulRemoteIP, xRemotePort );\r
2984 \r
2985         if( ( pxSocket == NULL ) || ( prvTCPSocketIsActive( ( UBaseType_t ) pxSocket->u.xTCP.ucTCPState ) == pdFALSE ) )\r
2986         {\r
2987                 /* A TCP messages is received but either there is no socket with the\r
2988                 given port number or the there is a socket, but it is in one of these\r
2989                 non-active states:  eCLOSED, eCLOSE_WAIT, eFIN_WAIT_2, eCLOSING, or\r
2990                 eTIME_WAIT. */\r
2991 \r
2992                 FreeRTOS_debug_printf( ( "TCP: No active socket on port %d (%lxip:%d)\n", xLocalPort, ulRemoteIP, xRemotePort ) );\r
2993 \r
2994                 /* Send a RST to all packets that can not be handled.  As a result\r
2995                 the other party will get a ECONN error.  There are two exceptions:\r
2996                 1) A packet that already has the RST flag set.\r
2997                 2) A packet that only has the ACK flag set.\r
2998                 A packet with only the ACK flag set might be the last ACK in\r
2999                 a three-way hand-shake that closes a connection. */\r
3000                 if( ( ( ucTCPFlags & ipTCP_FLAG_CTRL ) != ipTCP_FLAG_ACK ) &&\r
3001                         ( ( ucTCPFlags & ipTCP_FLAG_RST ) == 0u ) )\r
3002                 {\r
3003                         prvTCPSendReset( pxNetworkBuffer );\r
3004                 }\r
3005 \r
3006                 /* The packet can't be handled. */\r
3007                 xResult = pdFAIL;\r
3008         }\r
3009         else\r
3010         {\r
3011                 pxSocket->u.xTCP.ucRepCount = 0u;\r
3012 \r
3013                 if( pxSocket->u.xTCP.ucTCPState == eTCP_LISTEN )\r
3014                 {\r
3015                         /* The matching socket is in a listening state.  Test if the peer\r
3016                         has set the SYN flag. */\r
3017                         if( ( ucTCPFlags & ipTCP_FLAG_CTRL ) != ipTCP_FLAG_SYN )\r
3018                         {\r
3019                                 /* What happens: maybe after a reboot, a client doesn't know the\r
3020                                 connection had gone.  Send a RST in order to get a new connect\r
3021                                 request. */\r
3022                                 #if( ipconfigHAS_DEBUG_PRINTF == 1 )\r
3023                                 {\r
3024                                 FreeRTOS_debug_printf( ( "TCP: Server can't handle flags: %s from %lxip:%u to port %u\n",\r
3025                                         prvTCPFlagMeaning( ( UBaseType_t ) ucTCPFlags ), ulRemoteIP, xRemotePort, xLocalPort ) );\r
3026                                 }\r
3027                                 #endif /* ipconfigHAS_DEBUG_PRINTF */\r
3028 \r
3029                                 if( ( ucTCPFlags & ipTCP_FLAG_RST ) == 0u )\r
3030                                 {\r
3031                                         prvTCPSendReset( pxNetworkBuffer );\r
3032                                 }\r
3033                                 xResult = pdFAIL;\r
3034                         }\r
3035                         else\r
3036                         {\r
3037                                 /* prvHandleListen() will either return a newly created socket\r
3038                                 (if bReuseSocket is false), otherwise it returns the current\r
3039                                 socket which will later get connected. */\r
3040                                 pxSocket = prvHandleListen( pxSocket, pxNetworkBuffer );\r
3041 \r
3042                                 if( pxSocket == NULL )\r
3043                                 {\r
3044                                         xResult = pdFAIL;\r
3045                                 }\r
3046                         }\r
3047                 }       /* if( pxSocket->u.xTCP.ucTCPState == eTCP_LISTEN ). */\r
3048                 else\r
3049                 {\r
3050                         /* This is not a socket in listening mode. Check for the RST\r
3051                         flag. */\r
3052                         if( ( ucTCPFlags & ipTCP_FLAG_RST ) != 0u )\r
3053                         {\r
3054                                 /* The target socket is not in a listening state, any RST packet\r
3055                                 will cause the socket to be closed. */\r
3056                                 FreeRTOS_debug_printf( ( "TCP: RST received from %lxip:%u for %u\n", ulRemoteIP, xRemotePort, xLocalPort ) );\r
3057                                 /* _HT_: should indicate that 'ECONNRESET' must be returned to the used during next API. */\r
3058                                 vTCPStateChange( pxSocket, eCLOSED );\r
3059 \r
3060                                 /* The packet cannot be handled. */\r
3061                                 xResult = pdFAIL;\r
3062                         }\r
3063                         else if( ( ( ucTCPFlags & ipTCP_FLAG_CTRL ) == ipTCP_FLAG_SYN ) && ( pxSocket->u.xTCP.ucTCPState >= eESTABLISHED ) )\r
3064                         {\r
3065                                 /* SYN flag while this socket is already connected. */\r
3066                                 FreeRTOS_debug_printf( ( "TCP: SYN unexpected from %lxip:%u\n", ulRemoteIP, xRemotePort ) );\r
3067 \r
3068                                 /* The packet cannot be handled. */\r
3069                                 xResult = pdFAIL;\r
3070                         }\r
3071                         else\r
3072                         {\r
3073                                 /* Update the copy of the TCP header only (skipping eth and IP\r
3074                                 headers).  It might be used later on, whenever data must be sent\r
3075                                 to the peer. */\r
3076                                 const BaseType_t lOffset = ( BaseType_t ) ( ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv4_HEADER );\r
3077                                 memcpy( pxSocket->u.xTCP.xPacket.u.ucLastPacket + lOffset, pxNetworkBuffer->pucEthernetBuffer + lOffset, ipSIZE_OF_TCP_HEADER );\r
3078                         }\r
3079                 }\r
3080         }\r
3081 \r
3082         if( xResult != pdFAIL )\r
3083         {\r
3084                 /* Touch the alive timers because we received a message for this\r
3085                 socket. */\r
3086                 prvTCPTouchSocket( pxSocket );\r
3087 \r
3088                 /* Parse the TCP option(s), if present. */\r
3089                 /* _HT_ : if we're in the SYN phase, and peer does not send a MSS option,\r
3090                 then we MUST assume an MSS size of 536 bytes for backward compatibility. */\r
3091 \r
3092                 /* When there are no TCP options, the TCP offset equals 20 bytes, which is stored as\r
3093                 the number 5 (words) in the higher niblle of the TCP-offset byte. */\r
3094                 if( ( pxTCPPacket->xTCPHeader.ucTCPOffset & TCP_OFFSET_LENGTH_BITS ) > TCP_OFFSET_STANDARD_LENGTH )\r
3095                 {\r
3096                         prvCheckOptions( pxSocket, pxNetworkBuffer );\r
3097                 }\r
3098 \r
3099 \r
3100                 #if( ipconfigUSE_TCP_WIN == 1 )\r
3101                 {\r
3102                         pxSocket->u.xTCP.ulWindowSize = FreeRTOS_ntohs( pxTCPPacket->xTCPHeader.usWindow );\r
3103                         pxSocket->u.xTCP.ulWindowSize =\r
3104                                 ( pxSocket->u.xTCP.ulWindowSize << pxSocket->u.xTCP.ucPeerWinScaleFactor );\r
3105                 }\r
3106                 #endif\r
3107 \r
3108                 /* In prvTCPHandleState() the incoming messages will be handled\r
3109                 depending on the current state of the connection. */\r
3110                 if( prvTCPHandleState( pxSocket, &pxNetworkBuffer ) > 0 )\r
3111                 {\r
3112                         /* prvTCPHandleState() has sent a message, see if there are more to\r
3113                         be transmitted. */\r
3114                         #if( ipconfigUSE_TCP_WIN == 1 )\r
3115                         {\r
3116                                 prvTCPSendRepeated( pxSocket, &pxNetworkBuffer );\r
3117                         }\r
3118                         #endif /* ipconfigUSE_TCP_WIN */\r
3119                 }\r
3120 \r
3121                 if( pxNetworkBuffer != NULL )\r
3122                 {\r
3123                         /* We must check if the buffer is unequal to NULL, because the\r
3124                         socket might keep a reference to it in case a delayed ACK must be\r
3125                         sent. */\r
3126                         vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );\r
3127                         pxNetworkBuffer = NULL;\r
3128                 }\r
3129 \r
3130                 /* And finally, calculate when this socket wants to be woken up. */\r
3131                 prvTCPNextTimeout ( pxSocket );\r
3132                 /* Return pdPASS to tell that the network buffer is 'consumed'. */\r
3133                 xResult = pdPASS;\r
3134         }\r
3135 \r
3136         /* pdPASS being returned means the buffer has been consumed. */\r
3137         return xResult;\r
3138 }\r
3139 /*-----------------------------------------------------------*/\r
3140 \r
3141 static FreeRTOS_Socket_t *prvHandleListen( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer )\r
3142 {\r
3143 TCPPacket_t * pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );\r
3144 FreeRTOS_Socket_t *pxReturn;\r
3145 \r
3146         /* A pure SYN (without ACK) has come in, create a new socket to answer\r
3147         it. */\r
3148         if( pxSocket->u.xTCP.bits.bReuseSocket != pdFALSE_UNSIGNED )\r
3149         {\r
3150                 /* The flag bReuseSocket indicates that the same instance of the\r
3151                 listening socket should be used for the connection. */\r
3152                 pxReturn = pxSocket;\r
3153                 pxSocket->u.xTCP.bits.bPassQueued = pdTRUE_UNSIGNED;\r
3154                 pxSocket->u.xTCP.pxPeerSocket = pxSocket;\r
3155         }\r
3156         else\r
3157         {\r
3158                 /* The socket does not have the bReuseSocket flag set meaning create a\r
3159                 new socket when a connection comes in. */\r
3160                 pxReturn = NULL;\r
3161 \r
3162                 if( pxSocket->u.xTCP.usChildCount >= pxSocket->u.xTCP.usBacklog )\r
3163                 {\r
3164                         FreeRTOS_printf( ( "Check: Socket %u already has %u / %u child%s\n",\r
3165                                 pxSocket->usLocalPort,\r
3166                                 pxSocket->u.xTCP.usChildCount,\r
3167                                 pxSocket->u.xTCP.usBacklog,\r
3168                                 pxSocket->u.xTCP.usChildCount == 1 ? "" : "ren" ) );\r
3169                         prvTCPSendReset( pxNetworkBuffer );\r
3170                 }\r
3171                 else\r
3172                 {\r
3173                         FreeRTOS_Socket_t *pxNewSocket = (FreeRTOS_Socket_t *)\r
3174                                 FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_STREAM, FREERTOS_IPPROTO_TCP );\r
3175 \r
3176                         if( ( pxNewSocket == NULL ) || ( pxNewSocket == FREERTOS_INVALID_SOCKET ) )\r
3177                         {\r
3178                                 FreeRTOS_debug_printf( ( "TCP: Listen: new socket failed\n" ) );\r
3179                                 prvTCPSendReset( pxNetworkBuffer );\r
3180                         }\r
3181                         else if( prvTCPSocketCopy( pxNewSocket, pxSocket ) != pdFALSE )\r
3182                         {\r
3183                                 /* The socket will be connected immediately, no time for the\r
3184                                 owner to setsockopt's, therefore copy properties of the server\r
3185                                 socket to the new socket.  Only the binding might fail (due to\r
3186                                 lack of resources). */\r
3187                                 pxReturn = pxNewSocket;\r
3188                         }\r
3189                 }\r
3190         }\r
3191 \r
3192         if( pxReturn != NULL )\r
3193         {\r
3194                 pxReturn->u.xTCP.usRemotePort = FreeRTOS_htons( pxTCPPacket->xTCPHeader.usSourcePort );\r
3195                 pxReturn->u.xTCP.ulRemoteIP = FreeRTOS_htonl( pxTCPPacket->xIPHeader.ulSourceIPAddress );\r
3196                 pxReturn->u.xTCP.xTCPWindow.ulOurSequenceNumber = ulNextInitialSequenceNumber;\r
3197 \r
3198                 /* Here is the SYN action. */\r
3199                 pxReturn->u.xTCP.xTCPWindow.rx.ulCurrentSequenceNumber = FreeRTOS_ntohl( pxTCPPacket->xTCPHeader.ulSequenceNumber );\r
3200                 prvSocketSetMSS( pxReturn );\r
3201 \r
3202                 prvTCPCreateWindow( pxReturn );\r
3203 \r
3204                 /* It is recommended to increase the ISS for each new connection with a value of 0x102. */\r
3205                 ulNextInitialSequenceNumber += INITIAL_SEQUENCE_NUMBER_INCREMENT;\r
3206 \r
3207                 vTCPStateChange( pxReturn, eSYN_FIRST );\r
3208 \r
3209                 /* Make a copy of the header up to the TCP header.  It is needed later\r
3210                 on, whenever data must be sent to the peer. */\r
3211                 memcpy( pxReturn->u.xTCP.xPacket.u.ucLastPacket, pxNetworkBuffer->pucEthernetBuffer, sizeof( pxReturn->u.xTCP.xPacket.u.ucLastPacket ) );\r
3212         }\r
3213         return pxReturn;\r
3214 }\r
3215 /*-----------------------------------------------------------*/\r
3216 \r
3217 /*\r
3218  * Duplicates a socket after a listening socket receives a connection.\r
3219  */\r
3220 static BaseType_t prvTCPSocketCopy( FreeRTOS_Socket_t *pxNewSocket, FreeRTOS_Socket_t *pxSocket )\r
3221 {\r
3222 struct freertos_sockaddr xAddress;\r
3223 \r
3224         pxNewSocket->xReceiveBlockTime = pxSocket->xReceiveBlockTime;\r
3225         pxNewSocket->xSendBlockTime = pxSocket->xSendBlockTime;\r
3226         pxNewSocket->ucSocketOptions = pxSocket->ucSocketOptions;\r
3227         pxNewSocket->u.xTCP.uxRxStreamSize = pxSocket->u.xTCP.uxRxStreamSize;\r
3228         pxNewSocket->u.xTCP.uxTxStreamSize = pxSocket->u.xTCP.uxTxStreamSize;\r
3229         pxNewSocket->u.xTCP.uxLittleSpace = pxSocket->u.xTCP.uxLittleSpace;\r
3230         pxNewSocket->u.xTCP.uxEnoughSpace = pxSocket->u.xTCP.uxEnoughSpace;\r
3231         pxNewSocket->u.xTCP.uxRxWinSize  = pxSocket->u.xTCP.uxRxWinSize;\r
3232         pxNewSocket->u.xTCP.uxTxWinSize  = pxSocket->u.xTCP.uxTxWinSize;\r
3233 \r
3234         #if( ipconfigSOCKET_HAS_USER_SEMAPHORE == 1 )\r
3235         {\r
3236                 pxNewSocket->pxUserSemaphore = pxSocket->pxUserSemaphore;\r
3237         }\r
3238         #endif /* ipconfigSOCKET_HAS_USER_SEMAPHORE */\r
3239 \r
3240         #if( ipconfigUSE_CALLBACKS == 1 )\r
3241         {\r
3242                 /* In case call-backs are used, copy them from parent to child. */\r
3243                 pxNewSocket->u.xTCP.pxHandleConnected = pxSocket->u.xTCP.pxHandleConnected;\r
3244                 pxNewSocket->u.xTCP.pxHandleReceive = pxSocket->u.xTCP.pxHandleReceive;\r
3245                 pxNewSocket->u.xTCP.pxHandleSent = pxSocket->u.xTCP.pxHandleSent;\r
3246         }\r
3247         #endif /* ipconfigUSE_CALLBACKS */\r
3248 \r
3249         #if( ipconfigSUPPORT_SELECT_FUNCTION == 1 )\r
3250         {\r
3251                 /* Child socket of listening sockets will inherit the Socket Set\r
3252                 Otherwise the owner has no chance of including it into the set. */\r
3253                 if( pxSocket->pxSocketSet )\r
3254                 {\r
3255                         pxNewSocket->pxSocketSet = pxSocket->pxSocketSet;\r
3256                         pxNewSocket->xSelectBits = pxSocket->xSelectBits | eSELECT_READ | eSELECT_EXCEPT;\r
3257                 }\r
3258         }\r
3259         #endif /* ipconfigSUPPORT_SELECT_FUNCTION */\r
3260 \r
3261         /* And bind it to the same local port as its parent. */\r
3262         xAddress.sin_addr = *ipLOCAL_IP_ADDRESS_POINTER;\r
3263         xAddress.sin_port = FreeRTOS_htons( pxSocket->usLocalPort );\r
3264 \r
3265         #if( ipconfigTCP_HANG_PROTECTION == 1 )\r
3266         {\r
3267                 /* Only when there is anti-hanging protection, a socket may become an\r
3268                 orphan temporarily.  Once this socket is really connected, the owner of\r
3269                 the server socket will be notified. */\r
3270 \r
3271                 /* When bPassQueued is true, the socket is an orphan until it gets\r
3272                 connected. */\r
3273                 pxNewSocket->u.xTCP.bits.bPassQueued = pdTRUE_UNSIGNED;\r
3274                 pxNewSocket->u.xTCP.pxPeerSocket = pxSocket;\r
3275         }\r
3276         #else\r
3277         {\r
3278                 /* A reference to the new socket may be stored and the socket is marked\r
3279                 as 'passable'. */\r
3280 \r
3281                 /* When bPassAccept is true, this socket may be returned in a call to\r
3282                 accept(). */\r
3283                 pxNewSocket->u.xTCP.bits.bPassAccept = pdTRUE_UNSIGNED;\r
3284                 if(pxSocket->u.xTCP.pxPeerSocket == NULL )\r
3285                 {\r
3286                         pxSocket->u.xTCP.pxPeerSocket = pxNewSocket;\r
3287                 }\r
3288         }\r
3289         #endif\r
3290 \r
3291         pxSocket->u.xTCP.usChildCount++;\r
3292 \r
3293         FreeRTOS_debug_printf( ( "Gain: Socket %u now has %u / %u child%s\n",\r
3294                 pxSocket->usLocalPort,\r
3295                 pxSocket->u.xTCP.usChildCount,\r
3296                 pxSocket->u.xTCP.usBacklog,\r
3297                 pxSocket->u.xTCP.usChildCount == 1u ? "" : "ren" ) );\r
3298 \r
3299         /* Now bind the child socket to the same port as the listening socket. */\r
3300         if( vSocketBind ( pxNewSocket, &xAddress, sizeof( xAddress ), pdTRUE ) != 0 )\r
3301         {\r
3302                 FreeRTOS_debug_printf( ( "TCP: Listen: new socket bind error\n" ) );\r
3303                 vSocketClose( pxNewSocket );\r
3304                 return pdFALSE;\r
3305         }\r
3306 \r
3307         return pdTRUE;\r
3308 }\r
3309 /*-----------------------------------------------------------*/\r
3310 \r
3311 #if( ( ipconfigHAS_DEBUG_PRINTF != 0 ) || ( ipconfigHAS_PRINTF != 0 ) )\r
3312 \r
3313         const char *FreeRTOS_GetTCPStateName( UBaseType_t ulState )\r
3314         {\r
3315                 if( ulState >= ( UBaseType_t ) ARRAY_SIZE( pcStateNames ) )\r
3316                 {\r
3317                         ulState = ( UBaseType_t ) ARRAY_SIZE( pcStateNames ) - 1u;\r
3318                 }\r
3319                 return pcStateNames[ ulState ];\r
3320         }\r
3321 \r
3322 #endif /* ( ( ipconfigHAS_DEBUG_PRINTF != 0 ) || ( ipconfigHAS_PRINTF != 0 ) ) */\r
3323 /*-----------------------------------------------------------*/\r
3324 \r
3325 /*\r
3326  * In the API accept(), the user asks is there is a new client?  As API's can\r
3327  * not walk through the xBoundTCPSocketsList the IP-task will do this.\r
3328  */\r
3329 BaseType_t xTCPCheckNewClient( FreeRTOS_Socket_t *pxSocket )\r
3330 {\r
3331 TickType_t xLocalPort = FreeRTOS_htons( pxSocket->usLocalPort );\r
3332 ListItem_t *pxIterator;\r
3333 FreeRTOS_Socket_t *pxFound;\r
3334 BaseType_t xResult = pdFALSE;\r
3335 \r
3336         /* Here xBoundTCPSocketsList can be accessed safely IP-task is the only one\r
3337         who has access. */\r
3338         for( pxIterator = ( ListItem_t * ) listGET_HEAD_ENTRY( &xBoundTCPSocketsList );\r
3339                 pxIterator != ( ListItem_t * ) listGET_END_MARKER( &xBoundTCPSocketsList );\r
3340                 pxIterator = ( ListItem_t * ) listGET_NEXT( pxIterator ) )\r
3341         {\r
3342                 if( listGET_LIST_ITEM_VALUE( pxIterator ) == xLocalPort )\r
3343                 {\r
3344                         pxFound = ( FreeRTOS_Socket_t * ) listGET_LIST_ITEM_OWNER( pxIterator );\r
3345                         if( ( pxFound->ucProtocol == FREERTOS_IPPROTO_TCP ) && ( pxFound->u.xTCP.bits.bPassAccept != pdFALSE_UNSIGNED ) )\r
3346                         {\r
3347                                 pxSocket->u.xTCP.pxPeerSocket = pxFound;\r
3348                                 FreeRTOS_debug_printf( ( "xTCPCheckNewClient[0]: client on port %u\n", pxSocket->usLocalPort ) );\r
3349                                 xResult = pdTRUE;\r
3350                                 break;\r
3351                         }\r
3352                 }\r
3353         }\r
3354         return xResult;\r
3355 }\r
3356 /*-----------------------------------------------------------*/\r
3357 \r
3358 #endif /* ipconfigUSE_TCP == 1 */\r
3359 \r