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