portBASE_TYPE xNetworkInterfaceOutput( xNetworkBufferDescriptor_t * const pxNetworkBuffer )
	{
	xEthernetHeader_t *pxEthernetHeader;
	xIPStackEvent_t xRxEvent = { eEthernetRxEvent, NULL };
	extern uint8_t xDefaultPartUDPPacketHeader[];
	static const xMACAddress_t xBroadcastMACAddress = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
	portBASE_TYPE xCanLoopback;

		pxEthernetHeader = ( xEthernetHeader_t * ) pxNetworkBuffer->pucEthernetBuffer;

		if( memcmp( ( void * ) &( pxEthernetHeader->xDestinationAddress ), ( void * ) &xBroadcastMACAddress, sizeof( xMACAddress_t ) ) == 0 )
		{
			/* This is a broadcast. */
			xCanLoopback = pdTRUE;
		}
		else if( memcmp( ( void * ) &( pxEthernetHeader->xDestinationAddress ), ( void * ) xDefaultPartUDPPacketHeader, sizeof( xMACAddress_t ) ) == 0 )
		{
			/* This is being sent to itself. */
			xCanLoopback = pdTRUE;
		}
		else
		{
			/* This is being sent externally. */
			xCanLoopback = pdFALSE;
		}

		iptraceNETWORK_INTERFACE_TRANSMIT();

		if( xCanLoopback == pdTRUE )
		{
			/* Just loop the frame back to the input queue.  Here the loopback
			is sending a message to itself, so a block time cannot be used for
			fear of deadlocking. */
			xRxEvent.pvData = ( void * ) pxNetworkBuffer;
			if( xQueueSendToBack( xNetworkEventQueue, &xRxEvent, ( portTickType ) 0 ) == pdFALSE )
			{
				vNetworkBufferRelease( pxNetworkBuffer );
				iptraceETHERNET_RX_EVENT_LOST();
			}
			else
			{
				iptraceNETWORK_INTERFACE_RECEIVE();
			}
		}
		else
		{
			/* Send the packet. */
			xSemaphoreTake( xPCAPMutex, portMAX_DELAY );
			{
				pcap_sendpacket( pxOpenedInterfaceHandle, pxNetworkBuffer->pucEthernetBuffer, pxNetworkBuffer->xDataLength );
			}
			xSemaphoreGive( xPCAPMutex );

			/* The buffer has been transmitted so can be released. */
			vNetworkBufferRelease( pxNetworkBuffer );
		}

		return pdPASS;
	}
Example #2
0
BaseType_t xNetworkInterfaceOutput( xNetworkBufferDescriptor_t * const pxNetworkBuffer )
{
    BaseType_t xReturn = pdFAIL;
    int32_t x;

    /* Attempt to obtain access to a Tx descriptor. */
    for( x = 0; x < niMAX_TX_ATTEMPTS; x++ )
    {
        if( gmac_dev_write( &xGMACStruct, pxNetworkBuffer->pucEthernetBuffer, ( uint32_t ) pxNetworkBuffer->xDataLength, NULL ) == GMAC_OK )
        {
            /* The Tx has been initiated. */
            xReturn = pdPASS;
            break;
        }
        else
        {
            iptraceWAITING_FOR_TX_DMA_DESCRIPTOR();
            vTaskDelay( niTX_BUFFER_FREE_WAIT );
        }
    }

    /* Finished with the network buffer. */
    vNetworkBufferRelease( pxNetworkBuffer );

    return xReturn;
}
portBASE_TYPE xNetworkInterfaceOutput( xNetworkBufferDescriptor_t * const pxNetworkBuffer )
{
extern void vEMACCopyWrite( uint8_t * pucBuffer, uint16_t usLength );

	vEMACCopyWrite( pxNetworkBuffer->pucEthernetBuffer, pxNetworkBuffer->xDataLength );

	/* Finished with the network buffer. */
	vNetworkBufferRelease( pxNetworkBuffer );

	return pdTRUE;
}
	portBASE_TYPE xNetworkInterfaceOutput( xNetworkBufferDescriptor_t * const pxNetworkBuffer )
	{
		xSemaphoreTake( xPCAPMutex, portMAX_DELAY );
		{
			iptraceNETWORK_INTERFACE_TRANSMIT();
			pcap_sendpacket( pxOpenedInterfaceHandle, pxNetworkBuffer->pucEthernetBuffer, pxNetworkBuffer->xDataLength );
		}
		xSemaphoreGive( xPCAPMutex );

		/* The buffer has been transmitted so can be released. */
		vNetworkBufferRelease( pxNetworkBuffer );

		return pdPASS;
	}
