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