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 pure GPL open source license (as opposed to the modified GPL license
\r
9 * under which FreeRTOS is distributed) or a commercial license. Details of
\r
10 * both license options follow:
\r
12 * - Open source licensing -
\r
13 * FreeRTOS+UDP is a free download and may be used, modified, evaluated and
\r
14 * distributed without charge provided the user adheres to version two of the
\r
15 * GNU General Public License (GPL) and does not remove the copyright notice or
\r
16 * this text. The GPL V2 text is available on the gnu.org web site, and on the
\r
17 * following URL: http://www.FreeRTOS.org/gpl-2.0.txt.
\r
19 * - Commercial licensing -
\r
20 * Businesses and individuals that for commercial or other reasons cannot comply
\r
21 * with the terms of the GPL V2 license must obtain a commercial license before
\r
22 * incorporating FreeRTOS+UDP into proprietary software for distribution in any
\r
23 * form. Commercial licenses can be purchased from http://shop.freertos.org/udp
\r
24 * and do not require any source files to be changed.
\r
26 * FreeRTOS+UDP is distributed in the hope that it will be useful. You cannot
\r
27 * use FreeRTOS+UDP unless you agree that you use the software 'as is'.
\r
28 * FreeRTOS+UDP is provided WITHOUT ANY WARRANTY; without even the implied
\r
29 * warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR
\r
30 * PURPOSE. Real Time Engineers Ltd. disclaims all conditions and terms, be they
\r
31 * implied, expressed, or statutory.
\r
33 * 1 tab == 4 spaces!
\r
35 * http://www.FreeRTOS.org
\r
36 * http://www.FreeRTOS.org/udp
\r
40 /* Standard includes. */
\r
43 /* FreeRTOS includes. */
\r
44 #include "FreeRTOS.h"
\r
49 /* FreeRTOS+UDP includes. */
\r
50 #include "FreeRTOS_UDP_IP.h"
\r
51 #include "FreeRTOS_IP_Private.h"
\r
52 #include "FreeRTOS_Sockets.h"
\r
53 #include "NetworkBufferManagement.h"
\r
55 /* Sanity check the UDP payload length setting is compatible with the
\r
56 fragmentation setting. */
\r
57 #if ipconfigCAN_FRAGMENT_OUTGOING_PACKETS == 1
\r
58 #if ( ( ipMAX_UDP_PAYLOAD_LENGTH % 8 ) != 0 )
\r
59 #error ( ipconfigNETWORK_MTU - 28 ) must be divisible by 8 when fragmentation is used
\r
60 #endif /* ipMAX_UDP_PAYLOAD_LENGTH */
\r
61 #endif /* ipconfigFRAGMENT_OUTGOING_PACKETS */
\r
63 /* The ItemValue of the sockets xBoundSocketListItem member holds the socket's
\r
65 #define socketSET_SOCKET_ADDRESS( pxSocket, usPort ) listSET_LIST_ITEM_VALUE( ( &( ( pxSocket )->xBoundSocketListItem ) ), ( usPort ) )
\r
66 #define socketGET_SOCKET_ADDRESS( pxSocket ) listGET_LIST_ITEM_VALUE( ( &( ( pxSocket )->xBoundSocketListItem ) ) )
\r
68 /* xWaitingPacketSemaphore is not created until the socket is bound, so can be
\r
69 tested to see if bind() has been called. */
\r
70 #define socketSOCKET_IS_BOUND( pxSocket ) ( ( uint32_t ) pxSocket->xWaitingPacketSemaphore )
\r
72 /* If FreeRTOS_sendto() is called on a socket that is not bound to a port
\r
73 number then, depending on the FreeRTOSIPConfig.h settings, it might be that a
\r
74 port number is automatically generated for the socket. Automatically generated
\r
75 port numbers will be between socketAUTO_PORT_ALLOCATION_START_NUMBER and
\r
77 #define socketAUTO_PORT_ALLOCATION_START_NUMBER ( ( uint16_t ) 0xc000 )
\r
79 /* When the automatically generated port numbers overflow, the next value used
\r
80 is not set back to socketAUTO_PORT_ALLOCATION_START_NUMBER because it is likely
\r
81 that the first few automatically generated ports will still be in use. Instead
\r
82 it is reset back to the value defined by this constant. */
\r
83 #define socketAUTO_PORT_ALLOCATION_RESET_NUMBER ( ( uint16_t ) 0xc100 )
\r
85 /* The number of octets that make up an IP address. */
\r
86 #define socketMAX_IP_ADDRESS_OCTETS 4
\r
87 /*-----------------------------------------------------------*/
\r
90 * Allocate the next port number from the private allocation range.
\r
92 static uint16_t prvGetPrivatePortNumber( void );
\r
95 * Return the list itme from within pxList that has an item value of
\r
96 * xWantedItemValue. If there is no such list item return NULL.
\r
98 xListItem * pxListFindListItemWithValue( xList *pxList, portTickType xWantedItemValue );
\r
100 /*-----------------------------------------------------------*/
\r
102 typedef struct XSOCKET
\r
104 xSemaphoreHandle xWaitingPacketSemaphore;
\r
105 xList xWaitingPacketsList;
\r
106 xListItem xBoundSocketListItem; /* Used to reference the socket from a bound sockets list. */
\r
107 portTickType xReceiveBlockTime;
\r
108 portTickType xSendBlockTime;
\r
109 uint8_t ucSocketOptions;
\r
110 #if ipconfigSUPPORT_SELECT_FUNCTION == 1
\r
111 xQueueHandle xSelectQueue;
\r
113 } xFreeRTOS_Socket_t;
\r
116 /* The list that contains mappings between sockets and port numbers. Accesses
\r
117 to this list must be protected by critical sections of one kind or another. */
\r
118 static xList xBoundSocketsList;
\r
120 /*-----------------------------------------------------------*/
\r
122 xSocket_t FreeRTOS_socket( portBASE_TYPE xDomain, portBASE_TYPE xType, portBASE_TYPE xProtocol )
\r
124 xFreeRTOS_Socket_t *pxSocket;
\r
126 /* Only UDP on Ethernet is currently supported. */
\r
127 configASSERT( xDomain == FREERTOS_AF_INET );
\r
128 configASSERT( xType == FREERTOS_SOCK_DGRAM );
\r
129 configASSERT( xProtocol == FREERTOS_IPPROTO_UDP );
\r
130 configASSERT( listLIST_IS_INITIALISED( &xBoundSocketsList ) );
\r
132 /* Allocate the structure that will hold the socket information. */
\r
133 pxSocket = ( xFreeRTOS_Socket_t * ) pvPortMalloc( sizeof( xFreeRTOS_Socket_t ) );
\r
135 if( pxSocket == NULL )
\r
137 pxSocket = ( xFreeRTOS_Socket_t * ) FREERTOS_INVALID_SOCKET;
\r
138 iptraceFAILED_TO_CREATE_SOCKET();
\r
142 /* Initialise the socket's members. The semaphore will be created if
\r
143 the socket is bound to an address, for now the pointer to the semaphore
\r
144 is just set to NULL to show it has not been created. */
\r
145 pxSocket->xWaitingPacketSemaphore = NULL;
\r
146 vListInitialise( &( pxSocket->xWaitingPacketsList ) );
\r
147 vListInitialiseItem( &( pxSocket->xBoundSocketListItem ) );
\r
148 listSET_LIST_ITEM_OWNER( &( pxSocket->xBoundSocketListItem ), ( void * ) pxSocket );
\r
149 pxSocket->xSendBlockTime = ( portTickType ) 0;
\r
150 pxSocket->xReceiveBlockTime = portMAX_DELAY;
\r
151 pxSocket->ucSocketOptions = FREERTOS_SO_UDPCKSUM_OUT;
\r
152 #if ipconfigSUPPORT_SELECT_FUNCTION == 1
\r
153 pxSocket->xSelectQueue = NULL;
\r
157 /* Remove compiler warnings in the case the configASSERT() is not defined. */
\r
160 ( void ) xProtocol;
\r
162 return ( xSocket_t ) pxSocket;
\r
164 /*-----------------------------------------------------------*/
\r
166 #if ipconfigSUPPORT_SELECT_FUNCTION == 1
\r
168 xSocketSet_t FreeRTOS_CreateSocketSet( unsigned portBASE_TYPE uxEventQueueLength )
\r
170 xQueueHandle xSelectQueue;
\r
172 /* Create the queue into which the address of sockets that are
\r
173 available to read are posted. */
\r
174 xSelectQueue = xQueueCreate( uxEventQueueLength, sizeof( xSocket_t ) );
\r
176 return ( xSocketSet_t ) xSelectQueue;
\r
179 #endif /* ipconfigSUPPORT_SELECT_FUNCTION */
\r
180 /*-----------------------------------------------------------*/
\r
182 #if ipconfigSUPPORT_SELECT_FUNCTION == 1
\r
184 portBASE_TYPE FreeRTOS_FD_SET( xSocket_t xSocket, xSocketSet_t xSocketSet )
\r
186 xFreeRTOS_Socket_t *pxSocket = ( xFreeRTOS_Socket_t * ) xSocket;
\r
187 portBASE_TYPE xReturn;
\r
189 /* Is the socket already a member of a select group? */
\r
190 if( pxSocket->xSelectQueue == NULL )
\r
192 /* Store a pointer to the select group in the socket for future
\r
194 pxSocket->xSelectQueue = ( xQueueHandle ) xSocketSet;
\r
199 /* The socket is already a member of a select group so cannot be added
\r
207 #endif /* ipconfigSUPPORT_SELECT_FUNCTION */
\r
208 /*-----------------------------------------------------------*/
\r
210 #if ipconfigSUPPORT_SELECT_FUNCTION == 1
\r
212 portBASE_TYPE FreeRTOS_FD_CLR( xSocket_t xSocket, xSocketSet_t xSocketSet )
\r
214 xFreeRTOS_Socket_t *pxSocket = ( xFreeRTOS_Socket_t * ) xSocket;
\r
215 portBASE_TYPE xReturn;
\r
217 /* Is the socket a member of the select group? */
\r
218 if( pxSocket->xSelectQueue == ( xQueueHandle ) xSocketSet )
\r
220 /* The socket is no longer a member of the select group. */
\r
221 pxSocket->xSelectQueue = NULL;
\r
232 #endif /* ipconfigSUPPORT_SELECT_FUNCTION */
\r
233 /*-----------------------------------------------------------*/
\r
235 #if ipconfigSUPPORT_SELECT_FUNCTION == 1
\r
237 xSocket_t FreeRTOS_select( xSocketSet_t xSocketSet, portTickType xBlockTimeTicks )
\r
239 xFreeRTOS_Socket_t *pxSocket;
\r
241 /* Wait for a socket to be ready to read. */
\r
242 if( xQueueReceive( ( xQueueHandle ) xSocketSet, &pxSocket, xBlockTimeTicks ) != pdPASS )
\r
247 return ( xSocket_t ) pxSocket;
\r
250 #endif /* ipconfigSUPPORT_SELECT_FUNCTION */
\r
251 /*-----------------------------------------------------------*/
\r
253 int32_t FreeRTOS_recvfrom( xSocket_t xSocket, void *pvBuffer, size_t xBufferLength, uint32_t ulFlags, struct freertos_sockaddr *pxSourceAddress, socklen_t *pxSourceAddressLength )
\r
255 xNetworkBufferDescriptor_t *pxNetworkBuffer;
\r
257 xFreeRTOS_Socket_t *pxSocket;
\r
259 pxSocket = ( xFreeRTOS_Socket_t * ) xSocket;
\r
261 /* The function prototype is designed to maintain the expected Berkeley
\r
262 sockets standard, but this implementation does not use all the parameters. */
\r
263 ( void ) pxSourceAddressLength;
\r
265 if( socketSOCKET_IS_BOUND( pxSocket ) != pdFALSE )
\r
267 /* The semaphore is given when received data is queued on the socket. */
\r
268 if( xSemaphoreTake( pxSocket->xWaitingPacketSemaphore, pxSocket->xReceiveBlockTime ) == pdPASS )
\r
270 taskENTER_CRITICAL();
\r
272 configASSERT( ( listCURRENT_LIST_LENGTH( &( pxSocket->xWaitingPacketsList ) ) > 0U ) );
\r
274 /* The owner of the list item is the network buffer. */
\r
275 pxNetworkBuffer = ( xNetworkBufferDescriptor_t * ) listGET_OWNER_OF_HEAD_ENTRY( &( pxSocket->xWaitingPacketsList ) );
\r
277 /* Remove the network buffer from the list of buffers waiting to
\r
278 be processed by the socket. */
\r
279 uxListRemove( &( pxNetworkBuffer->xBufferListItem ) );
\r
281 taskEXIT_CRITICAL();
\r
283 if( ( ulFlags & FREERTOS_ZERO_COPY ) == 0 )
\r
285 /* The zero copy flag is not set. Truncate the length if it
\r
286 won't fit in the provided buffer. */
\r
287 if( pxNetworkBuffer->xDataLength > xBufferLength )
\r
289 iptraceRECVFROM_DISCARDING_BYTES( ( xBufferLength - pxNetworkBuffer->xDataLength ) );
\r
290 pxNetworkBuffer->xDataLength = xBufferLength;
\r
293 /* Copy the received data into the provided buffer, then
\r
294 release the network buffer. */
\r
295 memcpy( pvBuffer, ( void * ) &( pxNetworkBuffer->pucEthernetBuffer[ ipUDP_PAYLOAD_OFFSET ] ), pxNetworkBuffer->xDataLength );
\r
296 vNetworkBufferRelease( pxNetworkBuffer );
\r
300 /* The zero copy flag was set. pvBuffer is not a buffer into
\r
301 which the received data can be copied, but a pointer that must
\r
302 be set to point to the buffer in which the received data has
\r
303 already been placed. */
\r
304 *( ( void** ) pvBuffer ) = ( void * ) ( &( pxNetworkBuffer->pucEthernetBuffer[ ipUDP_PAYLOAD_OFFSET ] ) );
\r
307 /* The returned value is the data length, which may have been
\r
308 capped to the receive buffer size. */
\r
309 lReturn = ( int32_t ) pxNetworkBuffer->xDataLength;
\r
311 if( pxSourceAddress != NULL )
\r
313 pxSourceAddress->sin_port = pxNetworkBuffer->usPort;
\r
314 pxSourceAddress->sin_addr = pxNetworkBuffer->ulIPAddress;
\r
319 lReturn = FREERTOS_EWOULDBLOCK;
\r
320 iptraceRECVFROM_TIMEOUT();
\r
325 lReturn = FREERTOS_EINVAL;
\r
330 /*-----------------------------------------------------------*/
\r
332 #if ipconfigCAN_FRAGMENT_OUTGOING_PACKETS == 1
\r
334 int32_t FreeRTOS_sendto( xSocket_t xSocket, const void *pvBuffer, size_t xTotalDataLength, uint32_t ulFlags, const struct freertos_sockaddr *pxDestinationAddress, socklen_t xDestinationAddressLength )
\r
336 xNetworkBufferDescriptor_t *pxNetworkBuffer;
\r
337 xIPFragmentParameters_t *pxFragmentParameters;
\r
338 size_t xBytesToSend, xBytesRemaining;
\r
339 xIPStackEvent_t xStackTxEvent = { eStackTxEvent, NULL };
\r
340 extern xQueueHandle xNetworkEventQueue;
\r
341 uint8_t *pucBuffer;
\r
342 xTimeOutType xTimeOut;
\r
343 portTickType xTicksToWait;
\r
344 uint16_t usFragmentOffset;
\r
345 xFreeRTOS_Socket_t *pxSocket;
\r
347 pxSocket = ( xFreeRTOS_Socket_t * ) xSocket;
\r
349 /* The function prototype is designed to maintain the expected Berkeley
\r
350 sockets standard, but this implementation does not use all the
\r
352 ( void ) xDestinationAddressLength;
\r
353 configASSERT( xNetworkEventQueue );
\r
354 configASSERT( pvBuffer );
\r
356 xBytesRemaining = xTotalDataLength;
\r
358 if( socketSOCKET_IS_BOUND( pxSocket ) == pdFALSE )
\r
360 /* If the socket is not already bound to an address, bind it now.
\r
361 Passing NULL as the address parameter tells FreeRTOS_bind() to select
\r
362 the address to bind to. */
\r
363 FreeRTOS_bind( xSocket, NULL, 0 );
\r
366 if( socketSOCKET_IS_BOUND( pxSocket ) != pdFALSE )
\r
368 /* pucBuffer will be reset if this send turns out to be a zero copy
\r
369 send because in that case pvBuffer is actually a pointer to an
\r
370 xUserData_t structure, not the UDP payload. */
\r
371 pucBuffer = ( uint8_t * ) pvBuffer;
\r
372 vTaskSetTimeOutState( &xTimeOut );
\r
373 xTicksToWait = pxSocket->xSendBlockTime;
\r
375 /* The data being transmitted will be sent in
\r
376 ipMAX_UDP_PAYLOAD_LENGTH chunks if xDataLength is greater than the
\r
377 network buffer payload size. Loop until all the data is sent. */
\r
378 while( xBytesRemaining > 0 )
\r
380 if( xBytesRemaining > ipMAX_UDP_PAYLOAD_LENGTH )
\r
382 /* Cap the amount being sent in this packet to the maximum
\r
383 UDP payload size. This will be a multiple of 8 already,
\r
384 removing the need to check in the code. */
\r
385 xBytesToSend = ipMAX_UDP_PAYLOAD_LENGTH;
\r
389 /* Send all remaining bytes - which may well be the total
\r
390 number of bytes if the packet was not chopped up. */
\r
391 xBytesToSend = xBytesRemaining;
\r
394 /* If the zero copy flag is set, then the data is already in a
\r
395 network buffer. Otherwise, get a new network buffer. */
\r
396 if( ( ulFlags & FREERTOS_ZERO_COPY ) == 0 )
\r
398 if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdTRUE )
\r
403 pxNetworkBuffer = pxNetworkBufferGet( xBytesToSend + sizeof( xUDPPacket_t ), xTicksToWait );
\r
407 if( xTotalDataLength > ipMAX_UDP_PAYLOAD_LENGTH )
\r
409 /* The packet needs fragmenting, but zero copy buffers
\r
410 cannot be fragmented. */
\r
411 pxNetworkBuffer = NULL;
\r
415 /* When zero copy is used, pvBuffer is a pointer to the
\r
416 payload of a buffer that has already been obtained from the
\r
417 stack. Obtain the network buffer pointer from the buffer. */
\r
418 pucBuffer = ( uint8_t * ) pvBuffer;
\r
419 pucBuffer -= ( ipBUFFER_PADDING + sizeof( xUDPPacket_t ) );
\r
420 pxNetworkBuffer = * ( ( xNetworkBufferDescriptor_t ** ) pucBuffer );
\r
424 if( pxNetworkBuffer != NULL )
\r
426 /* Use the part of the network buffer that will be completed
\r
427 by the IP layer as temporary storage to pass extra
\r
428 information required by the IP layer. */
\r
429 pxFragmentParameters = ( xIPFragmentParameters_t * ) &( pxNetworkBuffer->pucEthernetBuffer[ ipFRAGMENTATION_PARAMETERS_OFFSET ] );
\r
430 pxFragmentParameters->ucSocketOptions = pxSocket->ucSocketOptions;
\r
432 if( xBytesRemaining > ipMAX_UDP_PAYLOAD_LENGTH )
\r
434 /* The packet is being chopped up, and more data will
\r
436 pxFragmentParameters->ucSocketOptions = ( pxSocket->ucSocketOptions | FREERTOS_NOT_LAST_IN_FRAGMENTED_PACKET );
\r
439 if( xTotalDataLength > ipMAX_UDP_PAYLOAD_LENGTH )
\r
441 /* Let the IP layer know this packet has been chopped up,
\r
442 and supply the IP layer with any addition information it
\r
443 needs to make sense of it. */
\r
444 pxFragmentParameters->ucSocketOptions |= FREERTOS_FRAGMENTED_PACKET;
\r
445 usFragmentOffset = ( uint16_t ) ( xTotalDataLength - xBytesRemaining );
\r
446 pxFragmentParameters->usFragmentedPacketOffset = usFragmentOffset;
\r
447 pxFragmentParameters->usFragmentLength = ( uint16_t ) xBytesToSend;
\r
451 usFragmentOffset = 0;
\r
454 /* Write the payload into the packet. The IP layer is
\r
455 queried to find where in the IP payload the data should be
\r
456 written. This is because the necessary offset is different
\r
457 for the first packet, because the first packet leaves space
\r
458 for a UDP header. Note that this changes usFragmentOffset
\r
459 from the offset in the entire UDP packet, to the offset
\r
460 in the IP packet. */
\r
461 if( ( ulFlags & FREERTOS_ZERO_COPY ) == 0 )
\r
463 /* Only copy the data if it is not already in the
\r
464 expected location. */
\r
465 usFragmentOffset = ipGET_UDP_PAYLOAD_OFFSET_FOR_FRAGMENT( usFragmentOffset );
\r
466 memcpy( ( void * ) &( pxNetworkBuffer->pucEthernetBuffer[ usFragmentOffset ] ), ( void * ) pucBuffer, xBytesToSend );
\r
468 pxNetworkBuffer->xDataLength = xTotalDataLength;
\r
469 pxNetworkBuffer->usPort = pxDestinationAddress->sin_port;
\r
470 pxNetworkBuffer->usBoundPort = ( uint16_t ) socketGET_SOCKET_ADDRESS( pxSocket );
\r
471 pxNetworkBuffer->ulIPAddress = pxDestinationAddress->sin_addr;
\r
473 /* Tell the networking task that the packet needs sending. */
\r
474 xStackTxEvent.pvData = pxNetworkBuffer;
\r
476 if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdTRUE )
\r
481 if( xQueueSendToBack( xNetworkEventQueue, &xStackTxEvent, xTicksToWait ) != pdPASS )
\r
483 /* If the buffer was allocated in this function, release it. */
\r
484 if( ( ulFlags & FREERTOS_ZERO_COPY ) == 0 )
\r
486 vNetworkBufferRelease( pxNetworkBuffer );
\r
488 iptraceSTACK_TX_EVENT_LOST( ipSTACK_TX_EVENT );
\r
492 /* Adjust counters ready to either exit the loop, or send
\r
493 another chunk of data. */
\r
494 xBytesRemaining -= xBytesToSend;
\r
495 pucBuffer += xBytesToSend;
\r
499 /* If errno was available, errno would be set to
\r
500 FREERTOS_ENOPKTS. As it is, the function must return the
\r
501 number of transmitted bytes, so the calling function knows how
\r
502 much data was actually sent. */
\r
508 return ( xTotalDataLength - xBytesRemaining );
\r
511 #else /* ipconfigCAN_FRAGMENT_OUTGOING_PACKETS */
\r
513 int32_t FreeRTOS_sendto( xSocket_t xSocket, const void *pvBuffer, size_t xTotalDataLength, uint32_t ulFlags, const struct freertos_sockaddr *pxDestinationAddress, socklen_t xDestinationAddressLength )
\r
515 xNetworkBufferDescriptor_t *pxNetworkBuffer;
\r
516 xIPStackEvent_t xStackTxEvent = { eStackTxEvent, NULL };
\r
517 extern xQueueHandle xNetworkEventQueue;
\r
518 xTimeOutType xTimeOut;
\r
519 portTickType xTicksToWait;
\r
520 int32_t lReturn = 0;
\r
521 xFreeRTOS_Socket_t *pxSocket;
\r
522 uint8_t *pucBuffer;
\r
524 pxSocket = ( xFreeRTOS_Socket_t * ) xSocket;
\r
526 /* The function prototype is designed to maintain the expected Berkeley
\r
527 sockets standard, but this implementation does not use all the
\r
529 ( void ) xDestinationAddressLength;
\r
530 configASSERT( xNetworkEventQueue );
\r
531 configASSERT( pvBuffer );
\r
533 if( xTotalDataLength <= ipMAX_UDP_PAYLOAD_LENGTH )
\r
535 if( socketSOCKET_IS_BOUND( pxSocket ) == pdFALSE )
\r
537 /* If the socket is not already bound to an address, bind it now.
\r
538 Passing NULL as the address parameter tells FreeRTOS_bind() to
\r
539 select the address to bind to. */
\r
540 FreeRTOS_bind( pxSocket, NULL, 0 );
\r
543 if( socketSOCKET_IS_BOUND( pxSocket ) != pdFALSE )
\r
545 xTicksToWait = pxSocket->xSendBlockTime;
\r
547 if( ( ulFlags & FREERTOS_ZERO_COPY ) == 0 )
\r
549 /* Zero copy is not set, so obtain a network buffer into
\r
550 which the payload will be copied. */
\r
551 vTaskSetTimeOutState( &xTimeOut );
\r
552 pxNetworkBuffer = pxNetworkBufferGet( xTotalDataLength + sizeof( xUDPPacket_t ), xTicksToWait );
\r
554 if( pxNetworkBuffer != NULL )
\r
556 memcpy( ( void * ) &( pxNetworkBuffer->pucEthernetBuffer[ ipUDP_PAYLOAD_OFFSET ] ), ( void * ) pvBuffer, xTotalDataLength );
\r
558 if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdTRUE )
\r
560 /* The entire block time has been used up. */
\r
567 /* When zero copy is used, pvBuffer is a pointer to the
\r
568 payload of a buffer that has already been obtained from the
\r
569 stack. Obtain the network buffer pointer from the buffer. */
\r
570 pucBuffer = ( uint8_t * ) pvBuffer;
\r
571 pucBuffer -= ( ipBUFFER_PADDING + sizeof( xUDPPacket_t ) );
\r
572 pxNetworkBuffer = * ( ( xNetworkBufferDescriptor_t ** ) pucBuffer );
\r
575 if( pxNetworkBuffer != NULL )
\r
577 pxNetworkBuffer->xDataLength = xTotalDataLength;
\r
578 pxNetworkBuffer->usPort = pxDestinationAddress->sin_port;
\r
579 pxNetworkBuffer->usBoundPort = ( uint16_t ) socketGET_SOCKET_ADDRESS( pxSocket );
\r
580 pxNetworkBuffer->ulIPAddress = pxDestinationAddress->sin_addr;
\r
582 /* The socket options are passed to the IP layer in the
\r
583 space that will eventually get used by the Ethernet header. */
\r
584 pxNetworkBuffer->pucEthernetBuffer[ ipSOCKET_OPTIONS_OFFSET ] = pxSocket->ucSocketOptions;
\r
586 /* Tell the networking task that the packet needs sending. */
\r
587 xStackTxEvent.pvData = pxNetworkBuffer;
\r
589 if( xQueueSendToBack( xNetworkEventQueue, &xStackTxEvent, xTicksToWait ) != pdPASS )
\r
591 /* If the buffer was allocated in this function, release it. */
\r
592 if( ( ulFlags & FREERTOS_ZERO_COPY ) == 0 )
\r
594 vNetworkBufferRelease( pxNetworkBuffer );
\r
596 iptraceSTACK_TX_EVENT_LOST( ipSTACK_TX_EVENT );
\r
600 lReturn = ( int32_t ) xTotalDataLength;
\r
605 /* If errno was available, errno would be set to
\r
606 FREERTOS_ENOPKTS. As it is, the function must return the
\r
607 number of transmitted bytes, so the calling function knows how
\r
608 much data was actually sent. */
\r
609 iptraceNO_BUFFER_FOR_SENDTO();
\r
614 iptraceSENDTO_SOCKET_NOT_BOUND();
\r
619 /* The data is longer than the available buffer space. Setting
\r
620 ipconfigCAN_FRAGMENT_OUTGOING_PACKETS to 1 may allow this packet
\r
622 iptraceSENDTO_DATA_TOO_LONG();
\r
628 #endif /* ipconfigCAN_FRAGMENT_OUTGOING_PACKETS */
\r
629 /*-----------------------------------------------------------*/
\r
631 portBASE_TYPE FreeRTOS_bind( xSocket_t xSocket, struct freertos_sockaddr * pxAddress, socklen_t xAddressLength )
\r
633 portBASE_TYPE xReturn = 0; /* In Berkeley sockets, 0 means pass for bind(). */
\r
634 xFreeRTOS_Socket_t *pxSocket;
\r
635 #if ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND == 1
\r
636 struct freertos_sockaddr xAddress;
\r
637 #endif /* ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND */
\r
639 pxSocket = ( xFreeRTOS_Socket_t * ) xSocket;
\r
641 /* The function prototype is designed to maintain the expected Berkeley
\r
642 sockets standard, but this implementation does not use all the parameters. */
\r
643 ( void ) xAddressLength;
\r
645 configASSERT( xSocket );
\r
646 configASSERT( xSocket != FREERTOS_INVALID_SOCKET );
\r
648 #if ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND == 1
\r
650 /* pxAddress will be NULL if sendto() was called on a socket without the
\r
651 socket being bound to an address. In this case, automatically allocate
\r
652 an address to the socket. There is a very tiny chance that the allocated
\r
653 port will already be in use - if that is the case, then the check below
\r
654 [pxListFindListItemWithValue()] will result in an error being returned. */
\r
655 if( pxAddress == NULL )
\r
657 pxAddress = &xAddress;
\r
658 pxAddress->sin_port = prvGetPrivatePortNumber();
\r
661 #endif /* ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND == 1 */
\r
663 /* Sockets must be bound before calling FreeRTOS_sendto() if
\r
664 ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND is not set to 1. */
\r
665 configASSERT( pxAddress );
\r
667 if( pxAddress != NULL )
\r
669 if( pxAddress->sin_port == 0 )
\r
671 pxAddress->sin_port = prvGetPrivatePortNumber();
\r
676 /* Check to ensure the port is not already in use. */
\r
677 if( pxListFindListItemWithValue( &xBoundSocketsList, ( portTickType ) pxAddress->sin_port ) != NULL )
\r
679 xReturn = FREERTOS_EADDRINUSE;
\r
684 /* Check that xReturn has not been set before continuing. */
\r
687 if( pxSocket->xWaitingPacketSemaphore == NULL )
\r
689 /* Create the semaphore used to count the number of packets that
\r
690 are queued on this socket. */
\r
691 pxSocket->xWaitingPacketSemaphore = xSemaphoreCreateCounting( ipconfigNUM_NETWORK_BUFFERS, 0 );
\r
693 if( pxSocket->xWaitingPacketSemaphore != NULL )
\r
695 /* Allocate the port number to the socket. */
\r
696 socketSET_SOCKET_ADDRESS( pxSocket, pxAddress->sin_port );
\r
697 taskENTER_CRITICAL();
\r
699 /* Add the socket to the list of bound ports. */
\r
700 vListInsertEnd( &xBoundSocketsList, &( pxSocket->xBoundSocketListItem ) );
\r
702 taskEXIT_CRITICAL();
\r
706 /* Out of memory. */
\r
707 xReturn = FREERTOS_ENOBUFS;
\r
712 /* The socket is already bound. */
\r
713 xReturn = FREERTOS_EINVAL;
\r
719 xReturn = FREERTOS_EADDRNOTAVAIL;
\r
724 iptraceBIND_FAILED( xSocket, ( FreeRTOS_ntohs( pxAddress->sin_port ) ) );
\r
729 /*-----------------------------------------------------------*/
\r
731 portBASE_TYPE FreeRTOS_closesocket( xSocket_t xSocket )
\r
733 xNetworkBufferDescriptor_t *pxNetworkBuffer;
\r
734 xFreeRTOS_Socket_t *pxSocket;
\r
736 pxSocket = ( xFreeRTOS_Socket_t * ) xSocket;
\r
738 configASSERT( pxSocket );
\r
739 configASSERT( pxSocket != FREERTOS_INVALID_SOCKET );
\r
741 /* Socket must be unbound first, to ensure no more packets are queued on
\r
743 if( socketSOCKET_IS_BOUND( pxSocket ) != pdFALSE )
\r
745 taskENTER_CRITICAL();
\r
747 uxListRemove( &( pxSocket->xBoundSocketListItem ) );
\r
749 taskEXIT_CRITICAL();
\r
752 /* Now the socket is not bound the list of waiting packets can be
\r
754 if( pxSocket->xWaitingPacketSemaphore != NULL )
\r
756 while( listCURRENT_LIST_LENGTH( &( pxSocket->xWaitingPacketsList ) ) > 0U )
\r
758 pxNetworkBuffer = ( xNetworkBufferDescriptor_t * ) listGET_OWNER_OF_HEAD_ENTRY( &( pxSocket->xWaitingPacketsList ) );
\r
759 uxListRemove( &( pxNetworkBuffer->xBufferListItem ) );
\r
760 vNetworkBufferRelease( pxNetworkBuffer );
\r
762 vSemaphoreDelete( pxSocket->xWaitingPacketSemaphore );
\r
765 vPortFree( pxSocket );
\r
769 /*-----------------------------------------------------------*/
\r
771 void FreeRTOS_SocketsInit( void )
\r
773 vListInitialise( &xBoundSocketsList );
\r
775 /*-----------------------------------------------------------*/
\r
777 portBASE_TYPE FreeRTOS_setsockopt( xSocket_t xSocket, int32_t lLevel, int32_t lOptionName, const void *pvOptionValue, size_t xOptionLength )
\r
779 /* The standard Berkeley function returns 0 for success. */
\r
780 portBASE_TYPE xReturn = 0;
\r
781 portBASE_TYPE lOptionValue;
\r
782 xFreeRTOS_Socket_t *pxSocket;
\r
784 pxSocket = ( xFreeRTOS_Socket_t * ) xSocket;
\r
786 /* The function prototype is designed to maintain the expected Berkeley
\r
787 sockets standard, but this implementation does not use all the parameters. */
\r
789 ( void ) xOptionLength;
\r
791 configASSERT( xSocket );
\r
793 switch( lOptionName )
\r
795 case FREERTOS_SO_RCVTIMEO :
\r
796 /* Receive time out. */
\r
797 pxSocket->xReceiveBlockTime = *( ( portTickType * ) pvOptionValue );
\r
800 case FREERTOS_SO_SNDTIMEO :
\r
801 /* The send time out is capped for the reason stated in the comments
\r
802 where ipconfigMAX_SEND_BLOCK_TIME_TICKS is defined in
\r
803 FreeRTOSIPConfig.h (assuming an official configuration file is being
\r
805 pxSocket->xSendBlockTime = *( ( portTickType * ) pvOptionValue );
\r
806 if( pxSocket->xSendBlockTime > ipconfigMAX_SEND_BLOCK_TIME_TICKS )
\r
808 pxSocket->xSendBlockTime = ipconfigMAX_SEND_BLOCK_TIME_TICKS;
\r
812 case FREERTOS_SO_UDPCKSUM_OUT :
\r
813 /* Turn calculating of the UDP checksum on/off for this socket. */
\r
814 lOptionValue = ( portBASE_TYPE ) pvOptionValue;
\r
816 if( lOptionValue == 0 )
\r
818 pxSocket->ucSocketOptions &= ~FREERTOS_SO_UDPCKSUM_OUT;
\r
822 pxSocket->ucSocketOptions |= FREERTOS_SO_UDPCKSUM_OUT;
\r
827 /* No other options are handled. */
\r
828 xReturn = FREERTOS_ENOPROTOOPT;
\r
834 /*-----------------------------------------------------------*/
\r
836 portBASE_TYPE xProcessReceivedUDPPacket( xNetworkBufferDescriptor_t *pxNetworkBuffer, uint16_t usPort )
\r
838 xListItem *pxListItem;
\r
839 portBASE_TYPE xReturn = pdPASS;
\r
840 xFreeRTOS_Socket_t *pxSocket;
\r
841 portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
\r
845 /* See if there is a list item associated with the port number on the
\r
846 list of bound sockets. */
\r
847 pxListItem = pxListFindListItemWithValue( &xBoundSocketsList, ( portTickType ) usPort );
\r
851 if( pxListItem != NULL )
\r
853 /* The owner of the list item is the socket itself. */
\r
854 pxSocket = ( xFreeRTOS_Socket_t * ) listGET_LIST_ITEM_OWNER( pxListItem );
\r
858 #if( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
\r
860 /* Is the socket a member of a select() group? */
\r
861 if( pxSocket->xSelectQueue != NULL )
\r
863 /* Can the select group be notified that the socket is
\r
864 ready to be read? */
\r
865 if( xQueueSendFromISR( pxSocket->xSelectQueue, &pxSocket, &xHigherPriorityTaskWoken ) != pdPASS )
\r
867 /* Could not notify the select group. */
\r
869 iptraceFAILED_TO_NOTIFY_SELECT_GROUP( pxSocket );
\r
875 if( xReturn == pdPASS )
\r
877 taskENTER_CRITICAL();
\r
879 /* Add the network packet to the list of packets to be
\r
880 processed by the socket. */
\r
881 vListInsertEnd( &( pxSocket->xWaitingPacketsList ), &( pxNetworkBuffer->xBufferListItem ) );
\r
883 taskEXIT_CRITICAL();
\r
885 /* The socket's counting semaphore records how many packets are
\r
886 waiting to be processed by the socket. */
\r
887 xSemaphoreGiveFromISR( pxSocket->xWaitingPacketSemaphore, &xHigherPriorityTaskWoken );
\r
890 if( xTaskResumeAll() == pdFALSE )
\r
892 if( xHigherPriorityTaskWoken != pdFALSE )
\r
905 /*-----------------------------------------------------------*/
\r
907 static uint16_t prvGetPrivatePortNumber( void )
\r
909 static uint16_t usNextPortToUse = socketAUTO_PORT_ALLOCATION_START_NUMBER - 1;
\r
912 /* Assign the next port in the range. */
\r
913 taskENTER_CRITICAL();
\r
915 taskEXIT_CRITICAL();
\r
917 /* Has it overflowed? */
\r
918 if( usNextPortToUse == 0U )
\r
920 /* Don't go right back to the start of the dynamic/private port
\r
921 range numbers as any persistent sockets are likely to have been
\r
922 create first so the early port numbers may still be in use. */
\r
923 usNextPortToUse = socketAUTO_PORT_ALLOCATION_RESET_NUMBER;
\r
926 usReturn = FreeRTOS_htons( usNextPortToUse );
\r
930 /*-----------------------------------------------------------*/
\r
932 xListItem * pxListFindListItemWithValue( xList *pxList, portTickType xWantedItemValue )
\r
934 xListItem *pxIterator, *pxReturn;
\r
937 for( pxIterator = ( xListItem * ) pxList->xListEnd.pxNext; pxIterator != ( xListItem* ) &( pxList->xListEnd ); pxIterator = ( xListItem * ) pxIterator->pxNext )
\r
939 if( pxIterator->xItemValue == xWantedItemValue )
\r
941 pxReturn = pxIterator;
\r
948 /*-----------------------------------------------------------*/
\r
950 #if ipconfigINCLUDE_FULL_INET_ADDR == 1
\r
952 uint32_t FreeRTOS_inet_addr( const uint8_t * pucIPAddress )
\r
954 const uint8_t ucDecimalBase = 10;
\r
955 uint8_t ucOctet[ socketMAX_IP_ADDRESS_OCTETS ];
\r
956 const uint8_t *pucPointerOnEntering;
\r
957 uint32_t ulReturn = 0UL, ulOctetNumber, ulValue;
\r
958 portBASE_TYPE xResult = pdPASS;
\r
960 for( ulOctetNumber = 0; ulOctetNumber < socketMAX_IP_ADDRESS_OCTETS; ulOctetNumber++ )
\r
963 pucPointerOnEntering = pucIPAddress;
\r
965 while( ( *pucIPAddress >= ( uint8_t ) '0' ) && ( *pucIPAddress <= ( uint8_t ) '9' ) )
\r
967 /* Move previous read characters into the next decimal
\r
969 ulValue *= ucDecimalBase;
\r
971 /* Add the binary value of the ascii character. */
\r
972 ulValue += ( *pucIPAddress - ( uint8_t ) '0' );
\r
974 /* Move to next character in the string. */
\r
978 /* Check characters were read. */
\r
979 if( pucIPAddress == pucPointerOnEntering )
\r
984 /* Check the value fits in an 8-bit number. */
\r
985 if( ulValue > 0xffUL )
\r
991 ucOctet[ ulOctetNumber ] = ( uint8_t ) ulValue;
\r
993 /* Check the next character is as expected. */
\r
994 if( ulOctetNumber < ( socketMAX_IP_ADDRESS_OCTETS - 1 ) )
\r
996 if( *pucIPAddress != ( uint8_t ) '.' )
\r
1002 /* Move past the dot. */
\r
1008 if( xResult == pdFAIL )
\r
1010 /* No point going on. */
\r
1015 if( *pucIPAddress != ( uint8_t ) 0x00 )
\r
1017 /* Expected the end of the string. */
\r
1021 if( ulOctetNumber != socketMAX_IP_ADDRESS_OCTETS )
\r
1023 /* Didn't read enough octets. */
\r
1027 if( xResult == pdPASS )
\r
1029 ulReturn = FreeRTOS_inet_addr_quick( ucOctet[ 0 ], ucOctet[ 1 ], ucOctet[ 2 ], ucOctet[ 3 ] );
\r
1035 #endif /* ipconfigINCLUDE_FULL_INET_ADDR */
\r
1036 /*-----------------------------------------------------------*/
\r