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 standard GPL open source license, or a commercial license. The
\r
9 * standard GPL license (unlike the modified GPL license under which FreeRTOS
\r
10 * itself is distributed) requires that all software statically linked with
\r
11 * FreeRTOS+UDP is also distributed under the same GPL V2 license terms.
\r
12 * Details of both license options follow:
\r
14 * - Open source licensing -
\r
15 * FreeRTOS+UDP is a free download and may be used, modified, evaluated and
\r
16 * distributed without charge provided the user adheres to version two of the
\r
17 * GNU General Public License (GPL) and does not remove the copyright notice or
\r
18 * this text. The GPL V2 text is available on the gnu.org web site, and on the
\r
19 * following URL: http://www.FreeRTOS.org/gpl-2.0.txt.
\r
21 * - Commercial licensing -
\r
22 * Businesses and individuals that for commercial or other reasons cannot comply
\r
23 * with the terms of the GPL V2 license must obtain a commercial license before
\r
24 * incorporating FreeRTOS+UDP into proprietary software for distribution in any
\r
25 * form. Commercial licenses can be purchased from http://shop.freertos.org/udp
\r
26 * and do not require any source files to be changed.
\r
28 * FreeRTOS+UDP is distributed in the hope that it will be useful. You cannot
\r
29 * use FreeRTOS+UDP unless you agree that you use the software 'as is'.
\r
30 * FreeRTOS+UDP is provided WITHOUT ANY WARRANTY; without even the implied
\r
31 * warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR
\r
32 * PURPOSE. Real Time Engineers Ltd. disclaims all conditions and terms, be they
\r
33 * implied, expressed, or statutory.
\r
35 * 1 tab == 4 spaces!
\r
37 * http://www.FreeRTOS.org
\r
38 * http://www.FreeRTOS.org/udp
\r
42 /* Standard includes. */
\r
45 /* FreeRTOS includes. */
\r
46 #include "FreeRTOS.h"
\r
51 /* FreeRTOS+UDP includes. */
\r
52 #include "FreeRTOS_UDP_IP.h"
\r
53 #include "FreeRTOS_IP_Private.h"
\r
54 #include "FreeRTOS_Sockets.h"
\r
55 #include "NetworkBufferManagement.h"
\r
57 /* Sanity check the UDP payload length setting is compatible with the
\r
58 fragmentation setting. */
\r
59 #if ipconfigCAN_FRAGMENT_OUTGOING_PACKETS == 1
\r
60 #if ( ( ipMAX_UDP_PAYLOAD_LENGTH % 8 ) != 0 )
\r
61 #error ( ipconfigNETWORK_MTU - 28 ) must be divisible by 8 when fragmentation is used
\r
62 #endif /* ipMAX_UDP_PAYLOAD_LENGTH */
\r
63 #endif /* ipconfigFRAGMENT_OUTGOING_PACKETS */
\r
65 /* The ItemValue of the sockets xBoundSocketListItem member holds the socket's
\r
67 #define socketSET_SOCKET_ADDRESS( pxSocket, usPort ) listSET_LIST_ITEM_VALUE( ( &( ( pxSocket )->xBoundSocketListItem ) ), ( usPort ) )
\r
68 #define socketGET_SOCKET_ADDRESS( pxSocket ) listGET_LIST_ITEM_VALUE( ( &( ( pxSocket )->xBoundSocketListItem ) ) )
\r
70 /* xWaitingPacketSemaphore is not created until the socket is bound, so can be
\r
71 tested to see if bind() has been called. */
\r
72 #define socketSOCKET_IS_BOUND( pxSocket ) ( ( uint32_t ) pxSocket->xWaitingPacketSemaphore )
\r
74 /* If FreeRTOS_sendto() is called on a socket that is not bound to a port
\r
75 number then, depending on the FreeRTOSIPConfig.h settings, it might be that a
\r
76 port number is automatically generated for the socket. Automatically generated
\r
77 port numbers will be between socketAUTO_PORT_ALLOCATION_START_NUMBER and
\r
79 #define socketAUTO_PORT_ALLOCATION_START_NUMBER ( ( uint16_t ) 0xc000 )
\r
81 /* When the automatically generated port numbers overflow, the next value used
\r
82 is not set back to socketAUTO_PORT_ALLOCATION_START_NUMBER because it is likely
\r
83 that the first few automatically generated ports will still be in use. Instead
\r
84 it is reset back to the value defined by this constant. */
\r
85 #define socketAUTO_PORT_ALLOCATION_RESET_NUMBER ( ( uint16_t ) 0xc100 )
\r
87 /* The number of octets that make up an IP address. */
\r
88 #define socketMAX_IP_ADDRESS_OCTETS 4
\r
89 /*-----------------------------------------------------------*/
\r
92 * Allocate the next port number from the private allocation range.
\r
94 static uint16_t prvGetPrivatePortNumber( void );
\r
97 * Return the list itme from within pxList that has an item value of
\r
98 * xWantedItemValue. If there is no such list item return NULL.
\r
100 xListItem * pxListFindListItemWithValue( xList *pxList, portTickType xWantedItemValue );
\r
102 /*-----------------------------------------------------------*/
\r
104 typedef struct XSOCKET
\r
106 xSemaphoreHandle xWaitingPacketSemaphore;
\r
107 xList xWaitingPacketsList;
\r
108 xListItem xBoundSocketListItem; /* Used to reference the socket from a bound sockets list. */
\r
109 portTickType xReceiveBlockTime;
\r
110 portTickType xSendBlockTime;
\r
111 uint8_t ucSocketOptions;
\r
112 #if ipconfigSUPPORT_SELECT_FUNCTION == 1
\r
113 xQueueHandle xSelectQueue;
\r
115 } xFreeRTOS_Socket_t;
\r
118 /* The list that contains mappings between sockets and port numbers. Accesses
\r
119 to this list must be protected by critical sections of one kind or another. */
\r
120 static xList xBoundSocketsList;
\r
122 /*-----------------------------------------------------------*/
\r
124 xSocket_t FreeRTOS_socket( portBASE_TYPE xDomain, portBASE_TYPE xType, portBASE_TYPE xProtocol )
\r
126 xFreeRTOS_Socket_t *pxSocket;
\r
128 /* Only UDP on Ethernet is currently supported. */
\r
129 configASSERT( xDomain == FREERTOS_AF_INET );
\r
130 configASSERT( xType == FREERTOS_SOCK_DGRAM );
\r
131 configASSERT( xProtocol == FREERTOS_IPPROTO_UDP );
\r
132 configASSERT( listLIST_IS_INITIALISED( &xBoundSocketsList ) );
\r
134 /* Allocate the structure that will hold the socket information. */
\r
135 pxSocket = ( xFreeRTOS_Socket_t * ) pvPortMalloc( sizeof( xFreeRTOS_Socket_t ) );
\r
137 if( pxSocket == NULL )
\r
139 pxSocket = ( xFreeRTOS_Socket_t * ) FREERTOS_INVALID_SOCKET;
\r
140 iptraceFAILED_TO_CREATE_SOCKET();
\r
144 /* Initialise the socket's members. The semaphore will be created if
\r
145 the socket is bound to an address, for now the pointer to the semaphore
\r
146 is just set to NULL to show it has not been created. */
\r
147 pxSocket->xWaitingPacketSemaphore = NULL;
\r
148 vListInitialise( &( pxSocket->xWaitingPacketsList ) );
\r
149 vListInitialiseItem( &( pxSocket->xBoundSocketListItem ) );
\r
150 listSET_LIST_ITEM_OWNER( &( pxSocket->xBoundSocketListItem ), ( void * ) pxSocket );
\r
151 pxSocket->xSendBlockTime = ( portTickType ) 0;
\r
152 pxSocket->xReceiveBlockTime = portMAX_DELAY;
\r
153 pxSocket->ucSocketOptions = FREERTOS_SO_UDPCKSUM_OUT;
\r
154 #if ipconfigSUPPORT_SELECT_FUNCTION == 1
\r
155 pxSocket->xSelectQueue = NULL;
\r
159 /* Remove compiler warnings in the case the configASSERT() is not defined. */
\r
162 ( void ) xProtocol;
\r
164 return ( xSocket_t ) pxSocket;
\r
166 /*-----------------------------------------------------------*/
\r
168 #if ipconfigSUPPORT_SELECT_FUNCTION == 1
\r
170 xSocketSet_t FreeRTOS_CreateSocketSet( unsigned portBASE_TYPE uxEventQueueLength )
\r
172 xQueueHandle xSelectQueue;
\r
174 /* Create the queue into which the address of sockets that are
\r
175 available to read are posted. */
\r
176 xSelectQueue = xQueueCreate( uxEventQueueLength, sizeof( xSocket_t ) );
\r
178 return ( xSocketSet_t ) xSelectQueue;
\r
181 #endif /* ipconfigSUPPORT_SELECT_FUNCTION */
\r
182 /*-----------------------------------------------------------*/
\r
184 #if ipconfigSUPPORT_SELECT_FUNCTION == 1
\r
186 portBASE_TYPE FreeRTOS_FD_SET( xSocket_t xSocket, xSocketSet_t xSocketSet )
\r
188 xFreeRTOS_Socket_t *pxSocket = ( xFreeRTOS_Socket_t * ) xSocket;
\r
189 portBASE_TYPE xReturn = pdFALSE;
\r
190 unsigned portBASE_TYPE uxMessagesWaiting;
\r
192 configASSERT( xSocket );
\r
194 /* Is the socket already a member of a select group? */
\r
195 if( pxSocket->xSelectQueue == NULL )
\r
197 taskENTER_CRITICAL();
\r
199 /* Are there packets queued on the socket already? */
\r
200 uxMessagesWaiting = uxQueueMessagesWaiting( pxSocket->xWaitingPacketSemaphore );
\r
202 /* Are there enough notification spaces in the select queue for the
\r
203 number of packets already queued on the socket? */
\r
204 if( uxQueueSpacesAvailable( ( xQueueHandle ) xSocketSet ) >= uxMessagesWaiting )
\r
206 /* Store a pointer to the select group in the socket for
\r
207 future reference. */
\r
208 pxSocket->xSelectQueue = ( xQueueHandle ) xSocketSet;
\r
210 while( uxMessagesWaiting > 0 )
\r
212 /* Add notifications of the number of packets that are
\r
213 already queued on the socket to the select queue. */
\r
214 xQueueSendFromISR( pxSocket->xSelectQueue, &pxSocket, NULL );
\r
215 uxMessagesWaiting--;
\r
221 taskEXIT_CRITICAL();
\r
227 #endif /* ipconfigSUPPORT_SELECT_FUNCTION */
\r
228 /*-----------------------------------------------------------*/
\r
230 #if ipconfigSUPPORT_SELECT_FUNCTION == 1
\r
232 portBASE_TYPE FreeRTOS_FD_CLR( xSocket_t xSocket, xSocketSet_t xSocketSet )
\r
234 xFreeRTOS_Socket_t *pxSocket = ( xFreeRTOS_Socket_t * ) xSocket;
\r
235 portBASE_TYPE xReturn;
\r
237 /* Is the socket a member of the select group? */
\r
238 if( pxSocket->xSelectQueue == ( xQueueHandle ) xSocketSet )
\r
240 /* The socket is no longer a member of the select group. */
\r
241 pxSocket->xSelectQueue = NULL;
\r
252 #endif /* ipconfigSUPPORT_SELECT_FUNCTION */
\r
253 /*-----------------------------------------------------------*/
\r
255 #if ipconfigSUPPORT_SELECT_FUNCTION == 1
\r
257 xSocket_t FreeRTOS_select( xSocketSet_t xSocketSet, portTickType xBlockTimeTicks )
\r
259 xFreeRTOS_Socket_t *pxSocket;
\r
261 /* Wait for a socket to be ready to read. */
\r
262 if( xQueueReceive( ( xQueueHandle ) xSocketSet, &pxSocket, xBlockTimeTicks ) != pdPASS )
\r
267 return ( xSocket_t ) pxSocket;
\r
270 #endif /* ipconfigSUPPORT_SELECT_FUNCTION */
\r
271 /*-----------------------------------------------------------*/
\r
273 int32_t FreeRTOS_recvfrom( xSocket_t xSocket, void *pvBuffer, size_t xBufferLength, uint32_t ulFlags, struct freertos_sockaddr *pxSourceAddress, socklen_t *pxSourceAddressLength )
\r
275 xNetworkBufferDescriptor_t *pxNetworkBuffer;
\r
277 xFreeRTOS_Socket_t *pxSocket;
\r
279 pxSocket = ( xFreeRTOS_Socket_t * ) xSocket;
\r
281 /* The function prototype is designed to maintain the expected Berkeley
\r
282 sockets standard, but this implementation does not use all the parameters. */
\r
283 ( void ) pxSourceAddressLength;
\r
285 if( socketSOCKET_IS_BOUND( pxSocket ) != pdFALSE )
\r
287 /* The semaphore is given when received data is queued on the socket. */
\r
288 if( xSemaphoreTake( pxSocket->xWaitingPacketSemaphore, pxSocket->xReceiveBlockTime ) == pdPASS )
\r
290 taskENTER_CRITICAL();
\r
292 configASSERT( ( listCURRENT_LIST_LENGTH( &( pxSocket->xWaitingPacketsList ) ) > 0U ) );
\r
294 /* The owner of the list item is the network buffer. */
\r
295 pxNetworkBuffer = ( xNetworkBufferDescriptor_t * ) listGET_OWNER_OF_HEAD_ENTRY( &( pxSocket->xWaitingPacketsList ) );
\r
297 /* Remove the network buffer from the list of buffers waiting to
\r
298 be processed by the socket. */
\r
299 uxListRemove( &( pxNetworkBuffer->xBufferListItem ) );
\r
301 taskEXIT_CRITICAL();
\r
303 if( ( ulFlags & FREERTOS_ZERO_COPY ) == 0 )
\r
305 /* The zero copy flag is not set. Truncate the length if it
\r
306 won't fit in the provided buffer. */
\r
307 if( pxNetworkBuffer->xDataLength > xBufferLength )
\r
309 iptraceRECVFROM_DISCARDING_BYTES( ( xBufferLength - pxNetworkBuffer->xDataLength ) );
\r
310 pxNetworkBuffer->xDataLength = xBufferLength;
\r
313 /* Copy the received data into the provided buffer, then
\r
314 release the network buffer. */
\r
315 memcpy( pvBuffer, ( void * ) &( pxNetworkBuffer->pucEthernetBuffer[ ipUDP_PAYLOAD_OFFSET ] ), pxNetworkBuffer->xDataLength );
\r
316 vNetworkBufferRelease( pxNetworkBuffer );
\r
320 /* The zero copy flag was set. pvBuffer is not a buffer into
\r
321 which the received data can be copied, but a pointer that must
\r
322 be set to point to the buffer in which the received data has
\r
323 already been placed. */
\r
324 *( ( void** ) pvBuffer ) = ( void * ) ( &( pxNetworkBuffer->pucEthernetBuffer[ ipUDP_PAYLOAD_OFFSET ] ) );
\r
327 /* The returned value is the data length, which may have been
\r
328 capped to the receive buffer size. */
\r
329 lReturn = ( int32_t ) pxNetworkBuffer->xDataLength;
\r
331 if( pxSourceAddress != NULL )
\r
333 pxSourceAddress->sin_port = pxNetworkBuffer->usPort;
\r
334 pxSourceAddress->sin_addr = pxNetworkBuffer->ulIPAddress;
\r
339 lReturn = FREERTOS_EWOULDBLOCK;
\r
340 iptraceRECVFROM_TIMEOUT();
\r
345 lReturn = FREERTOS_EINVAL;
\r
350 /*-----------------------------------------------------------*/
\r
352 #if ipconfigCAN_FRAGMENT_OUTGOING_PACKETS == 1
\r
354 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
356 xNetworkBufferDescriptor_t *pxNetworkBuffer;
\r
357 xIPFragmentParameters_t *pxFragmentParameters;
\r
358 size_t xBytesToSend, xBytesRemaining;
\r
359 xIPStackEvent_t xStackTxEvent = { eStackTxEvent, NULL };
\r
360 extern xQueueHandle xNetworkEventQueue;
\r
361 uint8_t *pucBuffer;
\r
362 xTimeOutType xTimeOut;
\r
363 portTickType xTicksToWait;
\r
364 uint16_t usFragmentOffset;
\r
365 xFreeRTOS_Socket_t *pxSocket;
\r
367 pxSocket = ( xFreeRTOS_Socket_t * ) xSocket;
\r
369 /* The function prototype is designed to maintain the expected Berkeley
\r
370 sockets standard, but this implementation does not use all the
\r
372 ( void ) xDestinationAddressLength;
\r
373 configASSERT( xNetworkEventQueue );
\r
374 configASSERT( pvBuffer );
\r
376 xBytesRemaining = xTotalDataLength;
\r
378 if( socketSOCKET_IS_BOUND( pxSocket ) == pdFALSE )
\r
380 /* If the socket is not already bound to an address, bind it now.
\r
381 Passing NULL as the address parameter tells FreeRTOS_bind() to select
\r
382 the address to bind to. */
\r
383 FreeRTOS_bind( xSocket, NULL, 0 );
\r
386 if( socketSOCKET_IS_BOUND( pxSocket ) != pdFALSE )
\r
388 /* pucBuffer will be reset if this send turns out to be a zero copy
\r
389 send because in that case pvBuffer is actually a pointer to an
\r
390 xUserData_t structure, not the UDP payload. */
\r
391 pucBuffer = ( uint8_t * ) pvBuffer;
\r
392 vTaskSetTimeOutState( &xTimeOut );
\r
393 xTicksToWait = pxSocket->xSendBlockTime;
\r
395 /* The data being transmitted will be sent in
\r
396 ipMAX_UDP_PAYLOAD_LENGTH chunks if xDataLength is greater than the
\r
397 network buffer payload size. Loop until all the data is sent. */
\r
398 while( xBytesRemaining > 0 )
\r
400 if( xBytesRemaining > ipMAX_UDP_PAYLOAD_LENGTH )
\r
402 /* Cap the amount being sent in this packet to the maximum
\r
403 UDP payload size. This will be a multiple of 8 already,
\r
404 removing the need to check in the code. */
\r
405 xBytesToSend = ipMAX_UDP_PAYLOAD_LENGTH;
\r
409 /* Send all remaining bytes - which may well be the total
\r
410 number of bytes if the packet was not chopped up. */
\r
411 xBytesToSend = xBytesRemaining;
\r
414 /* If the zero copy flag is set, then the data is already in a
\r
415 network buffer. Otherwise, get a new network buffer. */
\r
416 if( ( ulFlags & FREERTOS_ZERO_COPY ) == 0 )
\r
418 if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdTRUE )
\r
423 pxNetworkBuffer = pxNetworkBufferGet( xBytesToSend + sizeof( xUDPPacket_t ), xTicksToWait );
\r
427 if( xTotalDataLength > ipMAX_UDP_PAYLOAD_LENGTH )
\r
429 /* The packet needs fragmenting, but zero copy buffers
\r
430 cannot be fragmented. */
\r
431 pxNetworkBuffer = NULL;
\r
435 /* When zero copy is used, pvBuffer is a pointer to the
\r
436 payload of a buffer that has already been obtained from the
\r
437 stack. Obtain the network buffer pointer from the buffer. */
\r
438 pucBuffer = ( uint8_t * ) pvBuffer;
\r
439 pucBuffer -= ( ipBUFFER_PADDING + sizeof( xUDPPacket_t ) );
\r
440 pxNetworkBuffer = * ( ( xNetworkBufferDescriptor_t ** ) pucBuffer );
\r
444 if( pxNetworkBuffer != NULL )
\r
446 /* Use the part of the network buffer that will be completed
\r
447 by the IP layer as temporary storage to pass extra
\r
448 information required by the IP layer. */
\r
449 pxFragmentParameters = ( xIPFragmentParameters_t * ) &( pxNetworkBuffer->pucEthernetBuffer[ ipFRAGMENTATION_PARAMETERS_OFFSET ] );
\r
450 pxFragmentParameters->ucSocketOptions = pxSocket->ucSocketOptions;
\r
452 if( xBytesRemaining > ipMAX_UDP_PAYLOAD_LENGTH )
\r
454 /* The packet is being chopped up, and more data will
\r
456 pxFragmentParameters->ucSocketOptions = ( pxSocket->ucSocketOptions | FREERTOS_NOT_LAST_IN_FRAGMENTED_PACKET );
\r
459 if( xTotalDataLength > ipMAX_UDP_PAYLOAD_LENGTH )
\r
461 /* Let the IP layer know this packet has been chopped up,
\r
462 and supply the IP layer with any addition information it
\r
463 needs to make sense of it. */
\r
464 pxFragmentParameters->ucSocketOptions |= FREERTOS_FRAGMENTED_PACKET;
\r
465 usFragmentOffset = ( uint16_t ) ( xTotalDataLength - xBytesRemaining );
\r
466 pxFragmentParameters->usFragmentedPacketOffset = usFragmentOffset;
\r
467 pxFragmentParameters->usFragmentLength = ( uint16_t ) xBytesToSend;
\r
471 usFragmentOffset = 0;
\r
474 /* Write the payload into the packet. The IP layer is
\r
475 queried to find where in the IP payload the data should be
\r
476 written. This is because the necessary offset is different
\r
477 for the first packet, because the first packet leaves space
\r
478 for a UDP header. Note that this changes usFragmentOffset
\r
479 from the offset in the entire UDP packet, to the offset
\r
480 in the IP packet. */
\r
481 if( ( ulFlags & FREERTOS_ZERO_COPY ) == 0 )
\r
483 /* Only copy the data if it is not already in the
\r
484 expected location. */
\r
485 usFragmentOffset = ipGET_UDP_PAYLOAD_OFFSET_FOR_FRAGMENT( usFragmentOffset );
\r
486 memcpy( ( void * ) &( pxNetworkBuffer->pucEthernetBuffer[ usFragmentOffset ] ), ( void * ) pucBuffer, xBytesToSend );
\r
488 pxNetworkBuffer->xDataLength = xTotalDataLength;
\r
489 pxNetworkBuffer->usPort = pxDestinationAddress->sin_port;
\r
490 pxNetworkBuffer->usBoundPort = ( uint16_t ) socketGET_SOCKET_ADDRESS( pxSocket );
\r
491 pxNetworkBuffer->ulIPAddress = pxDestinationAddress->sin_addr;
\r
493 /* Tell the networking task that the packet needs sending. */
\r
494 xStackTxEvent.pvData = pxNetworkBuffer;
\r
496 if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdTRUE )
\r
501 if( xQueueSendToBack( xNetworkEventQueue, &xStackTxEvent, xTicksToWait ) != pdPASS )
\r
503 /* If the buffer was allocated in this function, release it. */
\r
504 if( ( ulFlags & FREERTOS_ZERO_COPY ) == 0 )
\r
506 vNetworkBufferRelease( pxNetworkBuffer );
\r
508 iptraceSTACK_TX_EVENT_LOST( ipSTACK_TX_EVENT );
\r
512 /* Adjust counters ready to either exit the loop, or send
\r
513 another chunk of data. */
\r
514 xBytesRemaining -= xBytesToSend;
\r
515 pucBuffer += xBytesToSend;
\r
519 /* If errno was available, errno would be set to
\r
520 FREERTOS_ENOPKTS. As it is, the function must return the
\r
521 number of transmitted bytes, so the calling function knows how
\r
522 much data was actually sent. */
\r
528 return ( xTotalDataLength - xBytesRemaining );
\r
531 #else /* ipconfigCAN_FRAGMENT_OUTGOING_PACKETS */
\r
533 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
535 xNetworkBufferDescriptor_t *pxNetworkBuffer;
\r
536 xIPStackEvent_t xStackTxEvent = { eStackTxEvent, NULL };
\r
537 extern xQueueHandle xNetworkEventQueue;
\r
538 xTimeOutType xTimeOut;
\r
539 portTickType xTicksToWait;
\r
540 int32_t lReturn = 0;
\r
541 xFreeRTOS_Socket_t *pxSocket;
\r
542 uint8_t *pucBuffer;
\r
544 pxSocket = ( xFreeRTOS_Socket_t * ) xSocket;
\r
546 /* The function prototype is designed to maintain the expected Berkeley
\r
547 sockets standard, but this implementation does not use all the
\r
549 ( void ) xDestinationAddressLength;
\r
550 configASSERT( xNetworkEventQueue );
\r
551 configASSERT( pvBuffer );
\r
553 if( xTotalDataLength <= ipMAX_UDP_PAYLOAD_LENGTH )
\r
555 if( socketSOCKET_IS_BOUND( pxSocket ) == pdFALSE )
\r
557 /* If the socket is not already bound to an address, bind it now.
\r
558 Passing NULL as the address parameter tells FreeRTOS_bind() to
\r
559 select the address to bind to. */
\r
560 FreeRTOS_bind( pxSocket, NULL, 0 );
\r
563 if( socketSOCKET_IS_BOUND( pxSocket ) != pdFALSE )
\r
565 xTicksToWait = pxSocket->xSendBlockTime;
\r
567 if( ( ulFlags & FREERTOS_ZERO_COPY ) == 0 )
\r
569 /* Zero copy is not set, so obtain a network buffer into
\r
570 which the payload will be copied. */
\r
571 vTaskSetTimeOutState( &xTimeOut );
\r
572 pxNetworkBuffer = pxNetworkBufferGet( xTotalDataLength + sizeof( xUDPPacket_t ), xTicksToWait );
\r
574 if( pxNetworkBuffer != NULL )
\r
576 memcpy( ( void * ) &( pxNetworkBuffer->pucEthernetBuffer[ ipUDP_PAYLOAD_OFFSET ] ), ( void * ) pvBuffer, xTotalDataLength );
\r
578 if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdTRUE )
\r
580 /* The entire block time has been used up. */
\r
587 /* When zero copy is used, pvBuffer is a pointer to the
\r
588 payload of a buffer that has already been obtained from the
\r
589 stack. Obtain the network buffer pointer from the buffer. */
\r
590 pucBuffer = ( uint8_t * ) pvBuffer;
\r
591 pucBuffer -= ( ipBUFFER_PADDING + sizeof( xUDPPacket_t ) );
\r
592 pxNetworkBuffer = * ( ( xNetworkBufferDescriptor_t ** ) pucBuffer );
\r
595 if( pxNetworkBuffer != NULL )
\r
597 pxNetworkBuffer->xDataLength = xTotalDataLength;
\r
598 pxNetworkBuffer->usPort = pxDestinationAddress->sin_port;
\r
599 pxNetworkBuffer->usBoundPort = ( uint16_t ) socketGET_SOCKET_ADDRESS( pxSocket );
\r
600 pxNetworkBuffer->ulIPAddress = pxDestinationAddress->sin_addr;
\r
602 /* The socket options are passed to the IP layer in the
\r
603 space that will eventually get used by the Ethernet header. */
\r
604 pxNetworkBuffer->pucEthernetBuffer[ ipSOCKET_OPTIONS_OFFSET ] = pxSocket->ucSocketOptions;
\r
606 /* Tell the networking task that the packet needs sending. */
\r
607 xStackTxEvent.pvData = pxNetworkBuffer;
\r
609 if( xQueueSendToBack( xNetworkEventQueue, &xStackTxEvent, xTicksToWait ) != pdPASS )
\r
611 /* If the buffer was allocated in this function, release it. */
\r
612 if( ( ulFlags & FREERTOS_ZERO_COPY ) == 0 )
\r
614 vNetworkBufferRelease( pxNetworkBuffer );
\r
616 iptraceSTACK_TX_EVENT_LOST( ipSTACK_TX_EVENT );
\r
620 lReturn = ( int32_t ) xTotalDataLength;
\r
625 /* If errno was available, errno would be set to
\r
626 FREERTOS_ENOPKTS. As it is, the function must return the
\r
627 number of transmitted bytes, so the calling function knows how
\r
628 much data was actually sent. */
\r
629 iptraceNO_BUFFER_FOR_SENDTO();
\r
634 iptraceSENDTO_SOCKET_NOT_BOUND();
\r
639 /* The data is longer than the available buffer space. Setting
\r
640 ipconfigCAN_FRAGMENT_OUTGOING_PACKETS to 1 may allow this packet
\r
642 iptraceSENDTO_DATA_TOO_LONG();
\r
648 #endif /* ipconfigCAN_FRAGMENT_OUTGOING_PACKETS */
\r
649 /*-----------------------------------------------------------*/
\r
651 portBASE_TYPE FreeRTOS_bind( xSocket_t xSocket, struct freertos_sockaddr * pxAddress, socklen_t xAddressLength )
\r
653 portBASE_TYPE xReturn = 0; /* In Berkeley sockets, 0 means pass for bind(). */
\r
654 xFreeRTOS_Socket_t *pxSocket;
\r
655 #if ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND == 1
\r
656 struct freertos_sockaddr xAddress;
\r
657 #endif /* ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND */
\r
659 pxSocket = ( xFreeRTOS_Socket_t * ) xSocket;
\r
661 /* The function prototype is designed to maintain the expected Berkeley
\r
662 sockets standard, but this implementation does not use all the parameters. */
\r
663 ( void ) xAddressLength;
\r
665 configASSERT( xSocket );
\r
666 configASSERT( xSocket != FREERTOS_INVALID_SOCKET );
\r
668 #if ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND == 1
\r
670 /* pxAddress will be NULL if sendto() was called on a socket without the
\r
671 socket being bound to an address. In this case, automatically allocate
\r
672 an address to the socket. There is a very tiny chance that the allocated
\r
673 port will already be in use - if that is the case, then the check below
\r
674 [pxListFindListItemWithValue()] will result in an error being returned. */
\r
675 if( pxAddress == NULL )
\r
677 pxAddress = &xAddress;
\r
678 pxAddress->sin_port = prvGetPrivatePortNumber();
\r
681 #endif /* ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND == 1 */
\r
683 /* Sockets must be bound before calling FreeRTOS_sendto() if
\r
684 ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND is not set to 1. */
\r
685 configASSERT( pxAddress );
\r
687 if( pxAddress != NULL )
\r
689 if( pxAddress->sin_port == 0 )
\r
691 pxAddress->sin_port = prvGetPrivatePortNumber();
\r
696 /* Check to ensure the port is not already in use. */
\r
697 if( pxListFindListItemWithValue( &xBoundSocketsList, ( portTickType ) pxAddress->sin_port ) != NULL )
\r
699 xReturn = FREERTOS_EADDRINUSE;
\r
704 /* Check that xReturn has not been set before continuing. */
\r
707 if( pxSocket->xWaitingPacketSemaphore == NULL )
\r
709 /* Create the semaphore used to count the number of packets that
\r
710 are queued on this socket. */
\r
711 pxSocket->xWaitingPacketSemaphore = xSemaphoreCreateCounting( ipconfigNUM_NETWORK_BUFFERS, 0 );
\r
713 if( pxSocket->xWaitingPacketSemaphore != NULL )
\r
715 /* Allocate the port number to the socket. */
\r
716 socketSET_SOCKET_ADDRESS( pxSocket, pxAddress->sin_port );
\r
717 taskENTER_CRITICAL();
\r
719 /* Add the socket to the list of bound ports. */
\r
720 vListInsertEnd( &xBoundSocketsList, &( pxSocket->xBoundSocketListItem ) );
\r
722 taskEXIT_CRITICAL();
\r
726 /* Out of memory. */
\r
727 xReturn = FREERTOS_ENOBUFS;
\r
732 /* The socket is already bound. */
\r
733 xReturn = FREERTOS_EINVAL;
\r
739 xReturn = FREERTOS_EADDRNOTAVAIL;
\r
744 iptraceBIND_FAILED( xSocket, ( FreeRTOS_ntohs( pxAddress->sin_port ) ) );
\r
749 /*-----------------------------------------------------------*/
\r
751 portBASE_TYPE FreeRTOS_closesocket( xSocket_t xSocket )
\r
753 xNetworkBufferDescriptor_t *pxNetworkBuffer;
\r
754 xFreeRTOS_Socket_t *pxSocket;
\r
756 pxSocket = ( xFreeRTOS_Socket_t * ) xSocket;
\r
758 configASSERT( pxSocket );
\r
759 configASSERT( pxSocket != FREERTOS_INVALID_SOCKET );
\r
761 /* Socket must be unbound first, to ensure no more packets are queued on
\r
763 if( socketSOCKET_IS_BOUND( pxSocket ) != pdFALSE )
\r
765 taskENTER_CRITICAL();
\r
767 uxListRemove( &( pxSocket->xBoundSocketListItem ) );
\r
769 taskEXIT_CRITICAL();
\r
772 /* Now the socket is not bound the list of waiting packets can be
\r
774 if( pxSocket->xWaitingPacketSemaphore != NULL )
\r
776 while( listCURRENT_LIST_LENGTH( &( pxSocket->xWaitingPacketsList ) ) > 0U )
\r
778 pxNetworkBuffer = ( xNetworkBufferDescriptor_t * ) listGET_OWNER_OF_HEAD_ENTRY( &( pxSocket->xWaitingPacketsList ) );
\r
779 uxListRemove( &( pxNetworkBuffer->xBufferListItem ) );
\r
780 vNetworkBufferRelease( pxNetworkBuffer );
\r
782 vSemaphoreDelete( pxSocket->xWaitingPacketSemaphore );
\r
785 vPortFree( pxSocket );
\r
789 /*-----------------------------------------------------------*/
\r
791 void FreeRTOS_SocketsInit( void )
\r
793 vListInitialise( &xBoundSocketsList );
\r
795 /*-----------------------------------------------------------*/
\r
797 portBASE_TYPE FreeRTOS_setsockopt( xSocket_t xSocket, int32_t lLevel, int32_t lOptionName, const void *pvOptionValue, size_t xOptionLength )
\r
799 /* The standard Berkeley function returns 0 for success. */
\r
800 portBASE_TYPE xReturn = 0;
\r
801 portBASE_TYPE lOptionValue;
\r
802 xFreeRTOS_Socket_t *pxSocket;
\r
804 pxSocket = ( xFreeRTOS_Socket_t * ) xSocket;
\r
806 /* The function prototype is designed to maintain the expected Berkeley
\r
807 sockets standard, but this implementation does not use all the parameters. */
\r
809 ( void ) xOptionLength;
\r
811 configASSERT( xSocket );
\r
813 switch( lOptionName )
\r
815 case FREERTOS_SO_RCVTIMEO :
\r
816 /* Receive time out. */
\r
817 pxSocket->xReceiveBlockTime = *( ( portTickType * ) pvOptionValue );
\r
820 case FREERTOS_SO_SNDTIMEO :
\r
821 /* The send time out is capped for the reason stated in the comments
\r
822 where ipconfigMAX_SEND_BLOCK_TIME_TICKS is defined in
\r
823 FreeRTOSIPConfig.h (assuming an official configuration file is being
\r
825 pxSocket->xSendBlockTime = *( ( portTickType * ) pvOptionValue );
\r
826 if( pxSocket->xSendBlockTime > ipconfigMAX_SEND_BLOCK_TIME_TICKS )
\r
828 pxSocket->xSendBlockTime = ipconfigMAX_SEND_BLOCK_TIME_TICKS;
\r
832 case FREERTOS_SO_UDPCKSUM_OUT :
\r
833 /* Turn calculating of the UDP checksum on/off for this socket. */
\r
834 lOptionValue = ( portBASE_TYPE ) pvOptionValue;
\r
836 if( lOptionValue == 0 )
\r
838 pxSocket->ucSocketOptions &= ~FREERTOS_SO_UDPCKSUM_OUT;
\r
842 pxSocket->ucSocketOptions |= FREERTOS_SO_UDPCKSUM_OUT;
\r
847 /* No other options are handled. */
\r
848 xReturn = FREERTOS_ENOPROTOOPT;
\r
854 /*-----------------------------------------------------------*/
\r
856 portBASE_TYPE xProcessReceivedUDPPacket( xNetworkBufferDescriptor_t *pxNetworkBuffer, uint16_t usPort )
\r
858 xListItem *pxListItem;
\r
859 portBASE_TYPE xReturn = pdPASS;
\r
860 xFreeRTOS_Socket_t *pxSocket;
\r
861 portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
\r
865 /* See if there is a list item associated with the port number on the
\r
866 list of bound sockets. */
\r
867 pxListItem = pxListFindListItemWithValue( &xBoundSocketsList, ( portTickType ) usPort );
\r
871 if( pxListItem != NULL )
\r
873 /* The owner of the list item is the socket itself. */
\r
874 pxSocket = ( xFreeRTOS_Socket_t * ) listGET_LIST_ITEM_OWNER( pxListItem );
\r
878 #if( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
\r
880 /* Is the socket a member of a select() group? */
\r
881 if( pxSocket->xSelectQueue != NULL )
\r
883 /* Can the select group be notified that the socket is
\r
884 ready to be read? */
\r
885 if( xQueueSendFromISR( pxSocket->xSelectQueue, &pxSocket, &xHigherPriorityTaskWoken ) != pdPASS )
\r
887 /* Could not notify the select group. */
\r
889 iptraceFAILED_TO_NOTIFY_SELECT_GROUP( pxSocket );
\r
895 if( xReturn == pdPASS )
\r
897 taskENTER_CRITICAL();
\r
899 /* Add the network packet to the list of packets to be
\r
900 processed by the socket. */
\r
901 vListInsertEnd( &( pxSocket->xWaitingPacketsList ), &( pxNetworkBuffer->xBufferListItem ) );
\r
903 taskEXIT_CRITICAL();
\r
905 /* The socket's counting semaphore records how many packets are
\r
906 waiting to be processed by the socket. */
\r
907 xSemaphoreGiveFromISR( pxSocket->xWaitingPacketSemaphore, &xHigherPriorityTaskWoken );
\r
910 if( xTaskResumeAll() == pdFALSE )
\r
912 if( xHigherPriorityTaskWoken != pdFALSE )
\r
925 /*-----------------------------------------------------------*/
\r
927 static uint16_t prvGetPrivatePortNumber( void )
\r
929 static uint16_t usNextPortToUse = socketAUTO_PORT_ALLOCATION_START_NUMBER - 1;
\r
932 /* Assign the next port in the range. */
\r
933 taskENTER_CRITICAL();
\r
935 taskEXIT_CRITICAL();
\r
937 /* Has it overflowed? */
\r
938 if( usNextPortToUse == 0U )
\r
940 /* Don't go right back to the start of the dynamic/private port
\r
941 range numbers as any persistent sockets are likely to have been
\r
942 create first so the early port numbers may still be in use. */
\r
943 usNextPortToUse = socketAUTO_PORT_ALLOCATION_RESET_NUMBER;
\r
946 usReturn = FreeRTOS_htons( usNextPortToUse );
\r
950 /*-----------------------------------------------------------*/
\r
952 xListItem * pxListFindListItemWithValue( xList *pxList, portTickType xWantedItemValue )
\r
954 xListItem *pxIterator, *pxReturn;
\r
957 for( pxIterator = ( xListItem * ) pxList->xListEnd.pxNext; pxIterator != ( xListItem* ) &( pxList->xListEnd ); pxIterator = ( xListItem * ) pxIterator->pxNext )
\r
959 if( pxIterator->xItemValue == xWantedItemValue )
\r
961 pxReturn = pxIterator;
\r
968 /*-----------------------------------------------------------*/
\r
970 #if ipconfigINCLUDE_FULL_INET_ADDR == 1
\r
972 uint32_t FreeRTOS_inet_addr( const uint8_t * pucIPAddress )
\r
974 const uint8_t ucDecimalBase = 10;
\r
975 uint8_t ucOctet[ socketMAX_IP_ADDRESS_OCTETS ];
\r
976 const uint8_t *pucPointerOnEntering;
\r
977 uint32_t ulReturn = 0UL, ulOctetNumber, ulValue;
\r
978 portBASE_TYPE xResult = pdPASS;
\r
980 for( ulOctetNumber = 0; ulOctetNumber < socketMAX_IP_ADDRESS_OCTETS; ulOctetNumber++ )
\r
983 pucPointerOnEntering = pucIPAddress;
\r
985 while( ( *pucIPAddress >= ( uint8_t ) '0' ) && ( *pucIPAddress <= ( uint8_t ) '9' ) )
\r
987 /* Move previous read characters into the next decimal
\r
989 ulValue *= ucDecimalBase;
\r
991 /* Add the binary value of the ascii character. */
\r
992 ulValue += ( *pucIPAddress - ( uint8_t ) '0' );
\r
994 /* Move to next character in the string. */
\r
998 /* Check characters were read. */
\r
999 if( pucIPAddress == pucPointerOnEntering )
\r
1004 /* Check the value fits in an 8-bit number. */
\r
1005 if( ulValue > 0xffUL )
\r
1011 ucOctet[ ulOctetNumber ] = ( uint8_t ) ulValue;
\r
1013 /* Check the next character is as expected. */
\r
1014 if( ulOctetNumber < ( socketMAX_IP_ADDRESS_OCTETS - 1 ) )
\r
1016 if( *pucIPAddress != ( uint8_t ) '.' )
\r
1022 /* Move past the dot. */
\r
1028 if( xResult == pdFAIL )
\r
1030 /* No point going on. */
\r
1035 if( *pucIPAddress != ( uint8_t ) 0x00 )
\r
1037 /* Expected the end of the string. */
\r
1041 if( ulOctetNumber != socketMAX_IP_ADDRESS_OCTETS )
\r
1043 /* Didn't read enough octets. */
\r
1047 if( xResult == pdPASS )
\r
1049 ulReturn = FreeRTOS_inet_addr_quick( ucOctet[ 0 ], ucOctet[ 1 ], ucOctet[ 2 ], ucOctet[ 3 ] );
\r
1055 #endif /* ipconfigINCLUDE_FULL_INET_ADDR */
\r
1056 /*-----------------------------------------------------------*/
\r