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