]> begriffs open source - freertos/blob - FreeRTOS-Plus/Source/FreeRTOS-Plus-UDP/FreeRTOS_Sockets.c
Add the option to specify a stack size in the standard demo MessageBuffer tests.
[freertos] / FreeRTOS-Plus / Source / FreeRTOS-Plus-UDP / FreeRTOS_Sockets.c
1 /*\r
2  * FreeRTOS+UDP V1.0.4\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://www.FreeRTOS.org\r
23  * http://aws.amazon.com/freertos\r
24  *\r
25  * 1 tab == 4 spaces!\r
26  */\r
27 \r
28 /* Standard includes. */\r
29 #include <stdint.h>\r
30 \r
31 /* FreeRTOS includes. */\r
32 #include "FreeRTOS.h"\r
33 #include "task.h"\r
34 #include "queue.h"\r
35 #include "semphr.h"\r
36 \r
37 /* FreeRTOS+UDP includes. */\r
38 #include "FreeRTOS_UDP_IP.h"\r
39 #include "FreeRTOS_IP_Private.h"\r
40 #include "FreeRTOS_Sockets.h"\r
41 #include "NetworkBufferManagement.h"\r
42 \r
43 /* Sanity check the UDP payload length setting is compatible with the\r
44 fragmentation setting. */\r
45 #if ipconfigCAN_FRAGMENT_OUTGOING_PACKETS == 1\r
46         #if ( ( ipMAX_UDP_PAYLOAD_LENGTH % 8 ) != 0 )\r
47                 #error ( ipconfigNETWORK_MTU - 28 ) must be divisible by 8 when fragmentation is used\r
48         #endif /* ipMAX_UDP_PAYLOAD_LENGTH */\r
49 #endif /* ipconfigFRAGMENT_OUTGOING_PACKETS */\r
50 \r
51 /* The ItemValue of the sockets xBoundSocketListItem member holds the socket's\r
52 port number. */\r
53 #define socketSET_SOCKET_ADDRESS( pxSocket, usPort ) listSET_LIST_ITEM_VALUE( ( &( ( pxSocket )->xBoundSocketListItem ) ), ( usPort ) )\r
54 #define socketGET_SOCKET_ADDRESS( pxSocket ) listGET_LIST_ITEM_VALUE( ( &( ( pxSocket )->xBoundSocketListItem ) ) )\r
55 \r
56 /* xWaitingPacketSemaphore is not created until the socket is bound, so can be\r
57 tested to see if bind() has been called. */\r
58 #define socketSOCKET_IS_BOUND( pxSocket ) ( ( BaseType_t ) pxSocket->xWaitingPacketSemaphore )\r
59 \r
60 /* If FreeRTOS_sendto() is called on a socket that is not bound to a port\r
61 number then, depending on the FreeRTOSIPConfig.h settings, it might be that a\r
62 port number is automatically generated for the socket.  Automatically generated\r
63 port numbers will be between socketAUTO_PORT_ALLOCATION_START_NUMBER and\r
64 0xffff. */\r
65 #define socketAUTO_PORT_ALLOCATION_START_NUMBER ( ( uint16_t ) 0xc000 )\r
66 \r
67 /* When the automatically generated port numbers overflow, the next value used\r
68 is not set back to socketAUTO_PORT_ALLOCATION_START_NUMBER because it is likely\r
69 that the first few automatically generated ports will still be in use.  Instead\r
70 it is reset back to the value defined by this constant. */\r
71 #define socketAUTO_PORT_ALLOCATION_RESET_NUMBER ( ( uint16_t ) 0xc100 )\r
72 \r
73 /* The number of octets that make up an IP address. */\r
74 #define socketMAX_IP_ADDRESS_OCTETS             4\r
75 /*-----------------------------------------------------------*/\r
76 \r
77 /*\r
78  * Allocate the next port number from the private allocation range.\r
79  */\r
80 static uint16_t prvGetPrivatePortNumber( void );\r
81 \r
82 /*\r
83  * Return the list itme from within pxList that has an item value of\r
84  * xWantedItemValue.  If there is no such list item return NULL.\r
85  */\r
86 xListItem * pxListFindListItemWithValue( xList *pxList, TickType_t xWantedItemValue );\r
87 \r
88 /*-----------------------------------------------------------*/\r
89 \r
90 typedef struct XSOCKET\r
91 {\r
92         xSemaphoreHandle xWaitingPacketSemaphore;\r
93         xList xWaitingPacketsList;\r
94         xListItem xBoundSocketListItem; /* Used to reference the socket from a bound sockets list. */\r
95         TickType_t xReceiveBlockTime;\r
96         TickType_t xSendBlockTime;\r
97         uint8_t ucSocketOptions;\r
98         #if ipconfigSUPPORT_SELECT_FUNCTION == 1\r
99                 xQueueHandle xSelectQueue;\r
100         #endif\r
101 } xFreeRTOS_Socket_t;\r
102 \r
103 \r
104 /* The list that contains mappings between sockets and port numbers.  Accesses\r
105 to this list must be protected by critical sections of one kind or another. */\r
106 static xList xBoundSocketsList;\r
107 \r
108 /*-----------------------------------------------------------*/\r
109 \r
110 xSocket_t FreeRTOS_socket( BaseType_t xDomain, BaseType_t xType, BaseType_t xProtocol )\r
111 {\r
112 xFreeRTOS_Socket_t *pxSocket;\r
113 \r
114         /* Only UDP on Ethernet is currently supported. */\r
115         configASSERT( xDomain == FREERTOS_AF_INET );\r
116         configASSERT( xType == FREERTOS_SOCK_DGRAM );\r
117         configASSERT( xProtocol == FREERTOS_IPPROTO_UDP );\r
118         configASSERT( listLIST_IS_INITIALISED( &xBoundSocketsList ) );\r
119 \r
120         /* Allocate the structure that will hold the socket information. */\r
121         pxSocket = ( xFreeRTOS_Socket_t * ) pvPortMalloc( sizeof( xFreeRTOS_Socket_t ) );\r
122 \r
123         if( pxSocket == NULL )\r
124         {\r
125                 pxSocket = ( xFreeRTOS_Socket_t * ) FREERTOS_INVALID_SOCKET;\r
126                 iptraceFAILED_TO_CREATE_SOCKET();\r
127         }\r
128         else\r
129         {\r
130                 /* Initialise the socket's members.  The semaphore will be created if\r
131                 the socket is bound to an address, for now the pointer to the semaphore\r
132                 is just set to NULL to show it has not been created. */\r
133                 pxSocket->xWaitingPacketSemaphore = NULL;\r
134                 vListInitialise( &( pxSocket->xWaitingPacketsList ) );\r
135                 vListInitialiseItem( &( pxSocket->xBoundSocketListItem ) );\r
136                 listSET_LIST_ITEM_OWNER( &( pxSocket->xBoundSocketListItem ), ( void * ) pxSocket );\r
137                 pxSocket->xSendBlockTime = ( TickType_t ) 0;\r
138                 pxSocket->xReceiveBlockTime = portMAX_DELAY;\r
139                 pxSocket->ucSocketOptions = FREERTOS_SO_UDPCKSUM_OUT;\r
140                 #if ipconfigSUPPORT_SELECT_FUNCTION == 1\r
141                         pxSocket->xSelectQueue = NULL;\r
142                 #endif\r
143         }\r
144 \r
145         /* Remove compiler warnings in the case the configASSERT() is not defined. */\r
146         ( void ) xDomain;\r
147         ( void ) xType;\r
148         ( void ) xProtocol;\r
149 \r
150         return ( xSocket_t ) pxSocket;\r
151 }\r
152 /*-----------------------------------------------------------*/\r
153 \r
154 #if ipconfigSUPPORT_SELECT_FUNCTION == 1\r
155 \r
156         xSocketSet_t FreeRTOS_CreateSocketSet( UBaseType_t uxEventQueueLength )\r
157         {\r
158         xQueueHandle xSelectQueue;\r
159 \r
160                 /* Create the queue into which the address of sockets that are\r
161                 available to read are posted. */\r
162                 xSelectQueue = xQueueCreate( uxEventQueueLength, sizeof( xSocket_t ) );\r
163 \r
164                 return ( xSocketSet_t ) xSelectQueue;\r
165         }\r
166 \r
167 #endif /* ipconfigSUPPORT_SELECT_FUNCTION */\r
168 /*-----------------------------------------------------------*/\r
169 \r
170 #if ipconfigSUPPORT_SELECT_FUNCTION == 1\r
171 \r
172         BaseType_t FreeRTOS_FD_SET( xSocket_t xSocket, xSocketSet_t xSocketSet )\r
173         {\r
174         xFreeRTOS_Socket_t *pxSocket = ( xFreeRTOS_Socket_t * ) xSocket;\r
175         BaseType_t xReturn = pdFALSE;\r
176         UBaseType_t uxMessagesWaiting;\r
177 \r
178                 configASSERT( xSocket );\r
179 \r
180                 /* Is the socket already a member of a select group? */\r
181                 if( pxSocket->xSelectQueue == NULL )\r
182                 {\r
183                         taskENTER_CRITICAL();\r
184                         {\r
185                                 /* Are there packets queued on the socket already? */\r
186                                 uxMessagesWaiting = uxQueueMessagesWaiting( pxSocket->xWaitingPacketSemaphore );\r
187 \r
188                                 /* Are there enough notification spaces in the select queue for the\r
189                                 number of packets already queued on the socket? */\r
190                                 if( uxQueueSpacesAvailable( ( xQueueHandle ) xSocketSet ) >= uxMessagesWaiting )\r
191                                 {\r
192                                         /* Store a pointer to the select group in the socket for\r
193                                         future reference. */\r
194                                         pxSocket->xSelectQueue = ( xQueueHandle ) xSocketSet;\r
195 \r
196                                         while( uxMessagesWaiting > 0 )\r
197                                         {\r
198                                                 /* Add notifications of the number of packets that are\r
199                                                 already queued on the socket to the select queue. */\r
200                                                 xQueueSendFromISR( pxSocket->xSelectQueue, &pxSocket, NULL );\r
201                                                 uxMessagesWaiting--;\r
202                                         }\r
203 \r
204                                         xReturn = pdPASS;\r
205                                 }\r
206                         }\r
207                         taskEXIT_CRITICAL();\r
208                 }\r
209 \r
210                 return xReturn;\r
211         }\r
212 \r
213 #endif /* ipconfigSUPPORT_SELECT_FUNCTION */\r
214 /*-----------------------------------------------------------*/\r
215 \r
216 #if ipconfigSUPPORT_SELECT_FUNCTION == 1\r
217 \r
218         BaseType_t FreeRTOS_FD_CLR( xSocket_t xSocket, xSocketSet_t xSocketSet )\r
219         {\r
220         xFreeRTOS_Socket_t *pxSocket = ( xFreeRTOS_Socket_t * ) xSocket;\r
221         BaseType_t xReturn;\r
222 \r
223                 /* Is the socket a member of the select group? */\r
224                 if( pxSocket->xSelectQueue == ( xQueueHandle ) xSocketSet )\r
225                 {\r
226                         /* The socket is no longer a member of the select group. */\r
227                         pxSocket->xSelectQueue = NULL;\r
228                         xReturn = pdPASS;\r
229                 }\r
230                 else\r
231                 {\r
232                         xReturn = pdFAIL;\r
233                 }\r
234 \r
235                 return xReturn;\r
236         }\r
237 \r
238 #endif /* ipconfigSUPPORT_SELECT_FUNCTION */\r
239 /*-----------------------------------------------------------*/\r
240 \r
241 #if ipconfigSUPPORT_SELECT_FUNCTION == 1\r
242 \r
243         xSocket_t FreeRTOS_select( xSocketSet_t xSocketSet, TickType_t xBlockTimeTicks )\r
244         {\r
245         xFreeRTOS_Socket_t *pxSocket;\r
246 \r
247                 /* Wait for a socket to be ready to read. */\r
248                 if( xQueueReceive( ( xQueueHandle ) xSocketSet, &pxSocket, xBlockTimeTicks ) != pdPASS )\r
249                 {\r
250                         pxSocket = NULL;\r
251                 }\r
252 \r
253                 return ( xSocket_t ) pxSocket;\r
254         }\r
255 \r
256 #endif /* ipconfigSUPPORT_SELECT_FUNCTION */\r
257 /*-----------------------------------------------------------*/\r
258 \r
259 int32_t FreeRTOS_recvfrom( xSocket_t xSocket, void *pvBuffer, size_t xBufferLength, uint32_t ulFlags, struct freertos_sockaddr *pxSourceAddress, socklen_t *pxSourceAddressLength )\r
260 {\r
261 xNetworkBufferDescriptor_t *pxNetworkBuffer;\r
262 int32_t lReturn;\r
263 xFreeRTOS_Socket_t *pxSocket;\r
264 \r
265         pxSocket = ( xFreeRTOS_Socket_t * ) xSocket;\r
266 \r
267         /* The function prototype is designed to maintain the expected Berkeley\r
268         sockets standard, but this implementation does not use all the parameters. */\r
269         ( void ) pxSourceAddressLength;\r
270 \r
271         if( socketSOCKET_IS_BOUND( pxSocket ) != pdFALSE )\r
272         {\r
273                 /* The semaphore is given when received data is queued on the socket. */\r
274                 if( xSemaphoreTake( pxSocket->xWaitingPacketSemaphore, pxSocket->xReceiveBlockTime ) == pdPASS )\r
275                 {\r
276                         taskENTER_CRITICAL();\r
277                         {\r
278                                 configASSERT( ( listCURRENT_LIST_LENGTH( &( pxSocket->xWaitingPacketsList ) ) > 0U ) );\r
279 \r
280                                 /* The owner of the list item is the network buffer. */\r
281                                 pxNetworkBuffer = ( xNetworkBufferDescriptor_t * ) listGET_OWNER_OF_HEAD_ENTRY( &( pxSocket->xWaitingPacketsList ) );\r
282 \r
283                                 /* Remove the network buffer from the list of buffers waiting to\r
284                                 be processed by the socket. */\r
285                                 uxListRemove( &( pxNetworkBuffer->xBufferListItem ) );\r
286                         }\r
287                         taskEXIT_CRITICAL();\r
288 \r
289                         if( ( ulFlags & FREERTOS_ZERO_COPY ) == 0 )\r
290                         {\r
291                                 /* The zero copy flag is not set.  Truncate the length if it\r
292                                 won't fit in the provided buffer. */\r
293                                 if( pxNetworkBuffer->xDataLength > xBufferLength )\r
294                                 {\r
295                                         iptraceRECVFROM_DISCARDING_BYTES( ( xBufferLength - pxNetworkBuffer->xDataLength ) );\r
296                                         pxNetworkBuffer->xDataLength = xBufferLength;\r
297                                 }\r
298 \r
299                                 /* Copy the received data into the provided buffer, then\r
300                                 release the network buffer. */\r
301                                 memcpy( pvBuffer, ( void * ) &( pxNetworkBuffer->pucEthernetBuffer[ ipUDP_PAYLOAD_OFFSET ] ), pxNetworkBuffer->xDataLength );\r
302                                 vNetworkBufferRelease( pxNetworkBuffer );\r
303                         }\r
304                         else\r
305                         {\r
306                                 /* The zero copy flag was set.  pvBuffer is not a buffer into\r
307                                 which the received data can be copied, but a pointer that must\r
308                                 be set to point to the buffer in which the received data has\r
309                                 already been placed. */\r
310                                 *( ( void** ) pvBuffer ) = ( void * ) ( &( pxNetworkBuffer->pucEthernetBuffer[ ipUDP_PAYLOAD_OFFSET ] ) );\r
311                         }\r
312 \r
313                         /* The returned value is the data length, which may have been\r
314                         capped to the receive buffer size. */\r
315                         lReturn = ( int32_t ) pxNetworkBuffer->xDataLength;\r
316 \r
317                         if( pxSourceAddress != NULL )\r
318                         {\r
319                                 pxSourceAddress->sin_port = pxNetworkBuffer->usPort;\r
320                                 pxSourceAddress->sin_addr = pxNetworkBuffer->ulIPAddress;\r
321                         }\r
322                 }\r
323                 else\r
324                 {\r
325                         lReturn = FREERTOS_EWOULDBLOCK;\r
326                         iptraceRECVFROM_TIMEOUT();\r
327                 }\r
328         }\r
329         else\r
330         {\r
331                 lReturn = FREERTOS_EINVAL;\r
332         }\r
333 \r
334         return lReturn;\r
335 }\r
336 /*-----------------------------------------------------------*/\r
337 \r
338 #if ipconfigCAN_FRAGMENT_OUTGOING_PACKETS == 1\r
339 \r
340         int32_t FreeRTOS_sendto( xSocket_t xSocket, const void *pvBuffer, size_t xTotalDataLength, uint32_t ulFlags, const struct freertos_sockaddr *pxDestinationAddress, socklen_t xDestinationAddressLength )\r
341         {\r
342         xNetworkBufferDescriptor_t *pxNetworkBuffer;\r
343         xIPFragmentParameters_t *pxFragmentParameters;\r
344         size_t xBytesToSend, xBytesRemaining;\r
345         xIPStackEvent_t xStackTxEvent = { eStackTxEvent, NULL };\r
346         extern xQueueHandle xNetworkEventQueue;\r
347         uint8_t *pucBuffer;\r
348         xTimeOutType xTimeOut;\r
349         TickType_t xTicksToWait;\r
350         uint16_t usFragmentOffset;\r
351         xFreeRTOS_Socket_t *pxSocket;\r
352 \r
353                 pxSocket = ( xFreeRTOS_Socket_t * ) xSocket;\r
354 \r
355                 /* The function prototype is designed to maintain the expected Berkeley\r
356                 sockets standard, but this implementation does not use all the\r
357                 parameters. */\r
358                 ( void ) xDestinationAddressLength;\r
359                 configASSERT( xNetworkEventQueue );\r
360                 configASSERT( pvBuffer );\r
361 \r
362                 xBytesRemaining = xTotalDataLength;\r
363 \r
364                 if( socketSOCKET_IS_BOUND( pxSocket ) == pdFALSE )\r
365                 {\r
366                         /* If the socket is not already bound to an address, bind it now.\r
367                         Passing NULL as the address parameter tells FreeRTOS_bind() to select\r
368                         the address to bind to. */\r
369                         FreeRTOS_bind( xSocket, NULL, 0 );\r
370                 }\r
371 \r
372                 if( socketSOCKET_IS_BOUND( pxSocket ) != pdFALSE )\r
373                 {\r
374                         /* pucBuffer will be reset if this send turns out to be a zero copy\r
375                         send because in that case pvBuffer is actually a pointer to an\r
376                         xUserData_t structure, not the UDP payload. */\r
377                         pucBuffer = ( uint8_t * ) pvBuffer;\r
378                         vTaskSetTimeOutState( &xTimeOut );\r
379                         xTicksToWait = pxSocket->xSendBlockTime;\r
380 \r
381                         /* The data being transmitted will be sent in\r
382                         ipMAX_UDP_PAYLOAD_LENGTH chunks if xDataLength is greater than the\r
383                         network buffer payload size.  Loop until all the data is sent. */\r
384                         while( xBytesRemaining > 0 )\r
385                         {\r
386                                 if( xBytesRemaining > ipMAX_UDP_PAYLOAD_LENGTH )\r
387                                 {\r
388                                         /* Cap the amount being sent in this packet to the maximum\r
389                                         UDP payload size.  This will be a multiple of 8 already,\r
390                                         removing the need to check in the code. */\r
391                                         xBytesToSend = ipMAX_UDP_PAYLOAD_LENGTH;\r
392                                 }\r
393                                 else\r
394                                 {\r
395                                         /* Send all remaining bytes - which may well be the total\r
396                                         number of bytes if the packet was not chopped up. */\r
397                                         xBytesToSend = xBytesRemaining;\r
398                                 }\r
399 \r
400                                 /* If the zero copy flag is set, then the data is already in a\r
401                                 network buffer.  Otherwise, get a new network buffer. */\r
402                                 if( ( ulFlags & FREERTOS_ZERO_COPY ) == 0 )\r
403                                 {\r
404                                         if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdTRUE )\r
405                                         {\r
406                                                 xTicksToWait = 0;\r
407                                         }\r
408 \r
409                                         pxNetworkBuffer = pxNetworkBufferGet( xBytesToSend + sizeof( xUDPPacket_t ), xTicksToWait );\r
410                                 }\r
411                                 else\r
412                                 {\r
413                                         if( xTotalDataLength > ipMAX_UDP_PAYLOAD_LENGTH )\r
414                                         {\r
415                                                 /* The packet needs fragmenting, but zero copy buffers\r
416                                                 cannot be fragmented. */\r
417                                                 pxNetworkBuffer = NULL;\r
418                                         }\r
419                                         else\r
420                                         {\r
421                                                 /* When zero copy is used, pvBuffer is a pointer to the\r
422                                                 payload of a buffer that has already been obtained from the\r
423                                                 stack.  Obtain the network buffer pointer from the buffer. */\r
424                                                 pucBuffer = ( uint8_t * ) pvBuffer;\r
425                                                 pucBuffer -= ( ipBUFFER_PADDING + sizeof( xUDPPacket_t ) );\r
426                                                 pxNetworkBuffer = * ( ( xNetworkBufferDescriptor_t ** ) pucBuffer );\r
427                                         }\r
428                                 }\r
429 \r
430                                 if( pxNetworkBuffer != NULL )\r
431                                 {\r
432                                         /* Use the part of the network buffer that will be completed\r
433                                         by the IP layer as temporary storage to pass extra\r
434                                         information required by the IP layer. */\r
435                                         pxFragmentParameters = ( xIPFragmentParameters_t * ) &( pxNetworkBuffer->pucEthernetBuffer[ ipFRAGMENTATION_PARAMETERS_OFFSET ] );\r
436                                         pxFragmentParameters->ucSocketOptions = pxSocket->ucSocketOptions;\r
437 \r
438                                         if( xBytesRemaining > ipMAX_UDP_PAYLOAD_LENGTH )\r
439                                         {\r
440                                                 /* The packet is being chopped up, and more data will\r
441                                                 follow. */\r
442                                                 pxFragmentParameters->ucSocketOptions = ( pxSocket->ucSocketOptions | FREERTOS_NOT_LAST_IN_FRAGMENTED_PACKET );\r
443                                         }\r
444 \r
445                                         if( xTotalDataLength > ipMAX_UDP_PAYLOAD_LENGTH )\r
446                                         {\r
447                                                 /* Let the IP layer know this packet has been chopped up,\r
448                                                 and supply the IP layer with any addition information it\r
449                                                 needs to make sense of it. */\r
450                                                 pxFragmentParameters->ucSocketOptions |= FREERTOS_FRAGMENTED_PACKET;\r
451                                                 usFragmentOffset = ( uint16_t ) ( xTotalDataLength - xBytesRemaining );\r
452                                                 pxFragmentParameters->usFragmentedPacketOffset = usFragmentOffset;\r
453                                                 pxFragmentParameters->usFragmentLength = ( uint16_t ) xBytesToSend;\r
454                                         }\r
455                                         else\r
456                                         {\r
457                                                 usFragmentOffset = 0;\r
458                                         }\r
459 \r
460                                         /* Write the payload into the packet.  The IP layer is\r
461                                         queried to find where in the IP payload the data should be\r
462                                         written.  This is because the necessary offset is different\r
463                                         for the first packet, because the first packet leaves space\r
464                                         for a UDP header.  Note that this changes usFragmentOffset\r
465                                         from the offset in the entire UDP packet, to the offset\r
466                                         in the IP packet. */\r
467                                         if( ( ulFlags & FREERTOS_ZERO_COPY ) == 0 )\r
468                                         {\r
469                                                 /* Only copy the data if it is not already in the\r
470                                                 expected location. */\r
471                                                 usFragmentOffset = ipGET_UDP_PAYLOAD_OFFSET_FOR_FRAGMENT( usFragmentOffset );\r
472                                                 memcpy( ( void * ) &( pxNetworkBuffer->pucEthernetBuffer[ usFragmentOffset ] ), ( void * ) pucBuffer, xBytesToSend );\r
473                                         }\r
474                                         pxNetworkBuffer->xDataLength = xTotalDataLength;\r
475                                         pxNetworkBuffer->usPort = pxDestinationAddress->sin_port;\r
476                                         pxNetworkBuffer->usBoundPort = ( uint16_t ) socketGET_SOCKET_ADDRESS( pxSocket );\r
477                                         pxNetworkBuffer->ulIPAddress = pxDestinationAddress->sin_addr;\r
478 \r
479                                         /* Tell the networking task that the packet needs sending. */\r
480                                         xStackTxEvent.pvData = pxNetworkBuffer;\r
481 \r
482                                         if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdTRUE )\r
483                                         {\r
484                                                 xTicksToWait = 0;\r
485                                         }\r
486 \r
487                                         if( xQueueSendToBack( xNetworkEventQueue, &xStackTxEvent, xTicksToWait ) != pdPASS )\r
488                                         {\r
489                                                 /* If the buffer was allocated in this function, release it. */\r
490                                                 if( ( ulFlags & FREERTOS_ZERO_COPY ) == 0 )\r
491                                                 {\r
492                                                         vNetworkBufferRelease( pxNetworkBuffer );\r
493                                                 }\r
494                                                 iptraceSTACK_TX_EVENT_LOST( ipSTACK_TX_EVENT );\r
495                                                 break;\r
496                                         }\r
497 \r
498                                         /* Adjust counters ready to either exit the loop, or send\r
499                                         another chunk of data. */\r
500                                         xBytesRemaining -= xBytesToSend;\r
501                                         pucBuffer += xBytesToSend;\r
502                                 }\r
503                                 else\r
504                                 {\r
505                                         /* If errno was available, errno would be set to\r
506                                         FREERTOS_ENOPKTS.  As it is, the function must return the\r
507                                         number of transmitted bytes, so the calling function knows how\r
508                                         much data was actually sent. */\r
509                                         break;\r
510                                 }\r
511                         }\r
512                 }\r
513 \r
514                 return ( xTotalDataLength - xBytesRemaining );\r
515         } /* Tested */\r
516 \r
517 #else /* ipconfigCAN_FRAGMENT_OUTGOING_PACKETS */\r
518 \r
519         int32_t FreeRTOS_sendto( xSocket_t xSocket, const void *pvBuffer, size_t xTotalDataLength, uint32_t ulFlags, const struct freertos_sockaddr *pxDestinationAddress, socklen_t xDestinationAddressLength )\r
520         {\r
521         xNetworkBufferDescriptor_t *pxNetworkBuffer;\r
522         xIPStackEvent_t xStackTxEvent = { eStackTxEvent, NULL };\r
523         extern xQueueHandle xNetworkEventQueue;\r
524         xTimeOutType xTimeOut;\r
525         TickType_t xTicksToWait;\r
526         int32_t lReturn = 0;\r
527         xFreeRTOS_Socket_t *pxSocket;\r
528         uint8_t *pucBuffer;\r
529 \r
530                 pxSocket = ( xFreeRTOS_Socket_t * ) xSocket;\r
531 \r
532                 /* The function prototype is designed to maintain the expected Berkeley\r
533                 sockets standard, but this implementation does not use all the\r
534                 parameters. */\r
535                 ( void ) xDestinationAddressLength;\r
536                 configASSERT( xNetworkEventQueue );\r
537                 configASSERT( pvBuffer );\r
538 \r
539                 if( xTotalDataLength <= ipMAX_UDP_PAYLOAD_LENGTH )\r
540                 {\r
541                         if( socketSOCKET_IS_BOUND( pxSocket ) == pdFALSE )\r
542                         {\r
543                                 /* If the socket is not already bound to an address, bind it now.\r
544                                 Passing NULL as the address parameter tells FreeRTOS_bind() to\r
545                                 select the address to bind to. */\r
546                                 FreeRTOS_bind( pxSocket, NULL, 0 );\r
547                         }\r
548 \r
549                         if( socketSOCKET_IS_BOUND( pxSocket ) != pdFALSE )\r
550                         {\r
551                                 xTicksToWait = pxSocket->xSendBlockTime;\r
552 \r
553                                 if( ( ulFlags & FREERTOS_ZERO_COPY ) == 0 )\r
554                                 {\r
555                                         /* Zero copy is not set, so obtain a network buffer into\r
556                                         which the payload will be copied. */\r
557                                         vTaskSetTimeOutState( &xTimeOut );\r
558                                         pxNetworkBuffer = pxNetworkBufferGet( xTotalDataLength + sizeof( xUDPPacket_t ), xTicksToWait );\r
559 \r
560                                         if( pxNetworkBuffer != NULL )\r
561                                         {\r
562                                                 memcpy( ( void * ) &( pxNetworkBuffer->pucEthernetBuffer[ ipUDP_PAYLOAD_OFFSET ] ), ( void * ) pvBuffer, xTotalDataLength );\r
563 \r
564                                                 if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdTRUE )\r
565                                                 {\r
566                                                         /* The entire block time has been used up. */\r
567                                                         xTicksToWait = 0;\r
568                                                 }\r
569                                         }\r
570                                 }\r
571                                 else\r
572                                 {\r
573                                         /* When zero copy is used, pvBuffer is a pointer to the\r
574                                         payload of a buffer that has already been obtained from the\r
575                                         stack.  Obtain the network buffer pointer from the buffer. */\r
576                                         pucBuffer = ( uint8_t * ) pvBuffer;\r
577                                         pucBuffer -= ( ipBUFFER_PADDING + sizeof( xUDPPacket_t ) );\r
578                                         pxNetworkBuffer = * ( ( xNetworkBufferDescriptor_t ** ) pucBuffer );\r
579                                 }\r
580 \r
581                                 if( pxNetworkBuffer != NULL )\r
582                                 {\r
583                                         pxNetworkBuffer->xDataLength = xTotalDataLength;\r
584                                         pxNetworkBuffer->usPort = pxDestinationAddress->sin_port;\r
585                                         pxNetworkBuffer->usBoundPort = ( uint16_t ) socketGET_SOCKET_ADDRESS( pxSocket );\r
586                                         pxNetworkBuffer->ulIPAddress = pxDestinationAddress->sin_addr;\r
587 \r
588                                         /* The socket options are passed to the IP layer in the\r
589                                         space that will eventually get used by the Ethernet header. */\r
590                                         pxNetworkBuffer->pucEthernetBuffer[ ipSOCKET_OPTIONS_OFFSET ] = pxSocket->ucSocketOptions;\r
591 \r
592                                         /* Tell the networking task that the packet needs sending. */\r
593                                         xStackTxEvent.pvData = pxNetworkBuffer;\r
594 \r
595                                         if( xQueueSendToBack( xNetworkEventQueue, &xStackTxEvent, xTicksToWait ) != pdPASS )\r
596                                         {\r
597                                                 /* If the buffer was allocated in this function, release it. */\r
598                                                 if( ( ulFlags & FREERTOS_ZERO_COPY ) == 0 )\r
599                                                 {\r
600                                                         vNetworkBufferRelease( pxNetworkBuffer );\r
601                                                 }\r
602                                                 iptraceSTACK_TX_EVENT_LOST( ipSTACK_TX_EVENT );\r
603                                         }\r
604                                         else\r
605                                         {\r
606                                                 lReturn = ( int32_t ) xTotalDataLength;\r
607                                         }\r
608                                 }\r
609                                 else\r
610                                 {\r
611                                         /* If errno was available, errno would be set to\r
612                                         FREERTOS_ENOPKTS.  As it is, the function must return the\r
613                                         number of transmitted bytes, so the calling function knows how\r
614                                         much data was actually sent. */\r
615                                         iptraceNO_BUFFER_FOR_SENDTO();\r
616                                 }\r
617                         }\r
618                         else\r
619                         {\r
620                                 iptraceSENDTO_SOCKET_NOT_BOUND();\r
621                         }\r
622                 }\r
623                 else\r
624                 {\r
625                         /* The data is longer than the available buffer space.  Setting\r
626                         ipconfigCAN_FRAGMENT_OUTGOING_PACKETS to 1 may allow this packet\r
627                         to be sent. */\r
628                         iptraceSENDTO_DATA_TOO_LONG();\r
629                 }\r
630 \r
631                 return lReturn;\r
632         } /* Tested */\r
633 \r
634 #endif /* ipconfigCAN_FRAGMENT_OUTGOING_PACKETS */\r
635 /*-----------------------------------------------------------*/\r
636 \r
637 BaseType_t FreeRTOS_bind( xSocket_t xSocket, struct freertos_sockaddr * pxAddress, socklen_t xAddressLength )\r
638 {\r
639 BaseType_t xReturn = 0; /* In Berkeley sockets, 0 means pass for bind(). */\r
640 xFreeRTOS_Socket_t *pxSocket;\r
641 #if ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND == 1\r
642         struct freertos_sockaddr xAddress;\r
643 #endif /* ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND */\r
644 \r
645         pxSocket = ( xFreeRTOS_Socket_t * ) xSocket;\r
646 \r
647         /* The function prototype is designed to maintain the expected Berkeley\r
648         sockets standard, but this implementation does not use all the parameters. */\r
649         ( void ) xAddressLength;\r
650 \r
651         configASSERT( xSocket );\r
652         configASSERT( xSocket != FREERTOS_INVALID_SOCKET );\r
653 \r
654         #if ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND == 1\r
655         {\r
656                 /* pxAddress will be NULL if sendto() was called on a socket without the\r
657                 socket being bound to an address.  In this case, automatically allocate\r
658                 an address to the socket.  There is a very tiny chance that the allocated\r
659                 port will already be in use - if that is the case, then the check below\r
660                 [pxListFindListItemWithValue()] will result in an error being returned. */\r
661                 if( pxAddress == NULL )\r
662                 {\r
663                         pxAddress = &xAddress;\r
664                         pxAddress->sin_port = prvGetPrivatePortNumber();\r
665                 }\r
666         }\r
667         #endif /* ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND == 1 */\r
668 \r
669         /* Sockets must be bound before calling FreeRTOS_sendto() if\r
670         ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND is not set to 1. */\r
671         configASSERT( pxAddress );\r
672 \r
673         if( pxAddress != NULL )\r
674         {\r
675                 if( pxAddress->sin_port == 0 )\r
676                 {\r
677                         pxAddress->sin_port = prvGetPrivatePortNumber();\r
678                 }\r
679 \r
680                 vTaskSuspendAll();\r
681                 {\r
682                         /* Check to ensure the port is not already in use. */\r
683                         if( pxListFindListItemWithValue( &xBoundSocketsList, ( TickType_t ) pxAddress->sin_port ) != NULL )\r
684                         {\r
685                                 xReturn = FREERTOS_EADDRINUSE;\r
686                         }\r
687                 }\r
688                 xTaskResumeAll();\r
689 \r
690                 /* Check that xReturn has not been set before continuing. */\r
691                 if( xReturn == 0 )\r
692                 {\r
693                         if( pxSocket->xWaitingPacketSemaphore == NULL )\r
694                         {\r
695                                 /* Create the semaphore used to count the number of packets that\r
696                                 are queued on this socket. */\r
697                                 pxSocket->xWaitingPacketSemaphore = xSemaphoreCreateCounting( ipconfigNUM_NETWORK_BUFFERS, 0 );\r
698 \r
699                                 if( pxSocket->xWaitingPacketSemaphore != NULL )\r
700                                 {\r
701                                         /* Allocate the port number to the socket. */\r
702                                         socketSET_SOCKET_ADDRESS( pxSocket, pxAddress->sin_port );\r
703                                         taskENTER_CRITICAL();\r
704                                         {\r
705                                                 /* Add the socket to the list of bound ports. */\r
706                                                 vListInsertEnd( &xBoundSocketsList, &( pxSocket->xBoundSocketListItem ) );\r
707                                         }\r
708                                         taskEXIT_CRITICAL();\r
709                                 }\r
710                                 else\r
711                                 {\r
712                                         /* Out of memory. */\r
713                                         xReturn = FREERTOS_ENOBUFS;\r
714                                 }\r
715                         }\r
716                         else\r
717                         {\r
718                                 /* The socket is already bound. */\r
719                                 xReturn = FREERTOS_EINVAL;\r
720                         }\r
721                 }\r
722         }\r
723         else\r
724         {\r
725                 xReturn = FREERTOS_EADDRNOTAVAIL;\r
726         }\r
727 \r
728         if( xReturn != 0 )\r
729         {\r
730                 iptraceBIND_FAILED( xSocket, ( FreeRTOS_ntohs( pxAddress->sin_port ) ) );\r
731         }\r
732 \r
733         return xReturn;\r
734 } /* Tested */\r
735 /*-----------------------------------------------------------*/\r
736 \r
737 BaseType_t FreeRTOS_closesocket( xSocket_t xSocket )\r
738 {\r
739 xNetworkBufferDescriptor_t *pxNetworkBuffer;\r
740 xFreeRTOS_Socket_t *pxSocket;\r
741 \r
742         pxSocket = ( xFreeRTOS_Socket_t * ) xSocket;\r
743 \r
744         configASSERT( pxSocket );\r
745         configASSERT( pxSocket != FREERTOS_INVALID_SOCKET );\r
746 \r
747         /* Socket must be unbound first, to ensure no more packets are queued on\r
748         it. */\r
749         if( socketSOCKET_IS_BOUND( pxSocket ) != pdFALSE )\r
750         {\r
751                 taskENTER_CRITICAL();\r
752                 {\r
753                         uxListRemove( &( pxSocket->xBoundSocketListItem ) );\r
754                 }\r
755                 taskEXIT_CRITICAL();\r
756         }\r
757 \r
758         /* Now the socket is not bound the list of waiting packets can be\r
759         drained. */\r
760         if( pxSocket->xWaitingPacketSemaphore != NULL )\r
761         {\r
762                 while( listCURRENT_LIST_LENGTH( &( pxSocket->xWaitingPacketsList ) ) > 0U )\r
763                 {\r
764                         pxNetworkBuffer = ( xNetworkBufferDescriptor_t * ) listGET_OWNER_OF_HEAD_ENTRY( &( pxSocket->xWaitingPacketsList ) );\r
765                         uxListRemove( &( pxNetworkBuffer->xBufferListItem ) );\r
766                         vNetworkBufferRelease( pxNetworkBuffer );\r
767                 }\r
768                 vSemaphoreDelete( pxSocket->xWaitingPacketSemaphore );\r
769         }\r
770 \r
771         vPortFree( pxSocket );\r
772 \r
773         return 0;\r
774 } /* Tested */\r
775 /*-----------------------------------------------------------*/\r
776 \r
777 void FreeRTOS_SocketsInit( void )\r
778 {\r
779         vListInitialise( &xBoundSocketsList );\r
780 }\r
781 /*-----------------------------------------------------------*/\r
782 \r
783 BaseType_t FreeRTOS_setsockopt( xSocket_t xSocket, int32_t lLevel, int32_t lOptionName, const void *pvOptionValue, size_t xOptionLength )\r
784 {\r
785 /* The standard Berkeley function returns 0 for success. */\r
786 BaseType_t xReturn = 0;\r
787 BaseType_t lOptionValue;\r
788 xFreeRTOS_Socket_t *pxSocket;\r
789 \r
790         pxSocket = ( xFreeRTOS_Socket_t * ) xSocket;\r
791 \r
792         /* The function prototype is designed to maintain the expected Berkeley\r
793         sockets standard, but this implementation does not use all the parameters. */\r
794         ( void ) lLevel;\r
795         ( void ) xOptionLength;\r
796 \r
797         configASSERT( xSocket );\r
798 \r
799         switch( lOptionName )\r
800         {\r
801                 case FREERTOS_SO_RCVTIMEO       :\r
802                         /* Receive time out. */\r
803                         pxSocket->xReceiveBlockTime = *( ( TickType_t * ) pvOptionValue );\r
804                         break;\r
805 \r
806                 case FREERTOS_SO_SNDTIMEO       :\r
807                         /* The send time out is capped for the reason stated in the comments\r
808                         where ipconfigMAX_SEND_BLOCK_TIME_TICKS is defined in\r
809                         FreeRTOSIPConfig.h (assuming an official configuration file is being\r
810                         used. */\r
811                         pxSocket->xSendBlockTime = *( ( TickType_t * ) pvOptionValue );\r
812                         if( pxSocket->xSendBlockTime > ipconfigMAX_SEND_BLOCK_TIME_TICKS )\r
813                         {\r
814                                 pxSocket->xSendBlockTime = ipconfigMAX_SEND_BLOCK_TIME_TICKS;\r
815                         }\r
816                         break;\r
817 \r
818                 case FREERTOS_SO_UDPCKSUM_OUT :\r
819                         /* Turn calculating of the UDP checksum on/off for this socket. */\r
820                         lOptionValue = ( BaseType_t ) pvOptionValue;\r
821 \r
822                         if( lOptionValue == 0 )\r
823                         {\r
824                                 pxSocket->ucSocketOptions &= ~FREERTOS_SO_UDPCKSUM_OUT;\r
825                         }\r
826                         else\r
827                         {\r
828                                 pxSocket->ucSocketOptions |= FREERTOS_SO_UDPCKSUM_OUT;\r
829                         }\r
830                         break;\r
831 \r
832                 default :\r
833                         /* No other options are handled. */\r
834                         xReturn = FREERTOS_ENOPROTOOPT;\r
835                         break;\r
836         }\r
837 \r
838         return xReturn;\r
839 } /* Tested */\r
840 /*-----------------------------------------------------------*/\r
841 \r
842 BaseType_t xProcessReceivedUDPPacket( xNetworkBufferDescriptor_t *pxNetworkBuffer, uint16_t usPort )\r
843 {\r
844 xListItem *pxListItem;\r
845 BaseType_t xReturn = pdPASS;\r
846 xFreeRTOS_Socket_t *pxSocket;\r
847 BaseType_t xHigherPriorityTaskWoken = pdFALSE;\r
848 \r
849         vTaskSuspendAll();\r
850         {\r
851                 /* See if there is a list item associated with the port number on the\r
852                 list of bound sockets. */\r
853                 pxListItem = pxListFindListItemWithValue( &xBoundSocketsList, ( TickType_t ) usPort );\r
854         }\r
855         xTaskResumeAll();\r
856 \r
857         if( pxListItem != NULL )\r
858         {\r
859                 /* The owner of the list item is the socket itself. */\r
860                 pxSocket = ( xFreeRTOS_Socket_t * ) listGET_LIST_ITEM_OWNER( pxListItem );\r
861 \r
862                 vTaskSuspendAll();\r
863                 {\r
864                         #if( ipconfigSUPPORT_SELECT_FUNCTION == 1 )\r
865                         {\r
866                                 /* Is the socket a member of a select() group? */\r
867                                 if( pxSocket->xSelectQueue != NULL )\r
868                                 {\r
869                                         /* Can the select group be notified that the socket is\r
870                                         ready to be read? */\r
871                                         if( xQueueSendFromISR( pxSocket->xSelectQueue, &pxSocket, &xHigherPriorityTaskWoken ) != pdPASS )\r
872                                         {\r
873                                                 /* Could not notify the select group. */\r
874                                                 xReturn = pdFAIL;\r
875                                                 iptraceFAILED_TO_NOTIFY_SELECT_GROUP( pxSocket );\r
876                                         }\r
877                                 }\r
878                         }\r
879                         #endif\r
880 \r
881                         if( xReturn == pdPASS )\r
882                         {\r
883                                 taskENTER_CRITICAL();\r
884                                 {\r
885                                         /* Add the network packet to the list of packets to be\r
886                                         processed by the socket. */\r
887                                         vListInsertEnd( &( pxSocket->xWaitingPacketsList ), &( pxNetworkBuffer->xBufferListItem ) );\r
888                                 }\r
889                                 taskEXIT_CRITICAL();\r
890 \r
891                                 /* The socket's counting semaphore records how many packets are\r
892                                 waiting to be processed by the socket. */\r
893                                 xSemaphoreGiveFromISR( pxSocket->xWaitingPacketSemaphore, &xHigherPriorityTaskWoken );\r
894                         }\r
895                 }\r
896                 if( xTaskResumeAll() == pdFALSE )\r
897                 {\r
898                         if( xHigherPriorityTaskWoken != pdFALSE )\r
899                         {\r
900                                 taskYIELD();\r
901                         }\r
902                 }\r
903         }\r
904         else\r
905         {\r
906                 xReturn = pdFAIL;\r
907         }\r
908 \r
909         return xReturn;\r
910 }\r
911 /*-----------------------------------------------------------*/\r
912 \r
913 static uint16_t prvGetPrivatePortNumber( void )\r
914 {\r
915 static uint16_t usNextPortToUse = socketAUTO_PORT_ALLOCATION_START_NUMBER - 1;\r
916 uint16_t usReturn;\r
917 \r
918         /* Assign the next port in the range. */\r
919         taskENTER_CRITICAL();\r
920         {\r
921                 usNextPortToUse++;\r
922 \r
923                 /* Has it overflowed? */\r
924                 if( usNextPortToUse == 0U )\r
925                 {\r
926                         /* Don't go right back to the start of the dynamic/private port\r
927                         range numbers as any persistent sockets are likely to have been\r
928                         create first so the early port numbers may still be in use. */\r
929                         usNextPortToUse = socketAUTO_PORT_ALLOCATION_RESET_NUMBER;\r
930                 }\r
931 \r
932                 usReturn = FreeRTOS_htons( usNextPortToUse );\r
933         }\r
934         taskEXIT_CRITICAL();\r
935 \r
936         return usReturn;\r
937 } /* Tested */\r
938 /*-----------------------------------------------------------*/\r
939 \r
940 xListItem * pxListFindListItemWithValue( xList *pxList, TickType_t xWantedItemValue )\r
941 {\r
942 xListItem *pxIterator, *pxReturn;\r
943 \r
944         pxReturn = NULL;\r
945         for( pxIterator = ( xListItem * ) pxList->xListEnd.pxNext; pxIterator != ( xListItem* ) &( pxList->xListEnd ); pxIterator = ( xListItem * ) pxIterator->pxNext )\r
946         {\r
947                 if( pxIterator->xItemValue == xWantedItemValue )\r
948                 {\r
949                         pxReturn = pxIterator;\r
950                         break;\r
951                 }\r
952         }\r
953 \r
954         return pxReturn;\r
955 } /* Tested */\r
956 /*-----------------------------------------------------------*/\r
957 \r
958 #if ipconfigINCLUDE_FULL_INET_ADDR == 1\r
959 \r
960         uint32_t FreeRTOS_inet_addr( const char *pcIPAddress )\r
961         {\r
962         const uint8_t ucDecimalBase = 10;\r
963         uint8_t ucOctet[ socketMAX_IP_ADDRESS_OCTETS ];\r
964         const char *pcPointerOnEntering;\r
965         uint32_t ulReturn = 0UL, ulOctetNumber, ulValue;\r
966         BaseType_t xResult = pdPASS;\r
967 \r
968                 for( ulOctetNumber = 0; ulOctetNumber < socketMAX_IP_ADDRESS_OCTETS; ulOctetNumber++ )\r
969                 {\r
970                         ulValue = 0;\r
971                         pcPointerOnEntering = pcIPAddress;\r
972 \r
973                         while( ( *pcIPAddress >= ( uint8_t ) '0' ) && ( *pcIPAddress <= ( uint8_t ) '9' ) )\r
974                         {\r
975                                 /* Move previous read characters into the next decimal\r
976                                 position. */\r
977                                 ulValue *= ucDecimalBase;\r
978 \r
979                                 /* Add the binary value of the ascii character. */\r
980                                 ulValue += ( *pcIPAddress - ( uint8_t ) '0' );\r
981 \r
982                                 /* Move to next character in the string. */\r
983                                 pcIPAddress++;\r
984                         }\r
985 \r
986                         /* Check characters were read. */\r
987                         if( pcIPAddress == pcPointerOnEntering )\r
988                         {\r
989                                 xResult = pdFAIL;\r
990                         }\r
991 \r
992                         /* Check the value fits in an 8-bit number. */\r
993                         if( ulValue > 0xffUL )\r
994                         {\r
995                                 xResult = pdFAIL;\r
996                         }\r
997                         else\r
998                         {\r
999                                 ucOctet[ ulOctetNumber ] = ( uint8_t ) ulValue;\r
1000 \r
1001                                 /* Check the next character is as expected. */\r
1002                                 if( ulOctetNumber < ( socketMAX_IP_ADDRESS_OCTETS - 1 ) )\r
1003                                 {\r
1004                                         if( *pcIPAddress != ( uint8_t ) '.' )\r
1005                                         {\r
1006                                                 xResult = pdFAIL;\r
1007                                         }\r
1008                                         else\r
1009                                         {\r
1010                                                 /* Move past the dot. */\r
1011                                                 pcIPAddress++;\r
1012                                         }\r
1013                                 }\r
1014                         }\r
1015 \r
1016                         if( xResult == pdFAIL )\r
1017                         {\r
1018                                 /* No point going on. */\r
1019                                 break;\r
1020                         }\r
1021                 }\r
1022 \r
1023                 if( *pcIPAddress != ( uint8_t ) 0x00 )\r
1024                 {\r
1025                         /* Expected the end of the string. */\r
1026                         xResult = pdFAIL;\r
1027                 }\r
1028 \r
1029                 if( ulOctetNumber != socketMAX_IP_ADDRESS_OCTETS )\r
1030                 {\r
1031                         /* Didn't read enough octets. */\r
1032                         xResult = pdFAIL;\r
1033                 }\r
1034 \r
1035                 if( xResult == pdPASS )\r
1036                 {\r
1037                         ulReturn = FreeRTOS_inet_addr_quick( ucOctet[ 0 ], ucOctet[ 1 ], ucOctet[ 2 ], ucOctet[ 3 ] );\r
1038                 }\r
1039 \r
1040                 return ulReturn;\r
1041         }\r
1042 \r
1043 #endif /* ipconfigINCLUDE_FULL_INET_ADDR */\r
1044 /*-----------------------------------------------------------*/\r
1045 \r