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