/*\r
- * FreeRTOS+TCP V2.0.3\r
+ * FreeRTOS+TCP V2.0.7\r
* Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.\r
*\r
* Permission is hereby granted, free of charge, to any person obtaining a copy of\r
\r
\r
/* Time delay between repeated attempts to initialise the network hardware. */\r
-#ifndef ipINITIALISATION_RETRY_DELAY\r
- #define ipINITIALISATION_RETRY_DELAY ( pdMS_TO_TICKS( 3000 ) )\r
-#endif\r
+#define ipINITIALISATION_RETRY_DELAY ( pdMS_TO_TICKS( 3000 ) )\r
\r
/* Defines how often the ARP timer callback function is executed. The time is\r
shorted in the Windows simulator as simulated time is not real time. */\r
/*\r
* Process incoming IP packets.\r
*/\r
-static eFrameProcessingResult_t prvProcessIPPacket( const IPPacket_t * const pxIPPacket, NetworkBufferDescriptor_t * const pxNetworkBuffer );\r
+static eFrameProcessingResult_t prvProcessIPPacket( IPPacket_t * const pxIPPacket, NetworkBufferDescriptor_t * const pxNetworkBuffer );\r
\r
#if ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) || ( ipconfigSUPPORT_OUTGOING_PINGS == 1 )\r
/*\r
/* Calculate the acceptable maximum sleep time. */\r
xNextIPSleep = prvCalculateSleepTime();\r
\r
- /* Wait until there is something to do. The event is initialised to "no\r
- event" in case the following call exits due to a time out rather than a\r
- message being received. */\r
- xReceivedEvent.eEventType = eNoEvent;\r
- xQueueReceive( xNetworkEventQueue, ( void * ) &xReceivedEvent, xNextIPSleep );\r
+ /* Wait until there is something to do. If the following call exits\r
+ * due to a time out rather than a message being received, set a\r
+ * 'NoEvent' value. */\r
+ if ( xQueueReceive( xNetworkEventQueue, ( void * ) &xReceivedEvent, xNextIPSleep ) == pdFALSE ) {\r
+ xReceivedEvent.eEventType = eNoEvent;\r
+ }\r
\r
#if( ipconfigCHECK_IP_QUEUE_SPACE != 0 )\r
{\r
#if( ipconfigUSE_TCP == 1 )\r
{\r
BaseType_t xWillSleep;\r
- /* xStart keeps a copy of the last time this function was active,\r
- and during every call it will be updated with xTaskGetTickCount()\r
- '0' means: not yet initialised (although later '0' might be returned\r
- by xTaskGetTickCount(), which is no problem). */\r
- static TickType_t xStart = ( TickType_t ) 0;\r
- TickType_t xTimeNow, xNextTime;\r
+ TickType_t xNextTime;\r
BaseType_t xCheckTCPSockets;\r
- extern uint32_t ulNextInitialSequenceNumber;\r
\r
if( uxQueueMessagesWaiting( xNetworkEventQueue ) == 0u )\r
{\r
xWillSleep = pdFALSE;\r
}\r
\r
- xTimeNow = xTaskGetTickCount();\r
-\r
- if( xStart != ( TickType_t ) 0 )\r
- {\r
- /* It is advised to increment the Initial Sequence Number every 4\r
- microseconds which makes 250 times per ms. This will make it harder\r
- for a third party to 'guess' our sequence number and 'take over'\r
- a TCP connection */\r
- ulNextInitialSequenceNumber += ipINITIAL_SEQUENCE_NUMBER_FACTOR * ( ( xTimeNow - xStart ) * portTICK_PERIOD_MS );\r
- }\r
-\r
- xStart = xTimeNow;\r
-\r
/* Sockets need to be checked if the TCP timer has expired. */\r
xCheckTCPSockets = prvIPTimerCheck( &xTCPTimer );\r
\r
\r
if( pxNetworkBuffer != NULL )\r
{\r
+ /* Set the actual packet size in case a bigger buffer was returned. */\r
+ pxNetworkBuffer->xDataLength = \r
+ sizeof( UDPPacket_t ) + xRequestedSizeBytes;\r
+\r
/* Leave space for the UPD header. */\r
pvReturn = ( void * ) &( pxNetworkBuffer->pucEthernetBuffer[ ipUDP_PAYLOAD_OFFSET_IPv4 ] );\r
}\r
\r
if( pxNewBuffer != NULL )\r
{\r
+ /* Set the actual packet size in case a bigger buffer than requested \r
+ was returned. */\r
+ pxNewBuffer->xDataLength = xNewLength;\r
+\r
+ /* Copy the original packet information. */\r
pxNewBuffer->ulIPAddress = pxNetworkBuffer->ulIPAddress;\r
pxNewBuffer->usPort = pxNetworkBuffer->usPort;\r
pxNewBuffer->usBoundPort = pxNetworkBuffer->usBoundPort;\r
\r
/* Added to prevent ARP flood to gateway. Ensure the\r
gateway is on the same subnet as the IP address. */\r
- if( xNetworkAddressing.ulGatewayAddress != 0ul )\r
- {\r
- configASSERT( ( ( *ipLOCAL_IP_ADDRESS_POINTER ) & xNetworkAddressing.ulNetMask ) == ( xNetworkAddressing.ulGatewayAddress & xNetworkAddressing.ulNetMask ) );\r
- }\r
+ configASSERT( ( ( *ipLOCAL_IP_ADDRESS_POINTER ) & xNetworkAddressing.ulNetMask ) == ( xNetworkAddressing.ulGatewayAddress & xNetworkAddressing.ulNetMask ) );\r
}\r
#endif /* ipconfigUSE_DHCP == 1 */\r
\r
memcpy( ( void * ) ipLOCAL_MAC_ADDRESS, ( void * ) ucMACAddress, ( size_t ) ipMAC_ADDRESS_LENGTH_BYTES );\r
\r
/* Prepare the sockets interface. */\r
- vNetworkSocketsInit();\r
-\r
- /* Create the task that processes Ethernet and stack events. */\r
- xReturn = xTaskCreate( prvIPTask, "IP-task", ( uint16_t ) ipconfigIP_TASK_STACK_SIZE_WORDS, NULL, ( UBaseType_t ) ipconfigIP_TASK_PRIORITY, &xIPTaskHandle );\r
+ xReturn = vNetworkSocketsInit();\r
+ \r
+ if( pdTRUE == xReturn )\r
+ {\r
+ /* Create the task that processes Ethernet and stack events. */\r
+ xReturn = xTaskCreate( prvIPTask, "IP-task", ( uint16_t )ipconfigIP_TASK_STACK_SIZE_WORDS, NULL, ( UBaseType_t )ipconfigIP_TASK_PRIORITY, &xIPTaskHandle );\r
+ }\r
}\r
else\r
{\r
static void prvProcessEthernetPacket( NetworkBufferDescriptor_t * const pxNetworkBuffer )\r
{\r
EthernetHeader_t *pxEthernetHeader;\r
-volatile eFrameProcessingResult_t eReturned; /* Volatile to prevent complier warnings when ipCONSIDER_FRAME_FOR_PROCESSING just sets it to eProcessBuffer. */\r
+eFrameProcessingResult_t eReturned = eReleaseBuffer;\r
\r
configASSERT( pxNetworkBuffer );\r
\r
/* Interpret the Ethernet frame. */\r
- eReturned = ipCONSIDER_FRAME_FOR_PROCESSING( pxNetworkBuffer->pucEthernetBuffer );\r
- pxEthernetHeader = ( EthernetHeader_t * ) ( pxNetworkBuffer->pucEthernetBuffer );\r
-\r
- if( eReturned == eProcessBuffer )\r
- {\r
- /* Interpret the received Ethernet packet. */\r
- switch( pxEthernetHeader->usFrameType )\r
- {\r
- case ipARP_FRAME_TYPE :\r
- /* The Ethernet frame contains an ARP packet. */\r
- eReturned = eARPProcessPacket( ( ARPPacket_t * ) pxNetworkBuffer->pucEthernetBuffer );\r
- break;\r
-\r
- case ipIPv4_FRAME_TYPE :\r
- /* The Ethernet frame contains an IP packet. */\r
- eReturned = prvProcessIPPacket( ( IPPacket_t * ) pxNetworkBuffer->pucEthernetBuffer, pxNetworkBuffer );\r
- break;\r
-\r
- default :\r
- /* No other packet types are handled. Nothing to do. */\r
- eReturned = eReleaseBuffer;\r
- break;\r
- }\r
- }\r
+ if( pxNetworkBuffer->xDataLength >= sizeof( EthernetHeader_t ) )\r
+ {\r
+ eReturned = ipCONSIDER_FRAME_FOR_PROCESSING( pxNetworkBuffer->pucEthernetBuffer );\r
+ pxEthernetHeader = ( EthernetHeader_t * )( pxNetworkBuffer->pucEthernetBuffer );\r
+\r
+ if( eReturned == eProcessBuffer )\r
+ {\r
+ /* Interpret the received Ethernet packet. */\r
+ switch( pxEthernetHeader->usFrameType )\r
+ {\r
+ case ipARP_FRAME_TYPE:\r
+ /* The Ethernet frame contains an ARP packet. */\r
+ if( pxNetworkBuffer->xDataLength >= sizeof( ARPPacket_t ) )\r
+ {\r
+ eReturned = eARPProcessPacket( ( ARPPacket_t * )pxNetworkBuffer->pucEthernetBuffer );\r
+ }\r
+ else\r
+ {\r
+ eReturned = eReleaseBuffer;\r
+ }\r
+ break;\r
+\r
+ case ipIPv4_FRAME_TYPE:\r
+ /* The Ethernet frame contains an IP packet. */\r
+ if( pxNetworkBuffer->xDataLength >= sizeof( IPPacket_t ) )\r
+ {\r
+ eReturned = prvProcessIPPacket( ( IPPacket_t * )pxNetworkBuffer->pucEthernetBuffer, pxNetworkBuffer );\r
+ }\r
+ else\r
+ {\r
+ eReturned = eReleaseBuffer;\r
+ }\r
+ break;\r
+\r
+ default:\r
+ /* No other packet types are handled. Nothing to do. */\r
+ eReturned = eReleaseBuffer;\r
+ break;\r
+ }\r
+ }\r
+ }\r
\r
/* Perform any actions that resulted from processing the Ethernet frame. */\r
switch( eReturned )\r
This method may decrease the usage of sparse network buffers. */\r
uint32_t ulDestinationIPAddress = pxIPHeader->ulDestinationIPAddress;\r
\r
- /* Ensure that the incoming packet is not fragmented (fragmentation\r
- was only supported for outgoing packets, and is not currently\r
- not supported at all). */\r
+ /* Ensure that the incoming packet is not fragmented (only outgoing\r
+ packets can be fragmented) as these are the only handled IP frames\r
+ currently. */\r
if( ( pxIPHeader->usFragmentOffset & ipFRAGMENT_OFFSET_BIT_MASK ) != 0U )\r
{\r
/* Can not handle, fragmented packet. */\r
eReturn = eReleaseBuffer;\r
}\r
/* Is the upper-layer checksum (TCP/UDP/ICMP) correct? */\r
- else if( usGenerateProtocolChecksum( ( uint8_t * )( pxNetworkBuffer->pucEthernetBuffer ), pdFALSE ) != ipCORRECT_CRC )\r
+ else if( usGenerateProtocolChecksum( ( uint8_t * )( pxNetworkBuffer->pucEthernetBuffer ), pxNetworkBuffer->xDataLength, pdFALSE ) != ipCORRECT_CRC )\r
{\r
/* Protocol checksum not accepted. */\r
eReturn = eReleaseBuffer;\r
}\r
/*-----------------------------------------------------------*/\r
\r
-static eFrameProcessingResult_t prvProcessIPPacket( const IPPacket_t * const pxIPPacket, NetworkBufferDescriptor_t * const pxNetworkBuffer )\r
+static eFrameProcessingResult_t prvProcessIPPacket( IPPacket_t * const pxIPPacket, NetworkBufferDescriptor_t * const pxNetworkBuffer )\r
{\r
eFrameProcessingResult_t eReturn;\r
-const IPHeader_t * pxIPHeader = &( pxIPPacket->xIPHeader );\r
+IPHeader_t * pxIPHeader = &( pxIPPacket->xIPHeader );\r
UBaseType_t uxHeaderLength = ( UBaseType_t ) ( ( pxIPHeader->ucVersionHeaderLength & 0x0Fu ) << 2 );\r
uint8_t ucProtocol;\r
\r
+ /* Bound the calculated header length: take away the Ethernet header size,\r
+ then check if the IP header is claiming to be longer than the remaining\r
+ total packet size. Also check for minimal header field length. */\r
+ if( uxHeaderLength > pxNetworkBuffer->xDataLength - ipSIZE_OF_ETH_HEADER ||\r
+ uxHeaderLength < ipSIZE_OF_IPv4_HEADER )\r
+ {\r
+ return eReleaseBuffer;\r
+ }\r
+\r
ucProtocol = pxIPPacket->xIPHeader.ucProtocol;\r
/* Check if the IP headers are acceptable and if it has our destination. */\r
eReturn = prvAllowIPPacket( pxIPPacket, pxNetworkBuffer, uxHeaderLength );\r
* Note: IP options are mostly use in Multi-cast protocols */\r
const size_t optlen = ( ( size_t ) uxHeaderLength ) - ipSIZE_OF_IPv4_HEADER;\r
/* From: the previous start of UDP/ICMP/TCP data */\r
- uint8_t *pucSource = ( ( uint8_t * ) pxIPHeader ) + uxHeaderLength;\r
+ uint8_t *pucSource = ( uint8_t* )(pxNetworkBuffer->pucEthernetBuffer + sizeof( EthernetHeader_t ) + uxHeaderLength);\r
/* To: the usual start of UDP/ICMP/TCP data at offset 20 from IP header */\r
- uint8_t *pucTarget = ( ( uint8_t * ) pxIPHeader ) + ipSIZE_OF_IPv4_HEADER;\r
+ uint8_t *pucTarget = ( uint8_t* )(pxNetworkBuffer->pucEthernetBuffer + sizeof( EthernetHeader_t ) + ipSIZE_OF_IPv4_HEADER);\r
/* How many: total length minus the options and the lower headers */\r
const size_t xMoveLen = pxNetworkBuffer->xDataLength - optlen - ipSIZE_OF_IPv4_HEADER - ipSIZE_OF_ETH_HEADER;\r
\r
memmove( pucTarget, pucSource, xMoveLen );\r
pxNetworkBuffer->xDataLength -= optlen;\r
+\r
+ /* Fix-up new version/header length field in IP packet. */\r
+ pxIPHeader->ucVersionHeaderLength =\r
+ ( pxIPHeader->ucVersionHeaderLength & 0xF0 ) | /* High nibble is the version. */\r
+ ( ( ipSIZE_OF_IPv4_HEADER >> 2 ) & 0x0F ); /* Low nibble is the header size, in bytes, divided by four. */\r
}\r
+\r
/* Add the IP and MAC addresses to the ARP table if they are not\r
already there - otherwise refresh the age of the existing\r
entry. */\r
be able to validate what it receives. */\r
#if ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) || ( ipconfigSUPPORT_OUTGOING_PINGS == 1 )\r
{\r
- ICMPPacket_t *pxICMPPacket = ( ICMPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );\r
- if( pxIPHeader->ulDestinationIPAddress == *ipLOCAL_IP_ADDRESS_POINTER )\r
- {\r
- eReturn = prvProcessICMPPacket( pxICMPPacket );\r
- }\r
+ if( pxNetworkBuffer->xDataLength >= sizeof( ICMPPacket_t ) )\r
+ {\r
+ ICMPPacket_t *pxICMPPacket = ( ICMPPacket_t * )( pxNetworkBuffer->pucEthernetBuffer );\r
+ if( pxIPHeader->ulDestinationIPAddress == *ipLOCAL_IP_ADDRESS_POINTER )\r
+ {\r
+ eReturn = prvProcessICMPPacket( pxICMPPacket );\r
+ }\r
+ }\r
+ else\r
+ {\r
+ eReturn = eReleaseBuffer;\r
+ }\r
}\r
#endif /* ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) || ( ipconfigSUPPORT_OUTGOING_PINGS == 1 ) */\r
break;\r
/* The IP packet contained a UDP frame. */\r
UDPPacket_t *pxUDPPacket = ( UDPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );\r
\r
- /* Note the header values required prior to the\r
- checksum generation as the checksum pseudo header\r
- may clobber some of these values. */\r
- pxNetworkBuffer->xDataLength = FreeRTOS_ntohs( pxUDPPacket->xUDPHeader.usLength ) - sizeof( UDPHeader_t );\r
- /* HT:endian: fields in pxNetworkBuffer (usPort, ulIPAddress) were network order */\r
- pxNetworkBuffer->usPort = pxUDPPacket->xUDPHeader.usSourcePort;\r
- pxNetworkBuffer->ulIPAddress = pxUDPPacket->xIPHeader.ulSourceIPAddress;\r
-\r
- /* ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM:\r
- * In some cases, the upper-layer checksum has been calculated\r
- * by the NIC driver */\r
- /* Pass the packet payload to the UDP sockets implementation. */\r
- /* HT:endian: xProcessReceivedUDPPacket wanted network order */\r
- if( xProcessReceivedUDPPacket( pxNetworkBuffer, pxUDPPacket->xUDPHeader.usDestinationPort ) == pdPASS )\r
- {\r
- eReturn = eFrameConsumed;\r
- }\r
+ /* Only proceed if the payload length indicated in the header\r
+ appears to be valid. */\r
+ if ( pxNetworkBuffer->xDataLength >= sizeof( UDPPacket_t ) )\r
+ {\r
+ /* Ensure that downstream UDP packet handling has the lesser\r
+ * of: the actual network buffer Ethernet frame length, or \r
+ * the sender's UDP packet header payload length, minus the\r
+ * size of the UDP header. \r
+ *\r
+ * The size of the UDP packet structure in this implementation \r
+ * includes the size of the Ethernet header, the size of \r
+ * the IP header, and the size of the UDP header.\r
+ */\r
+ \r
+ pxNetworkBuffer->xDataLength -= sizeof( UDPPacket_t );\r
+ if( ( FreeRTOS_ntohs( pxUDPPacket->xUDPHeader.usLength ) - sizeof( UDPHeader_t ) ) <\r
+ pxNetworkBuffer->xDataLength )\r
+ {\r
+ pxNetworkBuffer->xDataLength = FreeRTOS_ntohs( pxUDPPacket->xUDPHeader.usLength ) - \r
+ sizeof( UDPHeader_t );\r
+ }\r
+\r
+ /* Fields in pxNetworkBuffer (usPort, ulIPAddress) are network order. */\r
+ pxNetworkBuffer->usPort = pxUDPPacket->xUDPHeader.usSourcePort;\r
+ pxNetworkBuffer->ulIPAddress = pxUDPPacket->xIPHeader.ulSourceIPAddress;\r
+\r
+ /* ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM:\r
+ * In some cases, the upper-layer checksum has been calculated\r
+ * by the NIC driver.\r
+ * \r
+ * Pass the packet payload to the UDP sockets implementation. */\r
+ if( xProcessReceivedUDPPacket( pxNetworkBuffer, \r
+ pxUDPPacket->xUDPHeader.usDestinationPort ) == pdPASS )\r
+ {\r
+ eReturn = eFrameConsumed;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ eReturn = eReleaseBuffer;\r
+ }\r
}\r
break;\r
\r
#endif /* ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) || ( ipconfigSUPPORT_OUTGOING_PINGS == 1 ) */\r
/*-----------------------------------------------------------*/\r
\r
-uint16_t usGenerateProtocolChecksum( const uint8_t * const pucEthernetBuffer, BaseType_t xOutgoingPacket )\r
+uint16_t usGenerateProtocolChecksum( const uint8_t * const pucEthernetBuffer, size_t uxBufferLength, BaseType_t xOutgoingPacket )\r
{\r
uint32_t ulLength;\r
uint16_t usChecksum, *pusChecksum;\r
const char *pcType;\r
#endif\r
\r
- pxIPPacket = ( const IPPacket_t * ) pucEthernetBuffer;\r
- uxIPHeaderLength = ( UBaseType_t ) ( 4u * ( pxIPPacket->xIPHeader.ucVersionHeaderLength & 0x0Fu ) ); /*_RB_ Why 4? */\r
- pxProtPack = ( ProtocolPacket_t * ) ( pucEthernetBuffer + ( uxIPHeaderLength - ipSIZE_OF_IPv4_HEADER ) );\r
- ucProtocol = pxIPPacket->xIPHeader.ucProtocol;\r
+ /* Check for minimum packet size. */\r
+ if( uxBufferLength < sizeof( IPPacket_t ) )\r
+ {\r
+ return ipINVALID_LENGTH;\r
+ }\r
\r
+ /* Parse the packet length. */\r
+ pxIPPacket = ( const IPPacket_t * ) pucEthernetBuffer;\r
+ \r
+ /* Per https://tools.ietf.org/html/rfc791, the four-bit Internet Header \r
+ Length field contains the length of the internet header in 32-bit words. */\r
+ uxIPHeaderLength = ( UBaseType_t ) \r
+ ( sizeof( uint32_t ) * ( pxIPPacket->xIPHeader.ucVersionHeaderLength & 0x0Fu ) ); \r
+\r
+ /* Check for minimum packet size. */\r
+ if( uxBufferLength < sizeof( IPPacket_t ) + uxIPHeaderLength - ipSIZE_OF_IPv4_HEADER )\r
+ {\r
+ return ipINVALID_LENGTH;\r
+ }\r
+ if( uxBufferLength < FreeRTOS_ntohs( pxIPPacket->xIPHeader.usLength ) )\r
+ {\r
+ return ipINVALID_LENGTH;\r
+ }\r
+\r
+ /* Identify the next protocol. */\r
+ ucProtocol = pxIPPacket->xIPHeader.ucProtocol; \r
+\r
+ /* N.B., if this IP packet header includes Options, then the following \r
+ assignment results in a pointer into the protocol packet with the Ethernet \r
+ and IP headers incorrectly aligned. However, either way, the "third"\r
+ protocol (Layer 3 or 4) header will be aligned, which is the convenience \r
+ of this calculation. */\r
+ pxProtPack = ( ProtocolPacket_t * ) ( pucEthernetBuffer + ( uxIPHeaderLength - ipSIZE_OF_IPv4_HEADER ) );\r
+\r
+ /* Switch on the Layer 3/4 protocol. */\r
if( ucProtocol == ( uint8_t ) ipPROTOCOL_UDP )\r
{\r
+ if( uxBufferLength < uxIPHeaderLength + ipSIZE_OF_ETH_HEADER + ipSIZE_OF_UDP_HEADER )\r
+ {\r
+ return ipINVALID_LENGTH;\r
+ }\r
+\r
pusChecksum = ( uint16_t * ) ( &( pxProtPack->xUDPPacket.xUDPHeader.usChecksum ) );\r
#if( ipconfigHAS_DEBUG_PRINTF != 0 )\r
{\r
}\r
else if( ucProtocol == ( uint8_t ) ipPROTOCOL_TCP )\r
{\r
- pusChecksum = ( uint16_t * ) ( &( pxProtPack->xTCPPacket.xTCPHeader.usChecksum ) );\r
+ if( uxBufferLength < uxIPHeaderLength + ipSIZE_OF_ETH_HEADER + ipSIZE_OF_TCP_HEADER )\r
+ {\r
+ return ipINVALID_LENGTH;\r
+ }\r
+ \r
+ pusChecksum = ( uint16_t * ) ( &( pxProtPack->xTCPPacket.xTCPHeader.usChecksum ) );\r
#if( ipconfigHAS_DEBUG_PRINTF != 0 )\r
{\r
pcType = "TCP";\r
else if( ( ucProtocol == ( uint8_t ) ipPROTOCOL_ICMP ) ||\r
( ucProtocol == ( uint8_t ) ipPROTOCOL_IGMP ) )\r
{\r
- pusChecksum = ( uint16_t * ) ( &( pxProtPack->xICMPPacket.xICMPHeader.usChecksum ) );\r
-\r
+ if( uxBufferLength < uxIPHeaderLength + ipSIZE_OF_ETH_HEADER + ipSIZE_OF_ICMP_HEADER )\r
+ {\r
+ return ipINVALID_LENGTH;\r
+ }\r
+ \r
+ pusChecksum = ( uint16_t * ) ( &( pxProtPack->xICMPPacket.xICMPHeader.usChecksum ) );\r
#if( ipconfigHAS_DEBUG_PRINTF != 0 )\r
{\r
if( ucProtocol == ( uint8_t ) ipPROTOCOL_ICMP )\r
return ipUNHANDLED_PROTOCOL;\r
}\r
\r
+ /* The protocol and checksum field have been identified. Check the direction\r
+ of the packet. */\r
if( xOutgoingPacket != pdFALSE )\r
{\r
/* This is an outgoing packet. Before calculating the checksum, set it\r
/* And then continue at the IPv4 source and destination addresses. */\r
usChecksum = ( uint16_t )\r
( ~usGenerateChecksum( ( uint32_t ) usChecksum, ( uint8_t * )&( pxIPPacket->xIPHeader.ulSourceIPAddress ),\r
- ( size_t )( 2u * sizeof( pxIPPacket->xIPHeader.ulSourceIPAddress ) + ulLength ) ) );\r
+ ( 2u * sizeof( pxIPPacket->xIPHeader.ulSourceIPAddress ) + ulLength ) ) );\r
\r
/* Sum TCP header and data. */\r
}\r
}\r
/*-----------------------------------------------------------*/\r
\r
+/**\r
+ * This method generates a checksum for a given IPv4 header, per RFC791 (page 14).\r
+ * The checksum algorithm is decribed as:\r
+ * "[T]he 16 bit one's complement of the one's complement sum of all 16 bit words in the\r
+ * header. For purposes of computing the checksum, the value of the checksum field is zero."\r
+ *\r
+ * In a nutshell, that means that each 16-bit 'word' must be summed, after which\r
+ * the number of 'carries' (overflows) is added to the result. If that addition\r
+ * produces an overflow, that 'carry' must also be added to the final result. The final checksum\r
+ * should be the bitwise 'not' (ones-complement) of the result if the packet is\r
+ * meant to be transmitted, but this method simply returns the raw value, probably\r
+ * because when a packet is received, the checksum is verified by checking that\r
+ * ((received & calculated) == 0) without applying a bitwise 'not' to the 'calculated' checksum.\r
+ *\r
+ * This logic is optimized for microcontrollers which have limited resources, so the logic looks odd.\r
+ * It iterates over the full range of 16-bit words, but it does so by processing several 32-bit\r
+ * words at once whenever possible. Its first step is to align the memory pointer to a 32-bit boundary,\r
+ * after which it runs a fast loop to process multiple 32-bit words at once and adding their 'carries'.\r
+ * Finally, it finishes up by processing any remaining 16-bit words, and adding up all of the 'carries'.\r
+ * With 32-bit arithmetic, the number of 16-bit 'carries' produced by sequential additions can be found\r
+ * by looking at the 16 most-significant bits of the 32-bit integer, since a 32-bit int will continue\r
+ * counting up instead of overflowing after 16 bits. That is why the actual checksum calculations look like:\r
+ * union.u32 = ( uint32_t ) union.u16[ 0 ] + union.u16[ 1 ];\r
+ *\r
+ * Arguments:\r
+ * ulSum: This argument provides a value to initialize the progressive summation\r
+ * of the header's values to. It is often 0, but protocols like TCP or UDP\r
+ * can have pseudo-header fields which need to be included in the checksum.\r
+ * pucNextData: This argument contains the address of the first byte which this\r
+ * method should process. The method's memory iterator is initialized to this value.\r
+ * uxDataLengthBytes: This argument contains the number of bytes that this method\r
+ * should process.\r
+ */\r
uint16_t usGenerateChecksum( uint32_t ulSum, const uint8_t * pucNextData, size_t uxDataLengthBytes )\r
{\r
xUnion32 xSum2, xSum, xTerm;\r
\r
void FreeRTOS_UpdateMACAddress( const uint8_t ucMACAddress[ipMAC_ADDRESS_LENGTH_BYTES] )\r
{\r
- /* Copy the MAC address at the start of the default packet header fragment. */\r
- memcpy( ( void * )ipLOCAL_MAC_ADDRESS, ( void * )ucMACAddress, ( size_t )ipMAC_ADDRESS_LENGTH_BYTES );\r
+ /* Copy the MAC address at the start of the default packet header fragment. */\r
+ memcpy( ( void * )ipLOCAL_MAC_ADDRESS, ( void * )ucMACAddress, ( size_t )ipMAC_ADDRESS_LENGTH_BYTES );\r
}\r
/*-----------------------------------------------------------*/\r
\r