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