2 * FreeRTOS+UDP V1.0.0 (C) 2013 Real Time Engineers ltd.
\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
7 * FreeRTOS+UDP uses a dual license model that allows the software to be used
\r
8 * under a standard GPL open source license, or a commercial license. The
\r
9 * standard GPL license (unlike the modified GPL license under which FreeRTOS
\r
10 * itself is distributed) requires that all software statically linked with
\r
11 * FreeRTOS+UDP is also distributed under the same GPL V2 license terms.
\r
12 * Details of both license options follow:
\r
14 * - Open source licensing -
\r
15 * FreeRTOS+UDP is a free download and may be used, modified, evaluated and
\r
16 * distributed without charge provided the user adheres to version two of the
\r
17 * GNU General Public License (GPL) and does not remove the copyright notice or
\r
18 * this text. The GPL V2 text is available on the gnu.org web site, and on the
\r
19 * following URL: http://www.FreeRTOS.org/gpl-2.0.txt.
\r
21 * - Commercial licensing -
\r
22 * Businesses and individuals that for commercial or other reasons cannot comply
\r
23 * with the terms of the GPL V2 license must obtain a commercial license before
\r
24 * incorporating FreeRTOS+UDP into proprietary software for distribution in any
\r
25 * form. Commercial licenses can be purchased from http://shop.freertos.org/udp
\r
26 * and do not require any source files to be changed.
\r
28 * FreeRTOS+UDP is distributed in the hope that it will be useful. You cannot
\r
29 * use FreeRTOS+UDP unless you agree that you use the software 'as is'.
\r
30 * FreeRTOS+UDP is provided WITHOUT ANY WARRANTY; without even the implied
\r
31 * warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR
\r
32 * PURPOSE. Real Time Engineers Ltd. disclaims all conditions and terms, be they
\r
33 * implied, expressed, or statutory.
\r
35 * 1 tab == 4 spaces!
\r
37 * http://www.FreeRTOS.org
\r
38 * http://www.FreeRTOS.org/udp
\r
42 /* Standard includes. */
\r
45 /* FreeRTOS includes. */
\r
46 #include "FreeRTOS.h"
\r
51 /* FreeRTOS+UDP includes. */
\r
52 #include "FreeRTOS_UDP_IP.h"
\r
53 #include "FreeRTOS_IP_Private.h"
\r
54 #include "FreeRTOS_Sockets.h"
\r
55 #include "NetworkBufferManagement.h"
\r
57 /* Sanity check the UDP payload length setting is compatible with the
\r
58 fragmentation setting. */
\r
59 #if ipconfigCAN_FRAGMENT_OUTGOING_PACKETS == 1
\r
60 #if ( ( ipMAX_UDP_PAYLOAD_LENGTH % 8 ) != 0 )
\r
61 #error ( ipconfigNETWORK_MTU - 28 ) must be divisible by 8 when fragmentation is used
\r
62 #endif /* ipMAX_UDP_PAYLOAD_LENGTH */
\r
63 #endif /* ipconfigFRAGMENT_OUTGOING_PACKETS */
\r
65 /* The ItemValue of the sockets xBoundSocketListItem member holds the socket's
\r
67 #define socketSET_SOCKET_ADDRESS( pxSocket, usPort ) listSET_LIST_ITEM_VALUE( ( &( ( pxSocket )->xBoundSocketListItem ) ), ( usPort ) )
\r
68 #define socketGET_SOCKET_ADDRESS( pxSocket ) listGET_LIST_ITEM_VALUE( ( &( ( pxSocket )->xBoundSocketListItem ) ) )
\r
70 /* xWaitingPacketSemaphore is not created until the socket is bound, so can be
\r
71 tested to see if bind() has been called. */
\r
72 #define socketSOCKET_IS_BOUND( pxSocket ) ( ( uint32_t ) pxSocket->xWaitingPacketSemaphore )
\r
74 /* If FreeRTOS_sendto() is called on a socket that is not bound to a port
\r
75 number then, depending on the FreeRTOSIPConfig.h settings, it might be that a
\r
76 port number is automatically generated for the socket. Automatically generated
\r
77 port numbers will be between socketAUTO_PORT_ALLOCATION_START_NUMBER and
\r
79 #define socketAUTO_PORT_ALLOCATION_START_NUMBER ( ( uint16_t ) 0xc000 )
\r
81 /* When the automatically generated port numbers overflow, the next value used
\r
82 is not set back to socketAUTO_PORT_ALLOCATION_START_NUMBER because it is likely
\r
83 that the first few automatically generated ports will still be in use. Instead
\r
84 it is reset back to the value defined by this constant. */
\r
85 #define socketAUTO_PORT_ALLOCATION_RESET_NUMBER ( ( uint16_t ) 0xc100 )
\r
87 /* The number of octets that make up an IP address. */
\r
88 #define socketMAX_IP_ADDRESS_OCTETS 4
\r
89 /*-----------------------------------------------------------*/
\r
92 * Allocate the next port number from the private allocation range.
\r
94 static uint16_t prvGetPrivatePortNumber( void );
\r
97 * Return the list itme from within pxList that has an item value of
\r
98 * xWantedItemValue. If there is no such list item return NULL.
\r
100 xListItem * pxListFindListItemWithValue( xList *pxList, portTickType xWantedItemValue );
\r
102 /*-----------------------------------------------------------*/
\r
104 typedef struct XSOCKET
\r
106 xSemaphoreHandle xWaitingPacketSemaphore;
\r
107 xList xWaitingPacketsList;
\r
108 xListItem xBoundSocketListItem; /* Used to reference the socket from a bound sockets list. */
\r
109 portTickType xReceiveBlockTime;
\r
110 portTickType xSendBlockTime;
\r
111 uint8_t ucSocketOptions;
\r
112 #if ipconfigSUPPORT_SELECT_FUNCTION == 1
\r
113 xQueueHandle xSelectQueue;
\r
115 } xFreeRTOS_Socket_t;
\r
118 /* The list that contains mappings between sockets and port numbers. Accesses
\r
119 to this list must be protected by critical sections of one kind or another. */
\r
120 static xList xBoundSocketsList;
\r
122 /*-----------------------------------------------------------*/
\r
124 xSocket_t FreeRTOS_socket( portBASE_TYPE xDomain, portBASE_TYPE xType, portBASE_TYPE xProtocol )
\r
126 xFreeRTOS_Socket_t *pxSocket;
\r
128 /* Only UDP on Ethernet is currently supported. */
\r
129 configASSERT( xDomain == FREERTOS_AF_INET );
\r
130 configASSERT( xType == FREERTOS_SOCK_DGRAM );
\r
131 configASSERT( xProtocol == FREERTOS_IPPROTO_UDP );
\r
132 configASSERT( listLIST_IS_INITIALISED( &xBoundSocketsList ) );
\r
134 /* Allocate the structure that will hold the socket information. */
\r
135 pxSocket = ( xFreeRTOS_Socket_t * ) pvPortMalloc( sizeof( xFreeRTOS_Socket_t ) );
\r
137 if( pxSocket == NULL )
\r
139 pxSocket = ( xFreeRTOS_Socket_t * ) FREERTOS_INVALID_SOCKET;
\r
140 iptraceFAILED_TO_CREATE_SOCKET();
\r
144 /* Initialise the socket's members. The semaphore will be created if
\r
145 the socket is bound to an address, for now the pointer to the semaphore
\r
146 is just set to NULL to show it has not been created. */
\r
147 pxSocket->xWaitingPacketSemaphore = NULL;
\r
148 vListInitialise( &( pxSocket->xWaitingPacketsList ) );
\r
149 vListInitialiseItem( &( pxSocket->xBoundSocketListItem ) );
\r
150 listSET_LIST_ITEM_OWNER( &( pxSocket->xBoundSocketListItem ), ( void * ) pxSocket );
\r
151 pxSocket->xSendBlockTime = ( portTickType ) 0;
\r
152 pxSocket->xReceiveBlockTime = portMAX_DELAY;
\r
153 pxSocket->ucSocketOptions = FREERTOS_SO_UDPCKSUM_OUT;
\r
154 #if ipconfigSUPPORT_SELECT_FUNCTION == 1
\r
155 pxSocket->xSelectQueue = NULL;
\r
159 /* Remove compiler warnings in the case the configASSERT() is not defined. */
\r
162 ( void ) xProtocol;
\r
164 return ( xSocket_t ) pxSocket;
\r
166 /*-----------------------------------------------------------*/
\r
168 #if ipconfigSUPPORT_SELECT_FUNCTION == 1
\r
170 xSocketSet_t FreeRTOS_CreateSocketSet( unsigned portBASE_TYPE uxEventQueueLength )
\r
172 xQueueHandle xSelectQueue;
\r
174 /* Create the queue into which the address of sockets that are
\r
175 available to read are posted. */
\r
176 xSelectQueue = xQueueCreate( uxEventQueueLength, sizeof( xSocket_t ) );
\r
178 return ( xSocketSet_t ) xSelectQueue;
\r
181 #endif /* ipconfigSUPPORT_SELECT_FUNCTION */
\r
182 /*-----------------------------------------------------------*/
\r
184 #if ipconfigSUPPORT_SELECT_FUNCTION == 1
\r
186 portBASE_TYPE FreeRTOS_FD_SET( xSocket_t xSocket, xSocketSet_t xSocketSet )
\r
188 xFreeRTOS_Socket_t *pxSocket = ( xFreeRTOS_Socket_t * ) xSocket;
\r
189 portBASE_TYPE xReturn;
\r
191 /* Is the socket already a member of a select group? */
\r
192 if( pxSocket->xSelectQueue == NULL )
\r
194 /* Store a pointer to the select group in the socket for future
\r
196 pxSocket->xSelectQueue = ( xQueueHandle ) xSocketSet;
\r
201 /* The socket is already a member of a select group so cannot be added
\r
209 #endif /* ipconfigSUPPORT_SELECT_FUNCTION */
\r
210 /*-----------------------------------------------------------*/
\r
212 #if ipconfigSUPPORT_SELECT_FUNCTION == 1
\r
214 portBASE_TYPE FreeRTOS_FD_CLR( xSocket_t xSocket, xSocketSet_t xSocketSet )
\r
216 xFreeRTOS_Socket_t *pxSocket = ( xFreeRTOS_Socket_t * ) xSocket;
\r
217 portBASE_TYPE xReturn;
\r
219 /* Is the socket a member of the select group? */
\r
220 if( pxSocket->xSelectQueue == ( xQueueHandle ) xSocketSet )
\r
222 /* The socket is no longer a member of the select group. */
\r
223 pxSocket->xSelectQueue = NULL;
\r
234 #endif /* ipconfigSUPPORT_SELECT_FUNCTION */
\r
235 /*-----------------------------------------------------------*/
\r
237 #if ipconfigSUPPORT_SELECT_FUNCTION == 1
\r
239 xSocket_t FreeRTOS_select( xSocketSet_t xSocketSet, portTickType xBlockTimeTicks )
\r
241 xFreeRTOS_Socket_t *pxSocket;
\r
243 /* Wait for a socket to be ready to read. */
\r
244 if( xQueueReceive( ( xQueueHandle ) xSocketSet, &pxSocket, xBlockTimeTicks ) != pdPASS )
\r
249 return ( xSocket_t ) pxSocket;
\r
252 #endif /* ipconfigSUPPORT_SELECT_FUNCTION */
\r
253 /*-----------------------------------------------------------*/
\r
255 int32_t FreeRTOS_recvfrom( xSocket_t xSocket, void *pvBuffer, size_t xBufferLength, uint32_t ulFlags, struct freertos_sockaddr *pxSourceAddress, socklen_t *pxSourceAddressLength )
\r
257 xNetworkBufferDescriptor_t *pxNetworkBuffer;
\r
259 xFreeRTOS_Socket_t *pxSocket;
\r
261 pxSocket = ( xFreeRTOS_Socket_t * ) xSocket;
\r
263 /* The function prototype is designed to maintain the expected Berkeley
\r
264 sockets standard, but this implementation does not use all the parameters. */
\r
265 ( void ) pxSourceAddressLength;
\r
267 if( socketSOCKET_IS_BOUND( pxSocket ) != pdFALSE )
\r
269 /* The semaphore is given when received data is queued on the socket. */
\r
270 if( xSemaphoreTake( pxSocket->xWaitingPacketSemaphore, pxSocket->xReceiveBlockTime ) == pdPASS )
\r
272 taskENTER_CRITICAL();
\r
274 configASSERT( ( listCURRENT_LIST_LENGTH( &( pxSocket->xWaitingPacketsList ) ) > 0U ) );
\r
276 /* The owner of the list item is the network buffer. */
\r
277 pxNetworkBuffer = ( xNetworkBufferDescriptor_t * ) listGET_OWNER_OF_HEAD_ENTRY( &( pxSocket->xWaitingPacketsList ) );
\r
279 /* Remove the network buffer from the list of buffers waiting to
\r
280 be processed by the socket. */
\r
281 uxListRemove( &( pxNetworkBuffer->xBufferListItem ) );
\r
283 taskEXIT_CRITICAL();
\r
285 if( ( ulFlags & FREERTOS_ZERO_COPY ) == 0 )
\r
287 /* The zero copy flag is not set. Truncate the length if it
\r
288 won't fit in the provided buffer. */
\r
289 if( pxNetworkBuffer->xDataLength > xBufferLength )
\r
291 iptraceRECVFROM_DISCARDING_BYTES( ( xBufferLength - pxNetworkBuffer->xDataLength ) );
\r
292 pxNetworkBuffer->xDataLength = xBufferLength;
\r
295 /* Copy the received data into the provided buffer, then
\r
296 release the network buffer. */
\r
297 memcpy( pvBuffer, ( void * ) &( pxNetworkBuffer->pucEthernetBuffer[ ipUDP_PAYLOAD_OFFSET ] ), pxNetworkBuffer->xDataLength );
\r
298 vNetworkBufferRelease( pxNetworkBuffer );
\r
302 /* The zero copy flag was set. pvBuffer is not a buffer into
\r
303 which the received data can be copied, but a pointer that must
\r
304 be set to point to the buffer in which the received data has
\r
305 already been placed. */
\r
306 *( ( void** ) pvBuffer ) = ( void * ) ( &( pxNetworkBuffer->pucEthernetBuffer[ ipUDP_PAYLOAD_OFFSET ] ) );
\r
309 /* The returned value is the data length, which may have been
\r
310 capped to the receive buffer size. */
\r
311 lReturn = ( int32_t ) pxNetworkBuffer->xDataLength;
\r
313 if( pxSourceAddress != NULL )
\r
315 pxSourceAddress->sin_port = pxNetworkBuffer->usPort;
\r
316 pxSourceAddress->sin_addr = pxNetworkBuffer->ulIPAddress;
\r
321 lReturn = FREERTOS_EWOULDBLOCK;
\r
322 iptraceRECVFROM_TIMEOUT();
\r
327 lReturn = FREERTOS_EINVAL;
\r
332 /*-----------------------------------------------------------*/
\r
334 #if ipconfigCAN_FRAGMENT_OUTGOING_PACKETS == 1
\r
336 int32_t FreeRTOS_sendto( xSocket_t xSocket, const void *pvBuffer, size_t xTotalDataLength, uint32_t ulFlags, const struct freertos_sockaddr *pxDestinationAddress, socklen_t xDestinationAddressLength )
\r
338 xNetworkBufferDescriptor_t *pxNetworkBuffer;
\r
339 xIPFragmentParameters_t *pxFragmentParameters;
\r
340 size_t xBytesToSend, xBytesRemaining;
\r
341 xIPStackEvent_t xStackTxEvent = { eStackTxEvent, NULL };
\r
342 extern xQueueHandle xNetworkEventQueue;
\r
343 uint8_t *pucBuffer;
\r
344 xTimeOutType xTimeOut;
\r
345 portTickType xTicksToWait;
\r
346 uint16_t usFragmentOffset;
\r
347 xFreeRTOS_Socket_t *pxSocket;
\r
349 pxSocket = ( xFreeRTOS_Socket_t * ) xSocket;
\r
351 /* The function prototype is designed to maintain the expected Berkeley
\r
352 sockets standard, but this implementation does not use all the
\r
354 ( void ) xDestinationAddressLength;
\r
355 configASSERT( xNetworkEventQueue );
\r
356 configASSERT( pvBuffer );
\r
358 xBytesRemaining = xTotalDataLength;
\r
360 if( socketSOCKET_IS_BOUND( pxSocket ) == pdFALSE )
\r
362 /* If the socket is not already bound to an address, bind it now.
\r
363 Passing NULL as the address parameter tells FreeRTOS_bind() to select
\r
364 the address to bind to. */
\r
365 FreeRTOS_bind( xSocket, NULL, 0 );
\r
368 if( socketSOCKET_IS_BOUND( pxSocket ) != pdFALSE )
\r
370 /* pucBuffer will be reset if this send turns out to be a zero copy
\r
371 send because in that case pvBuffer is actually a pointer to an
\r
372 xUserData_t structure, not the UDP payload. */
\r
373 pucBuffer = ( uint8_t * ) pvBuffer;
\r
374 vTaskSetTimeOutState( &xTimeOut );
\r
375 xTicksToWait = pxSocket->xSendBlockTime;
\r
377 /* The data being transmitted will be sent in
\r
378 ipMAX_UDP_PAYLOAD_LENGTH chunks if xDataLength is greater than the
\r
379 network buffer payload size. Loop until all the data is sent. */
\r
380 while( xBytesRemaining > 0 )
\r
382 if( xBytesRemaining > ipMAX_UDP_PAYLOAD_LENGTH )
\r
384 /* Cap the amount being sent in this packet to the maximum
\r
385 UDP payload size. This will be a multiple of 8 already,
\r
386 removing the need to check in the code. */
\r
387 xBytesToSend = ipMAX_UDP_PAYLOAD_LENGTH;
\r
391 /* Send all remaining bytes - which may well be the total
\r
392 number of bytes if the packet was not chopped up. */
\r
393 xBytesToSend = xBytesRemaining;
\r
396 /* If the zero copy flag is set, then the data is already in a
\r
397 network buffer. Otherwise, get a new network buffer. */
\r
398 if( ( ulFlags & FREERTOS_ZERO_COPY ) == 0 )
\r
400 if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdTRUE )
\r
405 pxNetworkBuffer = pxNetworkBufferGet( xBytesToSend + sizeof( xUDPPacket_t ), xTicksToWait );
\r
409 if( xTotalDataLength > ipMAX_UDP_PAYLOAD_LENGTH )
\r
411 /* The packet needs fragmenting, but zero copy buffers
\r
412 cannot be fragmented. */
\r
413 pxNetworkBuffer = NULL;
\r
417 /* When zero copy is used, pvBuffer is a pointer to the
\r
418 payload of a buffer that has already been obtained from the
\r
419 stack. Obtain the network buffer pointer from the buffer. */
\r
420 pucBuffer = ( uint8_t * ) pvBuffer;
\r
421 pucBuffer -= ( ipBUFFER_PADDING + sizeof( xUDPPacket_t ) );
\r
422 pxNetworkBuffer = * ( ( xNetworkBufferDescriptor_t ** ) pucBuffer );
\r
426 if( pxNetworkBuffer != NULL )
\r
428 /* Use the part of the network buffer that will be completed
\r
429 by the IP layer as temporary storage to pass extra
\r
430 information required by the IP layer. */
\r
431 pxFragmentParameters = ( xIPFragmentParameters_t * ) &( pxNetworkBuffer->pucEthernetBuffer[ ipFRAGMENTATION_PARAMETERS_OFFSET ] );
\r
432 pxFragmentParameters->ucSocketOptions = pxSocket->ucSocketOptions;
\r
434 if( xBytesRemaining > ipMAX_UDP_PAYLOAD_LENGTH )
\r
436 /* The packet is being chopped up, and more data will
\r
438 pxFragmentParameters->ucSocketOptions = ( pxSocket->ucSocketOptions | FREERTOS_NOT_LAST_IN_FRAGMENTED_PACKET );
\r
441 if( xTotalDataLength > ipMAX_UDP_PAYLOAD_LENGTH )
\r
443 /* Let the IP layer know this packet has been chopped up,
\r
444 and supply the IP layer with any addition information it
\r
445 needs to make sense of it. */
\r
446 pxFragmentParameters->ucSocketOptions |= FREERTOS_FRAGMENTED_PACKET;
\r
447 usFragmentOffset = ( uint16_t ) ( xTotalDataLength - xBytesRemaining );
\r
448 pxFragmentParameters->usFragmentedPacketOffset = usFragmentOffset;
\r
449 pxFragmentParameters->usFragmentLength = ( uint16_t ) xBytesToSend;
\r
453 usFragmentOffset = 0;
\r
456 /* Write the payload into the packet. The IP layer is
\r
457 queried to find where in the IP payload the data should be
\r
458 written. This is because the necessary offset is different
\r
459 for the first packet, because the first packet leaves space
\r
460 for a UDP header. Note that this changes usFragmentOffset
\r
461 from the offset in the entire UDP packet, to the offset
\r
462 in the IP packet. */
\r
463 if( ( ulFlags & FREERTOS_ZERO_COPY ) == 0 )
\r
465 /* Only copy the data if it is not already in the
\r
466 expected location. */
\r
467 usFragmentOffset = ipGET_UDP_PAYLOAD_OFFSET_FOR_FRAGMENT( usFragmentOffset );
\r
468 memcpy( ( void * ) &( pxNetworkBuffer->pucEthernetBuffer[ usFragmentOffset ] ), ( void * ) pucBuffer, xBytesToSend );
\r
470 pxNetworkBuffer->xDataLength = xTotalDataLength;
\r
471 pxNetworkBuffer->usPort = pxDestinationAddress->sin_port;
\r
472 pxNetworkBuffer->usBoundPort = ( uint16_t ) socketGET_SOCKET_ADDRESS( pxSocket );
\r
473 pxNetworkBuffer->ulIPAddress = pxDestinationAddress->sin_addr;
\r
475 /* Tell the networking task that the packet needs sending. */
\r
476 xStackTxEvent.pvData = pxNetworkBuffer;
\r
478 if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdTRUE )
\r
483 if( xQueueSendToBack( xNetworkEventQueue, &xStackTxEvent, xTicksToWait ) != pdPASS )
\r
485 /* If the buffer was allocated in this function, release it. */
\r
486 if( ( ulFlags & FREERTOS_ZERO_COPY ) == 0 )
\r
488 vNetworkBufferRelease( pxNetworkBuffer );
\r
490 iptraceSTACK_TX_EVENT_LOST( ipSTACK_TX_EVENT );
\r
494 /* Adjust counters ready to either exit the loop, or send
\r
495 another chunk of data. */
\r
496 xBytesRemaining -= xBytesToSend;
\r
497 pucBuffer += xBytesToSend;
\r
501 /* If errno was available, errno would be set to
\r
502 FREERTOS_ENOPKTS. As it is, the function must return the
\r
503 number of transmitted bytes, so the calling function knows how
\r
504 much data was actually sent. */
\r
510 return ( xTotalDataLength - xBytesRemaining );
\r
513 #else /* ipconfigCAN_FRAGMENT_OUTGOING_PACKETS */
\r
515 int32_t FreeRTOS_sendto( xSocket_t xSocket, const void *pvBuffer, size_t xTotalDataLength, uint32_t ulFlags, const struct freertos_sockaddr *pxDestinationAddress, socklen_t xDestinationAddressLength )
\r
517 xNetworkBufferDescriptor_t *pxNetworkBuffer;
\r
518 xIPStackEvent_t xStackTxEvent = { eStackTxEvent, NULL };
\r
519 extern xQueueHandle xNetworkEventQueue;
\r
520 xTimeOutType xTimeOut;
\r
521 portTickType xTicksToWait;
\r
522 int32_t lReturn = 0;
\r
523 xFreeRTOS_Socket_t *pxSocket;
\r
524 uint8_t *pucBuffer;
\r
526 pxSocket = ( xFreeRTOS_Socket_t * ) xSocket;
\r
528 /* The function prototype is designed to maintain the expected Berkeley
\r
529 sockets standard, but this implementation does not use all the
\r
531 ( void ) xDestinationAddressLength;
\r
532 configASSERT( xNetworkEventQueue );
\r
533 configASSERT( pvBuffer );
\r
535 if( xTotalDataLength <= ipMAX_UDP_PAYLOAD_LENGTH )
\r
537 if( socketSOCKET_IS_BOUND( pxSocket ) == pdFALSE )
\r
539 /* If the socket is not already bound to an address, bind it now.
\r
540 Passing NULL as the address parameter tells FreeRTOS_bind() to
\r
541 select the address to bind to. */
\r
542 FreeRTOS_bind( pxSocket, NULL, 0 );
\r
545 if( socketSOCKET_IS_BOUND( pxSocket ) != pdFALSE )
\r
547 xTicksToWait = pxSocket->xSendBlockTime;
\r
549 if( ( ulFlags & FREERTOS_ZERO_COPY ) == 0 )
\r
551 /* Zero copy is not set, so obtain a network buffer into
\r
552 which the payload will be copied. */
\r
553 vTaskSetTimeOutState( &xTimeOut );
\r
554 pxNetworkBuffer = pxNetworkBufferGet( xTotalDataLength + sizeof( xUDPPacket_t ), xTicksToWait );
\r
556 if( pxNetworkBuffer != NULL )
\r
558 memcpy( ( void * ) &( pxNetworkBuffer->pucEthernetBuffer[ ipUDP_PAYLOAD_OFFSET ] ), ( void * ) pvBuffer, xTotalDataLength );
\r
560 if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdTRUE )
\r
562 /* The entire block time has been used up. */
\r
569 /* When zero copy is used, pvBuffer is a pointer to the
\r
570 payload of a buffer that has already been obtained from the
\r
571 stack. Obtain the network buffer pointer from the buffer. */
\r
572 pucBuffer = ( uint8_t * ) pvBuffer;
\r
573 pucBuffer -= ( ipBUFFER_PADDING + sizeof( xUDPPacket_t ) );
\r
574 pxNetworkBuffer = * ( ( xNetworkBufferDescriptor_t ** ) pucBuffer );
\r
577 if( pxNetworkBuffer != NULL )
\r
579 pxNetworkBuffer->xDataLength = xTotalDataLength;
\r
580 pxNetworkBuffer->usPort = pxDestinationAddress->sin_port;
\r
581 pxNetworkBuffer->usBoundPort = ( uint16_t ) socketGET_SOCKET_ADDRESS( pxSocket );
\r
582 pxNetworkBuffer->ulIPAddress = pxDestinationAddress->sin_addr;
\r
584 /* The socket options are passed to the IP layer in the
\r
585 space that will eventually get used by the Ethernet header. */
\r
586 pxNetworkBuffer->pucEthernetBuffer[ ipSOCKET_OPTIONS_OFFSET ] = pxSocket->ucSocketOptions;
\r
588 /* Tell the networking task that the packet needs sending. */
\r
589 xStackTxEvent.pvData = pxNetworkBuffer;
\r
591 if( xQueueSendToBack( xNetworkEventQueue, &xStackTxEvent, xTicksToWait ) != pdPASS )
\r
593 /* If the buffer was allocated in this function, release it. */
\r
594 if( ( ulFlags & FREERTOS_ZERO_COPY ) == 0 )
\r
596 vNetworkBufferRelease( pxNetworkBuffer );
\r
598 iptraceSTACK_TX_EVENT_LOST( ipSTACK_TX_EVENT );
\r
602 lReturn = ( int32_t ) xTotalDataLength;
\r
607 /* If errno was available, errno would be set to
\r
608 FREERTOS_ENOPKTS. As it is, the function must return the
\r
609 number of transmitted bytes, so the calling function knows how
\r
610 much data was actually sent. */
\r
611 iptraceNO_BUFFER_FOR_SENDTO();
\r
616 iptraceSENDTO_SOCKET_NOT_BOUND();
\r
621 /* The data is longer than the available buffer space. Setting
\r
622 ipconfigCAN_FRAGMENT_OUTGOING_PACKETS to 1 may allow this packet
\r
624 iptraceSENDTO_DATA_TOO_LONG();
\r
630 #endif /* ipconfigCAN_FRAGMENT_OUTGOING_PACKETS */
\r
631 /*-----------------------------------------------------------*/
\r
633 portBASE_TYPE FreeRTOS_bind( xSocket_t xSocket, struct freertos_sockaddr * pxAddress, socklen_t xAddressLength )
\r
635 portBASE_TYPE xReturn = 0; /* In Berkeley sockets, 0 means pass for bind(). */
\r
636 xFreeRTOS_Socket_t *pxSocket;
\r
637 #if ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND == 1
\r
638 struct freertos_sockaddr xAddress;
\r
639 #endif /* ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND */
\r
641 pxSocket = ( xFreeRTOS_Socket_t * ) xSocket;
\r
643 /* The function prototype is designed to maintain the expected Berkeley
\r
644 sockets standard, but this implementation does not use all the parameters. */
\r
645 ( void ) xAddressLength;
\r
647 configASSERT( xSocket );
\r
648 configASSERT( xSocket != FREERTOS_INVALID_SOCKET );
\r
650 #if ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND == 1
\r
652 /* pxAddress will be NULL if sendto() was called on a socket without the
\r
653 socket being bound to an address. In this case, automatically allocate
\r
654 an address to the socket. There is a very tiny chance that the allocated
\r
655 port will already be in use - if that is the case, then the check below
\r
656 [pxListFindListItemWithValue()] will result in an error being returned. */
\r
657 if( pxAddress == NULL )
\r
659 pxAddress = &xAddress;
\r
660 pxAddress->sin_port = prvGetPrivatePortNumber();
\r
663 #endif /* ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND == 1 */
\r
665 /* Sockets must be bound before calling FreeRTOS_sendto() if
\r
666 ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND is not set to 1. */
\r
667 configASSERT( pxAddress );
\r
669 if( pxAddress != NULL )
\r
671 if( pxAddress->sin_port == 0 )
\r
673 pxAddress->sin_port = prvGetPrivatePortNumber();
\r
678 /* Check to ensure the port is not already in use. */
\r
679 if( pxListFindListItemWithValue( &xBoundSocketsList, ( portTickType ) pxAddress->sin_port ) != NULL )
\r
681 xReturn = FREERTOS_EADDRINUSE;
\r
686 /* Check that xReturn has not been set before continuing. */
\r
689 if( pxSocket->xWaitingPacketSemaphore == NULL )
\r
691 /* Create the semaphore used to count the number of packets that
\r
692 are queued on this socket. */
\r
693 pxSocket->xWaitingPacketSemaphore = xSemaphoreCreateCounting( ipconfigNUM_NETWORK_BUFFERS, 0 );
\r
695 if( pxSocket->xWaitingPacketSemaphore != NULL )
\r
697 /* Allocate the port number to the socket. */
\r
698 socketSET_SOCKET_ADDRESS( pxSocket, pxAddress->sin_port );
\r
699 taskENTER_CRITICAL();
\r
701 /* Add the socket to the list of bound ports. */
\r
702 vListInsertEnd( &xBoundSocketsList, &( pxSocket->xBoundSocketListItem ) );
\r
704 taskEXIT_CRITICAL();
\r
708 /* Out of memory. */
\r
709 xReturn = FREERTOS_ENOBUFS;
\r
714 /* The socket is already bound. */
\r
715 xReturn = FREERTOS_EINVAL;
\r
721 xReturn = FREERTOS_EADDRNOTAVAIL;
\r
726 iptraceBIND_FAILED( xSocket, ( FreeRTOS_ntohs( pxAddress->sin_port ) ) );
\r
731 /*-----------------------------------------------------------*/
\r
733 portBASE_TYPE FreeRTOS_closesocket( xSocket_t xSocket )
\r
735 xNetworkBufferDescriptor_t *pxNetworkBuffer;
\r
736 xFreeRTOS_Socket_t *pxSocket;
\r
738 pxSocket = ( xFreeRTOS_Socket_t * ) xSocket;
\r
740 configASSERT( pxSocket );
\r
741 configASSERT( pxSocket != FREERTOS_INVALID_SOCKET );
\r
743 /* Socket must be unbound first, to ensure no more packets are queued on
\r
745 if( socketSOCKET_IS_BOUND( pxSocket ) != pdFALSE )
\r
747 taskENTER_CRITICAL();
\r
749 uxListRemove( &( pxSocket->xBoundSocketListItem ) );
\r
751 taskEXIT_CRITICAL();
\r
754 /* Now the socket is not bound the list of waiting packets can be
\r
756 if( pxSocket->xWaitingPacketSemaphore != NULL )
\r
758 while( listCURRENT_LIST_LENGTH( &( pxSocket->xWaitingPacketsList ) ) > 0U )
\r
760 pxNetworkBuffer = ( xNetworkBufferDescriptor_t * ) listGET_OWNER_OF_HEAD_ENTRY( &( pxSocket->xWaitingPacketsList ) );
\r
761 uxListRemove( &( pxNetworkBuffer->xBufferListItem ) );
\r
762 vNetworkBufferRelease( pxNetworkBuffer );
\r
764 vSemaphoreDelete( pxSocket->xWaitingPacketSemaphore );
\r
767 vPortFree( pxSocket );
\r
771 /*-----------------------------------------------------------*/
\r
773 void FreeRTOS_SocketsInit( void )
\r
775 vListInitialise( &xBoundSocketsList );
\r
777 /*-----------------------------------------------------------*/
\r
779 portBASE_TYPE FreeRTOS_setsockopt( xSocket_t xSocket, int32_t lLevel, int32_t lOptionName, const void *pvOptionValue, size_t xOptionLength )
\r
781 /* The standard Berkeley function returns 0 for success. */
\r
782 portBASE_TYPE xReturn = 0;
\r
783 portBASE_TYPE lOptionValue;
\r
784 xFreeRTOS_Socket_t *pxSocket;
\r
786 pxSocket = ( xFreeRTOS_Socket_t * ) xSocket;
\r
788 /* The function prototype is designed to maintain the expected Berkeley
\r
789 sockets standard, but this implementation does not use all the parameters. */
\r
791 ( void ) xOptionLength;
\r
793 configASSERT( xSocket );
\r
795 switch( lOptionName )
\r
797 case FREERTOS_SO_RCVTIMEO :
\r
798 /* Receive time out. */
\r
799 pxSocket->xReceiveBlockTime = *( ( portTickType * ) pvOptionValue );
\r
802 case FREERTOS_SO_SNDTIMEO :
\r
803 /* The send time out is capped for the reason stated in the comments
\r
804 where ipconfigMAX_SEND_BLOCK_TIME_TICKS is defined in
\r
805 FreeRTOSIPConfig.h (assuming an official configuration file is being
\r
807 pxSocket->xSendBlockTime = *( ( portTickType * ) pvOptionValue );
\r
808 if( pxSocket->xSendBlockTime > ipconfigMAX_SEND_BLOCK_TIME_TICKS )
\r
810 pxSocket->xSendBlockTime = ipconfigMAX_SEND_BLOCK_TIME_TICKS;
\r
814 case FREERTOS_SO_UDPCKSUM_OUT :
\r
815 /* Turn calculating of the UDP checksum on/off for this socket. */
\r
816 lOptionValue = ( portBASE_TYPE ) pvOptionValue;
\r
818 if( lOptionValue == 0 )
\r
820 pxSocket->ucSocketOptions &= ~FREERTOS_SO_UDPCKSUM_OUT;
\r
824 pxSocket->ucSocketOptions |= FREERTOS_SO_UDPCKSUM_OUT;
\r
829 /* No other options are handled. */
\r
830 xReturn = FREERTOS_ENOPROTOOPT;
\r
836 /*-----------------------------------------------------------*/
\r
838 portBASE_TYPE xProcessReceivedUDPPacket( xNetworkBufferDescriptor_t *pxNetworkBuffer, uint16_t usPort )
\r
840 xListItem *pxListItem;
\r
841 portBASE_TYPE xReturn = pdPASS;
\r
842 xFreeRTOS_Socket_t *pxSocket;
\r
843 portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
\r
847 /* See if there is a list item associated with the port number on the
\r
848 list of bound sockets. */
\r
849 pxListItem = pxListFindListItemWithValue( &xBoundSocketsList, ( portTickType ) usPort );
\r
853 if( pxListItem != NULL )
\r
855 /* The owner of the list item is the socket itself. */
\r
856 pxSocket = ( xFreeRTOS_Socket_t * ) listGET_LIST_ITEM_OWNER( pxListItem );
\r
860 #if( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
\r
862 /* Is the socket a member of a select() group? */
\r
863 if( pxSocket->xSelectQueue != NULL )
\r
865 /* Can the select group be notified that the socket is
\r
866 ready to be read? */
\r
867 if( xQueueSendFromISR( pxSocket->xSelectQueue, &pxSocket, &xHigherPriorityTaskWoken ) != pdPASS )
\r
869 /* Could not notify the select group. */
\r
871 iptraceFAILED_TO_NOTIFY_SELECT_GROUP( pxSocket );
\r
877 if( xReturn == pdPASS )
\r
879 taskENTER_CRITICAL();
\r
881 /* Add the network packet to the list of packets to be
\r
882 processed by the socket. */
\r
883 vListInsertEnd( &( pxSocket->xWaitingPacketsList ), &( pxNetworkBuffer->xBufferListItem ) );
\r
885 taskEXIT_CRITICAL();
\r
887 /* The socket's counting semaphore records how many packets are
\r
888 waiting to be processed by the socket. */
\r
889 xSemaphoreGiveFromISR( pxSocket->xWaitingPacketSemaphore, &xHigherPriorityTaskWoken );
\r
892 if( xTaskResumeAll() == pdFALSE )
\r
894 if( xHigherPriorityTaskWoken != pdFALSE )
\r
907 /*-----------------------------------------------------------*/
\r
909 static uint16_t prvGetPrivatePortNumber( void )
\r
911 static uint16_t usNextPortToUse = socketAUTO_PORT_ALLOCATION_START_NUMBER - 1;
\r
914 /* Assign the next port in the range. */
\r
915 taskENTER_CRITICAL();
\r
917 taskEXIT_CRITICAL();
\r
919 /* Has it overflowed? */
\r
920 if( usNextPortToUse == 0U )
\r
922 /* Don't go right back to the start of the dynamic/private port
\r
923 range numbers as any persistent sockets are likely to have been
\r
924 create first so the early port numbers may still be in use. */
\r
925 usNextPortToUse = socketAUTO_PORT_ALLOCATION_RESET_NUMBER;
\r
928 usReturn = FreeRTOS_htons( usNextPortToUse );
\r
932 /*-----------------------------------------------------------*/
\r
934 xListItem * pxListFindListItemWithValue( xList *pxList, portTickType xWantedItemValue )
\r
936 xListItem *pxIterator, *pxReturn;
\r
939 for( pxIterator = ( xListItem * ) pxList->xListEnd.pxNext; pxIterator != ( xListItem* ) &( pxList->xListEnd ); pxIterator = ( xListItem * ) pxIterator->pxNext )
\r
941 if( pxIterator->xItemValue == xWantedItemValue )
\r
943 pxReturn = pxIterator;
\r
950 /*-----------------------------------------------------------*/
\r
952 #if ipconfigINCLUDE_FULL_INET_ADDR == 1
\r
954 uint32_t FreeRTOS_inet_addr( const uint8_t * pucIPAddress )
\r
956 const uint8_t ucDecimalBase = 10;
\r
957 uint8_t ucOctet[ socketMAX_IP_ADDRESS_OCTETS ];
\r
958 const uint8_t *pucPointerOnEntering;
\r
959 uint32_t ulReturn = 0UL, ulOctetNumber, ulValue;
\r
960 portBASE_TYPE xResult = pdPASS;
\r
962 for( ulOctetNumber = 0; ulOctetNumber < socketMAX_IP_ADDRESS_OCTETS; ulOctetNumber++ )
\r
965 pucPointerOnEntering = pucIPAddress;
\r
967 while( ( *pucIPAddress >= ( uint8_t ) '0' ) && ( *pucIPAddress <= ( uint8_t ) '9' ) )
\r
969 /* Move previous read characters into the next decimal
\r
971 ulValue *= ucDecimalBase;
\r
973 /* Add the binary value of the ascii character. */
\r
974 ulValue += ( *pucIPAddress - ( uint8_t ) '0' );
\r
976 /* Move to next character in the string. */
\r
980 /* Check characters were read. */
\r
981 if( pucIPAddress == pucPointerOnEntering )
\r
986 /* Check the value fits in an 8-bit number. */
\r
987 if( ulValue > 0xffUL )
\r
993 ucOctet[ ulOctetNumber ] = ( uint8_t ) ulValue;
\r
995 /* Check the next character is as expected. */
\r
996 if( ulOctetNumber < ( socketMAX_IP_ADDRESS_OCTETS - 1 ) )
\r
998 if( *pucIPAddress != ( uint8_t ) '.' )
\r
1004 /* Move past the dot. */
\r
1010 if( xResult == pdFAIL )
\r
1012 /* No point going on. */
\r
1017 if( *pucIPAddress != ( uint8_t ) 0x00 )
\r
1019 /* Expected the end of the string. */
\r
1023 if( ulOctetNumber != socketMAX_IP_ADDRESS_OCTETS )
\r
1025 /* Didn't read enough octets. */
\r
1029 if( xResult == pdPASS )
\r
1031 ulReturn = FreeRTOS_inet_addr_quick( ucOctet[ 0 ], ucOctet[ 1 ], ucOctet[ 2 ], ucOctet[ 3 ] );
\r
1037 #endif /* ipconfigINCLUDE_FULL_INET_ADDR */
\r
1038 /*-----------------------------------------------------------*/
\r