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