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