portBASE_TYPE xNetworkInterfaceOutput( xNetworkBufferDescriptor_t * const pxNetworkBuffer )
{
portBASE_TYPE xReturn = pdFAIL;
int32_t x;
extern void EMAC_StartTransmitNextBuffer( uint32_t ulLength );
extern void EMAC_SetNextPacketToSend( uint8_t * pucBuffer );


	/* Attempt to obtain access to a Tx buffer. */
	for( x = 0; x < niMAX_TX_ATTEMPTS; x++ )
	{
		if( EMAC_CheckTransmitIndex() == TRUE )
		{
			/* Will the data fit in the Tx buffer? */
			if( pxNetworkBuffer->xDataLength < EMAC_ETH_MAX_FLEN ) /*_RB_ The size needs to come from FreeRTOSIPConfig.h. */
			{
				/* Assign the buffer to the Tx descriptor that is now known to
				be free. */
				EMAC_SetNextPacketToSend( pxNetworkBuffer->pucEthernetBuffer );

				/* The EMAC now owns the buffer. */
				pxNetworkBuffer->pucEthernetBuffer = NULL;

				/* Initiate the Tx. */
				EMAC_StartTransmitNextBuffer( pxNetworkBuffer->xDataLength );
				iptraceNETWORK_INTERFACE_TRANSMIT();

				/* The Tx has been initiated. */
				xReturn = pdPASS;
			}
			break;
		}
		else
		{
			vTaskDelay( niTX_BUFFER_FREE_WAIT );
		}
	}

	/* Finished with the network buffer. */
	vNetworkBufferRelease( pxNetworkBuffer );

	return xReturn;
}
Example #6
0
BaseType_t xNetworkInterfaceOutput( xNetworkBufferDescriptor_t * const pxNetworkBuffer )
{
BaseType_t xReturn = pdFAIL;
int32_t x;

	/* Attempt to obtain access to a Tx descriptor. */
	for( x = 0; x < niMAX_TX_ATTEMPTS; x++ )
	{
		if( EMAC_CheckTransmitIndex() == TRUE )
		{
			/* Assign the buffer being transmitted to the Tx descriptor. */
			EMAC_SetNextPacketToSend( pxNetworkBuffer->pucEthernetBuffer );

			/* The EMAC now owns the buffer and will free it when it has been
			transmitted.  Set pucBuffer to NULL to ensure the buffer is not
			freed when the network buffer structure is returned to the pool
			of network buffers. */
			pxNetworkBuffer->pucEthernetBuffer = NULL;

			/* Initiate the Tx. */
			EMAC_StartTransmitNextBuffer( pxNetworkBuffer->xDataLength );
			iptraceNETWORK_INTERFACE_TRANSMIT();

			/* The Tx has been initiated. */
			xReturn = pdPASS;

			break;
		}
		else
		{
			iptraceWAITING_FOR_TX_DMA_DESCRIPTOR();
			vTaskDelay( niTX_BUFFER_FREE_WAIT );
		}
	}

	/* Finished with the network buffer. */
	vNetworkBufferRelease( pxNetworkBuffer );

	return xReturn;
}
BaseType_t FreeRTOS_closesocket( xSocket_t xSocket )
{
xNetworkBufferDescriptor_t *pxNetworkBuffer;
xFreeRTOS_Socket_t *pxSocket;

	pxSocket = ( xFreeRTOS_Socket_t * ) xSocket;

	configASSERT( pxSocket );
	configASSERT( pxSocket != FREERTOS_INVALID_SOCKET );

	/* Socket must be unbound first, to ensure no more packets are queued on
	it. */
	if( socketSOCKET_IS_BOUND( pxSocket ) != pdFALSE )
	{
		taskENTER_CRITICAL();
		{
			uxListRemove( &( pxSocket->xBoundSocketListItem ) );
		}
		taskEXIT_CRITICAL();
	}

	/* Now the socket is not bound the list of waiting packets can be
	drained. */
	if( pxSocket->xWaitingPacketSemaphore != NULL )
	{
		while( listCURRENT_LIST_LENGTH( &( pxSocket->xWaitingPacketsList ) ) > 0U )
		{
			pxNetworkBuffer = ( xNetworkBufferDescriptor_t * ) listGET_OWNER_OF_HEAD_ENTRY( &( pxSocket->xWaitingPacketsList ) );
			uxListRemove( &( pxNetworkBuffer->xBufferListItem ) );
			vNetworkBufferRelease( pxNetworkBuffer );
		}
		vSemaphoreDelete( pxSocket->xWaitingPacketSemaphore );
	}

	vPortFree( pxSocket );

	return 0;
} /* Tested */
static void prvInterruptSimulatorTask( void *pvParameters )
{
static struct pcap_pkthdr *pxHeader;
const uint8_t *pucPacketData;
long lResult;
xNetworkBufferDescriptor_t *pxNetworkBuffer;
xIPStackEvent_t xRxEvent = { eEthernetRxEvent, NULL };
eFrameProcessingResult_t eResult;

	/* Just to kill the compiler warning. */
	( void ) pvParameters;

	for( ;; )
	{
		/* Get the next packet. */
		xSemaphoreTake( xPCAPMutex, portMAX_DELAY );
		{
			lResult = pcap_next_ex( pxOpenedInterfaceHandle, &pxHeader, &pucPacketData );
		}
		xSemaphoreGive( xPCAPMutex );

		if( lResult == 1 )
		{
			eResult = ipCONSIDER_FRAME_FOR_PROCESSING( pucPacketData );
			if( eResult == eProcessBuffer )
			{
				/* Will the data fit into the frame buffer? */
				if( pxHeader->len <= ipTOTAL_ETHERNET_FRAME_SIZE )
				{
					/* Obtain a buffer into which the data can be placed.  This
					is only	an interrupt simulator, not a real interrupt, so it
					is ok to call the task level function here.  */
					xSemaphoreTake( xPCAPMutex, portMAX_DELAY );
					{
						pxNetworkBuffer = pxNetworkBufferGet( pxHeader->len, 0 );
					}
					xSemaphoreGive( xPCAPMutex );

					if( pxNetworkBuffer != NULL )
					{
						memcpy( pxNetworkBuffer->pucEthernetBuffer, pucPacketData, pxHeader->len );
						pxNetworkBuffer->xDataLength = ( size_t ) pxHeader->len;
						xRxEvent.pvData = ( void * ) pxNetworkBuffer;

						/* Data was received and stored.  Send a message to the IP
						task to let it know. */
						if( xQueueSendToBack( xNetworkEventQueue, &xRxEvent, ( portTickType ) 0 ) == pdFALSE )
						{
							/* The buffer could not be sent to the stack so
							must be released again.  This is only an interrupt
							simulator, not a real interrupt, so it is ok to use
							the task level function here. */
							vNetworkBufferRelease( pxNetworkBuffer );
							iptraceETHERNET_RX_EVENT_LOST();
						}
						else
						{
							iptraceNETWORK_INTERFACE_RECEIVE();
						}
					}
					else
					{
						iptraceETHERNET_RX_EVENT_LOST();
					}
				}
				else
				{
					/* Log that a packet was dropped because it would have
					overflowed the buffer. */
				}
			}
		}
		else
		{
			/* There is no real way of simulating an interrupt.  Make sure
			other tasks can run. */
			vTaskDelay( configWINDOWS_MAC_INTERRUPT_SIMULATOR_DELAY );
		}
	}
}
static void prvEMACHandlerTask( void *pvParameters )
{
size_t xDataLength;
const uint16_t usCRCLength = 4;
xNetworkBufferDescriptor_t *pxNetworkBuffer;
xIPStackEvent_t xRxEvent = { eEthernetRxEvent, NULL };

/* This is not included in the header file for some reason. */
extern uint8_t *EMAC_NextPacketToRead( void );

	( void ) pvParameters;
	configASSERT( xEMACRxEventSemaphore );

	for( ;; )
	{
		/* Wait for the EMAC interrupt to indicate that another packet has been
		received.  The while() loop is only needed if INCLUDE_vTaskSuspend is
		set to 0 in FreeRTOSConfig.h. */
		while( xSemaphoreTake( xEMACRxEventSemaphore, portMAX_DELAY ) == pdFALSE );

		/* At least one packet has been received. */
		while( EMAC_CheckReceiveIndex() != FALSE )
		{
			/* Obtain the length, minus the CRC.  The CRC is four bytes
			but the length is already minus 1. */
			xDataLength = ( size_t ) EMAC_GetReceiveDataSize() - ( usCRCLength - 1U );

			if( xDataLength > 0U )
			{
				/* Obtain a network buffer to pass this data into the
				stack.  No storage is required as the network buffer
				will point directly to the buffer that already holds
				the	received data. */
				pxNetworkBuffer = pxNetworkBufferGet( 0, ( portTickType ) 0 );

				if( pxNetworkBuffer != NULL )
				{
					pxNetworkBuffer->pucEthernetBuffer = EMAC_NextPacketToRead();
					pxNetworkBuffer->xDataLength = xDataLength;
					xRxEvent.pvData = ( void * ) pxNetworkBuffer;

					/* Data was received and stored.  Send a message to the IP
					task to let it know. */
					if( xQueueSendToBack( xNetworkEventQueue, &xRxEvent, ( portTickType ) 0 ) == pdFALSE )
					{
						vNetworkBufferRelease( pxNetworkBuffer );
						iptraceETHERNET_RX_EVENT_LOST();
					}
				}
				else
				{
					iptraceETHERNET_RX_EVENT_LOST();
				}

				iptraceNETWORK_INTERFACE_RECEIVE();
			}

			/* Release the frame. */
			EMAC_UpdateRxConsumeIndex();
		}
	}
}
xNetworkBufferDescriptor_t *pxNetworkBufferGet( size_t xRequestedSizeBytes, TickType_t xBlockTimeTicks )
{
xNetworkBufferDescriptor_t *pxReturn = NULL;

	if( ( xRequestedSizeBytes != 0 ) && ( xRequestedSizeBytes < sizeof( xARPPacket_t ) ) )
	{
		/* ARP packets can replace application packets, so the storage must be
		at least large enough to hold an ARP. */
		xRequestedSizeBytes = sizeof( xARPPacket_t );
	}

	/* If there is a semaphore available, there is a network buffer available. */
	if( xSemaphoreTake( xNetworkBufferSemaphore, xBlockTimeTicks ) == pdPASS )
	{
		/* Protect the structure as it is accessed from tasks and interrupts. */
		taskENTER_CRITICAL();
		{
			pxReturn = ( xNetworkBufferDescriptor_t * ) listGET_OWNER_OF_HEAD_ENTRY( &xFreeBuffersList );
			uxListRemove( &( pxReturn->xBufferListItem ) );
		}
		taskEXIT_CRITICAL();

		/* Allocate storage of exactly the requested size to the buffer. */
		configASSERT( pxReturn->pucEthernetBuffer == NULL );
		if( xRequestedSizeBytes > 0 )
		{
			/* Extra space is obtained so a pointer to the network buffer can
			be stored at the beginning of the buffer. */
			pxReturn->pucEthernetBuffer = ( uint8_t * ) pvPortMalloc( xRequestedSizeBytes + ipBUFFER_PADDING );

			if( pxReturn->pucEthernetBuffer == NULL )
			{
				/* The attempt to allocate storage for the buffer payload failed,
				so the network buffer structure cannot be used and must be
				released. */
				vNetworkBufferRelease( pxReturn );
				pxReturn = NULL;
			}
			else
			{
				/* Store a pointer to the network buffer structure in the
				buffer storage area, then move the buffer pointer on past the
				stored pointer so the pointer value is not overwritten by the
				application when the buffer is used. */
				*( ( xNetworkBufferDescriptor_t ** ) ( pxReturn->pucEthernetBuffer ) ) = pxReturn;
				pxReturn->pucEthernetBuffer += ipBUFFER_PADDING;
				iptraceNETWORK_BUFFER_OBTAINED( pxReturn );

				/* Store the actual size of the allocated buffer, which may be
				greater than the requested size. */
				pxReturn->xDataLength = xRequestedSizeBytes;
			}
		}
		else
		{
			iptraceNETWORK_BUFFER_OBTAINED( pxReturn );
		}
	}

	if( pxReturn == NULL )
	{
		iptraceFAILED_TO_OBTAIN_NETWORK_BUFFER();
	}

	return pxReturn;
}
static void prvGMACDeferredInterruptHandlerTask( void *pvParameters )
{
xNetworkBufferDescriptor_t *pxNetworkBuffer;
xIPStackEvent_t xRxEvent = { eEthernetRxEvent, NULL };
static const TickType_t xBufferWaitDelay = 1500UL / portTICK_RATE_MS;
uint32_t ulReturned;

	( void ) pvParameters;
	configASSERT( xGMACRxEventSemaphore );

	for( ;; )
	{
		/* Wait for the GMAC interrupt to indicate that another packet has been
		received.  The while() loop is only needed if INCLUDE_vTaskSuspend is
		set to 0 in FreeRTOSConfig.h.  If INCLUDE_vTaskSuspend is set to 1
		then portMAX_DELAY would be an indefinite block time and
		xSemaphoreTake() would only return when the semaphore was actually
		obtained. */
		while( xSemaphoreTake( xGMACRxEventSemaphore, portMAX_DELAY ) == pdFALSE );

		/* Allocate a buffer to hold the data. */
		pxNetworkBuffer = pxNetworkBufferGet( ipTOTAL_ETHERNET_FRAME_SIZE, xBufferWaitDelay );

		if( pxNetworkBuffer != NULL )
		{
			/* At least one packet has been received. */
			ulReturned = gmac_dev_read( &xGMACStruct, pxNetworkBuffer->pucEthernetBuffer, ipTOTAL_ETHERNET_FRAME_SIZE, ( uint32_t * ) &( pxNetworkBuffer->xDataLength ) );
			if( ulReturned == GMAC_OK )
			{
				#if ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES == 1
				{
					if( pxNetworkBuffer->xDataLength > 0 )
					{
						/* If the frame would not be processed by the IP stack then
						don't even bother sending it to the IP stack. */
						if( eConsiderFrameForProcessing( pxNetworkBuffer->pucEthernetBuffer ) != eProcessBuffer )
						{
							pxNetworkBuffer->xDataLength = 0;
						}
					}
				}
				#endif

				if( pxNetworkBuffer->xDataLength > 0 )
				{
					/* Store a pointer to the network buffer structure in the
					padding	space that was left in front of the Ethernet frame.
					The pointer	is needed to ensure the network buffer structure
					can be located when it is time for it to be freed if the
					Ethernet frame gets	used as a zero copy buffer. */
					*( ( xNetworkBufferDescriptor_t ** ) ( ( pxNetworkBuffer->pucEthernetBuffer - ipBUFFER_PADDING ) ) ) = pxNetworkBuffer;

					/* Data was received and stored.  Send it to the IP task
					for processing. */
					xRxEvent.pvData = ( void * ) pxNetworkBuffer;
					if( xQueueSendToBack( xNetworkEventQueue, &xRxEvent, ( TickType_t ) 0 ) == pdFALSE )
					{
						/* The buffer could not be sent to the IP task so the
						buffer must be released. */
						vNetworkBufferRelease( pxNetworkBuffer );
						iptraceETHERNET_RX_EVENT_LOST();
					}
					else
					{
						iptraceNETWORK_INTERFACE_RECEIVE();
					}
				}
				else
				{
					/* The buffer does not contain any data so there is no
					point sending it to the IP task.  Just release it. */
					vNetworkBufferRelease( pxNetworkBuffer );
					iptraceETHERNET_RX_EVENT_LOST();
				}
			}
			else
			{
				vNetworkBufferRelease( pxNetworkBuffer );
				iptraceETHERNET_RX_EVENT_LOST();
			}
		}
		else
		{
			/* Left a frame in the driver as a buffer was not available. */
			gmac_dev_reset( &xGMACStruct );
		}
	}
}
Example #12
0
	int32_t FreeRTOS_sendto( xSocket_t xSocket, const void *pvBuffer, size_t xTotalDataLength, uint32_t ulFlags, const struct freertos_sockaddr *pxDestinationAddress, socklen_t xDestinationAddressLength )
	{
	xNetworkBufferDescriptor_t *pxNetworkBuffer;
	xIPStackEvent_t xStackTxEvent = { eStackTxEvent, NULL };
	extern xQueueHandle xNetworkEventQueue;
	xTimeOutType xTimeOut;
	TickType_t xTicksToWait;
	int32_t lReturn = 0;
	xFreeRTOS_Socket_t *pxSocket;
	uint8_t *pucBuffer;

		pxSocket = ( xFreeRTOS_Socket_t * ) xSocket;

		/* The function prototype is designed to maintain the expected Berkeley
		sockets standard, but this implementation does not use all the
		parameters. */
		( void ) xDestinationAddressLength;
		configASSERT( xNetworkEventQueue );
		configASSERT( pvBuffer );

		if( xTotalDataLength <= ipMAX_UDP_PAYLOAD_LENGTH )
		{
			if( socketSOCKET_IS_BOUND( pxSocket ) == pdFALSE )
			{
				/* If the socket is not already bound to an address, bind it now.
				Passing NULL as the address parameter tells FreeRTOS_bind() to
				select the address to bind to. */
				FreeRTOS_bind( pxSocket, NULL, 0 );
			}

			if( socketSOCKET_IS_BOUND( pxSocket ) != pdFALSE )
			{
				xTicksToWait = pxSocket->xSendBlockTime;

				if( ( ulFlags & FREERTOS_ZERO_COPY ) == 0 )
				{
					/* Zero copy is not set, so obtain a network buffer into
					which the payload will be copied. */
					vTaskSetTimeOutState( &xTimeOut );
					pxNetworkBuffer = pxNetworkBufferGet( xTotalDataLength + sizeof( xUDPPacket_t ), xTicksToWait );

					if( pxNetworkBuffer != NULL )
					{
						memcpy( ( void * ) &( pxNetworkBuffer->pucEthernetBuffer[ ipUDP_PAYLOAD_OFFSET ] ), ( void * ) pvBuffer, xTotalDataLength );

						if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdTRUE )
						{
							/* The entire block time has been used up. */
							xTicksToWait = 0;
						}
					}
				}
				else
				{
					/* When zero copy is used, pvBuffer is a pointer to the
					payload of a buffer that has already been obtained from the
					stack.  Obtain the network buffer pointer from the buffer. */
					pucBuffer = ( uint8_t * ) pvBuffer;
					pucBuffer -= ( ipBUFFER_PADDING + sizeof( xUDPPacket_t ) );
					pxNetworkBuffer = * ( ( xNetworkBufferDescriptor_t ** ) pucBuffer );
				}

				if( pxNetworkBuffer != NULL )
				{
					pxNetworkBuffer->xDataLength = xTotalDataLength;
					pxNetworkBuffer->usPort = pxDestinationAddress->sin_port;
					pxNetworkBuffer->usBoundPort = ( uint16_t ) socketGET_SOCKET_ADDRESS( pxSocket );
					pxNetworkBuffer->ulIPAddress = pxDestinationAddress->sin_addr;

					/* The socket options are passed to the IP layer in the
					space that will eventually get used by the Ethernet header. */
					pxNetworkBuffer->pucEthernetBuffer[ ipSOCKET_OPTIONS_OFFSET ] = pxSocket->ucSocketOptions;

					/* Tell the networking task that the packet needs sending. */
					xStackTxEvent.pvData = pxNetworkBuffer;

					if( xQueueSendToBack( xNetworkEventQueue, &xStackTxEvent, xTicksToWait ) != pdPASS )
					{
						/* If the buffer was allocated in this function, release it. */
						if( ( ulFlags & FREERTOS_ZERO_COPY ) == 0 )
						{
							vNetworkBufferRelease( pxNetworkBuffer );
						}
						iptraceSTACK_TX_EVENT_LOST( ipSTACK_TX_EVENT );
					}
					else
					{
						lReturn = ( int32_t ) xTotalDataLength;
					}
				}
				else
				{
					/* If errno was available, errno would be set to
					FREERTOS_ENOPKTS.  As it is, the function must return the
					number of transmitted bytes, so the calling function knows how
					much data was actually sent. */
					iptraceNO_BUFFER_FOR_SENDTO();
				}
			}
			else
			{
				iptraceSENDTO_SOCKET_NOT_BOUND();
			}
		}
		else
		{
			/* The data is longer than the available buffer space.  Setting
			ipconfigCAN_FRAGMENT_OUTGOING_PACKETS to 1 may allow this packet
			to be sent. */
			iptraceSENDTO_DATA_TOO_LONG();
		}

		return lReturn;
	} /* Tested */
