2 * FreeRTOS+TCP Labs Build 160919 (C) 2016 Real Time Engineers ltd.
\r
3 * Authors include Hein Tibosch and Richard Barry
\r
5 *******************************************************************************
\r
6 ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
\r
9 *** FREERTOS+TCP IS STILL IN THE LAB (mainly because the FTP and HTTP ***
\r
10 *** demos have a dependency on FreeRTOS+FAT, which is only in the Labs ***
\r
13 *** FreeRTOS+TCP is functional and has been used in commercial products ***
\r
14 *** for some time. Be aware however that we are still refining its ***
\r
15 *** design, the source code does not yet quite conform to the strict ***
\r
16 *** coding and style standards mandated by Real Time Engineers ltd., and ***
\r
17 *** the documentation and testing is not necessarily complete. ***
\r
19 *** PLEASE REPORT EXPERIENCES USING THE SUPPORT RESOURCES FOUND ON THE ***
\r
20 *** URL: http://www.FreeRTOS.org/contact Active early adopters may, at ***
\r
21 *** the sole discretion of Real Time Engineers Ltd., be offered versions ***
\r
22 *** under a license other than that described below. ***
\r
25 ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
\r
26 *******************************************************************************
\r
28 * FreeRTOS+TCP can be used under two different free open source licenses. The
\r
29 * license that applies is dependent on the processor on which FreeRTOS+TCP is
\r
30 * executed, as follows:
\r
32 * If FreeRTOS+TCP is executed on one of the processors listed under the Special
\r
33 * License Arrangements heading of the FreeRTOS+TCP license information web
\r
34 * page, then it can be used under the terms of the FreeRTOS Open Source
\r
35 * License. If FreeRTOS+TCP is used on any other processor, then it can be used
\r
36 * under the terms of the GNU General Public License V2. Links to the relevant
\r
39 * The FreeRTOS+TCP License Information Page: http://www.FreeRTOS.org/tcp_license
\r
40 * The FreeRTOS Open Source License: http://www.FreeRTOS.org/license
\r
41 * The GNU General Public License Version 2: http://www.FreeRTOS.org/gpl-2.0.txt
\r
43 * FreeRTOS+TCP is distributed in the hope that it will be useful. You cannot
\r
44 * use FreeRTOS+TCP unless you agree that you use the software 'as is'.
\r
45 * FreeRTOS+TCP is provided WITHOUT ANY WARRANTY; without even the implied
\r
46 * warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR
\r
47 * PURPOSE. Real Time Engineers Ltd. disclaims all conditions and terms, be they
\r
48 * implied, expressed, or statutory.
\r
50 * 1 tab == 4 spaces!
\r
52 * http://www.FreeRTOS.org
\r
53 * http://www.FreeRTOS.org/plus
\r
54 * http://www.FreeRTOS.org/labs
\r
58 /* Standard includes. */
\r
62 /* FreeRTOS includes. */
\r
63 #include "FreeRTOS.h"
\r
68 /* FreeRTOS+TCP includes. */
\r
69 #include "FreeRTOS_IP.h"
\r
70 #include "FreeRTOS_Sockets.h"
\r
71 #include "FreeRTOS_IP_Private.h"
\r
72 #include "FreeRTOS_UDP_IP.h"
\r
73 #include "FreeRTOS_ARP.h"
\r
74 #include "FreeRTOS_DHCP.h"
\r
75 #include "NetworkInterface.h"
\r
76 #include "NetworkBufferManagement.h"
\r
78 #if( ipconfigUSE_DNS == 1 )
\r
79 #include "FreeRTOS_DNS.h"
\r
82 /* The expected IP version and header length coded into the IP header itself. */
\r
83 #define ipIP_VERSION_AND_HEADER_LENGTH_BYTE ( ( uint8_t ) 0x45 )
\r
85 /* Part of the Ethernet and IP headers are always constant when sending an IPv4
\r
86 UDP packet. This array defines the constant parts, allowing this part of the
\r
87 packet to be filled in using a simple memcpy() instead of individual writes. */
\r
88 UDPPacketHeader_t xDefaultPartUDPPacketHeader =
\r
92 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Ethernet source MAC address. */
\r
93 0x08, 0x00, /* Ethernet frame type. */
\r
94 ipIP_VERSION_AND_HEADER_LENGTH_BYTE, /* ucVersionHeaderLength. */
\r
95 0x00, /* ucDifferentiatedServicesCode. */
\r
96 0x00, 0x00, /* usLength. */
\r
97 0x00, 0x00, /* usIdentification. */
\r
98 0x00, 0x00, /* usFragmentOffset. */
\r
99 ipconfigUDP_TIME_TO_LIVE, /* ucTimeToLive */
\r
100 ipPROTOCOL_UDP, /* ucProtocol. */
\r
101 0x00, 0x00, /* usHeaderChecksum. */
\r
102 0x00, 0x00, 0x00, 0x00 /* Source IP address. */
\r
105 /*-----------------------------------------------------------*/
\r
107 void vProcessGeneratedUDPPacket( NetworkBufferDescriptor_t * const pxNetworkBuffer )
\r
109 UDPPacket_t *pxUDPPacket;
\r
110 IPHeader_t *pxIPHeader;
\r
111 eARPLookupResult_t eReturned;
\r
112 uint32_t ulIPAddress = pxNetworkBuffer->ulIPAddress;
\r
114 /* Map the UDP packet onto the start of the frame. */
\r
115 pxUDPPacket = ( UDPPacket_t * ) pxNetworkBuffer->pucEthernetBuffer;
\r
117 /* Determine the ARP cache status for the requested IP address. */
\r
118 eReturned = eARPGetCacheEntry( &( ulIPAddress ), &( pxUDPPacket->xEthernetHeader.xDestinationAddress ) );
\r
120 if( eReturned != eCantSendPacket )
\r
122 if( eReturned == eARPCacheHit )
\r
124 #if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 0 )
\r
125 uint8_t ucSocketOptions;
\r
127 iptraceSENDING_UDP_PACKET( pxNetworkBuffer->ulIPAddress );
\r
129 /* Create short cuts to the data within the packet. */
\r
130 pxIPHeader = &( pxUDPPacket->xIPHeader );
\r
132 #if ( ipconfigSUPPORT_OUTGOING_PINGS == 1 )
\r
133 /* Is it possible that the packet is not actually a UDP packet
\r
134 after all, but an ICMP packet. */
\r
135 if( pxNetworkBuffer->usPort != ipPACKET_CONTAINS_ICMP_DATA )
\r
136 #endif /* ipconfigSUPPORT_OUTGOING_PINGS */
\r
138 UDPHeader_t *pxUDPHeader;
\r
140 pxUDPHeader = &( pxUDPPacket->xUDPHeader );
\r
142 pxUDPHeader->usDestinationPort = pxNetworkBuffer->usPort;
\r
143 pxUDPHeader->usSourcePort = pxNetworkBuffer->usBoundPort;
\r
144 pxUDPHeader->usLength = ( uint16_t ) ( pxNetworkBuffer->xDataLength + sizeof( UDPHeader_t ) );
\r
145 pxUDPHeader->usLength = FreeRTOS_htons( pxUDPHeader->usLength );
\r
146 pxUDPHeader->usChecksum = 0u;
\r
149 /* memcpy() the constant parts of the header information into
\r
150 the correct location within the packet. This fills in:
\r
151 xEthernetHeader.xSourceAddress
\r
152 xEthernetHeader.usFrameType
\r
153 xIPHeader.ucVersionHeaderLength
\r
154 xIPHeader.ucDifferentiatedServicesCode
\r
156 xIPHeader.usIdentification
\r
157 xIPHeader.usFragmentOffset
\r
158 xIPHeader.ucTimeToLive
\r
159 xIPHeader.ucProtocol
\r
161 xIPHeader.usHeaderChecksum
\r
164 /* Save options now, as they will be overwritten by memcpy */
\r
165 #if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 0 )
\r
167 ucSocketOptions = pxNetworkBuffer->pucEthernetBuffer[ ipSOCKET_OPTIONS_OFFSET ];
\r
171 memcpy( ( void *) &( pxUDPPacket->xEthernetHeader.xSourceAddress ), ( void * ) xDefaultPartUDPPacketHeader.ucBytes, sizeof( xDefaultPartUDPPacketHeader ) );
\r
173 #if ipconfigSUPPORT_OUTGOING_PINGS == 1
\r
174 if( pxNetworkBuffer->usPort == ipPACKET_CONTAINS_ICMP_DATA )
\r
176 pxIPHeader->ucProtocol = ipPROTOCOL_ICMP;
\r
177 pxIPHeader->usLength = ( uint16_t ) ( pxNetworkBuffer->xDataLength + sizeof( IPHeader_t ) );
\r
180 #endif /* ipconfigSUPPORT_OUTGOING_PINGS */
\r
182 pxIPHeader->usLength = ( uint16_t ) ( pxNetworkBuffer->xDataLength + sizeof( IPHeader_t ) + sizeof( UDPHeader_t ) );
\r
185 /* The total transmit size adds on the Ethernet header. */
\r
186 pxNetworkBuffer->xDataLength = pxIPHeader->usLength + sizeof( EthernetHeader_t );
\r
187 pxIPHeader->usLength = FreeRTOS_htons( pxIPHeader->usLength );
\r
188 pxIPHeader->ulDestinationIPAddress = pxNetworkBuffer->ulIPAddress;
\r
190 #if( ipconfigUSE_LLMNR == 1 )
\r
192 /* LLMNR messages are typically used on a LAN and they're
\r
193 * not supposed to cross routers */
\r
194 if( pxNetworkBuffer->ulIPAddress == ipLLMNR_IP_ADDR )
\r
196 pxIPHeader->ucTimeToLive = 0x01;
\r
201 #if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 0 )
\r
203 pxIPHeader->usHeaderChecksum = 0u;
\r
204 pxIPHeader->usHeaderChecksum = usGenerateChecksum( 0UL, ( uint8_t * ) &( pxIPHeader->ucVersionHeaderLength ), ipSIZE_OF_IPv4_HEADER );
\r
205 pxIPHeader->usHeaderChecksum = ~FreeRTOS_htons( pxIPHeader->usHeaderChecksum );
\r
207 if( ( ucSocketOptions & ( uint8_t ) FREERTOS_SO_UDPCKSUM_OUT ) != 0u )
\r
209 usGenerateProtocolChecksum( (uint8_t*)pxUDPPacket, pdTRUE );
\r
213 pxUDPPacket->xUDPHeader.usChecksum = 0u;
\r
218 else if( eReturned == eARPCacheMiss )
\r
220 /* Add an entry to the ARP table with a null hardware address.
\r
221 This allows the ARP timer to know that an ARP reply is
\r
222 outstanding, and perform retransmissions if necessary. */
\r
223 vARPRefreshCacheEntry( NULL, ulIPAddress );
\r
225 /* Generate an ARP for the required IP address. */
\r
226 iptracePACKET_DROPPED_TO_GENERATE_ARP( pxNetworkBuffer->ulIPAddress );
\r
227 pxNetworkBuffer->ulIPAddress = ulIPAddress;
\r
228 vARPGenerateRequestPacket( pxNetworkBuffer );
\r
232 /* The lookup indicated that an ARP request has already been
\r
233 sent out for the queried IP address. */
\r
234 eReturned = eCantSendPacket;
\r
238 if( eReturned != eCantSendPacket )
\r
240 /* The network driver is responsible for freeing the network buffer
\r
241 after the packet has been sent. */
\r
243 #if defined( ipconfigETHERNET_MINIMUM_PACKET_BYTES )
\r
245 if( pxNetworkBuffer->xDataLength < ( size_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES )
\r
249 for( xIndex = ( BaseType_t ) pxNetworkBuffer->xDataLength; xIndex < ( BaseType_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES; xIndex++ )
\r
251 pxNetworkBuffer->pucEthernetBuffer[ xIndex ] = 0u;
\r
253 pxNetworkBuffer->xDataLength = ( size_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES;
\r
258 xNetworkInterfaceOutput( pxNetworkBuffer, pdTRUE );
\r
262 /* The packet can't be sent (DHCP not completed?). Just drop the
\r
264 vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
\r
267 /*-----------------------------------------------------------*/
\r
269 BaseType_t xProcessReceivedUDPPacket( NetworkBufferDescriptor_t *pxNetworkBuffer, uint16_t usPort )
\r
271 BaseType_t xReturn = pdPASS;
\r
272 FreeRTOS_Socket_t *pxSocket;
\r
274 UDPPacket_t *pxUDPPacket = (UDPPacket_t *) pxNetworkBuffer->pucEthernetBuffer;
\r
276 pxSocket = pxUDPSocketLookup( usPort );
\r
281 /* When refreshing the ARP cache with received UDP packets we must be
\r
282 careful; hundreds of broadcast messages may pass and if we're not
\r
283 handling them, no use to fill the ARP cache with those IP addresses. */
\r
284 vARPRefreshCacheEntry( &( pxUDPPacket->xEthernetHeader.xSourceAddress ), pxUDPPacket->xIPHeader.ulSourceIPAddress );
\r
286 #if( ipconfigUSE_CALLBACKS == 1 )
\r
288 /* Did the owner of this socket register a reception handler ? */
\r
289 if( ipconfigIS_VALID_PROG_ADDRESS( pxSocket->u.xUDP.pxHandleReceive ) )
\r
291 struct freertos_sockaddr xSourceAddress, destinationAddress;
\r
292 void *pcData = ( void * ) &( pxNetworkBuffer->pucEthernetBuffer[ ipUDP_PAYLOAD_OFFSET_IPv4 ] );
\r
293 FOnUDPReceive_t xHandler = ( FOnUDPReceive_t ) pxSocket->u.xUDP.pxHandleReceive;
\r
294 xSourceAddress.sin_port = pxNetworkBuffer->usPort;
\r
295 xSourceAddress.sin_addr = pxNetworkBuffer->ulIPAddress;
\r
296 destinationAddress.sin_port = usPort;
\r
297 destinationAddress.sin_addr = pxUDPPacket->xIPHeader.ulDestinationIPAddress;
\r
299 if( xHandler( ( Socket_t * ) pxSocket, ( void* ) pcData, ( size_t ) pxNetworkBuffer->xDataLength,
\r
300 &xSourceAddress, &destinationAddress ) != pdFALSE )
\r
302 xReturn = pdFAIL; /* xHandler has consumed the data, do not add it to .xWaitingPacketsList'. */
\r
306 #endif /* ipconfigUSE_CALLBACKS */
\r
308 #if( ipconfigUDP_MAX_RX_PACKETS > 0 )
\r
310 if( xReturn == pdPASS )
\r
312 if ( listCURRENT_LIST_LENGTH( &( pxSocket->u.xUDP.xWaitingPacketsList ) ) >= pxSocket->u.xUDP.uxMaxPackets )
\r
314 FreeRTOS_debug_printf( ( "xProcessReceivedUDPPacket: buffer full %ld >= %ld port %u\n",
\r
315 listCURRENT_LIST_LENGTH( &( pxSocket->u.xUDP.xWaitingPacketsList ) ),
\r
316 pxSocket->u.xUDP.uxMaxPackets, pxSocket->usLocalPort ) );
\r
317 xReturn = pdFAIL; /* we did not consume or release the buffer */
\r
323 if( xReturn == pdPASS )
\r
327 if( xReturn == pdPASS )
\r
329 taskENTER_CRITICAL();
\r
331 /* Add the network packet to the list of packets to be
\r
332 processed by the socket. */
\r
333 vListInsertEnd( &( pxSocket->u.xUDP.xWaitingPacketsList ), &( pxNetworkBuffer->xBufferListItem ) );
\r
335 taskEXIT_CRITICAL();
\r
340 /* Set the socket's receive event */
\r
341 if( pxSocket->xEventGroup != NULL )
\r
343 xEventGroupSetBits( pxSocket->xEventGroup, eSOCKET_RECEIVE );
\r
346 #if( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
\r
348 if( ( pxSocket->pxSocketSet != NULL ) && ( ( pxSocket->xSelectBits & eSELECT_READ ) != 0 ) )
\r
350 xEventGroupSetBits( pxSocket->pxSocketSet->xSelectGroup, eSELECT_READ );
\r
355 #if( ipconfigSOCKET_HAS_USER_SEMAPHORE == 1 )
\r
357 if( pxSocket->pxUserSemaphore != NULL )
\r
359 xSemaphoreGive( pxSocket->pxUserSemaphore );
\r
364 #if( ipconfigUSE_DHCP == 1 )
\r
366 if( xIsDHCPSocket( pxSocket ) )
\r
368 xSendEventToIPTask( eDHCPEvent );
\r
376 /* There is no socket listening to the target port, but still it might
\r
377 be for this node. */
\r
379 #if( ipconfigUSE_DNS == 1 )
\r
380 /* A DNS reply, check for the source port. Although the DNS client
\r
381 does open a UDP socket to send a messages, this socket will be
\r
382 closed after a short timeout. Messages that come late (after the
\r
383 socket is closed) will be treated here. */
\r
384 if( FreeRTOS_ntohs( pxUDPPacket->xUDPHeader.usSourcePort ) == ipDNS_PORT )
\r
386 vARPRefreshCacheEntry( &( pxUDPPacket->xEthernetHeader.xSourceAddress ), pxUDPPacket->xIPHeader.ulSourceIPAddress );
\r
387 xReturn = ( BaseType_t )ulDNSHandlePacket( pxNetworkBuffer );
\r
392 #if( ipconfigUSE_LLMNR == 1 )
\r
393 /* A LLMNR request, check for the destination port. */
\r
394 if( ( usPort == FreeRTOS_ntohs( ipLLMNR_PORT ) ) ||
\r
395 ( pxUDPPacket->xUDPHeader.usSourcePort == FreeRTOS_ntohs( ipLLMNR_PORT ) ) )
\r
397 vARPRefreshCacheEntry( &( pxUDPPacket->xEthernetHeader.xSourceAddress ), pxUDPPacket->xIPHeader.ulSourceIPAddress );
\r
398 xReturn = ( BaseType_t )ulDNSHandlePacket( pxNetworkBuffer );
\r
401 #endif /* ipconfigUSE_LLMNR */
\r
403 #if( ipconfigUSE_NBNS == 1 )
\r
404 /* a NetBIOS request, check for the destination port */
\r
405 if( ( usPort == FreeRTOS_ntohs( ipNBNS_PORT ) ) ||
\r
406 ( pxUDPPacket->xUDPHeader.usSourcePort == FreeRTOS_ntohs( ipNBNS_PORT ) ) )
\r
408 vARPRefreshCacheEntry( &( pxUDPPacket->xEthernetHeader.xSourceAddress ), pxUDPPacket->xIPHeader.ulSourceIPAddress );
\r
409 xReturn = ( BaseType_t )ulNBNSHandlePacket( pxNetworkBuffer );
\r
412 #endif /* ipconfigUSE_NBNS */
\r
420 /*-----------------------------------------------------------*/
\r