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.
\r
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
\r
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
\r
17 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
\r
18 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
\r
19 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
\r
20 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\r
22 * http://www.FreeRTOS.org
\r
23 * http://aws.amazon.com/freertos
\r
25 * 1 tab == 4 spaces!
\r
28 /* Standard includes. */
\r
31 /* FreeRTOS includes. */
\r
32 #include "FreeRTOS.h"
\r
37 /* FreeRTOS+UDP includes. */
\r
38 #include "FreeRTOS_UDP_IP.h"
\r
39 #include "FreeRTOS_IP_Private.h"
\r
40 #include "FreeRTOS_Sockets.h"
\r
41 #include "NetworkBufferManagement.h"
\r
43 /* Sanity check the UDP payload length setting is compatible with the
\r
44 fragmentation setting. */
\r
45 #if ipconfigCAN_FRAGMENT_OUTGOING_PACKETS == 1
\r
46 #if ( ( ipMAX_UDP_PAYLOAD_LENGTH % 8 ) != 0 )
\r
47 #error ( ipconfigNETWORK_MTU - 28 ) must be divisible by 8 when fragmentation is used
\r
48 #endif /* ipMAX_UDP_PAYLOAD_LENGTH */
\r
49 #endif /* ipconfigFRAGMENT_OUTGOING_PACKETS */
\r
51 /* The ItemValue of the sockets xBoundSocketListItem member holds the socket's
\r
53 #define socketSET_SOCKET_ADDRESS( pxSocket, usPort ) listSET_LIST_ITEM_VALUE( ( &( ( pxSocket )->xBoundSocketListItem ) ), ( usPort ) )
\r
54 #define socketGET_SOCKET_ADDRESS( pxSocket ) listGET_LIST_ITEM_VALUE( ( &( ( pxSocket )->xBoundSocketListItem ) ) )
\r
56 /* xWaitingPacketSemaphore is not created until the socket is bound, so can be
\r
57 tested to see if bind() has been called. */
\r
58 #define socketSOCKET_IS_BOUND( pxSocket ) ( ( BaseType_t ) pxSocket->xWaitingPacketSemaphore )
\r
60 /* If FreeRTOS_sendto() is called on a socket that is not bound to a port
\r
61 number then, depending on the FreeRTOSIPConfig.h settings, it might be that a
\r
62 port number is automatically generated for the socket. Automatically generated
\r
63 port numbers will be between socketAUTO_PORT_ALLOCATION_START_NUMBER and
\r
65 #define socketAUTO_PORT_ALLOCATION_START_NUMBER ( ( uint16_t ) 0xc000 )
\r
67 /* When the automatically generated port numbers overflow, the next value used
\r
68 is not set back to socketAUTO_PORT_ALLOCATION_START_NUMBER because it is likely
\r
69 that the first few automatically generated ports will still be in use. Instead
\r
70 it is reset back to the value defined by this constant. */
\r
71 #define socketAUTO_PORT_ALLOCATION_RESET_NUMBER ( ( uint16_t ) 0xc100 )
\r
73 /* The number of octets that make up an IP address. */
\r
74 #define socketMAX_IP_ADDRESS_OCTETS 4
\r
75 /*-----------------------------------------------------------*/
\r
78 * Allocate the next port number from the private allocation range.
\r
80 static uint16_t prvGetPrivatePortNumber( void );
\r
83 * Return the list itme from within pxList that has an item value of
\r
84 * xWantedItemValue. If there is no such list item return NULL.
\r
86 xListItem * pxListFindListItemWithValue( xList *pxList, TickType_t xWantedItemValue );
\r
88 /*-----------------------------------------------------------*/
\r
90 typedef struct XSOCKET
\r
92 xSemaphoreHandle xWaitingPacketSemaphore;
\r
93 xList xWaitingPacketsList;
\r
94 xListItem xBoundSocketListItem; /* Used to reference the socket from a bound sockets list. */
\r
95 TickType_t xReceiveBlockTime;
\r
96 TickType_t xSendBlockTime;
\r
97 uint8_t ucSocketOptions;
\r
98 #if ipconfigSUPPORT_SELECT_FUNCTION == 1
\r
99 xQueueHandle xSelectQueue;
\r
101 } xFreeRTOS_Socket_t;
\r
104 /* The list that contains mappings between sockets and port numbers. Accesses
\r
105 to this list must be protected by critical sections of one kind or another. */
\r
106 static xList xBoundSocketsList;
\r
108 /*-----------------------------------------------------------*/
\r
110 xSocket_t FreeRTOS_socket( BaseType_t xDomain, BaseType_t xType, BaseType_t xProtocol )
\r
112 xFreeRTOS_Socket_t *pxSocket;
\r
114 /* Only UDP on Ethernet is currently supported. */
\r
115 configASSERT( xDomain == FREERTOS_AF_INET );
\r
116 configASSERT( xType == FREERTOS_SOCK_DGRAM );
\r
117 configASSERT( xProtocol == FREERTOS_IPPROTO_UDP );
\r
118 configASSERT( listLIST_IS_INITIALISED( &xBoundSocketsList ) );
\r
120 /* Allocate the structure that will hold the socket information. */
\r
121 pxSocket = ( xFreeRTOS_Socket_t * ) pvPortMalloc( sizeof( xFreeRTOS_Socket_t ) );
\r
123 if( pxSocket == NULL )
\r
125 pxSocket = ( xFreeRTOS_Socket_t * ) FREERTOS_INVALID_SOCKET;
\r
126 iptraceFAILED_TO_CREATE_SOCKET();
\r
130 /* Initialise the socket's members. The semaphore will be created if
\r
131 the socket is bound to an address, for now the pointer to the semaphore
\r
132 is just set to NULL to show it has not been created. */
\r
133 pxSocket->xWaitingPacketSemaphore = NULL;
\r
134 vListInitialise( &( pxSocket->xWaitingPacketsList ) );
\r
135 vListInitialiseItem( &( pxSocket->xBoundSocketListItem ) );
\r
136 listSET_LIST_ITEM_OWNER( &( pxSocket->xBoundSocketListItem ), ( void * ) pxSocket );
\r
137 pxSocket->xSendBlockTime = ( TickType_t ) 0;
\r
138 pxSocket->xReceiveBlockTime = portMAX_DELAY;
\r
139 pxSocket->ucSocketOptions = FREERTOS_SO_UDPCKSUM_OUT;
\r
140 #if ipconfigSUPPORT_SELECT_FUNCTION == 1
\r
141 pxSocket->xSelectQueue = NULL;
\r
145 /* Remove compiler warnings in the case the configASSERT() is not defined. */
\r
148 ( void ) xProtocol;
\r
150 return ( xSocket_t ) pxSocket;
\r
152 /*-----------------------------------------------------------*/
\r
154 #if ipconfigSUPPORT_SELECT_FUNCTION == 1
\r
156 xSocketSet_t FreeRTOS_CreateSocketSet( UBaseType_t uxEventQueueLength )
\r
158 xQueueHandle xSelectQueue;
\r
160 /* Create the queue into which the address of sockets that are
\r
161 available to read are posted. */
\r
162 xSelectQueue = xQueueCreate( uxEventQueueLength, sizeof( xSocket_t ) );
\r
164 return ( xSocketSet_t ) xSelectQueue;
\r
167 #endif /* ipconfigSUPPORT_SELECT_FUNCTION */
\r
168 /*-----------------------------------------------------------*/
\r
170 #if ipconfigSUPPORT_SELECT_FUNCTION == 1
\r
172 BaseType_t FreeRTOS_FD_SET( xSocket_t xSocket, xSocketSet_t xSocketSet )
\r
174 xFreeRTOS_Socket_t *pxSocket = ( xFreeRTOS_Socket_t * ) xSocket;
\r
175 BaseType_t xReturn = pdFALSE;
\r
176 UBaseType_t uxMessagesWaiting;
\r
178 configASSERT( xSocket );
\r
180 /* Is the socket already a member of a select group? */
\r
181 if( pxSocket->xSelectQueue == NULL )
\r
183 taskENTER_CRITICAL();
\r
185 /* Are there packets queued on the socket already? */
\r
186 uxMessagesWaiting = uxQueueMessagesWaiting( pxSocket->xWaitingPacketSemaphore );
\r
188 /* Are there enough notification spaces in the select queue for the
\r
189 number of packets already queued on the socket? */
\r
190 if( uxQueueSpacesAvailable( ( xQueueHandle ) xSocketSet ) >= uxMessagesWaiting )
\r
192 /* Store a pointer to the select group in the socket for
\r
193 future reference. */
\r
194 pxSocket->xSelectQueue = ( xQueueHandle ) xSocketSet;
\r
196 while( uxMessagesWaiting > 0 )
\r
198 /* Add notifications of the number of packets that are
\r
199 already queued on the socket to the select queue. */
\r
200 xQueueSendFromISR( pxSocket->xSelectQueue, &pxSocket, NULL );
\r
201 uxMessagesWaiting--;
\r
207 taskEXIT_CRITICAL();
\r
213 #endif /* ipconfigSUPPORT_SELECT_FUNCTION */
\r
214 /*-----------------------------------------------------------*/
\r
216 #if ipconfigSUPPORT_SELECT_FUNCTION == 1
\r
218 BaseType_t FreeRTOS_FD_CLR( xSocket_t xSocket, xSocketSet_t xSocketSet )
\r
220 xFreeRTOS_Socket_t *pxSocket = ( xFreeRTOS_Socket_t * ) xSocket;
\r
221 BaseType_t xReturn;
\r
223 /* Is the socket a member of the select group? */
\r
224 if( pxSocket->xSelectQueue == ( xQueueHandle ) xSocketSet )
\r
226 /* The socket is no longer a member of the select group. */
\r
227 pxSocket->xSelectQueue = NULL;
\r
238 #endif /* ipconfigSUPPORT_SELECT_FUNCTION */
\r
239 /*-----------------------------------------------------------*/
\r
241 #if ipconfigSUPPORT_SELECT_FUNCTION == 1
\r
243 xSocket_t FreeRTOS_select( xSocketSet_t xSocketSet, TickType_t xBlockTimeTicks )
\r
245 xFreeRTOS_Socket_t *pxSocket;
\r
247 /* Wait for a socket to be ready to read. */
\r
248 if( xQueueReceive( ( xQueueHandle ) xSocketSet, &pxSocket, xBlockTimeTicks ) != pdPASS )
\r
253 return ( xSocket_t ) pxSocket;
\r
256 #endif /* ipconfigSUPPORT_SELECT_FUNCTION */
\r
257 /*-----------------------------------------------------------*/
\r
259 int32_t FreeRTOS_recvfrom( xSocket_t xSocket, void *pvBuffer, size_t xBufferLength, uint32_t ulFlags, struct freertos_sockaddr *pxSourceAddress, socklen_t *pxSourceAddressLength )
\r
261 xNetworkBufferDescriptor_t *pxNetworkBuffer;
\r
263 xFreeRTOS_Socket_t *pxSocket;
\r
265 pxSocket = ( xFreeRTOS_Socket_t * ) xSocket;
\r
267 /* The function prototype is designed to maintain the expected Berkeley
\r
268 sockets standard, but this implementation does not use all the parameters. */
\r
269 ( void ) pxSourceAddressLength;
\r
271 if( socketSOCKET_IS_BOUND( pxSocket ) != pdFALSE )
\r
273 /* The semaphore is given when received data is queued on the socket. */
\r
274 if( xSemaphoreTake( pxSocket->xWaitingPacketSemaphore, pxSocket->xReceiveBlockTime ) == pdPASS )
\r
276 taskENTER_CRITICAL();
\r
278 configASSERT( ( listCURRENT_LIST_LENGTH( &( pxSocket->xWaitingPacketsList ) ) > 0U ) );
\r
280 /* The owner of the list item is the network buffer. */
\r
281 pxNetworkBuffer = ( xNetworkBufferDescriptor_t * ) listGET_OWNER_OF_HEAD_ENTRY( &( pxSocket->xWaitingPacketsList ) );
\r
283 /* Remove the network buffer from the list of buffers waiting to
\r
284 be processed by the socket. */
\r
285 uxListRemove( &( pxNetworkBuffer->xBufferListItem ) );
\r
287 taskEXIT_CRITICAL();
\r
289 if( ( ulFlags & FREERTOS_ZERO_COPY ) == 0 )
\r
291 /* The zero copy flag is not set. Truncate the length if it
\r
292 won't fit in the provided buffer. */
\r
293 if( pxNetworkBuffer->xDataLength > xBufferLength )
\r
295 iptraceRECVFROM_DISCARDING_BYTES( ( xBufferLength - pxNetworkBuffer->xDataLength ) );
\r
296 pxNetworkBuffer->xDataLength = xBufferLength;
\r
299 /* Copy the received data into the provided buffer, then
\r
300 release the network buffer. */
\r
301 memcpy( pvBuffer, ( void * ) &( pxNetworkBuffer->pucEthernetBuffer[ ipUDP_PAYLOAD_OFFSET ] ), pxNetworkBuffer->xDataLength );
\r
302 vNetworkBufferRelease( pxNetworkBuffer );
\r
306 /* The zero copy flag was set. pvBuffer is not a buffer into
\r
307 which the received data can be copied, but a pointer that must
\r
308 be set to point to the buffer in which the received data has
\r
309 already been placed. */
\r
310 *( ( void** ) pvBuffer ) = ( void * ) ( &( pxNetworkBuffer->pucEthernetBuffer[ ipUDP_PAYLOAD_OFFSET ] ) );
\r
313 /* The returned value is the data length, which may have been
\r
314 capped to the receive buffer size. */
\r
315 lReturn = ( int32_t ) pxNetworkBuffer->xDataLength;
\r
317 if( pxSourceAddress != NULL )
\r
319 pxSourceAddress->sin_port = pxNetworkBuffer->usPort;
\r
320 pxSourceAddress->sin_addr = pxNetworkBuffer->ulIPAddress;
\r
325 lReturn = FREERTOS_EWOULDBLOCK;
\r
326 iptraceRECVFROM_TIMEOUT();
\r
331 lReturn = FREERTOS_EINVAL;
\r
336 /*-----------------------------------------------------------*/
\r
338 #if ipconfigCAN_FRAGMENT_OUTGOING_PACKETS == 1
\r
340 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
342 xNetworkBufferDescriptor_t *pxNetworkBuffer;
\r
343 xIPFragmentParameters_t *pxFragmentParameters;
\r
344 size_t xBytesToSend, xBytesRemaining;
\r
345 xIPStackEvent_t xStackTxEvent = { eStackTxEvent, NULL };
\r
346 extern xQueueHandle xNetworkEventQueue;
\r
347 uint8_t *pucBuffer;
\r
348 xTimeOutType xTimeOut;
\r
349 TickType_t xTicksToWait;
\r
350 uint16_t usFragmentOffset;
\r
351 xFreeRTOS_Socket_t *pxSocket;
\r
353 pxSocket = ( xFreeRTOS_Socket_t * ) xSocket;
\r
355 /* The function prototype is designed to maintain the expected Berkeley
\r
356 sockets standard, but this implementation does not use all the
\r
358 ( void ) xDestinationAddressLength;
\r
359 configASSERT( xNetworkEventQueue );
\r
360 configASSERT( pvBuffer );
\r
362 xBytesRemaining = xTotalDataLength;
\r
364 if( socketSOCKET_IS_BOUND( pxSocket ) == pdFALSE )
\r
366 /* If the socket is not already bound to an address, bind it now.
\r
367 Passing NULL as the address parameter tells FreeRTOS_bind() to select
\r
368 the address to bind to. */
\r
369 FreeRTOS_bind( xSocket, NULL, 0 );
\r
372 if( socketSOCKET_IS_BOUND( pxSocket ) != pdFALSE )
\r
374 /* pucBuffer will be reset if this send turns out to be a zero copy
\r
375 send because in that case pvBuffer is actually a pointer to an
\r
376 xUserData_t structure, not the UDP payload. */
\r
377 pucBuffer = ( uint8_t * ) pvBuffer;
\r
378 vTaskSetTimeOutState( &xTimeOut );
\r
379 xTicksToWait = pxSocket->xSendBlockTime;
\r
381 /* The data being transmitted will be sent in
\r
382 ipMAX_UDP_PAYLOAD_LENGTH chunks if xDataLength is greater than the
\r
383 network buffer payload size. Loop until all the data is sent. */
\r
384 while( xBytesRemaining > 0 )
\r
386 if( xBytesRemaining > ipMAX_UDP_PAYLOAD_LENGTH )
\r
388 /* Cap the amount being sent in this packet to the maximum
\r
389 UDP payload size. This will be a multiple of 8 already,
\r
390 removing the need to check in the code. */
\r
391 xBytesToSend = ipMAX_UDP_PAYLOAD_LENGTH;
\r
395 /* Send all remaining bytes - which may well be the total
\r
396 number of bytes if the packet was not chopped up. */
\r
397 xBytesToSend = xBytesRemaining;
\r
400 /* If the zero copy flag is set, then the data is already in a
\r
401 network buffer. Otherwise, get a new network buffer. */
\r
402 if( ( ulFlags & FREERTOS_ZERO_COPY ) == 0 )
\r
404 if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdTRUE )
\r
409 pxNetworkBuffer = pxNetworkBufferGet( xBytesToSend + sizeof( xUDPPacket_t ), xTicksToWait );
\r
413 if( xTotalDataLength > ipMAX_UDP_PAYLOAD_LENGTH )
\r
415 /* The packet needs fragmenting, but zero copy buffers
\r
416 cannot be fragmented. */
\r
417 pxNetworkBuffer = NULL;
\r
421 /* When zero copy is used, pvBuffer is a pointer to the
\r
422 payload of a buffer that has already been obtained from the
\r
423 stack. Obtain the network buffer pointer from the buffer. */
\r
424 pucBuffer = ( uint8_t * ) pvBuffer;
\r
425 pucBuffer -= ( ipBUFFER_PADDING + sizeof( xUDPPacket_t ) );
\r
426 pxNetworkBuffer = * ( ( xNetworkBufferDescriptor_t ** ) pucBuffer );
\r
430 if( pxNetworkBuffer != NULL )
\r
432 /* Use the part of the network buffer that will be completed
\r
433 by the IP layer as temporary storage to pass extra
\r
434 information required by the IP layer. */
\r
435 pxFragmentParameters = ( xIPFragmentParameters_t * ) &( pxNetworkBuffer->pucEthernetBuffer[ ipFRAGMENTATION_PARAMETERS_OFFSET ] );
\r
436 pxFragmentParameters->ucSocketOptions = pxSocket->ucSocketOptions;
\r
438 if( xBytesRemaining > ipMAX_UDP_PAYLOAD_LENGTH )
\r
440 /* The packet is being chopped up, and more data will
\r
442 pxFragmentParameters->ucSocketOptions = ( pxSocket->ucSocketOptions | FREERTOS_NOT_LAST_IN_FRAGMENTED_PACKET );
\r
445 if( xTotalDataLength > ipMAX_UDP_PAYLOAD_LENGTH )
\r
447 /* Let the IP layer know this packet has been chopped up,
\r
448 and supply the IP layer with any addition information it
\r
449 needs to make sense of it. */
\r
450 pxFragmentParameters->ucSocketOptions |= FREERTOS_FRAGMENTED_PACKET;
\r
451 usFragmentOffset = ( uint16_t ) ( xTotalDataLength - xBytesRemaining );
\r
452 pxFragmentParameters->usFragmentedPacketOffset = usFragmentOffset;
\r
453 pxFragmentParameters->usFragmentLength = ( uint16_t ) xBytesToSend;
\r
457 usFragmentOffset = 0;
\r
460 /* Write the payload into the packet. The IP layer is
\r
461 queried to find where in the IP payload the data should be
\r
462 written. This is because the necessary offset is different
\r
463 for the first packet, because the first packet leaves space
\r
464 for a UDP header. Note that this changes usFragmentOffset
\r
465 from the offset in the entire UDP packet, to the offset
\r
466 in the IP packet. */
\r
467 if( ( ulFlags & FREERTOS_ZERO_COPY ) == 0 )
\r
469 /* Only copy the data if it is not already in the
\r
470 expected location. */
\r
471 usFragmentOffset = ipGET_UDP_PAYLOAD_OFFSET_FOR_FRAGMENT( usFragmentOffset );
\r
472 memcpy( ( void * ) &( pxNetworkBuffer->pucEthernetBuffer[ usFragmentOffset ] ), ( void * ) pucBuffer, xBytesToSend );
\r
474 pxNetworkBuffer->xDataLength = xTotalDataLength;
\r
475 pxNetworkBuffer->usPort = pxDestinationAddress->sin_port;
\r
476 pxNetworkBuffer->usBoundPort = ( uint16_t ) socketGET_SOCKET_ADDRESS( pxSocket );
\r
477 pxNetworkBuffer->ulIPAddress = pxDestinationAddress->sin_addr;
\r
479 /* Tell the networking task that the packet needs sending. */
\r
480 xStackTxEvent.pvData = pxNetworkBuffer;
\r
482 if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdTRUE )
\r
487 if( xQueueSendToBack( xNetworkEventQueue, &xStackTxEvent, xTicksToWait ) != pdPASS )
\r
489 /* If the buffer was allocated in this function, release it. */
\r
490 if( ( ulFlags & FREERTOS_ZERO_COPY ) == 0 )
\r
492 vNetworkBufferRelease( pxNetworkBuffer );
\r
494 iptraceSTACK_TX_EVENT_LOST( ipSTACK_TX_EVENT );
\r
498 /* Adjust counters ready to either exit the loop, or send
\r
499 another chunk of data. */
\r
500 xBytesRemaining -= xBytesToSend;
\r
501 pucBuffer += xBytesToSend;
\r
505 /* If errno was available, errno would be set to
\r
506 FREERTOS_ENOPKTS. As it is, the function must return the
\r
507 number of transmitted bytes, so the calling function knows how
\r
508 much data was actually sent. */
\r
514 return ( xTotalDataLength - xBytesRemaining );
\r
517 #else /* ipconfigCAN_FRAGMENT_OUTGOING_PACKETS */
\r
519 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
521 xNetworkBufferDescriptor_t *pxNetworkBuffer;
\r
522 xIPStackEvent_t xStackTxEvent = { eStackTxEvent, NULL };
\r
523 extern xQueueHandle xNetworkEventQueue;
\r
524 xTimeOutType xTimeOut;
\r
525 TickType_t xTicksToWait;
\r
526 int32_t lReturn = 0;
\r
527 xFreeRTOS_Socket_t *pxSocket;
\r
528 uint8_t *pucBuffer;
\r
530 pxSocket = ( xFreeRTOS_Socket_t * ) xSocket;
\r
532 /* The function prototype is designed to maintain the expected Berkeley
\r
533 sockets standard, but this implementation does not use all the
\r
535 ( void ) xDestinationAddressLength;
\r
536 configASSERT( xNetworkEventQueue );
\r
537 configASSERT( pvBuffer );
\r
539 if( xTotalDataLength <= ipMAX_UDP_PAYLOAD_LENGTH )
\r
541 if( socketSOCKET_IS_BOUND( pxSocket ) == pdFALSE )
\r
543 /* If the socket is not already bound to an address, bind it now.
\r
544 Passing NULL as the address parameter tells FreeRTOS_bind() to
\r
545 select the address to bind to. */
\r
546 FreeRTOS_bind( pxSocket, NULL, 0 );
\r
549 if( socketSOCKET_IS_BOUND( pxSocket ) != pdFALSE )
\r
551 xTicksToWait = pxSocket->xSendBlockTime;
\r
553 if( ( ulFlags & FREERTOS_ZERO_COPY ) == 0 )
\r
555 /* Zero copy is not set, so obtain a network buffer into
\r
556 which the payload will be copied. */
\r
557 vTaskSetTimeOutState( &xTimeOut );
\r
558 pxNetworkBuffer = pxNetworkBufferGet( xTotalDataLength + sizeof( xUDPPacket_t ), xTicksToWait );
\r
560 if( pxNetworkBuffer != NULL )
\r
562 memcpy( ( void * ) &( pxNetworkBuffer->pucEthernetBuffer[ ipUDP_PAYLOAD_OFFSET ] ), ( void * ) pvBuffer, xTotalDataLength );
\r
564 if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdTRUE )
\r
566 /* The entire block time has been used up. */
\r
573 /* When zero copy is used, pvBuffer is a pointer to the
\r
574 payload of a buffer that has already been obtained from the
\r
575 stack. Obtain the network buffer pointer from the buffer. */
\r
576 pucBuffer = ( uint8_t * ) pvBuffer;
\r
577 pucBuffer -= ( ipBUFFER_PADDING + sizeof( xUDPPacket_t ) );
\r
578 pxNetworkBuffer = * ( ( xNetworkBufferDescriptor_t ** ) pucBuffer );
\r
581 if( pxNetworkBuffer != NULL )
\r
583 pxNetworkBuffer->xDataLength = xTotalDataLength;
\r
584 pxNetworkBuffer->usPort = pxDestinationAddress->sin_port;
\r
585 pxNetworkBuffer->usBoundPort = ( uint16_t ) socketGET_SOCKET_ADDRESS( pxSocket );
\r
586 pxNetworkBuffer->ulIPAddress = pxDestinationAddress->sin_addr;
\r
588 /* The socket options are passed to the IP layer in the
\r
589 space that will eventually get used by the Ethernet header. */
\r
590 pxNetworkBuffer->pucEthernetBuffer[ ipSOCKET_OPTIONS_OFFSET ] = pxSocket->ucSocketOptions;
\r
592 /* Tell the networking task that the packet needs sending. */
\r
593 xStackTxEvent.pvData = pxNetworkBuffer;
\r
595 if( xQueueSendToBack( xNetworkEventQueue, &xStackTxEvent, xTicksToWait ) != pdPASS )
\r
597 /* If the buffer was allocated in this function, release it. */
\r
598 if( ( ulFlags & FREERTOS_ZERO_COPY ) == 0 )
\r
600 vNetworkBufferRelease( pxNetworkBuffer );
\r
602 iptraceSTACK_TX_EVENT_LOST( ipSTACK_TX_EVENT );
\r
606 lReturn = ( int32_t ) xTotalDataLength;
\r
611 /* If errno was available, errno would be set to
\r
612 FREERTOS_ENOPKTS. As it is, the function must return the
\r
613 number of transmitted bytes, so the calling function knows how
\r
614 much data was actually sent. */
\r
615 iptraceNO_BUFFER_FOR_SENDTO();
\r
620 iptraceSENDTO_SOCKET_NOT_BOUND();
\r
625 /* The data is longer than the available buffer space. Setting
\r
626 ipconfigCAN_FRAGMENT_OUTGOING_PACKETS to 1 may allow this packet
\r
628 iptraceSENDTO_DATA_TOO_LONG();
\r
634 #endif /* ipconfigCAN_FRAGMENT_OUTGOING_PACKETS */
\r
635 /*-----------------------------------------------------------*/
\r
637 BaseType_t FreeRTOS_bind( xSocket_t xSocket, struct freertos_sockaddr * pxAddress, socklen_t xAddressLength )
\r
639 BaseType_t xReturn = 0; /* In Berkeley sockets, 0 means pass for bind(). */
\r
640 xFreeRTOS_Socket_t *pxSocket;
\r
641 #if ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND == 1
\r
642 struct freertos_sockaddr xAddress;
\r
643 #endif /* ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND */
\r
645 pxSocket = ( xFreeRTOS_Socket_t * ) xSocket;
\r
647 /* The function prototype is designed to maintain the expected Berkeley
\r
648 sockets standard, but this implementation does not use all the parameters. */
\r
649 ( void ) xAddressLength;
\r
651 configASSERT( xSocket );
\r
652 configASSERT( xSocket != FREERTOS_INVALID_SOCKET );
\r
654 #if ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND == 1
\r
656 /* pxAddress will be NULL if sendto() was called on a socket without the
\r
657 socket being bound to an address. In this case, automatically allocate
\r
658 an address to the socket. There is a very tiny chance that the allocated
\r
659 port will already be in use - if that is the case, then the check below
\r
660 [pxListFindListItemWithValue()] will result in an error being returned. */
\r
661 if( pxAddress == NULL )
\r
663 pxAddress = &xAddress;
\r
664 pxAddress->sin_port = prvGetPrivatePortNumber();
\r
667 #endif /* ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND == 1 */
\r
669 /* Sockets must be bound before calling FreeRTOS_sendto() if
\r
670 ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND is not set to 1. */
\r
671 configASSERT( pxAddress );
\r
673 if( pxAddress != NULL )
\r
675 if( pxAddress->sin_port == 0 )
\r
677 pxAddress->sin_port = prvGetPrivatePortNumber();
\r
682 /* Check to ensure the port is not already in use. */
\r
683 if( pxListFindListItemWithValue( &xBoundSocketsList, ( TickType_t ) pxAddress->sin_port ) != NULL )
\r
685 xReturn = FREERTOS_EADDRINUSE;
\r
690 /* Check that xReturn has not been set before continuing. */
\r
693 if( pxSocket->xWaitingPacketSemaphore == NULL )
\r
695 /* Create the semaphore used to count the number of packets that
\r
696 are queued on this socket. */
\r
697 pxSocket->xWaitingPacketSemaphore = xSemaphoreCreateCounting( ipconfigNUM_NETWORK_BUFFERS, 0 );
\r
699 if( pxSocket->xWaitingPacketSemaphore != NULL )
\r
701 /* Allocate the port number to the socket. */
\r
702 socketSET_SOCKET_ADDRESS( pxSocket, pxAddress->sin_port );
\r
703 taskENTER_CRITICAL();
\r
705 /* Add the socket to the list of bound ports. */
\r
706 vListInsertEnd( &xBoundSocketsList, &( pxSocket->xBoundSocketListItem ) );
\r
708 taskEXIT_CRITICAL();
\r
712 /* Out of memory. */
\r
713 xReturn = FREERTOS_ENOBUFS;
\r
718 /* The socket is already bound. */
\r
719 xReturn = FREERTOS_EINVAL;
\r
725 xReturn = FREERTOS_EADDRNOTAVAIL;
\r
730 iptraceBIND_FAILED( xSocket, ( FreeRTOS_ntohs( pxAddress->sin_port ) ) );
\r
735 /*-----------------------------------------------------------*/
\r
737 BaseType_t FreeRTOS_closesocket( xSocket_t xSocket )
\r
739 xNetworkBufferDescriptor_t *pxNetworkBuffer;
\r
740 xFreeRTOS_Socket_t *pxSocket;
\r
742 pxSocket = ( xFreeRTOS_Socket_t * ) xSocket;
\r
744 configASSERT( pxSocket );
\r
745 configASSERT( pxSocket != FREERTOS_INVALID_SOCKET );
\r
747 /* Socket must be unbound first, to ensure no more packets are queued on
\r
749 if( socketSOCKET_IS_BOUND( pxSocket ) != pdFALSE )
\r
751 taskENTER_CRITICAL();
\r
753 uxListRemove( &( pxSocket->xBoundSocketListItem ) );
\r
755 taskEXIT_CRITICAL();
\r
758 /* Now the socket is not bound the list of waiting packets can be
\r
760 if( pxSocket->xWaitingPacketSemaphore != NULL )
\r
762 while( listCURRENT_LIST_LENGTH( &( pxSocket->xWaitingPacketsList ) ) > 0U )
\r
764 pxNetworkBuffer = ( xNetworkBufferDescriptor_t * ) listGET_OWNER_OF_HEAD_ENTRY( &( pxSocket->xWaitingPacketsList ) );
\r
765 uxListRemove( &( pxNetworkBuffer->xBufferListItem ) );
\r
766 vNetworkBufferRelease( pxNetworkBuffer );
\r
768 vSemaphoreDelete( pxSocket->xWaitingPacketSemaphore );
\r
771 vPortFree( pxSocket );
\r
775 /*-----------------------------------------------------------*/
\r
777 void FreeRTOS_SocketsInit( void )
\r
779 vListInitialise( &xBoundSocketsList );
\r
781 /*-----------------------------------------------------------*/
\r
783 BaseType_t FreeRTOS_setsockopt( xSocket_t xSocket, int32_t lLevel, int32_t lOptionName, const void *pvOptionValue, size_t xOptionLength )
\r
785 /* The standard Berkeley function returns 0 for success. */
\r
786 BaseType_t xReturn = 0;
\r
787 BaseType_t lOptionValue;
\r
788 xFreeRTOS_Socket_t *pxSocket;
\r
790 pxSocket = ( xFreeRTOS_Socket_t * ) xSocket;
\r
792 /* The function prototype is designed to maintain the expected Berkeley
\r
793 sockets standard, but this implementation does not use all the parameters. */
\r
795 ( void ) xOptionLength;
\r
797 configASSERT( xSocket );
\r
799 switch( lOptionName )
\r
801 case FREERTOS_SO_RCVTIMEO :
\r
802 /* Receive time out. */
\r
803 pxSocket->xReceiveBlockTime = *( ( TickType_t * ) pvOptionValue );
\r
806 case FREERTOS_SO_SNDTIMEO :
\r
807 /* The send time out is capped for the reason stated in the comments
\r
808 where ipconfigMAX_SEND_BLOCK_TIME_TICKS is defined in
\r
809 FreeRTOSIPConfig.h (assuming an official configuration file is being
\r
811 pxSocket->xSendBlockTime = *( ( TickType_t * ) pvOptionValue );
\r
812 if( pxSocket->xSendBlockTime > ipconfigMAX_SEND_BLOCK_TIME_TICKS )
\r
814 pxSocket->xSendBlockTime = ipconfigMAX_SEND_BLOCK_TIME_TICKS;
\r
818 case FREERTOS_SO_UDPCKSUM_OUT :
\r
819 /* Turn calculating of the UDP checksum on/off for this socket. */
\r
820 lOptionValue = ( BaseType_t ) pvOptionValue;
\r
822 if( lOptionValue == 0 )
\r
824 pxSocket->ucSocketOptions &= ~FREERTOS_SO_UDPCKSUM_OUT;
\r
828 pxSocket->ucSocketOptions |= FREERTOS_SO_UDPCKSUM_OUT;
\r
833 /* No other options are handled. */
\r
834 xReturn = FREERTOS_ENOPROTOOPT;
\r
840 /*-----------------------------------------------------------*/
\r
842 BaseType_t xProcessReceivedUDPPacket( xNetworkBufferDescriptor_t *pxNetworkBuffer, uint16_t usPort )
\r
844 xListItem *pxListItem;
\r
845 BaseType_t xReturn = pdPASS;
\r
846 xFreeRTOS_Socket_t *pxSocket;
\r
847 BaseType_t xHigherPriorityTaskWoken = pdFALSE;
\r
851 /* See if there is a list item associated with the port number on the
\r
852 list of bound sockets. */
\r
853 pxListItem = pxListFindListItemWithValue( &xBoundSocketsList, ( TickType_t ) usPort );
\r
857 if( pxListItem != NULL )
\r
859 /* The owner of the list item is the socket itself. */
\r
860 pxSocket = ( xFreeRTOS_Socket_t * ) listGET_LIST_ITEM_OWNER( pxListItem );
\r
864 #if( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
\r
866 /* Is the socket a member of a select() group? */
\r
867 if( pxSocket->xSelectQueue != NULL )
\r
869 /* Can the select group be notified that the socket is
\r
870 ready to be read? */
\r
871 if( xQueueSendFromISR( pxSocket->xSelectQueue, &pxSocket, &xHigherPriorityTaskWoken ) != pdPASS )
\r
873 /* Could not notify the select group. */
\r
875 iptraceFAILED_TO_NOTIFY_SELECT_GROUP( pxSocket );
\r
881 if( xReturn == pdPASS )
\r
883 taskENTER_CRITICAL();
\r
885 /* Add the network packet to the list of packets to be
\r
886 processed by the socket. */
\r
887 vListInsertEnd( &( pxSocket->xWaitingPacketsList ), &( pxNetworkBuffer->xBufferListItem ) );
\r
889 taskEXIT_CRITICAL();
\r
891 /* The socket's counting semaphore records how many packets are
\r
892 waiting to be processed by the socket. */
\r
893 xSemaphoreGiveFromISR( pxSocket->xWaitingPacketSemaphore, &xHigherPriorityTaskWoken );
\r
896 if( xTaskResumeAll() == pdFALSE )
\r
898 if( xHigherPriorityTaskWoken != pdFALSE )
\r
911 /*-----------------------------------------------------------*/
\r
913 static uint16_t prvGetPrivatePortNumber( void )
\r
915 static uint16_t usNextPortToUse = socketAUTO_PORT_ALLOCATION_START_NUMBER - 1;
\r
918 /* Assign the next port in the range. */
\r
919 taskENTER_CRITICAL();
\r
923 /* Has it overflowed? */
\r
924 if( usNextPortToUse == 0U )
\r
926 /* Don't go right back to the start of the dynamic/private port
\r
927 range numbers as any persistent sockets are likely to have been
\r
928 create first so the early port numbers may still be in use. */
\r
929 usNextPortToUse = socketAUTO_PORT_ALLOCATION_RESET_NUMBER;
\r
932 usReturn = FreeRTOS_htons( usNextPortToUse );
\r
934 taskEXIT_CRITICAL();
\r
938 /*-----------------------------------------------------------*/
\r
940 xListItem * pxListFindListItemWithValue( xList *pxList, TickType_t xWantedItemValue )
\r
942 xListItem *pxIterator, *pxReturn;
\r
945 for( pxIterator = ( xListItem * ) pxList->xListEnd.pxNext; pxIterator != ( xListItem* ) &( pxList->xListEnd ); pxIterator = ( xListItem * ) pxIterator->pxNext )
\r
947 if( pxIterator->xItemValue == xWantedItemValue )
\r
949 pxReturn = pxIterator;
\r
956 /*-----------------------------------------------------------*/
\r
958 #if ipconfigINCLUDE_FULL_INET_ADDR == 1
\r
960 uint32_t FreeRTOS_inet_addr( const char *pcIPAddress )
\r
962 const uint8_t ucDecimalBase = 10;
\r
963 uint8_t ucOctet[ socketMAX_IP_ADDRESS_OCTETS ];
\r
964 const char *pcPointerOnEntering;
\r
965 uint32_t ulReturn = 0UL, ulOctetNumber, ulValue;
\r
966 BaseType_t xResult = pdPASS;
\r
968 for( ulOctetNumber = 0; ulOctetNumber < socketMAX_IP_ADDRESS_OCTETS; ulOctetNumber++ )
\r
971 pcPointerOnEntering = pcIPAddress;
\r
973 while( ( *pcIPAddress >= ( uint8_t ) '0' ) && ( *pcIPAddress <= ( uint8_t ) '9' ) )
\r
975 /* Move previous read characters into the next decimal
\r
977 ulValue *= ucDecimalBase;
\r
979 /* Add the binary value of the ascii character. */
\r
980 ulValue += ( *pcIPAddress - ( uint8_t ) '0' );
\r
982 /* Move to next character in the string. */
\r
986 /* Check characters were read. */
\r
987 if( pcIPAddress == pcPointerOnEntering )
\r
992 /* Check the value fits in an 8-bit number. */
\r
993 if( ulValue > 0xffUL )
\r
999 ucOctet[ ulOctetNumber ] = ( uint8_t ) ulValue;
\r
1001 /* Check the next character is as expected. */
\r
1002 if( ulOctetNumber < ( socketMAX_IP_ADDRESS_OCTETS - 1 ) )
\r
1004 if( *pcIPAddress != ( uint8_t ) '.' )
\r
1010 /* Move past the dot. */
\r
1016 if( xResult == pdFAIL )
\r
1018 /* No point going on. */
\r
1023 if( *pcIPAddress != ( uint8_t ) 0x00 )
\r
1025 /* Expected the end of the string. */
\r
1029 if( ulOctetNumber != socketMAX_IP_ADDRESS_OCTETS )
\r
1031 /* Didn't read enough octets. */
\r
1035 if( xResult == pdPASS )
\r
1037 ulReturn = FreeRTOS_inet_addr_quick( ucOctet[ 0 ], ucOctet[ 1 ], ucOctet[ 2 ], ucOctet[ 3 ] );
\r
1043 #endif /* ipconfigINCLUDE_FULL_INET_ADDR */
\r
1044 /*-----------------------------------------------------------*/
\r