2 * FreeRTOS+UDP V1.0.0 (C) 2013 Real Time Engineers ltd.
\r
4 * FreeRTOS+UDP is an add-on component to FreeRTOS. It is not, in itself, part
\r
5 * of the FreeRTOS kernel. FreeRTOS+UDP is licensed separately from FreeRTOS,
\r
6 * and uses a different license to FreeRTOS. FreeRTOS+UDP uses a dual license
\r
7 * model, information on which is provided below:
\r
9 * - Open source licensing -
\r
10 * FreeRTOS+UDP is a free download and may be used, modified and distributed
\r
11 * without charge provided the user adheres to version two of the GNU General
\r
12 * Public license (GPL) and does not remove the copyright notice or this text.
\r
13 * The GPL V2 text is available on the gnu.org web site, and on the following
\r
14 * URL: http://www.FreeRTOS.org/gpl-2.0.txt
\r
16 * - Commercial licensing -
\r
17 * Businesses and individuals who wish to incorporate FreeRTOS+UDP into
\r
18 * proprietary software for redistribution in any form must first obtain a
\r
19 * (very) low cost commercial license - and in-so-doing support the maintenance,
\r
20 * support and further development of the FreeRTOS+UDP product. Commercial
\r
21 * licenses can be obtained from http://shop.freertos.org and do not require any
\r
22 * source files to be changed.
\r
24 * FreeRTOS+UDP is distributed in the hope that it will be useful. You cannot
\r
25 * use FreeRTOS+UDP unless you agree that you use the software 'as is'.
\r
26 * FreeRTOS+UDP is provided WITHOUT ANY WARRANTY; without even the implied
\r
27 * warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR
\r
28 * PURPOSE. Real Time Engineers Ltd. disclaims all conditions and terms, be they
\r
29 * implied, expressed, or statutory.
\r
31 * 1 tab == 4 spaces!
\r
33 * http://www.FreeRTOS.org
\r
34 * http://www.FreeRTOS.org/udp
\r
38 /* Standard includes. */
\r
41 /* FreeRTOS includes. */
\r
42 #include "FreeRTOS.h"
\r
47 /* FreeRTOS+UDP includes. */
\r
48 #include "FreeRTOS_UDP_IP.h"
\r
49 #include "FreeRTOS_IP_Private.h"
\r
50 #include "FreeRTOS_Sockets.h"
\r
51 #include "NetworkBufferManagement.h"
\r
53 /* Sanity check the UDP payload length setting is compatible with the
\r
54 fragmentation setting. */
\r
55 #if ipconfigCAN_FRAGMENT_OUTGOING_PACKETS == 1
\r
56 #if ( ( ipMAX_UDP_PAYLOAD_LENGTH % 8 ) != 0 )
\r
57 #error ( ipconfigNETWORK_MTU - 28 ) must be divisible by 8 when fragmentation is used
\r
58 #endif /* ipMAX_UDP_PAYLOAD_LENGTH */
\r
59 #endif /* ipconfigFRAGMENT_OUTGOING_PACKETS */
\r
61 /* The ItemValue of the sockets xBoundSocketListItem member holds the socket's
\r
63 #define socketSET_SOCKET_ADDRESS( pxSocket, usPort ) listSET_LIST_ITEM_VALUE( ( &( ( pxSocket )->xBoundSocketListItem ) ), ( usPort ) )
\r
64 #define socketGET_SOCKET_ADDRESS( pxSocket ) listGET_LIST_ITEM_VALUE( ( &( ( pxSocket )->xBoundSocketListItem ) ) )
\r
66 /* xWaitingPacketSemaphore is not created until the socket is bound, so can be
\r
67 tested to see if bind() has been called. */
\r
68 #define socketSOCKET_IS_BOUND( pxSocket ) ( ( uint32_t ) pxSocket->xWaitingPacketSemaphore )
\r
70 /* If FreeRTOS_sendto() is called on a socket that is not bound to a port
\r
71 number then, depending on the FreeRTOSIPConfig.h settings, it might be that a
\r
72 port number is automatically generated for the socket. Automatically generated
\r
73 port numbers will be between socketAUTO_PORT_ALLOCATION_START_NUMBER and
\r
75 #define socketAUTO_PORT_ALLOCATION_START_NUMBER ( ( uint16_t ) 0xc000 )
\r
77 /* When the automatically generated port numbers overflow, the next value used
\r
78 is not set back to socketAUTO_PORT_ALLOCATION_START_NUMBER because it is likely
\r
79 that the first few automatically generated ports will still be in use. Instead
\r
80 it is reset back to the value defined by this constant. */
\r
81 #define socketAUTO_PORT_ALLOCATION_RESET_NUMBER ( ( uint16_t ) 0xc100 )
\r
83 /* The number of octets that make up an IP address. */
\r
84 #define socketMAX_IP_ADDRESS_OCTETS 4
\r
85 /*-----------------------------------------------------------*/
\r
88 * Allocate the next port number from the private allocation range.
\r
90 static uint16_t prvGetPrivatePortNumber( void );
\r
93 * Return the list itme from within pxList that has an item value of
\r
94 * xWantedItemValue. If there is no such list item return NULL.
\r
96 xListItem * pxListFindListItemWithValue( xList *pxList, portTickType xWantedItemValue );
\r
98 /*-----------------------------------------------------------*/
\r
100 typedef struct XSOCKET
\r
102 xSemaphoreHandle xWaitingPacketSemaphore;
\r
103 xList xWaitingPacketsList;
\r
104 xListItem xBoundSocketListItem; /* Used to reference the socket from a bound sockets list. */
\r
105 portTickType xReceiveBlockTime;
\r
106 portTickType xSendBlockTime;
\r
107 uint8_t ucSocketOptions;
\r
108 #if ipconfigSUPPORT_SELECT_FUNCTION == 1
\r
109 xQueueHandle xSelectQueue;
\r
111 } xFreeRTOS_Socket_t;
\r
114 /* The list that contains mappings between sockets and port numbers. Accesses
\r
115 to this list must be protected by critical sections of one kind or another. */
\r
116 static xList xBoundSocketsList;
\r
118 /*-----------------------------------------------------------*/
\r
120 xSocket_t FreeRTOS_socket( portBASE_TYPE xDomain, portBASE_TYPE xType, portBASE_TYPE xProtocol )
\r
122 xFreeRTOS_Socket_t *pxSocket;
\r
124 /* Only UDP on Ethernet is currently supported. */
\r
125 configASSERT( xDomain == FREERTOS_AF_INET );
\r
126 configASSERT( xType == FREERTOS_SOCK_DGRAM );
\r
127 configASSERT( xProtocol == FREERTOS_IPPROTO_UDP );
\r
128 configASSERT( listLIST_IS_INITIALISED( &xBoundSocketsList ) );
\r
130 /* Allocate the structure that will hold the socket information. */
\r
131 pxSocket = ( xFreeRTOS_Socket_t * ) pvPortMalloc( sizeof( xFreeRTOS_Socket_t ) );
\r
133 if( pxSocket == NULL )
\r
135 pxSocket = ( xFreeRTOS_Socket_t * ) FREERTOS_INVALID_SOCKET;
\r
136 iptraceFAILED_TO_CREATE_SOCKET();
\r
140 /* Initialise the socket's members. The semaphore will be created if
\r
141 the socket is bound to an address, for now the pointer to the semaphore
\r
142 is just set to NULL to show it has not been created. */
\r
143 pxSocket->xWaitingPacketSemaphore = NULL;
\r
144 vListInitialise( &( pxSocket->xWaitingPacketsList ) );
\r
145 vListInitialiseItem( &( pxSocket->xBoundSocketListItem ) );
\r
146 listSET_LIST_ITEM_OWNER( &( pxSocket->xBoundSocketListItem ), ( void * ) pxSocket );
\r
147 pxSocket->xSendBlockTime = ( portTickType ) 0;
\r
148 pxSocket->xReceiveBlockTime = portMAX_DELAY;
\r
149 pxSocket->ucSocketOptions = FREERTOS_SO_UDPCKSUM_OUT;
\r
150 #if ipconfigSUPPORT_SELECT_FUNCTION == 1
\r
151 pxSocket->xSelectQueue = NULL;
\r
155 /* Remove compiler warnings in the case the configASSERT() is not defined. */
\r
158 ( void ) xProtocol;
\r
160 return ( xSocket_t ) pxSocket;
\r
162 /*-----------------------------------------------------------*/
\r
164 #if ipconfigSUPPORT_SELECT_FUNCTION == 1
\r
166 xSocketSet_t FreeRTOS_CreateSocketSet( unsigned portBASE_TYPE uxEventQueueLength )
\r
168 xQueueHandle xSelectQueue;
\r
170 /* Create the queue into which the address of sockets that are
\r
171 available to read are posted. */
\r
172 xSelectQueue = xQueueCreate( uxEventQueueLength, sizeof( xSocket_t ) );
\r
174 return ( xSocketSet_t ) xSelectQueue;
\r
177 #endif /* ipconfigSUPPORT_SELECT_FUNCTION */
\r
178 /*-----------------------------------------------------------*/
\r
180 #if ipconfigSUPPORT_SELECT_FUNCTION == 1
\r
182 portBASE_TYPE FreeRTOS_FD_SET( xSocket_t xSocket, xSocketSet_t xSocketSet )
\r
184 xFreeRTOS_Socket_t *pxSocket = ( xFreeRTOS_Socket_t * ) xSocket;
\r
185 portBASE_TYPE xReturn;
\r
187 /* Is the socket already a member of a select group? */
\r
188 if( pxSocket->xSelectQueue == NULL )
\r
190 /* Store a pointer to the select group in the socket for future
\r
192 pxSocket->xSelectQueue = ( xQueueHandle ) xSocketSet;
\r
197 /* The socket is already a member of a select group so cannot be added
\r
205 #endif /* ipconfigSUPPORT_SELECT_FUNCTION */
\r
206 /*-----------------------------------------------------------*/
\r
208 #if ipconfigSUPPORT_SELECT_FUNCTION == 1
\r
210 portBASE_TYPE FreeRTOS_FD_CLR( xSocket_t xSocket, xSocketSet_t xSocketSet )
\r
212 xFreeRTOS_Socket_t *pxSocket = ( xFreeRTOS_Socket_t * ) xSocket;
\r
213 portBASE_TYPE xReturn;
\r
215 /* Is the socket a member of the select group? */
\r
216 if( pxSocket->xSelectQueue == ( xQueueHandle ) xSocketSet )
\r
218 /* The socket is no longer a member of the select group. */
\r
219 pxSocket->xSelectQueue = NULL;
\r
230 #endif /* ipconfigSUPPORT_SELECT_FUNCTION */
\r
231 /*-----------------------------------------------------------*/
\r
233 #if ipconfigSUPPORT_SELECT_FUNCTION == 1
\r
235 xSocket_t FreeRTOS_select( xSocketSet_t xSocketSet, portTickType xBlockTimeTicks )
\r
237 xFreeRTOS_Socket_t *pxSocket;
\r
239 /* Wait for a socket to be ready to read. */
\r
240 if( xQueueReceive( ( xQueueHandle ) xSocketSet, &pxSocket, xBlockTimeTicks ) != pdPASS )
\r
245 return ( xSocket_t ) pxSocket;
\r
248 #endif /* ipconfigSUPPORT_SELECT_FUNCTION */
\r
249 /*-----------------------------------------------------------*/
\r
251 int32_t FreeRTOS_recvfrom( xSocket_t xSocket, void *pvBuffer, size_t xBufferLength, uint32_t ulFlags, struct freertos_sockaddr *pxSourceAddress, socklen_t *pxSourceAddressLength )
\r
253 xNetworkBufferDescriptor_t *pxNetworkBuffer;
\r
255 xFreeRTOS_Socket_t *pxSocket;
\r
257 pxSocket = ( xFreeRTOS_Socket_t * ) xSocket;
\r
259 /* The function prototype is designed to maintain the expected Berkeley
\r
260 sockets standard, but this implementation does not use all the parameters. */
\r
261 ( void ) pxSourceAddressLength;
\r
263 if( socketSOCKET_IS_BOUND( pxSocket ) != pdFALSE )
\r
265 /* The semaphore is given when received data is queued on the socket. */
\r
266 if( xSemaphoreTake( pxSocket->xWaitingPacketSemaphore, pxSocket->xReceiveBlockTime ) == pdPASS )
\r
268 taskENTER_CRITICAL();
\r
270 configASSERT( ( listCURRENT_LIST_LENGTH( &( pxSocket->xWaitingPacketsList ) ) > 0U ) );
\r
272 /* The owner of the list item is the network buffer. */
\r
273 pxNetworkBuffer = ( xNetworkBufferDescriptor_t * ) listGET_OWNER_OF_HEAD_ENTRY( &( pxSocket->xWaitingPacketsList ) );
\r
275 /* Remove the network buffer from the list of buffers waiting to
\r
276 be processed by the socket. */
\r
277 uxListRemove( &( pxNetworkBuffer->xBufferListItem ) );
\r
279 taskEXIT_CRITICAL();
\r
281 if( ( ulFlags & FREERTOS_ZERO_COPY ) == 0 )
\r
283 /* The zero copy flag is not set. Truncate the length if it
\r
284 won't fit in the provided buffer. */
\r
285 if( pxNetworkBuffer->xDataLength > xBufferLength )
\r
287 iptraceRECVFROM_DISCARDING_BYTES( ( xBufferLength - pxNetworkBuffer->xDataLength ) );
\r
288 pxNetworkBuffer->xDataLength = xBufferLength;
\r
291 /* Copy the received data into the provided buffer, then
\r
292 release the network buffer. */
\r
293 memcpy( pvBuffer, ( void * ) &( pxNetworkBuffer->pucEthernetBuffer[ ipUDP_PAYLOAD_OFFSET ] ), pxNetworkBuffer->xDataLength );
\r
294 vNetworkBufferRelease( pxNetworkBuffer );
\r
298 /* The zero copy flag was set. pvBuffer is not a buffer into
\r
299 which the received data can be copied, but a pointer that must
\r
300 be set to point to the buffer in which the received data has
\r
301 already been placed. */
\r
302 *( ( void** ) pvBuffer ) = ( void * ) ( &( pxNetworkBuffer->pucEthernetBuffer[ ipUDP_PAYLOAD_OFFSET ] ) );
\r
305 /* The returned value is the data length, which may have been
\r
306 capped to the receive buffer size. */
\r
307 lReturn = ( int32_t ) pxNetworkBuffer->xDataLength;
\r
309 if( pxSourceAddress != NULL )
\r
311 pxSourceAddress->sin_port = pxNetworkBuffer->usPort;
\r
312 pxSourceAddress->sin_addr = pxNetworkBuffer->ulIPAddress;
\r
317 lReturn = FREERTOS_EWOULDBLOCK;
\r
318 iptraceRECVFROM_TIMEOUT();
\r
323 lReturn = FREERTOS_EINVAL;
\r
328 /*-----------------------------------------------------------*/
\r
330 #if ipconfigCAN_FRAGMENT_OUTGOING_PACKETS == 1
\r
332 int32_t FreeRTOS_sendto( xSocket_t xSocket, const void *pvBuffer, size_t xTotalDataLength, uint32_t ulFlags, const struct freertos_sockaddr *pxDestinationAddress, socklen_t xDestinationAddressLength )
\r
334 xNetworkBufferDescriptor_t *pxNetworkBuffer;
\r
335 xIPFragmentParameters_t *pxFragmentParameters;
\r
336 size_t xBytesToSend, xBytesRemaining;
\r
337 xIPStackEvent_t xStackTxEvent = { eStackTxEvent, NULL };
\r
338 extern xQueueHandle xNetworkEventQueue;
\r
339 uint8_t *pucBuffer;
\r
340 xTimeOutType xTimeOut;
\r
341 portTickType xTicksToWait;
\r
342 uint16_t usFragmentOffset;
\r
343 xFreeRTOS_Socket_t *pxSocket;
\r
345 pxSocket = ( xFreeRTOS_Socket_t * ) xSocket;
\r
347 /* The function prototype is designed to maintain the expected Berkeley
\r
348 sockets standard, but this implementation does not use all the
\r
350 ( void ) xDestinationAddressLength;
\r
351 configASSERT( xNetworkEventQueue );
\r
352 configASSERT( pvBuffer );
\r
354 xBytesRemaining = xTotalDataLength;
\r
356 if( socketSOCKET_IS_BOUND( pxSocket ) == pdFALSE )
\r
358 /* If the socket is not already bound to an address, bind it now.
\r
359 Passing NULL as the address parameter tells FreeRTOS_bind() to select
\r
360 the address to bind to. */
\r
361 FreeRTOS_bind( xSocket, NULL, 0 );
\r
364 if( socketSOCKET_IS_BOUND( pxSocket ) != pdFALSE )
\r
366 /* pucBuffer will be reset if this send turns out to be a zero copy
\r
367 send because in that case pvBuffer is actually a pointer to an
\r
368 xUserData_t structure, not the UDP payload. */
\r
369 pucBuffer = ( uint8_t * ) pvBuffer;
\r
370 vTaskSetTimeOutState( &xTimeOut );
\r
371 xTicksToWait = pxSocket->xSendBlockTime;
\r
373 /* The data being transmitted will be sent in
\r
374 ipMAX_UDP_PAYLOAD_LENGTH chunks if xDataLength is greater than the
\r
375 network buffer payload size. Loop until all the data is sent. */
\r
376 while( xBytesRemaining > 0 )
\r
378 if( xBytesRemaining > ipMAX_UDP_PAYLOAD_LENGTH )
\r
380 /* Cap the amount being sent in this packet to the maximum
\r
381 UDP payload size. This will be a multiple of 8 already,
\r
382 removing the need to check in the code. */
\r
383 xBytesToSend = ipMAX_UDP_PAYLOAD_LENGTH;
\r
387 /* Send all remaining bytes - which may well be the total
\r
388 number of bytes if the packet was not chopped up. */
\r
389 xBytesToSend = xBytesRemaining;
\r
392 /* If the zero copy flag is set, then the data is already in a
\r
393 network buffer. Otherwise, get a new network buffer. */
\r
394 if( ( ulFlags & FREERTOS_ZERO_COPY ) == 0 )
\r
396 if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdTRUE )
\r
401 pxNetworkBuffer = pxNetworkBufferGet( xBytesToSend + sizeof( xUDPPacket_t ), xTicksToWait );
\r
405 if( xTotalDataLength > ipMAX_UDP_PAYLOAD_LENGTH )
\r
407 /* The packet needs fragmenting, but zero copy buffers
\r
408 cannot be fragmented. */
\r
409 pxNetworkBuffer = NULL;
\r
413 /* When zero copy is used, pvBuffer is a pointer to the
\r
414 payload of a buffer that has already been obtained from the
\r
415 stack. Obtain the network buffer pointer from the buffer. */
\r
416 pucBuffer = ( uint8_t * ) pvBuffer;
\r
417 pucBuffer -= ( ipBUFFER_PADDING + sizeof( xUDPPacket_t ) );
\r
418 pxNetworkBuffer = * ( ( xNetworkBufferDescriptor_t ** ) pucBuffer );
\r
422 if( pxNetworkBuffer != NULL )
\r
424 /* Use the part of the network buffer that will be completed
\r
425 by the IP layer as temporary storage to pass extra
\r
426 information required by the IP layer. */
\r
427 pxFragmentParameters = ( xIPFragmentParameters_t * ) &( pxNetworkBuffer->pucEthernetBuffer[ ipFRAGMENTATION_PARAMETERS_OFFSET ] );
\r
428 pxFragmentParameters->ucSocketOptions = pxSocket->ucSocketOptions;
\r
430 if( xBytesRemaining > ipMAX_UDP_PAYLOAD_LENGTH )
\r
432 /* The packet is being chopped up, and more data will
\r
434 pxFragmentParameters->ucSocketOptions = ( pxSocket->ucSocketOptions | FREERTOS_NOT_LAST_IN_FRAGMENTED_PACKET );
\r
437 if( xTotalDataLength > ipMAX_UDP_PAYLOAD_LENGTH )
\r
439 /* Let the IP layer know this packet has been chopped up,
\r
440 and supply the IP layer with any addition information it
\r
441 needs to make sense of it. */
\r
442 pxFragmentParameters->ucSocketOptions |= FREERTOS_FRAGMENTED_PACKET;
\r
443 usFragmentOffset = ( uint16_t ) ( xTotalDataLength - xBytesRemaining );
\r
444 pxFragmentParameters->usFragmentedPacketOffset = usFragmentOffset;
\r
445 pxFragmentParameters->usFragmentLength = ( uint16_t ) xBytesToSend;
\r
449 usFragmentOffset = 0;
\r
452 /* Write the payload into the packet. The IP layer is
\r
453 queried to find where in the IP payload the data should be
\r
454 written. This is because the necessary offset is different
\r
455 for the first packet, because the first packet leaves space
\r
456 for a UDP header. Note that this changes usFragmentOffset
\r
457 from the offset in the entire UDP packet, to the offset
\r
458 in the IP packet. */
\r
459 if( ( ulFlags & FREERTOS_ZERO_COPY ) == 0 )
\r
461 /* Only copy the data if it is not already in the
\r
462 expected location. */
\r
463 usFragmentOffset = ipGET_UDP_PAYLOAD_OFFSET_FOR_FRAGMENT( usFragmentOffset );
\r
464 memcpy( ( void * ) &( pxNetworkBuffer->pucEthernetBuffer[ usFragmentOffset ] ), ( void * ) pucBuffer, xBytesToSend );
\r
466 pxNetworkBuffer->xDataLength = xTotalDataLength;
\r
467 pxNetworkBuffer->usPort = pxDestinationAddress->sin_port;
\r
468 pxNetworkBuffer->usBoundPort = ( uint16_t ) socketGET_SOCKET_ADDRESS( pxSocket );
\r
469 pxNetworkBuffer->ulIPAddress = pxDestinationAddress->sin_addr;
\r
471 /* Tell the networking task that the packet needs sending. */
\r
472 xStackTxEvent.pvData = pxNetworkBuffer;
\r
474 if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdTRUE )
\r
479 if( xQueueSendToBack( xNetworkEventQueue, &xStackTxEvent, xTicksToWait ) != pdPASS )
\r
481 /* If the buffer was allocated in this function, release it. */
\r
482 if( ( ulFlags & FREERTOS_ZERO_COPY ) == 0 )
\r
484 vNetworkBufferRelease( pxNetworkBuffer );
\r
486 iptraceSTACK_TX_EVENT_LOST( ipSTACK_TX_EVENT );
\r
490 /* Adjust counters ready to either exit the loop, or send
\r
491 another chunk of data. */
\r
492 xBytesRemaining -= xBytesToSend;
\r
493 pucBuffer += xBytesToSend;
\r
497 /* If errno was available, errno would be set to
\r
498 FREERTOS_ENOPKTS. As it is, the function must return the
\r
499 number of transmitted bytes, so the calling function knows how
\r
500 much data was actually sent. */
\r
506 return ( xTotalDataLength - xBytesRemaining );
\r
509 #else /* ipconfigCAN_FRAGMENT_OUTGOING_PACKETS */
\r
511 int32_t FreeRTOS_sendto( xSocket_t xSocket, const void *pvBuffer, size_t xTotalDataLength, uint32_t ulFlags, const struct freertos_sockaddr *pxDestinationAddress, socklen_t xDestinationAddressLength )
\r
513 xNetworkBufferDescriptor_t *pxNetworkBuffer;
\r
514 xIPStackEvent_t xStackTxEvent = { eStackTxEvent, NULL };
\r
515 extern xQueueHandle xNetworkEventQueue;
\r
516 xTimeOutType xTimeOut;
\r
517 portTickType xTicksToWait;
\r
518 int32_t lReturn = 0;
\r
519 xFreeRTOS_Socket_t *pxSocket;
\r
520 uint8_t *pucBuffer;
\r
522 pxSocket = ( xFreeRTOS_Socket_t * ) xSocket;
\r
524 /* The function prototype is designed to maintain the expected Berkeley
\r
525 sockets standard, but this implementation does not use all the
\r
527 ( void ) xDestinationAddressLength;
\r
528 configASSERT( xNetworkEventQueue );
\r
529 configASSERT( pvBuffer );
\r
531 if( xTotalDataLength <= ipMAX_UDP_PAYLOAD_LENGTH )
\r
533 if( socketSOCKET_IS_BOUND( pxSocket ) == pdFALSE )
\r
535 /* If the socket is not already bound to an address, bind it now.
\r
536 Passing NULL as the address parameter tells FreeRTOS_bind() to
\r
537 select the address to bind to. */
\r
538 FreeRTOS_bind( pxSocket, NULL, 0 );
\r
541 if( socketSOCKET_IS_BOUND( pxSocket ) != pdFALSE )
\r
543 xTicksToWait = pxSocket->xSendBlockTime;
\r
545 if( ( ulFlags & FREERTOS_ZERO_COPY ) == 0 )
\r
547 /* Zero copy is not set, so obtain a network buffer into
\r
548 which the payload will be copied. */
\r
549 vTaskSetTimeOutState( &xTimeOut );
\r
550 pxNetworkBuffer = pxNetworkBufferGet( xTotalDataLength + sizeof( xUDPPacket_t ), xTicksToWait );
\r
552 if( pxNetworkBuffer != NULL )
\r
554 memcpy( ( void * ) &( pxNetworkBuffer->pucEthernetBuffer[ ipUDP_PAYLOAD_OFFSET ] ), ( void * ) pvBuffer, xTotalDataLength );
\r
556 if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdTRUE )
\r
558 /* The entire block time has been used up. */
\r
565 /* When zero copy is used, pvBuffer is a pointer to the
\r
566 payload of a buffer that has already been obtained from the
\r
567 stack. Obtain the network buffer pointer from the buffer. */
\r
568 pucBuffer = ( uint8_t * ) pvBuffer;
\r
569 pucBuffer -= ( ipBUFFER_PADDING + sizeof( xUDPPacket_t ) );
\r
570 pxNetworkBuffer = * ( ( xNetworkBufferDescriptor_t ** ) pucBuffer );
\r
573 if( pxNetworkBuffer != NULL )
\r
575 pxNetworkBuffer->xDataLength = xTotalDataLength;
\r
576 pxNetworkBuffer->usPort = pxDestinationAddress->sin_port;
\r
577 pxNetworkBuffer->usBoundPort = ( uint16_t ) socketGET_SOCKET_ADDRESS( pxSocket );
\r
578 pxNetworkBuffer->ulIPAddress = pxDestinationAddress->sin_addr;
\r
580 /* The socket options are passed to the IP layer in the
\r
581 space that will eventually get used by the Ethernet header. */
\r
582 pxNetworkBuffer->pucEthernetBuffer[ ipSOCKET_OPTIONS_OFFSET ] = pxSocket->ucSocketOptions;
\r
584 /* Tell the networking task that the packet needs sending. */
\r
585 xStackTxEvent.pvData = pxNetworkBuffer;
\r
587 if( xQueueSendToBack( xNetworkEventQueue, &xStackTxEvent, xTicksToWait ) != pdPASS )
\r
589 /* If the buffer was allocated in this function, release it. */
\r
590 if( ( ulFlags & FREERTOS_ZERO_COPY ) == 0 )
\r
592 vNetworkBufferRelease( pxNetworkBuffer );
\r
594 iptraceSTACK_TX_EVENT_LOST( ipSTACK_TX_EVENT );
\r
598 lReturn = ( int32_t ) xTotalDataLength;
\r
603 /* If errno was available, errno would be set to
\r
604 FREERTOS_ENOPKTS. As it is, the function must return the
\r
605 number of transmitted bytes, so the calling function knows how
\r
606 much data was actually sent. */
\r
607 iptraceNO_BUFFER_FOR_SENDTO();
\r
612 iptraceSENDTO_SOCKET_NOT_BOUND();
\r
617 /* The data is longer than the available buffer space. Setting
\r
618 ipconfigCAN_FRAGMENT_OUTGOING_PACKETS to 1 may allow this packet
\r
620 iptraceSENDTO_DATA_TOO_LONG();
\r
626 #endif /* ipconfigCAN_FRAGMENT_OUTGOING_PACKETS */
\r
627 /*-----------------------------------------------------------*/
\r
629 portBASE_TYPE FreeRTOS_bind( xSocket_t xSocket, struct freertos_sockaddr * pxAddress, socklen_t xAddressLength )
\r
631 portBASE_TYPE xReturn = 0; /* In Berkeley sockets, 0 means pass for bind(). */
\r
632 xFreeRTOS_Socket_t *pxSocket;
\r
633 #if ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND == 1
\r
634 struct freertos_sockaddr xAddress;
\r
635 #endif /* ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND */
\r
637 pxSocket = ( xFreeRTOS_Socket_t * ) xSocket;
\r
639 /* The function prototype is designed to maintain the expected Berkeley
\r
640 sockets standard, but this implementation does not use all the parameters. */
\r
641 ( void ) xAddressLength;
\r
643 configASSERT( xSocket );
\r
644 configASSERT( xSocket != FREERTOS_INVALID_SOCKET );
\r
646 #if ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND == 1
\r
648 /* pxAddress will be NULL if sendto() was called on a socket without the
\r
649 socket being bound to an address. In this case, automatically allocate
\r
650 an address to the socket. There is a very tiny chance that the allocated
\r
651 port will already be in use - if that is the case, then the check below
\r
652 [pxListFindListItemWithValue()] will result in an error being returned. */
\r
653 if( pxAddress == NULL )
\r
655 pxAddress = &xAddress;
\r
656 pxAddress->sin_port = prvGetPrivatePortNumber();
\r
659 #endif /* ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND == 1 */
\r
661 /* Sockets must be bound before calling FreeRTOS_sendto() if
\r
662 ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND is not set to 1. */
\r
663 configASSERT( pxAddress );
\r
665 if( pxAddress != NULL )
\r
667 if( pxAddress->sin_port == 0 )
\r
669 pxAddress->sin_port = prvGetPrivatePortNumber();
\r
674 /* Check to ensure the port is not already in use. */
\r
675 if( pxListFindListItemWithValue( &xBoundSocketsList, ( portTickType ) pxAddress->sin_port ) != NULL )
\r
677 xReturn = FREERTOS_EADDRINUSE;
\r
682 /* Check that xReturn has not been set before continuing. */
\r
685 if( pxSocket->xWaitingPacketSemaphore == NULL )
\r
687 /* Create the semaphore used to count the number of packets that
\r
688 are queued on this socket. */
\r
689 pxSocket->xWaitingPacketSemaphore = xSemaphoreCreateCounting( ipconfigNUM_NETWORK_BUFFERS, 0 );
\r
691 if( pxSocket->xWaitingPacketSemaphore != NULL )
\r
693 /* Allocate the port number to the socket. */
\r
694 socketSET_SOCKET_ADDRESS( pxSocket, pxAddress->sin_port );
\r
695 taskENTER_CRITICAL();
\r
697 /* Add the socket to the list of bound ports. */
\r
698 vListInsertEnd( &xBoundSocketsList, &( pxSocket->xBoundSocketListItem ) );
\r
700 taskEXIT_CRITICAL();
\r
704 /* Out of memory. */
\r
705 xReturn = FREERTOS_ENOBUFS;
\r
710 /* The socket is already bound. */
\r
711 xReturn = FREERTOS_EINVAL;
\r
717 xReturn = FREERTOS_EADDRNOTAVAIL;
\r
722 iptraceBIND_FAILED( xSocket, ( FreeRTOS_ntohs( pxAddress->sin_port ) ) );
\r
727 /*-----------------------------------------------------------*/
\r
729 portBASE_TYPE FreeRTOS_closesocket( xSocket_t xSocket )
\r
731 xNetworkBufferDescriptor_t *pxNetworkBuffer;
\r
732 xFreeRTOS_Socket_t *pxSocket;
\r
734 pxSocket = ( xFreeRTOS_Socket_t * ) xSocket;
\r
736 configASSERT( pxSocket );
\r
737 configASSERT( pxSocket != FREERTOS_INVALID_SOCKET );
\r
739 /* Socket must be unbound first, to ensure no more packets are queued on
\r
741 if( socketSOCKET_IS_BOUND( pxSocket ) != pdFALSE )
\r
743 taskENTER_CRITICAL();
\r
745 uxListRemove( &( pxSocket->xBoundSocketListItem ) );
\r
747 taskEXIT_CRITICAL();
\r
750 /* Now the socket is not bound the list of waiting packets can be
\r
752 if( pxSocket->xWaitingPacketSemaphore != NULL )
\r
754 while( listCURRENT_LIST_LENGTH( &( pxSocket->xWaitingPacketsList ) ) > 0U )
\r
756 pxNetworkBuffer = ( xNetworkBufferDescriptor_t * ) listGET_OWNER_OF_HEAD_ENTRY( &( pxSocket->xWaitingPacketsList ) );
\r
757 uxListRemove( &( pxNetworkBuffer->xBufferListItem ) );
\r
758 vNetworkBufferRelease( pxNetworkBuffer );
\r
760 vSemaphoreDelete( pxSocket->xWaitingPacketSemaphore );
\r
763 vPortFree( pxSocket );
\r
767 /*-----------------------------------------------------------*/
\r
769 void FreeRTOS_SocketsInit( void )
\r
771 vListInitialise( &xBoundSocketsList );
\r
773 /*-----------------------------------------------------------*/
\r
775 portBASE_TYPE FreeRTOS_setsockopt( xSocket_t xSocket, int32_t lLevel, int32_t lOptionName, const void *pvOptionValue, size_t xOptionLength )
\r
777 /* The standard Berkeley function returns 0 for success. */
\r
778 portBASE_TYPE xReturn = 0;
\r
779 portBASE_TYPE lOptionValue;
\r
780 xFreeRTOS_Socket_t *pxSocket;
\r
782 pxSocket = ( xFreeRTOS_Socket_t * ) xSocket;
\r
784 /* The function prototype is designed to maintain the expected Berkeley
\r
785 sockets standard, but this implementation does not use all the parameters. */
\r
787 ( void ) xOptionLength;
\r
789 configASSERT( xSocket );
\r
791 switch( lOptionName )
\r
793 case FREERTOS_SO_RCVTIMEO :
\r
794 /* Receive time out. */
\r
795 pxSocket->xReceiveBlockTime = *( ( portTickType * ) pvOptionValue );
\r
798 case FREERTOS_SO_SNDTIMEO :
\r
799 /* The send time out is capped for the reason stated in the comments
\r
800 where ipconfigMAX_SEND_BLOCK_TIME_TICKS is defined in
\r
801 FreeRTOSIPConfig.h (assuming an official configuration file is being
\r
803 pxSocket->xSendBlockTime = *( ( portTickType * ) pvOptionValue );
\r
804 if( pxSocket->xSendBlockTime > ipconfigMAX_SEND_BLOCK_TIME_TICKS )
\r
806 pxSocket->xSendBlockTime = ipconfigMAX_SEND_BLOCK_TIME_TICKS;
\r
810 case FREERTOS_SO_UDPCKSUM_OUT :
\r
811 /* Turn calculating of the UDP checksum on/off for this socket. */
\r
812 lOptionValue = ( portBASE_TYPE ) pvOptionValue;
\r
814 if( lOptionValue == 0 )
\r
816 pxSocket->ucSocketOptions &= ~FREERTOS_SO_UDPCKSUM_OUT;
\r
820 pxSocket->ucSocketOptions |= FREERTOS_SO_UDPCKSUM_OUT;
\r
825 /* No other options are handled. */
\r
826 xReturn = FREERTOS_ENOPROTOOPT;
\r
832 /*-----------------------------------------------------------*/
\r
834 portBASE_TYPE xProcessReceivedUDPPacket( xNetworkBufferDescriptor_t *pxNetworkBuffer, uint16_t usPort )
\r
836 xListItem *pxListItem;
\r
837 portBASE_TYPE xReturn = pdPASS;
\r
838 xFreeRTOS_Socket_t *pxSocket;
\r
839 portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
\r
843 /* See if there is a list item associated with the port number on the
\r
844 list of bound sockets. */
\r
845 pxListItem = pxListFindListItemWithValue( &xBoundSocketsList, ( portTickType ) usPort );
\r
849 if( pxListItem != NULL )
\r
851 /* The owner of the list item is the socket itself. */
\r
852 pxSocket = ( xFreeRTOS_Socket_t * ) listGET_LIST_ITEM_OWNER( pxListItem );
\r
856 #if( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
\r
858 /* Is the socket a member of a select() group? */
\r
859 if( pxSocket->xSelectQueue != NULL )
\r
861 /* Can the select group be notified that the socket is
\r
862 ready to be read? */
\r
863 if( xQueueSendFromISR( pxSocket->xSelectQueue, &pxSocket, &xHigherPriorityTaskWoken ) != pdPASS )
\r
865 /* Could not notify the select group. */
\r
867 iptraceFAILED_TO_NOTIFY_SELECT_GROUP( pxSocket );
\r
873 if( xReturn == pdPASS )
\r
875 taskENTER_CRITICAL();
\r
877 /* Add the network packet to the list of packets to be
\r
878 processed by the socket. */
\r
879 vListInsertEnd( &( pxSocket->xWaitingPacketsList ), &( pxNetworkBuffer->xBufferListItem ) );
\r
881 taskEXIT_CRITICAL();
\r
883 /* The socket's counting semaphore records how many packets are
\r
884 waiting to be processed by the socket. */
\r
885 xSemaphoreGiveFromISR( pxSocket->xWaitingPacketSemaphore, &xHigherPriorityTaskWoken );
\r
888 if( xTaskResumeAll() == pdFALSE )
\r
890 if( xHigherPriorityTaskWoken != pdFALSE )
\r
903 /*-----------------------------------------------------------*/
\r
905 static uint16_t prvGetPrivatePortNumber( void )
\r
907 static uint16_t usNextPortToUse = socketAUTO_PORT_ALLOCATION_START_NUMBER - 1;
\r
910 /* Assign the next port in the range. */
\r
911 taskENTER_CRITICAL();
\r
913 taskEXIT_CRITICAL();
\r
915 /* Has it overflowed? */
\r
916 if( usNextPortToUse == 0U )
\r
918 /* Don't go right back to the start of the dynamic/private port
\r
919 range numbers as any persistent sockets are likely to have been
\r
920 create first so the early port numbers may still be in use. */
\r
921 usNextPortToUse = socketAUTO_PORT_ALLOCATION_RESET_NUMBER;
\r
924 usReturn = FreeRTOS_htons( usNextPortToUse );
\r
928 /*-----------------------------------------------------------*/
\r
930 xListItem * pxListFindListItemWithValue( xList *pxList, portTickType xWantedItemValue )
\r
932 xListItem *pxIterator, *pxReturn;
\r
935 for( pxIterator = ( xListItem * ) pxList->xListEnd.pxNext; pxIterator != ( xListItem* ) &( pxList->xListEnd ); pxIterator = ( xListItem * ) pxIterator->pxNext )
\r
937 if( pxIterator->xItemValue == xWantedItemValue )
\r
939 pxReturn = pxIterator;
\r
946 /*-----------------------------------------------------------*/
\r
948 #if ipconfigINCLUDE_FULL_INET_ADDR == 1
\r
950 uint32_t FreeRTOS_inet_addr( const uint8_t * pucIPAddress )
\r
952 const uint8_t ucDecimalBase = 10;
\r
953 uint8_t ucOctet[ socketMAX_IP_ADDRESS_OCTETS ];
\r
954 const uint8_t *pucPointerOnEntering;
\r
955 uint32_t ulReturn = 0UL, ulOctetNumber, ulValue;
\r
956 portBASE_TYPE xResult = pdPASS;
\r
958 for( ulOctetNumber = 0; ulOctetNumber < socketMAX_IP_ADDRESS_OCTETS; ulOctetNumber++ )
\r
961 pucPointerOnEntering = pucIPAddress;
\r
963 while( ( *pucIPAddress >= ( uint8_t ) '0' ) && ( *pucIPAddress <= ( uint8_t ) '9' ) )
\r
965 /* Move previous read characters into the next decimal
\r
967 ulValue *= ucDecimalBase;
\r
969 /* Add the binary value of the ascii character. */
\r
970 ulValue += ( *pucIPAddress - ( uint8_t ) '0' );
\r
972 /* Move to next character in the string. */
\r
976 /* Check characters were read. */
\r
977 if( pucIPAddress == pucPointerOnEntering )
\r
982 /* Check the value fits in an 8-bit number. */
\r
983 if( ulValue > 0xffUL )
\r
989 ucOctet[ ulOctetNumber ] = ( uint8_t ) ulValue;
\r
991 /* Check the next character is as expected. */
\r
992 if( ulOctetNumber < ( socketMAX_IP_ADDRESS_OCTETS - 1 ) )
\r
994 if( *pucIPAddress != ( uint8_t ) '.' )
\r
1000 /* Move past the dot. */
\r
1006 if( xResult == pdFAIL )
\r
1008 /* No point going on. */
\r
1013 if( *pucIPAddress != ( uint8_t ) 0x00 )
\r
1015 /* Expected the end of the string. */
\r
1019 if( ulOctetNumber != socketMAX_IP_ADDRESS_OCTETS )
\r
1021 /* Didn't read enough octets. */
\r
1025 if( xResult == pdPASS )
\r
1027 ulReturn = FreeRTOS_inet_addr_quick( ucOctet[ 0 ], ucOctet[ 1 ], ucOctet[ 2 ], ucOctet[ 3 ] );
\r
1033 #endif /* ipconfigINCLUDE_FULL_INET_ADDR */
\r
1034 /*-----------------------------------------------------------*/
\r