/* * FreeRTOS+TCP V2.3.1 * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * * http://aws.amazon.com/freertos * http://www.FreeRTOS.org */ /** * @file FreeRTOS_Routing.c * @brief Implements endpoint interfaces functions and utilities. */ /* Standard includes. */ #include #include /* FreeRTOS includes. */ #include "FreeRTOS.h" #include "task.h" /* FreeRTOS+TCP includes. */ #include "FreeRTOS_IP.h" #include "FreeRTOS_Sockets.h" #include "FreeRTOS_IP_Private.h" #include "FreeRTOS_ARP.h" #include "FreeRTOS_UDP_IP.h" #include "FreeRTOS_DHCP.h" #include "NetworkBufferManagement.h" #if ( ipconfigUSE_LLMNR == 1 ) #include "FreeRTOS_DNS.h" #endif /* ipconfigUSE_LLMNR */ #include "FreeRTOS_Routing.h" /** @brief A list of all network end-points. Each element has a next pointer. */ struct xNetworkEndPoint * pxNetworkEndPoints = NULL; /** @brief A list of all network interfaces: */ struct xNetworkInterface * pxNetworkInterfaces = NULL; /* * Add a new IP-address to a Network Interface. The object pointed to by * 'pxEndPoint' and the interface must continue to exist. */ static NetworkEndPoint_t * FreeRTOS_AddEndPoint( NetworkInterface_t * pxInterface, NetworkEndPoint_t * pxEndPoint ); /** @brief A util struct to list the IPv6 IP types, prefix and type bit mask */ struct xIPv6_Couple { IPv6_Type_t eType; /**< IPv6 IP type enum */ uint16_t usMask; /**< IPv6 IP type bit mask */ uint16_t usExpected; /**< IPv6 IP type prefix */ }; /*-----------------------------------------------------------*/ #if ( ipconfigUSE_IPv4 != 0 ) /** * @brief Configure and install a new IPv4 end-point. * * @param[in] pxNetworkInterface The interface to which it belongs. * @param[in] pxEndPoint Space for the new end-point. This memory is dedicated for the * end-point and should not be freed or get any other purpose. * @param[in] ucIPAddress The IP-address. * @param[in] ucNetMask The prefix which shall be used for this end-point. * @param[in] ucGatewayAddress The IP-address of a device on the LAN which can serve as * as a gateway to the Internet. * @param[in] ucDNSServerAddress The IP-address of a DNS server. * @param[in] ucMACAddress The MAC address of the end-point. */ void FreeRTOS_FillEndPoint( NetworkInterface_t * pxNetworkInterface, NetworkEndPoint_t * pxEndPoint, const uint8_t ucIPAddress[ ipIP_ADDRESS_LENGTH_BYTES ], const uint8_t ucNetMask[ ipIP_ADDRESS_LENGTH_BYTES ], const uint8_t ucGatewayAddress[ ipIP_ADDRESS_LENGTH_BYTES ], const uint8_t ucDNSServerAddress[ ipIP_ADDRESS_LENGTH_BYTES ], const uint8_t ucMACAddress[ ipMAC_ADDRESS_LENGTH_BYTES ] ) { uint32_t ulIPAddress; if( ( pxNetworkInterface == NULL ) || ( pxEndPoint == NULL ) ) { /* Invalid input. */ FreeRTOS_printf( ( "FreeRTOS_FillEndPoint: Invalid input, netif=%p, endpoint=%p\n", ( void * ) pxNetworkInterface, ( void * ) pxEndPoint ) ); } else { /* Fill in and add an end-point to a network interface. * The user must make sure that the object pointed to by 'pxEndPoint' * will remain to exist. */ ( void ) memset( pxEndPoint, 0, sizeof( *pxEndPoint ) ); ulIPAddress = FreeRTOS_inet_addr_quick( ucIPAddress[ 0 ], ucIPAddress[ 1 ], ucIPAddress[ 2 ], ucIPAddress[ 3 ] ); pxEndPoint->ipv4_settings.ulNetMask = FreeRTOS_inet_addr_quick( ucNetMask[ 0 ], ucNetMask[ 1 ], ucNetMask[ 2 ], ucNetMask[ 3 ] ); pxEndPoint->ipv4_settings.ulGatewayAddress = FreeRTOS_inet_addr_quick( ucGatewayAddress[ 0 ], ucGatewayAddress[ 1 ], ucGatewayAddress[ 2 ], ucGatewayAddress[ 3 ] ); pxEndPoint->ipv4_settings.ulDNSServerAddresses[ 0 ] = FreeRTOS_inet_addr_quick( ucDNSServerAddress[ 0 ], ucDNSServerAddress[ 1 ], ucDNSServerAddress[ 2 ], ucDNSServerAddress[ 3 ] ); pxEndPoint->ipv4_settings.ulBroadcastAddress = ulIPAddress | ~( pxEndPoint->ipv4_settings.ulNetMask ); /* Copy the current values to the default values. */ ( void ) memcpy( &( pxEndPoint->ipv4_defaults ), &( pxEndPoint->ipv4_settings ), sizeof( pxEndPoint->ipv4_defaults ) ); /* The default IP-address will be used in case DHCP is not used, or also if DHCP has failed, or * when the user chooses to use the default IP-address. */ pxEndPoint->ipv4_defaults.ulIPAddress = ulIPAddress; /* The field 'ipv4_settings.ulIPAddress' will be set later on. */ ( void ) memcpy( pxEndPoint->xMACAddress.ucBytes, ucMACAddress, sizeof( pxEndPoint->xMACAddress ) ); ( void ) FreeRTOS_AddEndPoint( pxNetworkInterface, pxEndPoint ); } } /*-----------------------------------------------------------*/ #endif /* ( ipconfigUSE_IPv4 != 0 ) */ #if ( ipconfigCOMPATIBLE_WITH_SINGLE == 0 ) #if ( ipconfigHAS_ROUTING_STATISTICS == 1 ) RoutingStats_t xRoutingStatistics; #endif /*-----------------------------------------------------------*/ /** * @brief Add a network interface to the list of interfaces. Check if the interface was * already added in an earlier call. * * @param[in] pxInterface The address of the new interface. * * @return The value of the parameter 'pxInterface'. */ NetworkInterface_t * FreeRTOS_AddNetworkInterface( NetworkInterface_t * pxInterface ) { NetworkInterface_t * pxIterator = NULL; if( pxInterface != NULL ) { /* This interface will be added to the end of the list of interfaces, so * there is no pxNext yet. */ pxInterface->pxNext = NULL; /* The end point for this interface has not yet been set. */ /*_RB_ As per other comments, why not set the end point at the same time? */ pxInterface->pxEndPoint = NULL; if( pxNetworkInterfaces == NULL ) { /* No other interfaces are set yet, so this is the first in the list. */ pxNetworkInterfaces = pxInterface; } else { /* Other interfaces are already defined, so iterate to the end of the * list. */ /*_RB_ Question - if ipconfigMULTI_INTERFACE is used to define the * maximum number of interfaces, would it be more efficient to have an * array of interfaces rather than a linked list of interfaces? */ pxIterator = pxNetworkInterfaces; for( ; ; ) { if( pxIterator == pxInterface ) { /* This interface was already added. */ break; } if( pxIterator->pxNext == NULL ) { pxIterator->pxNext = pxInterface; break; } pxIterator = pxIterator->pxNext; } } } return pxInterface; } /*-----------------------------------------------------------*/ /** * @brief Get the first Network Interface, or NULL if none has been added. * * @return The first interface, or NULL if none has been added */ NetworkInterface_t * FreeRTOS_FirstNetworkInterface( void ) { return pxNetworkInterfaces; } /*-----------------------------------------------------------*/ /** * @brief Get the next interface. * * @return The interface that comes after 'pxInterface'. NULL when either 'pxInterface' * is NULL, or when 'pxInterface' is the last interface. */ NetworkInterface_t * FreeRTOS_NextNetworkInterface( const NetworkInterface_t * pxInterface ) { NetworkInterface_t * pxReturn; if( pxInterface != NULL ) { pxReturn = pxInterface->pxNext; } else { pxReturn = NULL; } return pxReturn; } /*-----------------------------------------------------------*/ /** * @brief Add an end-point to a given interface. * * @param[in] pxInterface The interface that gets a new end-point. * @param[in] pxEndPoint The end-point to be added. * * @return The value of the parameter 'pxEndPoint'. */ static NetworkEndPoint_t * FreeRTOS_AddEndPoint( NetworkInterface_t * pxInterface, NetworkEndPoint_t * pxEndPoint ) { NetworkEndPoint_t * pxIterator = NULL; /* This end point will go to the end of the list, so there is no pxNext * yet. */ pxEndPoint->pxNext = NULL; /* Double link between the NetworkInterface_t that is using the addressing * defined by this NetworkEndPoint_t structure. */ pxEndPoint->pxNetworkInterface = pxInterface; if( pxInterface->pxEndPoint == NULL ) { /*_RB_ When would pxInterface->pxEndPoint ever not be NULL unless this is called twice? */ /*_HT_ It may be called twice. */ pxInterface->pxEndPoint = pxEndPoint; } if( pxNetworkEndPoints == NULL ) { /* No other end points are defined yet - so this is the first in the * list. */ pxNetworkEndPoints = pxEndPoint; } else { /* Other end points are already defined so iterate to the end of the * list. */ pxIterator = pxNetworkEndPoints; for( ; ; ) { if( pxIterator == pxEndPoint ) { /* This end-point has already been added to the list. */ break; } if( pxIterator->pxNext == NULL ) { pxIterator->pxNext = pxEndPoint; break; } pxIterator = pxIterator->pxNext; } } #if ( ipconfigUSE_IPv6 != 0 ) if( pxEndPoint->bits.bIPv6 == pdTRUE_UNSIGNED ) { FreeRTOS_printf( ( "FreeRTOS_AddEndPoint: MAC: %02x-%02x IPv6: %pip\n", pxEndPoint->xMACAddress.ucBytes[ 4 ], pxEndPoint->xMACAddress.ucBytes[ 5 ], ( void * ) pxEndPoint->ipv6_defaults.xIPAddress.ucBytes ) ); } #endif /* ( ipconfigUSE_IPv6 != 0 ) */ #if ( ipconfigUSE_IPv4 != 0 ) if( pxEndPoint->bits.bIPv6 == pdFALSE_UNSIGNED ) { FreeRTOS_printf( ( "FreeRTOS_AddEndPoint: MAC: %02x-%02x IPv4: %xip\n", pxEndPoint->xMACAddress.ucBytes[ 4 ], pxEndPoint->xMACAddress.ucBytes[ 5 ], ( unsigned ) FreeRTOS_ntohl( pxEndPoint->ipv4_defaults.ulIPAddress ) ) ); } #endif /* ( ipconfigUSE_IPv4 != 0 ) */ return pxEndPoint; } /*-----------------------------------------------------------*/ /** * @brief Find the first end-point bound to a given interface. * * @param[in] pxInterface The interface whose first end-point will be returned. * * @return The first end-point that is found to the interface, or NULL when the * interface doesn't have any end-point yet. */ NetworkEndPoint_t * FreeRTOS_FirstEndPoint( const NetworkInterface_t * pxInterface ) { NetworkEndPoint_t * pxEndPoint = pxNetworkEndPoints; /* Find and return the NetworkEndPoint_t structure that is associated with * the pxInterface NetworkInterface_t. *//*_RB_ Could this be made a two way link, so the NetworkEndPoint_t can just be read from the NetworkInterface_t structure? Looks like there is a pointer in the struct already. */ while( pxEndPoint != NULL ) { if( ( pxInterface == NULL ) || ( pxEndPoint->pxNetworkInterface == pxInterface ) ) { break; } pxEndPoint = pxEndPoint->pxNext; } return pxEndPoint; } /*-----------------------------------------------------------*/ /** * @brief Get the next end-point. The parameter 'pxInterface' may be NULL, which means: * don't care which interface the end-point is bound to. * * @param[in] pxInterface An interface of interest, or NULL when iterating through all * end-points. * @param[in] pxEndPoint This is the current end-point. * * @return The end-point that is found, or NULL when there are no more end-points in the list. */ NetworkEndPoint_t * FreeRTOS_NextEndPoint( const NetworkInterface_t * pxInterface, NetworkEndPoint_t * pxEndPoint ) { NetworkEndPoint_t * pxResult = pxEndPoint; if( pxResult != NULL ) { pxResult = pxResult->pxNext; while( pxResult != NULL ) { if( ( pxInterface == NULL ) || ( pxResult->pxNetworkInterface == pxInterface ) ) { break; } pxResult = pxResult->pxNext; } } else { pxResult = FreeRTOS_FirstEndPoint( pxInterface ); } return pxResult; } /*-----------------------------------------------------------*/ /** * @brief Find the end-point which has a given IPv4 address. * * @param[in] ulIPAddress The IP-address of interest, or 0 if any IPv4 end-point may be returned. * @param[in] ulWhere For maintaining routing statistics ulWhere acts as an index to the data structure * that keep track of the number of times 'FreeRTOS_FindEndPointOnIP_IPv4()' * has been called from a particular location. Used only if * ipconfigHAS_ROUTING_STATISTICS is enabled. * * @return The end-point found or NULL. */ NetworkEndPoint_t * FreeRTOS_FindEndPointOnIP_IPv4( uint32_t ulIPAddress, uint32_t ulWhere ) { NetworkEndPoint_t * pxEndPoint = pxNetworkEndPoints; #if ( ipconfigHAS_ROUTING_STATISTICS == 1 ) uint32_t ulLocationCount = ( uint32_t ) ( sizeof( xRoutingStatistics.ulLocationsIP ) / sizeof( xRoutingStatistics.ulLocationsIP[ 0 ] ) ); xRoutingStatistics.ulOnIp++; if( ulWhere < ulLocationCount ) { xRoutingStatistics.ulLocationsIP[ ulWhere ]++; } #endif /* ( ipconfigHAS_ROUTING_STATISTICS == 1 ) */ while( pxEndPoint != NULL ) { #if ( ipconfigUSE_IPv4 != 0 ) #if ( ipconfigUSE_IPv6 != 0 ) if( pxEndPoint->bits.bIPv6 == 0U ) #endif { if( ( ulIPAddress == 0U ) || ( pxEndPoint->ipv4_settings.ulIPAddress == 0U ) || ( pxEndPoint->ipv4_settings.ulIPAddress == ulIPAddress ) ) { break; } } #endif /* ( ipconfigUSE_IPv4 != 0 ) */ pxEndPoint = pxEndPoint->pxNext; } ( void ) ulIPAddress; return pxEndPoint; } /*-----------------------------------------------------------*/ #if ( ipconfigUSE_IPv6 != 0 ) /** * @brief Find the end-point which handles a given IPv6 address. * * @param[in] pxIPAddress The IP-address of interest. * * @return The end-point found or NULL. */ NetworkEndPoint_t * FreeRTOS_FindEndPointOnIP_IPv6( const IPv6_Address_t * pxIPAddress ) { NetworkEndPoint_t * pxEndPoint = pxNetworkEndPoints; while( pxEndPoint != NULL ) { if( pxEndPoint->bits.bIPv6 != pdFALSE_UNSIGNED ) { if( xCompareIPv6_Address( &( pxEndPoint->ipv6_settings.xIPAddress ), pxIPAddress, pxEndPoint->ipv6_settings.uxPrefixLength ) == 0 ) { break; } } pxEndPoint = pxEndPoint->pxNext; } return pxEndPoint; } #endif /* ipconfigUSE_IPv6 */ /*-----------------------------------------------------------*/ /** * @brief Find the end-point that has a certain MAC-address. * * @param[in] pxMACAddress The Ethernet packet. * @param[in] pxInterface The interface on which the packet was received, or NULL when unknown. * * @return The end-point that has the given MAC-address. */ NetworkEndPoint_t * FreeRTOS_FindEndPointOnMAC( const MACAddress_t * pxMACAddress, const NetworkInterface_t * pxInterface ) { NetworkEndPoint_t * pxEndPoint = pxNetworkEndPoints; #if ( ipconfigHAS_ROUTING_STATISTICS == 1 ) { xRoutingStatistics.ulOnMAC++; } #endif /* If input MAC address is NULL, return NULL. */ if( pxMACAddress == NULL ) { pxEndPoint = NULL; } /*_RB_ Question - would it be more efficient to store the mac addresses in * uin64_t variables for direct comparison instead of using memcmp()? [don't * know if there is a quick way of creating a 64-bit number from the 48-byte * MAC address without getting junk in the top 2 bytes]. */ /* Find the end-point with given MAC-address. */ while( pxEndPoint != NULL ) { if( ( pxInterface == NULL ) || ( pxInterface == pxEndPoint->pxNetworkInterface ) ) { if( memcmp( pxEndPoint->xMACAddress.ucBytes, pxMACAddress->ucBytes, ipMAC_ADDRESS_LENGTH_BYTES ) == 0 ) { break; } } pxEndPoint = pxEndPoint->pxNext; } return pxEndPoint; } /*-----------------------------------------------------------*/ /** * @brief Find an end-point that handles a given IPv4-address. * * @param[in] ulIPAddress The IP-address for which an end-point is looked-up. * @param[in] ulWhere For maintaining routing statistics ulWhere acts as an index to the data structure * that keep track of the number of times 'FreeRTOS_InterfaceEndPointOnNetMask()' * has been called from a particular location. Used only if * ipconfigHAS_ROUTING_STATISTICS is enabled. * * @return An end-point that has the same network mask as the given IP-address. */ NetworkEndPoint_t * FreeRTOS_FindEndPointOnNetMask( uint32_t ulIPAddress, uint32_t ulWhere ) { /* The 'ulWhere' parameter is only for debugging purposes. */ return FreeRTOS_InterfaceEndPointOnNetMask( NULL, ulIPAddress, ulWhere ); } /*-----------------------------------------------------------*/ /** * @brief Find an end-point that handles a given IPv4-address. * * @param[in] pxInterface Only end-points that have this interface are returned, unless * pxInterface is NULL. * @param[in] ulIPAddress The IP-address for which an end-point is looked-up. * * @param[in] ulWhere For maintaining routing statistics ulWhere acts as an index to the data structure * that keep track of the number of times 'FreeRTOS_InterfaceEndPointOnNetMask()' * has been called from a particular location. Used only if * ipconfigHAS_ROUTING_STATISTICS is enabled. * * @return An end-point that has the same network mask as the given IP-address. */ NetworkEndPoint_t * FreeRTOS_InterfaceEndPointOnNetMask( const NetworkInterface_t * pxInterface, uint32_t ulIPAddress, uint32_t ulWhere ) { NetworkEndPoint_t * pxEndPoint = pxNetworkEndPoints; #if ( ipconfigHAS_ROUTING_STATISTICS == 1 ) uint32_t ulLocationCount = ( uint32_t ) ( sizeof( xRoutingStatistics.ulLocations ) / sizeof( xRoutingStatistics.ulLocations[ 0 ] ) ); xRoutingStatistics.ulOnNetMask++; if( ulWhere < ulLocationCount ) { xRoutingStatistics.ulLocations[ ulWhere ]++; } #endif /* ( ipconfigHAS_ROUTING_STATISTICS == 1 ) */ /* Find the best fitting end-point to reach a given IP-address. */ /*_RB_ Presumably then a broadcast reply could go out on a different end point to that on * which the broadcast was received - although that should not be an issue if the nodes are * on the same LAN it could be an issue if the nodes are on separate LAN's. */ while( pxEndPoint != NULL ) { if( ( pxInterface == NULL ) || ( pxEndPoint->pxNetworkInterface == pxInterface ) ) { #if ( ipconfigUSE_IPv4 != 0 ) #if ( ipconfigUSE_IPv6 != 0 ) if( pxEndPoint->bits.bIPv6 == pdFALSE_UNSIGNED ) #endif { if( ( ulIPAddress == ~0U ) || ( ( ulIPAddress & pxEndPoint->ipv4_settings.ulNetMask ) == ( pxEndPoint->ipv4_settings.ulIPAddress & pxEndPoint->ipv4_settings.ulNetMask ) ) ) { /* Found a match. */ break; } } #endif /* if ( ipconfigUSE_IPv4 != 0 ) */ } pxEndPoint = pxEndPoint->pxNext; } /* This was only for debugging. */ if( pxEndPoint == NULL ) { FreeRTOS_debug_printf( ( "FreeRTOS_FindEndPointOnNetMask[%d]: No match for %xip\n", ( unsigned ) ulWhere, ( unsigned ) FreeRTOS_ntohl( ulIPAddress ) ) ); } return pxEndPoint; } /*-----------------------------------------------------------*/ #if ( ipconfigUSE_IPv6 != 0 ) /** * @brief Configure and install a new IPv6 end-point. * * @param[in] pxNetworkInterface The interface to which it belongs. * @param[in] pxEndPoint Space for the new end-point. This memory is dedicated for the * end-point and should not be freed or get any other purpose. * @param[in] pxIPAddress The IP-address. * @param[in] pxNetPrefix The prefix which shall be used for this end-point. * @param[in] uxPrefixLength The length of the above end-point. * @param[in] pxGatewayAddress The IP-address of a device on the LAN which can serve as * as a gateway to the Internet. * @param[in] pxDNSServerAddress The IP-address of a DNS server. * @param[in] ucMACAddress The MAC address of the end-point. */ void FreeRTOS_FillEndPoint_IPv6( NetworkInterface_t * pxNetworkInterface, NetworkEndPoint_t * pxEndPoint, const IPv6_Address_t * pxIPAddress, const IPv6_Address_t * pxNetPrefix, size_t uxPrefixLength, const IPv6_Address_t * pxGatewayAddress, const IPv6_Address_t * pxDNSServerAddress, const uint8_t ucMACAddress[ ipMAC_ADDRESS_LENGTH_BYTES ] ) { if( ( pxNetworkInterface == NULL ) || ( pxEndPoint == NULL ) || ( pxIPAddress == NULL ) || ( ucMACAddress == NULL ) ) { /* Invalid input. */ FreeRTOS_printf( ( "FreeRTOS_FillEndPoint_IPv6: Invalid input, netif=%p, endpoint=%p, pxIPAddress=%p, ucMACAddress=%p\n", ( void * ) pxNetworkInterface, ( void * ) pxEndPoint, ( void * ) pxIPAddress, ( void * ) ucMACAddress ) ); } else { ( void ) memset( pxEndPoint, 0, sizeof( *pxEndPoint ) ); pxEndPoint->bits.bIPv6 = pdTRUE_UNSIGNED; pxEndPoint->ipv6_settings.uxPrefixLength = uxPrefixLength; if( pxGatewayAddress != NULL ) { ( void ) memcpy( pxEndPoint->ipv6_settings.xGatewayAddress.ucBytes, pxGatewayAddress->ucBytes, ipSIZE_OF_IPv6_ADDRESS ); } if( pxDNSServerAddress != NULL ) { ( void ) memcpy( pxEndPoint->ipv6_settings.xDNSServerAddresses[ 0 ].ucBytes, pxDNSServerAddress->ucBytes, ipSIZE_OF_IPv6_ADDRESS ); } if( pxNetPrefix != NULL ) { ( void ) memcpy( pxEndPoint->ipv6_settings.xPrefix.ucBytes, pxNetPrefix->ucBytes, ipSIZE_OF_IPv6_ADDRESS ); } /* Copy the current values to the default values. */ ( void ) memcpy( &( pxEndPoint->ipv6_defaults ), &( pxEndPoint->ipv6_settings ), sizeof( pxEndPoint->ipv6_defaults ) ); ( void ) memcpy( pxEndPoint->ipv6_defaults.xIPAddress.ucBytes, pxIPAddress->ucBytes, ipSIZE_OF_IPv6_ADDRESS ); ( void ) memcpy( pxEndPoint->xMACAddress.ucBytes, ucMACAddress, ipMAC_ADDRESS_LENGTH_BYTES ); ( void ) FreeRTOS_AddEndPoint( pxNetworkInterface, pxEndPoint ); } } #endif /* if ( ipconfigUSE_IPv6 != 0 ) */ /*-----------------------------------------------------------*/ #if ( ipconfigUSE_IPv6 != 0 ) /** * @brief Find an end-point that handles a given IPv6-address. * * @param[in] pxIPv6Address The IP-address for which an end-point is looked-up. * * @return An end-point that has the same network mask as the given IP-address. */ NetworkEndPoint_t * FreeRTOS_FindEndPointOnNetMask_IPv6( const IPv6_Address_t * pxIPv6Address ) { NetworkEndPoint_t * pxEndPoint = pxNetworkEndPoints; while( pxEndPoint != NULL ) { if( pxEndPoint->bits.bIPv6 != pdFALSE_UNSIGNED ) { if( xCompareIPv6_Address( &( pxEndPoint->ipv6_settings.xIPAddress ), pxIPv6Address, pxEndPoint->ipv6_settings.uxPrefixLength ) == 0 ) { break; } } pxEndPoint = pxEndPoint->pxNext; } return pxEndPoint; } #endif /* ipconfigUSE_IPv6 */ /*-----------------------------------------------------------*/ /** * @brief Check IP-type, IP- and MAC-address found in the network packet. */ #define rMATCH_IP_ADDR 0 /**< Find an endpoint with a matching IP-address. */ #define rMATCH_IPv6_TYPE 1 /**< Find an endpoint with a matching IPv6 type (both global or non global). */ #define rMATCH_MAC_ADDR 2 /**< Find an endpoint with a matching MAC-address. */ #define rMATCH_IP_TYPE 3 /**< Find an endpoint with a matching IP-type, v4 or v6. */ #define rMATCH_COUNT 4 /**< The number of methods. */ NetworkEndPoint_t * pxEasyFit( const NetworkInterface_t * pxNetworkInterface, const uint16_t usFrameType, const IP_Address_t * pxIPAddressFrom, const IP_Address_t * pxIPAddressTo, const MACAddress_t * pxMACAddress ); /** * @brief Find an end-point that handles an incoming packet based on its type, source/destination & MAC address. * * @param[in] pxNetworkInterface The interface via which the packet was received. * @param[in] usFrameType Frame type of the packet. * @param[in] pxIPAddressFrom Source IP address of the packet. * @param[in] pxIPAddressTo Destination IP address of the packet. * @param[in] pxMACAddress Destination MAC address of the packet. * * @return An end-point that handles the packet. */ NetworkEndPoint_t * pxEasyFit( const NetworkInterface_t * pxNetworkInterface, const uint16_t usFrameType, const IP_Address_t * pxIPAddressFrom, const IP_Address_t * pxIPAddressTo, const MACAddress_t * pxMACAddress ) { NetworkEndPoint_t * pxEndPoint; NetworkEndPoint_t * pxReturn = NULL; /* endpoints found for IP-type, IP-address, and MAC-address. */ NetworkEndPoint_t * pxFound[ rMATCH_COUNT ] = { NULL, NULL, NULL, NULL }; BaseType_t xCount[ rMATCH_COUNT ] = { 0, 0, 0, 0 }; BaseType_t xIndex; BaseType_t xIsIPv6 = ( usFrameType == ipIPv6_FRAME_TYPE ) ? pdTRUE : pdFALSE; BaseType_t xGatewayTarget = pdFALSE; BaseType_t xTargetGlobal = pdFALSE; ( void ) pxIPAddressFrom; ( void ) xGatewayTarget; ( void ) xTargetGlobal; #if ( ipconfigUSE_IPv6 != 0 ) if( xIsIPv6 == pdTRUE ) { /* Generic GW address fe80::1. */ static const uint8_t ucBytes[ 16 ] = { 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }; xGatewayTarget = ( memcmp( ucBytes, pxIPAddressTo->xIP_IPv6.ucBytes, 16 ) == 0 ) ? pdTRUE : pdFALSE; if( xGatewayTarget == pdTRUE ) { FreeRTOS_debug_printf( ( " GW address %pip to %pip\n", ( void * ) pxIPAddressFrom->xIP_IPv6.ucBytes, ( void * ) pxIPAddressTo->xIP_IPv6.ucBytes ) ); } xTargetGlobal = ( xIPv6_GetIPType( &( pxIPAddressTo->xIP_IPv6 ) ) == eIPv6_Global ) ? pdTRUE : pdFALSE; } #endif /* ( ipconfigUSE_IPv6 != 0 ) */ for( pxEndPoint = FreeRTOS_FirstEndPoint( pxNetworkInterface ); pxEndPoint != NULL; pxEndPoint = FreeRTOS_NextEndPoint( pxNetworkInterface, pxEndPoint ) ) { BaseType_t xSameMACAddress = ( memcmp( pxEndPoint->xMACAddress.ucBytes, pxMACAddress->ucBytes, ipMAC_ADDRESS_LENGTH_BYTES ) == 0 ) ? pdTRUE : pdFALSE; if( xIsIPv6 == ( BaseType_t ) pxEndPoint->bits.bIPv6 ) { pxFound[ rMATCH_IP_TYPE ] = pxEndPoint; xCount[ rMATCH_IP_TYPE ]++; /* Case default is impossible to reach because no endpoints for disabled IP type. */ switch( xIsIPv6 ) /* LCOV_EXCL_BR_LINE */ { #if ( ipconfigUSE_IPv6 != 0 ) case ( BaseType_t ) pdTRUE: { IPv6_Type_t xEndpointType = xIPv6_GetIPType( &( pxEndPoint->ipv6_settings.xIPAddress ) ); if( xEndpointType != eIPv6_Unknown ) { BaseType_t xEndpointGlobal = ( xEndpointType == eIPv6_Global ) ? pdTRUE : pdFALSE; if( ( memcmp( pxEndPoint->ipv6_settings.xIPAddress.ucBytes, pxIPAddressTo->xIP_IPv6.ucBytes, ipSIZE_OF_IPv6_ADDRESS ) == 0 ) ) { pxFound[ rMATCH_IP_ADDR ] = pxEndPoint; xCount[ rMATCH_IP_ADDR ]++; } else if( xTargetGlobal == xEndpointGlobal ) { pxFound[ rMATCH_IPv6_TYPE ] = pxEndPoint; xCount[ rMATCH_IPv6_TYPE ]++; } else { /* do nothing, coverity happy */ } } else { /* do nothing, coverity happy */ } } break; #endif /* ( ipconfigUSE_IPv6 != 0 ) */ case ( BaseType_t ) pdFALSE: default: #if ( ipconfigUSE_IPv4 != 0 ) if( pxEndPoint->ipv4_settings.ulIPAddress == pxIPAddressTo->ulIP_IPv4 ) { pxFound[ rMATCH_IP_ADDR ] = pxEndPoint; xCount[ rMATCH_IP_ADDR ]++; } else { /* do nothing, coverity happy */ } #endif /* ( ipconfigUSE_IPv4 != 0 ) */ break; } if( xSameMACAddress == pdTRUE ) { xCount[ rMATCH_MAC_ADDR ]++; pxFound[ rMATCH_MAC_ADDR ] = pxEndPoint; } } } for( xIndex = 0; xIndex < rMATCH_COUNT; xIndex++ ) { if( xCount[ xIndex ] >= 1 ) { pxReturn = pxFound[ xIndex ]; break; } } #if ( ipconfigHAS_PRINTF != 0 ) if( pxReturn == NULL ) { char pcBufferFrom[ 40 ]; char pcBufferTo[ 40 ]; BaseType_t xFamily = ( usFrameType == ipIPv6_FRAME_TYPE ) ? FREERTOS_AF_INET6 : FREERTOS_AF_INET4; const char * xRetNtopTo; const char * xRetNtopFrom; xRetNtopTo = FreeRTOS_inet_ntop( xFamily, ( void * ) pxIPAddressTo->xIP_IPv6.ucBytes, pcBufferTo, sizeof( pcBufferTo ) ); xRetNtopFrom = FreeRTOS_inet_ntop( xFamily, ( void * ) pxIPAddressFrom->xIP_IPv6.ucBytes, pcBufferFrom, sizeof( pcBufferFrom ) ); FreeRTOS_debug_printf( ( "EasyFit[%x]: %d %d %d ( %s ->%s ) BAD\n", usFrameType, ( unsigned ) xCount[ 0 ], ( unsigned ) xCount[ 1 ], ( unsigned ) xCount[ 2 ], ( xRetNtopFrom == NULL ) ? "INVALID" : pcBufferFrom, ( xRetNtopTo == NULL ) ? "INVALID" : pcBufferTo ) ); } #endif /* ( ipconfigHAS_PRINTF != 0 ) */ return pxReturn; } /** * @brief Find out the best matching end-point given an incoming Ethernet packet. * * @param[in] pxNetworkInterface The interface on which the packet was received. * @param[in] pucEthernetBuffer The Ethernet packet that was just received. * * @return The end-point that should handle the incoming Ethernet packet. */ NetworkEndPoint_t * FreeRTOS_MatchingEndpoint( const NetworkInterface_t * pxNetworkInterface, const uint8_t * pucEthernetBuffer ) { NetworkEndPoint_t * pxEndPoint = NULL; /* MISRA Ref 11.3.1 [Misaligned access] */ /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */ /* coverity[misra_c_2012_rule_11_3_violation] */ const ProtocolPacket_t * pxPacket = ( ( const ProtocolPacket_t * ) pucEthernetBuffer ); #if ( ipconfigUSE_IPv6 != 0 ) /* MISRA Ref 11.3.1 [Misaligned access] */ /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */ /* coverity[misra_c_2012_rule_11_3_violation] */ const IPPacket_IPv6_t * pxIPPacket_IPv6 = ( ( const IPPacket_IPv6_t * ) pucEthernetBuffer ); #endif /* ( ipconfigUSE_IPv6 != 0 ) */ configASSERT( pucEthernetBuffer != NULL ); /* Check if 'pucEthernetBuffer()' has the expected alignment, * which is 32-bits + 2. */ #ifndef _lint { /* MISRA Ref 11.4.3 [Casting pointer to int for verification] */ /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-114 */ /* coverity[misra_c_2012_rule_11_4_violation] */ uintptr_t uxAddress = ( uintptr_t ) pucEthernetBuffer; uxAddress += 2U; configASSERT( ( uxAddress % 4U ) == 0U ); /* And in case configASSERT is not defined. */ ( void ) uxAddress; } #endif /* ifndef _lint */ /* An Ethernet packet has been received. Inspect the contents to see which * defined end-point has the best match. */ #if ( ipconfigHAS_ROUTING_STATISTICS == 1 ) { /* Some stats while developing. */ xRoutingStatistics.ulMatching++; } #endif { uint16_t usFrameType = pxPacket->xUDPPacket.xEthernetHeader.usFrameType; IP_Address_t xIPAddressFrom; IP_Address_t xIPAddressTo; MACAddress_t xMACAddress; BaseType_t xDoProcessPacket = pdFALSE; ( void ) memset( xIPAddressFrom.xIP_IPv6.ucBytes, 0, ipSIZE_OF_IPv6_ADDRESS ); ( void ) memset( xIPAddressTo.xIP_IPv6.ucBytes, 0, ipSIZE_OF_IPv6_ADDRESS ); switch( usFrameType ) { case ipIPv6_FRAME_TYPE: /* Handle IPv6 frame types if ipconfigUSE_IPv6 != 0 */ #if ( ipconfigUSE_IPv6 != 0 ) ( void ) memcpy( xIPAddressFrom.xIP_IPv6.ucBytes, pxIPPacket_IPv6->xIPHeader.xSourceAddress.ucBytes, ipSIZE_OF_IPv6_ADDRESS ); ( void ) memcpy( xIPAddressTo.xIP_IPv6.ucBytes, pxIPPacket_IPv6->xIPHeader.xDestinationAddress.ucBytes, ipSIZE_OF_IPv6_ADDRESS ); xDoProcessPacket = pdTRUE; #endif /* ( ipconfigUSE_IPv6 != 0 ) */ break; case ipARP_FRAME_TYPE: /* Handle ARP frame types if ipconfigUSE_IPv4 != 0 */ #if ( ipconfigUSE_IPv4 != 0 ) { /* MISRA Ref 11.3.1 [Misaligned access] */ /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */ /* coverity[misra_c_2012_rule_11_3_violation] */ const ARPPacket_t * pxARPFrame = ( const ARPPacket_t * ) pucEthernetBuffer; if( pxARPFrame->xARPHeader.usOperation == ( uint16_t ) ipARP_REQUEST ) { ( void ) memcpy( xIPAddressFrom.xIP_IPv6.ucBytes, pxPacket->xARPPacket.xARPHeader.ucSenderProtocolAddress, sizeof( uint32_t ) ); xIPAddressTo.ulIP_IPv4 = pxPacket->xARPPacket.xARPHeader.ulTargetProtocolAddress; } else if( pxARPFrame->xARPHeader.usOperation == ( uint16_t ) ipARP_REPLY ) { ( void ) memcpy( xIPAddressTo.xIP_IPv6.ucBytes, pxPacket->xARPPacket.xARPHeader.ucSenderProtocolAddress, sizeof( uint32_t ) ); xIPAddressFrom.ulIP_IPv4 = pxPacket->xARPPacket.xARPHeader.ulTargetProtocolAddress; } else { /* do nothing, coverity happy */ } FreeRTOS_debug_printf( ( "pxEasyFit: ARP %xip -> %xip\n", ( unsigned ) FreeRTOS_ntohl( xIPAddressFrom.ulIP_IPv4 ), ( unsigned ) FreeRTOS_ntohl( xIPAddressTo.ulIP_IPv4 ) ) ); } xDoProcessPacket = pdTRUE; #endif /* ( ipconfigUSE_IPv4 != 0 ) */ break; case ipIPv4_FRAME_TYPE: /* Handle IPv4 frame types if ipconfigUSE_IPv4 != 0 */ #if ( ipconfigUSE_IPv4 != 0 ) xIPAddressFrom.ulIP_IPv4 = pxPacket->xUDPPacket.xIPHeader.ulSourceIPAddress; xIPAddressTo.ulIP_IPv4 = pxPacket->xUDPPacket.xIPHeader.ulDestinationIPAddress; xDoProcessPacket = pdTRUE; #endif /* ( ipconfigUSE_IPv4 != 0 ) */ break; default: #if ( ipconfigPROCESS_CUSTOM_ETHERNET_FRAMES == 1 ) /* Custom frame types, match by MAC address only. */ xDoProcessPacket = pdTRUE; #endif break; } if( xDoProcessPacket == pdTRUE ) { ( void ) memcpy( xMACAddress.ucBytes, pxPacket->xUDPPacket.xEthernetHeader.xDestinationAddress.ucBytes, ipMAC_ADDRESS_LENGTH_BYTES ); pxEndPoint = pxEasyFit( pxNetworkInterface, usFrameType, &xIPAddressFrom, &xIPAddressTo, &xMACAddress ); } } return pxEndPoint; } /*-----------------------------------------------------------*/ /** * @brief Find an end-point that defines a gateway of a certain type ( IPv4 or IPv6 ). * * @param[in] xIPType The type of Gateway to look for ( ipTYPE_IPv4 or ipTYPE_IPv6 ). * * @return The end-point that will lead to the gateway, or NULL when no gateway was found. */ NetworkEndPoint_t * FreeRTOS_FindGateWay( BaseType_t xIPType ) { NetworkEndPoint_t * pxEndPoint = pxNetworkEndPoints; while( pxEndPoint != NULL ) { #if ( ipconfigUSE_IPv6 == 0 ) ( void ) xIPType; if( pxEndPoint->ipv4_settings.ulGatewayAddress != 0U ) /* access to ipv4_settings is checked. */ { break; } #else if( ( xIPType == ( BaseType_t ) ipTYPE_IPv6 ) && ( pxEndPoint->bits.bIPv6 != pdFALSE_UNSIGNED ) ) { /* Check if the IP-address is non-zero. */ if( memcmp( FreeRTOS_in6addr_any.ucBytes, pxEndPoint->ipv6_settings.xGatewayAddress.ucBytes, ipSIZE_OF_IPv6_ADDRESS ) != 0 ) { break; } } else if( ( xIPType == ( BaseType_t ) ipTYPE_IPv4 ) && ( pxEndPoint->bits.bIPv6 == pdFALSE_UNSIGNED ) ) { if( pxEndPoint->ipv4_settings.ulGatewayAddress != 0U ) { break; } } else { /* This end-point is not the right IP-type. */ } #endif /* ( ipconfigUSE_IPv6 != 0 ) */ pxEndPoint = pxEndPoint->pxNext; } return pxEndPoint; } /*-----------------------------------------------------------*/ #if ( ipconfigUSE_IPv6 != 0 ) /* Get the first end-point belonging to a given interface. * When pxInterface is NULL, the very first end-point will be returned. */ /** * @brief Find the first IPv6 end-point. * * @param[in] pxInterface Either NULL ( don't care ), or a specific interface. * * @return The end-point found, or NULL when there are no end-points at all. */ NetworkEndPoint_t * FreeRTOS_FirstEndPoint_IPv6( const NetworkInterface_t * pxInterface ) { NetworkEndPoint_t * pxEndPoint = pxNetworkEndPoints; while( pxEndPoint != NULL ) { if( ( ( pxInterface == NULL ) || ( pxEndPoint->pxNetworkInterface == pxInterface ) ) && ( pxEndPoint->bits.bIPv6 != pdFALSE_UNSIGNED ) ) { break; } pxEndPoint = pxEndPoint->pxNext; } return pxEndPoint; } #endif /* ipconfigUSE_IPv6 */ /*-----------------------------------------------------------*/ /** * @brief Get the end-point that is bound to a socket. * * @param[in] xSocket The socket of interest. * * @return An end-point or NULL in case the socket is not bound to an end-point. */ NetworkEndPoint_t * pxGetSocketEndpoint( ConstSocket_t xSocket ) { const FreeRTOS_Socket_t * pxSocket = ( const FreeRTOS_Socket_t * ) xSocket; NetworkEndPoint_t * pxResult; if( pxSocket != NULL ) { pxResult = pxSocket->pxEndPoint; } else { pxResult = NULL; } return pxResult; } /*-----------------------------------------------------------*/ /** * @brief Assign an end-point to a socket. * * @param[in] xSocket The socket to which an end-point will be assigned. * @param[in] pxEndPoint The end-point to be assigned. */ void vSetSocketEndpoint( Socket_t xSocket, NetworkEndPoint_t * pxEndPoint ) { FreeRTOS_Socket_t * pxSocket = ( FreeRTOS_Socket_t * ) xSocket; if( pxSocket != NULL ) { pxSocket->pxEndPoint = pxEndPoint; } } /*-----------------------------------------------------------*/ #else /* ( ipconfigCOMPATIBLE_WITH_SINGLE == 0 ) */ /* Here below the most important function of FreeRTOS_Routing.c in a short * version: it is assumed that only 1 interface and 1 end-point will be created. * The reason for this is downward compatibility with the earlier release of * FreeRTOS+TCP, which had a single network interface only. */ /** * @brief Add a network interface to the list of interfaces. Check if this will be * first and only interface ( ipconfigCOMPATIBLE_WITH_SINGLE = 1 ). * * @param[in] pxInterface The address of the new interface. * * @return The value of the parameter 'pxInterface'. */ NetworkInterface_t * FreeRTOS_AddNetworkInterface( NetworkInterface_t * pxInterface ) { configASSERT( pxNetworkInterfaces == NULL ); pxNetworkInterfaces = pxInterface; return pxInterface; } /*-----------------------------------------------------------*/ /** * @brief And an end-point to an interface. Note that when ipconfigCOMPATIBLE_WITH_SINGLE * is defined, only one interface is allowed, which will have one end-point only. * * @param[in] pxInterface The interface to which the end-point is assigned. * @param[in] pxEndPoint The end-point to be assigned to the above interface. * * @return The value of the parameter 'pxEndPoint'. */ static NetworkEndPoint_t * FreeRTOS_AddEndPoint( NetworkInterface_t * pxInterface, NetworkEndPoint_t * pxEndPoint ) { /* This code is in backward-compatibility mode. * Only one end-point is allowed, make sure that * no end-point has been defined yet. */ configASSERT( pxNetworkEndPoints == NULL ); /* This end point will go to the end of the list, so there is no pxNext * yet. */ pxEndPoint->pxNext = NULL; /* Double link between the NetworkInterface_t that is using the addressing * defined by this NetworkEndPoint_t structure. */ pxEndPoint->pxNetworkInterface = pxInterface; pxInterface->pxEndPoint = pxEndPoint; /* No other end points are defined yet - so this is the first in the * list. */ pxNetworkEndPoints = pxEndPoint; return pxEndPoint; } /*-----------------------------------------------------------*/ /** * @brief Find the end-point which has a given IPv4 address. * * @param[in] ulIPAddress The IP-address of interest, or 0 if any IPv4 end-point may be returned. * * @return The end-point found or NULL. */ NetworkEndPoint_t * FreeRTOS_FindEndPointOnIP_IPv4( uint32_t ulIPAddress, uint32_t ulWhere ) { NetworkEndPoint_t * pxResult = NULL; ( void ) ulIPAddress; ( void ) ulWhere; if( ( ulIPAddress == 0U ) || ( pxNetworkEndPoints->ipv4_settings.ulIPAddress == ulIPAddress ) ) { pxResult = pxNetworkEndPoints; } return pxResult; } /*-----------------------------------------------------------*/ /** * @brief Find the end-point that has a certain MAC-address. * * @param[in] pxMACAddress The Ethernet packet. * @param[in] pxInterface The interface on which the packet was received, or NULL when unknown. * * @return The end-point that has the given MAC-address. */ NetworkEndPoint_t * FreeRTOS_FindEndPointOnMAC( const MACAddress_t * pxMACAddress, const NetworkInterface_t * pxInterface ) { NetworkEndPoint_t * pxResult = NULL; ( void ) pxMACAddress; ( void ) pxInterface; if( ( pxMACAddress != NULL ) && ( memcmp( pxNetworkEndPoints->xMACAddress.ucBytes, pxMACAddress->ucBytes, ipMAC_ADDRESS_LENGTH_BYTES ) == 0 ) ) { pxResult = pxNetworkEndPoints; } return pxResult; } /*-----------------------------------------------------------*/ /** * @brief Find an end-point that handles a given IPv4-address. * * @param[in] ulIPAddress The IP-address for which an end-point is looked-up. * * @return An end-point that has the same network mask as the given IP-address. */ NetworkEndPoint_t * FreeRTOS_FindEndPointOnNetMask( uint32_t ulIPAddress, uint32_t ulWhere ) { return FreeRTOS_InterfaceEndPointOnNetMask( NULL, ulIPAddress, ulWhere ); } /*-----------------------------------------------------------*/ /** * @brief Find an end-point that defines a gateway of a certain type ( IPv4 or IPv6 ). * * @param[in] xIPType The type of Gateway to look for ( ipTYPE_IPv4 or ipTYPE_IPv6 ). * * @return The end-point that will lead to the gateway, or NULL when no gateway was found. */ NetworkEndPoint_t * FreeRTOS_FindGateWay( BaseType_t xIPType ) { NetworkEndPoint_t * pxReturn = NULL; ( void ) xIPType; if( pxNetworkEndPoints != NULL ) { if( pxNetworkEndPoints->ipv4_settings.ulGatewayAddress != 0U ) { pxReturn = pxNetworkEndPoints; } } return pxReturn; } /*-----------------------------------------------------------*/ /** * @brief Find the first end-point bound to a given interface. * * @param[in] pxInterface The interface whose first end-point will be returned. * * @return The first end-point that is found to the interface, or NULL when the * interface doesn't have any end-point yet. */ NetworkEndPoint_t * FreeRTOS_FirstEndPoint( const NetworkInterface_t * pxInterface ) { ( void ) pxInterface; /* ipconfigCOMPATIBLE_WITH_SINGLE is defined and this is the simplified version: * only one interface and one end-point is defined. */ return pxNetworkEndPoints; } /*-----------------------------------------------------------*/ /** * @brief Get the first Network Interface, or NULL if none has been added. * * @return The first interface, or NULL if none has been added */ NetworkInterface_t * FreeRTOS_FirstNetworkInterface( void ) { /* ipconfigCOMPATIBLE_WITH_SINGLE is defined: only one interface and * one end-point is defined. */ return pxNetworkInterfaces; } /*-----------------------------------------------------------*/ /** * @brief Find an end-point that handles a given IPv4-address. * * @param[in] pxInterface Ignored in this simplified version. * @param[in] ulIPAddress The IP-address for which an end-point is looked-up. * * @return An end-point that has the same network mask as the given IP-address. */ NetworkEndPoint_t * FreeRTOS_InterfaceEndPointOnNetMask( const NetworkInterface_t * pxInterface, uint32_t ulIPAddress, uint32_t ulWhere ) { NetworkEndPoint_t * pxResult = NULL; ( void ) pxInterface; ( void ) ulWhere; if( ( ( ulIPAddress ^ pxNetworkEndPoints->ipv4_settings.ulIPAddress ) & pxNetworkEndPoints->ipv4_settings.ulNetMask ) == 0U ) { pxResult = pxNetworkEndPoints; } return pxResult; } /*-----------------------------------------------------------*/ /** * @brief Find out the best matching end-point given an incoming Ethernet packet. * * @param[in] pxNetworkInterface The interface on which the packet was received. * @param[in] pucEthernetBuffer The Ethernet packet that was just received. * * @return The end-point that should handle the incoming Ethernet packet. */ NetworkEndPoint_t * FreeRTOS_MatchingEndpoint( const NetworkInterface_t * pxNetworkInterface, const uint8_t * pucEthernetBuffer ) { ( void ) pxNetworkInterface; ( void ) pucEthernetBuffer; /* ipconfigCOMPATIBLE_WITH_SINGLE is defined: only one interface and * one end-point is defined. */ return pxNetworkEndPoints; } /*-----------------------------------------------------------*/ /** * @brief Get the next end-point. As this is the simplified version, it will always * return NULL. * * @param[in] pxInterface An interface of interest, or NULL when iterating through all * end-points. * @param[in] pxEndPoint This is the current end-point. * * @return NULL because ipconfigCOMPATIBLE_WITH_SINGLE is defined. */ NetworkEndPoint_t * FreeRTOS_NextEndPoint( const NetworkInterface_t * pxInterface, NetworkEndPoint_t * pxEndPoint ) { ( void ) pxInterface; ( void ) pxEndPoint; return NULL; } /*-----------------------------------------------------------*/ /** * @brief Get the next interface. * * @return NULL because ipconfigCOMPATIBLE_WITH_SINGLE is defined. */ NetworkInterface_t * FreeRTOS_NextNetworkInterface( const NetworkInterface_t * pxInterface ) { ( void ) pxInterface; return NULL; } /*-----------------------------------------------------------*/ #if ( ipconfigUSE_IPv6 != 0 ) NetworkEndPoint_t * FreeRTOS_FindEndPointOnIP_IPv6( const IPv6_Address_t * pxIPAddress ) { ( void ) pxIPAddress; return pxNetworkEndPoints; } #endif /*-----------------------------------------------------------*/ #if ( ipconfigUSE_IPv6 != 0 ) NetworkEndPoint_t * FreeRTOS_FindEndPointOnNetMask_IPv6( const IPv6_Address_t * pxIPv6Address ) { ( void ) pxIPv6Address; return pxNetworkEndPoints; } #endif /*-----------------------------------------------------------*/ #if ( ipconfigUSE_IPv6 != 0 ) NetworkEndPoint_t * FreeRTOS_FirstEndPoint_IPv6( const NetworkInterface_t * pxInterface ) { ( void ) pxInterface; return pxNetworkEndPoints; } #endif /*-----------------------------------------------------------*/ #endif /* ( ipconfigCOMPATIBLE_WITH_SINGLE == 0 ) */ /** * @brief Returns the IP type of the given IPv6 address. * * @param[in] pxAddress The IPv6 address whose type needs to be returned. * @returns The IP type of the given address. */ IPv6_Type_t xIPv6_GetIPType( const IPv6_Address_t * pxAddress ) { IPv6_Type_t eResult = eIPv6_Unknown; BaseType_t xIndex; static const struct xIPv6_Couple xIPCouples[] = { /* IP-type Mask Value */ { eIPv6_Global, 0xE000U, 0x2000U }, /* 001 */ { eIPv6_LinkLocal, 0xFFC0U, 0xFE80U }, /* 1111 1110 10 */ { eIPv6_SiteLocal, 0xFFC0U, 0xFEC0U }, /* 1111 1110 11 */ { eIPv6_Multicast, 0xFF00U, 0xFF00U }, /* 1111 1111 */ }; if( pxAddress != NULL ) { for( xIndex = 0; xIndex < ARRAY_SIZE_X( xIPCouples ); xIndex++ ) { uint16_t usAddress = ( uint16_t ) ( ( ( ( uint16_t ) pxAddress->ucBytes[ 0 ] ) << 8 ) | ( ( uint16_t ) pxAddress->ucBytes[ 1 ] ) ); if( ( usAddress & xIPCouples[ xIndex ].usMask ) == xIPCouples[ xIndex ].usExpected ) { eResult = xIPCouples[ xIndex ].eType; break; } } } return eResult; } /*-----------------------------------------------------------*/ /** * @brief Returns the string representation of the IP address of the end point. * * @param[in] pxEndPoint End point for which IP address needs to be returned. * @param[in] pcBuffer A char buffer of required size to which the string will be written. * @param[in] uxSize Size of the char buffer - pcBuffer. * * @returns The pointer to the char buffer that contains the string representation of the end point IP address. * The string will be "NULL" if the end point pointer is NULL. */ const char * pcEndpointName( const NetworkEndPoint_t * pxEndPoint, char * pcBuffer, size_t uxSize ) { if( pxEndPoint == NULL ) { /* MISRA Ref 21.6.1 [snprintf and logging] */ /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-216 */ /* coverity[misra_c_2012_rule_21_6_violation] */ ( void ) snprintf( pcBuffer, uxSize, "NULL" ); } else { switch( pxEndPoint->bits.bIPv6 ) /* LCOV_EXCL_BR_LINE */ { #if ( ipconfigUSE_IPv4 != 0 ) case pdFALSE_UNSIGNED: ( void ) FreeRTOS_inet_ntop( FREERTOS_AF_INET4, ( const void * ) &( pxEndPoint->ipv4_settings.ulIPAddress ), pcBuffer, ( socklen_t ) uxSize ); break; #endif /* ( ipconfigUSE_IPv4 != 0 ) */ #if ( ipconfigUSE_IPv6 != 0 ) case pdTRUE_UNSIGNED: ( void ) FreeRTOS_inet_ntop( FREERTOS_AF_INET6, pxEndPoint->ipv6_settings.xIPAddress.ucBytes, pcBuffer, ( socklen_t ) uxSize ); break; #endif /* ( ipconfigUSE_IPv6 != 0 ) */ default: /* MISRA 16.4 Compliance */ /* MISRA Ref 21.6.1 [snprintf and logging] */ /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-216 */ /* coverity[misra_c_2012_rule_21_6_violation] */ ( void ) snprintf( pcBuffer, uxSize, "NULL" ); break; } } return pcBuffer; } /*-----------------------------------------------------------*/