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