Example #13
0
	int32_t FreeRTOS_sendto( xSocket_t xSocket, const void *pvBuffer, size_t xTotalDataLength, uint32_t ulFlags, const struct freertos_sockaddr *pxDestinationAddress, socklen_t xDestinationAddressLength )
	{
	xNetworkBufferDescriptor_t *pxNetworkBuffer;
	xIPFragmentParameters_t *pxFragmentParameters;
	size_t xBytesToSend, xBytesRemaining;
	xIPStackEvent_t xStackTxEvent = { eStackTxEvent, NULL };
	extern xQueueHandle xNetworkEventQueue;
	uint8_t *pucBuffer;
	xTimeOutType xTimeOut;
	TickType_t xTicksToWait;
	uint16_t usFragmentOffset;
	xFreeRTOS_Socket_t *pxSocket;

		pxSocket = ( xFreeRTOS_Socket_t * ) xSocket;

		/* The function prototype is designed to maintain the expected Berkeley
		sockets standard, but this implementation does not use all the
		parameters. */
		( void ) xDestinationAddressLength;
		configASSERT( xNetworkEventQueue );
		configASSERT( pvBuffer );

		xBytesRemaining = xTotalDataLength;

		if( socketSOCKET_IS_BOUND( pxSocket ) == pdFALSE )
		{
			/* If the socket is not already bound to an address, bind it now.
			Passing NULL as the address parameter tells FreeRTOS_bind() to select
			the address to bind to. */
			FreeRTOS_bind( xSocket, NULL, 0 );
		}

		if( socketSOCKET_IS_BOUND( pxSocket ) != pdFALSE )
		{
			/* pucBuffer will be reset if this send turns out to be a zero copy
			send because in that case pvBuffer is actually a pointer to an
			xUserData_t structure, not the UDP payload. */
			pucBuffer = ( uint8_t * ) pvBuffer;
			vTaskSetTimeOutState( &xTimeOut );
			xTicksToWait = pxSocket->xSendBlockTime;

			/* The data being transmitted will be sent in
			ipMAX_UDP_PAYLOAD_LENGTH chunks if xDataLength is greater than the
			network buffer payload size.  Loop until all the data is sent. */
			while( xBytesRemaining > 0 )
			{
				if( xBytesRemaining > ipMAX_UDP_PAYLOAD_LENGTH )
				{
					/* Cap the amount being sent in this packet to the maximum
					UDP payload size.  This will be a multiple of 8 already,
					removing the need to check in the code. */
					xBytesToSend = ipMAX_UDP_PAYLOAD_LENGTH;
				}
				else
				{
					/* Send all remaining bytes - which may well be the total
					number of bytes if the packet was not chopped up. */
					xBytesToSend = xBytesRemaining;
				}

				/* If the zero copy flag is set, then the data is already in a
				network buffer.  Otherwise, get a new network buffer. */
				if( ( ulFlags & FREERTOS_ZERO_COPY ) == 0 )
				{
					if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdTRUE )
					{
						xTicksToWait = 0;
					}

					pxNetworkBuffer = pxNetworkBufferGet( xBytesToSend + sizeof( xUDPPacket_t ), xTicksToWait );
				}
				else
				{
					if( xTotalDataLength > ipMAX_UDP_PAYLOAD_LENGTH )
					{
						/* The packet needs fragmenting, but zero copy buffers
						cannot be fragmented. */
						pxNetworkBuffer = NULL;
					}
					else
					{
						/* When zero copy is used, pvBuffer is a pointer to the
						payload of a buffer that has already been obtained from the
						stack.  Obtain the network buffer pointer from the buffer. */
						pucBuffer = ( uint8_t * ) pvBuffer;
						pucBuffer -= ( ipBUFFER_PADDING + sizeof( xUDPPacket_t ) );
						pxNetworkBuffer = * ( ( xNetworkBufferDescriptor_t ** ) pucBuffer );
					}
				}

				if( pxNetworkBuffer != NULL )
				{
					/* Use the part of the network buffer that will be completed
					by the IP layer as temporary storage to pass extra
					information required by the IP layer. */
					pxFragmentParameters = ( xIPFragmentParameters_t * ) &( pxNetworkBuffer->pucEthernetBuffer[ ipFRAGMENTATION_PARAMETERS_OFFSET ] );
					pxFragmentParameters->ucSocketOptions = pxSocket->ucSocketOptions;

					if( xBytesRemaining > ipMAX_UDP_PAYLOAD_LENGTH )
					{
						/* The packet is being chopped up, and more data will
						follow. */
						pxFragmentParameters->ucSocketOptions = ( pxSocket->ucSocketOptions | FREERTOS_NOT_LAST_IN_FRAGMENTED_PACKET );
					}

					if( xTotalDataLength > ipMAX_UDP_PAYLOAD_LENGTH )
					{
						/* Let the IP layer know this packet has been chopped up,
						and supply the IP layer with any addition information it
						needs to make sense of it. */
						pxFragmentParameters->ucSocketOptions |= FREERTOS_FRAGMENTED_PACKET;
						usFragmentOffset = ( uint16_t ) ( xTotalDataLength - xBytesRemaining );
						pxFragmentParameters->usFragmentedPacketOffset = usFragmentOffset;
						pxFragmentParameters->usFragmentLength = ( uint16_t ) xBytesToSend;
					}
					else
					{
						usFragmentOffset = 0;
					}

					/* Write the payload into the packet.  The IP layer is
					queried to find where in the IP payload the data should be
					written.  This is because the necessary offset is different
					for the first packet, because the first packet leaves space
					for a UDP header.  Note that this changes usFragmentOffset
					from the offset in the entire UDP packet, to the offset
					in the IP packet. */
					if( ( ulFlags & FREERTOS_ZERO_COPY ) == 0 )
					{
						/* Only copy the data if it is not already in the
						expected location. */
						usFragmentOffset = ipGET_UDP_PAYLOAD_OFFSET_FOR_FRAGMENT( usFragmentOffset );
						memcpy( ( void * ) &( pxNetworkBuffer->pucEthernetBuffer[ usFragmentOffset ] ), ( void * ) pucBuffer, xBytesToSend );
					}
					pxNetworkBuffer->xDataLength = xTotalDataLength;
					pxNetworkBuffer->usPort = pxDestinationAddress->sin_port;
					pxNetworkBuffer->usBoundPort = ( uint16_t ) socketGET_SOCKET_ADDRESS( pxSocket );
					pxNetworkBuffer->ulIPAddress = pxDestinationAddress->sin_addr;

					/* Tell the networking task that the packet needs sending. */
					xStackTxEvent.pvData = pxNetworkBuffer;

					if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdTRUE )
					{
						xTicksToWait = 0;
					}

					if( xQueueSendToBack( xNetworkEventQueue, &xStackTxEvent, xTicksToWait ) != pdPASS )
					{
						/* If the buffer was allocated in this function, release it. */
						if( ( ulFlags & FREERTOS_ZERO_COPY ) == 0 )
						{
							vNetworkBufferRelease( pxNetworkBuffer );
						}
						iptraceSTACK_TX_EVENT_LOST( ipSTACK_TX_EVENT );
						break;
					}

					/* Adjust counters ready to either exit the loop, or send
					another chunk of data. */
					xBytesRemaining -= xBytesToSend;
					pucBuffer += xBytesToSend;
				}
				else
				{
					/* If errno was available, errno would be set to
					FREERTOS_ENOPKTS.  As it is, the function must return the
					number of transmitted bytes, so the calling function knows how
					much data was actually sent. */
					break;
				}
			}
		}

		return ( xTotalDataLength - xBytesRemaining );
	} /* Tested */
