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