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