mirror of
https://github.com/apache/nuttx.git
synced 2026-06-06 16:50:55 +08:00
Squashed commit of the following:
The MLD implementation did not follow the RFC correctly when it is the Querier. The Querier should use a general query and get query messages from all members of all groups. This would be driven by a single timer per sub-nset since all groups are queried at once. Instead, the design used a Multicast Address Specific Query with one timer per group and ignores groups that we are not members of.
Similary, the MLDv1 compatibility timer should be a single, separate timer, not a per-group timer.
net/mld: Group may be NULL when sending a general query
This commit is contained in:
+46
-19
@@ -123,35 +123,45 @@
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/* Group flags */
|
||||
/* Global flags */
|
||||
|
||||
#define MLD_QUERIER (1 << 0) /* Querier */
|
||||
#define MLD_V1COMPAT (1 << 1) /* MLDv1 compatibility mode */
|
||||
#define MLD_GENPEND (1 << 2) /* General query pending */
|
||||
|
||||
#define SET_MLD_QUERIER(f) do { (f) |= MLD_QUERIER; } while (0)
|
||||
#define SET_MLD_V1COMPAT(f) do { (f) |= MLD_V1COMPAT; } while (0)
|
||||
#define SET_MLD_GENPEND(f) do { (f) |= MLD_GENPEND; } while (0)
|
||||
|
||||
#define CLR_MLD_QUERIER(f) do { (f) &= ~MLD_QUERIER; } while (0)
|
||||
#define CLR_MLD_V1COMPAT(f) do { (f) &= ~MLD_V1COMPAT; } while (0)
|
||||
#define CLR_MLD_GENPEND(f) do { (f) &= ~MLD_GENPEND; } while (0)
|
||||
|
||||
#define IS_MLD_QUERIER(f) (((f) & MLD_QUERIER) != 0)
|
||||
#define IS_MLD_V1COMPAT(f) (((f) & MLD_V1COMPAT) != 0)
|
||||
#define IS_MLD_GENPEND(f) (((f) & MLD_GENPEND) != 0)
|
||||
|
||||
/* Group flags */
|
||||
|
||||
#define MLD_STARTUP (1 << 1) /* Startup unsolicited Reports */
|
||||
#define MLD_V1COMPAT (1 << 2) /* Version 1 compatibility mode */
|
||||
#define MLD_LASTREPORT (1 << 3) /* We were the last to report */
|
||||
#define MLD_SCHEDMSG (1 << 4) /* Outgoing message scheduled */
|
||||
#define MLD_WAITMSG (1 << 5) /* Block until message sent */
|
||||
#define MLD_RPTPEND (1 << 6) /* Report pending */
|
||||
|
||||
#define SET_MLD_QUERIER(f) do { (f) |= MLD_QUERIER; } while (0)
|
||||
#define SET_MLD_STARTUP(f) do { (f) |= MLD_STARTUP; } while (0)
|
||||
#define SET_MLD_V1COMPAT(f) do { (f) |= MLD_V1COMPAT; } while (0)
|
||||
#define SET_MLD_LASTREPORT(f) do { (f) |= MLD_LASTREPORT; } while (0)
|
||||
#define SET_MLD_SCHEDMSG(f) do { (f) |= MLD_SCHEDMSG; } while (0)
|
||||
#define SET_MLD_WAITMSG(f) do { (f) |= MLD_WAITMSG; } while (0)
|
||||
#define SET_MLD_RPTPEND(f) do { (f) |= MLD_RPTPEND; } while (0)
|
||||
|
||||
#define CLR_MLD_QUERIER(f) do { (f) &= ~MLD_QUERIER; } while (0)
|
||||
#define CLR_MLD_STARTUP(f) do { (f) &= ~MLD_STARTUP; } while (0)
|
||||
#define CLR_MLD_V1COMPAT(f) do { (f) &= ~MLD_V1COMPAT; } while (0)
|
||||
#define CLR_MLD_LASTREPORT(f) do { (f) &= ~MLD_LASTREPORT; } while (0)
|
||||
#define CLR_MLD_SCHEDMSG(f) do { (f) &= ~MLD_SCHEDMSG; } while (0)
|
||||
#define CLR_MLD_WAITMSG(f) do { (f) &= ~MLD_WAITMSG; } while (0)
|
||||
#define CLR_MLD_RPTPEND(f) do { (f) &= ~MLD_RPTPEND; } while (0)
|
||||
|
||||
#define IS_MLD_QUERIER(f) (((f) & MLD_QUERIER) != 0)
|
||||
#define IS_MLD_STARTUP(f) (((f) & MLD_STARTUP) != 0)
|
||||
#define IS_MLD_V1COMPAT(f) (((f) & MLD_V1COMPAT) != 0)
|
||||
#define IS_MLD_LASTREPORT(f) (((f) & MLD_LASTREPORT) != 0)
|
||||
#define IS_MLD_SCHEDMSG(f) (((f) & MLD_SCHEDMSG) != 0)
|
||||
#define IS_MLD_WAITMSG(f) (((f) & MLD_WAITMSG) != 0)
|
||||
@@ -201,10 +211,6 @@ enum mld_msgtype_e
|
||||
|
||||
/* This structure represents one group member. There is a list of groups
|
||||
* for each device interface structure.
|
||||
*
|
||||
* There will be a group for the all systems group address but this
|
||||
* will not run the state machine as it is used to kick off reports
|
||||
* from all the other groups
|
||||
*/
|
||||
|
||||
typedef FAR struct wdog_s *WDOG_ID;
|
||||
@@ -214,7 +220,6 @@ struct mld_group_s
|
||||
net_ipv6addr_t grpaddr; /* Group IPv6 address */
|
||||
struct work_s work; /* For deferred timeout operations */
|
||||
WDOG_ID polldog; /* Timer used for periodic or delayed events */
|
||||
WDOG_ID v1dog; /* MLDv1 compatibility mode timer */
|
||||
sem_t sem; /* Used to wait for message transmission */
|
||||
#ifdef CONFIG_NET_MLD_ROUTER
|
||||
uint16_t members; /* Number of members currently reporting (excludes us) */
|
||||
@@ -287,7 +292,7 @@ int mld_query(FAR struct net_driver_s *dev,
|
||||
* Name: mld_report_v1
|
||||
*
|
||||
* Description:
|
||||
* Called from icmpv6_input() when a Version 1 Multicast Listener Report is
|
||||
* Called from icmpv6_input() when a MLDv1 Multicast Listener Report is
|
||||
* received.
|
||||
*
|
||||
****************************************************************************/
|
||||
@@ -363,6 +368,18 @@ FAR struct mld_group_s *mld_grpallocfind(FAR struct net_driver_s *dev,
|
||||
void mld_grpfree(FAR struct net_driver_s *dev,
|
||||
FAR struct mld_group_s *group);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: mld_new_pollcycle
|
||||
*
|
||||
* Description:
|
||||
* Update accumulated membership at the beginning of each new poll cycle
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_NET_MLD_ROUTER
|
||||
void mld_new_pollcycle(FAR struct net_driver_s *dev);
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: mld_schedmsg
|
||||
*
|
||||
@@ -431,7 +448,7 @@ void mld_send(FAR struct net_driver_s *dev, FAR struct mld_group_s *group,
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
uint8_t mld_report_msgtype(FAR struct mld_group_s *group);
|
||||
uint8_t mld_report_msgtype(FAR struct net_driver_s *dev);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: mld_joingroup
|
||||
@@ -474,14 +491,14 @@ int mld_joingroup(FAR const struct ipv6_mreq *mrec);
|
||||
int mld_leavegroup(FAR const struct ipv6_mreq *mrec);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: mld_start_polltimer
|
||||
* Name: mld_start_gentimer
|
||||
*
|
||||
* Description:
|
||||
* Start the MLD poll timer.
|
||||
* Start/Re-start the general query timer.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void mld_start_polltimer(FAR struct mld_group_s *group, clock_t ticks);
|
||||
void mld_start_gentimer(FAR struct net_driver_s *dev, clock_t ticks);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: mld_start_v1timer
|
||||
@@ -491,7 +508,17 @@ void mld_start_polltimer(FAR struct mld_group_s *group, clock_t ticks);
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void mld_start_v1timer(FAR struct mld_group_s *group, clock_t ticks);
|
||||
void mld_start_v1timer(FAR struct net_driver_s *dev, clock_t ticks);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: mld_start_polltimer
|
||||
*
|
||||
* Description:
|
||||
* Start the MLD poll timer.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void mld_start_polltimer(FAR struct mld_group_s *group, clock_t ticks);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: mld_addmcastmac
|
||||
|
||||
+54
-17
@@ -109,31 +109,28 @@ FAR struct mld_group_s *mld_grpalloc(FAR struct net_driver_s *dev,
|
||||
goto errout_with_sem;
|
||||
}
|
||||
|
||||
group->v1dog = wd_create();
|
||||
DEBUGASSERT(group->v1dog != NULL);
|
||||
if (group->v1dog == NULL)
|
||||
{
|
||||
goto errout_with_polldog;
|
||||
}
|
||||
|
||||
/* Save the interface index */
|
||||
|
||||
group->ifindex = dev->d_ifindex;
|
||||
|
||||
/* All routers start up as a Querier on each of their attached links. */
|
||||
#ifndef CONFIG_CONFIG_NET_MLD_ROUTER
|
||||
/* Start the query timer if we are the Querier and this is the first
|
||||
* group member of the group.
|
||||
*/
|
||||
|
||||
SET_MLD_QUERIER(group->flags);
|
||||
if (dev->d_mld.grplist.head == NULL)
|
||||
{
|
||||
mld_start_gentimer(dev, MSEC2TICK(MLD_QUERY_MSEC));
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Add the group structure to the list in the device structure */
|
||||
|
||||
sq_addfirst((FAR sq_entry_t *)group, &dev->d_mld_grplist);
|
||||
sq_addfirst((FAR sq_entry_t *)group, &dev->d_mld.grplist);
|
||||
}
|
||||
|
||||
return group;
|
||||
|
||||
errout_with_polldog:
|
||||
wd_delete(group->polldog);
|
||||
|
||||
errout_with_sem:
|
||||
(void)nxsem_destroy(&group->sem);
|
||||
kmm_free(group);
|
||||
@@ -160,7 +157,7 @@ FAR struct mld_group_s *mld_grpfind(FAR struct net_driver_s *dev,
|
||||
addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], addr[6],
|
||||
addr[7]);
|
||||
|
||||
for (group = (FAR struct mld_group_s *)dev->d_mld_grplist.head;
|
||||
for (group = (FAR struct mld_group_s *)dev->d_mld.grplist.head;
|
||||
group;
|
||||
group = group->next)
|
||||
{
|
||||
@@ -222,11 +219,10 @@ void mld_grpfree(FAR struct net_driver_s *dev, FAR struct mld_group_s *group)
|
||||
/* Cancel the timers */
|
||||
|
||||
wd_cancel(group->polldog);
|
||||
wd_cancel(group->v1dog);
|
||||
|
||||
/* Remove the group structure from the group list in the device structure */
|
||||
|
||||
sq_rem((FAR sq_entry_t *)group, &dev->d_mld_grplist);
|
||||
sq_rem((FAR sq_entry_t *)group, &dev->d_mld.grplist);
|
||||
|
||||
/* Destroy the wait semaphore */
|
||||
|
||||
@@ -235,12 +231,53 @@ void mld_grpfree(FAR struct net_driver_s *dev, FAR struct mld_group_s *group)
|
||||
/* Destroy the timers */
|
||||
|
||||
wd_delete(group->polldog);
|
||||
wd_delete(group->v1dog);
|
||||
|
||||
/* Then release the group structure resources. */
|
||||
|
||||
mldinfo("Call sched_kfree()\n");
|
||||
kmm_free(group);
|
||||
|
||||
#ifndef CONFIG_CONFIG_NET_MLD_ROUTER
|
||||
/* If there are no longer any groups, then stop the general query and v1
|
||||
* compatibility timers.
|
||||
*/
|
||||
|
||||
if (dev->d_mld.grplist.head == NULL)
|
||||
{
|
||||
wd_cancel(dev->d_mld.gendog);
|
||||
wd_cancel(dev->d_mld.v1dog);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: mld_new_pollcycle
|
||||
*
|
||||
* Description:
|
||||
* Update accumulated membership at the beginning of each new poll cycle
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_NET_MLD_ROUTER
|
||||
void mld_new_pollcycle(FAR struct net_driver_s *dev)
|
||||
{
|
||||
FAR struct mld_group_s *member;
|
||||
|
||||
/* Update member ship in every group */
|
||||
|
||||
for (member = (FAR struct mld_group_s *)dev->d_mld.grplist.head;
|
||||
member;
|
||||
member = member->next)
|
||||
{
|
||||
/* Save the number of members that reported in the previous query
|
||||
* cycle; reset the number of members that have reported in the new
|
||||
* query cycle.
|
||||
*/
|
||||
|
||||
member->lstmbrs = member->members;
|
||||
member->members = 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* CONFIG_NET_MLD */
|
||||
|
||||
@@ -38,9 +38,11 @@
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <debug.h>
|
||||
|
||||
#include <nuttx/wdog.h>
|
||||
#include <nuttx/net/netdev.h>
|
||||
#include <nuttx/net/ip.h>
|
||||
#include <nuttx/net/mld.h>
|
||||
@@ -77,7 +79,18 @@ void mld_initialize(void)
|
||||
void mld_devinit(struct net_driver_s *dev)
|
||||
{
|
||||
mldinfo("MLD initializing dev %p\n", dev);
|
||||
DEBUGASSERT(dev->d_mld_grplist.head == NULL);
|
||||
|
||||
/* Initialize the MLD state in the device structure */
|
||||
|
||||
memset(&dev->d_mld, 0, sizeof(struct mld_netdev_s));
|
||||
|
||||
dev->d_mld.gendog = wd_create();
|
||||
dev->d_mld.v1dog = wd_create();
|
||||
DEBUGASSERT(dev->d_mld.gendog != NULL && dev->d_mld.v1dog != NULL);
|
||||
|
||||
/* All routers start up as a Querier on each of their attached links. */
|
||||
|
||||
SET_MLD_QUERIER(dev->d_mld.flags);
|
||||
|
||||
/* Add the all nodes address to the group */
|
||||
|
||||
@@ -88,4 +101,10 @@ void mld_devinit(struct net_driver_s *dev)
|
||||
mld_addmcastmac(dev, g_ipv6_allnodes);
|
||||
mld_addmcastmac(dev, g_ipv6_allrouters);
|
||||
mld_addmcastmac(dev, g_ipv6_allmldv2routers);
|
||||
|
||||
#ifdef CONFIG_CONFIG_NET_MLD_ROUTER
|
||||
/* Start the general query timer. */
|
||||
|
||||
mld_start_gentimer(dev, MSEC2TICK(MLD_QUERY_MSEC));
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -193,7 +193,6 @@ int mld_leavegroup(FAR const struct ipv6_mreq *mrec)
|
||||
*/
|
||||
|
||||
wd_cancel(group->polldog);
|
||||
wd_cancel(group->v1dog);
|
||||
CLR_MLD_SCHEDMSG(group->flags);
|
||||
CLR_MLD_WAITMSG(group->flags);
|
||||
|
||||
|
||||
+21
-2
@@ -78,9 +78,28 @@ void mld_poll(FAR struct net_driver_s *dev)
|
||||
dev->d_len = 0;
|
||||
dev->d_sndlen = 0;
|
||||
|
||||
/* Check if a general query is pending */
|
||||
|
||||
if (IS_MLD_GENPEND(dev->d_mld.flags))
|
||||
{
|
||||
/* Clear the pending flag */
|
||||
|
||||
CLR_MLD_GENPEND(dev->d_mld.flags);
|
||||
|
||||
/* Are we still the querier? */
|
||||
|
||||
if (IS_MLD_QUERIER(dev->d_mld.flags))
|
||||
{
|
||||
/* Yes, send the general query and return */
|
||||
|
||||
mld_send(dev, NULL, MLD_SEND_GENQUERY);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check each member of the group */
|
||||
|
||||
for (group = (FAR struct mld_group_s *)dev->d_mld_grplist.head;
|
||||
for (group = (FAR struct mld_group_s *)dev->d_mld.grplist.head;
|
||||
group;
|
||||
group = group->next)
|
||||
{
|
||||
@@ -120,7 +139,7 @@ void mld_poll(FAR struct net_driver_s *dev)
|
||||
{
|
||||
/* Yes.. create the MLD message in the driver buffer */
|
||||
|
||||
mld_send(dev, group, mld_report_msgtype(group));
|
||||
mld_send(dev, group, mld_report_msgtype(dev));
|
||||
|
||||
/* Indicate that the report is no longer pending */
|
||||
|
||||
|
||||
+55
-103
@@ -65,7 +65,7 @@
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: mld_setup_v1compat
|
||||
* Name: mld_check_v1compat
|
||||
*
|
||||
* Description:
|
||||
* If this is for MLDv1 query, then select MLDv1 compatibility mode and
|
||||
@@ -74,21 +74,11 @@
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void mld_setup_v1compat(FAR struct mld_group_s *group,
|
||||
FAR const struct mld_mcast_listen_query_s *query,
|
||||
bool mldv1)
|
||||
static inline void mld_check_v1compat(FAR struct net_driver_s *dev,
|
||||
bool mldv1)
|
||||
{
|
||||
unsigned int respmsec;
|
||||
|
||||
if (mldv1)
|
||||
{
|
||||
#if 0 /* REVISIT */
|
||||
/* Get the QQI from the query. Since this is MLDv1, we know that
|
||||
* the value is not encoded.
|
||||
*/
|
||||
|
||||
respmsec = MSEC_PER_SEC * MLD_QQI_VALUE(query->qqic);
|
||||
#else
|
||||
/* REVISIT: I am confused. Per RFC 3810:
|
||||
* "The Older Version Querier Present Timeout is the time-out for
|
||||
* transitioning a host back to MLDv2 Host Compatibility Mode. When
|
||||
@@ -103,34 +93,20 @@ static void mld_setup_v1compat(FAR struct mld_group_s *group,
|
||||
* field. That is an MLDv2 extension.
|
||||
*/
|
||||
|
||||
respmsec = MLD_QUERY_MSEC;
|
||||
#endif
|
||||
|
||||
/* Select MLDv1 compatibility mode (might already be selected) */
|
||||
|
||||
SET_MLD_V1COMPAT(group->flags);
|
||||
SET_MLD_V1COMPAT(dev->d_mld.flags);
|
||||
|
||||
/* Whenever a host changes its compatibility mode, it cancels all its
|
||||
* pending responses and retransmission timers.
|
||||
/* REVISIT: Whenever a host changes its compatibility mode, it cancels
|
||||
* all its pending responses and retransmission timers. Logic Missing.
|
||||
*/
|
||||
|
||||
wd_cancel(group->polldog);
|
||||
|
||||
/* REVISIT: We cannot cancel a pending message if there is a waiter.
|
||||
* Some additional logic would be required to avoid a hang.
|
||||
*/
|
||||
|
||||
if (!IS_MLD_WAITMSG(group->flags))
|
||||
{
|
||||
CLR_MLD_SCHEDMSG(group->flags);
|
||||
}
|
||||
|
||||
/* And start the MLDv1 compatibility timer. If the timer is already
|
||||
* running, this will reset the timer.
|
||||
*/
|
||||
|
||||
mld_start_v1timer(group,
|
||||
MSEC2TICK(MLD_V1PRESENT_MSEC((clock_t)respmsec)));
|
||||
mld_start_v1timer(dev,
|
||||
MSEC2TICK(MLD_V1PRESENT_MSEC((clock_t)MLD_QUERY_MSEC)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -197,21 +173,19 @@ static bool mld_cmpaddr(FAR struct net_driver_s *dev,
|
||||
* Name: mld_check_querier
|
||||
*
|
||||
* Description:
|
||||
* Check if we are still the querier for this group (assuming that we are
|
||||
* currently the querier). This compares the IPv6 Source Address of the
|
||||
* query against and the IPv6 address of the link. Ff the source address
|
||||
* is numerically less than the link address, when we are no longer the
|
||||
* querier.
|
||||
* Check if we are still the querier (assuming that we are currently the
|
||||
* querier). This compares the IPv6 Source Address of the query against
|
||||
* the IPv6 address of the link. If the source address is numerically
|
||||
* less than the link address, when we are no longer the querier.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void mld_check_querier(FAR struct net_driver_s *dev,
|
||||
FAR struct ipv6_hdr_s *ipv6,
|
||||
FAR struct mld_group_s *group)
|
||||
FAR struct ipv6_hdr_s *ipv6)
|
||||
{
|
||||
/* Check if this member is a Querier */
|
||||
|
||||
if (IS_MLD_QUERIER(group->flags))
|
||||
if (IS_MLD_QUERIER(dev->d_mld.flags))
|
||||
{
|
||||
/* This is a querier, check if the IPv6 source address is numerically
|
||||
* less than the IPv6 address assigned to this link.
|
||||
@@ -221,21 +195,17 @@ static void mld_check_querier(FAR struct net_driver_s *dev,
|
||||
{
|
||||
/* Switch to non-Querier mode */
|
||||
|
||||
CLR_MLD_QUERIER(group->flags);
|
||||
CLR_MLD_QUERIER(dev->d_mld.flags);
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if the member is a Non-Querier AND that we are past the start up
|
||||
* phase (where the timer is used for a different purpose)?
|
||||
*/
|
||||
/* Check if the member is a Non-Querier. */
|
||||
|
||||
if (!IS_MLD_QUERIER(group->flags) && !IS_MLD_STARTUP(group->flags))
|
||||
if (!IS_MLD_QUERIER(dev->d_mld.flags))
|
||||
{
|
||||
/* Yes.. cancel the poll timer and [re-]start the 'Other Querier
|
||||
* Present' Timeout.
|
||||
*/
|
||||
/* Yes.. [re-]start the 'Other Querier Present' Timeout. */
|
||||
|
||||
mld_start_polltimer(group, MSEC2TICK(MLD_OQUERY_MSEC));
|
||||
mld_start_gentimer(dev, MSEC2TICK(MLD_OQUERY_MSEC));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -307,6 +277,13 @@ int mld_query(FAR struct net_driver_s *dev,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Warn if we received a MLDv2 query in MLDv1 compatibility mode. */
|
||||
|
||||
if (!mldv1 && IS_MLD_V1COMPAT(dev->d_mld.flags))
|
||||
{
|
||||
mldwarn("WARNING: MLDv2 query received in MLDv1 compatibility mode\n");
|
||||
}
|
||||
|
||||
/* There are three variants of the Query message (RFC 3810):
|
||||
*
|
||||
* 1. A "General Query" is sent by the Querier to learn which
|
||||
@@ -352,64 +329,37 @@ int mld_query(FAR struct net_driver_s *dev,
|
||||
mldinfo("General multicast query\n");
|
||||
MLD_STATINCR(g_netstats.mld.gm_query_received);
|
||||
|
||||
/* Two passes through the member list. On the first, just check if we
|
||||
* are still the querier for the qroup.
|
||||
*/
|
||||
/* Check if we are still the querier for this sub-net */
|
||||
|
||||
for (member = (FAR struct mld_group_s *)dev->d_mld_grplist.head;
|
||||
member;
|
||||
member = member->next)
|
||||
{
|
||||
/* Skip over the all systems group entry */
|
||||
|
||||
if (!net_ipv6addr_cmp(member->grpaddr, g_ipv6_allnodes))
|
||||
{
|
||||
/* Check if we are still the querier for this group */
|
||||
|
||||
mld_check_querier(dev, ipv6, member);
|
||||
|
||||
/* Warn if we received a MLDv2 query in MLDv1 compatibility
|
||||
* mode.
|
||||
*/
|
||||
|
||||
if (!mldv1 && IS_MLD_V1COMPAT(member->flags))
|
||||
{
|
||||
mldinfo("WARNING: MLDv2 query received in MLDv1 "
|
||||
"compatibility mode\n");
|
||||
}
|
||||
mld_check_querier(dev, ipv6);
|
||||
|
||||
#ifdef CONFIG_NET_MLD_ROUTER
|
||||
/* Save the number of members that reported in the previous
|
||||
* query cycle; reset the number of members that have
|
||||
* reported in the new query cycle.
|
||||
*/
|
||||
|
||||
member->lstmbrs = member->members;
|
||||
member->members = 0;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/* On the second time through, we send the Report in response to the
|
||||
* query. This has to be done twice because because there is only
|
||||
* a single packet buffer that is used for both incoming and outgoing
|
||||
* packets. When the report is sent, it will clobber the incoming
|
||||
* query. Any attempt to send an additional Report would also clobber
|
||||
* a preceding report
|
||||
/* Update accumulated membership at the beginning of each new poll
|
||||
* cycle
|
||||
*/
|
||||
|
||||
for (member = (FAR struct mld_group_s *)dev->d_mld_grplist.head;
|
||||
member;
|
||||
mld_new_pollcycle(dev)
|
||||
#endif
|
||||
|
||||
/* Check MLDv1 compatibility mode */
|
||||
|
||||
mld_check_v1compat(dev, mldv1);
|
||||
|
||||
/* Send the Report in response to the query. This has to be done
|
||||
* multiple times because because there is only a single packet buffer
|
||||
* that is used for both incoming and outgoing packets. When the
|
||||
* report is sent, it will clobber the incoming* query. Any attempt
|
||||
* to send an additional Report would also clobber a preceding report
|
||||
*/
|
||||
|
||||
for (member = (FAR struct mld_group_s *)dev->d_mld.grplist.head;
|
||||
member != NULL;
|
||||
member = member->next)
|
||||
{
|
||||
/* Skip over the all systems group entry */
|
||||
|
||||
if (!net_ipv6addr_cmp(member->grpaddr, g_ipv6_allnodes))
|
||||
{
|
||||
/* Check MLDv1 compatibility mode */
|
||||
|
||||
mld_setup_v1compat(member, query, mldv1);
|
||||
|
||||
/* Have we already sent a report from this loop? */
|
||||
|
||||
if (rptsent)
|
||||
@@ -424,7 +374,7 @@ int mld_query(FAR struct net_driver_s *dev,
|
||||
{
|
||||
/* No.. Send one report now. */
|
||||
|
||||
mld_send(dev, member, mld_report_msgtype(member));
|
||||
mld_send(dev, member, mld_report_msgtype(dev));
|
||||
rptsent = true;
|
||||
CLR_MLD_RPTPEND(member->flags);
|
||||
}
|
||||
@@ -458,7 +408,7 @@ int mld_query(FAR struct net_driver_s *dev,
|
||||
|
||||
/* Check if we are still the querier for this group */
|
||||
|
||||
mld_check_querier(dev, ipv6, group);
|
||||
mld_check_querier(dev, ipv6);
|
||||
|
||||
#ifdef CONFIG_NET_MLD_ROUTER
|
||||
/* Save the number of members that reported in the previous query cycle;
|
||||
@@ -471,7 +421,7 @@ int mld_query(FAR struct net_driver_s *dev,
|
||||
|
||||
/* Warn if we received a MLDv2 query in MLDv1 compatibility mode. */
|
||||
|
||||
if (!mldv1 && IS_MLD_V1COMPAT(group->flags))
|
||||
if (!mldv1 && IS_MLD_V1COMPAT(dev->d_mld.flags))
|
||||
{
|
||||
mldinfo("WARNING: MLDv2 query received in MLDv1 compatibility mode\n");
|
||||
}
|
||||
@@ -496,11 +446,12 @@ int mld_query(FAR struct net_driver_s *dev,
|
||||
|
||||
/* Check MLDv1 compatibility mode */
|
||||
|
||||
mld_setup_v1compat(group, query, mldv1);
|
||||
mld_check_v1compat(dev, mldv1);
|
||||
|
||||
/* Send the report */
|
||||
|
||||
mld_send(dev, group, mld_report_msgtype(group));
|
||||
mld_send(dev, group, mld_report_msgtype(dev));
|
||||
CLR_MLD_RPTPEND(group->flags);
|
||||
}
|
||||
|
||||
/* Not sent to all systems. Check for Unicast General Query */
|
||||
@@ -512,11 +463,12 @@ int mld_query(FAR struct net_driver_s *dev,
|
||||
|
||||
/* Check MLDv1 compatibility mode */
|
||||
|
||||
mld_setup_v1compat(group, query, mldv1);
|
||||
mld_check_v1compat(dev, mldv1);
|
||||
|
||||
/* Send the report */
|
||||
|
||||
mld_send(dev, group, mld_report_msgtype(group));
|
||||
mld_send(dev, group, mld_report_msgtype(dev));
|
||||
CLR_MLD_RPTPEND(group->flags);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -157,7 +157,7 @@ int mld_report(FAR struct net_driver_s *dev, FAR const net_ipv6addr_t grpaddr)
|
||||
int mld_report_v1(FAR struct net_driver_s *dev,
|
||||
FAR const struct mld_mcast_listen_report_v1_s *report)
|
||||
{
|
||||
mldinfo("Version 1 Multicast Listener Report\n");
|
||||
mldinfo("MLDv1 Multicast Listener Report\n");
|
||||
DEBUGASSERT(dev != NULL && report != NULL);
|
||||
|
||||
MLD_STATINCR(g_netstats.mld.v1report_received);
|
||||
|
||||
+23
-9
@@ -120,6 +120,11 @@ void mld_send(FAR struct net_driver_s *dev, FAR struct mld_group_s *group,
|
||||
FAR const uint16_t *destipaddr;
|
||||
unsigned int mldsize;
|
||||
|
||||
/* Only a general query message can have a NULL group */
|
||||
|
||||
DEBUGASSERT(dev != NULL);
|
||||
DEBUGASSERT(msgtype == MLD_SEND_GENQUERY || group != NULL);
|
||||
|
||||
/* Select IPv6 */
|
||||
|
||||
IFF_SET_IPv6(dev->d_flags);
|
||||
@@ -131,7 +136,8 @@ void mld_send(FAR struct net_driver_s *dev, FAR struct mld_group_s *group,
|
||||
case MLD_SEND_GENQUERY: /* Send General Query */
|
||||
case MLD_SEND_MASQUERY: /* Send Multicast Address Specific (MAS) Query */
|
||||
{
|
||||
mldinfo("Send General Query, flags=%02x\n", group->flags);
|
||||
mldinfo("Send General/MAS Query, flags=%02x\n",
|
||||
group != NULL ? group->flags : dev->d_mld.flags);
|
||||
mldsize = SIZEOF_MLD_MCAST_LISTEN_QUERY_S(0);
|
||||
}
|
||||
break;
|
||||
@@ -290,7 +296,7 @@ void mld_send(FAR struct net_driver_s *dev, FAR struct mld_group_s *group,
|
||||
|
||||
/* Fields unique to the extended MLDv2 query */
|
||||
|
||||
if (!IS_MLD_V1COMPAT(group->flags))
|
||||
if (!IS_MLD_V1COMPAT(dev->d_mld.flags))
|
||||
{
|
||||
query->flags = MLD_ROBUSTNESS;
|
||||
query->qqic = MLD_QRESP_SEC;
|
||||
@@ -307,13 +313,21 @@ void mld_send(FAR struct net_driver_s *dev, FAR struct mld_group_s *group,
|
||||
/* Save the number of members that reported in the previous query
|
||||
* cycle; reset the number of members that have reported in the
|
||||
* new query cycle.
|
||||
*
|
||||
* REVISIT: This would have to be done for all groups, not just
|
||||
* this one.
|
||||
*/
|
||||
|
||||
group->lstmbrs = group->members;
|
||||
group->members = 0;
|
||||
if (msgtype == MLD_SEND_GENQUERY)
|
||||
{
|
||||
/* Update accumulated membership for all groups. */
|
||||
|
||||
mld_new_pollcycle(dev)
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Updated accumulated membership only for this group */
|
||||
|
||||
group->lstmbrs = group->members;
|
||||
group->members = 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
@@ -404,9 +418,9 @@ void mld_send(FAR struct net_driver_s *dev, FAR struct mld_group_s *group,
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
uint8_t mld_report_msgtype(FAR struct mld_group_s *group)
|
||||
uint8_t mld_report_msgtype(FAR struct net_driver_s *dev)
|
||||
{
|
||||
if (IS_MLD_V1COMPAT(group->flags))
|
||||
if (IS_MLD_V1COMPAT(dev->d_mld.flags))
|
||||
{
|
||||
return MLD_SEND_V1REPORT;
|
||||
}
|
||||
|
||||
+324
-199
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user