2 * FreeRTOS+UDP V1.0.4
\r
3 * Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
\r
5 * Permission is hereby granted, free of charge, to any person obtaining a copy of
\r
6 * this software and associated documentation files (the "Software"), to deal in
\r
7 * the Software without restriction, including without limitation the rights to
\r
8 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
\r
9 * the Software, and to permit persons to whom the Software is furnished to do so,
\r
10 * subject to the following conditions:
\r
12 * The above copyright notice and this permission notice shall be included in all
\r
13 * copies or substantial portions of the Software. If you wish to use our Amazon
\r
14 * FreeRTOS name, please do so in a fair use way that does not cause confusion.
\r
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
\r
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
\r
18 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
\r
19 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
\r
20 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
\r
21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\r
23 * http://www.FreeRTOS.org
\r
24 * http://aws.amazon.com/freertos
\r
26 * 1 tab == 4 spaces!
\r
29 /* Standard includes. */
\r
32 /* FreeRTOS includes. */
\r
33 #include "FreeRTOS.h"
\r
38 /* FreeRTOS+UDP includes. */
\r
39 #include "FreeRTOS_UDP_IP.h"
\r
40 #include "FreeRTOS_IP_Private.h"
\r
41 #include "FreeRTOS_Sockets.h"
\r
42 #include "NetworkBufferManagement.h"
\r
44 /* Sanity check the UDP payload length setting is compatible with the
\r
45 fragmentation setting. */
\r
46 #if ipconfigCAN_FRAGMENT_OUTGOING_PACKETS == 1
\r
47 #if ( ( ipMAX_UDP_PAYLOAD_LENGTH % 8 ) != 0 )
\r
48 #error ( ipconfigNETWORK_MTU - 28 ) must be divisible by 8 when fragmentation is used
\r
49 #endif /* ipMAX_UDP_PAYLOAD_LENGTH */
\r
50 #endif /* ipconfigFRAGMENT_OUTGOING_PACKETS */
\r
52 /* The ItemValue of the sockets xBoundSocketListItem member holds the socket's
\r
54 #define socketSET_SOCKET_ADDRESS( pxSocket, usPort ) listSET_LIST_ITEM_VALUE( ( &( ( pxSocket )->xBoundSocketListItem ) ), ( usPort ) )
\r
55 #define socketGET_SOCKET_ADDRESS( pxSocket ) listGET_LIST_ITEM_VALUE( ( &( ( pxSocket )->xBoundSocketListItem ) ) )
\r
57 /* xWaitingPacketSemaphore is not created until the socket is bound, so can be
\r
58 tested to see if bind() has been called. */
\r
59 #define socketSOCKET_IS_BOUND( pxSocket ) ( ( BaseType_t ) pxSocket->xWaitingPacketSemaphore )
\r
61 /* If FreeRTOS_sendto() is called on a socket that is not bound to a port
\r
62 number then, depending on the FreeRTOSIPConfig.h settings, it might be that a
\r
63 port number is automatically generated for the socket. Automatically generated
\r
64 port numbers will be between socketAUTO_PORT_ALLOCATION_START_NUMBER and
\r
66 #define socketAUTO_PORT_ALLOCATION_START_NUMBER ( ( uint16_t ) 0xc000 )
\r
68 /* When the automatically generated port numbers overflow, the next value used
\r
69 is not set back to socketAUTO_PORT_ALLOCATION_START_NUMBER because it is likely
\r
70 that the first few automatically generated ports will still be in use. Instead
\r
71 it is reset back to the value defined by this constant. */
\r
72 #define socketAUTO_PORT_ALLOCATION_RESET_NUMBER ( ( uint16_t ) 0xc100 )
\r
74 /* The number of octets that make up an IP address. */
\r
75 #define socketMAX_IP_ADDRESS_OCTETS 4
\r
76 /*-----------------------------------------------------------*/
\r
79 * Allocate the next port number from the private allocation range.
\r
81 static uint16_t prvGetPrivatePortNumber( void );
\r
84 * Return the list itme from within pxList that has an item value of
\r
85 * xWantedItemValue. If there is no such list item return NULL.
\r
87 xListItem * pxListFindListItemWithValue( xList *pxList, TickType_t xWantedItemValue );
\r
89 /*-----------------------------------------------------------*/
\r
91 typedef struct XSOCKET
\r
93 xSemaphoreHandle xWaitingPacketSemaphore;
\r
94 xList xWaitingPacketsList;
\r
95 xListItem xBoundSocketListItem; /* Used to reference the socket from a bound sockets list. */
\r
96 TickType_t xReceiveBlockTime;
\r
97 TickType_t xSendBlockTime;
\r
98 uint8_t ucSocketOptions;
\r
99 #if ipconfigSUPPORT_SELECT_FUNCTION == 1
\r
100 xQueueHandle xSelectQueue;
\r
102 } xFreeRTOS_Socket_t;
\r
105 /* The list that contains mappings between sockets and port numbers. Accesses
\r
106 to this list must be protected by critical sections of one kind or another. */
\r
107 static xList xBoundSocketsList;
\r
109 /*-----------------------------------------------------------*/
\r
111 xSocket_t FreeRTOS_socket( BaseType_t xDomain, BaseType_t xType, BaseType_t xProtocol )
\r
113 xFreeRTOS_Socket_t *pxSocket;
\r
115 /* Only UDP on Ethernet is currently supported. */
\r
116 configASSERT( xDomain == FREERTOS_AF_INET );
\r
117 configASSERT( xType == FREERTOS_SOCK_DGRAM );
\r
118 configASSERT( xProtocol == FREERTOS_IPPROTO_UDP );
\r
119 configASSERT( listLIST_IS_INITIALISED( &xBoundSocketsList ) );
\r
121 /* Allocate the structure that will hold the socket information. */
\r
122 pxSocket = ( xFreeRTOS_Socket_t * ) pvPortMalloc( sizeof( xFreeRTOS_Socket_t ) );
\r
124 if( pxSocket == NULL )
\r
126 pxSocket = ( xFreeRTOS_Socket_t * ) FREERTOS_INVALID_SOCKET;
\r
127 iptraceFAILED_TO_CREATE_SOCKET();
\r
131 /* Initialise the socket's members. The semaphore will be created if
\r
132 the socket is bound to an address, for now the pointer to the semaphore
\r
133 is just set to NULL to show it has not been created. */
\r
134 pxSocket->xWaitingPacketSemaphore = NULL;
\r
135 vListInitialise( &( pxSocket->xWaitingPacketsList ) );
\r
136 vListInitialiseItem( &( pxSocket->xBoundSocketListItem ) );
\r
137 listSET_LIST_ITEM_OWNER( &( pxSocket->xBoundSocketListItem ), ( void * ) pxSocket );
\r
138 pxSocket->xSendBlockTime = ( TickType_t ) 0;
\r
139 pxSocket->xReceiveBlockTime = portMAX_DELAY;
\r
140 pxSocket->ucSocketOptions = FREERTOS_SO_UDPCKSUM_OUT;
\r
141 #if ipconfigSUPPORT_SELECT_FUNCTION == 1
\r
142 pxSocket->xSelectQueue = NULL;
\r
146 /* Remove compiler warnings in the case the configASSERT() is not defined. */
\r
149 ( void ) xProtocol;
\r
151 return ( xSocket_t ) pxSocket;
\r
153 /*-----------------------------------------------------------*/
\r
155 #if ipconfigSUPPORT_SELECT_FUNCTION == 1
\r
157 xSocketSet_t FreeRTOS_CreateSocketSet( UBaseType_t uxEventQueueLength )
\r
159 xQueueHandle xSelectQueue;
\r
161 /* Create the queue into which the address of sockets that are
\r
162 available to read are posted. */
\r
163 xSelectQueue = xQueueCreate( uxEventQueueLength, sizeof( xSocket_t ) );
\r
165 return ( xSocketSet_t ) xSelectQueue;
\r
168 #endif /* ipconfigSUPPORT_SELECT_FUNCTION */
\r
169 /*-----------------------------------------------------------*/
\r
171 #if ipconfigSUPPORT_SELECT_FUNCTION == 1
\r
173 BaseType_t FreeRTOS_FD_SET( xSocket_t xSocket, xSocketSet_t xSocketSet )
\r
175 xFreeRTOS_Socket_t *pxSocket = ( xFreeRTOS_Socket_t * ) xSocket;
\r
176 BaseType_t xReturn = pdFALSE;
\r
177 UBaseType_t uxMessagesWaiting;
\r
179 configASSERT( xSocket );
\r
181 /* Is the socket already a member of a select group? */
\r
182 if( pxSocket->xSelectQueue == NULL )
\r
184 taskENTER_CRITICAL();
\r
186 /* Are there packets queued on the socket already? */
\r
187 uxMessagesWaiting = uxQueueMessagesWaiting( pxSocket->xWaitingPacketSemaphore );
\r
189 /* Are there enough notification spaces in the select queue for the
\r
190 number of packets already queued on the socket? */
\r
191 if( uxQueueSpacesAvailable( ( xQueueHandle ) xSocketSet ) >= uxMessagesWaiting )
\r
193 /* Store a pointer to the select group in the socket for
\r
194 future reference. */
\r
195 pxSocket->xSelectQueue = ( xQueueHandle ) xSocketSet;
\r
197 while( uxMessagesWaiting > 0 )
\r
199 /* Add notifications of the number of packets that are
\r
200 already queued on the socket to the select queue. */
\r
201 xQueueSendFromISR( pxSocket->xSelectQueue, &pxSocket, NULL );
\r
202 uxMessagesWaiting--;
\r
208 taskEXIT_CRITICAL();
\r
214 #endif /* ipconfigSUPPORT_SELECT_FUNCTION */
\r
215 /*-----------------------------------------------------------*/
\r
217 #if ipconfigSUPPORT_SELECT_FUNCTION == 1
\r
219 BaseType_t FreeRTOS_FD_CLR( xSocket_t xSocket, xSocketSet_t xSocketSet )
\r
221 xFreeRTOS_Socket_t *pxSocket = ( xFreeRTOS_Socket_t * ) xSocket;
\r
222 BaseType_t xReturn;
\r
224 /* Is the socket a member of the select group? */
\r
225 if( pxSocket->xSelectQueue == ( xQueueHandle ) xSocketSet )
\r
227 /* The socket is no longer a member of the select group. */
\r
228 pxSocket->xSelectQueue = NULL;
\r
239 #endif /* ipconfigSUPPORT_SELECT_FUNCTION */
\r
240 /*-----------------------------------------------------------*/
\r
242 #if ipconfigSUPPORT_SELECT_FUNCTION == 1
\r
244 xSocket_t FreeRTOS_select( xSocketSet_t xSocketSet, TickType_t xBlockTimeTicks )
\r
246 xFreeRTOS_Socket_t *pxSocket;
\r
248 /* Wait for a socket to be ready to read. */
\r
249 if( xQueueReceive( ( xQueueHandle ) xSocketSet, &pxSocket, xBlockTimeTicks ) != pdPASS )
\r
254 return ( xSocket_t ) pxSocket;
\r
257 #endif /* ipconfigSUPPORT_SELECT_FUNCTION */
\r
258 /*-----------------------------------------------------------*/
\r
260 int32_t FreeRTOS_recvfrom( xSocket_t xSocket, void *pvBuffer, size_t xBufferLength, uint32_t ulFlags, struct freertos_sockaddr *pxSourceAddress, socklen_t *pxSourceAddressLength )
\r
262 xNetworkBufferDescriptor_t *pxNetworkBuffer;
\r
264 xFreeRTOS_Socket_t *pxSocket;
\r
266 pxSocket = ( xFreeRTOS_Socket_t * ) xSocket;
\r
268 /* The function prototype is designed to maintain the expected Berkeley
\r
269 sockets standard, but this implementation does not use all the parameters. */
\r
270 ( void ) pxSourceAddressLength;
\r
272 if( socketSOCKET_IS_BOUND( pxSocket ) != pdFALSE )
\r
274 /* The semaphore is given when received data is queued on the socket. */
\r
275 if( xSemaphoreTake( pxSocket->xWaitingPacketSemaphore, pxSocket->xReceiveBlockTime ) == pdPASS )
\r
277 taskENTER_CRITICAL();
\r
279 configASSERT( ( listCURRENT_LIST_LENGTH( &( pxSocket->xWaitingPacketsList ) ) > 0U ) );
\r
281 /* The owner of the list item is the network buffer. */
\r
282 pxNetworkBuffer = ( xNetworkBufferDescriptor_t * ) listGET_OWNER_OF_HEAD_ENTRY( &( pxSocket->xWaitingPacketsList ) );
\r
284 /* Remove the network buffer from the list of buffers waiting to
\r
285 be processed by the socket. */
\r
286 uxListRemove( &( pxNetworkBuffer->xBufferListItem ) );
\r
288 taskEXIT_CRITICAL();
\r
290 if( ( ulFlags & FREERTOS_ZERO_COPY ) == 0 )
\r
292 /* The zero copy flag is not set. Truncate the length if it
\r
293 won't fit in the provided buffer. */
\r
294 if( pxNetworkBuffer->xDataLength > xBufferLength )
\r
296 iptraceRECVFROM_DISCARDING_BYTES( ( xBufferLength - pxNetworkBuffer->xDataLength ) );
\r
297 pxNetworkBuffer->xDataLength = xBufferLength;
\r
300 /* Copy the received data into the provided buffer, then
\r
301 release the network buffer. */
\r
302 memcpy( pvBuffer, ( void * ) &( pxNetworkBuffer->pucEthernetBuffer[ ipUDP_PAYLOAD_OFFSET ] ), pxNetworkBuffer->xDataLength );
\r
303 vNetworkBufferRelease( pxNetworkBuffer );
\r
307 /* The zero copy flag was set. pvBuffer is not a buffer into
\r
308 which the received data can be copied, but a pointer that must
\r
309 be set to point to the buffer in which the received data has
\r
310 already been placed. */
\r
311 *( ( void** ) pvBuffer ) = ( void * ) ( &( pxNetworkBuffer->pucEthernetBuffer[ ipUDP_PAYLOAD_OFFSET ] ) );
\r
314 /* The returned value is the data length, which may have been
\r
315 capped to the receive buffer size. */
\r
316 lReturn = ( int32_t ) pxNetworkBuffer->xDataLength;
\r
318 if( pxSourceAddress != NULL )
\r
320 pxSourceAddress->sin_port = pxNetworkBuffer->usPort;
\r
321 pxSourceAddress->sin_addr = pxNetworkBuffer->ulIPAddress;
\r
326 lReturn = FREERTOS_EWOULDBLOCK;
\r
327 iptraceRECVFROM_TIMEOUT();
\r
332 lReturn = FREERTOS_EINVAL;
\r
337 /*-----------------------------------------------------------*/
\r
339 #if ipconfigCAN_FRAGMENT_OUTGOING_PACKETS == 1
\r
341 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
343 xNetworkBufferDescriptor_t *pxNetworkBuffer;
\r
344 xIPFragmentParameters_t *pxFragmentParameters;
\r
345 size_t xBytesToSend, xBytesRemaining;
\r
346 xIPStackEvent_t xStackTxEvent = { eStackTxEvent, NULL };
\r
347 extern xQueueHandle xNetworkEventQueue;
\r
348 uint8_t *pucBuffer;
\r
349 xTimeOutType xTimeOut;
\r
350 TickType_t xTicksToWait;
\r
351 uint16_t usFragmentOffset;
\r
352 xFreeRTOS_Socket_t *pxSocket;
\r
354 pxSocket = ( xFreeRTOS_Socket_t * ) xSocket;
\r
356 /* The function prototype is designed to maintain the expected Berkeley
\r
357 sockets standard, but this implementation does not use all the
\r
359 ( void ) xDestinationAddressLength;
\r
360 configASSERT( xNetworkEventQueue );
\r
361 configASSERT( pvBuffer );
\r
363 xBytesRemaining = xTotalDataLength;
\r
365 if( socketSOCKET_IS_BOUND( pxSocket ) == pdFALSE )
\r
367 /* If the socket is not already bound to an address, bind it now.
\r
368 Passing NULL as the address parameter tells FreeRTOS_bind() to select
\r
369 the address to bind to. */
\r
370 FreeRTOS_bind( xSocket, NULL, 0 );
\r
373 if( socketSOCKET_IS_BOUND( pxSocket ) != pdFALSE )
\r
375 /* pucBuffer will be reset if this send turns out to be a zero copy
\r
376 send because in that case pvBuffer is actually a pointer to an
\r
377 xUserData_t structure, not the UDP payload. */
\r
378 pucBuffer = ( uint8_t * ) pvBuffer;
\r
379 vTaskSetTimeOutState( &xTimeOut );
\r
380 xTicksToWait = pxSocket->xSendBlockTime;
\r
382 /* The data being transmitted will be sent in
\r
383 ipMAX_UDP_PAYLOAD_LENGTH chunks if xDataLength is greater than the
\r
384 network buffer payload size. Loop until all the data is sent. */
\r
385 while( xBytesRemaining > 0 )
\r
387 if( xBytesRemaining > ipMAX_UDP_PAYLOAD_LENGTH )
\r
389 /* Cap the amount being sent in this packet to the maximum
\r
390 UDP payload size. This will be a multiple of 8 already,
\r
391 removing the need to check in the code. */
\r
392 xBytesToSend = ipMAX_UDP_PAYLOAD_LENGTH;
\r
396 /* Send all remaining bytes - which may well be the total
\r
397 number of bytes if the packet was not chopped up. */
\r
398 xBytesToSend = xBytesRemaining;
\r
401 /* If the zero copy flag is set, then the data is already in a
\r
402 network buffer. Otherwise, get a new network buffer. */
\r
403 if( ( ulFlags & FREERTOS_ZERO_COPY ) == 0 )
\r
405 if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdTRUE )
\r
410 pxNetworkBuffer = pxNetworkBufferGet( xBytesToSend + sizeof( xUDPPacket_t ), xTicksToWait );
\r
414 if( xTotalDataLength > ipMAX_UDP_PAYLOAD_LENGTH )
\r
416 /* The packet needs fragmenting, but zero copy buffers
\r
417 cannot be fragmented. */
\r
418 pxNetworkBuffer = NULL;
\r
422 /* When zero copy is used, pvBuffer is a pointer to the
\r
423 payload of a buffer that has already been obtained from the
\r
424 stack. Obtain the network buffer pointer from the buffer. */
\r
425 pucBuffer = ( uint8_t * ) pvBuffer;
\r
426 pucBuffer -= ( ipBUFFER_PADDING + sizeof( xUDPPacket_t ) );
\r
427 pxNetworkBuffer = * ( ( xNetworkBufferDescriptor_t ** ) pucBuffer );
\r
431 if( pxNetworkBuffer != NULL )
\r
433 /* Use the part of the network buffer that will be completed
\r
434 by the IP layer as temporary storage to pass extra
\r
435 information required by the IP layer. */
\r
436 pxFragmentParameters = ( xIPFragmentParameters_t * ) &( pxNetworkBuffer->pucEthernetBuffer[ ipFRAGMENTATION_PARAMETERS_OFFSET ] );
\r
437 pxFragmentParameters->ucSocketOptions = pxSocket->ucSocketOptions;
\r
439 if( xBytesRemaining > ipMAX_UDP_PAYLOAD_LENGTH )
\r
441 /* The packet is being chopped up, and more data will
\r
443 pxFragmentParameters->ucSocketOptions = ( pxSocket->ucSocketOptions | FREERTOS_NOT_LAST_IN_FRAGMENTED_PACKET );
\r
446 if( xTotalDataLength > ipMAX_UDP_PAYLOAD_LENGTH )
\r
448 /* Let the IP layer know this packet has been chopped up,
\r
449 and supply the IP layer with any addition information it
\r
450 needs to make sense of it. */
\r
451 pxFragmentParameters->ucSocketOptions |= FREERTOS_FRAGMENTED_PACKET;
\r
452 usFragmentOffset = ( uint16_t ) ( xTotalDataLength - xBytesRemaining );
\r
453 pxFragmentParameters->usFragmentedPacketOffset = usFragmentOffset;
\r
454 pxFragmentParameters->usFragmentLength = ( uint16_t ) xBytesToSend;
\r
458 usFragmentOffset = 0;
\r
461 /* Write the payload into the packet. The IP layer is
\r
462 queried to find where in the IP payload the data should be
\r
463 written. This is because the necessary offset is different
\r
464 for the first packet, because the first packet leaves space
\r
465 for a UDP header. Note that this changes usFragmentOffset
\r
466 from the offset in the entire UDP packet, to the offset
\r
467 in the IP packet. */
\r
468 if( ( ulFlags & FREERTOS_ZERO_COPY ) == 0 )
\r
470 /* Only copy the data if it is not already in the
\r
471 expected location. */
\r
472 usFragmentOffset = ipGET_UDP_PAYLOAD_OFFSET_FOR_FRAGMENT( usFragmentOffset );
\r
473 memcpy( ( void * ) &( pxNetworkBuffer->pucEthernetBuffer[ usFragmentOffset ] ), ( void * ) pucBuffer, xBytesToSend );
\r
475 pxNetworkBuffer->xDataLength = xTotalDataLength;
\r
476 pxNetworkBuffer->usPort = pxDestinationAddress->sin_port;
\r
477 pxNetworkBuffer->usBoundPort = ( uint16_t ) socketGET_SOCKET_ADDRESS( pxSocket );
\r
478 pxNetworkBuffer->ulIPAddress = pxDestinationAddress->sin_addr;
\r
480 /* Tell the networking task that the packet needs sending. */
\r
481 xStackTxEvent.pvData = pxNetworkBuffer;
\r
483 if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdTRUE )
\r
488 if( xQueueSendToBack( xNetworkEventQueue, &xStackTxEvent, xTicksToWait ) != pdPASS )
\r
490 /* If the buffer was allocated in this function, release it. */
\r
491 if( ( ulFlags & FREERTOS_ZERO_COPY ) == 0 )
\r
493 vNetworkBufferRelease( pxNetworkBuffer );
\r
495 iptraceSTACK_TX_EVENT_LOST( ipSTACK_TX_EVENT );
\r
499 /* Adjust counters ready to either exit the loop, or send
\r
500 another chunk of data. */
\r
501 xBytesRemaining -= xBytesToSend;
\r
502 pucBuffer += xBytesToSend;
\r
506 /* If errno was available, errno would be set to
\r
507 FREERTOS_ENOPKTS. As it is, the function must return the
\r
508 number of transmitted bytes, so the calling function knows how
\r
509 much data was actually sent. */
\r
515 return ( xTotalDataLength - xBytesRemaining );
\r
518 #else /* ipconfigCAN_FRAGMENT_OUTGOING_PACKETS */
\r
520 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
522 xNetworkBufferDescriptor_t *pxNetworkBuffer;
\r
523 xIPStackEvent_t xStackTxEvent = { eStackTxEvent, NULL };
\r
524 extern xQueueHandle xNetworkEventQueue;
\r
525 xTimeOutType xTimeOut;
\r
526 TickType_t xTicksToWait;
\r
527 int32_t lReturn = 0;
\r
528 xFreeRTOS_Socket_t *pxSocket;
\r
529 uint8_t *pucBuffer;
\r
531 pxSocket = ( xFreeRTOS_Socket_t * ) xSocket;
\r
533 /* The function prototype is designed to maintain the expected Berkeley
\r
534 sockets standard, but this implementation does not use all the
\r
536 ( void ) xDestinationAddressLength;
\r
537 configASSERT( xNetworkEventQueue );
\r
538 configASSERT( pvBuffer );
\r
540 if( xTotalDataLength <= ipMAX_UDP_PAYLOAD_LENGTH )
\r
542 if( socketSOCKET_IS_BOUND( pxSocket ) == pdFALSE )
\r
544 /* If the socket is not already bound to an address, bind it now.
\r
545 Passing NULL as the address parameter tells FreeRTOS_bind() to
\r
546 select the address to bind to. */
\r
547 FreeRTOS_bind( pxSocket, NULL, 0 );
\r
550 if( socketSOCKET_IS_BOUND( pxSocket ) != pdFALSE )
\r
552 xTicksToWait = pxSocket->xSendBlockTime;
\r
554 if( ( ulFlags & FREERTOS_ZERO_COPY ) == 0 )
\r
556 /* Zero copy is not set, so obtain a network buffer into
\r
557 which the payload will be copied. */
\r
558 vTaskSetTimeOutState( &xTimeOut );
\r
559 pxNetworkBuffer = pxNetworkBufferGet( xTotalDataLength + sizeof( xUDPPacket_t ), xTicksToWait );
\r
561 if( pxNetworkBuffer != NULL )
\r
563 memcpy( ( void * ) &( pxNetworkBuffer->pucEthernetBuffer[ ipUDP_PAYLOAD_OFFSET ] ), ( void * ) pvBuffer, xTotalDataLength );
\r
565 if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdTRUE )
\r
567 /* The entire block time has been used up. */
\r
574 /* When zero copy is used, pvBuffer is a pointer to the
\r
575 payload of a buffer that has already been obtained from the
\r
576 stack. Obtain the network buffer pointer from the buffer. */
\r
577 pucBuffer = ( uint8_t * ) pvBuffer;
\r
578 pucBuffer -= ( ipBUFFER_PADDING + sizeof( xUDPPacket_t ) );
\r
579 pxNetworkBuffer = * ( ( xNetworkBufferDescriptor_t ** ) pucBuffer );
\r
582 if( pxNetworkBuffer != NULL )
\r
584 pxNetworkBuffer->xDataLength = xTotalDataLength;
\r
585 pxNetworkBuffer->usPort = pxDestinationAddress->sin_port;
\r
586 pxNetworkBuffer->usBoundPort = ( uint16_t ) socketGET_SOCKET_ADDRESS( pxSocket );
\r
587 pxNetworkBuffer->ulIPAddress = pxDestinationAddress->sin_addr;
\r
589 /* The socket options are passed to the IP layer in the
\r
590 space that will eventually get used by the Ethernet header. */
\r
591 pxNetworkBuffer->pucEthernetBuffer[ ipSOCKET_OPTIONS_OFFSET ] = pxSocket->ucSocketOptions;
\r
593 /* Tell the networking task that the packet needs sending. */
\r
594 xStackTxEvent.pvData = pxNetworkBuffer;
\r
596 if( xQueueSendToBack( xNetworkEventQueue, &xStackTxEvent, xTicksToWait ) != pdPASS )
\r
598 /* If the buffer was allocated in this function, release it. */
\r
599 if( ( ulFlags & FREERTOS_ZERO_COPY ) == 0 )
\r
601 vNetworkBufferRelease( pxNetworkBuffer );
\r
603 iptraceSTACK_TX_EVENT_LOST( ipSTACK_TX_EVENT );
\r
607 lReturn = ( int32_t ) xTotalDataLength;
\r
612 /* If errno was available, errno would be set to
\r
613 FREERTOS_ENOPKTS. As it is, the function must return the
\r
614 number of transmitted bytes, so the calling function knows how
\r
615 much data was actually sent. */
\r
616 iptraceNO_BUFFER_FOR_SENDTO();
\r
621 iptraceSENDTO_SOCKET_NOT_BOUND();
\r
626 /* The data is longer than the available buffer space. Setting
\r
627 ipconfigCAN_FRAGMENT_OUTGOING_PACKETS to 1 may allow this packet
\r
629 iptraceSENDTO_DATA_TOO_LONG();
\r
635 #endif /* ipconfigCAN_FRAGMENT_OUTGOING_PACKETS */
\r
636 /*-----------------------------------------------------------*/
\r
638 BaseType_t FreeRTOS_bind( xSocket_t xSocket, struct freertos_sockaddr * pxAddress, socklen_t xAddressLength )
\r
640 BaseType_t xReturn = 0; /* In Berkeley sockets, 0 means pass for bind(). */
\r
641 xFreeRTOS_Socket_t *pxSocket;
\r
642 #if ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND == 1
\r
643 struct freertos_sockaddr xAddress;
\r
644 #endif /* ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND */
\r
646 pxSocket = ( xFreeRTOS_Socket_t * ) xSocket;
\r
648 /* The function prototype is designed to maintain the expected Berkeley
\r
649 sockets standard, but this implementation does not use all the parameters. */
\r
650 ( void ) xAddressLength;
\r
652 configASSERT( xSocket );
\r
653 configASSERT( xSocket != FREERTOS_INVALID_SOCKET );
\r
655 #if ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND == 1
\r
657 /* pxAddress will be NULL if sendto() was called on a socket without the
\r
658 socket being bound to an address. In this case, automatically allocate
\r
659 an address to the socket. There is a very tiny chance that the allocated
\r
660 port will already be in use - if that is the case, then the check below
\r
661 [pxListFindListItemWithValue()] will result in an error being returned. */
\r
662 if( pxAddress == NULL )
\r
664 pxAddress = &xAddress;
\r
665 pxAddress->sin_port = prvGetPrivatePortNumber();
\r
668 #endif /* ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND == 1 */
\r
670 /* Sockets must be bound before calling FreeRTOS_sendto() if
\r
671 ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND is not set to 1. */
\r
672 configASSERT( pxAddress );
\r
674 if( pxAddress != NULL )
\r
676 if( pxAddress->sin_port == 0 )
\r
678 pxAddress->sin_port = prvGetPrivatePortNumber();
\r
683 /* Check to ensure the port is not already in use. */
\r
684 if( pxListFindListItemWithValue( &xBoundSocketsList, ( TickType_t ) pxAddress->sin_port ) != NULL )
\r
686 xReturn = FREERTOS_EADDRINUSE;
\r
691 /* Check that xReturn has not been set before continuing. */
\r
694 if( pxSocket->xWaitingPacketSemaphore == NULL )
\r
696 /* Create the semaphore used to count the number of packets that
\r
697 are queued on this socket. */
\r
698 pxSocket->xWaitingPacketSemaphore = xSemaphoreCreateCounting( ipconfigNUM_NETWORK_BUFFERS, 0 );
\r
700 if( pxSocket->xWaitingPacketSemaphore != NULL )
\r
702 /* Allocate the port number to the socket. */
\r
703 socketSET_SOCKET_ADDRESS( pxSocket, pxAddress->sin_port );
\r
704 taskENTER_CRITICAL();
\r
706 /* Add the socket to the list of bound ports. */
\r
707 vListInsertEnd( &xBoundSocketsList, &( pxSocket->xBoundSocketListItem ) );
\r
709 taskEXIT_CRITICAL();
\r
713 /* Out of memory. */
\r
714 xReturn = FREERTOS_ENOBUFS;
\r
719 /* The socket is already bound. */
\r
720 xReturn = FREERTOS_EINVAL;
\r
726 xReturn = FREERTOS_EADDRNOTAVAIL;
\r
731 iptraceBIND_FAILED( xSocket, ( FreeRTOS_ntohs( pxAddress->sin_port ) ) );
\r
736 /*-----------------------------------------------------------*/
\r
738 BaseType_t FreeRTOS_closesocket( xSocket_t xSocket )
\r
740 xNetworkBufferDescriptor_t *pxNetworkBuffer;
\r
741 xFreeRTOS_Socket_t *pxSocket;
\r
743 pxSocket = ( xFreeRTOS_Socket_t * ) xSocket;
\r
745 configASSERT( pxSocket );
\r
746 configASSERT( pxSocket != FREERTOS_INVALID_SOCKET );
\r
748 /* Socket must be unbound first, to ensure no more packets are queued on
\r
750 if( socketSOCKET_IS_BOUND( pxSocket ) != pdFALSE )
\r
752 taskENTER_CRITICAL();
\r
754 uxListRemove( &( pxSocket->xBoundSocketListItem ) );
\r
756 taskEXIT_CRITICAL();
\r
759 /* Now the socket is not bound the list of waiting packets can be
\r
761 if( pxSocket->xWaitingPacketSemaphore != NULL )
\r
763 while( listCURRENT_LIST_LENGTH( &( pxSocket->xWaitingPacketsList ) ) > 0U )
\r
765 pxNetworkBuffer = ( xNetworkBufferDescriptor_t * ) listGET_OWNER_OF_HEAD_ENTRY( &( pxSocket->xWaitingPacketsList ) );
\r
766 uxListRemove( &( pxNetworkBuffer->xBufferListItem ) );
\r
767 vNetworkBufferRelease( pxNetworkBuffer );
\r
769 vSemaphoreDelete( pxSocket->xWaitingPacketSemaphore );
\r
772 vPortFree( pxSocket );
\r
776 /*-----------------------------------------------------------*/
\r
778 void FreeRTOS_SocketsInit( void )
\r
780 vListInitialise( &xBoundSocketsList );
\r
782 /*-----------------------------------------------------------*/
\r
784 BaseType_t FreeRTOS_setsockopt( xSocket_t xSocket, int32_t lLevel, int32_t lOptionName, const void *pvOptionValue, size_t xOptionLength )
\r
786 /* The standard Berkeley function returns 0 for success. */
\r
787 BaseType_t xReturn = 0;
\r
788 BaseType_t lOptionValue;
\r
789 xFreeRTOS_Socket_t *pxSocket;
\r
791 pxSocket = ( xFreeRTOS_Socket_t * ) xSocket;
\r
793 /* The function prototype is designed to maintain the expected Berkeley
\r
794 sockets standard, but this implementation does not use all the parameters. */
\r
796 ( void ) xOptionLength;
\r
798 configASSERT( xSocket );
\r
800 switch( lOptionName )
\r
802 case FREERTOS_SO_RCVTIMEO :
\r
803 /* Receive time out. */
\r
804 pxSocket->xReceiveBlockTime = *( ( TickType_t * ) pvOptionValue );
\r
807 case FREERTOS_SO_SNDTIMEO :
\r
808 /* The send time out is capped for the reason stated in the comments
\r
809 where ipconfigMAX_SEND_BLOCK_TIME_TICKS is defined in
\r
810 FreeRTOSIPConfig.h (assuming an official configuration file is being
\r
812 pxSocket->xSendBlockTime = *( ( TickType_t * ) pvOptionValue );
\r
813 if( pxSocket->xSendBlockTime > ipconfigMAX_SEND_BLOCK_TIME_TICKS )
\r
815 pxSocket->xSendBlockTime = ipconfigMAX_SEND_BLOCK_TIME_TICKS;
\r
819 case FREERTOS_SO_UDPCKSUM_OUT :
\r
820 /* Turn calculating of the UDP checksum on/off for this socket. */
\r
821 lOptionValue = ( BaseType_t ) pvOptionValue;
\r
823 if( lOptionValue == 0 )
\r
825 pxSocket->ucSocketOptions &= ~FREERTOS_SO_UDPCKSUM_OUT;
\r
829 pxSocket->ucSocketOptions |= FREERTOS_SO_UDPCKSUM_OUT;
\r
834 /* No other options are handled. */
\r
835 xReturn = FREERTOS_ENOPROTOOPT;
\r
841 /*-----------------------------------------------------------*/
\r
843 BaseType_t xProcessReceivedUDPPacket( xNetworkBufferDescriptor_t *pxNetworkBuffer, uint16_t usPort )
\r
845 xListItem *pxListItem;
\r
846 BaseType_t xReturn = pdPASS;
\r
847 xFreeRTOS_Socket_t *pxSocket;
\r
848 BaseType_t xHigherPriorityTaskWoken = pdFALSE;
\r
852 /* See if there is a list item associated with the port number on the
\r
853 list of bound sockets. */
\r
854 pxListItem = pxListFindListItemWithValue( &xBoundSocketsList, ( TickType_t ) usPort );
\r
858 if( pxListItem != NULL )
\r
860 /* The owner of the list item is the socket itself. */
\r
861 pxSocket = ( xFreeRTOS_Socket_t * ) listGET_LIST_ITEM_OWNER( pxListItem );
\r
865 #if( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
\r
867 /* Is the socket a member of a select() group? */
\r
868 if( pxSocket->xSelectQueue != NULL )
\r
870 /* Can the select group be notified that the socket is
\r
871 ready to be read? */
\r
872 if( xQueueSendFromISR( pxSocket->xSelectQueue, &pxSocket, &xHigherPriorityTaskWoken ) != pdPASS )
\r
874 /* Could not notify the select group. */
\r
876 iptraceFAILED_TO_NOTIFY_SELECT_GROUP( pxSocket );
\r
882 if( xReturn == pdPASS )
\r
884 taskENTER_CRITICAL();
\r
886 /* Add the network packet to the list of packets to be
\r
887 processed by the socket. */
\r
888 vListInsertEnd( &( pxSocket->xWaitingPacketsList ), &( pxNetworkBuffer->xBufferListItem ) );
\r
890 taskEXIT_CRITICAL();
\r
892 /* The socket's counting semaphore records how many packets are
\r
893 waiting to be processed by the socket. */
\r
894 xSemaphoreGiveFromISR( pxSocket->xWaitingPacketSemaphore, &xHigherPriorityTaskWoken );
\r
897 if( xTaskResumeAll() == pdFALSE )
\r
899 if( xHigherPriorityTaskWoken != pdFALSE )
\r
912 /*-----------------------------------------------------------*/
\r
914 static uint16_t prvGetPrivatePortNumber( void )
\r
916 static uint16_t usNextPortToUse = socketAUTO_PORT_ALLOCATION_START_NUMBER - 1;
\r
919 /* Assign the next port in the range. */
\r
920 taskENTER_CRITICAL();
\r
924 /* Has it overflowed? */
\r
925 if( usNextPortToUse == 0U )
\r
927 /* Don't go right back to the start of the dynamic/private port
\r
928 range numbers as any persistent sockets are likely to have been
\r
929 create first so the early port numbers may still be in use. */
\r
930 usNextPortToUse = socketAUTO_PORT_ALLOCATION_RESET_NUMBER;
\r
933 usReturn = FreeRTOS_htons( usNextPortToUse );
\r
935 taskEXIT_CRITICAL();
\r
939 /*-----------------------------------------------------------*/
\r
941 xListItem * pxListFindListItemWithValue( xList *pxList, TickType_t xWantedItemValue )
\r
943 xListItem *pxIterator, *pxReturn;
\r
946 for( pxIterator = ( xListItem * ) pxList->xListEnd.pxNext; pxIterator != ( xListItem* ) &( pxList->xListEnd ); pxIterator = ( xListItem * ) pxIterator->pxNext )
\r
948 if( pxIterator->xItemValue == xWantedItemValue )
\r
950 pxReturn = pxIterator;
\r
957 /*-----------------------------------------------------------*/
\r
959 #if ipconfigINCLUDE_FULL_INET_ADDR == 1
\r
961 uint32_t FreeRTOS_inet_addr( const char *pcIPAddress )
\r
963 const uint8_t ucDecimalBase = 10;
\r
964 uint8_t ucOctet[ socketMAX_IP_ADDRESS_OCTETS ];
\r
965 const char *pcPointerOnEntering;
\r
966 uint32_t ulReturn = 0UL, ulOctetNumber, ulValue;
\r
967 BaseType_t xResult = pdPASS;
\r
969 for( ulOctetNumber = 0; ulOctetNumber < socketMAX_IP_ADDRESS_OCTETS; ulOctetNumber++ )
\r
972 pcPointerOnEntering = pcIPAddress;
\r
974 while( ( *pcIPAddress >= ( uint8_t ) '0' ) && ( *pcIPAddress <= ( uint8_t ) '9' ) )
\r
976 /* Move previous read characters into the next decimal
\r
978 ulValue *= ucDecimalBase;
\r
980 /* Add the binary value of the ascii character. */
\r
981 ulValue += ( *pcIPAddress - ( uint8_t ) '0' );
\r
983 /* Move to next character in the string. */
\r
987 /* Check characters were read. */
\r
988 if( pcIPAddress == pcPointerOnEntering )
\r
993 /* Check the value fits in an 8-bit number. */
\r
994 if( ulValue > 0xffUL )
\r
1000 ucOctet[ ulOctetNumber ] = ( uint8_t ) ulValue;
\r
1002 /* Check the next character is as expected. */
\r
1003 if( ulOctetNumber < ( socketMAX_IP_ADDRESS_OCTETS - 1 ) )
\r
1005 if( *pcIPAddress != ( uint8_t ) '.' )
\r
1011 /* Move past the dot. */
\r
1017 if( xResult == pdFAIL )
\r
1019 /* No point going on. */
\r
1024 if( *pcIPAddress != ( uint8_t ) 0x00 )
\r
1026 /* Expected the end of the string. */
\r
1030 if( ulOctetNumber != socketMAX_IP_ADDRESS_OCTETS )
\r
1032 /* Didn't read enough octets. */
\r
1036 if( xResult == pdPASS )
\r
1038 ulReturn = FreeRTOS_inet_addr_quick( ucOctet[ 0 ], ucOctet[ 1 ], ucOctet[ 2 ], ucOctet[ 3 ] );
\r
1044 #endif /* ipconfigINCLUDE_FULL_INET_ADDR */
\r
1045 /*-----------------------------------------------------------*/
\r