2 * FreeRTOS+UDP V1.0.3 (C) 2014 Real Time Engineers ltd.
\r
3 * All rights reserved
\r
5 * This file is part of the FreeRTOS+UDP distribution. The FreeRTOS+UDP license
\r
6 * terms are different to the FreeRTOS license terms.
\r
8 * FreeRTOS+UDP uses a dual license model that allows the software to be used
\r
9 * under a standard GPL open source license, or a commercial license. The
\r
10 * standard GPL license (unlike the modified GPL license under which FreeRTOS
\r
11 * itself is distributed) requires that all software statically linked with
\r
12 * FreeRTOS+UDP is also distributed under the same GPL V2 license terms.
\r
13 * Details of both license options follow:
\r
15 * - Open source licensing -
\r
16 * FreeRTOS+UDP is a free download and may be used, modified, evaluated and
\r
17 * distributed without charge provided the user adheres to version two of the
\r
18 * GNU General Public License (GPL) and does not remove the copyright notice or
\r
19 * this text. The GPL V2 text is available on the gnu.org web site, and on the
\r
20 * following URL: http://www.FreeRTOS.org/gpl-2.0.txt.
\r
22 * - Commercial licensing -
\r
23 * Businesses and individuals that for commercial or other reasons cannot comply
\r
24 * with the terms of the GPL V2 license must obtain a commercial license before
\r
25 * incorporating FreeRTOS+UDP into proprietary software for distribution in any
\r
26 * form. Commercial licenses can be purchased from http://shop.freertos.org/udp
\r
27 * and do not require any source files to be changed.
\r
29 * FreeRTOS+UDP is distributed in the hope that it will be useful. You cannot
\r
30 * use FreeRTOS+UDP unless you agree that you use the software 'as is'.
\r
31 * FreeRTOS+UDP is provided WITHOUT ANY WARRANTY; without even the implied
\r
32 * warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR
\r
33 * PURPOSE. Real Time Engineers Ltd. disclaims all conditions and terms, be they
\r
34 * implied, expressed, or statutory.
\r
36 * 1 tab == 4 spaces!
\r
38 * http://www.FreeRTOS.org
\r
39 * http://www.FreeRTOS.org/udp
\r
43 /* Standard includes. */
\r
46 /* FreeRTOS includes. */
\r
47 #include "FreeRTOS.h"
\r
52 /* FreeRTOS+UDP includes. */
\r
53 #include "FreeRTOS_UDP_IP.h"
\r
54 #include "FreeRTOS_IP_Private.h"
\r
55 #include "FreeRTOS_Sockets.h"
\r
56 #include "NetworkBufferManagement.h"
\r
58 /* Sanity check the UDP payload length setting is compatible with the
\r
59 fragmentation setting. */
\r
60 #if ipconfigCAN_FRAGMENT_OUTGOING_PACKETS == 1
\r
61 #if ( ( ipMAX_UDP_PAYLOAD_LENGTH % 8 ) != 0 )
\r
62 #error ( ipconfigNETWORK_MTU - 28 ) must be divisible by 8 when fragmentation is used
\r
63 #endif /* ipMAX_UDP_PAYLOAD_LENGTH */
\r
64 #endif /* ipconfigFRAGMENT_OUTGOING_PACKETS */
\r
66 /* The ItemValue of the sockets xBoundSocketListItem member holds the socket's
\r
68 #define socketSET_SOCKET_ADDRESS( pxSocket, usPort ) listSET_LIST_ITEM_VALUE( ( &( ( pxSocket )->xBoundSocketListItem ) ), ( usPort ) )
\r
69 #define socketGET_SOCKET_ADDRESS( pxSocket ) listGET_LIST_ITEM_VALUE( ( &( ( pxSocket )->xBoundSocketListItem ) ) )
\r
71 /* xWaitingPacketSemaphore is not created until the socket is bound, so can be
\r
72 tested to see if bind() has been called. */
\r
73 #define socketSOCKET_IS_BOUND( pxSocket ) ( ( BaseType_t ) pxSocket->xWaitingPacketSemaphore )
\r
75 /* If FreeRTOS_sendto() is called on a socket that is not bound to a port
\r
76 number then, depending on the FreeRTOSIPConfig.h settings, it might be that a
\r
77 port number is automatically generated for the socket. Automatically generated
\r
78 port numbers will be between socketAUTO_PORT_ALLOCATION_START_NUMBER and
\r
80 #define socketAUTO_PORT_ALLOCATION_START_NUMBER ( ( uint16_t ) 0xc000 )
\r
82 /* When the automatically generated port numbers overflow, the next value used
\r
83 is not set back to socketAUTO_PORT_ALLOCATION_START_NUMBER because it is likely
\r
84 that the first few automatically generated ports will still be in use. Instead
\r
85 it is reset back to the value defined by this constant. */
\r
86 #define socketAUTO_PORT_ALLOCATION_RESET_NUMBER ( ( uint16_t ) 0xc100 )
\r
88 /* The number of octets that make up an IP address. */
\r
89 #define socketMAX_IP_ADDRESS_OCTETS 4
\r
90 /*-----------------------------------------------------------*/
\r
93 * Allocate the next port number from the private allocation range.
\r
95 static uint16_t prvGetPrivatePortNumber( void );
\r
98 * Return the list itme from within pxList that has an item value of
\r
99 * xWantedItemValue. If there is no such list item return NULL.
\r
101 xListItem * pxListFindListItemWithValue( xList *pxList, TickType_t xWantedItemValue );
\r
103 /*-----------------------------------------------------------*/
\r
105 typedef struct XSOCKET
\r
107 xSemaphoreHandle xWaitingPacketSemaphore;
\r
108 xList xWaitingPacketsList;
\r
109 xListItem xBoundSocketListItem; /* Used to reference the socket from a bound sockets list. */
\r
110 TickType_t xReceiveBlockTime;
\r
111 TickType_t xSendBlockTime;
\r
112 uint8_t ucSocketOptions;
\r
113 #if ipconfigSUPPORT_SELECT_FUNCTION == 1
\r
114 xQueueHandle xSelectQueue;
\r
116 } xFreeRTOS_Socket_t;
\r
119 /* The list that contains mappings between sockets and port numbers. Accesses
\r
120 to this list must be protected by critical sections of one kind or another. */
\r
121 static xList xBoundSocketsList;
\r
123 /*-----------------------------------------------------------*/
\r
125 xSocket_t FreeRTOS_socket( BaseType_t xDomain, BaseType_t xType, BaseType_t xProtocol )
\r
127 xFreeRTOS_Socket_t *pxSocket;
\r
129 /* Only UDP on Ethernet is currently supported. */
\r
130 configASSERT( xDomain == FREERTOS_AF_INET );
\r
131 configASSERT( xType == FREERTOS_SOCK_DGRAM );
\r
132 configASSERT( xProtocol == FREERTOS_IPPROTO_UDP );
\r
133 configASSERT( listLIST_IS_INITIALISED( &xBoundSocketsList ) );
\r
135 /* Allocate the structure that will hold the socket information. */
\r
136 pxSocket = ( xFreeRTOS_Socket_t * ) pvPortMalloc( sizeof( xFreeRTOS_Socket_t ) );
\r
138 if( pxSocket == NULL )
\r
140 pxSocket = ( xFreeRTOS_Socket_t * ) FREERTOS_INVALID_SOCKET;
\r
141 iptraceFAILED_TO_CREATE_SOCKET();
\r
145 /* Initialise the socket's members. The semaphore will be created if
\r
146 the socket is bound to an address, for now the pointer to the semaphore
\r
147 is just set to NULL to show it has not been created. */
\r
148 pxSocket->xWaitingPacketSemaphore = NULL;
\r
149 vListInitialise( &( pxSocket->xWaitingPacketsList ) );
\r
150 vListInitialiseItem( &( pxSocket->xBoundSocketListItem ) );
\r
151 listSET_LIST_ITEM_OWNER( &( pxSocket->xBoundSocketListItem ), ( void * ) pxSocket );
\r
152 pxSocket->xSendBlockTime = ( TickType_t ) 0;
\r
153 pxSocket->xReceiveBlockTime = portMAX_DELAY;
\r
154 pxSocket->ucSocketOptions = FREERTOS_SO_UDPCKSUM_OUT;
\r
155 #if ipconfigSUPPORT_SELECT_FUNCTION == 1
\r
156 pxSocket->xSelectQueue = NULL;
\r
160 /* Remove compiler warnings in the case the configASSERT() is not defined. */
\r
163 ( void ) xProtocol;
\r
165 return ( xSocket_t ) pxSocket;
\r
167 /*-----------------------------------------------------------*/
\r
169 #if ipconfigSUPPORT_SELECT_FUNCTION == 1
\r
171 xSocketSet_t FreeRTOS_CreateSocketSet( UBaseType_t uxEventQueueLength )
\r
173 xQueueHandle xSelectQueue;
\r
175 /* Create the queue into which the address of sockets that are
\r
176 available to read are posted. */
\r
177 xSelectQueue = xQueueCreate( uxEventQueueLength, sizeof( xSocket_t ) );
\r
179 return ( xSocketSet_t ) xSelectQueue;
\r
182 #endif /* ipconfigSUPPORT_SELECT_FUNCTION */
\r
183 /*-----------------------------------------------------------*/
\r
185 #if ipconfigSUPPORT_SELECT_FUNCTION == 1
\r
187 BaseType_t FreeRTOS_FD_SET( xSocket_t xSocket, xSocketSet_t xSocketSet )
\r
189 xFreeRTOS_Socket_t *pxSocket = ( xFreeRTOS_Socket_t * ) xSocket;
\r
190 BaseType_t xReturn = pdFALSE;
\r
191 UBaseType_t uxMessagesWaiting;
\r
193 configASSERT( xSocket );
\r
195 /* Is the socket already a member of a select group? */
\r
196 if( pxSocket->xSelectQueue == NULL )
\r
198 taskENTER_CRITICAL();
\r
200 /* Are there packets queued on the socket already? */
\r
201 uxMessagesWaiting = uxQueueMessagesWaiting( pxSocket->xWaitingPacketSemaphore );
\r
203 /* Are there enough notification spaces in the select queue for the
\r
204 number of packets already queued on the socket? */
\r
205 if( uxQueueSpacesAvailable( ( xQueueHandle ) xSocketSet ) >= uxMessagesWaiting )
\r
207 /* Store a pointer to the select group in the socket for
\r
208 future reference. */
\r
209 pxSocket->xSelectQueue = ( xQueueHandle ) xSocketSet;
\r
211 while( uxMessagesWaiting > 0 )
\r
213 /* Add notifications of the number of packets that are
\r
214 already queued on the socket to the select queue. */
\r
215 xQueueSendFromISR( pxSocket->xSelectQueue, &pxSocket, NULL );
\r
216 uxMessagesWaiting--;
\r
222 taskEXIT_CRITICAL();
\r
228 #endif /* ipconfigSUPPORT_SELECT_FUNCTION */
\r
229 /*-----------------------------------------------------------*/
\r
231 #if ipconfigSUPPORT_SELECT_FUNCTION == 1
\r
233 BaseType_t FreeRTOS_FD_CLR( xSocket_t xSocket, xSocketSet_t xSocketSet )
\r
235 xFreeRTOS_Socket_t *pxSocket = ( xFreeRTOS_Socket_t * ) xSocket;
\r
236 BaseType_t xReturn;
\r
238 /* Is the socket a member of the select group? */
\r
239 if( pxSocket->xSelectQueue == ( xQueueHandle ) xSocketSet )
\r
241 /* The socket is no longer a member of the select group. */
\r
242 pxSocket->xSelectQueue = NULL;
\r
253 #endif /* ipconfigSUPPORT_SELECT_FUNCTION */
\r
254 /*-----------------------------------------------------------*/
\r
256 #if ipconfigSUPPORT_SELECT_FUNCTION == 1
\r
258 xSocket_t FreeRTOS_select( xSocketSet_t xSocketSet, TickType_t xBlockTimeTicks )
\r
260 xFreeRTOS_Socket_t *pxSocket;
\r
262 /* Wait for a socket to be ready to read. */
\r
263 if( xQueueReceive( ( xQueueHandle ) xSocketSet, &pxSocket, xBlockTimeTicks ) != pdPASS )
\r
268 return ( xSocket_t ) pxSocket;
\r
271 #endif /* ipconfigSUPPORT_SELECT_FUNCTION */
\r
272 /*-----------------------------------------------------------*/
\r
274 int32_t FreeRTOS_recvfrom( xSocket_t xSocket, void *pvBuffer, size_t xBufferLength, uint32_t ulFlags, struct freertos_sockaddr *pxSourceAddress, socklen_t *pxSourceAddressLength )
\r
276 xNetworkBufferDescriptor_t *pxNetworkBuffer;
\r
278 xFreeRTOS_Socket_t *pxSocket;
\r
280 pxSocket = ( xFreeRTOS_Socket_t * ) xSocket;
\r
282 /* The function prototype is designed to maintain the expected Berkeley
\r
283 sockets standard, but this implementation does not use all the parameters. */
\r
284 ( void ) pxSourceAddressLength;
\r
286 if( socketSOCKET_IS_BOUND( pxSocket ) != pdFALSE )
\r
288 /* The semaphore is given when received data is queued on the socket. */
\r
289 if( xSemaphoreTake( pxSocket->xWaitingPacketSemaphore, pxSocket->xReceiveBlockTime ) == pdPASS )
\r
291 taskENTER_CRITICAL();
\r
293 configASSERT( ( listCURRENT_LIST_LENGTH( &( pxSocket->xWaitingPacketsList ) ) > 0U ) );
\r
295 /* The owner of the list item is the network buffer. */
\r
296 pxNetworkBuffer = ( xNetworkBufferDescriptor_t * ) listGET_OWNER_OF_HEAD_ENTRY( &( pxSocket->xWaitingPacketsList ) );
\r
298 /* Remove the network buffer from the list of buffers waiting to
\r
299 be processed by the socket. */
\r
300 uxListRemove( &( pxNetworkBuffer->xBufferListItem ) );
\r
302 taskEXIT_CRITICAL();
\r
304 if( ( ulFlags & FREERTOS_ZERO_COPY ) == 0 )
\r
306 /* The zero copy flag is not set. Truncate the length if it
\r
307 won't fit in the provided buffer. */
\r
308 if( pxNetworkBuffer->xDataLength > xBufferLength )
\r
310 iptraceRECVFROM_DISCARDING_BYTES( ( xBufferLength - pxNetworkBuffer->xDataLength ) );
\r
311 pxNetworkBuffer->xDataLength = xBufferLength;
\r
314 /* Copy the received data into the provided buffer, then
\r
315 release the network buffer. */
\r
316 memcpy( pvBuffer, ( void * ) &( pxNetworkBuffer->pucEthernetBuffer[ ipUDP_PAYLOAD_OFFSET ] ), pxNetworkBuffer->xDataLength );
\r
317 vNetworkBufferRelease( pxNetworkBuffer );
\r
321 /* The zero copy flag was set. pvBuffer is not a buffer into
\r
322 which the received data can be copied, but a pointer that must
\r
323 be set to point to the buffer in which the received data has
\r
324 already been placed. */
\r
325 *( ( void** ) pvBuffer ) = ( void * ) ( &( pxNetworkBuffer->pucEthernetBuffer[ ipUDP_PAYLOAD_OFFSET ] ) );
\r
328 /* The returned value is the data length, which may have been
\r
329 capped to the receive buffer size. */
\r
330 lReturn = ( int32_t ) pxNetworkBuffer->xDataLength;
\r
332 if( pxSourceAddress != NULL )
\r
334 pxSourceAddress->sin_port = pxNetworkBuffer->usPort;
\r
335 pxSourceAddress->sin_addr = pxNetworkBuffer->ulIPAddress;
\r
340 lReturn = FREERTOS_EWOULDBLOCK;
\r
341 iptraceRECVFROM_TIMEOUT();
\r
346 lReturn = FREERTOS_EINVAL;
\r
351 /*-----------------------------------------------------------*/
\r
353 #if ipconfigCAN_FRAGMENT_OUTGOING_PACKETS == 1
\r
355 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
357 xNetworkBufferDescriptor_t *pxNetworkBuffer;
\r
358 xIPFragmentParameters_t *pxFragmentParameters;
\r
359 size_t xBytesToSend, xBytesRemaining;
\r
360 xIPStackEvent_t xStackTxEvent = { eStackTxEvent, NULL };
\r
361 extern xQueueHandle xNetworkEventQueue;
\r
362 uint8_t *pucBuffer;
\r
363 xTimeOutType xTimeOut;
\r
364 TickType_t xTicksToWait;
\r
365 uint16_t usFragmentOffset;
\r
366 xFreeRTOS_Socket_t *pxSocket;
\r
368 pxSocket = ( xFreeRTOS_Socket_t * ) xSocket;
\r
370 /* The function prototype is designed to maintain the expected Berkeley
\r
371 sockets standard, but this implementation does not use all the
\r
373 ( void ) xDestinationAddressLength;
\r
374 configASSERT( xNetworkEventQueue );
\r
375 configASSERT( pvBuffer );
\r
377 xBytesRemaining = xTotalDataLength;
\r
379 if( socketSOCKET_IS_BOUND( pxSocket ) == pdFALSE )
\r
381 /* If the socket is not already bound to an address, bind it now.
\r
382 Passing NULL as the address parameter tells FreeRTOS_bind() to select
\r
383 the address to bind to. */
\r
384 FreeRTOS_bind( xSocket, NULL, 0 );
\r
387 if( socketSOCKET_IS_BOUND( pxSocket ) != pdFALSE )
\r
389 /* pucBuffer will be reset if this send turns out to be a zero copy
\r
390 send because in that case pvBuffer is actually a pointer to an
\r
391 xUserData_t structure, not the UDP payload. */
\r
392 pucBuffer = ( uint8_t * ) pvBuffer;
\r
393 vTaskSetTimeOutState( &xTimeOut );
\r
394 xTicksToWait = pxSocket->xSendBlockTime;
\r
396 /* The data being transmitted will be sent in
\r
397 ipMAX_UDP_PAYLOAD_LENGTH chunks if xDataLength is greater than the
\r
398 network buffer payload size. Loop until all the data is sent. */
\r
399 while( xBytesRemaining > 0 )
\r
401 if( xBytesRemaining > ipMAX_UDP_PAYLOAD_LENGTH )
\r
403 /* Cap the amount being sent in this packet to the maximum
\r
404 UDP payload size. This will be a multiple of 8 already,
\r
405 removing the need to check in the code. */
\r
406 xBytesToSend = ipMAX_UDP_PAYLOAD_LENGTH;
\r
410 /* Send all remaining bytes - which may well be the total
\r
411 number of bytes if the packet was not chopped up. */
\r
412 xBytesToSend = xBytesRemaining;
\r
415 /* If the zero copy flag is set, then the data is already in a
\r
416 network buffer. Otherwise, get a new network buffer. */
\r
417 if( ( ulFlags & FREERTOS_ZERO_COPY ) == 0 )
\r
419 if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdTRUE )
\r
424 pxNetworkBuffer = pxNetworkBufferGet( xBytesToSend + sizeof( xUDPPacket_t ), xTicksToWait );
\r
428 if( xTotalDataLength > ipMAX_UDP_PAYLOAD_LENGTH )
\r
430 /* The packet needs fragmenting, but zero copy buffers
\r
431 cannot be fragmented. */
\r
432 pxNetworkBuffer = NULL;
\r
436 /* When zero copy is used, pvBuffer is a pointer to the
\r
437 payload of a buffer that has already been obtained from the
\r
438 stack. Obtain the network buffer pointer from the buffer. */
\r
439 pucBuffer = ( uint8_t * ) pvBuffer;
\r
440 pucBuffer -= ( ipBUFFER_PADDING + sizeof( xUDPPacket_t ) );
\r
441 pxNetworkBuffer = * ( ( xNetworkBufferDescriptor_t ** ) pucBuffer );
\r
445 if( pxNetworkBuffer != NULL )
\r
447 /* Use the part of the network buffer that will be completed
\r
448 by the IP layer as temporary storage to pass extra
\r
449 information required by the IP layer. */
\r
450 pxFragmentParameters = ( xIPFragmentParameters_t * ) &( pxNetworkBuffer->pucEthernetBuffer[ ipFRAGMENTATION_PARAMETERS_OFFSET ] );
\r
451 pxFragmentParameters->ucSocketOptions = pxSocket->ucSocketOptions;
\r
453 if( xBytesRemaining > ipMAX_UDP_PAYLOAD_LENGTH )
\r
455 /* The packet is being chopped up, and more data will
\r
457 pxFragmentParameters->ucSocketOptions = ( pxSocket->ucSocketOptions | FREERTOS_NOT_LAST_IN_FRAGMENTED_PACKET );
\r
460 if( xTotalDataLength > ipMAX_UDP_PAYLOAD_LENGTH )
\r
462 /* Let the IP layer know this packet has been chopped up,
\r
463 and supply the IP layer with any addition information it
\r
464 needs to make sense of it. */
\r
465 pxFragmentParameters->ucSocketOptions |= FREERTOS_FRAGMENTED_PACKET;
\r
466 usFragmentOffset = ( uint16_t ) ( xTotalDataLength - xBytesRemaining );
\r
467 pxFragmentParameters->usFragmentedPacketOffset = usFragmentOffset;
\r
468 pxFragmentParameters->usFragmentLength = ( uint16_t ) xBytesToSend;
\r
472 usFragmentOffset = 0;
\r
475 /* Write the payload into the packet. The IP layer is
\r
476 queried to find where in the IP payload the data should be
\r
477 written. This is because the necessary offset is different
\r
478 for the first packet, because the first packet leaves space
\r
479 for a UDP header. Note that this changes usFragmentOffset
\r
480 from the offset in the entire UDP packet, to the offset
\r
481 in the IP packet. */
\r
482 if( ( ulFlags & FREERTOS_ZERO_COPY ) == 0 )
\r
484 /* Only copy the data if it is not already in the
\r
485 expected location. */
\r
486 usFragmentOffset = ipGET_UDP_PAYLOAD_OFFSET_FOR_FRAGMENT( usFragmentOffset );
\r
487 memcpy( ( void * ) &( pxNetworkBuffer->pucEthernetBuffer[ usFragmentOffset ] ), ( void * ) pucBuffer, xBytesToSend );
\r
489 pxNetworkBuffer->xDataLength = xTotalDataLength;
\r
490 pxNetworkBuffer->usPort = pxDestinationAddress->sin_port;
\r
491 pxNetworkBuffer->usBoundPort = ( uint16_t ) socketGET_SOCKET_ADDRESS( pxSocket );
\r
492 pxNetworkBuffer->ulIPAddress = pxDestinationAddress->sin_addr;
\r
494 /* Tell the networking task that the packet needs sending. */
\r
495 xStackTxEvent.pvData = pxNetworkBuffer;
\r
497 if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdTRUE )
\r
502 if( xQueueSendToBack( xNetworkEventQueue, &xStackTxEvent, xTicksToWait ) != pdPASS )
\r
504 /* If the buffer was allocated in this function, release it. */
\r
505 if( ( ulFlags & FREERTOS_ZERO_COPY ) == 0 )
\r
507 vNetworkBufferRelease( pxNetworkBuffer );
\r
509 iptraceSTACK_TX_EVENT_LOST( ipSTACK_TX_EVENT );
\r
513 /* Adjust counters ready to either exit the loop, or send
\r
514 another chunk of data. */
\r
515 xBytesRemaining -= xBytesToSend;
\r
516 pucBuffer += xBytesToSend;
\r
520 /* If errno was available, errno would be set to
\r
521 FREERTOS_ENOPKTS. As it is, the function must return the
\r
522 number of transmitted bytes, so the calling function knows how
\r
523 much data was actually sent. */
\r
529 return ( xTotalDataLength - xBytesRemaining );
\r
532 #else /* ipconfigCAN_FRAGMENT_OUTGOING_PACKETS */
\r
534 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
536 xNetworkBufferDescriptor_t *pxNetworkBuffer;
\r
537 xIPStackEvent_t xStackTxEvent = { eStackTxEvent, NULL };
\r
538 extern xQueueHandle xNetworkEventQueue;
\r
539 xTimeOutType xTimeOut;
\r
540 TickType_t xTicksToWait;
\r
541 int32_t lReturn = 0;
\r
542 xFreeRTOS_Socket_t *pxSocket;
\r
543 uint8_t *pucBuffer;
\r
545 pxSocket = ( xFreeRTOS_Socket_t * ) xSocket;
\r
547 /* The function prototype is designed to maintain the expected Berkeley
\r
548 sockets standard, but this implementation does not use all the
\r
550 ( void ) xDestinationAddressLength;
\r
551 configASSERT( xNetworkEventQueue );
\r
552 configASSERT( pvBuffer );
\r
554 if( xTotalDataLength <= ipMAX_UDP_PAYLOAD_LENGTH )
\r
556 if( socketSOCKET_IS_BOUND( pxSocket ) == pdFALSE )
\r
558 /* If the socket is not already bound to an address, bind it now.
\r
559 Passing NULL as the address parameter tells FreeRTOS_bind() to
\r
560 select the address to bind to. */
\r
561 FreeRTOS_bind( pxSocket, NULL, 0 );
\r
564 if( socketSOCKET_IS_BOUND( pxSocket ) != pdFALSE )
\r
566 xTicksToWait = pxSocket->xSendBlockTime;
\r
568 if( ( ulFlags & FREERTOS_ZERO_COPY ) == 0 )
\r
570 /* Zero copy is not set, so obtain a network buffer into
\r
571 which the payload will be copied. */
\r
572 vTaskSetTimeOutState( &xTimeOut );
\r
573 pxNetworkBuffer = pxNetworkBufferGet( xTotalDataLength + sizeof( xUDPPacket_t ), xTicksToWait );
\r
575 if( pxNetworkBuffer != NULL )
\r
577 memcpy( ( void * ) &( pxNetworkBuffer->pucEthernetBuffer[ ipUDP_PAYLOAD_OFFSET ] ), ( void * ) pvBuffer, xTotalDataLength );
\r
579 if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdTRUE )
\r
581 /* The entire block time has been used up. */
\r
588 /* When zero copy is used, pvBuffer is a pointer to the
\r
589 payload of a buffer that has already been obtained from the
\r
590 stack. Obtain the network buffer pointer from the buffer. */
\r
591 pucBuffer = ( uint8_t * ) pvBuffer;
\r
592 pucBuffer -= ( ipBUFFER_PADDING + sizeof( xUDPPacket_t ) );
\r
593 pxNetworkBuffer = * ( ( xNetworkBufferDescriptor_t ** ) pucBuffer );
\r
596 if( pxNetworkBuffer != NULL )
\r
598 pxNetworkBuffer->xDataLength = xTotalDataLength;
\r
599 pxNetworkBuffer->usPort = pxDestinationAddress->sin_port;
\r
600 pxNetworkBuffer->usBoundPort = ( uint16_t ) socketGET_SOCKET_ADDRESS( pxSocket );
\r
601 pxNetworkBuffer->ulIPAddress = pxDestinationAddress->sin_addr;
\r
603 /* The socket options are passed to the IP layer in the
\r
604 space that will eventually get used by the Ethernet header. */
\r
605 pxNetworkBuffer->pucEthernetBuffer[ ipSOCKET_OPTIONS_OFFSET ] = pxSocket->ucSocketOptions;
\r
607 /* Tell the networking task that the packet needs sending. */
\r
608 xStackTxEvent.pvData = pxNetworkBuffer;
\r
610 if( xQueueSendToBack( xNetworkEventQueue, &xStackTxEvent, xTicksToWait ) != pdPASS )
\r
612 /* If the buffer was allocated in this function, release it. */
\r
613 if( ( ulFlags & FREERTOS_ZERO_COPY ) == 0 )
\r
615 vNetworkBufferRelease( pxNetworkBuffer );
\r
617 iptraceSTACK_TX_EVENT_LOST( ipSTACK_TX_EVENT );
\r
621 lReturn = ( int32_t ) xTotalDataLength;
\r
626 /* If errno was available, errno would be set to
\r
627 FREERTOS_ENOPKTS. As it is, the function must return the
\r
628 number of transmitted bytes, so the calling function knows how
\r
629 much data was actually sent. */
\r
630 iptraceNO_BUFFER_FOR_SENDTO();
\r
635 iptraceSENDTO_SOCKET_NOT_BOUND();
\r
640 /* The data is longer than the available buffer space. Setting
\r
641 ipconfigCAN_FRAGMENT_OUTGOING_PACKETS to 1 may allow this packet
\r
643 iptraceSENDTO_DATA_TOO_LONG();
\r
649 #endif /* ipconfigCAN_FRAGMENT_OUTGOING_PACKETS */
\r
650 /*-----------------------------------------------------------*/
\r
652 BaseType_t FreeRTOS_bind( xSocket_t xSocket, struct freertos_sockaddr * pxAddress, socklen_t xAddressLength )
\r
654 BaseType_t xReturn = 0; /* In Berkeley sockets, 0 means pass for bind(). */
\r
655 xFreeRTOS_Socket_t *pxSocket;
\r
656 #if ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND == 1
\r
657 struct freertos_sockaddr xAddress;
\r
658 #endif /* ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND */
\r
660 pxSocket = ( xFreeRTOS_Socket_t * ) xSocket;
\r
662 /* The function prototype is designed to maintain the expected Berkeley
\r
663 sockets standard, but this implementation does not use all the parameters. */
\r
664 ( void ) xAddressLength;
\r
666 configASSERT( xSocket );
\r
667 configASSERT( xSocket != FREERTOS_INVALID_SOCKET );
\r
669 #if ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND == 1
\r
671 /* pxAddress will be NULL if sendto() was called on a socket without the
\r
672 socket being bound to an address. In this case, automatically allocate
\r
673 an address to the socket. There is a very tiny chance that the allocated
\r
674 port will already be in use - if that is the case, then the check below
\r
675 [pxListFindListItemWithValue()] will result in an error being returned. */
\r
676 if( pxAddress == NULL )
\r
678 pxAddress = &xAddress;
\r
679 pxAddress->sin_port = prvGetPrivatePortNumber();
\r
682 #endif /* ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND == 1 */
\r
684 /* Sockets must be bound before calling FreeRTOS_sendto() if
\r
685 ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND is not set to 1. */
\r
686 configASSERT( pxAddress );
\r
688 if( pxAddress != NULL )
\r
690 if( pxAddress->sin_port == 0 )
\r
692 pxAddress->sin_port = prvGetPrivatePortNumber();
\r
697 /* Check to ensure the port is not already in use. */
\r
698 if( pxListFindListItemWithValue( &xBoundSocketsList, ( TickType_t ) pxAddress->sin_port ) != NULL )
\r
700 xReturn = FREERTOS_EADDRINUSE;
\r
705 /* Check that xReturn has not been set before continuing. */
\r
708 if( pxSocket->xWaitingPacketSemaphore == NULL )
\r
710 /* Create the semaphore used to count the number of packets that
\r
711 are queued on this socket. */
\r
712 pxSocket->xWaitingPacketSemaphore = xSemaphoreCreateCounting( ipconfigNUM_NETWORK_BUFFERS, 0 );
\r
714 if( pxSocket->xWaitingPacketSemaphore != NULL )
\r
716 /* Allocate the port number to the socket. */
\r
717 socketSET_SOCKET_ADDRESS( pxSocket, pxAddress->sin_port );
\r
718 taskENTER_CRITICAL();
\r
720 /* Add the socket to the list of bound ports. */
\r
721 vListInsertEnd( &xBoundSocketsList, &( pxSocket->xBoundSocketListItem ) );
\r
723 taskEXIT_CRITICAL();
\r
727 /* Out of memory. */
\r
728 xReturn = FREERTOS_ENOBUFS;
\r
733 /* The socket is already bound. */
\r
734 xReturn = FREERTOS_EINVAL;
\r
740 xReturn = FREERTOS_EADDRNOTAVAIL;
\r
745 iptraceBIND_FAILED( xSocket, ( FreeRTOS_ntohs( pxAddress->sin_port ) ) );
\r
750 /*-----------------------------------------------------------*/
\r
752 BaseType_t FreeRTOS_closesocket( xSocket_t xSocket )
\r
754 xNetworkBufferDescriptor_t *pxNetworkBuffer;
\r
755 xFreeRTOS_Socket_t *pxSocket;
\r
757 pxSocket = ( xFreeRTOS_Socket_t * ) xSocket;
\r
759 configASSERT( pxSocket );
\r
760 configASSERT( pxSocket != FREERTOS_INVALID_SOCKET );
\r
762 /* Socket must be unbound first, to ensure no more packets are queued on
\r
764 if( socketSOCKET_IS_BOUND( pxSocket ) != pdFALSE )
\r
766 taskENTER_CRITICAL();
\r
768 uxListRemove( &( pxSocket->xBoundSocketListItem ) );
\r
770 taskEXIT_CRITICAL();
\r
773 /* Now the socket is not bound the list of waiting packets can be
\r
775 if( pxSocket->xWaitingPacketSemaphore != NULL )
\r
777 while( listCURRENT_LIST_LENGTH( &( pxSocket->xWaitingPacketsList ) ) > 0U )
\r
779 pxNetworkBuffer = ( xNetworkBufferDescriptor_t * ) listGET_OWNER_OF_HEAD_ENTRY( &( pxSocket->xWaitingPacketsList ) );
\r
780 uxListRemove( &( pxNetworkBuffer->xBufferListItem ) );
\r
781 vNetworkBufferRelease( pxNetworkBuffer );
\r
783 vSemaphoreDelete( pxSocket->xWaitingPacketSemaphore );
\r
786 vPortFree( pxSocket );
\r
790 /*-----------------------------------------------------------*/
\r
792 void FreeRTOS_SocketsInit( void )
\r
794 vListInitialise( &xBoundSocketsList );
\r
796 /*-----------------------------------------------------------*/
\r
798 BaseType_t FreeRTOS_setsockopt( xSocket_t xSocket, int32_t lLevel, int32_t lOptionName, const void *pvOptionValue, size_t xOptionLength )
\r
800 /* The standard Berkeley function returns 0 for success. */
\r
801 BaseType_t xReturn = 0;
\r
802 BaseType_t lOptionValue;
\r
803 xFreeRTOS_Socket_t *pxSocket;
\r
805 pxSocket = ( xFreeRTOS_Socket_t * ) xSocket;
\r
807 /* The function prototype is designed to maintain the expected Berkeley
\r
808 sockets standard, but this implementation does not use all the parameters. */
\r
810 ( void ) xOptionLength;
\r
812 configASSERT( xSocket );
\r
814 switch( lOptionName )
\r
816 case FREERTOS_SO_RCVTIMEO :
\r
817 /* Receive time out. */
\r
818 pxSocket->xReceiveBlockTime = *( ( TickType_t * ) pvOptionValue );
\r
821 case FREERTOS_SO_SNDTIMEO :
\r
822 /* The send time out is capped for the reason stated in the comments
\r
823 where ipconfigMAX_SEND_BLOCK_TIME_TICKS is defined in
\r
824 FreeRTOSIPConfig.h (assuming an official configuration file is being
\r
826 pxSocket->xSendBlockTime = *( ( TickType_t * ) pvOptionValue );
\r
827 if( pxSocket->xSendBlockTime > ipconfigMAX_SEND_BLOCK_TIME_TICKS )
\r
829 pxSocket->xSendBlockTime = ipconfigMAX_SEND_BLOCK_TIME_TICKS;
\r
833 case FREERTOS_SO_UDPCKSUM_OUT :
\r
834 /* Turn calculating of the UDP checksum on/off for this socket. */
\r
835 lOptionValue = ( BaseType_t ) pvOptionValue;
\r
837 if( lOptionValue == 0 )
\r
839 pxSocket->ucSocketOptions &= ~FREERTOS_SO_UDPCKSUM_OUT;
\r
843 pxSocket->ucSocketOptions |= FREERTOS_SO_UDPCKSUM_OUT;
\r
848 /* No other options are handled. */
\r
849 xReturn = FREERTOS_ENOPROTOOPT;
\r
855 /*-----------------------------------------------------------*/
\r
857 BaseType_t xProcessReceivedUDPPacket( xNetworkBufferDescriptor_t *pxNetworkBuffer, uint16_t usPort )
\r
859 xListItem *pxListItem;
\r
860 BaseType_t xReturn = pdPASS;
\r
861 xFreeRTOS_Socket_t *pxSocket;
\r
862 BaseType_t xHigherPriorityTaskWoken = pdFALSE;
\r
866 /* See if there is a list item associated with the port number on the
\r
867 list of bound sockets. */
\r
868 pxListItem = pxListFindListItemWithValue( &xBoundSocketsList, ( TickType_t ) usPort );
\r
872 if( pxListItem != NULL )
\r
874 /* The owner of the list item is the socket itself. */
\r
875 pxSocket = ( xFreeRTOS_Socket_t * ) listGET_LIST_ITEM_OWNER( pxListItem );
\r
879 #if( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
\r
881 /* Is the socket a member of a select() group? */
\r
882 if( pxSocket->xSelectQueue != NULL )
\r
884 /* Can the select group be notified that the socket is
\r
885 ready to be read? */
\r
886 if( xQueueSendFromISR( pxSocket->xSelectQueue, &pxSocket, &xHigherPriorityTaskWoken ) != pdPASS )
\r
888 /* Could not notify the select group. */
\r
890 iptraceFAILED_TO_NOTIFY_SELECT_GROUP( pxSocket );
\r
896 if( xReturn == pdPASS )
\r
898 taskENTER_CRITICAL();
\r
900 /* Add the network packet to the list of packets to be
\r
901 processed by the socket. */
\r
902 vListInsertEnd( &( pxSocket->xWaitingPacketsList ), &( pxNetworkBuffer->xBufferListItem ) );
\r
904 taskEXIT_CRITICAL();
\r
906 /* The socket's counting semaphore records how many packets are
\r
907 waiting to be processed by the socket. */
\r
908 xSemaphoreGiveFromISR( pxSocket->xWaitingPacketSemaphore, &xHigherPriorityTaskWoken );
\r
911 if( xTaskResumeAll() == pdFALSE )
\r
913 if( xHigherPriorityTaskWoken != pdFALSE )
\r
926 /*-----------------------------------------------------------*/
\r
928 static uint16_t prvGetPrivatePortNumber( void )
\r
930 static uint16_t usNextPortToUse = socketAUTO_PORT_ALLOCATION_START_NUMBER - 1;
\r
933 /* Assign the next port in the range. */
\r
934 taskENTER_CRITICAL();
\r
938 /* Has it overflowed? */
\r
939 if( usNextPortToUse == 0U )
\r
941 /* Don't go right back to the start of the dynamic/private port
\r
942 range numbers as any persistent sockets are likely to have been
\r
943 create first so the early port numbers may still be in use. */
\r
944 usNextPortToUse = socketAUTO_PORT_ALLOCATION_RESET_NUMBER;
\r
947 usReturn = FreeRTOS_htons( usNextPortToUse );
\r
949 taskEXIT_CRITICAL();
\r
953 /*-----------------------------------------------------------*/
\r
955 xListItem * pxListFindListItemWithValue( xList *pxList, TickType_t xWantedItemValue )
\r
957 xListItem *pxIterator, *pxReturn;
\r
960 for( pxIterator = ( xListItem * ) pxList->xListEnd.pxNext; pxIterator != ( xListItem* ) &( pxList->xListEnd ); pxIterator = ( xListItem * ) pxIterator->pxNext )
\r
962 if( pxIterator->xItemValue == xWantedItemValue )
\r
964 pxReturn = pxIterator;
\r
971 /*-----------------------------------------------------------*/
\r
973 #if ipconfigINCLUDE_FULL_INET_ADDR == 1
\r
975 uint32_t FreeRTOS_inet_addr( const char *pcIPAddress )
\r
977 const uint8_t ucDecimalBase = 10;
\r
978 uint8_t ucOctet[ socketMAX_IP_ADDRESS_OCTETS ];
\r
979 const char *pcPointerOnEntering;
\r
980 uint32_t ulReturn = 0UL, ulOctetNumber, ulValue;
\r
981 BaseType_t xResult = pdPASS;
\r
983 for( ulOctetNumber = 0; ulOctetNumber < socketMAX_IP_ADDRESS_OCTETS; ulOctetNumber++ )
\r
986 pcPointerOnEntering = pcIPAddress;
\r
988 while( ( *pcIPAddress >= ( uint8_t ) '0' ) && ( *pcIPAddress <= ( uint8_t ) '9' ) )
\r
990 /* Move previous read characters into the next decimal
\r
992 ulValue *= ucDecimalBase;
\r
994 /* Add the binary value of the ascii character. */
\r
995 ulValue += ( *pcIPAddress - ( uint8_t ) '0' );
\r
997 /* Move to next character in the string. */
\r
1001 /* Check characters were read. */
\r
1002 if( pcIPAddress == pcPointerOnEntering )
\r
1007 /* Check the value fits in an 8-bit number. */
\r
1008 if( ulValue > 0xffUL )
\r
1014 ucOctet[ ulOctetNumber ] = ( uint8_t ) ulValue;
\r
1016 /* Check the next character is as expected. */
\r
1017 if( ulOctetNumber < ( socketMAX_IP_ADDRESS_OCTETS - 1 ) )
\r
1019 if( *pcIPAddress != ( uint8_t ) '.' )
\r
1025 /* Move past the dot. */
\r
1031 if( xResult == pdFAIL )
\r
1033 /* No point going on. */
\r
1038 if( *pcIPAddress != ( uint8_t ) 0x00 )
\r
1040 /* Expected the end of the string. */
\r
1044 if( ulOctetNumber != socketMAX_IP_ADDRESS_OCTETS )
\r
1046 /* Didn't read enough octets. */
\r
1050 if( xResult == pdPASS )
\r
1052 ulReturn = FreeRTOS_inet_addr_quick( ucOctet[ 0 ], ucOctet[ 1 ], ucOctet[ 2 ], ucOctet[ 3 ] );
\r
1058 #endif /* ipconfigINCLUDE_FULL_INET_ADDR */
\r
1059 /*-----------------------------------------------------------*/
\r