Skip to content

Commit

Permalink
Adds NetIf functions for filtering MAC addresses (#1065)
Browse files Browse the repository at this point in the history
* Adds ipconfigMAC_FILTERING that when enabled, adds two MAC manipulation functions to NetworkInterface_t
Adds documentation and design notes for the MAC filtering functions of the SAME70 network driver.
Exposes pcLOCAL_ALL_NODES_MULTICAST_MAC[ ipMAC_ADDRESS_LENGTH_BYTES ] so that network drivers can add it to the received multicast addresses during initialization.
Adds functions to the SAME70 network driver that allow modification of what MAC addresses are being received by the hardware. This implementation utilizes the 4 specific match registers and the 64bit hash match register that are present in the SAME70/V71 microcontrollers.
Registes the mDNS address when the SAME70 network driver is initialized.
Moves the registering of the solicited-node multicast address from the network driver to vIPNetworkUpCalls()
Adds 'U'  to some uint8_t[] initializers

* Removes ipconfigMAC_FILTERING
Rewrites the comment describing the MAC filtering functions.

* Adds checks for ipconfigUSE_IPv6
Fixes a copy/paste bug that was allowing pfRemoveAllowedMAC() to be called without being checked for non-NULL

* Updates the unit tests for better coverage. Thanks @htibosch

* Converts the indexing variables to `size_t xIndex` and avoids inline for() declarations in DriverSAM/NetworkInterface.c
Consolidates the solicited-node MAC and MLD management into a single function.
Calls the new solicited-node address management function on network UP/DOWN events.

* Update some comments
Rewrites the generation of the solicited-node multicast IPv6 address. Thanks @htibosch
Sprits the allocation and NULL check when allocating an MLD report. Thanks @AniruddhaKanhere

* Moves vManageSolicitedNodeAddress() from FreeRTOS_IP_Utils.c to FreeRTOS_IPv6_Utils.c
Changes some indexing variables prefix to "ux"

* Adds a macros for easy checking if a MAC address is unicast or multicast.
Improves the readability of the SAME70 hash register code by adding a bunch of macros and defines
Moves all hash register macros anad variables to the top of NetworkInterface.c where they belong.

* Adds xNetworkInterface * parameters to the MAC filtering functions as requested by @HTRamsey

* Updates the DriverSAM network inteface to include the new MAC filter function parameters.

* more renaming

* Adds overflow check when incrementing the specific match register counters. Thanks @HTRamsey

* Adds proper casting when converting byte arrays to uint32_t registers. Thanks @htibosch.

* Exposes pcLOCAL_ALL_NODES_MULTICAST_IP so that it can be re-used by the user

* Fixes an array initializer that was not constant at compile time.
Removes code that was not supposed to be in this PR

* Uncrustify: triggered by comment.

* Fix unit tests

* Fix formatting

---------

Co-authored-by: Emil Popov <[email protected]>
Co-authored-by: Tony Josi <[email protected]>
Co-authored-by: Aniruddha Kanhere <[email protected]>
Co-authored-by: GitHub Action <[email protected]>
  • Loading branch information
5 people authored Apr 8, 2024
1 parent 7b68a91 commit aa7f9f0
Show file tree
Hide file tree
Showing 17 changed files with 1,064 additions and 50 deletions.
8 changes: 8 additions & 0 deletions source/FreeRTOS_IP.c
Original file line number Diff line number Diff line change
Expand Up @@ -624,6 +624,14 @@ TaskHandle_t FreeRTOS_GetIPTaskHandle( void )
*/
void vIPNetworkUpCalls( struct xNetworkEndPoint * pxEndPoint )
{
if( pxEndPoint->bits.bIPv6 == pdTRUE_UNSIGNED )
{
/* IPv6 end-points have a solicited-node address that needs extra housekeeping. */
#if ( ipconfigIS_ENABLED( ipconfigUSE_IPv6 ) )
vManageSolicitedNodeAddress( pxEndPoint, pdTRUE );
#endif
}

pxEndPoint->bits.bEndPointUp = pdTRUE_UNSIGNED;

#if ( ipconfigUSE_NETWORK_EVENT_HOOK == 1 )
Expand Down
9 changes: 9 additions & 0 deletions source/FreeRTOS_IP_Utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -835,6 +835,15 @@ void prvProcessNetworkDownEvent( struct xNetworkInterface * pxInterface )
{
/* The bit 'bEndPointUp' stays low until vIPNetworkUpCalls() is called. */
pxEndPoint->bits.bEndPointUp = pdFALSE_UNSIGNED;

if( pxEndPoint->bits.bIPv6 == pdTRUE_UNSIGNED )
{
/* IPv6 end-points have a solicited-node address that needs extra housekeeping. */
#if ( ipconfigIS_ENABLED( ipconfigUSE_IPv6 ) )
vManageSolicitedNodeAddress( pxEndPoint, pdFALSE );
#endif
}

#if ( ipconfigUSE_NETWORK_EVENT_HOOK == 1 )
{
if( pxEndPoint->bits.bCallDownHook != pdFALSE_UNSIGNED )
Expand Down
67 changes: 67 additions & 0 deletions source/FreeRTOS_IPv6_Utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,73 @@ size_t usGetExtensionHeaderLength( const uint8_t * pucEthernetBuffer,
}
/*-----------------------------------------------------------*/

/**
* @brief Every IPv6 end-point has a solicited node multicast address and a corresponding
* multicast MAC address. The IPv6 solicited node address also has an MLD reports associated
* with it. This function manages both the MAC address and the MLD report associated with
* the end-point's solicited-node address. On network UP, this function registers the MAC address
* with the network driver's filter and creates and MLD report for the UPv6 multicast address.
* On network DOWN, the function unregisters the MAC address and removes the MLD report.
* This is a "convenience" function that keeps all these tasks under one roof for easier maintenance.
*
* @param[in] pxEndPoint The end-point for which a network up/down event is being handled.
* @param[in] xNetworkGoingUp pdTRUE when the network goes UP, pdFALSE when the network goes DOWN.
*/
void vManageSolicitedNodeAddress( const struct xNetworkEndPoint * pxEndPoint,
BaseType_t xNetworkGoingUp )
{
IPv6_Type_t xAddressType;
MACAddress_t xMACAddress;

configASSERT( pxEndPoint != NULL );
configASSERT( pxEndPoint->pxNetworkInterface != NULL );

/* do{}while(0) to allow for the use of break statements */
do
{
/* During the very first network DOWN event, pxEndPoint->ipv6_settings does not yet hold the proper address and
* therefore the calculated MAC address will be incorrect. Nothing bad will happen though, because the address
* type check below will kick us out before the call to pfRemoveAllowedMAC(). Without the check below, the network
* driver ends up being called once to register 33:33:FF:00:00:00 and that MAC never gets unregistered. */

/* Solicited-node multicast addresses only apply to normal unicast non-loopback addresses. */
xAddressType = xIPv6_GetIPType( &( pxEndPoint->ipv6_settings.xIPAddress ) );

if( ( xAddressType != eIPv6_LinkLocal ) && ( xAddressType != eIPv6_SiteLocal ) && ( xAddressType != eIPv6_Global ) )
{
/* The address of this end-point is something other than a normal unicast address... Maybe it's the
* loopback address or maybe this is an error scenario. In any case, there is no corresponding
* solicited-node multicast address that we need to manage. Do nothing.*/
break;
}

/* Calculate the multicast MAC that corresponds to this endpoint's IPv6 address. */
xMACAddress.ucBytes[ 0 ] = ipMULTICAST_MAC_ADDRESS_IPv6_0;
xMACAddress.ucBytes[ 1 ] = ipMULTICAST_MAC_ADDRESS_IPv6_0;
xMACAddress.ucBytes[ 2 ] = 0xFFU;
xMACAddress.ucBytes[ 3 ] = pxEndPoint->ipv6_settings.xIPAddress.ucBytes[ 13 ];
xMACAddress.ucBytes[ 4 ] = pxEndPoint->ipv6_settings.xIPAddress.ucBytes[ 14 ];
xMACAddress.ucBytes[ 5 ] = pxEndPoint->ipv6_settings.xIPAddress.ucBytes[ 15 ];

/* Update the network driver filter */
if( xNetworkGoingUp == pdTRUE )
{
if( pxEndPoint->pxNetworkInterface->pfAddAllowedMAC != NULL )
{
pxEndPoint->pxNetworkInterface->pfAddAllowedMAC( pxEndPoint->pxNetworkInterface, xMACAddress.ucBytes );
}
}
else
{
if( pxEndPoint->pxNetworkInterface->pfRemoveAllowedMAC != NULL )
{
pxEndPoint->pxNetworkInterface->pfRemoveAllowedMAC( pxEndPoint->pxNetworkInterface, xMACAddress.ucBytes );
}
}
} while( pdFALSE );
}
/*-----------------------------------------------------------*/

/* *INDENT-OFF* */
#endif /* ( ipconfigUSE_IPv6 != 0 ) */
/* *INDENT-ON* */
7 changes: 2 additions & 5 deletions source/FreeRTOS_ND.c
Original file line number Diff line number Diff line change
Expand Up @@ -74,12 +74,9 @@
#define ndMAX_CACHE_AGE_BEFORE_NEW_ND_SOLICITATION ( 3U )

/** @brief All nodes on the local network segment: IP address. */
/* MISRA Ref 8.9.1 [File scoped variables] */
/* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-89 */
/* coverity[misra_c_2012_rule_8_9_violation] */
static const uint8_t pcLOCAL_ALL_NODES_MULTICAST_IP[ ipSIZE_OF_IPv6_ADDRESS ] = { 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }; /* ff02:1 */
const uint8_t pcLOCAL_ALL_NODES_MULTICAST_IP[ ipSIZE_OF_IPv6_ADDRESS ] = { 0xffU, 0x02U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x01U }; /* ff02::1 */
/** @brief All nodes on the local network segment: MAC address. */
static const uint8_t pcLOCAL_ALL_NODES_MULTICAST_MAC[ ipMAC_ADDRESS_LENGTH_BYTES ] = { 0x33, 0x33, 0x00, 0x00, 0x00, 0x01 };
const uint8_t pcLOCAL_ALL_NODES_MULTICAST_MAC[ ipMAC_ADDRESS_LENGTH_BYTES ] = { 0x33U, 0x33U, 0x00U, 0x00U, 0x00U, 0x01U };

/** @brief See if the MAC-address can be resolved because it is a multi-cast address. */
static eARPLookupResult_t prvMACResolve( const IPv6_Address_t * pxAddressToLookup,
Expand Down
1 change: 1 addition & 0 deletions source/include/FreeRTOS_IP_Utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ void vPreCheckConfigs( void );
*/
void prvProcessNetworkDownEvent( struct xNetworkInterface * pxInterface );


/* *INDENT-OFF* */
#ifdef __cplusplus
} /* extern "C" */
Expand Down
3 changes: 3 additions & 0 deletions source/include/FreeRTOS_IPv6_Utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@ size_t usGetExtensionHeaderLength( const uint8_t * pucEthernetBuffer,
size_t uxBufferLength,
uint8_t * pucProtocol );

void vManageSolicitedNodeAddress( const struct xNetworkEndPoint * pxEndPoint,
BaseType_t xNetworkGoingUp );

/* *INDENT-OFF* */
#ifdef __cplusplus
} /* extern "C" */
Expand Down
2 changes: 2 additions & 0 deletions source/include/FreeRTOS_ND.h
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,8 @@
void FreeRTOS_PrintNDCache( void );
#endif

extern const uint8_t pcLOCAL_ALL_NODES_MULTICAST_IP[ ipSIZE_OF_IPv6_ADDRESS ];
extern const uint8_t pcLOCAL_ALL_NODES_MULTICAST_MAC[ ipMAC_ADDRESS_LENGTH_BYTES ];
#endif /* ipconfigUSE_IPv6 != 0 */


Expand Down
40 changes: 40 additions & 0 deletions source/include/FreeRTOS_Routing.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@
/* Return true as long as the LinkStatus on the PHY is present. */
typedef BaseType_t ( * GetPhyLinkStatusFunction_t ) ( struct xNetworkInterface * pxDescriptor );

/* Functions that manipulate what MAC addresses are received by this interface */
typedef void ( * NetworkInterfaceMACFilterFunction_t ) ( struct xNetworkInterface * pxInterface,
const uint8_t * pucMacAddressBytes );

/** @brief These NetworkInterface access functions are collected in a struct: */
typedef struct xNetworkInterface
{
Expand All @@ -63,6 +67,42 @@
NetworkInterfaceInitialiseFunction_t pfInitialise; /**< This function will be called upon initialisation and repeated until it returns pdPASS. */
NetworkInterfaceOutputFunction_t pfOutput; /**< This function is supposed to send out a packet. */
GetPhyLinkStatusFunction_t pfGetPhyLinkStatus; /**< This function will return pdTRUE as long as the PHY Link Status is high. */

/*
* pfAddAllowedMAC and pfRemoveAllowedMAC form the network driver's address filtering API.
* The network stack uses these functions to alter which MAC addresses will be received.
* The MAC addresses passed to the functions can be unicast or multicast. It is important
* to note that the stack may call these functions multiple times for the the same MAC address.
* For example, if two sockets subscribe to the same multicast group, pfAddAllowedMAC()
* will be called twice with the same MAC address. The network driver is responsible for
* keeping track of these calls. The network driver should continue receiving that
* particular MAC address until pfRemoveAllowedMAC() is called the same number of times.
*
* Most EMAC hardware nowadays can filter frames based on both specific MAC address matching
* and hash matching. Specific address matching is ideal because as the name suggests,
* only frames with the exact MAC address are received. Usually however, the number of
* specific MAC addresses is limited ( to 4 in many cases ) and is sometimes not enough for
* all the MAC addresses that the network stack needs to receive.
* Hash matching is usually based around a 64-bit hash table. For every incoming frame,
* the EMAC calculates a hash value (mod 64) of the destination MAC address.
* The hash value is looked up in the 64-bit hash table and if that bit is set, the frame is
* received. If the bit is clear, the frame is dropped. With hash matching, multiple
* MAC addresses are represented by a single bit. It is the responsibility of the network
* driver to manage both the hash address matching and specific address matching capabilities
* of the EMAC hardware.
* A quick and dirty implementation option is to receive all MAC addresses and set both
* pfAddAllowedMAC and pfRemoveAllowedMAC to NULL. This results in an interface running
* in promiscuous mode and the entire burden of MAC filtering falls on the network stack.
* For a more realistic implementation, check out
* "portable/NetworkInterface/DriverSAM/NetworkInterface.c" It demonstrates the use of both
* specific and hash address matching as well as keeping count of how many time the
* individual registers/bits have been used. That implementation's init functions also
* demonstrates the use of prvAddAllowedMACAddress() function to register all end-point's
* MAC addresses whether the endpoints used the same or different MAC addresses.
*/
NetworkInterfaceMACFilterFunction_t pfAddAllowedMAC;
NetworkInterfaceMACFilterFunction_t pfRemoveAllowedMAC;

struct
{
uint32_t
Expand Down
3 changes: 3 additions & 0 deletions source/include/NetworkInterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ void vNetworkInterfaceAllocateRAMToBuffers( NetworkBufferDescriptor_t pxNetworkB

BaseType_t xGetPhyLinkStatus( struct xNetworkInterface * pxInterface );

#define MAC_IS_MULTICAST( pucMACAddressBytes ) ( ( pucMACAddressBytes[ 0 ] & 1U ) != 0U )
#define MAC_IS_UNICAST( pucMACAddressBytes ) ( ( pucMACAddressBytes[ 0 ] & 1U ) == 0U )

/* *INDENT-OFF* */
#ifdef __cplusplus
} /* extern "C" */
Expand Down
Loading

0 comments on commit aa7f9f0

Please sign in to comment.