]> git.sur5r.net Git - freertos/blob - FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_TCP_IP.c
Add missing +TCP code.
[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                 /* A pseudo network buffer can not be released. */\r
748                 xReleaseAfterSend = pdFALSE;\r
749         }\r
750 \r
751         #if( ipconfigZERO_COPY_TX_DRIVER != 0 )\r
752         {\r
753                 if( xReleaseAfterSend == pdFALSE )\r
754                 {\r
755                         pxNetworkBuffer = pxDuplicateNetworkBufferWithDescriptor( pxNetworkBuffer, ( BaseType_t ) pxNetworkBuffer->xDataLength );\r
756                         if( pxNetworkBuffer == NULL )\r
757                         {\r
758                                 FreeRTOS_debug_printf( ( "prvTCPReturnPacket: duplicate failed\n" ) );\r
759                         }\r
760                         xReleaseAfterSend = pdTRUE;\r
761                 }\r
762         }\r
763         #endif /* ipconfigZERO_COPY_TX_DRIVER */\r
764 \r
765         if( pxNetworkBuffer != NULL )\r
766         {\r
767                 pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );\r
768                 pxIPHeader = &pxTCPPacket->xIPHeader;\r
769                 pxEthernetHeader = &pxTCPPacket->xEthernetHeader;\r
770 \r
771                 /* Fill the packet, using hton translations. */\r
772                 if( pxSocket != NULL )\r
773                 {\r
774                         /* Calculate the space in the RX buffer in order to advertise the\r
775                         size of this socket's reception window. */\r
776                         pxTCPWindow = &( pxSocket->u.xTCP.xTCPWindow );\r
777 \r
778                         if( pxSocket->u.xTCP.rxStream != NULL )\r
779                         {\r
780                                 /* An RX stream was created already, see how much space is\r
781                                 available. */\r
782                                 ulFrontSpace = ( uint32_t ) uxStreamBufferFrontSpace( pxSocket->u.xTCP.rxStream );\r
783                         }\r
784                         else\r
785                         {\r
786                                 /* No RX stream has been created, the full stream size is\r
787                                 available. */\r
788                                 ulFrontSpace = ( uint32_t ) pxSocket->u.xTCP.uxRxStreamSize;\r
789                         }\r
790 \r
791                         /* Take the minimum of the RX buffer space and the RX window size. */\r
792                         ulSpace = FreeRTOS_min_uint32( pxSocket->u.xTCP.ulRxCurWinSize, pxTCPWindow->xSize.ulRxWindowLength );\r
793 \r
794                         if( ( pxSocket->u.xTCP.bits.bLowWater != pdFALSE_UNSIGNED ) || ( pxSocket->u.xTCP.bits.bRxStopped != pdFALSE_UNSIGNED ) )\r
795                         {\r
796                                 /* The low-water mark was reached, meaning there was little\r
797                                 space left.  The socket will wait until the application has read\r
798                                 or flushed the incoming data, and 'zero-window' will be\r
799                                 advertised. */\r
800                                 ulSpace = 0u;\r
801                         }\r
802 \r
803                         /* If possible, advertise an RX window size of at least 1 MSS, otherwise\r
804                         the peer might start 'zero window probing', i.e. sending small packets\r
805                         (1, 2, 4, 8... bytes). */\r
806                         if( ( ulSpace < pxSocket->u.xTCP.usCurMSS ) && ( ulFrontSpace >= pxSocket->u.xTCP.usCurMSS ) )\r
807                         {\r
808                                 ulSpace = pxSocket->u.xTCP.usCurMSS;\r
809                         }\r
810 \r
811                         /* Avoid overflow of the 16-bit win field. */\r
812                         #if( ipconfigUSE_TCP_WIN != 0 )\r
813                         {\r
814                                 ulWinSize = ( ulSpace >> pxSocket->u.xTCP.ucMyWinScaleFactor );\r
815                         }\r
816                         #else\r
817                         {\r
818                                 ulWinSize = ulSpace;\r
819                         }\r
820                         #endif\r
821                         if( ulWinSize > 0xfffcUL )\r
822                         {\r
823                                 ulWinSize = 0xfffcUL;\r
824                         }\r
825 \r
826                         pxTCPPacket->xTCPHeader.usWindow = FreeRTOS_htons( ( uint16_t ) ulWinSize );\r
827 \r
828                         #if( ipconfigHAS_DEBUG_PRINTF != 0 )\r
829                         {\r
830                                 if( ipconfigTCP_MAY_LOG_PORT( pxSocket->usLocalPort ) != pdFALSE )\r
831                                 {\r
832                                         if( ( xTCPWindowLoggingLevel != 0 ) && ( pxSocket->u.xTCP.bits.bWinChange != pdFALSE_UNSIGNED ) )\r
833                                         {\r
834                                         size_t uxFrontSpace;\r
835 \r
836                                                 if(pxSocket->u.xTCP.rxStream != NULL)\r
837                                                 {\r
838                                                         uxFrontSpace =  uxStreamBufferFrontSpace( pxSocket->u.xTCP.rxStream ) ;\r
839                                                 }\r
840                                                 else\r
841                                                 {\r
842                                                         uxFrontSpace = 0u;\r
843                                                 }\r
844 \r
845                                                 FreeRTOS_debug_printf( ( "%s: %lxip:%u: [%lu < %lu] winSize %ld\n",\r
846                                                 pxSocket->u.xTCP.bits.bLowWater ? "STOP" : "GO ",\r
847                                                         pxSocket->u.xTCP.ulRemoteIP,\r
848                                                         pxSocket->u.xTCP.usRemotePort,\r
849                                                         pxSocket->u.xTCP.bits.bLowWater ? pxSocket->u.xTCP.uxLittleSpace : uxFrontSpace, pxSocket->u.xTCP.uxEnoughSpace,\r
850                                                         (int32_t) ( pxTCPWindow->rx.ulHighestSequenceNumber - pxTCPWindow->rx.ulCurrentSequenceNumber ) ) );\r
851                                         }\r
852                                 }\r
853                         }\r
854                         #endif /* ipconfigHAS_DEBUG_PRINTF != 0 */\r
855 \r
856                         /* The new window size has been advertised, switch off the flag. */\r
857                         pxSocket->u.xTCP.bits.bWinChange = pdFALSE_UNSIGNED;\r
858 \r
859                         /* Later on, when deciding to delay an ACK, a precise estimate is needed\r
860                         of the free RX space.  At this moment, 'ulHighestRxAllowed' would be the\r
861                         highest sequence number minus 1 that the socket will accept. */\r
862                         pxSocket->u.xTCP.ulHighestRxAllowed = pxTCPWindow->rx.ulCurrentSequenceNumber + ulSpace;\r
863 \r
864                         #if( ipconfigTCP_KEEP_ALIVE == 1 )\r
865                                 if( pxSocket->u.xTCP.bits.bSendKeepAlive != pdFALSE_UNSIGNED )\r
866                                 {\r
867                                         /* Sending a keep-alive packet, send the current sequence number\r
868                                         minus 1, which will     be recognised as a keep-alive packet an\r
869                                         responded to by acknowledging the last byte. */\r
870                                         pxSocket->u.xTCP.bits.bSendKeepAlive = pdFALSE_UNSIGNED;\r
871                                         pxSocket->u.xTCP.bits.bWaitKeepAlive = pdTRUE_UNSIGNED;\r
872 \r
873                                         pxTCPPacket->xTCPHeader.ulSequenceNumber = pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber - 1UL;\r
874                                         pxTCPPacket->xTCPHeader.ulSequenceNumber = FreeRTOS_htonl( pxTCPPacket->xTCPHeader.ulSequenceNumber );\r
875                                 }\r
876                                 else\r
877                         #endif\r
878                         {\r
879                                 pxTCPPacket->xTCPHeader.ulSequenceNumber = FreeRTOS_htonl( pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber );\r
880 \r
881                                 if( ( pxTCPPacket->xTCPHeader.ucTCPFlags & ( uint8_t ) ipTCP_FLAG_FIN ) != 0u )\r
882                                 {\r
883                                         /* Suppress FIN in case this packet carries earlier data to be\r
884                                         retransmitted. */\r
885                                         uint32_t ulDataLen = ( uint32_t ) ( ulLen - ( ipSIZE_OF_TCP_HEADER + ipSIZE_OF_IPv4_HEADER ) );\r
886                                         if( ( pxTCPWindow->ulOurSequenceNumber + ulDataLen ) != pxTCPWindow->tx.ulFINSequenceNumber )\r
887                                         {\r
888                                                 pxTCPPacket->xTCPHeader.ucTCPFlags &= ( ( uint8_t ) ~ipTCP_FLAG_FIN );\r
889                                                 FreeRTOS_debug_printf( ( "Suppress FIN for %lu + %lu < %lu\n",\r
890                                                         pxTCPWindow->ulOurSequenceNumber - pxTCPWindow->tx.ulFirstSequenceNumber,\r
891                                                         ulDataLen,\r
892                                                         pxTCPWindow->tx.ulFINSequenceNumber - pxTCPWindow->tx.ulFirstSequenceNumber ) );\r
893                                         }\r
894                                 }\r
895                         }\r
896 \r
897                         /* Tell which sequence number is expected next time */\r
898                         pxTCPPacket->xTCPHeader.ulAckNr = FreeRTOS_htonl( pxTCPWindow->rx.ulCurrentSequenceNumber );\r
899                 }\r
900                 else\r
901                 {\r
902                         /* Sending data without a socket, probably replying with a RST flag\r
903                         Just swap the two sequence numbers. */\r
904                         vFlip_32( pxTCPPacket->xTCPHeader.ulSequenceNumber, pxTCPPacket->xTCPHeader.ulAckNr );\r
905                 }\r
906 \r
907                 pxIPHeader->ucTimeToLive           = ( uint8_t ) ipconfigTCP_TIME_TO_LIVE;\r
908                 pxIPHeader->usLength               = FreeRTOS_htons( ulLen );\r
909                 if( ( pxSocket == NULL ) || ( *ipLOCAL_IP_ADDRESS_POINTER == 0ul ) )\r
910                 {\r
911                         /* When pxSocket is NULL, this function is called by prvTCPSendReset()\r
912                         and the IP-addresses must be swapped.\r
913                         Also swap the IP-addresses in case the IP-tack doesn't have an\r
914                         IP-address yet, i.e. when ( *ipLOCAL_IP_ADDRESS_POINTER == 0ul ). */\r
915                         ulSourceAddress = pxIPHeader->ulDestinationIPAddress;\r
916                 }\r
917                 else\r
918                 {\r
919                         ulSourceAddress = *ipLOCAL_IP_ADDRESS_POINTER;\r
920                 }\r
921                 pxIPHeader->ulDestinationIPAddress = pxIPHeader->ulSourceIPAddress;\r
922                 pxIPHeader->ulSourceIPAddress = ulSourceAddress;\r
923                 vFlip_16( pxTCPPacket->xTCPHeader.usSourcePort, pxTCPPacket->xTCPHeader.usDestinationPort );\r
924 \r
925                 /* Just an increasing number. */\r
926                 pxIPHeader->usIdentification = FreeRTOS_htons( usPacketIdentifier );\r
927                 usPacketIdentifier++;\r
928                 pxIPHeader->usFragmentOffset = 0u;\r
929 \r
930                 #if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 0 )\r
931                 {\r
932                         /* calculate the IP header checksum, in case the driver won't do that. */\r
933                         pxIPHeader->usHeaderChecksum = 0x00u;\r
934                         pxIPHeader->usHeaderChecksum = usGenerateChecksum( 0u, ( uint8_t * ) &( pxIPHeader->ucVersionHeaderLength ), ipSIZE_OF_IPv4_HEADER );\r
935                         pxIPHeader->usHeaderChecksum = ~FreeRTOS_htons( pxIPHeader->usHeaderChecksum );\r
936 \r
937                         /* calculate the TCP checksum for an outgoing packet. */\r
938                         usGenerateProtocolChecksum( (uint8_t*)pxTCPPacket, pdTRUE );\r
939 \r
940                         /* A calculated checksum of 0 must be inverted as 0 means the checksum\r
941                         is disabled. */\r
942                         if( pxTCPPacket->xTCPHeader.usChecksum == 0x00u )\r
943                         {\r
944                                 pxTCPPacket->xTCPHeader.usChecksum = 0xffffU;\r
945                         }\r
946                 }\r
947                 #endif\r
948 \r
949                 #if( ipconfigUSE_LINKED_RX_MESSAGES != 0 )\r
950                 {\r
951                         pxNetworkBuffer->pxNextBuffer = NULL;\r
952                 }\r
953                 #endif\r
954 \r
955                 /* Important: tell NIC driver how many bytes must be sent. */\r
956                 pxNetworkBuffer->xDataLength = ulLen + ipSIZE_OF_ETH_HEADER;\r
957 \r
958                 /* Fill in the destination MAC addresses. */\r
959                 memcpy( ( void * ) &( pxEthernetHeader->xDestinationAddress ), ( void * ) &( pxEthernetHeader->xSourceAddress ),\r
960                         sizeof( pxEthernetHeader->xDestinationAddress ) );\r
961 \r
962                 /* The source MAC addresses is fixed to 'ipLOCAL_MAC_ADDRESS'. */\r
963                 memcpy( ( void * ) &( pxEthernetHeader->xSourceAddress ), ( void * ) ipLOCAL_MAC_ADDRESS, ( size_t ) ipMAC_ADDRESS_LENGTH_BYTES );\r
964 \r
965                 #if defined( ipconfigETHERNET_MINIMUM_PACKET_BYTES )\r
966                 {\r
967                         if( pxNetworkBuffer->xDataLength < ( size_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES )\r
968                         {\r
969                         BaseType_t xIndex;\r
970 \r
971                                 for( xIndex = ( BaseType_t ) pxNetworkBuffer->xDataLength; xIndex < ( BaseType_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES; xIndex++ )\r
972                                 {\r
973                                         pxNetworkBuffer->pucEthernetBuffer[ xIndex ] = 0u;\r
974                                 }\r
975                                 pxNetworkBuffer->xDataLength = ( size_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES;\r
976                         }\r
977                 }\r
978                 #endif\r
979 \r
980                 /* Send! */\r
981                 xNetworkInterfaceOutput( pxNetworkBuffer, xReleaseAfterSend );\r
982 \r
983                 if( xReleaseAfterSend == pdFALSE )\r
984                 {\r
985                         /* Swap-back some fields, as pxBuffer probably points to a socket field\r
986                         containing the packet header. */\r
987                         vFlip_16( pxTCPPacket->xTCPHeader.usSourcePort, pxTCPPacket->xTCPHeader.usDestinationPort);\r
988                         pxTCPPacket->xIPHeader.ulSourceIPAddress = pxTCPPacket->xIPHeader.ulDestinationIPAddress;\r
989                         memcpy( pxEthernetHeader->xSourceAddress.ucBytes, pxEthernetHeader->xDestinationAddress.ucBytes, ( size_t ) ipMAC_ADDRESS_LENGTH_BYTES );\r
990                 }\r
991                 else\r
992                 {\r
993                         /* Nothing to do: the buffer has been passed to DMA and will be released after use */\r
994                 }\r
995         } /* if( pxNetworkBuffer != NULL ) */\r
996 }\r
997 /*-----------------------------------------------------------*/\r
998 \r
999 /*\r
1000  * The SYN event is very important: the sequence numbers, which have a kind of\r
1001  * random starting value, are being synchronised.  The sliding window manager\r
1002  * (in FreeRTOS_TCP_WIN.c) needs to know them, along with the Maximum Segment\r
1003  * Size (MSS) in use.\r
1004  */\r
1005 static void prvTCPCreateWindow( FreeRTOS_Socket_t *pxSocket )\r
1006 {\r
1007         if( xTCPWindowLoggingLevel )\r
1008                 FreeRTOS_debug_printf( ( "Limits (using): TCP Win size %lu Water %lu <= %lu <= %lu\n",\r
1009                         pxSocket->u.xTCP.uxRxWinSize * ipconfigTCP_MSS,\r
1010                         pxSocket->u.xTCP.uxLittleSpace ,\r
1011                         pxSocket->u.xTCP.uxEnoughSpace,\r
1012                         pxSocket->u.xTCP.uxRxStreamSize ) );\r
1013         vTCPWindowCreate(\r
1014                 &pxSocket->u.xTCP.xTCPWindow,\r
1015                 ipconfigTCP_MSS * pxSocket->u.xTCP.uxRxWinSize,\r
1016                 ipconfigTCP_MSS * pxSocket->u.xTCP.uxTxWinSize,\r
1017                 pxSocket->u.xTCP.xTCPWindow.rx.ulCurrentSequenceNumber,\r
1018                 pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber,\r
1019                 ( uint32_t ) pxSocket->u.xTCP.usInitMSS );\r
1020 }\r
1021 /*-----------------------------------------------------------*/\r
1022 \r
1023 /*\r
1024  * Connecting sockets have a special state: eCONNECT_SYN.  In this phase,\r
1025  * the Ethernet address of the target will be found using ARP.  In case the\r
1026  * target IP address is not within the netmask, the hardware address of the\r
1027  * gateway will be used.\r
1028  */\r
1029 static BaseType_t prvTCPPrepareConnect( FreeRTOS_Socket_t *pxSocket )\r
1030 {\r
1031 TCPPacket_t *pxTCPPacket;\r
1032 IPHeader_t *pxIPHeader;\r
1033 eARPLookupResult_t eReturned;\r
1034 uint32_t ulRemoteIP;\r
1035 MACAddress_t xEthAddress;\r
1036 BaseType_t xReturn = pdTRUE;\r
1037 \r
1038         #if( ipconfigHAS_PRINTF != 0 )\r
1039         {\r
1040                 /* Only necessary for nicer logging. */\r
1041                 memset( xEthAddress.ucBytes, '\0', sizeof( xEthAddress.ucBytes ) );\r
1042         }\r
1043         #endif /* ipconfigHAS_PRINTF != 0 */\r
1044 \r
1045         ulRemoteIP = FreeRTOS_htonl( pxSocket->u.xTCP.ulRemoteIP );\r
1046 \r
1047         /* Determine the ARP cache status for the requested IP address. */\r
1048         eReturned = eARPGetCacheEntry( &( ulRemoteIP ), &( xEthAddress ) );\r
1049 \r
1050         switch( eReturned )\r
1051         {\r
1052                 case eARPCacheHit:              /* An ARP table lookup found a valid entry. */\r
1053                         break;                          /* We can now prepare the SYN packet. */\r
1054                 case eARPCacheMiss:             /* An ARP table lookup did not find a valid entry. */\r
1055                 case eCantSendPacket:   /* There is no IP address, or an ARP is still in progress. */\r
1056                 default:\r
1057                         /* Count the number of times it couldn't find the ARP address. */\r
1058                         pxSocket->u.xTCP.ucRepCount++;\r
1059         \r
1060                         FreeRTOS_debug_printf( ( "ARP for %lxip (using %lxip): rc=%d %02X:%02X:%02X %02X:%02X:%02X\n",\r
1061                                 pxSocket->u.xTCP.ulRemoteIP,\r
1062                                 FreeRTOS_htonl( ulRemoteIP ),\r
1063                                 eReturned,\r
1064                                 xEthAddress.ucBytes[ 0 ],\r
1065                                 xEthAddress.ucBytes[ 1 ],\r
1066                                 xEthAddress.ucBytes[ 2 ],\r
1067                                 xEthAddress.ucBytes[ 3 ],\r
1068                                 xEthAddress.ucBytes[ 4 ],\r
1069                                 xEthAddress.ucBytes[ 5 ] ) );\r
1070         \r
1071                         /* And issue a (new) ARP request */\r
1072                         FreeRTOS_OutputARPRequest( ulRemoteIP );\r
1073         \r
1074                         xReturn = pdFALSE;\r
1075                         break;\r
1076         }\r
1077 \r
1078         if( xReturn != pdFALSE )\r
1079         {\r
1080                 /* The MAC-address of the peer (or gateway) has been found,\r
1081                 now prepare the initial TCP packet and some fields in the socket. */\r
1082                 pxTCPPacket = ( TCPPacket_t * )pxSocket->u.xTCP.xPacket.u.ucLastPacket;\r
1083                 pxIPHeader = &pxTCPPacket->xIPHeader;\r
1084 \r
1085                 /* Reset the retry counter to zero... */\r
1086                 pxSocket->u.xTCP.ucRepCount = 0u;\r
1087 \r
1088                 /* ...and remember that the connect/SYN data are prepared. */\r
1089                 pxSocket->u.xTCP.bits.bConnPrepared = pdTRUE_UNSIGNED;\r
1090 \r
1091                 /* Now that the Ethernet address is known, the initial packet can be\r
1092                 prepared. */\r
1093                 memset( pxSocket->u.xTCP.xPacket.u.ucLastPacket, '\0', sizeof( pxSocket->u.xTCP.xPacket.u.ucLastPacket ) );\r
1094 \r
1095                 /* Write the Ethernet address in Source, because it will be swapped by\r
1096                 prvTCPReturnPacket(). */\r
1097                 memcpy( &pxTCPPacket->xEthernetHeader.xSourceAddress, &xEthAddress, sizeof( xEthAddress ) );\r
1098 \r
1099                 /* 'ipIPv4_FRAME_TYPE' is already in network-byte-order. */\r
1100                 pxTCPPacket->xEthernetHeader.usFrameType = ipIPv4_FRAME_TYPE;\r
1101 \r
1102                 pxIPHeader->ucVersionHeaderLength = 0x45u;\r
1103                 pxIPHeader->usLength = FreeRTOS_htons( sizeof( TCPPacket_t ) - sizeof( pxTCPPacket->xEthernetHeader ) );\r
1104                 pxIPHeader->ucTimeToLive = ( uint8_t ) ipconfigTCP_TIME_TO_LIVE;\r
1105 \r
1106                 pxIPHeader->ucProtocol = ( uint8_t ) ipPROTOCOL_TCP;\r
1107 \r
1108                 /* Addresses and ports will be stored swapped because prvTCPReturnPacket\r
1109                 will swap them back while replying. */\r
1110                 pxIPHeader->ulDestinationIPAddress = *ipLOCAL_IP_ADDRESS_POINTER;\r
1111                 pxIPHeader->ulSourceIPAddress = FreeRTOS_htonl( pxSocket->u.xTCP.ulRemoteIP );\r
1112 \r
1113                 pxTCPPacket->xTCPHeader.usSourcePort = FreeRTOS_htons( pxSocket->u.xTCP.usRemotePort );\r
1114                 pxTCPPacket->xTCPHeader.usDestinationPort = FreeRTOS_htons( pxSocket->usLocalPort );\r
1115 \r
1116                 /* We are actively connecting, so the peer's Initial Sequence Number (ISN)\r
1117                 isn't known yet. */\r
1118                 pxSocket->u.xTCP.xTCPWindow.rx.ulCurrentSequenceNumber = 0ul;\r
1119 \r
1120                 /* Start with ISN (Initial Sequence Number). */\r
1121                 pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber = ulNextInitialSequenceNumber;\r
1122 \r
1123                 /* And increment it with 268 for the next new connection, which is\r
1124                 recommended value. */\r
1125                 ulNextInitialSequenceNumber += 0x102UL;\r
1126 \r
1127                 /* The TCP header size is 20 bytes, divided by 4 equals 5, which is put in\r
1128                 the high nibble of the TCP offset field. */\r
1129                 pxTCPPacket->xTCPHeader.ucTCPOffset = 0x50u;\r
1130 \r
1131                 /* Only set the SYN flag. */\r
1132                 pxTCPPacket->xTCPHeader.ucTCPFlags = ipTCP_FLAG_SYN;\r
1133 \r
1134                 /* Set the values of usInitMSS / usCurMSS for this socket. */\r
1135                 prvSocketSetMSS( pxSocket );\r
1136 \r
1137                 /* For now this is also the advertised window size. */\r
1138                 pxSocket->u.xTCP.ulRxCurWinSize = pxSocket->u.xTCP.usInitMSS;\r
1139 \r
1140                 /* The initial sequence numbers at our side are known.  Later\r
1141                 vTCPWindowInit() will be called to fill in the peer's sequence numbers, but\r
1142                 first wait for a SYN+ACK reply. */\r
1143                 prvTCPCreateWindow( pxSocket );\r
1144         }\r
1145 \r
1146         return xReturn;\r
1147 }\r
1148 /*-----------------------------------------------------------*/\r
1149 \r
1150 /* For logging and debugging: make a string showing the TCP flags\r
1151 */\r
1152 #if( ipconfigHAS_DEBUG_PRINTF != 0 )\r
1153 \r
1154         static const char *prvTCPFlagMeaning( UBaseType_t xFlags)\r
1155         {\r
1156                 static char retString[10];\r
1157                 snprintf(retString, sizeof( retString ), "%c%c%c%c%c%c%c%c%c",\r
1158                         ( xFlags & ipTCP_FLAG_FIN )  ? 'F' : '.',       /* 0x0001: No more data from sender */\r
1159                         ( xFlags & ipTCP_FLAG_SYN )  ? 'S' : '.',       /* 0x0002: Synchronize sequence numbers */\r
1160                         ( xFlags & ipTCP_FLAG_RST )  ? 'R' : '.',       /* 0x0004: Reset the connection */\r
1161                         ( xFlags & ipTCP_FLAG_PSH )  ? 'P' : '.',       /* 0x0008: Push function: please push buffered data to the recv application */\r
1162                         ( xFlags & ipTCP_FLAG_ACK )  ? 'A' : '.',       /* 0x0010: Acknowledgment field is significant */\r
1163                         ( xFlags & ipTCP_FLAG_URG )  ? 'U' : '.',       /* 0x0020: Urgent pointer field is significant */\r
1164                         ( xFlags & ipTCP_FLAG_ECN )  ? 'E' : '.',       /* 0x0040: ECN-Echo */\r
1165                         ( xFlags & ipTCP_FLAG_CWR )  ? 'C' : '.',       /* 0x0080: Congestion Window Reduced */\r
1166                         ( xFlags & ipTCP_FLAG_NS )   ? 'N' : '.');      /* 0x0100: ECN-nonce concealment protection */\r
1167                 return retString;\r
1168         }\r
1169         /*-----------------------------------------------------------*/\r
1170 \r
1171 #endif /* ipconfigHAS_DEBUG_PRINTF */\r
1172 \r
1173 /*\r
1174  * Parse the TCP option(s) received, if present.  It has already been verified\r
1175  * that: ((pxTCPHeader->ucTCPOffset & 0xf0) > 0x50), meaning that the TP header\r
1176  * is longer than the usual 20 (5 x 4) bytes.\r
1177  */\r
1178 static void prvCheckOptions( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer )\r
1179 {\r
1180 TCPPacket_t * pxTCPPacket;\r
1181 TCPHeader_t * pxTCPHeader;\r
1182 const unsigned char *pucPtr;\r
1183 const unsigned char *pucLast;\r
1184 TCPWindow_t *pxTCPWindow;\r
1185 UBaseType_t uxNewMSS;\r
1186 \r
1187         pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );\r
1188         pxTCPHeader = &pxTCPPacket->xTCPHeader;\r
1189 \r
1190         /* A character pointer to iterate through the option data */\r
1191         pucPtr = pxTCPHeader->ucOptdata;\r
1192         pucLast = pucPtr + (((pxTCPHeader->ucTCPOffset >> 4) - 5) << 2);\r
1193         pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow;\r
1194 \r
1195         /* The comparison with pucLast is only necessary in case the option data are\r
1196         corrupted, we don't like to run into invalid memory and crash. */\r
1197         while( pucPtr < pucLast )\r
1198         {\r
1199                 if( pucPtr[ 0 ] == TCP_OPT_END )\r
1200                 {\r
1201                         /* End of options. */\r
1202                         return;\r
1203                 }\r
1204                 if( pucPtr[ 0 ] == TCP_OPT_NOOP)\r
1205                 {\r
1206                         pucPtr++;\r
1207 \r
1208                         /* NOP option, inserted to make the length a multiple of 4. */\r
1209                 }\r
1210 #if( ipconfigUSE_TCP_WIN != 0 )\r
1211                 else if( ( pucPtr[ 0 ] == TCP_OPT_WSOPT ) && ( pucPtr[ 1 ] == TCP_OPT_WSOPT_LEN ) )\r
1212                 {\r
1213                         pxSocket->u.xTCP.ucPeerWinScaleFactor = pucPtr[ 2 ];\r
1214                         pxSocket->u.xTCP.bits.bWinScaling = pdTRUE_UNSIGNED;\r
1215                         pucPtr += TCP_OPT_WSOPT_LEN;\r
1216                 }\r
1217 #endif  /* ipconfigUSE_TCP_WIN */\r
1218                 else if( ( pucPtr[ 0 ] == TCP_OPT_MSS ) && ( pucPtr[ 1 ] == TCP_OPT_MSS_LEN ) )\r
1219                 {\r
1220                         /* An MSS option with the correct option length.  FreeRTOS_htons()\r
1221                         is not needed here because usChar2u16() already returns a host\r
1222                         endian number. */\r
1223                         uxNewMSS = usChar2u16( pucPtr + 2 );\r
1224 \r
1225                         if( pxSocket->u.xTCP.usInitMSS != uxNewMSS )\r
1226                         {\r
1227                                 FreeRTOS_debug_printf( ( "MSS change %u -> %lu\n", pxSocket->u.xTCP.usInitMSS, uxNewMSS ) );\r
1228                         }\r
1229 \r
1230                         if( pxSocket->u.xTCP.usInitMSS > uxNewMSS )\r
1231                         {\r
1232                                 /* our MSS was bigger than the MSS of the other party: adapt it. */\r
1233                                 pxSocket->u.xTCP.bits.bMssChange = pdTRUE_UNSIGNED;\r
1234                                 if( ( pxTCPWindow != NULL ) && ( pxSocket->u.xTCP.usCurMSS > uxNewMSS ) )\r
1235                                 {\r
1236                                         /* The peer advertises a smaller MSS than this socket was\r
1237                                         using.  Use that as well. */\r
1238                                         FreeRTOS_debug_printf( ( "Change mss %d => %lu\n", pxSocket->u.xTCP.usCurMSS, uxNewMSS ) );\r
1239                                         pxSocket->u.xTCP.usCurMSS = ( uint16_t ) uxNewMSS;\r
1240                                 }\r
1241                                 pxTCPWindow->xSize.ulRxWindowLength = ( ( uint32_t ) uxNewMSS ) * ( pxTCPWindow->xSize.ulRxWindowLength / ( ( uint32_t ) uxNewMSS ) );\r
1242                                 pxTCPWindow->usMSSInit = ( uint16_t ) uxNewMSS;\r
1243                                 pxTCPWindow->usMSS = ( uint16_t ) uxNewMSS;\r
1244                                 pxSocket->u.xTCP.usInitMSS = ( uint16_t ) uxNewMSS;\r
1245                                 pxSocket->u.xTCP.usCurMSS = ( uint16_t ) uxNewMSS;\r
1246                         }\r
1247 \r
1248                         #if( ipconfigUSE_TCP_WIN != 1 )\r
1249                                 /* Without scaled windows, MSS is the only interesting option. */\r
1250                                 break;\r
1251                         #else\r
1252                                 /* Or else we continue to check another option: selective ACK. */\r
1253                                 pucPtr += TCP_OPT_MSS_LEN;\r
1254                         #endif  /* ipconfigUSE_TCP_WIN != 1 */\r
1255                 }\r
1256                 else\r
1257                 {\r
1258                         /* All other options have a length field, so that we easily\r
1259                         can skip past them. */\r
1260                         int len = ( int )pucPtr[ 1 ];\r
1261                         if( len == 0 )\r
1262                         {\r
1263                                 /* If the length field is zero, the options are malformed\r
1264                                 and we don't process them further. */\r
1265                                 break;\r
1266                         }\r
1267 \r
1268                         #if( ipconfigUSE_TCP_WIN == 1 )\r
1269                         {\r
1270                                 /* Selective ACK: the peer has received a packet but it is missing earlier\r
1271                                 packets.  At least this packet does not need retransmission anymore\r
1272                                 ulTCPWindowTxSack( ) takes care of this administration. */\r
1273                                 if( pucPtr[0] == TCP_OPT_SACK_A )\r
1274                                 {\r
1275                                         len -= 2;\r
1276                                         pucPtr += 2;\r
1277 \r
1278                                         while( len >= 8 )\r
1279                                         {\r
1280                                         uint32_t ulFirst = ulChar2u32( pucPtr );\r
1281                                         uint32_t ulLast  = ulChar2u32( pucPtr + 4 );\r
1282                                         uint32_t ulCount = ulTCPWindowTxSack( &pxSocket->u.xTCP.xTCPWindow, ulFirst, ulLast );\r
1283                                                 /* ulTCPWindowTxSack( ) returns the number of bytes which have been acked\r
1284                                                 starting from the head position.\r
1285                                                 Advance the tail pointer in txStream. */\r
1286                                                 if( ( pxSocket->u.xTCP.txStream  != NULL ) && ( ulCount > 0 ) )\r
1287                                                 {\r
1288                                                         /* Just advancing the tail index, 'ulCount' bytes have been confirmed. */\r
1289                                                         uxStreamBufferGet( pxSocket->u.xTCP.txStream, 0, NULL, ( size_t ) ulCount, pdFALSE );\r
1290                                                         pxSocket->xEventBits |= eSOCKET_SEND;\r
1291 \r
1292                                                         #if ipconfigSUPPORT_SELECT_FUNCTION == 1\r
1293                                                         {\r
1294                                                                 if( pxSocket->xSelectBits & eSELECT_WRITE )\r
1295                                                                 {\r
1296                                                                         /* The field 'xEventBits' is used to store regular socket events (at most 8),\r
1297                                                                         as well as 'select events', which will be left-shifted */\r
1298                                                                         pxSocket->xEventBits |= ( eSELECT_WRITE << SOCKET_EVENT_BIT_COUNT );\r
1299                                                                 }\r
1300                                                         }\r
1301                                                         #endif\r
1302 \r
1303                                                         /* In case the socket owner has installed an OnSent handler,\r
1304                                                         call it now. */\r
1305                                                         #if( ipconfigUSE_CALLBACKS == 1 )\r
1306                                                         {\r
1307                                                                 if( ipconfigIS_VALID_PROG_ADDRESS( pxSocket->u.xTCP.pxHandleSent ) )\r
1308                                                                 {\r
1309                                                                         pxSocket->u.xTCP.pxHandleSent( (Socket_t *)pxSocket, ulCount );\r
1310                                                                 }\r
1311                                                         }\r
1312                                                         #endif /* ipconfigUSE_CALLBACKS == 1  */\r
1313                                                 }\r
1314                                                 pucPtr += 8;\r
1315                                                 len -= 8;\r
1316                                         }\r
1317                                         /* len should be 0 by now. */\r
1318                                 }\r
1319                                 #if     ipconfigUSE_TCP_TIMESTAMPS == 1\r
1320                                         else if( pucPtr[0] == TCP_OPT_TIMESTAMP )\r
1321                                         {\r
1322                                                 len -= 2;       /* Skip option and length byte. */\r
1323                                                 pucPtr += 2;\r
1324                                                 pxSocket->u.xTCP.xTCPWindow.u.bits.bTimeStamps = pdTRUE_UNSIGNED;\r
1325                                                 pxSocket->u.xTCP.xTCPWindow.rx.ulTimeStamp = ulChar2u32( pucPtr );\r
1326                                                 pxSocket->u.xTCP.xTCPWindow.tx.ulTimeStamp = ulChar2u32( pucPtr + 4 );\r
1327                                         }\r
1328                                 #endif  /* ipconfigUSE_TCP_TIMESTAMPS == 1 */\r
1329                         }\r
1330                         #endif  /* ipconfigUSE_TCP_WIN == 1 */\r
1331 \r
1332                         pucPtr += len;\r
1333                 }\r
1334         }\r
1335 }\r
1336 /*-----------------------------------------------------------*/\r
1337 \r
1338 #if( ipconfigUSE_TCP_WIN != 0 )\r
1339 \r
1340         static uint8_t prvWinScaleFactor( FreeRTOS_Socket_t *pxSocket )\r
1341         {\r
1342         size_t uxWinSize;\r
1343         uint8_t ucFactor;\r
1344 \r
1345                 /* 'xTCP.uxRxWinSize' is the size of the reception window in units of MSS. */\r
1346                 uxWinSize = pxSocket->u.xTCP.uxRxWinSize * ( size_t ) pxSocket->u.xTCP.usInitMSS;\r
1347                 ucFactor = 0u;\r
1348                 while( uxWinSize > 0xfffful )\r
1349                 {\r
1350                         /* Divide by two and increase the binary factor by 1. */\r
1351                         uxWinSize >>= 1;\r
1352                         ucFactor++;\r
1353                 }\r
1354 \r
1355                 FreeRTOS_debug_printf( ( "prvWinScaleFactor: uxRxWinSize %lu MSS %lu Factor %u\n",\r
1356                         pxSocket->u.xTCP.uxRxWinSize,\r
1357                         pxSocket->u.xTCP.usInitMSS,\r
1358                         ucFactor ) );\r
1359 \r
1360                 return ucFactor;\r
1361         }\r
1362 \r
1363 #endif\r
1364 /*-----------------------------------------------------------*/\r
1365 \r
1366 /*\r
1367  * When opening a TCP connection, while SYN's are being sent, the  parties may\r
1368  * communicate what MSS (Maximum Segment Size) they intend to use.   MSS is the\r
1369  * nett size of the payload, always smaller than MTU.\r
1370 */\r
1371 static UBaseType_t prvSetSynAckOptions( FreeRTOS_Socket_t *pxSocket, TCPPacket_t * pxTCPPacket )\r
1372 {\r
1373 TCPHeader_t *pxTCPHeader = &pxTCPPacket->xTCPHeader;\r
1374 uint16_t usMSS = pxSocket->u.xTCP.usInitMSS;\r
1375 UBaseType_t uxOptionsLength;\r
1376 \r
1377         /* We send out the TCP Maximum Segment Size option with our SYN[+ACK]. */\r
1378 \r
1379         pxTCPHeader->ucOptdata[ 0 ] = ( uint8_t ) TCP_OPT_MSS;\r
1380         pxTCPHeader->ucOptdata[ 1 ] = ( uint8_t ) TCP_OPT_MSS_LEN;\r
1381         pxTCPHeader->ucOptdata[ 2 ] = ( uint8_t ) ( usMSS >> 8 );\r
1382         pxTCPHeader->ucOptdata[ 3 ] = ( uint8_t ) ( usMSS & 0xffu );\r
1383 \r
1384         #if( ipconfigUSE_TCP_WIN != 0 )\r
1385         {\r
1386                 pxSocket->u.xTCP.ucMyWinScaleFactor = prvWinScaleFactor( pxSocket );\r
1387 \r
1388                 pxTCPHeader->ucOptdata[ 4 ] = TCP_OPT_NOOP;\r
1389                 pxTCPHeader->ucOptdata[ 5 ] = ( uint8_t ) ( TCP_OPT_WSOPT );\r
1390                 pxTCPHeader->ucOptdata[ 6 ] = ( uint8_t ) ( TCP_OPT_WSOPT_LEN );\r
1391                 pxTCPHeader->ucOptdata[ 7 ] = ( uint8_t ) pxSocket->u.xTCP.ucMyWinScaleFactor;\r
1392                 uxOptionsLength = 8u;\r
1393         }\r
1394         #else\r
1395         {\r
1396                 uxOptionsLength = 4u;\r
1397         }\r
1398         #endif\r
1399 \r
1400         #if( ipconfigUSE_TCP_WIN == 0 )\r
1401         {\r
1402                 return uxOptionsLength;\r
1403         }\r
1404         #else\r
1405         {\r
1406                 #if( ipconfigUSE_TCP_TIMESTAMPS == 1 )\r
1407                         if( pxSocket->u.xTCP.xTCPWindow.u.bits.bTimeStamps )\r
1408                         {\r
1409                                 uxOptionsLength += prvTCPSetTimeStamp( uxOptionsLength, pxSocket, &pxTCPPacket->xTCPHeader );\r
1410                                 pxTCPHeader->ucOptdata[ uxOptionsLength + 0 ] = TCP_OPT_SACK_P; /* 4: Sack-Permitted Option. */\r
1411                                 pxTCPHeader->ucOptdata[ uxOptionsLength + 1 ] = 2u;\r
1412                                 uxOptionsLength += 2u;\r
1413                         }\r
1414                         else\r
1415                 #endif\r
1416                 {\r
1417                         pxTCPHeader->ucOptdata[ uxOptionsLength + 0 ] = TCP_OPT_NOOP;\r
1418                         pxTCPHeader->ucOptdata[ uxOptionsLength + 1 ] = TCP_OPT_NOOP;\r
1419                         pxTCPHeader->ucOptdata[ uxOptionsLength + 2 ] = TCP_OPT_SACK_P; /* 4: Sack-Permitted Option. */\r
1420                         pxTCPHeader->ucOptdata[ uxOptionsLength + 3 ] = 2;      /* 2: length of this option. */\r
1421                         uxOptionsLength += 4u;\r
1422                 }\r
1423                 return uxOptionsLength; /* bytes, not words. */\r
1424         }\r
1425         #endif  /* ipconfigUSE_TCP_WIN == 0 */\r
1426 }\r
1427 \r
1428 /*\r
1429  * For anti-hanging protection and TCP keep-alive messages.  Called in two\r
1430  * places: after receiving a packet and after a state change.  The socket's\r
1431  * alive timer may be reset.\r
1432  */\r
1433 static void prvTCPTouchSocket( FreeRTOS_Socket_t *pxSocket )\r
1434 {\r
1435         #if( ipconfigTCP_HANG_PROTECTION == 1 )\r
1436         {\r
1437                 pxSocket->u.xTCP.xLastActTime = xTaskGetTickCount( );\r
1438         }\r
1439         #endif\r
1440 \r
1441         #if( ipconfigTCP_KEEP_ALIVE == 1 )\r
1442         {\r
1443                 pxSocket->u.xTCP.bits.bWaitKeepAlive = pdFALSE_UNSIGNED;\r
1444                 pxSocket->u.xTCP.bits.bSendKeepAlive = pdFALSE_UNSIGNED;\r
1445                 pxSocket->u.xTCP.ucKeepRepCount = 0u;\r
1446                 pxSocket->u.xTCP.xLastAliveTime = xTaskGetTickCount();\r
1447         }\r
1448         #endif\r
1449 \r
1450         ( void ) pxSocket;\r
1451 }\r
1452 /*-----------------------------------------------------------*/\r
1453 \r
1454 /*\r
1455  * Changing to a new state. Centralised here to do specific actions such as\r
1456  * resetting the alive timer, calling the user's OnConnect handler to notify\r
1457  * that a socket has got (dis)connected, and setting bit to unblock a call to\r
1458  * FreeRTOS_select()\r
1459  */\r
1460 void vTCPStateChange( FreeRTOS_Socket_t *pxSocket, enum eTCP_STATE eTCPState )\r
1461 {\r
1462 FreeRTOS_Socket_t *xParent = NULL;\r
1463 BaseType_t bBefore = ( BaseType_t ) NOW_CONNECTED( pxSocket->u.xTCP.ucTCPState );       /* Was it connected ? */\r
1464 BaseType_t bAfter  = ( BaseType_t ) NOW_CONNECTED( eTCPState );                                         /* Is it connected now ? */\r
1465 #if( ipconfigHAS_DEBUG_PRINTF != 0 )\r
1466         BaseType_t xPreviousState = ( BaseType_t ) pxSocket->u.xTCP.ucTCPState;\r
1467 #endif\r
1468 #if( ipconfigUSE_CALLBACKS == 1 )\r
1469         FreeRTOS_Socket_t *xConnected = NULL;\r
1470 #endif\r
1471 \r
1472         /* Has the connected status changed? */\r
1473         if( bBefore != bAfter )\r
1474         {\r
1475                 /* Is the socket connected now ? */\r
1476                 if( bAfter != pdFALSE )\r
1477                 {\r
1478                         /* if bPassQueued is true, this socket is an orphan until it gets connected. */\r
1479                         if( pxSocket->u.xTCP.bits.bPassQueued != pdFALSE_UNSIGNED )\r
1480                         {\r
1481                                 /* Now that it is connected, find it's parent. */\r
1482                                 if( pxSocket->u.xTCP.bits.bReuseSocket != pdFALSE_UNSIGNED )\r
1483                                 {\r
1484                                         xParent = pxSocket;\r
1485                                 }\r
1486                                 else\r
1487                                 {\r
1488                                         xParent = pxSocket->u.xTCP.pxPeerSocket;\r
1489                                         configASSERT( xParent != NULL );\r
1490                                 }\r
1491                                 if( xParent != NULL )\r
1492                                 {\r
1493                                         if( xParent->u.xTCP.pxPeerSocket == NULL )\r
1494                                         {\r
1495                                                 xParent->u.xTCP.pxPeerSocket = pxSocket;\r
1496                                         }\r
1497 \r
1498                                         xParent->xEventBits |= eSOCKET_ACCEPT;\r
1499 \r
1500                                         #if( ipconfigSUPPORT_SELECT_FUNCTION == 1 )\r
1501                                         {\r
1502                                                 /* Library support FreeRTOS_select().  Receiving a new\r
1503                                                 connection is being translated as a READ event. */\r
1504                                                 if( ( xParent->xSelectBits & eSELECT_READ ) != 0 )\r
1505                                                 {\r
1506                                                         xParent->xEventBits |= ( eSELECT_READ << SOCKET_EVENT_BIT_COUNT );\r
1507                                                 }\r
1508                                         }\r
1509                                         #endif\r
1510 \r
1511                                         #if( ipconfigUSE_CALLBACKS == 1 )\r
1512                                         {\r
1513                                                 if( ( ipconfigIS_VALID_PROG_ADDRESS( xParent->u.xTCP.pxHandleConnected ) != pdFALSE ) &&\r
1514                                                         ( xParent->u.xTCP.bits.bReuseSocket == pdFALSE_UNSIGNED ) )\r
1515                                                 {\r
1516                                                         /* The listening socket does not become connected itself, in stead\r
1517                                                         a child socket is created.\r
1518                                                         Postpone a call the OnConnect event until the end of this function. */\r
1519                                                         xConnected = xParent;\r
1520                                                 }\r
1521                                         }\r
1522                                         #endif\r
1523                                 }\r
1524 \r
1525                                 /* Don't need to access the parent socket anymore, so the\r
1526                                 reference 'pxPeerSocket' may be cleared. */\r
1527                                 pxSocket->u.xTCP.pxPeerSocket = NULL;\r
1528                                 pxSocket->u.xTCP.bits.bPassQueued = pdFALSE_UNSIGNED;\r
1529 \r
1530                                 /* When true, this socket may be returned in a call to accept(). */\r
1531                                 pxSocket->u.xTCP.bits.bPassAccept = pdTRUE_UNSIGNED;\r
1532                         }\r
1533                         else\r
1534                         {\r
1535                                 pxSocket->xEventBits |= eSOCKET_CONNECT;\r
1536 \r
1537                                 #if( ipconfigSUPPORT_SELECT_FUNCTION == 1 )\r
1538                                 {\r
1539                                         if( pxSocket->xSelectBits & eSELECT_WRITE )\r
1540                                         {\r
1541                                                 pxSocket->xEventBits |= ( eSELECT_WRITE << SOCKET_EVENT_BIT_COUNT );\r
1542                                         }\r
1543                                 }\r
1544                                 #endif\r
1545                         }\r
1546                 }\r
1547                 else  /* bAfter == pdFALSE, connection is closed. */\r
1548                 {\r
1549                         /* Notify/wake-up the socket-owner by setting a semaphore. */\r
1550                         pxSocket->xEventBits |= eSOCKET_CLOSED;\r
1551 \r
1552                         #if( ipconfigSUPPORT_SELECT_FUNCTION == 1 )\r
1553                         {\r
1554                                 if( ( pxSocket->xSelectBits & eSELECT_EXCEPT ) != 0 )\r
1555                                 {\r
1556                                         pxSocket->xEventBits |= ( eSELECT_EXCEPT << SOCKET_EVENT_BIT_COUNT );\r
1557                                 }\r
1558                         }\r
1559                         #endif\r
1560                 }\r
1561                 #if( ipconfigUSE_CALLBACKS == 1 )\r
1562                 {\r
1563                         if( ( ipconfigIS_VALID_PROG_ADDRESS( pxSocket->u.xTCP.pxHandleConnected ) != pdFALSE ) && ( xConnected == NULL ) )\r
1564                         {\r
1565                                 /* The 'connected' state has changed, call the user handler. */\r
1566                                 xConnected = pxSocket;\r
1567                         }\r
1568                 }\r
1569                 #endif /* ipconfigUSE_CALLBACKS */\r
1570 \r
1571                 if( prvTCPSocketIsActive( ( UBaseType_t ) pxSocket->u.xTCP.ucTCPState ) == pdFALSE )\r
1572                 {\r
1573                         /* Now the socket isn't in an active state anymore so it\r
1574                         won't need further attention of the IP-task.\r
1575                         Setting time-out to zero means that the socket won't get checked during\r
1576                         timer events. */\r
1577                         pxSocket->u.xTCP.usTimeout = 0u;\r
1578                 }\r
1579         }\r
1580         else\r
1581         {\r
1582                 if( eTCPState == eCLOSED )\r
1583                 {\r
1584                         /* Socket goes to status eCLOSED because of a RST.\r
1585                         When nobody owns the socket yet, delete it. */\r
1586                         if( ( pxSocket->u.xTCP.bits.bPassQueued != pdFALSE_UNSIGNED ) ||\r
1587                                 ( pxSocket->u.xTCP.bits.bPassAccept != pdFALSE_UNSIGNED ) )\r
1588                         {\r
1589                                 FreeRTOS_debug_printf( ( "vTCPStateChange: Closing socket\n" ) );\r
1590                                 if( pxSocket->u.xTCP.bits.bReuseSocket == pdFALSE_UNSIGNED )\r
1591                                 {\r
1592                                         FreeRTOS_closesocket( pxSocket );\r
1593                                 }\r
1594                         }\r
1595                 }\r
1596         }\r
1597 \r
1598         /* Fill in the new state. */\r
1599         pxSocket->u.xTCP.ucTCPState = ( uint8_t ) eTCPState;\r
1600 \r
1601         /* Touch the alive timers because moving to another state. */\r
1602         prvTCPTouchSocket( pxSocket );\r
1603 \r
1604         #if( ipconfigHAS_DEBUG_PRINTF == 1 )\r
1605         {\r
1606         if( ( xTCPWindowLoggingLevel >= 0 ) && ( ipconfigTCP_MAY_LOG_PORT( pxSocket->usLocalPort ) != pdFALSE ) )\r
1607                 FreeRTOS_debug_printf( ( "Socket %d -> %lxip:%u State %s->%s\n",\r
1608                         pxSocket->usLocalPort,\r
1609                         pxSocket->u.xTCP.ulRemoteIP,\r
1610                         pxSocket->u.xTCP.usRemotePort,\r
1611                         FreeRTOS_GetTCPStateName( ( UBaseType_t ) xPreviousState ),\r
1612                         FreeRTOS_GetTCPStateName( ( UBaseType_t ) eTCPState ) ) );\r
1613         }\r
1614         #endif /* ipconfigHAS_DEBUG_PRINTF */\r
1615 \r
1616         #if( ipconfigUSE_CALLBACKS == 1 )\r
1617         {\r
1618                 if( xConnected != NULL )\r
1619                 {\r
1620                         /* The 'connected' state has changed, call the OnConnect handler of the parent. */\r
1621                         xConnected->u.xTCP.pxHandleConnected( ( Socket_t * ) xConnected, bAfter );\r
1622                 }\r
1623         }\r
1624         #endif\r
1625         if( xParent != NULL )\r
1626         {\r
1627                 vSocketWakeUpUser( xParent );\r
1628         }\r
1629 }\r
1630 /*-----------------------------------------------------------*/\r
1631 \r
1632 static NetworkBufferDescriptor_t *prvTCPBufferResize( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer,\r
1633         int32_t lDataLen, UBaseType_t uxOptionsLength )\r
1634 {\r
1635 NetworkBufferDescriptor_t *pxReturn;\r
1636 int32_t lNeeded;\r
1637 BaseType_t xResize;\r
1638 \r
1639         if( xBufferAllocFixedSize != pdFALSE )\r
1640         {\r
1641                 /* Network buffers are created with a fixed size and can hold the largest\r
1642                 MTU. */\r
1643                 lNeeded = ( int32_t ) ipTOTAL_ETHERNET_FRAME_SIZE;\r
1644                 /* and therefore, the buffer won't be too small.\r
1645                 Only ask for a new network buffer in case none was supplied. */\r
1646                 xResize = ( pxNetworkBuffer == NULL );\r
1647         }\r
1648         else\r
1649         {\r
1650                 /* Network buffers are created with a variable size. See if it must\r
1651                 grow. */\r
1652                 lNeeded = FreeRTOS_max_int32( ( int32_t ) sizeof( pxSocket->u.xTCP.xPacket.u.ucLastPacket ),\r
1653                         ( int32_t ) ( ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength ) + lDataLen );\r
1654                 /* In case we were called from a TCP timer event, a buffer must be\r
1655                 created.  Otherwise, test 'xDataLength' of the provided buffer. */\r
1656                 if( ( pxNetworkBuffer == NULL ) || ( pxNetworkBuffer->xDataLength < (size_t)lNeeded ) )\r
1657                 {\r
1658                         xResize = pdTRUE;\r
1659                 }\r
1660                 else\r
1661                 {\r
1662                         xResize = pdFALSE;\r
1663                 }\r
1664         }\r
1665 \r
1666         if( xResize != pdFALSE )\r
1667         {\r
1668                 /* The caller didn't provide a network buffer or the provided buffer is\r
1669                 too small.  As we must send-out a data packet, a buffer will be created\r
1670                 here. */\r
1671                 pxReturn = pxGetNetworkBufferWithDescriptor( ( uint32_t ) lNeeded, 0u );\r
1672 \r
1673                 if( pxReturn != NULL )\r
1674                 {\r
1675                         /* Copy the existing data to the new created buffer. */\r
1676                         if( pxNetworkBuffer )\r
1677                         {\r
1678                                 /* Either from the previous buffer... */\r
1679                                 memcpy( pxReturn->pucEthernetBuffer, pxNetworkBuffer->pucEthernetBuffer, pxNetworkBuffer->xDataLength );\r
1680 \r
1681                                 /* ...and release it. */\r
1682                                 vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );\r
1683                         }\r
1684                         else\r
1685                         {\r
1686                                 /* Or from the socket field 'xTCP.xPacket'. */\r
1687                                 memcpy( pxReturn->pucEthernetBuffer, pxSocket->u.xTCP.xPacket.u.ucLastPacket, sizeof( pxSocket->u.xTCP.xPacket.u.ucLastPacket ) );\r
1688                         }\r
1689                 }\r
1690         }\r
1691         else\r
1692         {\r
1693                 /* xResize is false, the network buffer provided was big enough. */\r
1694                 pxReturn = pxNetworkBuffer;\r
1695 \r
1696                 /* Thanks to Andrey Ivanov from swissEmbedded for reporting that the\r
1697                 xDataLength member must get the correct length too! */\r
1698                 pxNetworkBuffer->xDataLength = ( size_t ) ( ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength ) + ( size_t ) lDataLen;\r
1699         }\r
1700 \r
1701         return pxReturn;\r
1702 }\r
1703 /*-----------------------------------------------------------*/\r
1704 \r
1705 /*\r
1706  * Prepare an outgoing message, in case anything has to be sent.\r
1707  */\r
1708 static int32_t prvTCPPrepareSend( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer, UBaseType_t uxOptionsLength )\r
1709 {\r
1710 int32_t lDataLen;\r
1711 uint8_t *pucEthernetBuffer, *pucSendData;\r
1712 TCPPacket_t *pxTCPPacket;\r
1713 size_t uxOffset;\r
1714 uint32_t ulDataGot, ulDistance;\r
1715 TCPWindow_t *pxTCPWindow;\r
1716 NetworkBufferDescriptor_t *pxNewBuffer;\r
1717 int32_t lStreamPos;\r
1718 \r
1719         if( ( *ppxNetworkBuffer ) != NULL )\r
1720         {\r
1721                 /* A network buffer descriptor was already supplied */\r
1722                 pucEthernetBuffer = ( *ppxNetworkBuffer )->pucEthernetBuffer;\r
1723         }\r
1724         else\r
1725         {\r
1726                 /* For now let it point to the last packet header */\r
1727                 pucEthernetBuffer = pxSocket->u.xTCP.xPacket.u.ucLastPacket;\r
1728         }\r
1729 \r
1730         pxTCPPacket = ( TCPPacket_t * ) pucEthernetBuffer;\r
1731         pxTCPWindow = &( pxSocket->u.xTCP.xTCPWindow );\r
1732         lDataLen = 0;\r
1733         lStreamPos = 0;\r
1734         pxTCPPacket->xTCPHeader.ucTCPFlags |= ipTCP_FLAG_ACK;\r
1735 \r
1736         if( pxSocket->u.xTCP.txStream != NULL )\r
1737         {\r
1738                 /* ulTCPWindowTxGet will return the amount of data which may be sent\r
1739                 along with the position in the txStream.\r
1740                 Why check for MSS > 1 ?\r
1741                 Because some TCP-stacks (like uIP) use it for flow-control. */\r
1742                 if( pxSocket->u.xTCP.usCurMSS > 1u )\r
1743                 {\r
1744                         lDataLen = ( int32_t ) ulTCPWindowTxGet( pxTCPWindow, pxSocket->u.xTCP.ulWindowSize, &lStreamPos );\r
1745                 }\r
1746 \r
1747                 if( lDataLen > 0 )\r
1748                 {\r
1749                         /* Check if the current network buffer is big enough, if not,\r
1750                         resize it. */\r
1751                         pxNewBuffer = prvTCPBufferResize( pxSocket, *ppxNetworkBuffer, lDataLen, uxOptionsLength );\r
1752 \r
1753                         if( pxNewBuffer != NULL )\r
1754                         {\r
1755                                 *ppxNetworkBuffer = pxNewBuffer;\r
1756                                 pucEthernetBuffer = pxNewBuffer->pucEthernetBuffer;\r
1757                                 pxTCPPacket = ( TCPPacket_t * ) ( pucEthernetBuffer );\r
1758 \r
1759                                 pucSendData = pucEthernetBuffer + ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength;\r
1760 \r
1761                                 /* Translate the position in txStream to an offset from the tail\r
1762                                 marker. */\r
1763                                 uxOffset = uxStreamBufferDistance( pxSocket->u.xTCP.txStream, pxSocket->u.xTCP.txStream->uxTail, ( size_t ) lStreamPos );\r
1764 \r
1765                                 /* Here data is copied from the txStream in 'peek' mode.  Only\r
1766                                 when the packets are acked, the tail marker will be updated. */\r
1767                                 ulDataGot = ( uint32_t ) uxStreamBufferGet( pxSocket->u.xTCP.txStream, uxOffset, pucSendData, ( size_t ) lDataLen, pdTRUE );\r
1768 \r
1769                                 #if( ipconfigHAS_DEBUG_PRINTF != 0 )\r
1770                                 {\r
1771                                         if( ulDataGot != ( uint32_t ) lDataLen )\r
1772                                         {\r
1773                                                 FreeRTOS_debug_printf( ( "uxStreamBufferGet: pos %lu offs %lu only %lu != %lu\n",\r
1774                                                         lStreamPos, uxOffset, ulDataGot, lDataLen ) );\r
1775                                         }\r
1776                                 }\r
1777                                 #endif\r
1778 \r
1779                                 /* If the owner of the socket requests a closure, add the FIN\r
1780                                 flag to the last packet. */\r
1781                                 if( ( pxSocket->u.xTCP.bits.bCloseRequested != pdFALSE_UNSIGNED ) && ( pxSocket->u.xTCP.bits.bFinSent == pdFALSE_UNSIGNED ) )\r
1782                                 {\r
1783                                         ulDistance = ( uint32_t ) uxStreamBufferDistance( pxSocket->u.xTCP.txStream, ( size_t ) lStreamPos, pxSocket->u.xTCP.txStream->uxHead );\r
1784 \r
1785                                         if( ulDistance == ulDataGot )\r
1786                                         {\r
1787                                                 #if (ipconfigHAS_DEBUG_PRINTF == 1)\r
1788                                                 {\r
1789                                                 /* the order of volatile accesses is undefined\r
1790                                                         so such workaround */\r
1791                                                         size_t uxHead = pxSocket->u.xTCP.txStream->uxHead;\r
1792                                                         size_t uxMid = pxSocket->u.xTCP.txStream->uxMid;\r
1793                                                         size_t uxTail = pxSocket->u.xTCP.txStream->uxTail;\r
1794 \r
1795                                                         FreeRTOS_debug_printf( ( "CheckClose %lu <= %lu (%lu <= %lu <= %lu)\n", ulDataGot, ulDistance,\r
1796                                                                 uxTail, uxMid, uxHead ) );\r
1797                                                 }\r
1798                                                 #endif\r
1799                                                 /* Although the socket sends a FIN, it will stay in\r
1800                                                 ESTABLISHED until all current data has been received or\r
1801                                                 delivered. */\r
1802                                                 pxTCPPacket->xTCPHeader.ucTCPFlags |= ipTCP_FLAG_FIN;\r
1803                                                 pxTCPWindow->tx.ulFINSequenceNumber = pxTCPWindow->ulOurSequenceNumber + ( uint32_t ) lDataLen;\r
1804                                                 pxSocket->u.xTCP.bits.bFinSent = pdTRUE_UNSIGNED;\r
1805                                         }\r
1806                                 }\r
1807                         }\r
1808                         else\r
1809                         {\r
1810                                 lDataLen = -1;\r
1811                         }\r
1812                 }\r
1813         }\r
1814 \r
1815         if( ( lDataLen >= 0 ) && ( pxSocket->u.xTCP.ucTCPState == eESTABLISHED ) )\r
1816         {\r
1817                 /* See if the socket owner wants to shutdown this connection. */\r
1818                 if( ( pxSocket->u.xTCP.bits.bUserShutdown != pdFALSE_UNSIGNED ) &&\r
1819                         ( xTCPWindowTxDone( pxTCPWindow ) != pdFALSE ) )\r
1820                 {\r
1821                         pxSocket->u.xTCP.bits.bUserShutdown = pdFALSE_UNSIGNED;\r
1822                         pxTCPPacket->xTCPHeader.ucTCPFlags |= ipTCP_FLAG_FIN;\r
1823                         pxSocket->u.xTCP.bits.bFinSent = pdTRUE_UNSIGNED;\r
1824                         pxSocket->u.xTCP.bits.bWinChange = pdTRUE_UNSIGNED;\r
1825                         pxTCPWindow->tx.ulFINSequenceNumber = pxTCPWindow->tx.ulCurrentSequenceNumber;\r
1826                         vTCPStateChange( pxSocket, eFIN_WAIT_1 );\r
1827                 }\r
1828 \r
1829                 #if( ipconfigTCP_KEEP_ALIVE != 0 )\r
1830                 {\r
1831                         if( pxSocket->u.xTCP.ucKeepRepCount > 3u )\r
1832                         {\r
1833                                 FreeRTOS_debug_printf( ( "keep-alive: giving up %lxip:%u\n",\r
1834                                         pxSocket->u.xTCP.ulRemoteIP,                    /* IP address of remote machine. */\r
1835                                         pxSocket->u.xTCP.usRemotePort ) );      /* Port on remote machine. */\r
1836                                 vTCPStateChange( pxSocket, eCLOSE_WAIT );\r
1837                                 lDataLen = -1;\r
1838                         }\r
1839                         if( ( lDataLen == 0 ) && ( pxSocket->u.xTCP.bits.bWinChange == pdFALSE_UNSIGNED ) )\r
1840                         {\r
1841                                 /* If there is no data to be sent, and no window-update message,\r
1842                                 we might want to send a keep-alive message. */\r
1843                                 TickType_t xAge = xTaskGetTickCount( ) - pxSocket->u.xTCP.xLastAliveTime;\r
1844                                 TickType_t xMax;\r
1845                                 xMax = ( ( TickType_t ) ipconfigTCP_KEEP_ALIVE_INTERVAL * configTICK_RATE_HZ );\r
1846                                 if( pxSocket->u.xTCP.ucKeepRepCount )\r
1847                                 {\r
1848                                         xMax = ( 3u * configTICK_RATE_HZ );\r
1849                                 }\r
1850                                 if( xAge > xMax )\r
1851                                 {\r
1852                                         pxSocket->u.xTCP.xLastAliveTime = xTaskGetTickCount( );\r
1853                                         if( xTCPWindowLoggingLevel )\r
1854                                                 FreeRTOS_debug_printf( ( "keep-alive: %lxip:%u count %u\n",\r
1855                                                         pxSocket->u.xTCP.ulRemoteIP,\r
1856                                                         pxSocket->u.xTCP.usRemotePort,\r
1857                                                         pxSocket->u.xTCP.ucKeepRepCount ) );\r
1858                                         pxSocket->u.xTCP.bits.bSendKeepAlive = pdTRUE_UNSIGNED;\r
1859                                         pxSocket->u.xTCP.usTimeout = ( ( uint16_t ) pdMS_TO_TICKS( 2500 ) );\r
1860                                         pxSocket->u.xTCP.ucKeepRepCount++;\r
1861                                 }\r
1862                         }\r
1863                 }\r
1864                 #endif /* ipconfigTCP_KEEP_ALIVE */\r
1865         }\r
1866 \r
1867         /* Anything to send, a change of the advertised window size, or maybe send a\r
1868         keep-alive message? */\r
1869         if( ( lDataLen > 0 ) ||\r
1870                 ( pxSocket->u.xTCP.bits.bWinChange != pdFALSE_UNSIGNED ) ||\r
1871                 ( pxSocket->u.xTCP.bits.bSendKeepAlive != pdFALSE_UNSIGNED ) )\r
1872         {\r
1873                 pxTCPPacket->xTCPHeader.ucTCPFlags &= ( ( uint8_t ) ~ipTCP_FLAG_PSH );\r
1874                 pxTCPPacket->xTCPHeader.ucTCPOffset = ( uint8_t )( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 );\r
1875 \r
1876                 pxTCPPacket->xTCPHeader.ucTCPFlags |= ( uint8_t ) ipTCP_FLAG_ACK;\r
1877 \r
1878                 if( lDataLen != 0l )\r
1879                 {\r
1880                         pxTCPPacket->xTCPHeader.ucTCPFlags |= ( uint8_t ) ipTCP_FLAG_PSH;\r
1881                 }\r
1882 \r
1883                 #if     ipconfigUSE_TCP_TIMESTAMPS == 1\r
1884                 {\r
1885                         if( uxOptionsLength == 0u )\r
1886                         {\r
1887                                 if( pxSocket->u.xTCP.xTCPWindow.u.bits.bTimeStamps )\r
1888                                 {\r
1889                                         TCPPacket_t * pxTCPPacket = ( TCPPacket_t * ) ( pucEthernetBuffer );\r
1890                                         uxOptionsLength = prvTCPSetTimeStamp( 0, pxSocket, &pxTCPPacket->xTCPHeader );\r
1891                                 }\r
1892                         }\r
1893                 }\r
1894                 #endif\r
1895 \r
1896                 lDataLen += ( int32_t ) ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength );\r
1897         }\r
1898 \r
1899         return lDataLen;\r
1900 }\r
1901 /*-----------------------------------------------------------*/\r
1902 \r
1903 /*\r
1904  * Calculate after how much time this socket needs to be checked again.\r
1905  */\r
1906 static TickType_t prvTCPNextTimeout ( FreeRTOS_Socket_t *pxSocket )\r
1907 {\r
1908 TickType_t ulDelayMs = ( TickType_t ) tcpMAXIMUM_TCP_WAKEUP_TIME_MS;\r
1909 \r
1910         if( pxSocket->u.xTCP.ucTCPState == eCONNECT_SYN )\r
1911         {\r
1912                 /* The socket is actively connecting to a peer. */\r
1913                 if( pxSocket->u.xTCP.bits.bConnPrepared )\r
1914                 {\r
1915                         /* Ethernet address has been found, use progressive timeout for\r
1916                         active connect(). */\r
1917                         if( pxSocket->u.xTCP.ucRepCount < 3u )\r
1918                         {\r
1919                                 ulDelayMs = ( 3000UL << ( pxSocket->u.xTCP.ucRepCount - 1u ) );\r
1920                         }\r
1921                         else\r
1922                         {\r
1923                                 ulDelayMs = 11000UL;\r
1924                         }\r
1925                 }\r
1926                 else\r
1927                 {\r
1928                         /* Still in the ARP phase: check every half second. */\r
1929                         ulDelayMs = 500UL;\r
1930                 }\r
1931 \r
1932                 FreeRTOS_debug_printf( ( "Connect[%lxip:%u]: next timeout %u: %lu ms\n",\r
1933                         pxSocket->u.xTCP.ulRemoteIP, pxSocket->u.xTCP.usRemotePort,\r
1934                         pxSocket->u.xTCP.ucRepCount, ulDelayMs ) );\r
1935                 pxSocket->u.xTCP.usTimeout = ( uint16_t )pdMS_TO_MIN_TICKS( ulDelayMs );\r
1936         }\r
1937         else if( pxSocket->u.xTCP.usTimeout == 0u )\r
1938         {\r
1939                 /* Let the sliding window mechanism decide what time-out is appropriate. */\r
1940                 BaseType_t xResult = xTCPWindowTxHasData( &pxSocket->u.xTCP.xTCPWindow, pxSocket->u.xTCP.ulWindowSize, &ulDelayMs );\r
1941                 if( ulDelayMs == 0u )\r
1942                 {\r
1943                         if( xResult != ( BaseType_t )0 )\r
1944                         {\r
1945                                 ulDelayMs = 1UL;\r
1946                         }\r
1947                         else\r
1948                         {\r
1949                                 ulDelayMs = tcpMAXIMUM_TCP_WAKEUP_TIME_MS;\r
1950                         }\r
1951                 }\r
1952                 else\r
1953                 {\r
1954                         /* ulDelayMs contains the time to wait before a re-transmission. */\r
1955                 }\r
1956                 pxSocket->u.xTCP.usTimeout = ( uint16_t )pdMS_TO_MIN_TICKS( ulDelayMs );\r
1957         }\r
1958         else\r
1959         {\r
1960                 /* field '.usTimeout' has already been set (by the\r
1961                 keep-alive/delayed-ACK mechanism). */\r
1962         }\r
1963 \r
1964         /* Return the number of clock ticks before the timer expires. */\r
1965         return ( TickType_t ) pxSocket->u.xTCP.usTimeout;\r
1966 }\r
1967 /*-----------------------------------------------------------*/\r
1968 \r
1969 static void prvTCPAddTxData( FreeRTOS_Socket_t *pxSocket )\r
1970 {\r
1971 int32_t lCount, lLength;\r
1972 \r
1973         /* A txStream has been created already, see if the socket has new data for\r
1974         the sliding window.\r
1975 \r
1976         uxStreamBufferMidSpace() returns the distance between rxHead and rxMid.  It\r
1977         contains new Tx data which has not been passed to the sliding window yet.\r
1978         The oldest data not-yet-confirmed can be found at rxTail. */\r
1979         lLength = ( int32_t ) uxStreamBufferMidSpace( pxSocket->u.xTCP.txStream );\r
1980 \r
1981         if( lLength > 0 )\r
1982         {\r
1983                 /* All data between txMid and rxHead will now be passed to the sliding\r
1984                 window manager, so it can start transmitting them.\r
1985 \r
1986                 Hand over the new data to the sliding window handler.  It will be\r
1987                 split-up in chunks of 1460 bytes each (or less, depending on\r
1988                 ipconfigTCP_MSS). */\r
1989                 lCount = lTCPWindowTxAdd(       &pxSocket->u.xTCP.xTCPWindow,\r
1990                                                                 ( uint32_t ) lLength,\r
1991                                                                 ( int32_t ) pxSocket->u.xTCP.txStream->uxMid,\r
1992                                                                 ( int32_t ) pxSocket->u.xTCP.txStream->LENGTH );\r
1993 \r
1994                 /* Move the rxMid pointer forward up to rxHead. */\r
1995                 if( lCount > 0 )\r
1996                 {\r
1997                         vStreamBufferMoveMid( pxSocket->u.xTCP.txStream, ( size_t ) lCount );\r
1998                 }\r
1999         }\r
2000 }\r
2001 /*-----------------------------------------------------------*/\r
2002 \r
2003 /*\r
2004  * prvTCPHandleFin() will be called to handle socket closure\r
2005  * The Closure starts when either a FIN has been received and accepted,\r
2006  * Or when the socket has sent a FIN flag to the peer\r
2007  * Before being called, it has been checked that both reception and transmission\r
2008  * are complete.\r
2009  */\r
2010 static BaseType_t prvTCPHandleFin( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer )\r
2011 {\r
2012 TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );\r
2013 TCPHeader_t *pxTCPHeader = &pxTCPPacket->xTCPHeader;\r
2014 uint8_t ucTCPFlags = pxTCPHeader->ucTCPFlags;\r
2015 TCPWindow_t *pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow;\r
2016 BaseType_t xSendLength = 0;\r
2017 uint32_t ulAckNr = FreeRTOS_ntohl( pxTCPHeader->ulAckNr );\r
2018 \r
2019         if( ( ucTCPFlags & ipTCP_FLAG_FIN ) != 0u )\r
2020         {\r
2021                 pxTCPWindow->rx.ulCurrentSequenceNumber = pxTCPWindow->rx.ulFINSequenceNumber + 1u;\r
2022         }\r
2023         if( pxSocket->u.xTCP.bits.bFinSent == pdFALSE_UNSIGNED )\r
2024         {\r
2025                 /* We haven't yet replied with a FIN, do so now. */\r
2026                 pxTCPWindow->tx.ulFINSequenceNumber = pxTCPWindow->tx.ulCurrentSequenceNumber;\r
2027                 pxSocket->u.xTCP.bits.bFinSent = pdTRUE_UNSIGNED;\r
2028         }\r
2029         else\r
2030         {\r
2031                 /* We did send a FIN already, see if it's ACK'd. */\r
2032                 if( ulAckNr == pxTCPWindow->tx.ulFINSequenceNumber + 1u )\r
2033                 {\r
2034                         pxSocket->u.xTCP.bits.bFinAcked = pdTRUE_UNSIGNED;\r
2035                 }\r
2036         }\r
2037 \r
2038         if( pxSocket->u.xTCP.bits.bFinAcked == pdFALSE_UNSIGNED )\r
2039         {\r
2040                 pxTCPWindow->tx.ulCurrentSequenceNumber = pxTCPWindow->tx.ulFINSequenceNumber;\r
2041                 pxTCPHeader->ucTCPFlags = ipTCP_FLAG_ACK | ipTCP_FLAG_FIN;\r
2042 \r
2043                 /* And wait for the final ACK. */\r
2044                 vTCPStateChange( pxSocket, eLAST_ACK );\r
2045         }\r
2046         else\r
2047         {\r
2048                 /* Our FIN has been ACK'd, the outgoing sequence number is now fixed. */\r
2049                 pxTCPWindow->tx.ulCurrentSequenceNumber = pxTCPWindow->tx.ulFINSequenceNumber + 1u;\r
2050                 if( pxSocket->u.xTCP.bits.bFinRecv == pdFALSE_UNSIGNED )\r
2051                 {\r
2052                         /* We have sent out a FIN but the peer hasn't replied with a FIN\r
2053                         yet. Do nothing for the moment. */\r
2054                         pxTCPHeader->ucTCPFlags = 0u;\r
2055                 }\r
2056                 else\r
2057                 {\r
2058                         if( pxSocket->u.xTCP.bits.bFinLast == pdFALSE_UNSIGNED )\r
2059                         {\r
2060                                 /* This is the third of the three-way hand shake: the last\r
2061                                 ACK. */\r
2062                                 pxTCPHeader->ucTCPFlags = ipTCP_FLAG_ACK;\r
2063                         }\r
2064                         else\r
2065                         {\r
2066                                 /* The other party started the closure, so we just wait for the\r
2067                                 last ACK. */\r
2068                                 pxTCPHeader->ucTCPFlags = 0u;\r
2069                         }\r
2070 \r
2071                         /* And wait for the user to close this socket. */\r
2072                         vTCPStateChange( pxSocket, eCLOSE_WAIT );\r
2073                 }\r
2074         }\r
2075 \r
2076         pxTCPWindow->ulOurSequenceNumber = pxTCPWindow->tx.ulCurrentSequenceNumber;\r
2077 \r
2078         if( pxTCPHeader->ucTCPFlags != 0u )\r
2079         {\r
2080                 xSendLength = ( BaseType_t ) ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + pxTCPWindow->ucOptionLength );\r
2081         }\r
2082 \r
2083         pxTCPHeader->ucTCPOffset = ( uint8_t ) ( ( ipSIZE_OF_TCP_HEADER + pxTCPWindow->ucOptionLength ) << 2 );\r
2084 \r
2085         if( xTCPWindowLoggingLevel != 0 )\r
2086         {\r
2087                 FreeRTOS_debug_printf( ( "TCP: send FIN+ACK (ack %lu, cur/nxt %lu/%lu) ourSeqNr %lu | Rx %lu\n",\r
2088                         ulAckNr - pxTCPWindow->tx.ulFirstSequenceNumber,\r
2089                         pxTCPWindow->tx.ulCurrentSequenceNumber - pxTCPWindow->tx.ulFirstSequenceNumber,\r
2090                         pxTCPWindow->ulNextTxSequenceNumber - pxTCPWindow->tx.ulFirstSequenceNumber,\r
2091                         pxTCPWindow->ulOurSequenceNumber - pxTCPWindow->tx.ulFirstSequenceNumber,\r
2092                         pxTCPWindow->rx.ulCurrentSequenceNumber - pxTCPWindow->rx.ulFirstSequenceNumber ) );\r
2093         }\r
2094 \r
2095         return xSendLength;\r
2096 }\r
2097 /*-----------------------------------------------------------*/\r
2098 \r
2099 #if     ipconfigUSE_TCP_TIMESTAMPS == 1\r
2100 \r
2101         static UBaseType_t prvTCPSetTimeStamp( BaseType_t lOffset, FreeRTOS_Socket_t *pxSocket, TCPHeader_t *pxTCPHeader )\r
2102         {\r
2103         uint32_t ulTimes[2];\r
2104         uint8_t *ucOptdata = &( pxTCPHeader->ucOptdata[ lOffset ] );\r
2105 \r
2106                 ulTimes[0]   = ( xTaskGetTickCount ( ) * 1000u ) / configTICK_RATE_HZ;\r
2107                 ulTimes[0]   = FreeRTOS_htonl( ulTimes[0] );\r
2108                 ulTimes[1]   = FreeRTOS_htonl( pxSocket->u.xTCP.xTCPWindow.rx.ulTimeStamp );\r
2109                 ucOptdata[0] = ( uint8_t ) TCP_OPT_TIMESTAMP;\r
2110                 ucOptdata[1] = ( uint8_t ) TCP_OPT_TIMESTAMP_LEN;\r
2111                 memcpy( &(ucOptdata[2] ), ulTimes, 8u );\r
2112                 ucOptdata[10] = ( uint8_t ) TCP_OPT_NOOP;\r
2113                 ucOptdata[11] = ( uint8_t ) TCP_OPT_NOOP;\r
2114                 /* Do not return the same timestamps 2 times. */\r
2115                 pxSocket->u.xTCP.xTCPWindow.rx.ulTimeStamp = 0ul;\r
2116                 return 12u;\r
2117         }\r
2118 \r
2119 #endif\r
2120 /*-----------------------------------------------------------*/\r
2121 \r
2122 /*\r
2123  * prvCheckRxData(): called from prvTCPHandleState()\r
2124  *\r
2125  * The first thing that will be done is find the TCP payload data\r
2126  * and check the length of this data.\r
2127  */\r
2128 static BaseType_t prvCheckRxData( NetworkBufferDescriptor_t *pxNetworkBuffer, uint8_t **ppucRecvData )\r
2129 {\r
2130 TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );\r
2131 TCPHeader_t *pxTCPHeader = &( pxTCPPacket->xTCPHeader );\r
2132 int32_t lLength, lTCPHeaderLength, lReceiveLength, lUrgentLength;\r
2133 \r
2134         /* Determine the length and the offset of the user-data sent to this\r
2135         node.\r
2136 \r
2137         The size of the TCP header is given in a multiple of 4-byte words (single\r
2138         byte, needs no ntoh() translation).  A shift-right 2: is the same as\r
2139         (offset >> 4) * 4. */\r
2140     lTCPHeaderLength = ( BaseType_t ) ( ( pxTCPHeader->ucTCPOffset & VALID_BITS_IN_TCP_OFFSET_BYTE ) >> 2 );\r
2141 \r
2142         /* Let pucRecvData point to the first byte received. */\r
2143         *ppucRecvData = pxNetworkBuffer->pucEthernetBuffer + ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv4_HEADER + lTCPHeaderLength;\r
2144 \r
2145         /* Calculate lReceiveLength - the length of the TCP data received.  This is\r
2146         equal to the total packet length minus:\r
2147         ( LinkLayer length (14) + IP header length (20) + size of TCP header(20 +) ).*/\r
2148         lReceiveLength = ( ( int32_t ) pxNetworkBuffer->xDataLength ) - ( int32_t ) ipSIZE_OF_ETH_HEADER;\r
2149         lLength =  ( int32_t )FreeRTOS_htons( pxTCPPacket->xIPHeader.usLength );\r
2150 \r
2151         if( lReceiveLength > lLength )\r
2152         {\r
2153                 /* More bytes were received than the reported length, often because of\r
2154                 padding bytes at the end. */\r
2155                 lReceiveLength = lLength;\r
2156         }\r
2157 \r
2158         /* Subtract the size of the TCP and IP headers and the actual data size is\r
2159         known. */\r
2160         if( lReceiveLength > ( lTCPHeaderLength + ( int32_t ) ipSIZE_OF_IPv4_HEADER ) )\r
2161         {\r
2162                 lReceiveLength -= ( lTCPHeaderLength + ( int32_t ) ipSIZE_OF_IPv4_HEADER );\r
2163         }\r
2164         else\r
2165         {\r
2166                 lReceiveLength = 0;\r
2167         }\r
2168 \r
2169         /* Urgent Pointer:\r
2170         This field communicates the current value of the urgent pointer as a\r
2171         positive offset from the sequence number in this segment.  The urgent\r
2172         pointer points to the sequence number of the octet following the urgent\r
2173         data.  This field is only be interpreted in segments with the URG control\r
2174         bit set. */\r
2175         if( ( pxTCPHeader->ucTCPFlags & ipTCP_FLAG_URG ) != 0u )\r
2176         {\r
2177                 /* Although we ignore the urgent data, we have to skip it. */\r
2178                 lUrgentLength = ( int32_t ) FreeRTOS_htons( pxTCPHeader->usUrgent );\r
2179                 *ppucRecvData += lUrgentLength;\r
2180                 lReceiveLength -= FreeRTOS_min_int32( lReceiveLength, lUrgentLength );\r
2181         }\r
2182 \r
2183         return ( BaseType_t ) lReceiveLength;\r
2184 }\r
2185 /*-----------------------------------------------------------*/\r
2186 \r
2187 /*\r
2188  * prvStoreRxData(): called from prvTCPHandleState()\r
2189  *\r
2190  * The second thing is to do is check if the payload data may be accepted\r
2191  * If so, they will be added to the reception queue.\r
2192  */\r
2193 static BaseType_t prvStoreRxData( FreeRTOS_Socket_t *pxSocket, uint8_t *pucRecvData,\r
2194         NetworkBufferDescriptor_t *pxNetworkBuffer, uint32_t ulReceiveLength )\r
2195 {\r
2196 TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );\r
2197 TCPHeader_t *pxTCPHeader = &pxTCPPacket->xTCPHeader;\r
2198 TCPWindow_t *pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow;\r
2199 uint32_t ulSequenceNumber, ulSpace;\r
2200 int32_t lOffset, lStored;\r
2201 BaseType_t xResult = 0;\r
2202 \r
2203         ulSequenceNumber = FreeRTOS_ntohl( pxTCPHeader->ulSequenceNumber );\r
2204 \r
2205         if( ( ulReceiveLength > 0u ) && ( pxSocket->u.xTCP.ucTCPState >= eSYN_RECEIVED ) )\r
2206         {\r
2207                 /* See if way may accept the data contents and forward it to the socket\r
2208                 owner.\r
2209 \r
2210                 If it can't be "accept"ed it may have to be stored and send a selective\r
2211                 ack (SACK) option to confirm it.  In that case, xTCPWindowRxStore() will be\r
2212                 called later to store an out-of-order packet (in case lOffset is\r
2213                 negative). */\r
2214                 if ( pxSocket->u.xTCP.rxStream )\r
2215                 {\r
2216                         ulSpace = ( uint32_t )uxStreamBufferGetSpace ( pxSocket->u.xTCP.rxStream );\r
2217                 }\r
2218                 else\r
2219                 {\r
2220                         ulSpace = ( uint32_t )pxSocket->u.xTCP.uxRxStreamSize;\r
2221                 }\r
2222 \r
2223                 lOffset = lTCPWindowRxCheck( pxTCPWindow, ulSequenceNumber, ulReceiveLength, ulSpace );\r
2224 \r
2225                 if( lOffset >= 0 )\r
2226                 {\r
2227                         /* New data has arrived and may be made available to the user.  See\r
2228                         if the head marker in rxStream may be advanced, only if lOffset == 0.\r
2229                         In case the low-water mark is reached, bLowWater will be set\r
2230                         "low-water" here stands for "little space". */\r
2231                         lStored = lTCPAddRxdata( pxSocket, ( uint32_t ) lOffset, pucRecvData, ulReceiveLength );\r
2232 \r
2233                         if( lStored != ( int32_t ) ulReceiveLength )\r
2234                         {\r
2235                                 FreeRTOS_debug_printf( ( "lTCPAddRxdata: stored %ld / %lu bytes??\n", lStored, ulReceiveLength ) );\r
2236 \r
2237                                 /* Received data could not be stored.  The socket's flag\r
2238                                 bMallocError has been set.  The socket now has the status\r
2239                                 eCLOSE_WAIT and a RST packet will be sent back. */\r
2240                                 prvTCPSendReset( pxNetworkBuffer );\r
2241                                 xResult = -1;\r
2242                         }\r
2243                 }\r
2244 \r
2245                 /* After a missing packet has come in, higher packets may be passed to\r
2246                 the user. */\r
2247                 #if( ipconfigUSE_TCP_WIN == 1 )\r
2248                 {\r
2249                         /* Now lTCPAddRxdata() will move the rxHead pointer forward\r
2250                         so data becomes available to the user immediately\r
2251                         In case the low-water mark is reached, bLowWater will be set. */\r
2252                         if( ( xResult == 0 ) && ( pxTCPWindow->ulUserDataLength > 0 ) )\r
2253                         {\r
2254                                 lTCPAddRxdata( pxSocket, 0ul, NULL, pxTCPWindow->ulUserDataLength );\r
2255                                 pxTCPWindow->ulUserDataLength = 0;\r
2256                         }\r
2257                 }\r
2258                 #endif /* ipconfigUSE_TCP_WIN */\r
2259         }\r
2260         else\r
2261         {\r
2262                 pxTCPWindow->ucOptionLength = 0u;\r
2263         }\r
2264 \r
2265         return xResult;\r
2266 }\r
2267 /*-----------------------------------------------------------*/\r
2268 \r
2269 /* Set the TCP options (if any) for the outgoing packet. */\r
2270 static UBaseType_t prvSetOptions( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer )\r
2271 {\r
2272 TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );\r
2273 TCPHeader_t *pxTCPHeader = &pxTCPPacket->xTCPHeader;\r
2274 TCPWindow_t *pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow;\r
2275 UBaseType_t uxOptionsLength = pxTCPWindow->ucOptionLength;\r
2276 \r
2277         #if(    ipconfigUSE_TCP_WIN == 1 )\r
2278                 if( uxOptionsLength != 0u )\r
2279                 {\r
2280                         /* TCP options must be sent because a packet which is out-of-order\r
2281                         was received. */\r
2282                         if( xTCPWindowLoggingLevel >= 0 )\r
2283                                 FreeRTOS_debug_printf( ( "SACK[%d,%d]: optlen %lu sending %lu - %lu\n",\r
2284                                         pxSocket->usLocalPort,\r
2285                                         pxSocket->u.xTCP.usRemotePort,\r
2286                                         uxOptionsLength,\r
2287                                         FreeRTOS_ntohl( pxTCPWindow->ulOptionsData[ 1 ] ) - pxSocket->u.xTCP.xTCPWindow.rx.ulFirstSequenceNumber,\r
2288                                         FreeRTOS_ntohl( pxTCPWindow->ulOptionsData[ 2 ] ) - pxSocket->u.xTCP.xTCPWindow.rx.ulFirstSequenceNumber ) );\r
2289                         memcpy( pxTCPHeader->ucOptdata, pxTCPWindow->ulOptionsData, ( size_t ) uxOptionsLength );\r
2290 \r
2291                         /* The header length divided by 4, goes into the higher nibble,\r
2292                         effectively a shift-left 2. */\r
2293                         pxTCPHeader->ucTCPOffset = ( uint8_t )( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 );\r
2294                 }\r
2295                 else\r
2296         #endif  /* ipconfigUSE_TCP_WIN */\r
2297         if( ( pxSocket->u.xTCP.ucTCPState >= eESTABLISHED ) && ( pxSocket->u.xTCP.bits.bMssChange != pdFALSE_UNSIGNED ) )\r
2298         {\r
2299                 /* TCP options must be sent because the MSS has changed. */\r
2300                 pxSocket->u.xTCP.bits.bMssChange = pdFALSE_UNSIGNED;\r
2301                 if( xTCPWindowLoggingLevel >= 0 )\r
2302                 {\r
2303                         FreeRTOS_debug_printf( ( "MSS: sending %d\n", pxSocket->u.xTCP.usCurMSS ) );\r
2304                 }\r
2305 \r
2306                 pxTCPHeader->ucOptdata[ 0 ] = TCP_OPT_MSS;\r
2307                 pxTCPHeader->ucOptdata[ 1 ] = TCP_OPT_MSS_LEN;\r
2308                 pxTCPHeader->ucOptdata[ 2 ] = ( uint8_t ) ( ( pxSocket->u.xTCP.usCurMSS ) >> 8 );\r
2309                 pxTCPHeader->ucOptdata[ 3 ] = ( uint8_t ) ( ( pxSocket->u.xTCP.usCurMSS ) & 0xffu );\r
2310                 uxOptionsLength = 4u;\r
2311                 pxTCPHeader->ucTCPOffset = ( uint8_t )( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 );\r
2312         }\r
2313 \r
2314         #if(    ipconfigUSE_TCP_TIMESTAMPS == 1 )\r
2315         {\r
2316                 if( pxSocket->u.xTCP.xTCPWindow.u.bits.bTimeStamps )\r
2317                 {\r
2318                         uxOptionsLength += prvTCPSetTimeStamp( uxOptionsLength, pxSocket, pxTCPHeader );\r
2319                 }\r
2320         }\r
2321         #endif  /* ipconfigUSE_TCP_TIMESTAMPS == 1 */\r
2322 \r
2323         return uxOptionsLength;\r
2324 }\r
2325 /*-----------------------------------------------------------*/\r
2326 \r
2327 /*\r
2328  * prvHandleSynReceived(): called from prvTCPHandleState()\r
2329  *\r
2330  * Called from the states: eSYN_RECEIVED and eCONNECT_SYN\r
2331  * If the flags received are correct, the socket will move to eESTABLISHED.\r
2332  */\r
2333 static BaseType_t prvHandleSynReceived( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer,\r
2334         uint32_t ulReceiveLength, UBaseType_t uxOptionsLength )\r
2335 {\r
2336 TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( (*ppxNetworkBuffer)->pucEthernetBuffer );\r
2337 TCPHeader_t *pxTCPHeader = &pxTCPPacket->xTCPHeader;\r
2338 TCPWindow_t *pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow;\r
2339 uint8_t ucTCPFlags = pxTCPHeader->ucTCPFlags;\r
2340 uint32_t ulSequenceNumber = FreeRTOS_ntohl( pxTCPHeader->ulSequenceNumber );\r
2341 BaseType_t xSendLength = 0;\r
2342 \r
2343         /* Either expect a ACK or a SYN+ACK. */\r
2344         uint16_t usExpect = ( uint16_t ) ipTCP_FLAG_ACK;\r
2345         if( pxSocket->u.xTCP.ucTCPState == eCONNECT_SYN )\r
2346         {\r
2347                 usExpect |= ( uint16_t ) ipTCP_FLAG_SYN;\r
2348         }\r
2349 \r
2350         if( ( ucTCPFlags & 0x17u ) != usExpect )\r
2351         {\r
2352                 /* eSYN_RECEIVED: flags 0010 expected, not 0002. */\r
2353                 /* eSYN_RECEIVED: flags ACK  expected, not SYN. */\r
2354                 FreeRTOS_debug_printf( ( "%s: flags %04X expected, not %04X\n",\r
2355                         pxSocket->u.xTCP.ucTCPState == eSYN_RECEIVED ? "eSYN_RECEIVED" : "eCONNECT_SYN",\r
2356                         usExpect, ucTCPFlags ) );\r
2357                 vTCPStateChange( pxSocket, eCLOSE_WAIT );\r
2358                 pxTCPHeader->ucTCPFlags |= ipTCP_FLAG_RST;\r
2359                 xSendLength = ( BaseType_t ) ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength );\r
2360                 pxTCPHeader->ucTCPOffset = ( uint8_t )( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 );\r
2361         }\r
2362         else\r
2363         {\r
2364                 pxTCPWindow->usPeerPortNumber = pxSocket->u.xTCP.usRemotePort;\r
2365                 pxTCPWindow->usOurPortNumber = pxSocket->usLocalPort;\r
2366 \r
2367                 if( pxSocket->u.xTCP.ucTCPState == eCONNECT_SYN )\r
2368                 {\r
2369                         TCPPacket_t *pxLastTCPPacket = ( TCPPacket_t * ) ( pxSocket->u.xTCP.xPacket.u.ucLastPacket );\r
2370 \r
2371                         /* Clear the SYN flag in lastPacket. */\r
2372                         pxLastTCPPacket->xTCPHeader.ucTCPFlags = ipTCP_FLAG_ACK;\r
2373 \r
2374                         /* This socket was the one connecting actively so now perofmr the\r
2375                         synchronisation. */\r
2376                         vTCPWindowInit( &pxSocket->u.xTCP.xTCPWindow,\r
2377                                 ulSequenceNumber, pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber, ( uint32_t ) pxSocket->u.xTCP.usCurMSS );\r
2378                         pxTCPWindow->rx.ulCurrentSequenceNumber = pxTCPWindow->rx.ulHighestSequenceNumber = ulSequenceNumber + 1u;\r
2379                         pxTCPWindow->tx.ulCurrentSequenceNumber++; /* because we send a TCP_SYN [ | TCP_ACK ]; */\r
2380                         pxTCPWindow->ulNextTxSequenceNumber++;\r
2381                 }\r
2382                 else if( ulReceiveLength == 0u )\r
2383                 {\r
2384                         pxTCPWindow->rx.ulCurrentSequenceNumber = ulSequenceNumber;\r
2385                 }\r
2386 \r
2387                 /* The SYN+ACK has been confirmed, increase the next sequence number by\r
2388                 1. */\r
2389                 pxTCPWindow->ulOurSequenceNumber = pxTCPWindow->tx.ulFirstSequenceNumber + 1u;\r
2390 \r
2391                 #if( ipconfigUSE_TCP_WIN == 1 )\r
2392                 {\r
2393                         FreeRTOS_debug_printf( ( "TCP: %s %d => %lxip:%d set ESTAB (scaling %u)\n",\r
2394                                 pxSocket->u.xTCP.ucTCPState == eCONNECT_SYN ? "active" : "passive",\r
2395                                 pxSocket->usLocalPort,\r
2396                                 pxSocket->u.xTCP.ulRemoteIP,\r
2397                                 pxSocket->u.xTCP.usRemotePort,\r
2398                                 ( unsigned ) pxSocket->u.xTCP.bits.bWinScaling ) );\r
2399                 }\r
2400                 #endif /* ipconfigUSE_TCP_WIN */\r
2401 \r
2402                 if( ( pxSocket->u.xTCP.ucTCPState == eCONNECT_SYN ) || ( ulReceiveLength != 0u ) )\r
2403                 {\r
2404                         pxTCPHeader->ucTCPFlags = ipTCP_FLAG_ACK;\r
2405                         xSendLength = ( BaseType_t ) ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength );\r
2406                         pxTCPHeader->ucTCPOffset = ( uint8_t ) ( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 );\r
2407                 }\r
2408                 #if( ipconfigUSE_TCP_WIN != 0 )\r
2409                 {\r
2410                         if( pxSocket->u.xTCP.bits.bWinScaling == pdFALSE_UNSIGNED )\r
2411                         {\r
2412                                 /* The other party did not send a scaling factor.\r
2413                                 A shifting factor in this side must be canceled. */\r
2414                                 pxSocket->u.xTCP.ucMyWinScaleFactor = 0;\r
2415                                 pxSocket->u.xTCP.ucPeerWinScaleFactor = 0;\r
2416                         }\r
2417                 }\r
2418                 #endif /* ipconfigUSE_TCP_WIN */\r
2419                 /* This was the third step of connecting: SYN, SYN+ACK, ACK     so now the\r
2420                 connection is established. */\r
2421                 vTCPStateChange( pxSocket, eESTABLISHED );\r
2422         }\r
2423 \r
2424         return xSendLength;\r
2425 }\r
2426 /*-----------------------------------------------------------*/\r
2427 \r
2428 /*\r
2429  * prvHandleEstablished(): called from prvTCPHandleState()\r
2430  *\r
2431  * Called if the status is eESTABLISHED.  Data reception has been handled\r
2432  * earlier.  Here the ACK's from peer will be checked, and if a FIN is received,\r
2433  * the code will check if it may be accepted, i.e. if all expected data has been\r
2434  * completely received.\r
2435  */\r
2436 static BaseType_t prvHandleEstablished( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer,\r
2437         uint32_t ulReceiveLength, UBaseType_t uxOptionsLength )\r
2438 {\r
2439 TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( (*ppxNetworkBuffer)->pucEthernetBuffer );\r
2440 TCPHeader_t *pxTCPHeader = &pxTCPPacket->xTCPHeader;\r
2441 TCPWindow_t *pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow;\r
2442 uint8_t ucTCPFlags = pxTCPHeader->ucTCPFlags;\r
2443 uint32_t ulSequenceNumber = FreeRTOS_ntohl( pxTCPHeader->ulSequenceNumber ), ulCount;\r
2444 BaseType_t xSendLength = 0, xMayClose = pdFALSE, bRxComplete, bTxDone;\r
2445 int32_t lDistance, lSendResult;\r
2446 \r
2447         /* Remember the window size the peer is advertising. */\r
2448         pxSocket->u.xTCP.ulWindowSize = FreeRTOS_ntohs( pxTCPHeader->usWindow );\r
2449         #if( ipconfigUSE_TCP_WIN != 0 )\r
2450         {\r
2451                 pxSocket->u.xTCP.ulWindowSize =\r
2452                         ( pxSocket->u.xTCP.ulWindowSize << pxSocket->u.xTCP.ucPeerWinScaleFactor );\r
2453         }\r
2454         #endif\r
2455 \r
2456         if( ( ucTCPFlags & ( uint8_t ) ipTCP_FLAG_ACK ) != 0u )\r
2457         {\r
2458                 ulCount = ulTCPWindowTxAck( pxTCPWindow, FreeRTOS_ntohl( pxTCPPacket->xTCPHeader.ulAckNr ) );\r
2459 \r
2460                 /* ulTCPWindowTxAck() returns the number of bytes which have been acked,\r
2461                 starting at 'tx.ulCurrentSequenceNumber'.  Advance the tail pointer in\r
2462                 txStream. */\r
2463                 if( ( pxSocket->u.xTCP.txStream != NULL ) && ( ulCount > 0u ) )\r
2464                 {\r
2465                         /* Just advancing the tail index, 'ulCount' bytes have been\r
2466                         confirmed, and because there is new space in the txStream, the\r
2467                         user/owner should be woken up. */\r
2468                         /* _HT_ : only in case the socket's waiting? */\r
2469                         if( uxStreamBufferGet( pxSocket->u.xTCP.txStream, 0u, NULL, ( size_t ) ulCount, pdFALSE ) != 0u )\r
2470                         {\r
2471                                 pxSocket->xEventBits |= eSOCKET_SEND;\r
2472 \r
2473                                 #if ipconfigSUPPORT_SELECT_FUNCTION == 1\r
2474                                 {\r
2475                                         if( ( pxSocket->xSelectBits & eSELECT_WRITE ) != 0 )\r
2476                                         {\r
2477                                                 pxSocket->xEventBits |= ( eSELECT_WRITE << SOCKET_EVENT_BIT_COUNT );\r
2478                                         }\r
2479                                 }\r
2480                                 #endif\r
2481                                 /* In case the socket owner has installed an OnSent handler,\r
2482                                 call it now. */\r
2483                                 #if( ipconfigUSE_CALLBACKS == 1 )\r
2484                                 {\r
2485                                         if( ipconfigIS_VALID_PROG_ADDRESS( pxSocket->u.xTCP.pxHandleSent ) )\r
2486                                         {\r
2487                                                 pxSocket->u.xTCP.pxHandleSent( (Socket_t *)pxSocket, ulCount );\r
2488                                         }\r
2489                                 }\r
2490                                 #endif /* ipconfigUSE_CALLBACKS == 1  */\r
2491                         }\r
2492                 }\r
2493         }\r
2494 \r
2495         /* If this socket has a stream for transmission, add the data to the\r
2496         outgoing segment(s). */\r
2497         if( pxSocket->u.xTCP.txStream != NULL )\r
2498         {\r
2499                 prvTCPAddTxData( pxSocket );\r
2500         }\r
2501 \r
2502         pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber = pxTCPWindow->tx.ulCurrentSequenceNumber;\r
2503 \r
2504         if( ( pxSocket->u.xTCP.bits.bFinAccepted != pdFALSE_UNSIGNED ) || ( ( ucTCPFlags & ( uint8_t ) ipTCP_FLAG_FIN ) != 0u ) )\r
2505         {\r
2506                 /* Peer is requesting to stop, see if we're really finished. */\r
2507                 xMayClose = pdTRUE;\r
2508 \r
2509                 /* Checks are only necessary if we haven't sent a FIN yet. */\r
2510                 if( pxSocket->u.xTCP.bits.bFinSent == pdFALSE_UNSIGNED )\r
2511                 {\r
2512                         /* xTCPWindowTxDone returns true when all Tx queues are empty. */\r
2513                         bRxComplete = xTCPWindowRxEmpty( pxTCPWindow );\r
2514                         bTxDone     = xTCPWindowTxDone( pxTCPWindow );\r
2515 \r
2516                         if( ( bRxComplete == 0 ) || ( bTxDone == 0 ) )\r
2517                         {\r
2518                                 /* Refusing FIN: Rx incomp 1 optlen 4 tx done 1. */\r
2519                                 FreeRTOS_debug_printf( ( "Refusing FIN[%u,%u]: RxCompl %lu tx done %ld\n",\r
2520                                         pxSocket->usLocalPort,\r
2521                                         pxSocket->u.xTCP.usRemotePort,\r
2522                                         bRxComplete, bTxDone ) );\r
2523                                 xMayClose = pdFALSE;\r
2524                         }\r
2525                         else\r
2526                         {\r
2527                                 lDistance = ( int32_t ) ( ulSequenceNumber + ulReceiveLength - pxTCPWindow->rx.ulCurrentSequenceNumber );\r
2528 \r
2529                                 if( lDistance > 1 )\r
2530                                 {\r
2531                                         FreeRTOS_debug_printf( ( "Refusing FIN: Rx not complete %ld (cur %lu high %lu)\n",\r
2532                                                 lDistance, pxTCPWindow->rx.ulCurrentSequenceNumber - pxTCPWindow->rx.ulFirstSequenceNumber,\r
2533                                                 pxTCPWindow->rx.ulHighestSequenceNumber - pxTCPWindow->rx.ulFirstSequenceNumber ) );\r
2534 \r
2535                                         xMayClose = pdFALSE;\r
2536                                 }\r
2537                         }\r
2538                 }\r
2539 \r
2540                 if( xTCPWindowLoggingLevel > 0 )\r
2541                 {\r
2542                         FreeRTOS_debug_printf( ( "TCP: FIN received, mayClose = %ld (Rx %lu Len %ld, Tx %lu)\n",\r
2543                                 xMayClose, ulSequenceNumber - pxSocket->u.xTCP.xTCPWindow.rx.ulFirstSequenceNumber, ulReceiveLength,\r
2544                                 pxTCPWindow->tx.ulCurrentSequenceNumber - pxSocket->u.xTCP.xTCPWindow.tx.ulFirstSequenceNumber ) );\r
2545                 }\r
2546 \r
2547                 if( xMayClose != pdFALSE )\r
2548                 {\r
2549                         pxSocket->u.xTCP.bits.bFinAccepted = pdTRUE_UNSIGNED;\r
2550                         xSendLength = prvTCPHandleFin( pxSocket, *ppxNetworkBuffer );\r
2551                 }\r
2552         }\r
2553 \r
2554         if( xMayClose == pdFALSE )\r
2555         {\r
2556                 pxTCPHeader->ucTCPFlags = ipTCP_FLAG_ACK;\r
2557 \r
2558                 if( ulReceiveLength != 0u )\r
2559                 {\r
2560                         xSendLength = ( BaseType_t ) ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength );\r
2561                         /* TCP-offsett equals '( ( length / 4 ) << 4 )', resulting in a shift-left 2 */\r
2562                         pxTCPHeader->ucTCPOffset = ( uint8_t )( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 );\r
2563 \r
2564                         if( pxSocket->u.xTCP.bits.bFinSent != pdFALSE_UNSIGNED )\r
2565                         {\r
2566                                 pxTCPWindow->tx.ulCurrentSequenceNumber = pxTCPWindow->tx.ulFINSequenceNumber;\r
2567                         }\r
2568                 }\r
2569 \r
2570                 /* Now get data to be transmitted. */\r
2571                 /* _HT_ patch: since the MTU has be fixed at 1500 in stead of 1526, TCP\r
2572                 can not send-out both TCP options and also a full packet. Sending\r
2573                 options (SACK) is always more urgent than sending data, which can be\r
2574                 sent later. */\r
2575                 if( uxOptionsLength == 0u )\r
2576                 {\r
2577                         /* prvTCPPrepareSend might allocate a bigger network buffer, if\r
2578                         necessary. */\r
2579                         lSendResult = prvTCPPrepareSend( pxSocket, ppxNetworkBuffer, uxOptionsLength );\r
2580                         if( lSendResult > 0 )\r
2581                         {\r
2582                                 xSendLength = ( BaseType_t ) lSendResult;\r
2583                         }\r
2584                 }\r
2585         }\r
2586 \r
2587         return xSendLength;\r
2588 }\r
2589 /*-----------------------------------------------------------*/\r
2590 \r
2591 /*\r
2592  * Called from prvTCPHandleState().  There is data to be sent.  If\r
2593  * ipconfigUSE_TCP_WIN is defined, and if only an ACK must be sent, it will be\r
2594  * checked if it would better be postponed for efficiency.\r
2595  */\r
2596 static BaseType_t prvSendData( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer,\r
2597         uint32_t ulReceiveLength, BaseType_t xSendLength )\r
2598 {\r
2599 TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( (*ppxNetworkBuffer)->pucEthernetBuffer );\r
2600 TCPHeader_t *pxTCPHeader = &pxTCPPacket->xTCPHeader;\r
2601 TCPWindow_t *pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow;\r
2602 /* Find out what window size we may advertised. */\r
2603 uint32_t ulFrontSpace;\r
2604 int32_t lRxSpace;\r
2605 #if( ipconfigUSE_TCP_WIN == 1 )\r
2606         #if( ipconfigTCP_ACK_EARLIER_PACKET == 0 )\r
2607                 const int32_t lMinLength = 0;\r
2608         #else\r
2609                 int32_t lMinLength;\r
2610         #endif\r
2611 #endif\r
2612         pxSocket->u.xTCP.ulRxCurWinSize = pxTCPWindow->xSize.ulRxWindowLength -\r
2613                                                                          ( pxTCPWindow->rx.ulHighestSequenceNumber - pxTCPWindow->rx.ulCurrentSequenceNumber );\r
2614 \r
2615         /* Free space in rxStream. */\r
2616         if( pxSocket->u.xTCP.rxStream != NULL )\r
2617         {\r
2618                 ulFrontSpace = ( uint32_t ) uxStreamBufferFrontSpace( pxSocket->u.xTCP.rxStream );\r
2619         }\r
2620         else\r
2621         {\r
2622                 ulFrontSpace = ( uint32_t ) pxSocket->u.xTCP.uxRxStreamSize;\r
2623         }\r
2624 \r
2625         pxSocket->u.xTCP.ulRxCurWinSize = FreeRTOS_min_uint32( ulFrontSpace, pxSocket->u.xTCP.ulRxCurWinSize );\r
2626 \r
2627         /* Set the time-out field, so that we'll be called by the IP-task in case no\r
2628         next message will be received. */\r
2629         lRxSpace = (int32_t)( pxSocket->u.xTCP.ulHighestRxAllowed - pxTCPWindow->rx.ulCurrentSequenceNumber );\r
2630         #if ipconfigUSE_TCP_WIN == 1\r
2631         {\r
2632 \r
2633                 #if( ipconfigTCP_ACK_EARLIER_PACKET != 0 )\r
2634                 {\r
2635                         lMinLength = ( ( int32_t ) 2 ) * ( ( int32_t ) pxSocket->u.xTCP.usCurMSS );\r
2636                 }\r
2637                 #endif /* ipconfigTCP_ACK_EARLIER_PACKET */\r
2638 \r
2639                 /* In case we're receiving data continuously, we might postpone sending\r
2640                 an ACK to gain performance. */\r
2641                 if( ( ulReceiveLength > 0 ) &&                                                  /* Data was sent to this socket. */\r
2642                         ( lRxSpace >= lMinLength ) &&                                           /* There is Rx space for more data. */\r
2643                         ( pxSocket->u.xTCP.bits.bFinSent == pdFALSE_UNSIGNED ) &&       /* Not in a closure phase. */\r
2644                         ( xSendLength == ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER ) ) && /* No Tx data or options to be sent. */\r
2645                         ( pxSocket->u.xTCP.ucTCPState == eESTABLISHED ) &&      /* Connection established. */\r
2646                         ( pxTCPHeader->ucTCPFlags == ipTCP_FLAG_ACK ) )         /* There are no other flags than an ACK. */\r
2647                 {\r
2648                         if( pxSocket->u.xTCP.pxAckMessage != *ppxNetworkBuffer )\r
2649                         {\r
2650                                 /* There was still a delayed in queue, delete it. */\r
2651                                 if( pxSocket->u.xTCP.pxAckMessage != 0 )\r
2652                                 {\r
2653                                         vReleaseNetworkBufferAndDescriptor( pxSocket->u.xTCP.pxAckMessage );\r
2654                                 }\r
2655 \r
2656                                 pxSocket->u.xTCP.pxAckMessage = *ppxNetworkBuffer;\r
2657                         }\r
2658                         if( ( ulReceiveLength < ( uint32_t ) pxSocket->u.xTCP.usCurMSS ) ||     /* Received a small message. */\r
2659                                 ( lRxSpace < ( int32_t ) ( 2U * pxSocket->u.xTCP.usCurMSS ) ) ) /* There are less than 2 x MSS space in the Rx buffer. */\r
2660                         {\r
2661                                 pxSocket->u.xTCP.usTimeout = ( uint16_t ) pdMS_TO_MIN_TICKS( DELAYED_ACK_SHORT_DELAY_MS );\r
2662                         }\r
2663                         else\r
2664                         {\r
2665                                 /* Normally a delayed ACK should wait 200 ms for a next incoming\r
2666                                 packet.  Only wait 20 ms here to gain performance.  A slow ACK\r
2667                                 for full-size message. */\r
2668                                 pxSocket->u.xTCP.usTimeout = ( uint16_t ) pdMS_TO_MIN_TICKS( DELAYED_ACK_LONGER_DELAY_MS );\r
2669                         }\r
2670 \r
2671                         if( ( xTCPWindowLoggingLevel > 1 ) && ( ipconfigTCP_MAY_LOG_PORT( pxSocket->usLocalPort ) != pdFALSE ) )\r
2672                         {\r
2673                                 FreeRTOS_debug_printf( ( "Send[%u->%u] del ACK %lu SEQ %lu (len %lu) tmout %u d %lu\n",\r
2674                                         pxSocket->usLocalPort,\r
2675                                         pxSocket->u.xTCP.usRemotePort,\r
2676                                         pxTCPWindow->rx.ulCurrentSequenceNumber - pxTCPWindow->rx.ulFirstSequenceNumber,\r
2677                                         pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber - pxTCPWindow->tx.ulFirstSequenceNumber,\r
2678                                         xSendLength,\r
2679                                         pxSocket->u.xTCP.usTimeout, lRxSpace ) );\r
2680                         }\r
2681 \r
2682                         *ppxNetworkBuffer = NULL;\r
2683                         xSendLength = 0;\r
2684                 }\r
2685                 else if( pxSocket->u.xTCP.pxAckMessage != NULL )\r
2686                 {\r
2687                         /* As an ACK is not being delayed, remove any earlier delayed ACK\r
2688                         message. */\r
2689                         if( pxSocket->u.xTCP.pxAckMessage != *ppxNetworkBuffer )\r
2690                         {\r
2691                                 vReleaseNetworkBufferAndDescriptor( pxSocket->u.xTCP.pxAckMessage );\r
2692                         }\r
2693 \r
2694                         pxSocket->u.xTCP.pxAckMessage = NULL;\r
2695                 }\r
2696         }\r
2697         #else\r
2698         {\r
2699                 /* Remove compiler warnings. */\r
2700                 ( void ) ulReceiveLength;\r
2701                 ( void ) pxTCPHeader;\r
2702                 ( void ) lRxSpace;\r
2703         }\r
2704         #endif /* ipconfigUSE_TCP_WIN */\r
2705 \r
2706         if( xSendLength != 0 )\r
2707         {\r
2708                 if( ( xTCPWindowLoggingLevel > 1 ) && ( ipconfigTCP_MAY_LOG_PORT( pxSocket->usLocalPort ) != pdFALSE ) )\r
2709                 {\r
2710                         FreeRTOS_debug_printf( ( "Send[%u->%u] imm ACK %lu SEQ %lu (len %lu)\n",\r
2711                                 pxSocket->usLocalPort,\r
2712                                 pxSocket->u.xTCP.usRemotePort,\r
2713                                 pxTCPWindow->rx.ulCurrentSequenceNumber - pxTCPWindow->rx.ulFirstSequenceNumber,\r
2714                                 pxTCPWindow->ulOurSequenceNumber - pxTCPWindow->tx.ulFirstSequenceNumber,\r
2715                                 xSendLength ) );\r
2716                 }\r
2717 \r
2718                 /* Set the parameter 'xReleaseAfterSend' to the value of\r
2719                 ipconfigZERO_COPY_TX_DRIVER. */\r
2720                 prvTCPReturnPacket( pxSocket, *ppxNetworkBuffer, ( uint32_t ) xSendLength, ipconfigZERO_COPY_TX_DRIVER );\r
2721                 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )\r
2722                 {\r
2723                         /* The driver has taken ownership of the Network Buffer. */\r
2724                         *ppxNetworkBuffer = NULL;\r
2725                 }\r
2726                 #endif\r
2727         }\r
2728 \r
2729         return xSendLength;\r
2730 }\r
2731 /*-----------------------------------------------------------*/\r
2732 \r
2733 /*\r
2734  * prvTCPHandleState()\r
2735  * is the most important function of this TCP stack\r
2736  * We've tried to keep it (relatively short) by putting a lot of code in\r
2737  * the static functions above:\r
2738  *\r
2739  *              prvCheckRxData()\r
2740  *              prvStoreRxData()\r
2741  *              prvSetOptions()\r
2742  *              prvHandleSynReceived()\r
2743  *              prvHandleEstablished()\r
2744  *              prvSendData()\r
2745  *\r
2746  * As these functions are declared static, and they're called from one location\r
2747  * only, most compilers will inline them, thus avoiding a call and return.\r
2748  */\r
2749 static BaseType_t prvTCPHandleState( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer )\r
2750 {\r
2751 TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( (*ppxNetworkBuffer)->pucEthernetBuffer );\r
2752 TCPHeader_t *pxTCPHeader = &( pxTCPPacket->xTCPHeader );\r
2753 BaseType_t xSendLength = 0;\r
2754 uint32_t ulReceiveLength;       /* Number of bytes contained in the TCP message. */\r
2755 uint8_t *pucRecvData;\r
2756 uint32_t ulSequenceNumber = FreeRTOS_ntohl (pxTCPHeader->ulSequenceNumber);\r
2757 \r
2758         /* uxOptionsLength: the size of the options to be sent (always a multiple of\r
2759         4 bytes)\r
2760         1. in the SYN phase, we shall communicate the MSS\r
2761         2. in case of a SACK, Selective ACK, ack a segment which comes in\r
2762         out-of-order. */\r
2763 UBaseType_t uxOptionsLength = 0u;\r
2764 uint8_t ucTCPFlags = pxTCPHeader->ucTCPFlags;\r
2765 TCPWindow_t *pxTCPWindow = &( pxSocket->u.xTCP.xTCPWindow );\r
2766 \r
2767         /* First get the length and the position of the received data, if any.\r
2768         pucRecvData will point to the first byte of the TCP payload. */\r
2769         ulReceiveLength = ( uint32_t ) prvCheckRxData( *ppxNetworkBuffer, &pucRecvData );\r
2770 \r
2771         if( pxSocket->u.xTCP.ucTCPState >= eESTABLISHED )\r
2772         {\r
2773                 if ( pxTCPWindow->rx.ulCurrentSequenceNumber == ulSequenceNumber + 1u )\r
2774                 {\r
2775                         /* This is most probably a keep-alive message from peer.  Setting\r
2776                         'bWinChange' doesn't cause a window-size-change, the flag is used\r
2777                         here to force sending an immediate ACK. */\r
2778                         pxSocket->u.xTCP.bits.bWinChange = pdTRUE_UNSIGNED;\r
2779                 }\r
2780         }\r
2781 \r
2782         /* Keep track of the highest sequence number that might be expected within\r
2783         this connection. */\r
2784         if( ( ( int32_t ) ( ulSequenceNumber + ulReceiveLength - pxTCPWindow->rx.ulHighestSequenceNumber ) ) > 0 )\r
2785         {\r
2786                 pxTCPWindow->rx.ulHighestSequenceNumber = ulSequenceNumber + ulReceiveLength;\r
2787         }\r
2788 \r
2789         /* Storing data may result in a fatal error if malloc() fails. */\r
2790         if( prvStoreRxData( pxSocket, pucRecvData, *ppxNetworkBuffer, ulReceiveLength ) < 0 )\r
2791         {\r
2792                 xSendLength = -1;\r
2793         }\r
2794         else\r
2795         {\r
2796                 uxOptionsLength = prvSetOptions( pxSocket, *ppxNetworkBuffer );\r
2797 \r
2798                 if( ( pxSocket->u.xTCP.ucTCPState == eSYN_RECEIVED ) && ( ( ucTCPFlags & ipTCP_FLAG_CTRL ) == ipTCP_FLAG_SYN ) )\r
2799                 {\r
2800                         FreeRTOS_debug_printf( ( "eSYN_RECEIVED: ACK expected, not SYN: peer missed our SYN+ACK\n" ) );\r
2801 \r
2802                         /* In eSYN_RECEIVED a simple ACK is expected, but apparently the\r
2803                         'SYN+ACK' didn't arrive.  Step back to the previous state in which\r
2804                         a first incoming SYN is handled.  The SYN was counted already so\r
2805                         decrease it first. */\r
2806                         vTCPStateChange( pxSocket, eSYN_FIRST );\r
2807                 }\r
2808 \r
2809                 if( ( ( ucTCPFlags & ipTCP_FLAG_FIN ) != 0u ) && ( pxSocket->u.xTCP.bits.bFinRecv == pdFALSE_UNSIGNED ) )\r
2810                 {\r
2811                         /* It's the first time a FIN has been received, remember its\r
2812                         sequence number. */\r
2813                         pxTCPWindow->rx.ulFINSequenceNumber = ulSequenceNumber + ulReceiveLength;\r
2814                         pxSocket->u.xTCP.bits.bFinRecv = pdTRUE_UNSIGNED;\r
2815 \r
2816                         /* Was peer the first one to send a FIN? */\r
2817                         if( pxSocket->u.xTCP.bits.bFinSent == pdFALSE_UNSIGNED )\r
2818                         {\r
2819                                 /* If so, don't send the-last-ACK. */\r
2820                                 pxSocket->u.xTCP.bits.bFinLast = pdTRUE_UNSIGNED;\r
2821                         }\r
2822                 }\r
2823 \r
2824                 switch (pxSocket->u.xTCP.ucTCPState)\r
2825                 {\r
2826                 case eCLOSED:           /* (server + client) no connection state at all. */\r
2827                         /* Nothing to do for a closed socket, except waiting for the\r
2828                         owner. */\r
2829                         break;\r
2830 \r
2831                 case eTCP_LISTEN:       /* (server) waiting for a connection request from\r
2832                                                         any remote TCP and port. */\r
2833                         /* The listen state was handled in xProcessReceivedTCPPacket().\r
2834                         Should not come here. */\r
2835                         break;\r
2836 \r
2837                 case eSYN_FIRST:        /* (server) Just received a SYN request for a server\r
2838                                                         socket. */\r
2839                         {\r
2840                                 /* A new socket has been created, reply with a SYN+ACK.\r
2841                                 Acknowledge with seq+1 because the SYN is seen as pseudo data\r
2842                                 with len = 1. */\r
2843                                 uxOptionsLength = prvSetSynAckOptions( pxSocket, pxTCPPacket );\r
2844                                 pxTCPHeader->ucTCPFlags = ipTCP_FLAG_SYN | ipTCP_FLAG_ACK;\r
2845 \r
2846                                 xSendLength = ( BaseType_t ) ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength );\r
2847 \r
2848                                 /* Set the TCP offset field:  ipSIZE_OF_TCP_HEADER equals 20 and\r
2849                                 uxOptionsLength is a multiple of 4.  The complete expression is:\r
2850                                 ucTCPOffset = ( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) / 4 ) << 4 */\r
2851                                 pxTCPHeader->ucTCPOffset = ( uint8_t )( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 );\r
2852                                 vTCPStateChange( pxSocket, eSYN_RECEIVED );\r
2853 \r
2854                                 pxTCPWindow->rx.ulCurrentSequenceNumber = pxTCPWindow->rx.ulHighestSequenceNumber = ulSequenceNumber + 1u;\r
2855                                 pxTCPWindow->tx.ulCurrentSequenceNumber = pxTCPWindow->ulNextTxSequenceNumber = pxTCPWindow->tx.ulFirstSequenceNumber + 1u; /* because we send a TCP_SYN. */\r
2856                         }\r
2857                         break;\r
2858 \r
2859                 case eCONNECT_SYN:      /* (client) also called SYN_SENT: we've just send a\r
2860                                                         SYN, expect     a SYN+ACK and send a ACK now. */\r
2861                         /* Fall through */\r
2862                 case eSYN_RECEIVED:     /* (server) we've had a SYN, replied with SYN+SCK\r
2863                                                         expect a ACK and do nothing. */\r
2864                         xSendLength = prvHandleSynReceived( pxSocket, ppxNetworkBuffer, ulReceiveLength, uxOptionsLength );\r
2865                         break;\r
2866 \r
2867                 case eESTABLISHED:      /* (server + client) an open connection, data\r
2868                                                         received can be delivered to the user. The normal\r
2869                                                         state for the data transfer phase of the connection\r
2870                                                         The closing states are also handled here with the\r
2871                                                         use of some flags. */\r
2872                         xSendLength = prvHandleEstablished( pxSocket, ppxNetworkBuffer, ulReceiveLength, uxOptionsLength );\r
2873                         break;\r
2874 \r
2875                 case eLAST_ACK:         /* (server + client) waiting for an acknowledgement\r
2876                                                         of the connection termination request previously\r
2877                                                         sent to the remote TCP (which includes an\r
2878                                                         acknowledgement of its connection termination\r
2879                                                         request). */\r
2880                         /* Fall through */\r
2881                 case eFIN_WAIT_1:       /* (server + client) waiting for a connection termination request from the remote TCP,\r
2882                                                          * or an acknowledgement of the connection termination request previously sent. */\r
2883                         /* Fall through */\r
2884                 case eFIN_WAIT_2:       /* (server + client) waiting for a connection termination request from the remote TCP. */\r
2885                         xSendLength = prvTCPHandleFin( pxSocket, *ppxNetworkBuffer );\r
2886                         break;\r
2887 \r
2888                 case eCLOSE_WAIT:       /* (server + client) waiting for a connection\r
2889                                                         termination request from the local user.  Nothing to\r
2890                                                         do, connection is closed, wait for owner to close\r
2891                                                         this socket. */\r
2892                         break;\r
2893 \r
2894                 case eCLOSING:          /* (server + client) waiting for a connection\r
2895                                                         termination request acknowledgement from the remote\r
2896                                                         TCP. */\r
2897                         break;\r
2898 \r
2899                 case eTIME_WAIT:        /* (either server or client) waiting for enough time\r
2900                                                         to pass to be sure the remote TCP received the\r
2901                                                         acknowledgement of its connection termination\r
2902                                                         request. [According to RFC 793 a connection can stay\r
2903                                                         in TIME-WAIT for a maximum of four minutes known as\r
2904                                                         a MSL (maximum segment lifetime).]  These states are\r
2905                                                         implemented implicitly by settings flags like\r
2906                                                         'bFinSent', 'bFinRecv', and 'bFinAcked'. */\r
2907                         break;\r
2908                 default:\r
2909                         break;\r
2910                 }\r
2911         }\r
2912 \r
2913         if( xSendLength > 0 )\r
2914         {\r
2915                 xSendLength = prvSendData( pxSocket, ppxNetworkBuffer, ulReceiveLength, xSendLength );\r
2916         }\r
2917 \r
2918         return xSendLength;\r
2919 }\r
2920 /*-----------------------------------------------------------*/\r
2921 \r
2922 static BaseType_t prvTCPSendReset( NetworkBufferDescriptor_t *pxNetworkBuffer )\r
2923 {\r
2924         #if( ipconfigIGNORE_UNKNOWN_PACKETS == 0 )\r
2925         {\r
2926         TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );\r
2927         const BaseType_t xSendLength = ( BaseType_t ) ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + 0u );    /* Plus 0 options. */\r
2928 \r
2929                 pxTCPPacket->xTCPHeader.ucTCPFlags = ipTCP_FLAG_ACK | ipTCP_FLAG_RST;\r
2930                 pxTCPPacket->xTCPHeader.ucTCPOffset = ( ipSIZE_OF_TCP_HEADER + 0u ) << 2;\r
2931 \r
2932                 prvTCPReturnPacket( NULL, pxNetworkBuffer, ( uint32_t ) xSendLength, pdFALSE );\r
2933         }\r
2934         #endif /* !ipconfigIGNORE_UNKNOWN_PACKETS */\r
2935 \r
2936         /* Remove compiler warnings if ipconfigIGNORE_UNKNOWN_PACKETS == 1. */\r
2937         ( void ) pxNetworkBuffer;\r
2938 \r
2939         /* The packet was not consumed. */\r
2940         return pdFAIL;\r
2941 }\r
2942 /*-----------------------------------------------------------*/\r
2943 \r
2944 static void prvSocketSetMSS( FreeRTOS_Socket_t *pxSocket )\r
2945 {\r
2946 uint32_t ulMSS = ipconfigTCP_MSS;\r
2947 \r
2948         if( ( ( FreeRTOS_ntohl( pxSocket->u.xTCP.ulRemoteIP ) ^ *ipLOCAL_IP_ADDRESS_POINTER ) & xNetworkAddressing.ulNetMask ) != 0ul )\r
2949         {\r
2950                 /* Data for this peer will pass through a router, and maybe through\r
2951                 the internet.  Limit the MSS to 1400 bytes or less. */\r
2952                 ulMSS = FreeRTOS_min_uint32( ( uint32_t ) REDUCED_MSS_THROUGH_INTERNET, ulMSS );\r
2953         }\r
2954 \r
2955         FreeRTOS_debug_printf( ( "prvSocketSetMSS: %lu bytes for %lxip:%u\n", ulMSS, pxSocket->u.xTCP.ulRemoteIP, pxSocket->u.xTCP.usRemotePort ) );\r
2956 \r
2957         pxSocket->u.xTCP.usInitMSS = pxSocket->u.xTCP.usCurMSS = ( uint16_t ) ulMSS;\r
2958 }\r
2959 /*-----------------------------------------------------------*/\r
2960 \r
2961 /*\r
2962  *      FreeRTOS_TCP_IP has only 2 public functions, this is the second one:\r
2963  *      xProcessReceivedTCPPacket()\r
2964  *              prvTCPHandleState()\r
2965  *                      prvTCPPrepareSend()\r
2966  *                              prvTCPReturnPacket()\r
2967  *                              xNetworkInterfaceOutput()       // Sends data to the NIC\r
2968  *              prvTCPSendRepeated()\r
2969  *                      prvTCPReturnPacket()            // Prepare for returning\r
2970  *                      xNetworkInterfaceOutput()       // Sends data to the NIC\r
2971 */\r
2972 BaseType_t xProcessReceivedTCPPacket( NetworkBufferDescriptor_t *pxNetworkBuffer )\r
2973 {\r
2974 FreeRTOS_Socket_t *pxSocket;\r
2975 TCPPacket_t * pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );\r
2976 uint16_t ucTCPFlags = pxTCPPacket->xTCPHeader.ucTCPFlags;\r
2977 uint32_t ulLocalIP = FreeRTOS_htonl( pxTCPPacket->xIPHeader.ulDestinationIPAddress );\r
2978 uint16_t xLocalPort = FreeRTOS_htons( pxTCPPacket->xTCPHeader.usDestinationPort );\r
2979 uint32_t ulRemoteIP = FreeRTOS_htonl( pxTCPPacket->xIPHeader.ulSourceIPAddress );\r
2980 uint16_t xRemotePort = FreeRTOS_htons( pxTCPPacket->xTCPHeader.usSourcePort );\r
2981 BaseType_t xResult = pdPASS;\r
2982 \r
2983         /* Find the destination socket, and if not found: return a socket listing to\r
2984         the destination PORT. */\r
2985         pxSocket = ( FreeRTOS_Socket_t * ) pxTCPSocketLookup( ulLocalIP, xLocalPort, ulRemoteIP, xRemotePort );\r
2986 \r
2987         if( ( pxSocket == NULL ) || ( prvTCPSocketIsActive( ( UBaseType_t ) pxSocket->u.xTCP.ucTCPState ) == pdFALSE ) )\r
2988         {\r
2989                 /* A TCP messages is received but either there is no socket with the\r
2990                 given port number or the there is a socket, but it is in one of these\r
2991                 non-active states:  eCLOSED, eCLOSE_WAIT, eFIN_WAIT_2, eCLOSING, or\r
2992                 eTIME_WAIT. */\r
2993 \r
2994                 FreeRTOS_debug_printf( ( "TCP: No active socket on port %d (%lxip:%d)\n", xLocalPort, ulRemoteIP, xRemotePort ) );\r
2995 \r
2996                 /* Send a RST to all packets that can not be handled.  As a result\r
2997                 the other party will get a ECONN error.  There are two exceptions:\r
2998                 1) A packet that already has the RST flag set.\r
2999                 2) A packet that only has the ACK flag set.\r
3000                 A packet with only the ACK flag set might be the last ACK in\r
3001                 a three-way hand-shake that closes a connection. */\r
3002                 if( ( ( ucTCPFlags & ipTCP_FLAG_CTRL ) != ipTCP_FLAG_ACK ) &&\r
3003                         ( ( ucTCPFlags & ipTCP_FLAG_RST ) == 0u ) )\r
3004                 {\r
3005                         prvTCPSendReset( pxNetworkBuffer );\r
3006                 }\r
3007 \r
3008                 /* The packet can't be handled. */\r
3009                 xResult = pdFAIL;\r
3010         }\r
3011         else\r
3012         {\r
3013                 pxSocket->u.xTCP.ucRepCount = 0u;\r
3014 \r
3015                 if( pxSocket->u.xTCP.ucTCPState == eTCP_LISTEN )\r
3016                 {\r
3017                         /* The matching socket is in a listening state.  Test if the peer\r
3018                         has set the SYN flag. */\r
3019                         if( ( ucTCPFlags & ipTCP_FLAG_CTRL ) != ipTCP_FLAG_SYN )\r
3020                         {\r
3021                                 /* What happens: maybe after a reboot, a client doesn't know the\r
3022                                 connection had gone.  Send a RST in order to get a new connect\r
3023                                 request. */\r
3024                                 #if( ipconfigHAS_DEBUG_PRINTF == 1 )\r
3025                                 {\r
3026                                 FreeRTOS_debug_printf( ( "TCP: Server can't handle flags: %s from %lxip:%u to port %u\n",\r
3027                                         prvTCPFlagMeaning( ( UBaseType_t ) ucTCPFlags ), ulRemoteIP, xRemotePort, xLocalPort ) );\r
3028                                 }\r
3029                                 #endif /* ipconfigHAS_DEBUG_PRINTF */\r
3030 \r
3031                                 if( ( ucTCPFlags & ipTCP_FLAG_RST ) == 0u )\r
3032                                 {\r
3033                                         prvTCPSendReset( pxNetworkBuffer );\r
3034                                 }\r
3035                                 xResult = pdFAIL;\r
3036                         }\r
3037                         else\r
3038                         {\r
3039                                 /* prvHandleListen() will either return a newly created socket\r
3040                                 (if bReuseSocket is false), otherwise it returns the current\r
3041                                 socket which will later get connected. */\r
3042                                 pxSocket = prvHandleListen( pxSocket, pxNetworkBuffer );\r
3043 \r
3044                                 if( pxSocket == NULL )\r
3045                                 {\r
3046                                         xResult = pdFAIL;\r
3047                                 }\r
3048                         }\r
3049                 }       /* if( pxSocket->u.xTCP.ucTCPState == eTCP_LISTEN ). */\r
3050                 else\r
3051                 {\r
3052                         /* This is not a socket in listening mode. Check for the RST\r
3053                         flag. */\r
3054                         if( ( ucTCPFlags & ipTCP_FLAG_RST ) != 0u )\r
3055                         {\r
3056                                 /* The target socket is not in a listening state, any RST packet\r
3057                                 will cause the socket to be closed. */\r
3058                                 FreeRTOS_debug_printf( ( "TCP: RST received from %lxip:%u for %u\n", ulRemoteIP, xRemotePort, xLocalPort ) );\r
3059                                 /* _HT_: should indicate that 'ECONNRESET' must be returned to the used during next API. */\r
3060                                 vTCPStateChange( pxSocket, eCLOSED );\r
3061 \r
3062                                 /* The packet cannot be handled. */\r
3063                                 xResult = pdFAIL;\r
3064                         }\r
3065                         else if( ( ( ucTCPFlags & ipTCP_FLAG_CTRL ) == ipTCP_FLAG_SYN ) && ( pxSocket->u.xTCP.ucTCPState >= eESTABLISHED ) )\r
3066                         {\r
3067                                 /* SYN flag while this socket is already connected. */\r
3068                                 FreeRTOS_debug_printf( ( "TCP: SYN unexpected from %lxip:%u\n", ulRemoteIP, xRemotePort ) );\r
3069 \r
3070                                 /* The packet cannot be handled. */\r
3071                                 xResult = pdFAIL;\r
3072                         }\r
3073                         else\r
3074                         {\r
3075                                 /* Update the copy of the TCP header only (skipping eth and IP\r
3076                                 headers).  It might be used later on, whenever data must be sent\r
3077                                 to the peer. */\r
3078                                 const BaseType_t lOffset = ( BaseType_t ) ( ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv4_HEADER );\r
3079                                 memcpy( pxSocket->u.xTCP.xPacket.u.ucLastPacket + lOffset, pxNetworkBuffer->pucEthernetBuffer + lOffset, ipSIZE_OF_TCP_HEADER );\r
3080                         }\r
3081                 }\r
3082         }\r
3083 \r
3084         if( xResult != pdFAIL )\r
3085         {\r
3086                 /* Touch the alive timers because we received a message for this\r
3087                 socket. */\r
3088                 prvTCPTouchSocket( pxSocket );\r
3089 \r
3090                 /* Parse the TCP option(s), if present. */\r
3091                 /* _HT_ : if we're in the SYN phase, and peer does not send a MSS option,\r
3092                 then we MUST assume an MSS size of 536 bytes for backward compatibility. */\r
3093 \r
3094                 /* When there are no TCP options, the TCP offset equals 20 bytes, which is stored as\r
3095                 the number 5 (words) in the higher niblle of the TCP-offset byte. */\r
3096                 if( ( pxTCPPacket->xTCPHeader.ucTCPOffset & TCP_OFFSET_LENGTH_BITS ) > TCP_OFFSET_STANDARD_LENGTH )\r
3097                 {\r
3098                         prvCheckOptions( pxSocket, pxNetworkBuffer );\r
3099                 }\r
3100 \r
3101 \r
3102                 #if( ipconfigUSE_TCP_WIN == 1 )\r
3103                 {\r
3104                         pxSocket->u.xTCP.ulWindowSize = FreeRTOS_ntohs( pxTCPPacket->xTCPHeader.usWindow );\r
3105                         pxSocket->u.xTCP.ulWindowSize =\r
3106                                 ( pxSocket->u.xTCP.ulWindowSize << pxSocket->u.xTCP.ucPeerWinScaleFactor );\r
3107                 }\r
3108                 #endif\r
3109 \r
3110                 /* In prvTCPHandleState() the incoming messages will be handled\r
3111                 depending on the current state of the connection. */\r
3112                 if( prvTCPHandleState( pxSocket, &pxNetworkBuffer ) > 0 )\r
3113                 {\r
3114                         /* prvTCPHandleState() has sent a message, see if there are more to\r
3115                         be transmitted. */\r
3116                         #if( ipconfigUSE_TCP_WIN == 1 )\r
3117                         {\r
3118                                 prvTCPSendRepeated( pxSocket, &pxNetworkBuffer );\r
3119                         }\r
3120                         #endif /* ipconfigUSE_TCP_WIN */\r
3121                 }\r
3122 \r
3123                 if( pxNetworkBuffer != NULL )\r
3124                 {\r
3125                         /* We must check if the buffer is unequal to NULL, because the\r
3126                         socket might keep a reference to it in case a delayed ACK must be\r
3127                         sent. */\r
3128                         vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );\r
3129                         pxNetworkBuffer = NULL;\r
3130                 }\r
3131 \r
3132                 /* And finally, calculate when this socket wants to be woken up. */\r
3133                 prvTCPNextTimeout ( pxSocket );\r
3134                 /* Return pdPASS to tell that the network buffer is 'consumed'. */\r
3135                 xResult = pdPASS;\r
3136         }\r
3137 \r
3138         /* pdPASS being returned means the buffer has been consumed. */\r
3139         return xResult;\r
3140 }\r
3141 /*-----------------------------------------------------------*/\r
3142 \r
3143 static FreeRTOS_Socket_t *prvHandleListen( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer )\r
3144 {\r
3145 TCPPacket_t * pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );\r
3146 FreeRTOS_Socket_t *pxReturn;\r
3147 \r
3148         /* A pure SYN (without ACK) has come in, create a new socket to answer\r
3149         it. */\r
3150         if( pxSocket->u.xTCP.bits.bReuseSocket != pdFALSE_UNSIGNED )\r
3151         {\r
3152                 /* The flag bReuseSocket indicates that the same instance of the\r
3153                 listening socket should be used for the connection. */\r
3154                 pxReturn = pxSocket;\r
3155                 pxSocket->u.xTCP.bits.bPassQueued = pdTRUE_UNSIGNED;\r
3156                 pxSocket->u.xTCP.pxPeerSocket = pxSocket;\r
3157         }\r
3158         else\r
3159         {\r
3160                 /* The socket does not have the bReuseSocket flag set meaning create a\r
3161                 new socket when a connection comes in. */\r
3162                 pxReturn = NULL;\r
3163 \r
3164                 if( pxSocket->u.xTCP.usChildCount >= pxSocket->u.xTCP.usBacklog )\r
3165                 {\r
3166                         FreeRTOS_printf( ( "Check: Socket %u already has %u / %u child%s\n",\r
3167                                 pxSocket->usLocalPort,\r
3168                                 pxSocket->u.xTCP.usChildCount,\r
3169                                 pxSocket->u.xTCP.usBacklog,\r
3170                                 pxSocket->u.xTCP.usChildCount == 1 ? "" : "ren" ) );\r
3171                         prvTCPSendReset( pxNetworkBuffer );\r
3172                 }\r
3173                 else\r
3174                 {\r
3175                         FreeRTOS_Socket_t *pxNewSocket = (FreeRTOS_Socket_t *)\r
3176                                 FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_STREAM, FREERTOS_IPPROTO_TCP );\r
3177 \r
3178                         if( ( pxNewSocket == NULL ) || ( pxNewSocket == FREERTOS_INVALID_SOCKET ) )\r
3179                         {\r
3180                                 FreeRTOS_debug_printf( ( "TCP: Listen: new socket failed\n" ) );\r
3181                                 prvTCPSendReset( pxNetworkBuffer );\r
3182                         }\r
3183                         else if( prvTCPSocketCopy( pxNewSocket, pxSocket ) != pdFALSE )\r
3184                         {\r
3185                                 /* The socket will be connected immediately, no time for the\r
3186                                 owner to setsockopt's, therefore copy properties of the server\r
3187                                 socket to the new socket.  Only the binding might fail (due to\r
3188                                 lack of resources). */\r
3189                                 pxReturn = pxNewSocket;\r
3190                         }\r
3191                 }\r
3192         }\r
3193 \r
3194         if( pxReturn != NULL )\r
3195         {\r
3196                 pxReturn->u.xTCP.usRemotePort = FreeRTOS_htons( pxTCPPacket->xTCPHeader.usSourcePort );\r
3197                 pxReturn->u.xTCP.ulRemoteIP = FreeRTOS_htonl( pxTCPPacket->xIPHeader.ulSourceIPAddress );\r
3198                 pxReturn->u.xTCP.xTCPWindow.ulOurSequenceNumber = ulNextInitialSequenceNumber;\r
3199 \r
3200                 /* Here is the SYN action. */\r
3201                 pxReturn->u.xTCP.xTCPWindow.rx.ulCurrentSequenceNumber = FreeRTOS_ntohl( pxTCPPacket->xTCPHeader.ulSequenceNumber );\r
3202                 prvSocketSetMSS( pxReturn );\r
3203 \r
3204                 prvTCPCreateWindow( pxReturn );\r
3205 \r
3206                 /* It is recommended to increase the ISS for each new connection with a value of 0x102. */\r
3207                 ulNextInitialSequenceNumber += INITIAL_SEQUENCE_NUMBER_INCREMENT;\r
3208 \r
3209                 vTCPStateChange( pxReturn, eSYN_FIRST );\r
3210 \r
3211                 /* Make a copy of the header up to the TCP header.  It is needed later\r
3212                 on, whenever data must be sent to the peer. */\r
3213                 memcpy( pxReturn->u.xTCP.xPacket.u.ucLastPacket, pxNetworkBuffer->pucEthernetBuffer, sizeof( pxReturn->u.xTCP.xPacket.u.ucLastPacket ) );\r
3214         }\r
3215         return pxReturn;\r
3216 }\r
3217 /*-----------------------------------------------------------*/\r
3218 \r
3219 /*\r
3220  * Duplicates a socket after a listening socket receives a connection.\r
3221  */\r
3222 static BaseType_t prvTCPSocketCopy( FreeRTOS_Socket_t *pxNewSocket, FreeRTOS_Socket_t *pxSocket )\r
3223 {\r
3224 struct freertos_sockaddr xAddress;\r
3225 \r
3226         pxNewSocket->xReceiveBlockTime = pxSocket->xReceiveBlockTime;\r
3227         pxNewSocket->xSendBlockTime = pxSocket->xSendBlockTime;\r
3228         pxNewSocket->ucSocketOptions = pxSocket->ucSocketOptions;\r
3229         pxNewSocket->u.xTCP.uxRxStreamSize = pxSocket->u.xTCP.uxRxStreamSize;\r
3230         pxNewSocket->u.xTCP.uxTxStreamSize = pxSocket->u.xTCP.uxTxStreamSize;\r
3231         pxNewSocket->u.xTCP.uxLittleSpace = pxSocket->u.xTCP.uxLittleSpace;\r
3232         pxNewSocket->u.xTCP.uxEnoughSpace = pxSocket->u.xTCP.uxEnoughSpace;\r
3233         pxNewSocket->u.xTCP.uxRxWinSize  = pxSocket->u.xTCP.uxRxWinSize;\r
3234         pxNewSocket->u.xTCP.uxTxWinSize  = pxSocket->u.xTCP.uxTxWinSize;\r
3235 \r
3236         #if( ipconfigSOCKET_HAS_USER_SEMAPHORE == 1 )\r
3237         {\r
3238                 pxNewSocket->pxUserSemaphore = pxSocket->pxUserSemaphore;\r
3239         }\r
3240         #endif /* ipconfigSOCKET_HAS_USER_SEMAPHORE */\r
3241 \r
3242         #if( ipconfigUSE_CALLBACKS == 1 )\r
3243         {\r
3244                 /* In case call-backs are used, copy them from parent to child. */\r
3245                 pxNewSocket->u.xTCP.pxHandleConnected = pxSocket->u.xTCP.pxHandleConnected;\r
3246                 pxNewSocket->u.xTCP.pxHandleReceive = pxSocket->u.xTCP.pxHandleReceive;\r
3247                 pxNewSocket->u.xTCP.pxHandleSent = pxSocket->u.xTCP.pxHandleSent;\r
3248         }\r
3249         #endif /* ipconfigUSE_CALLBACKS */\r
3250 \r
3251         #if( ipconfigSUPPORT_SELECT_FUNCTION == 1 )\r
3252         {\r
3253                 /* Child socket of listening sockets will inherit the Socket Set\r
3254                 Otherwise the owner has no chance of including it into the set. */\r
3255                 if( pxSocket->pxSocketSet )\r
3256                 {\r
3257                         pxNewSocket->pxSocketSet = pxSocket->pxSocketSet;\r
3258                         pxNewSocket->xSelectBits = pxSocket->xSelectBits | eSELECT_READ | eSELECT_EXCEPT;\r
3259                 }\r
3260         }\r
3261         #endif /* ipconfigSUPPORT_SELECT_FUNCTION */\r
3262 \r
3263         /* And bind it to the same local port as its parent. */\r
3264         xAddress.sin_addr = *ipLOCAL_IP_ADDRESS_POINTER;\r
3265         xAddress.sin_port = FreeRTOS_htons( pxSocket->usLocalPort );\r
3266 \r
3267         #if( ipconfigTCP_HANG_PROTECTION == 1 )\r
3268         {\r
3269                 /* Only when there is anti-hanging protection, a socket may become an\r
3270                 orphan temporarily.  Once this socket is really connected, the owner of\r
3271                 the server socket will be notified. */\r
3272 \r
3273                 /* When bPassQueued is true, the socket is an orphan until it gets\r
3274                 connected. */\r
3275                 pxNewSocket->u.xTCP.bits.bPassQueued = pdTRUE_UNSIGNED;\r
3276                 pxNewSocket->u.xTCP.pxPeerSocket = pxSocket;\r
3277         }\r
3278         #else\r
3279         {\r
3280                 /* A reference to the new socket may be stored and the socket is marked\r
3281                 as 'passable'. */\r
3282 \r
3283                 /* When bPassAccept is true, this socket may be returned in a call to\r
3284                 accept(). */\r
3285                 pxNewSocket->u.xTCP.bits.bPassAccept = pdTRUE_UNSIGNED;\r
3286                 if(pxSocket->u.xTCP.pxPeerSocket == NULL )\r
3287                 {\r
3288                         pxSocket->u.xTCP.pxPeerSocket = pxNewSocket;\r
3289                 }\r
3290         }\r
3291         #endif\r
3292 \r
3293         pxSocket->u.xTCP.usChildCount++;\r
3294 \r
3295         FreeRTOS_debug_printf( ( "Gain: Socket %u now has %u / %u child%s\n",\r
3296                 pxSocket->usLocalPort,\r
3297                 pxSocket->u.xTCP.usChildCount,\r
3298                 pxSocket->u.xTCP.usBacklog,\r
3299                 pxSocket->u.xTCP.usChildCount == 1u ? "" : "ren" ) );\r
3300 \r
3301         /* Now bind the child socket to the same port as the listening socket. */\r
3302         if( vSocketBind ( pxNewSocket, &xAddress, sizeof( xAddress ), pdTRUE ) != 0 )\r
3303         {\r
3304                 FreeRTOS_debug_printf( ( "TCP: Listen: new socket bind error\n" ) );\r
3305                 vSocketClose( pxNewSocket );\r
3306                 return pdFALSE;\r
3307         }\r
3308 \r
3309         return pdTRUE;\r
3310 }\r
3311 /*-----------------------------------------------------------*/\r
3312 \r
3313 #if( ( ipconfigHAS_DEBUG_PRINTF != 0 ) || ( ipconfigHAS_PRINTF != 0 ) )\r
3314 \r
3315         const char *FreeRTOS_GetTCPStateName( UBaseType_t ulState )\r
3316         {\r
3317                 if( ulState >= ( UBaseType_t ) ARRAY_SIZE( pcStateNames ) )\r
3318                 {\r
3319                         ulState = ( UBaseType_t ) ARRAY_SIZE( pcStateNames ) - 1u;\r
3320                 }\r
3321                 return pcStateNames[ ulState ];\r
3322         }\r
3323 \r
3324 #endif /* ( ( ipconfigHAS_DEBUG_PRINTF != 0 ) || ( ipconfigHAS_PRINTF != 0 ) ) */\r
3325 /*-----------------------------------------------------------*/\r
3326 \r
3327 /*\r
3328  * In the API accept(), the user asks is there is a new client?  As API's can\r
3329  * not walk through the xBoundTCPSocketsList the IP-task will do this.\r
3330  */\r
3331 BaseType_t xTCPCheckNewClient( FreeRTOS_Socket_t *pxSocket )\r
3332 {\r
3333 TickType_t xLocalPort = FreeRTOS_htons( pxSocket->usLocalPort );\r
3334 ListItem_t *pxIterator;\r
3335 FreeRTOS_Socket_t *pxFound;\r
3336 BaseType_t xResult = pdFALSE;\r
3337 \r
3338         /* Here xBoundTCPSocketsList can be accessed safely IP-task is the only one\r
3339         who has access. */\r
3340         for( pxIterator = ( ListItem_t * ) listGET_HEAD_ENTRY( &xBoundTCPSocketsList );\r
3341                 pxIterator != ( ListItem_t * ) listGET_END_MARKER( &xBoundTCPSocketsList );\r
3342                 pxIterator = ( ListItem_t * ) listGET_NEXT( pxIterator ) )\r
3343         {\r
3344                 if( listGET_LIST_ITEM_VALUE( pxIterator ) == xLocalPort )\r
3345                 {\r
3346                         pxFound = ( FreeRTOS_Socket_t * ) listGET_LIST_ITEM_OWNER( pxIterator );\r
3347                         if( ( pxFound->ucProtocol == FREERTOS_IPPROTO_TCP ) && ( pxFound->u.xTCP.bits.bPassAccept != pdFALSE_UNSIGNED ) )\r
3348                         {\r
3349                                 pxSocket->u.xTCP.pxPeerSocket = pxFound;\r
3350                                 FreeRTOS_debug_printf( ( "xTCPCheckNewClient[0]: client on port %u\n", pxSocket->usLocalPort ) );\r
3351                                 xResult = pdTRUE;\r
3352                                 break;\r
3353                         }\r
3354                 }\r
3355         }\r
3356         return xResult;\r
3357 }\r
3358 /*-----------------------------------------------------------*/\r
3359 \r
3360 #endif /* ipconfigUSE_TCP == 1 */\r
3361 \r