Example #14
0
int32_t FreeRTOS_recvfrom( xSocket_t xSocket, void *pvBuffer, size_t xBufferLength, uint32_t ulFlags, struct freertos_sockaddr *pxSourceAddress, socklen_t *pxSourceAddressLength )
{
xNetworkBufferDescriptor_t *pxNetworkBuffer;
int32_t lReturn;
xFreeRTOS_Socket_t *pxSocket;

	pxSocket = ( xFreeRTOS_Socket_t * ) xSocket;

	/* The function prototype is designed to maintain the expected Berkeley
	sockets standard, but this implementation does not use all the parameters. */
	( void ) pxSourceAddressLength;

	if( socketSOCKET_IS_BOUND( pxSocket ) != pdFALSE )
	{
		/* The semaphore is given when received data is queued on the socket. */
		if( xSemaphoreTake( pxSocket->xWaitingPacketSemaphore, pxSocket->xReceiveBlockTime ) == pdPASS )
		{
			taskENTER_CRITICAL();
			{
				configASSERT( ( listCURRENT_LIST_LENGTH( &( pxSocket->xWaitingPacketsList ) ) > 0U ) );

				/* The owner of the list item is the network buffer. */
				pxNetworkBuffer = ( xNetworkBufferDescriptor_t * ) listGET_OWNER_OF_HEAD_ENTRY( &( pxSocket->xWaitingPacketsList ) );

				/* Remove the network buffer from the list of buffers waiting to
				be processed by the socket. */
				uxListRemove( &( pxNetworkBuffer->xBufferListItem ) );
			}
			taskEXIT_CRITICAL();

			if( ( ulFlags & FREERTOS_ZERO_COPY ) == 0 )
			{
				/* The zero copy flag is not set.  Truncate the length if it
				won't fit in the provided buffer. */
				if( pxNetworkBuffer->xDataLength > xBufferLength )
				{
					iptraceRECVFROM_DISCARDING_BYTES( ( xBufferLength - pxNetworkBuffer->xDataLength ) );
					pxNetworkBuffer->xDataLength = xBufferLength;
				}

				/* Copy the received data into the provided buffer, then
				release the network buffer. */
				memcpy( pvBuffer, ( void * ) &( pxNetworkBuffer->pucEthernetBuffer[ ipUDP_PAYLOAD_OFFSET ] ), pxNetworkBuffer->xDataLength );
				vNetworkBufferRelease( pxNetworkBuffer );
			}
			else
			{
				/* The zero copy flag was set.  pvBuffer is not a buffer into
				which the received data can be copied, but a pointer that must
				be set to point to the buffer in which the received data has
				already been placed. */
				*( ( void** ) pvBuffer ) = ( void * ) ( &( pxNetworkBuffer->pucEthernetBuffer[ ipUDP_PAYLOAD_OFFSET ] ) );
			}

			/* The returned value is the data length, which may have been
			capped to the receive buffer size. */
			lReturn = ( int32_t ) pxNetworkBuffer->xDataLength;

			if( pxSourceAddress != NULL )
			{
				pxSourceAddress->sin_port = pxNetworkBuffer->usPort;
				pxSourceAddress->sin_addr = pxNetworkBuffer->ulIPAddress;
			}
		}
		else
		{
			lReturn = FREERTOS_EWOULDBLOCK;
			iptraceRECVFROM_TIMEOUT();
		}
	}
	else
	{
		lReturn = FREERTOS_EINVAL;
	}

	return lReturn;
}
Example #15
0
static void prvEMACDeferredInterruptHandlerTask( void *pvParameters )
{
xNetworkBufferDescriptor_t *pxNetworkBuffer;
xIPStackEvent_t xRxEvent = { eEthernetRxEvent, NULL };

	( void ) pvParameters;
	configASSERT( xEMACRxEventSemaphore );

	for( ;; )
	{
		/* Wait for the EMAC interrupt to indicate that another packet has been
		received.  The while() loop is only needed if INCLUDE_vTaskSuspend is
		set to 0 in FreeRTOSConfig.h.  If INCLUDE_vTaskSuspend is set to 1
		then portMAX_DELAY would be an indefinite block time and
		xSemaphoreTake() would only return when the semaphore was actually
		obtained. */
		while( xSemaphoreTake( xEMACRxEventSemaphore, portMAX_DELAY ) == pdFALSE );

		/* At least one packet has been received. */
		while( EMAC_CheckReceiveIndex() != FALSE )
		{
			/* The buffer filled by the DMA is going to be passed into the IP
			stack.  Allocate another buffer for the DMA descriptor. */
			pxNetworkBuffer = pxNetworkBufferGet( ipTOTAL_ETHERNET_FRAME_SIZE, ( TickType_t ) 0 );

			if( pxNetworkBuffer != NULL )
			{
				/* Swap the buffer just allocated and referenced from the
				pxNetworkBuffer with the buffer that has already been filled by
				the DMA.  pxNetworkBuffer will then hold a reference to the
				buffer that already contains the data without any data having
				been copied between buffers. */
				EMAC_NextPacketToRead( pxNetworkBuffer );

				#if ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES == 1
				{
					if( pxNetworkBuffer->xDataLength > 0 )
					{
						/* If the frame would not be processed by the IP stack then
						don't even bother sending it to the IP stack. */
						if( eConsiderFrameForProcessing( pxNetworkBuffer->pucEthernetBuffer ) != eProcessBuffer )
						{
							pxNetworkBuffer->xDataLength = 0;
						}
					}
				}
				#endif

				if( pxNetworkBuffer->xDataLength > 0 )
				{
					/* Store a pointer to the network buffer structure in the
					padding	space that was left in front of the Ethernet frame.
					The pointer	is needed to ensure the network buffer structure
					can be located when it is time for it to be freed if the
					Ethernet frame gets	used as a zero copy buffer. */
					*( ( xNetworkBufferDescriptor_t ** ) ( ( pxNetworkBuffer->pucEthernetBuffer - ipBUFFER_PADDING ) ) ) = pxNetworkBuffer;

					/* Data was received and stored.  Send it to the IP task
					for processing. */
					xRxEvent.pvData = ( void * ) pxNetworkBuffer;
					if( xQueueSendToBack( xNetworkEventQueue, &xRxEvent, ( TickType_t ) 0 ) == pdFALSE )
					{
						/* The buffer could not be sent to the IP task so the
						buffer must be released. */
						vNetworkBufferRelease( pxNetworkBuffer );
						iptraceETHERNET_RX_EVENT_LOST();
					}
					else
					{
						iptraceNETWORK_INTERFACE_RECEIVE();
					}
				}
				else
				{
					/* The buffer does not contain any data so there is no
					point sending it to the IP task.  Just release it. */
					vNetworkBufferRelease( pxNetworkBuffer );
					iptraceETHERNET_RX_EVENT_LOST();
				}
			}
			else
			{
				iptraceETHERNET_RX_EVENT_LOST();
			}

			/* Release the descriptor. */
			EMAC_UpdateRxConsumeIndex();
		}
	}
}