/*\r
- * FreeRTOS+TCP V2.0.3\r
+ * FreeRTOS+TCP V2.0.11\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
+ {\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 = 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
+ xReturn = 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
+ 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
}\r
#endif\r
\r
+ /* Per the ARP Cache Validation section of https://tools.ietf.org/html/rfc1122, \r
+ treat network down as a "delivery problem" and flush the ARP cache for this\r
+ interface. */\r
+ FreeRTOS_ClearARP( );\r
+\r
/* The network has been disconnected (or is being initialised for the first\r
time). Perform whatever hardware processing is necessary to bring it up\r
again, or wait for it to be available again. This is hardware dependent. */\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
+ if( pxNetworkBuffer->xDataLength >= sizeof( EthernetHeader_t ) )\r
{\r
- /* Interpret the received Ethernet packet. */\r
- switch( pxEthernetHeader->usFrameType )\r
+ eReturned = ipCONSIDER_FRAME_FOR_PROCESSING( pxNetworkBuffer->pucEthernetBuffer );\r
+ pxEthernetHeader = ( EthernetHeader_t * )( pxNetworkBuffer->pucEthernetBuffer );\r
+\r
+ if( eReturned == eProcessBuffer )\r
{\r
- case ipARP_FRAME_TYPE :\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
+ 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
+ case ipIPv4_FRAME_TYPE:\r
/* The Ethernet frame contains an IP packet. */\r
- eReturned = prvProcessIPPacket( ( IPPacket_t * ) pxNetworkBuffer->pucEthernetBuffer, pxNetworkBuffer );\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
+ default:\r
/* No other packet types are handled. Nothing to do. */\r
eReturned = eReleaseBuffer;\r
break;\r
+ }\r
}\r
}\r
\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 = ( 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
+ if( pxNetworkBuffer->xDataLength >= sizeof( ICMPPacket_t ) )\r
{\r
- eReturn = prvProcessICMPPacket( pxICMPPacket );\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
/* 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
+ /* Only proceed if the payload length indicated in the header\r
+ appears to be valid. */\r
+ if ( pxNetworkBuffer->xDataLength >= sizeof( UDPPacket_t ) )\r
{\r
- eReturn = eFrameConsumed;\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 ) - 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
#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
+ /* 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
- uxIPHeaderLength = ( UBaseType_t ) ( 4u * ( pxIPPacket->xIPHeader.ucVersionHeaderLength & 0x0Fu ) ); /*_RB_ Why 4? */\r
- pxProtPack = ( ProtocolPacket_t * ) ( pucEthernetBuffer + ( uxIPHeaderLength - ipSIZE_OF_IPv4_HEADER ) );\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 ) ( 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
+ 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
else if( ( ucProtocol == ( uint8_t ) ipPROTOCOL_ICMP ) ||\r
( ucProtocol == ( uint8_t ) ipPROTOCOL_IGMP ) )\r
{\r
- pusChecksum = ( uint16_t * ) ( &( pxProtPack->xICMPPacket.xICMPHeader.usChecksum ) );\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