mirror of
https://github.com/FreeRTOS/FreeRTOS-Kernel.git
synced 2025-08-29 22:48:37 -04:00
Added +TCP code to main repo.
This commit is contained in:
parent
037abdddf2
commit
77e95538dc
114 changed files with 46629 additions and 446 deletions
420
FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_UDP_IP.c
Normal file
420
FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_UDP_IP.c
Normal file
|
@ -0,0 +1,420 @@
|
|||
/*
|
||||
* FreeRTOS+TCP Labs Build 160919 (C) 2016 Real Time Engineers ltd.
|
||||
* Authors include Hein Tibosch and Richard Barry
|
||||
*
|
||||
*******************************************************************************
|
||||
***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
|
||||
*** ***
|
||||
*** ***
|
||||
*** FREERTOS+TCP IS STILL IN THE LAB (mainly because the FTP and HTTP ***
|
||||
*** demos have a dependency on FreeRTOS+FAT, which is only in the Labs ***
|
||||
*** download): ***
|
||||
*** ***
|
||||
*** FreeRTOS+TCP is functional and has been used in commercial products ***
|
||||
*** for some time. Be aware however that we are still refining its ***
|
||||
*** design, the source code does not yet quite conform to the strict ***
|
||||
*** coding and style standards mandated by Real Time Engineers ltd., and ***
|
||||
*** the documentation and testing is not necessarily complete. ***
|
||||
*** ***
|
||||
*** PLEASE REPORT EXPERIENCES USING THE SUPPORT RESOURCES FOUND ON THE ***
|
||||
*** URL: http://www.FreeRTOS.org/contact Active early adopters may, at ***
|
||||
*** the sole discretion of Real Time Engineers Ltd., be offered versions ***
|
||||
*** under a license other than that described below. ***
|
||||
*** ***
|
||||
*** ***
|
||||
***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
|
||||
*******************************************************************************
|
||||
*
|
||||
* FreeRTOS+TCP can be used under two different free open source licenses. The
|
||||
* license that applies is dependent on the processor on which FreeRTOS+TCP is
|
||||
* executed, as follows:
|
||||
*
|
||||
* If FreeRTOS+TCP is executed on one of the processors listed under the Special
|
||||
* License Arrangements heading of the FreeRTOS+TCP license information web
|
||||
* page, then it can be used under the terms of the FreeRTOS Open Source
|
||||
* License. If FreeRTOS+TCP is used on any other processor, then it can be used
|
||||
* under the terms of the GNU General Public License V2. Links to the relevant
|
||||
* licenses follow:
|
||||
*
|
||||
* The FreeRTOS+TCP License Information Page: http://www.FreeRTOS.org/tcp_license
|
||||
* The FreeRTOS Open Source License: http://www.FreeRTOS.org/license
|
||||
* The GNU General Public License Version 2: http://www.FreeRTOS.org/gpl-2.0.txt
|
||||
*
|
||||
* FreeRTOS+TCP is distributed in the hope that it will be useful. You cannot
|
||||
* use FreeRTOS+TCP unless you agree that you use the software 'as is'.
|
||||
* FreeRTOS+TCP is provided WITHOUT ANY WARRANTY; without even the implied
|
||||
* warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. Real Time Engineers Ltd. disclaims all conditions and terms, be they
|
||||
* implied, expressed, or statutory.
|
||||
*
|
||||
* 1 tab == 4 spaces!
|
||||
*
|
||||
* http://www.FreeRTOS.org
|
||||
* http://www.FreeRTOS.org/plus
|
||||
* http://www.FreeRTOS.org/labs
|
||||
*
|
||||
*/
|
||||
|
||||
/* Standard includes. */
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/* FreeRTOS includes. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "queue.h"
|
||||
#include "semphr.h"
|
||||
|
||||
/* FreeRTOS+TCP includes. */
|
||||
#include "FreeRTOS_IP.h"
|
||||
#include "FreeRTOS_Sockets.h"
|
||||
#include "FreeRTOS_IP_Private.h"
|
||||
#include "FreeRTOS_UDP_IP.h"
|
||||
#include "FreeRTOS_ARP.h"
|
||||
#include "FreeRTOS_DHCP.h"
|
||||
#include "NetworkInterface.h"
|
||||
#include "NetworkBufferManagement.h"
|
||||
|
||||
#if( ipconfigUSE_DNS == 1 )
|
||||
#include "FreeRTOS_DNS.h"
|
||||
#endif
|
||||
|
||||
/* The expected IP version and header length coded into the IP header itself. */
|
||||
#define ipIP_VERSION_AND_HEADER_LENGTH_BYTE ( ( uint8_t ) 0x45 )
|
||||
|
||||
/* Part of the Ethernet and IP headers are always constant when sending an IPv4
|
||||
UDP packet. This array defines the constant parts, allowing this part of the
|
||||
packet to be filled in using a simple memcpy() instead of individual writes. */
|
||||
UDPPacketHeader_t xDefaultPartUDPPacketHeader =
|
||||
{
|
||||
/* .ucBytes : */
|
||||
{
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Ethernet source MAC address. */
|
||||
0x08, 0x00, /* Ethernet frame type. */
|
||||
ipIP_VERSION_AND_HEADER_LENGTH_BYTE, /* ucVersionHeaderLength. */
|
||||
0x00, /* ucDifferentiatedServicesCode. */
|
||||
0x00, 0x00, /* usLength. */
|
||||
0x00, 0x00, /* usIdentification. */
|
||||
0x00, 0x00, /* usFragmentOffset. */
|
||||
ipconfigUDP_TIME_TO_LIVE, /* ucTimeToLive */
|
||||
ipPROTOCOL_UDP, /* ucProtocol. */
|
||||
0x00, 0x00, /* usHeaderChecksum. */
|
||||
0x00, 0x00, 0x00, 0x00 /* Source IP address. */
|
||||
}
|
||||
};
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vProcessGeneratedUDPPacket( NetworkBufferDescriptor_t * const pxNetworkBuffer )
|
||||
{
|
||||
UDPPacket_t *pxUDPPacket;
|
||||
IPHeader_t *pxIPHeader;
|
||||
eARPLookupResult_t eReturned;
|
||||
uint32_t ulIPAddress = pxNetworkBuffer->ulIPAddress;
|
||||
|
||||
/* Map the UDP packet onto the start of the frame. */
|
||||
pxUDPPacket = ( UDPPacket_t * ) pxNetworkBuffer->pucEthernetBuffer;
|
||||
|
||||
/* Determine the ARP cache status for the requested IP address. */
|
||||
eReturned = eARPGetCacheEntry( &( ulIPAddress ), &( pxUDPPacket->xEthernetHeader.xDestinationAddress ) );
|
||||
|
||||
if( eReturned != eCantSendPacket )
|
||||
{
|
||||
if( eReturned == eARPCacheHit )
|
||||
{
|
||||
#if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 0 )
|
||||
uint8_t ucSocketOptions;
|
||||
#endif
|
||||
iptraceSENDING_UDP_PACKET( pxNetworkBuffer->ulIPAddress );
|
||||
|
||||
/* Create short cuts to the data within the packet. */
|
||||
pxIPHeader = &( pxUDPPacket->xIPHeader );
|
||||
|
||||
#if ( ipconfigSUPPORT_OUTGOING_PINGS == 1 )
|
||||
/* Is it possible that the packet is not actually a UDP packet
|
||||
after all, but an ICMP packet. */
|
||||
if( pxNetworkBuffer->usPort != ipPACKET_CONTAINS_ICMP_DATA )
|
||||
#endif /* ipconfigSUPPORT_OUTGOING_PINGS */
|
||||
{
|
||||
UDPHeader_t *pxUDPHeader;
|
||||
|
||||
pxUDPHeader = &( pxUDPPacket->xUDPHeader );
|
||||
|
||||
pxUDPHeader->usDestinationPort = pxNetworkBuffer->usPort;
|
||||
pxUDPHeader->usSourcePort = pxNetworkBuffer->usBoundPort;
|
||||
pxUDPHeader->usLength = ( uint16_t ) ( pxNetworkBuffer->xDataLength + sizeof( UDPHeader_t ) );
|
||||
pxUDPHeader->usLength = FreeRTOS_htons( pxUDPHeader->usLength );
|
||||
pxUDPHeader->usChecksum = 0u;
|
||||
}
|
||||
|
||||
/* memcpy() the constant parts of the header information into
|
||||
the correct location within the packet. This fills in:
|
||||
xEthernetHeader.xSourceAddress
|
||||
xEthernetHeader.usFrameType
|
||||
xIPHeader.ucVersionHeaderLength
|
||||
xIPHeader.ucDifferentiatedServicesCode
|
||||
xIPHeader.usLength
|
||||
xIPHeader.usIdentification
|
||||
xIPHeader.usFragmentOffset
|
||||
xIPHeader.ucTimeToLive
|
||||
xIPHeader.ucProtocol
|
||||
and
|
||||
xIPHeader.usHeaderChecksum
|
||||
*/
|
||||
|
||||
/* Save options now, as they will be overwritten by memcpy */
|
||||
#if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 0 )
|
||||
{
|
||||
ucSocketOptions = pxNetworkBuffer->pucEthernetBuffer[ ipSOCKET_OPTIONS_OFFSET ];
|
||||
}
|
||||
#endif
|
||||
|
||||
memcpy( ( void *) &( pxUDPPacket->xEthernetHeader.xSourceAddress ), ( void * ) xDefaultPartUDPPacketHeader.ucBytes, sizeof( xDefaultPartUDPPacketHeader ) );
|
||||
|
||||
#if ipconfigSUPPORT_OUTGOING_PINGS == 1
|
||||
if( pxNetworkBuffer->usPort == ipPACKET_CONTAINS_ICMP_DATA )
|
||||
{
|
||||
pxIPHeader->ucProtocol = ipPROTOCOL_ICMP;
|
||||
pxIPHeader->usLength = ( uint16_t ) ( pxNetworkBuffer->xDataLength + sizeof( IPHeader_t ) );
|
||||
}
|
||||
else
|
||||
#endif /* ipconfigSUPPORT_OUTGOING_PINGS */
|
||||
{
|
||||
pxIPHeader->usLength = ( uint16_t ) ( pxNetworkBuffer->xDataLength + sizeof( IPHeader_t ) + sizeof( UDPHeader_t ) );
|
||||
}
|
||||
|
||||
/* The total transmit size adds on the Ethernet header. */
|
||||
pxNetworkBuffer->xDataLength = pxIPHeader->usLength + sizeof( EthernetHeader_t );
|
||||
pxIPHeader->usLength = FreeRTOS_htons( pxIPHeader->usLength );
|
||||
pxIPHeader->ulDestinationIPAddress = pxNetworkBuffer->ulIPAddress;
|
||||
|
||||
#if( ipconfigUSE_LLMNR == 1 )
|
||||
{
|
||||
/* LLMNR messages are typically used on a LAN and they're
|
||||
* not supposed to cross routers */
|
||||
if( pxNetworkBuffer->ulIPAddress == ipLLMNR_IP_ADDR )
|
||||
{
|
||||
pxIPHeader->ucTimeToLive = 0x01;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 0 )
|
||||
{
|
||||
pxIPHeader->usHeaderChecksum = 0u;
|
||||
pxIPHeader->usHeaderChecksum = usGenerateChecksum( 0UL, ( uint8_t * ) &( pxIPHeader->ucVersionHeaderLength ), ipSIZE_OF_IPv4_HEADER );
|
||||
pxIPHeader->usHeaderChecksum = ~FreeRTOS_htons( pxIPHeader->usHeaderChecksum );
|
||||
|
||||
if( ( ucSocketOptions & ( uint8_t ) FREERTOS_SO_UDPCKSUM_OUT ) != 0u )
|
||||
{
|
||||
usGenerateProtocolChecksum( (uint8_t*)pxUDPPacket, pdTRUE );
|
||||
}
|
||||
else
|
||||
{
|
||||
pxUDPPacket->xUDPHeader.usChecksum = 0u;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else if( eReturned == eARPCacheMiss )
|
||||
{
|
||||
/* Add an entry to the ARP table with a null hardware address.
|
||||
This allows the ARP timer to know that an ARP reply is
|
||||
outstanding, and perform retransmissions if necessary. */
|
||||
vARPRefreshCacheEntry( NULL, ulIPAddress );
|
||||
|
||||
/* Generate an ARP for the required IP address. */
|
||||
iptracePACKET_DROPPED_TO_GENERATE_ARP( pxNetworkBuffer->ulIPAddress );
|
||||
pxNetworkBuffer->ulIPAddress = ulIPAddress;
|
||||
vARPGenerateRequestPacket( pxNetworkBuffer );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The lookup indicated that an ARP request has already been
|
||||
sent out for the queried IP address. */
|
||||
eReturned = eCantSendPacket;
|
||||
}
|
||||
}
|
||||
|
||||
if( eReturned != eCantSendPacket )
|
||||
{
|
||||
/* The network driver is responsible for freeing the network buffer
|
||||
after the packet has been sent. */
|
||||
|
||||
#if defined( ipconfigETHERNET_MINIMUM_PACKET_BYTES )
|
||||
{
|
||||
if( pxNetworkBuffer->xDataLength < ( size_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES )
|
||||
{
|
||||
BaseType_t xIndex;
|
||||
|
||||
for( xIndex = ( BaseType_t ) pxNetworkBuffer->xDataLength; xIndex < ( BaseType_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES; xIndex++ )
|
||||
{
|
||||
pxNetworkBuffer->pucEthernetBuffer[ xIndex ] = 0u;
|
||||
}
|
||||
pxNetworkBuffer->xDataLength = ( size_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
xNetworkInterfaceOutput( pxNetworkBuffer, pdTRUE );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The packet can't be sent (DHCP not completed?). Just drop the
|
||||
packet. */
|
||||
vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
BaseType_t xProcessReceivedUDPPacket( NetworkBufferDescriptor_t *pxNetworkBuffer, uint16_t usPort )
|
||||
{
|
||||
BaseType_t xReturn = pdPASS;
|
||||
FreeRTOS_Socket_t *pxSocket;
|
||||
|
||||
UDPPacket_t *pxUDPPacket = (UDPPacket_t *) pxNetworkBuffer->pucEthernetBuffer;
|
||||
|
||||
pxSocket = pxUDPSocketLookup( usPort );
|
||||
|
||||
if( pxSocket )
|
||||
{
|
||||
|
||||
/* When refreshing the ARP cache with received UDP packets we must be
|
||||
careful; hundreds of broadcast messages may pass and if we're not
|
||||
handling them, no use to fill the ARP cache with those IP addresses. */
|
||||
vARPRefreshCacheEntry( &( pxUDPPacket->xEthernetHeader.xSourceAddress ), pxUDPPacket->xIPHeader.ulSourceIPAddress );
|
||||
|
||||
#if( ipconfigUSE_CALLBACKS == 1 )
|
||||
{
|
||||
/* Did the owner of this socket register a reception handler ? */
|
||||
if( ipconfigIS_VALID_PROG_ADDRESS( pxSocket->u.xUDP.pxHandleReceive ) )
|
||||
{
|
||||
struct freertos_sockaddr xSourceAddress, destinationAddress;
|
||||
void *pcData = ( void * ) &( pxNetworkBuffer->pucEthernetBuffer[ ipUDP_PAYLOAD_OFFSET_IPv4 ] );
|
||||
FOnUDPReceive_t xHandler = ( FOnUDPReceive_t ) pxSocket->u.xUDP.pxHandleReceive;
|
||||
xSourceAddress.sin_port = pxNetworkBuffer->usPort;
|
||||
xSourceAddress.sin_addr = pxNetworkBuffer->ulIPAddress;
|
||||
destinationAddress.sin_port = usPort;
|
||||
destinationAddress.sin_addr = pxUDPPacket->xIPHeader.ulDestinationIPAddress;
|
||||
|
||||
if( xHandler( ( Socket_t * ) pxSocket, ( void* ) pcData, ( size_t ) pxNetworkBuffer->xDataLength,
|
||||
&xSourceAddress, &destinationAddress ) != pdFALSE )
|
||||
{
|
||||
xReturn = pdFAIL; /* xHandler has consumed the data, do not add it to .xWaitingPacketsList'. */
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* ipconfigUSE_CALLBACKS */
|
||||
|
||||
#if( ipconfigUDP_MAX_RX_PACKETS > 0 )
|
||||
{
|
||||
if( xReturn == pdPASS )
|
||||
{
|
||||
if ( listCURRENT_LIST_LENGTH( &( pxSocket->u.xUDP.xWaitingPacketsList ) ) >= pxSocket->u.xUDP.uxMaxPackets )
|
||||
{
|
||||
FreeRTOS_debug_printf( ( "xProcessReceivedUDPPacket: buffer full %ld >= %ld port %u\n",
|
||||
listCURRENT_LIST_LENGTH( &( pxSocket->u.xUDP.xWaitingPacketsList ) ),
|
||||
pxSocket->u.xUDP.uxMaxPackets, pxSocket->usLocalPort ) );
|
||||
xReturn = pdFAIL; /* we did not consume or release the buffer */
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if( xReturn == pdPASS )
|
||||
{
|
||||
vTaskSuspendAll();
|
||||
{
|
||||
if( xReturn == pdPASS )
|
||||
{
|
||||
taskENTER_CRITICAL();
|
||||
{
|
||||
/* Add the network packet to the list of packets to be
|
||||
processed by the socket. */
|
||||
vListInsertEnd( &( pxSocket->u.xUDP.xWaitingPacketsList ), &( pxNetworkBuffer->xBufferListItem ) );
|
||||
}
|
||||
taskEXIT_CRITICAL();
|
||||
}
|
||||
}
|
||||
xTaskResumeAll();
|
||||
|
||||
/* Set the socket's receive event */
|
||||
if( pxSocket->xEventGroup != NULL )
|
||||
{
|
||||
xEventGroupSetBits( pxSocket->xEventGroup, eSOCKET_RECEIVE );
|
||||
}
|
||||
|
||||
#if( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
|
||||
{
|
||||
if( ( pxSocket->pxSocketSet != NULL ) && ( ( pxSocket->xSelectBits & eSELECT_READ ) != 0 ) )
|
||||
{
|
||||
xEventGroupSetBits( pxSocket->pxSocketSet->xSelectGroup, eSELECT_READ );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if( ipconfigSOCKET_HAS_USER_SEMAPHORE == 1 )
|
||||
{
|
||||
if( pxSocket->pxUserSemaphore != NULL )
|
||||
{
|
||||
xSemaphoreGive( pxSocket->pxUserSemaphore );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if( ipconfigUSE_DHCP == 1 )
|
||||
{
|
||||
if( xIsDHCPSocket( pxSocket ) )
|
||||
{
|
||||
xSendEventToIPTask( eDHCPEvent );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* There is no socket listening to the target port, but still it might
|
||||
be for this node. */
|
||||
|
||||
#if( ipconfigUSE_DNS == 1 )
|
||||
/* A DNS reply, check for the source port. Although the DNS client
|
||||
does open a UDP socket to send a messages, this socket will be
|
||||
closed after a short timeout. Messages that come late (after the
|
||||
socket is closed) will be treated here. */
|
||||
if( FreeRTOS_ntohs( pxUDPPacket->xUDPHeader.usSourcePort ) == ipDNS_PORT )
|
||||
{
|
||||
vARPRefreshCacheEntry( &( pxUDPPacket->xEthernetHeader.xSourceAddress ), pxUDPPacket->xIPHeader.ulSourceIPAddress );
|
||||
xReturn = ( BaseType_t )ulDNSHandlePacket( pxNetworkBuffer );
|
||||
}
|
||||
else
|
||||
#endif
|
||||
|
||||
#if( ipconfigUSE_LLMNR == 1 )
|
||||
/* A LLMNR request, check for the destination port. */
|
||||
if( ( usPort == FreeRTOS_ntohs( ipLLMNR_PORT ) ) ||
|
||||
( pxUDPPacket->xUDPHeader.usSourcePort == FreeRTOS_ntohs( ipLLMNR_PORT ) ) )
|
||||
{
|
||||
vARPRefreshCacheEntry( &( pxUDPPacket->xEthernetHeader.xSourceAddress ), pxUDPPacket->xIPHeader.ulSourceIPAddress );
|
||||
xReturn = ( BaseType_t )ulDNSHandlePacket( pxNetworkBuffer );
|
||||
}
|
||||
else
|
||||
#endif /* ipconfigUSE_LLMNR */
|
||||
|
||||
#if( ipconfigUSE_NBNS == 1 )
|
||||
/* a NetBIOS request, check for the destination port */
|
||||
if( ( usPort == FreeRTOS_ntohs( ipNBNS_PORT ) ) ||
|
||||
( pxUDPPacket->xUDPHeader.usSourcePort == FreeRTOS_ntohs( ipNBNS_PORT ) ) )
|
||||
{
|
||||
vARPRefreshCacheEntry( &( pxUDPPacket->xEthernetHeader.xSourceAddress ), pxUDPPacket->xIPHeader.ulSourceIPAddress );
|
||||
xReturn = ( BaseType_t )ulNBNSHandlePacket( pxNetworkBuffer );
|
||||
}
|
||||
else
|
||||
#endif /* ipconfigUSE_NBNS */
|
||||
{
|
||||
xReturn = pdFAIL;
|
||||
}
|
||||
}
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
Loading…
Add table
Add a link
Reference in a new issue