]> git.sur5r.net Git - freertos/blobdiff - FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_IP.c
Fix some build issues in older kernel demo projects.
[freertos] / FreeRTOS-Plus / Source / FreeRTOS-Plus-TCP / FreeRTOS_IP.c
index 7f311ade8eda9a4f6852d848a26ecea84905e9db..fdb8fd11653a277e24cf556bc7689f9089c664b3 100644 (file)
@@ -1,5 +1,5 @@
 /*\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
@@ -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,12 @@ 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
+                       xReceivedEvent.eEventType = eNoEvent;\r
+               }\r
 \r
                #if( ipconfigCHECK_IP_QUEUE_SPACE != 0 )\r
                {\r
@@ -655,14 +654,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 +666,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 +803,10 @@ void *pvReturn;
 \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
@@ -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
-\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
@@ -1356,35 +1345,52 @@ 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
-       {\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
@@ -1433,9 +1439,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 +1487,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 +1506,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 +1535,21 @@ 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 =\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
@@ -1552,11 +1573,18 @@ 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
-                                       {\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
@@ -1566,23 +1594,47 @@ 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
-                                       {\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
@@ -1739,7 +1791,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 +1803,48 @@ uint8_t ucProtocol;
        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
@@ -1767,7 +1854,12 @@ uint8_t ucProtocol;
        }\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
@@ -1777,8 +1869,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
-\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 +1894,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 +1942,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 +1995,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
@@ -2095,8 +2226,8 @@ uint32_t FreeRTOS_GetNetmask( void )
 \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