]> git.sur5r.net Git - freertos/blobdiff - FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_IP.c
Update version number in +TCP code.
[freertos] / FreeRTOS-Plus / Source / FreeRTOS-Plus-TCP / FreeRTOS_IP.c
index 7f311ade8eda9a4f6852d848a26ecea84905e9db..325a69ac4813b9ac7460313792264d9b33d28250 100644 (file)
@@ -1,5 +1,5 @@
 /*\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
@@ -65,9 +65,7 @@ a constant. */
 \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
@@ -186,7 +184,7 @@ static void prvProcessEthernetPacket( NetworkBufferDescriptor_t * const pxNetwor
 /*\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
@@ -356,11 +354,13 @@ struct freertos_sockaddr xAddress;
                /* 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
@@ -655,14 +655,8 @@ static void prvCheckNetworkTimers( void )
        #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
@@ -673,19 +667,6 @@ static void prvCheckNetworkTimers( void )
                        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
@@ -823,6 +804,9 @@ void *pvReturn;
 \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
@@ -847,6 +831,11 @@ NetworkBufferDescriptor_t * pxNewBuffer;
 \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
@@ -997,10 +986,7 @@ BaseType_t xReturn = pdFALSE;
 \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
@@ -1009,10 +995,13 @@ BaseType_t xReturn = pdFALSE;
                        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
@@ -1299,6 +1288,11 @@ static void prvProcessNetworkDownEvent( void )
        }\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
@@ -1356,33 +1350,50 @@ void vIPNetworkUpCalls( void )
 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
@@ -1433,9 +1444,9 @@ eFrameProcessingResult_t eReturn = eProcessBuffer;
                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
@@ -1481,7 +1492,7 @@ eFrameProcessingResult_t eReturn = eProcessBuffer;
                                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
@@ -1500,13 +1511,22 @@ eFrameProcessingResult_t eReturn = eProcessBuffer;
 }\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
@@ -1520,15 +1540,20 @@ uint8_t ucProtocol;
                         * 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
@@ -1552,10 +1577,17 @@ uint8_t ucProtocol;
                                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
@@ -1566,22 +1598,45 @@ uint8_t ucProtocol;
                                        /* 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
@@ -1739,7 +1794,7 @@ uint8_t ucProtocol;
 #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
@@ -1751,13 +1806,47 @@ uint8_t ucProtocol;
        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
@@ -1767,6 +1856,11 @@ uint8_t ucProtocol;
        }\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
@@ -1777,8 +1871,12 @@ uint8_t ucProtocol;
        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
@@ -1798,6 +1896,8 @@ uint8_t ucProtocol;
                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
@@ -1844,7 +1944,7 @@ uint8_t ucProtocol;
                /* 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
@@ -1897,6 +1997,39 @@ uint8_t ucProtocol;
 }\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