forked from nuttx/nuttx-update
Squashed commit of the following:
net/mld: More updates from comparison with roughly leveraged code and the MDL RFCs 2710 and 3810. net/mld: More updated from comparison with roughly leveraged code and the MDL RFCs 2710 and 3810. net/mld: Beginning comparison with roughly leveraged code and the MDL RFCs 2710 and 3810.
This commit is contained in:
parent
46cf69c93e
commit
1c15aa3b2d
14 changed files with 517 additions and 230 deletions
|
@ -81,32 +81,6 @@
|
|||
#define IGMP_HDRLEN 8
|
||||
#define IPIGMP_HDRLEN (IGMP_HDRLEN + IPv4_HDRLEN + 4)
|
||||
|
||||
/* Group flags */
|
||||
|
||||
#define IGMP_PREALLOCATED (1 << 0)
|
||||
#define IGMP_LASTREPORT (1 << 1)
|
||||
#define IGMP_IDLEMEMBER (1 << 2)
|
||||
#define IGMP_SCHEDMSG (1 << 3)
|
||||
#define IGMP_WAITMSG (1 << 4)
|
||||
|
||||
#define SET_PREALLOCATED(f) do { (f) |= IGMP_PREALLOCATED; } while (0)
|
||||
#define SET_LASTREPORT(f) do { (f) |= IGMP_LASTREPORT; } while (0)
|
||||
#define SET_IDLEMEMBER(f) do { (f) |= IGMP_IDLEMEMBER; } while (0)
|
||||
#define SET_SCHEDMSG(f) do { (f) |= IGMP_SCHEDMSG; } while (0)
|
||||
#define SET_WAITMSG(f) do { (f) |= IGMP_WAITMSG; } while (0)
|
||||
|
||||
#define CLR_PREALLOCATED(f) do { (f) &= ~IGMP_PREALLOCATED; } while (0)
|
||||
#define CLR_LASTREPORT(f) do { (f) &= ~IGMP_LASTREPORT; } while (0)
|
||||
#define CLR_IDLEMEMBER(f) do { (f) &= ~IGMP_IDLEMEMBER; } while (0)
|
||||
#define CLR_SCHEDMSG(f) do { (f) &= ~IGMP_SCHEDMSG; } while (0)
|
||||
#define CLR_WAITMSG(f) do { (f) &= ~IGMP_WAITMSG; } while (0)
|
||||
|
||||
#define IS_PREALLOCATED(f) (((f) & IGMP_PREALLOCATED) != 0)
|
||||
#define IS_LASTREPORT(f) (((f) & IGMP_LASTREPORT) != 0)
|
||||
#define IS_IDLEMEMBER(f) (((f) & IGMP_IDLEMEMBER) != 0)
|
||||
#define IS_SCHEDMSG(f) (((f) & IGMP_SCHEDMSG) != 0)
|
||||
#define IS_WAITMSG(f) (((f) & IGMP_WAITMSG) != 0)
|
||||
|
||||
/* Time-to-Live must be one */
|
||||
|
||||
#define IGMP_TTL 1
|
||||
|
|
|
@ -90,7 +90,7 @@
|
|||
#define MLD_MRC_MANT_MASK (0xfff << MLD_MRC_MANT_SHIFT)
|
||||
# define MLD_MRC_MANT(n) ((uint16_t)(n) << MLD_MRC_MANT_SHIFT)
|
||||
|
||||
/* MRD conversion (for the case of MRC >= 32768) */
|
||||
/* Conversion of MRC to MRD in milliseconds (for the case of MRC >= 32768) */
|
||||
|
||||
#define MLD_MRC_GETEXP(mrc) (((mrc) & MLD_MRC_EXP_MASK) >> MLD_MRC_EXP_SHIFT)
|
||||
#define MLD_MRC_GETMANT(mrc) (((mrc) & MLD_MRC_MANT_MASK) >> MLD_MRC_MANT_SHIFT)
|
||||
|
@ -113,7 +113,7 @@
|
|||
#define MLD_QQIC_MANT_MASK (15 << MLD_QQIC_MANT_SHIFT)
|
||||
# define MLD_QQIC_MANT(n) ((uint8_t)(n) << MLD_QQIC_MANT_SHIFT)
|
||||
|
||||
/* QQI conversion (for the case of QQIC >= 128) */
|
||||
/* Conversion of QQIC to QQI in seconds (for the case of MRC >= 128) */
|
||||
|
||||
#define MLD_QQIC_GETEXP(qqic) (((qqic) & MLD_QQIC_EXP_MASK) >> MLD_QQIC_EXP_SHIFT)
|
||||
#define MLD_QQIC_GETMANT(qqic) (((qqic) & MLD_QQIC_MANT_MASK) >> MLD_QQIC_MANT_SHIFT)
|
||||
|
@ -165,6 +165,81 @@
|
|||
* the node no longer wishes to listen
|
||||
* to. */
|
||||
|
||||
/* MLD default values (RFC 3810) of tunable parameters.
|
||||
*
|
||||
* MLD_ROBUSTNESS Robustness Variable. The Robustness Variable
|
||||
* allows tuning for the expected packet loss on
|
||||
* a link.
|
||||
* MLD_QUERY_MSEC Query Interval. The Query Interval variable
|
||||
* denotes the interval between General Queries
|
||||
* sent by the Querier.
|
||||
* MLD_QRESP_MSEC Query Response Interval. The Maximum Response
|
||||
* Delay used to calculate the Maximum Response
|
||||
* Code inserted into the periodic General Queries.
|
||||
* MLD_MCASTLISTEN_MSEC Multicast Address Listening Interval. The
|
||||
* amount of time that must pass before a multicast
|
||||
* router decides there are no more listeners of a
|
||||
* multicast address or a particular source on a
|
||||
* link.
|
||||
* MLD_OQUERY_MSEC Other Querier Present Timeout. The length of
|
||||
* time that must pass before a multicast router
|
||||
* decides that there is no longer another multicast
|
||||
* router which should be the Querier.
|
||||
* MLD_STARTUP_MSEC Startup Query Interval. The interval between
|
||||
* General Queries sent by a Querier on startup.
|
||||
* MLD_STARTUP_COUNT Startup Query Count. The number of Queries sent
|
||||
* out on startup separated by the Startup Query
|
||||
* Interval.
|
||||
* MLD_LASTLISTEN_MSEC Last Listener Query Interval. The Maximum
|
||||
* Response Delay used to calculate the Maximum
|
||||
* Response Code inserted into Multicast Address
|
||||
* Specific Queries sent in response to Version 1
|
||||
* Multicast Listener Done messages. It is also
|
||||
* the Maximum Response Delay used to calculate
|
||||
* the Maximum Response Code inserted into Multicast
|
||||
* Address and Source Specific Query messages.
|
||||
* MLD_LASTLISTEN_COUNT Last Listener Query Count. The number of
|
||||
* Multicast Address Specific Queries sent before
|
||||
* the router assumes there are no local listeners.
|
||||
* The Last Listener Query Count is also the number
|
||||
* of Multicast Address and Source Specific Queries
|
||||
* sent before the router assumes there are no
|
||||
* listeners for a particular source.
|
||||
* MLD_LLQUERY_MSEC Last Listener Query Time. The time value
|
||||
* represented by the Last Listener Query Interval
|
||||
* multiplied by Last Listener Query Count.
|
||||
* MLD_UNSOLREPORT_MSEC Unsolicited Report Interval. The time between
|
||||
* repetitions of a node's initial report of
|
||||
* interest in a multicast address.
|
||||
* MLD_V1PRESENT_MSEC(m) Older Version Querier Present Timeout. The time-
|
||||
* out for transitioning a host back to MLDv2 Host
|
||||
* Compatibility Mode. 'm' is the Query Interval
|
||||
* in the last Query received in units of msec.
|
||||
* MLD_V1HOST_MSEC Older Version Host Present Timeout. The time-out
|
||||
* for transitioning a router back to MLDv2 Multicast
|
||||
* Address Compatibility Mode for a specific multicast
|
||||
* address. When an MLDv1 report is received for that
|
||||
* multicast address, routers set their Older Version
|
||||
* Host Present Timer to the Older Version Host Present
|
||||
* Timeout.
|
||||
*/
|
||||
|
||||
#define MLD_ROBUSTNESS (2)
|
||||
#define MLD_QUERY_MSEC (125 * 1000)
|
||||
#define MLD_QRESP_SEC (10)
|
||||
#define MLD_QRESP_MSEC (MLD_QRESP_SEC * 1000)
|
||||
#define MLD_MCASTLISTEN_MSEC (MLD_ROBUSTNESS * MLD_QUERY_MSEC + MLD_QRESP_MSEC)
|
||||
#define MLD_OQUERY_MSEC (MLD_ROBUSTNESS * MLD_QUERY_MSEC + (MLD_QRESP_MSEC / 2))
|
||||
#define MLD_STARTUP_MSEC (MLD_QUERY_MSEC / 4)
|
||||
#define MLD_STARTUP_COUNT MLD_ROBUSTNESS
|
||||
#define MLD_LASTLISTEN_MSEC (1000)
|
||||
#define MLD_LASTLISTEN_COUNT MLD_ROBUSTNESS
|
||||
#define MLD_LLQUERY_MSEC (MLD_LASTLISTEN_MSEC * MLD_LASTLISTEN_COUNT)
|
||||
#define MLD_UNSOLREPORT_MSEC (1000)
|
||||
#define MLD_UNSOLREPORT_COUNT MLD_ROBUSTNESS
|
||||
#define MLD_V1PRESENT_MSEC(m) (MLD_ROBUSTNESS * (m) + MLD_QRESP_MSEC)
|
||||
#define MLD_V1HOST_MSEC (MLD_ROBUSTNESS * MLD_QUERY_MSEC + MLD_QRESP_MSEC)
|
||||
|
||||
/****************************************************************************
|
||||
* Public Type Definitions
|
||||
****************************************************************************/
|
||||
|
@ -203,7 +278,7 @@ struct mld_mcast_listen_query_s
|
|||
uint16_t reserved2; /* Reserved, must be zero on transmission */
|
||||
net_ipv6addr_t grpaddr; /* 128-bit IPv6 multicast group address */
|
||||
uint8_t flags; /* See S and QRV flag definitions */
|
||||
uint8_t qqic; /* Querier's Query Interval Cod */
|
||||
uint8_t qqic; /* Querier's Query Interval Code */
|
||||
uint16_t nsources; /* Number of sources that follow */
|
||||
net_ipv6addr_t srcaddr[1]; /* Array of source IPv6 address (actual size is
|
||||
* nsources) */
|
||||
|
@ -212,8 +287,8 @@ struct mld_mcast_listen_query_s
|
|||
/* The actual size of the query structure depends on the number of sources */
|
||||
|
||||
#define SIZEOF_MLD_MCAST_LISTEN_QUERY_S(nsources) \
|
||||
(sizeof(struct mld_multicast_listener_query_s) + \
|
||||
sizeof(net_ipv6addr_t) * ((nsources) - 1)
|
||||
(sizeof(struct mld_mcast_listen_query_s) + \
|
||||
sizeof(net_ipv6addr_t) * ((nsources) - 1))
|
||||
|
||||
/* Multicast Listener Reports are sent by IP nodes to report (to neighboring
|
||||
* routers) the current multicast listening state, or changes in the
|
||||
|
@ -297,10 +372,12 @@ struct mld_stats_s
|
|||
{
|
||||
net_stats_t joins; /* Requests to join a group */
|
||||
net_stats_t leaves; /* Requests to leave a group */
|
||||
net_stats_t report_sched; /* Version 1 REPORT packets scheduled */
|
||||
net_stats_t done_sched; /* Version 1 DONE packets scheduled */
|
||||
net_stats_t report_sent; /* Version 1 REPORT packets sent */
|
||||
net_stats_t done_sent; /* Version 1 DONE packets sent */
|
||||
net_stats_t query_sched; /* General QUERY packets scheduled */
|
||||
net_stats_t report_sched; /* Unsolicited REPORT packets scheduled */
|
||||
net_stats_t done_sched; /* DONE packets scheduled */
|
||||
net_stats_t query_sent; /* General QUERY packets sent */
|
||||
net_stats_t report_sent; /* Unsolicited REPORT packets sent */
|
||||
net_stats_t done_sent; /* DONE packets sent */
|
||||
net_stats_t gmq_query_received; /* General multicast QUERY received */
|
||||
net_stats_t mas_query_received; /* Multicast Address Specific QUERY received */
|
||||
net_stats_t massq_query_received; /* Multicast Address and Source Specific QUERY received */
|
||||
|
|
|
@ -81,6 +81,32 @@
|
|||
|
||||
#ifdef CONFIG_NET_IGMP
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/* Group flags */
|
||||
|
||||
#define IGMP_IDLEMEMBER (1 << 0)
|
||||
#define IGMP_LASTREPORT (1 << 1)
|
||||
#define IGMP_SCHEDMSG (1 << 2)
|
||||
#define IGMP_WAITMSG (1 << 3)
|
||||
|
||||
#define SET_IDLEMEMBER(f) do { (f) |= IGMP_IDLEMEMBER; } while (0)
|
||||
#define SET_LASTREPORT(f) do { (f) |= IGMP_LASTREPORT; } while (0)
|
||||
#define SET_SCHEDMSG(f) do { (f) |= IGMP_SCHEDMSG; } while (0)
|
||||
#define SET_WAITMSG(f) do { (f) |= IGMP_WAITMSG; } while (0)
|
||||
|
||||
#define CLR_IDLEMEMBER(f) do { (f) &= ~IGMP_IDLEMEMBER; } while (0)
|
||||
#define CLR_LASTREPORT(f) do { (f) &= ~IGMP_LASTREPORT; } while (0)
|
||||
#define CLR_SCHEDMSG(f) do { (f) &= ~IGMP_SCHEDMSG; } while (0)
|
||||
#define CLR_WAITMSG(f) do { (f) &= ~IGMP_WAITMSG; } while (0)
|
||||
|
||||
#define IS_IDLEMEMBER(f) (((f) & IGMP_IDLEMEMBER) != 0)
|
||||
#define IS_LASTREPORT(f) (((f) & IGMP_LASTREPORT) != 0)
|
||||
#define IS_SCHEDMSG(f) (((f) & IGMP_SCHEDMSG) != 0)
|
||||
#define IS_WAITMSG(f) (((f) & IGMP_WAITMSG) != 0)
|
||||
|
||||
/****************************************************************************
|
||||
* Public Type Definitions
|
||||
****************************************************************************/
|
||||
|
|
|
@ -123,27 +123,31 @@
|
|||
|
||||
/* Group flags */
|
||||
|
||||
#define MLD_PREALLOCATED (1 << 0)
|
||||
#define MLD_LASTREPORT (1 << 1)
|
||||
#define MLD_IDLEMEMBER (1 << 2)
|
||||
#define MLD_SCHEDMSG (1 << 3)
|
||||
#define MLD_WAITMSG (1 << 4)
|
||||
#define MLD_QUERIER (1 << 0) /* Querier */
|
||||
#define MLD_STARTUP (1 << 2) /* Startup unsolicited Reports */
|
||||
#define MLD_V1COMPAT (1 << 3) /* 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 SET_MLD_PREALLOCATED(f) do { (f) |= MLD_PREALLOCATED; } while (0)
|
||||
#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_IDLEMEMBER(f) do { (f) |= MLD_IDLEMEMBER; } 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 CLR_MLD_PREALLOCATED(f) do { (f) &= ~MLD_PREALLOCATED; } 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_IDLEMEMBER(f) do { (f) &= ~MLD_IDLEMEMBER; } 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 IS_MLD_PREALLOCATED(f) (((f) & MLD_PREALLOCATED) != 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_IDLEMEMBER(f) (((f) & MLD_IDLEMEMBER) != 0)
|
||||
#define IS_MLD_SCHEDMSG(f) (((f) & MLD_SCHEDMSG) != 0)
|
||||
#define IS_MLD_WAITMSG(f) (((f) & MLD_WAITMSG) != 0)
|
||||
|
||||
|
@ -151,6 +155,18 @@
|
|||
* Public Type Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/* These are the types of messages that may be sent in response to a device
|
||||
* poll.
|
||||
*/
|
||||
|
||||
enum mld_msgtype_e
|
||||
{
|
||||
MLD_SEND_NONE = 0, /* Nothing to send */
|
||||
MLD_SEND_GENQUERY, /* Send General Query */
|
||||
MLD_SEND_REPORT, /* Send Unsolicited report */
|
||||
MLD_SEND_DONE /* Send Done message */
|
||||
};
|
||||
|
||||
/* This structure represents one group member. There is a list of groups
|
||||
* for each device interface structure.
|
||||
*
|
||||
|
@ -167,7 +183,8 @@ struct mld_group_s
|
|||
WDOG_ID wdog; /* WDOG used to detect timeouts */
|
||||
sem_t sem; /* Used to wait for message transmission */
|
||||
volatile uint8_t flags; /* See MLD_ flags definitions */
|
||||
uint8_t msgid; /* Pending message ID (if non-zero) */
|
||||
uint8_t msgtype; /* Pending message type to send (if non-zero) */
|
||||
uint8_t count; /* Report repetition count */
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
|
@ -315,7 +332,7 @@ void mld_grpfree(FAR struct net_driver_s *dev,
|
|||
*
|
||||
****************************************************************************/
|
||||
|
||||
void mld_schedmsg(FAR struct mld_group_s *group, uint8_t msgid);
|
||||
void mld_schedmsg(FAR struct mld_group_s *group, uint8_t msgtype);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: mld_waitmsg
|
||||
|
@ -326,7 +343,7 @@ void mld_schedmsg(FAR struct mld_group_s *group, uint8_t msgid);
|
|||
*
|
||||
****************************************************************************/
|
||||
|
||||
void mld_waitmsg(FAR struct mld_group_s *group, uint8_t msgid);
|
||||
void mld_waitmsg(FAR struct mld_group_s *group, uint8_t msgtype);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: mld_poll
|
||||
|
@ -407,15 +424,14 @@ int mld_joingroup(FAR const struct ipv6_mreq *mrec);
|
|||
int mld_leavegroup(FAR const struct ipv6_mreq *mrec);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: mld_startticks and mld_starttimer
|
||||
* Name: mld_starttimer
|
||||
*
|
||||
* Description:
|
||||
* Start the MLD timer with differing time units (ticks or deciseconds).
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void mld_startticks(FAR struct mld_group_s *group, unsigned int ticks);
|
||||
void mld_starttimer(FAR struct mld_group_s *group, uint8_t decisecs);
|
||||
void mld_starttimer(FAR struct mld_group_s *group, clock_t ticks);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: mld_cmptimer
|
||||
|
@ -425,7 +441,7 @@ void mld_starttimer(FAR struct mld_group_s *group, uint8_t decisecs);
|
|||
* value. If maxticks > ticks-remaining, then (1) cancel the timer (to
|
||||
* avoid race conditions) and return true.
|
||||
*
|
||||
* If true is returned then the caller must call mld_startticks() to
|
||||
* If true is returned then the caller must call mld_starttimer() to
|
||||
* restart the timer
|
||||
*
|
||||
****************************************************************************/
|
||||
|
|
|
@ -46,6 +46,12 @@
|
|||
#include "devif/devif.h"
|
||||
#include "mld/mld.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
#define IPv6BUF ((FAR struct ipv6_hdr_s *)&dev->d_buf[NET_LL_HDRLEN(dev)])
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
@ -54,15 +60,52 @@
|
|||
* Name: mld_done_v1
|
||||
*
|
||||
* Description:
|
||||
* Called from icmpv6_input() when a Version 1 Multicast Listener Done is
|
||||
* received.
|
||||
* Called from icmpv6_input() when a Version 1 Multicast Listener Done is
|
||||
* received.
|
||||
*
|
||||
* When a router in Querier state receives a Done message from a link,
|
||||
* if the Multicast Address identified in the message is present in the
|
||||
* Querier's list of addresses having listeners on that link, the Querier
|
||||
* periodically sends multiple Multicast-Address-Specific Queries to that
|
||||
* multicast address. If no Reports for the address are received from the
|
||||
* link after the maximum response delay in the Multicast-Address-Specific
|
||||
* Queries of the last query has passed, the routers on the link assume
|
||||
* that the address no longer has any listeners there; the address is
|
||||
* therefore deleted from the list and its disappearance is made known to
|
||||
* the multicast routing component.
|
||||
*
|
||||
* Routers in Non-Querier state MUST ignore Done messages.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int mld_done_v1(FAR struct net_driver_s *dev,
|
||||
FAR const struct mld_mcast_listen_done_v1_s *done)
|
||||
{
|
||||
FAR struct ipv6_hdr_s *ipv6 = IPv6BUF;
|
||||
FAR struct mld_group_s *group;
|
||||
|
||||
MLD_STATINCR(g_netstats.mld.done_received);
|
||||
#warning Missing logic
|
||||
return -ENOSYS;
|
||||
|
||||
/* Find the group (or create a new one) using the incoming IP address */
|
||||
|
||||
group = mld_grpfind(dev, ipv6->destipaddr);
|
||||
if (group == NULL)
|
||||
{
|
||||
return -ENOENT; /* REVISIT: Or should it return OK? */
|
||||
}
|
||||
|
||||
/* Ignore the Done message is this is not a Querier */
|
||||
|
||||
if (IS_MLD_QUERIER(group->flags))
|
||||
{
|
||||
/* REVISIT: Here we just remove the group from this list immediately.
|
||||
* The RFC requires that we send Multicast-Address-Specific Queries
|
||||
* repeatedly before doing this to assure that the listener is not
|
||||
* present.
|
||||
*/
|
||||
|
||||
mld_grpfree(dev, group);
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
|
|
@ -132,7 +132,11 @@ FAR struct mld_group_s *mld_grpalloc(FAR struct net_driver_s *dev,
|
|||
group->wdog = wd_create();
|
||||
DEBUGASSERT(group->wdog);
|
||||
|
||||
/* Interrupts must be disabled in order to modify the group list */
|
||||
/* All routers start up as a Querier on each of their attached links. */
|
||||
|
||||
SET_MLD_QUERIER(group->flags);
|
||||
|
||||
/* The network must be locked in order to modify the group list */
|
||||
|
||||
net_lock();
|
||||
|
||||
|
|
|
@ -105,34 +105,7 @@
|
|||
*
|
||||
* State transition diagram for a router in Non-Querier state is
|
||||
* similar, but non-Queriers do not send any messages and are only
|
||||
* driven by message reception.
|
||||
*
|
||||
* ________________
|
||||
* | |
|
||||
* | |
|
||||
* timer expired| |timer expired
|
||||
* (notify routing -)| No Listeners |(notify routing -)
|
||||
* --------->| Present |<---------
|
||||
* | | | |
|
||||
* | | | |
|
||||
* | | | |
|
||||
* | |________________| |
|
||||
* | | |
|
||||
* | |report received |
|
||||
* | |(notify routing +,|
|
||||
* | | start timer) |
|
||||
* ________|________ | ________|________
|
||||
* | |<--------- | |
|
||||
* | | report received | |
|
||||
* | | (start timer) | |
|
||||
* | Listeners |<-------------------| Checking |
|
||||
* | Present | m-a-s query rec'd | Listeners |
|
||||
* | | (start timer*) | |
|
||||
* ---->| |------------------->| |
|
||||
* | |_________________| |_________________|
|
||||
* | report received |
|
||||
* | (start timer) |
|
||||
* -----------------
|
||||
* driven by message reception (See RFC 2710/3810 or net/mld.h).
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
|
@ -193,9 +166,11 @@ int mld_joingroup(FAR const struct ipv6_mreq *mrec)
|
|||
MLD_STATINCR(g_netstats.mld.report_sched);
|
||||
mld_waitmsg(group, ICMPV6_MCAST_LISTEN_REPORT_V1);
|
||||
|
||||
/* And start the timer at 10*100 msec */
|
||||
/* And start the timer at 1 second */
|
||||
|
||||
mld_starttimer(group, 10);
|
||||
SET_MLD_STARTUP(group->flags);
|
||||
group->count = MLD_UNSOLREPORT_COUNT - 1;
|
||||
mld_starttimer(group, MSEC2TICK(MLD_UNSOLREPORT_MSEC));
|
||||
|
||||
/* Add the group (MAC) address to the Ethernet drivers MAC filter list */
|
||||
|
||||
|
|
|
@ -107,34 +107,7 @@
|
|||
*
|
||||
* State transition diagram for a router in Non-Querier state is
|
||||
* similar, but non-Queriers do not send any messages and are only
|
||||
* driven by message reception.
|
||||
*
|
||||
* ________________
|
||||
* | |
|
||||
* | |
|
||||
* timer expired| |timer expired
|
||||
* (notify routing -)| No Listeners |(notify routing -)
|
||||
* --------->| Present |<---------
|
||||
* | | | |
|
||||
* | | | |
|
||||
* | | | |
|
||||
* | |________________| |
|
||||
* | | |
|
||||
* | |report received |
|
||||
* | |(notify routing +,|
|
||||
* | | start timer) |
|
||||
* ________|________ | ________|________
|
||||
* | |<--------- | |
|
||||
* | | report received | |
|
||||
* | | (start timer) | |
|
||||
* | Listeners |<-------------------| Checking |
|
||||
* | Present | m-a-s query rec'd | Listeners |
|
||||
* | | (start timer*) | |
|
||||
* ---->| |------------------->| |
|
||||
* | |_________________| |_________________|
|
||||
* | report received |
|
||||
* | (start timer) |
|
||||
* -----------------
|
||||
* driven by message reception (See RFC 2710/3810 or net/mld.h).
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
|
|
|
@ -64,13 +64,13 @@
|
|||
*
|
||||
****************************************************************************/
|
||||
|
||||
void mld_schedmsg(FAR struct mld_group_s *group, uint8_t msgid)
|
||||
void mld_schedmsg(FAR struct mld_group_s *group, uint8_t msgtype)
|
||||
{
|
||||
/* The following should be atomic */
|
||||
|
||||
net_lock();
|
||||
DEBUGASSERT(!IS_MLD_SCHEDMSG(group->flags));
|
||||
group->msgid = msgid;
|
||||
group->msgtype = msgtype;
|
||||
SET_MLD_SCHEDMSG(group->flags);
|
||||
net_unlock();
|
||||
}
|
||||
|
@ -84,7 +84,7 @@ void mld_schedmsg(FAR struct mld_group_s *group, uint8_t msgid)
|
|||
*
|
||||
****************************************************************************/
|
||||
|
||||
void mld_waitmsg(FAR struct mld_group_s *group, uint8_t msgid)
|
||||
void mld_waitmsg(FAR struct mld_group_s *group, uint8_t msgtype)
|
||||
{
|
||||
int ret;
|
||||
|
||||
|
@ -93,7 +93,7 @@ void mld_waitmsg(FAR struct mld_group_s *group, uint8_t msgid)
|
|||
net_lock();
|
||||
DEBUGASSERT(!IS_MLD_WAITMSG(group->flags));
|
||||
SET_MLD_WAITMSG(group->flags);
|
||||
mld_schedmsg(group, msgid);
|
||||
mld_schedmsg(group, msgtype);
|
||||
|
||||
/* Then wait for the message to be sent */
|
||||
|
||||
|
|
|
@ -69,40 +69,47 @@
|
|||
****************************************************************************/
|
||||
|
||||
static inline void mld_sched_send(FAR struct net_driver_s *dev,
|
||||
FAR struct mld_group_s *group)
|
||||
FAR struct mld_group_s *group)
|
||||
{
|
||||
const net_ipv6addr_t *dest;
|
||||
|
||||
/* Check what kind of message we need to send. There are only two
|
||||
/* Check what kind of message we need to send. There are only three
|
||||
* possibilities:
|
||||
*/
|
||||
|
||||
if (group->msgid == ICMPV6_MCAST_LISTEN_REPORT_V1)
|
||||
if (group->msgtype == MLD_SEND_GENQUERY)
|
||||
{
|
||||
dest = &g_ipv6_allrouters;
|
||||
|
||||
ninfo("Send General Query, flags=%02x\n", group->flags);
|
||||
ninfo("destipaddr: %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
|
||||
ipv6->destipaddr[0], ipv6->destipaddr[1], ipv6->destipaddr[2],
|
||||
ipv6->destipaddr[3], ipv6->destipaddr[4], ipv6->destipaddr[5],
|
||||
ipv6->destipaddr[6], ipv6->destipaddr[7]);
|
||||
}
|
||||
else if (group->msgtype == MLD_SEND_REPORT)
|
||||
{
|
||||
dest = &group->grpaddr;
|
||||
|
||||
ninfo("Send ICMPV6_MCAST_LISTEN_REPORT_V1, flags=%02x\n", group->flags);
|
||||
ninfo("Send Report, flags=%02x\n", group->flags);
|
||||
ninfo("destipaddr: %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
|
||||
ipv6->destipaddr[0], ipv6->destipaddr[1], ipv6->destipaddr[2],
|
||||
ipv6->destipaddr[3], ipv6->destipaddr[4], ipv6->destipaddr[5],
|
||||
ipv6->destipaddr[6], ipv6->destipaddr[7]);
|
||||
|
||||
MLD_STATINCR(g_netstats.mld.report_sched);
|
||||
SET_MLD_LASTREPORT(group->flags); /* Remember we were the last to report */
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUGASSERT(group->msgid == ICMPV6_MCAST_LISTEN_DONE_V1);
|
||||
DEBUGASSERT(group->msgtype == MLD_SEND_DONE);
|
||||
|
||||
dest = &g_ipv6_allrouters;
|
||||
|
||||
ninfo("Send ICMPV6_MCAST_LISTEN_DONE_V1, flags=%02x\n", group->flags);
|
||||
ninfo("Send Done message, flags=%02x\n", group->flags);
|
||||
ninfo("destipaddr: %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
|
||||
ipv6->destipaddr[0], ipv6->destipaddr[1], ipv6->destipaddr[2],
|
||||
ipv6->destipaddr[3], ipv6->destipaddr[4], ipv6->destipaddr[5],
|
||||
ipv6->destipaddr[6], ipv6->destipaddr[7]);
|
||||
|
||||
MLD_STATINCR(g_netstats.mld.done_sched);
|
||||
}
|
||||
|
||||
/* Send the message */
|
||||
|
@ -112,7 +119,7 @@ static inline void mld_sched_send(FAR struct net_driver_s *dev,
|
|||
/* Indicate that the message has been sent */
|
||||
|
||||
CLR_MLD_SCHEDMSG(group->flags);
|
||||
group->msgid = 0;
|
||||
group->msgtype = 0;
|
||||
|
||||
/* If there is a thread waiting fore the message to be sent, wake it up */
|
||||
|
||||
|
|
|
@ -57,6 +57,109 @@
|
|||
|
||||
#define IPv6BUF ((FAR struct ipv6_hdr_s *)&dev->d_buf[NET_LL_HDRLEN(dev)])
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: mld_mrc2mrd
|
||||
*
|
||||
* Description:
|
||||
* Convert the MLD Maximum Response Code (MRC) to the Maximum Response
|
||||
* Delay (MRD) in units of system clock ticks.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static clock_t mld_mrc2mrd(uint16_t mrc)
|
||||
{
|
||||
uint32_t mrd; /* Units of milliseconds */
|
||||
|
||||
/* If bit 15 is not set (i.e., mrc < 32768), then no conversion is required. */
|
||||
|
||||
if (mrc < 32768)
|
||||
{
|
||||
mrd = mrc;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Conversion required */
|
||||
|
||||
mrd = MLD_MRD_VALUE(mrc);
|
||||
}
|
||||
|
||||
/* Return the MRD in units of clock ticks */
|
||||
|
||||
return MSEC2TICK((clock_t)mrd);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: mld_cmpaddr
|
||||
*
|
||||
* Description:
|
||||
* Perform a numerical comparison of the IPv6 Source Address and the IPv6
|
||||
* address of the link. Return true if the source address is less than
|
||||
* the link address.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static bool mld_cmpaddr(FAR struct net_driver_s *dev,
|
||||
const net_ipv6addr_t srcaddr)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
if (srcaddr[i] < dev->d_ipv6addr[i])
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: mld_check_querier
|
||||
*
|
||||
* Description:
|
||||
* Perform a numerical comparison of the IPv6 Source Address and the IPv6
|
||||
* address of the link. Return true if the source address is less than
|
||||
* the link address.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void mld_check_querier(FAR struct net_driver_s *dev,
|
||||
FAR struct ipv6_hdr_s *ipv6,
|
||||
FAR struct mld_group_s *member,
|
||||
uint16_t mrc)
|
||||
{
|
||||
clock_t ticks;
|
||||
|
||||
/* Check if this member is a Querier */
|
||||
|
||||
if (IS_MLD_QUERIER(member->flags))
|
||||
{
|
||||
/* This is a querier, check if the IPv6 source address is numerically
|
||||
* less than the IPv6 address assigned to this link.
|
||||
*/
|
||||
|
||||
if (mld_cmpaddr(dev, ipv6->srcipaddr))
|
||||
{
|
||||
/* This is a querier, then switch to non-querier and set a timeout.
|
||||
* If additional queries are received within this timeout period,
|
||||
* then we need to revert to Querier.
|
||||
*/
|
||||
|
||||
ticks = mld_mrc2mrd(mrc);
|
||||
if (mld_cmptimer(member, ticks))
|
||||
{
|
||||
mld_starttimer(member, ticks);
|
||||
CLR_MLD_QUERIER(member->flags);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
@ -65,7 +168,22 @@
|
|||
* Name: mld_query
|
||||
*
|
||||
* Description:
|
||||
* Called from icmpv6_input() when a Multicast Listener Query is received.
|
||||
* Called from icmpv6_input() when a Multicast Listener Query is received.
|
||||
*
|
||||
* A router may assume one of two roles: Querier or Non-Querier. There is
|
||||
* normally only one Querier per link. All routers start up as a Querier
|
||||
* on each of their attached links. If a router hears a Query message
|
||||
* whose IPv6 Source Address is numerically less than its own selected
|
||||
* address for that link, it MUST become a Non-Querier on that link. If a
|
||||
* delay passes without receiving, from a particular attached link, any
|
||||
* Queries from a router with an address less than its own, a router
|
||||
* resumes the role of Querier on that link.
|
||||
*
|
||||
* A Querier for a link periodically sends a General Query on that link,
|
||||
* to solicit reports of all multicast addresses of interest on that link.
|
||||
* On startup, a router SHOULD send multiple General Queries spaced closely
|
||||
* together Interval] on all attached links in order to quickly and
|
||||
* reliably discover the presence of multicast listeners on those links.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
|
@ -74,7 +192,7 @@ int mld_query(FAR struct net_driver_s *dev,
|
|||
{
|
||||
FAR struct ipv6_hdr_s *ipv6 = IPv6BUF;
|
||||
FAR struct mld_group_s *group;
|
||||
unsigned int ticks;
|
||||
uint16_t mrc;
|
||||
bool unspec;
|
||||
|
||||
ninfo("Multicast Listener Query\n");
|
||||
|
@ -101,6 +219,7 @@ int mld_query(FAR struct net_driver_s *dev,
|
|||
/* Check if the query was sent to all systems */
|
||||
|
||||
unspec = net_ipv6addr_cmp(query->grpaddr, g_ipv6_unspecaddr);
|
||||
mrc = NTOHS(query->mrc);
|
||||
|
||||
if (net_ipv6addr_cmp(ipv6->destipaddr, g_ipv6_allnodes))
|
||||
{
|
||||
|
@ -141,40 +260,41 @@ int mld_query(FAR struct net_driver_s *dev,
|
|||
|
||||
if (!net_ipv6addr_cmp(member->grpaddr, g_ipv6_allnodes))
|
||||
{
|
||||
ticks = net_dsec2tick((int)query->mrc);
|
||||
if (IS_MLD_IDLEMEMBER(member->flags) ||
|
||||
mld_cmptimer(member, ticks))
|
||||
{
|
||||
mld_startticks(member, ticks);
|
||||
CLR_MLD_IDLEMEMBER(member->flags);
|
||||
}
|
||||
/* REVISIT: Missing logic. No action is taken on the query. */
|
||||
|
||||
mld_check_querier(dev, ipv6, member, mrc);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!unspec && query->nsources == 0)
|
||||
{
|
||||
ninfo("Multicast Address Specific Query\n");
|
||||
|
||||
/* We first need to re-lookup the group since we used dest last time.
|
||||
* Use the incoming IPaddress!
|
||||
*/
|
||||
|
||||
MLD_STATINCR(g_netstats.mld.mas_query_received);
|
||||
|
||||
group = mld_grpallocfind(dev, query->grpaddr);
|
||||
ticks = net_dsec2tick((int)query->mrc);
|
||||
/* We first need to re-lookup the group since we used the incoming
|
||||
* dest last time. Use the group address in the query.
|
||||
*/
|
||||
|
||||
if (IS_MLD_IDLEMEMBER(group->flags) || mld_cmptimer(group, ticks))
|
||||
{
|
||||
mld_startticks(group, ticks);
|
||||
CLR_MLD_IDLEMEMBER(group->flags);
|
||||
}
|
||||
group = mld_grpallocfind(dev, query->grpaddr);
|
||||
|
||||
/* REVISIT: Missing logic. No action is taken on the query. */
|
||||
|
||||
mld_check_querier(dev, ipv6, group, mrc);
|
||||
}
|
||||
else
|
||||
{
|
||||
ninfo("Multicast Address and Source Specific Query\n");
|
||||
MLD_STATINCR(g_netstats.mld.massq_query_received);
|
||||
#warning Missing logic
|
||||
|
||||
/* We first need to re-lookup the group since we used the incoming
|
||||
* dest last time. Use the group address in the query.
|
||||
*/
|
||||
|
||||
group = mld_grpallocfind(dev, query->grpaddr);
|
||||
|
||||
/* REVISIT: Missing logic. No action is taken on the query. */
|
||||
|
||||
mld_check_querier(dev, ipv6, group, mrc);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -185,14 +305,7 @@ int mld_query(FAR struct net_driver_s *dev,
|
|||
ninfo("Unicast query\n");
|
||||
MLD_STATINCR(g_netstats.mld.ucast_query_received);
|
||||
|
||||
ninfo("Query to a specific group with the group address as destination\n");
|
||||
|
||||
ticks = net_dsec2tick((int)query->mrc);
|
||||
if (IS_MLD_IDLEMEMBER(group->flags) || mld_cmptimer(group, ticks))
|
||||
{
|
||||
mld_startticks(group, ticks);
|
||||
CLR_MLD_IDLEMEMBER(group->flags);
|
||||
}
|
||||
mld_check_querier(dev, ipv6, group, mrc);
|
||||
}
|
||||
|
||||
return OK;
|
||||
|
|
|
@ -65,6 +65,22 @@
|
|||
* Called from icmpv6_input() when a Version 1 or Version 2 Multicast
|
||||
* Listener Report is received.
|
||||
*
|
||||
* If a node receives another node's Report from an interface for a
|
||||
* multicast address while it has a timer running for that same address
|
||||
* on that interface, it stops its timer and does not send a Report for
|
||||
* that address, thus suppressing duplicate reports on the link.
|
||||
*
|
||||
* When a router receives a Report from a link, if the reported address
|
||||
* is not already present in the router's list of multicast address
|
||||
* having listeners on that link, the reported address is added to the
|
||||
* list, its timer is set, and its appearance is made known to the router's
|
||||
* multicast routing component. If a Report is received for a multicast
|
||||
* address that is already present in the router's list, the timer for that
|
||||
* address is reset. If an address's timer expires, it is assumed that
|
||||
* there are no longer any listeners for that address present on the link,
|
||||
* so it is deleted from the list and its disappearance is made known to
|
||||
* the multicast routing component.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int mld_report_v1(FAR struct net_driver_s *dev,
|
||||
|
@ -90,12 +106,11 @@ int mld_report_v1(FAR struct net_driver_s *dev,
|
|||
return -ENOENT;
|
||||
}
|
||||
|
||||
if (!IS_MLD_IDLEMEMBER(group->flags))
|
||||
{
|
||||
/* This is on a specific group we have already looked up */
|
||||
/* If we are a Querier, then reset the timer for that group. */
|
||||
|
||||
wd_cancel(group->wdog);
|
||||
SET_MLD_IDLEMEMBER(group->flags);
|
||||
if (IS_MLD_QUERIER(group->flags))
|
||||
{
|
||||
mld_starttimer(group, MSEC2TICK(MLD_UNSOLREPORT_MSEC));
|
||||
CLR_MLD_LASTREPORT(group->flags);
|
||||
}
|
||||
|
||||
|
@ -106,9 +121,16 @@ int mld_report_v1(FAR struct net_driver_s *dev,
|
|||
* Name: mld_report_v2
|
||||
*
|
||||
* Description:
|
||||
* Called from icmpv6_input() when a Version 2 Multicast Listener Report is
|
||||
* Called from icmpv6_input() when a Version 2 Multicast Listener Report is
|
||||
* received.
|
||||
*
|
||||
* Upon reception of an MLD message that contains a Report, the router
|
||||
* checks if the source address of the message is a valid link-local
|
||||
* address, if the Hop Limit is set to 1, and if the Router Alert option
|
||||
* is present in the Hop-By-Hop Options header of the IPv6 packet. If
|
||||
* any of these checks fails, the packet is dropped. If the validity of
|
||||
* the MLD message is verified, the router starts to process the Report.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int mld_report_v2(FAR struct net_driver_s *dev,
|
||||
|
@ -125,7 +147,25 @@ int mld_report_v2(FAR struct net_driver_s *dev,
|
|||
|
||||
MLD_STATINCR(g_netstats.mld.v2report_received);
|
||||
|
||||
/* Find the group (or create a new one) using the incoming IP address */
|
||||
/* Check for a valid report
|
||||
*
|
||||
* REVISIT: Missing required test for Router Alert option. That has
|
||||
* already been handled in ipv6_input() but is not available here
|
||||
* unless we re-parse the extension options.
|
||||
*/
|
||||
|
||||
if (!net_is_addr_linklocal(ipv6->srcipaddr) || ipv6->ttl != 1)
|
||||
{
|
||||
nwarn("WARNING: Bad Report, ttl=%u\n", ipv6->ttl);
|
||||
nwarn(" srcipaddr: %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
|
||||
ipv6->srcipaddr[0], ipv6->srcipaddr[1], ipv6->srcipaddr[2],
|
||||
ipv6->srcipaddr[3], ipv6->srcipaddr[4], ipv6->srcipaddr[5],
|
||||
ipv6->srcipaddr[6], ipv6->srcipaddr[7]);
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Find the group (or create a new one) using the incoming IP address */
|
||||
|
||||
group = mld_grpallocfind(dev, ipv6->destipaddr);
|
||||
if (group == NULL)
|
||||
|
@ -134,12 +174,11 @@ int mld_report_v2(FAR struct net_driver_s *dev,
|
|||
return -ENOENT;
|
||||
}
|
||||
|
||||
if (!IS_MLD_IDLEMEMBER(group->flags))
|
||||
{
|
||||
/* This is on a specific group we have already looked up */
|
||||
/* If we are a Querier, then reset the timer for that group. */
|
||||
|
||||
wd_cancel(group->wdog);
|
||||
SET_MLD_IDLEMEMBER(group->flags);
|
||||
if (IS_MLD_QUERIER(group->flags))
|
||||
{
|
||||
mld_starttimer(group, MSEC2TICK(MLD_UNSOLREPORT_MSEC));
|
||||
CLR_MLD_LASTREPORT(group->flags);
|
||||
}
|
||||
|
||||
|
|
|
@ -80,6 +80,8 @@
|
|||
#define RABUF ((FAR struct ipv6_router_alert_s *) \
|
||||
&dev->d_buf[NET_LL_HDRLEN(dev)] + IPv6_HDRLEN)
|
||||
#define RASIZE sizeof(struct ipv6_router_alert_s)
|
||||
#define QUERYBUF ((FAR struct mld_mcast_listen_query_s *) \
|
||||
&dev->d_buf[NET_LL_HDRLEN(dev)] + IPv6_HDRLEN + RASIZE)
|
||||
#define REPORTBUF ((FAR struct mld_mcast_listen_report_v1_s *) \
|
||||
&dev->d_buf[NET_LL_HDRLEN(dev)] + IPv6_HDRLEN + RASIZE)
|
||||
#define DONEBUF ((FAR struct mld_mcast_listen_done_v1_s *) \
|
||||
|
@ -117,7 +119,7 @@ void mld_send(FAR struct net_driver_s *dev, FAR struct mld_group_s *group,
|
|||
FAR struct ipv6_router_alert_s *ra;
|
||||
unsigned int mldsize;
|
||||
|
||||
ninfo("msgid: %02x \n", group->msgid);
|
||||
ninfo("msgtype: %02x \n", group->msgtype);
|
||||
ninfo("destipaddr: %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
|
||||
destipaddr[0], destipaddr[1], destipaddr[2], destipaddr[3],
|
||||
destipaddr[4], destipaddr[5], destipaddr[6], destipaddr[7]);
|
||||
|
@ -131,20 +133,20 @@ void mld_send(FAR struct net_driver_s *dev, FAR struct mld_group_s *group,
|
|||
* This will change.
|
||||
*/
|
||||
|
||||
switch (group->msgid)
|
||||
switch (group->msgtype)
|
||||
{
|
||||
case ICMPV6_MCAST_LISTEN_REPORT_V1:
|
||||
case MLD_SEND_GENQUERY: /* Send General Query */
|
||||
mldsize = SIZEOF_MLD_MCAST_LISTEN_QUERY_S(0);
|
||||
break;
|
||||
|
||||
case MLD_SEND_REPORT: /* Send Unsolicited report */
|
||||
mldsize = sizeof(struct mld_mcast_listen_report_v1_s);
|
||||
break;
|
||||
|
||||
case ICMPV6_MCAST_LISTEN_DONE_V1:
|
||||
case MLD_SEND_DONE: /* Send Done message */
|
||||
mldsize = sizeof(struct mld_mcast_listen_done_v1_s);
|
||||
break;
|
||||
|
||||
/* Not yet supported */
|
||||
|
||||
case ICMPV6_MCAST_LISTEN_QUERY:
|
||||
case ICMPV6_MCAST_LISTEN_REPORT_V2:
|
||||
default:
|
||||
DEBUGPANIC();
|
||||
return;
|
||||
|
@ -192,17 +194,42 @@ void mld_send(FAR struct net_driver_s *dev, FAR struct mld_group_s *group,
|
|||
* router alert)
|
||||
*/
|
||||
|
||||
switch (group->msgid)
|
||||
switch (group->msgtype)
|
||||
{
|
||||
case ICMPV6_MCAST_LISTEN_REPORT_V1:
|
||||
case MLD_SEND_GENQUERY:
|
||||
{
|
||||
FAR struct mld_mcast_listen_query_s *query = QUERYBUF;
|
||||
|
||||
/* Initializer the Query payload. In a General Query, both the
|
||||
* Multicast Address field and the Number of Sources (N)
|
||||
* field are zero.
|
||||
*/
|
||||
|
||||
memset(query, 0, sizeof(struct mld_mcast_listen_report_v1_s));
|
||||
net_ipv6addr_hdrcopy(query->grpaddr, &group->grpaddr);
|
||||
query->type = ICMPV6_MCAST_LISTEN_QUERY;
|
||||
query->mrc = MLD_QRESP_MSEC;
|
||||
query->flags = MLD_ROBUSTNESS;
|
||||
query->qqic = MLD_QRESP_SEC;
|
||||
|
||||
/* Calculate the ICMPv6 checksum. */
|
||||
|
||||
query->chksum = 0;
|
||||
query->chksum = ~icmpv6_chksum(dev);
|
||||
|
||||
MLD_STATINCR(g_netstats.mld.query_sent);
|
||||
}
|
||||
break;
|
||||
|
||||
case MLD_SEND_REPORT:
|
||||
{
|
||||
FAR struct mld_mcast_listen_report_v1_s *report = REPORTBUF;
|
||||
|
||||
/* Initializer the Report payload */
|
||||
|
||||
memset(report, 0, sizeof(struct mld_mcast_listen_report_v1_s));
|
||||
report->type = ICMPV6_MCAST_LISTEN_REPORT_V1;
|
||||
net_ipv6addr_hdrcopy(report->mcastaddr, &group->grpaddr);
|
||||
report->type = ICMPV6_MCAST_LISTEN_REPORT_V1;
|
||||
|
||||
/* Calculate the ICMPv6 checksum. */
|
||||
|
||||
|
@ -213,7 +240,7 @@ void mld_send(FAR struct net_driver_s *dev, FAR struct mld_group_s *group,
|
|||
}
|
||||
break;
|
||||
|
||||
case ICMPV6_MCAST_LISTEN_DONE_V1:
|
||||
case MLD_SEND_DONE:
|
||||
{
|
||||
FAR struct mld_mcast_listen_done_v1_s *done = DONEBUF;
|
||||
|
||||
|
|
|
@ -60,27 +60,27 @@
|
|||
|
||||
/* Debug ********************************************************************/
|
||||
|
||||
#undef MLD_GTMRDEBUG /* Define to enable detailed MLD group debug */
|
||||
#undef MLD_MTMRDEBUG /* Define to enable detailed MLD group debug */
|
||||
|
||||
#ifndef CONFIG_NET_MLD
|
||||
# undef MLD_GTMRDEBUG
|
||||
# undef MLD_MTMRDEBUG
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_CPP_HAVE_VARARGS
|
||||
# ifdef MLD_GTMRDEBUG
|
||||
# define gtmrerr(format, ...) nerr(format, ##__VA_ARGS__)
|
||||
# define gtmrinfo(format, ...) ninfo(format, ##__VA_ARGS__)
|
||||
# ifdef MLD_MTMRDEBUG
|
||||
# define mtmrerr(format, ...) nerr(format, ##__VA_ARGS__)
|
||||
# define mtmrinfo(format, ...) ninfo(format, ##__VA_ARGS__)
|
||||
# else
|
||||
# define gtmrerr(x...)
|
||||
# define gtmrinfo(x...)
|
||||
# define mtmrerr(x...)
|
||||
# define mtmrinfo(x...)
|
||||
# endif
|
||||
#else
|
||||
# ifdef MLD_GTMRDEBUG
|
||||
# define gtmrerr nerr
|
||||
# define gtmrinfo ninfo
|
||||
# ifdef MLD_MTMRDEBUG
|
||||
# define mtmrerr nerr
|
||||
# define mtmrinfo ninfo
|
||||
# else
|
||||
# define gtmrerr (void)
|
||||
# define gtmrinfo (void)
|
||||
# define mtmrerr (void)
|
||||
# define mtmrinfo (void)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
@ -110,30 +110,53 @@ static void mld_timeout(int argc, uint32_t arg, ...)
|
|||
group = (FAR struct mld_group_s *)arg;
|
||||
DEBUGASSERT(argc == 1 && group);
|
||||
|
||||
/* If the group exists and is no an IDLE MEMBER, then it must be a DELAYING
|
||||
* member. Race conditions are avoided because (1) the timer is not started
|
||||
* until after the first MLDv2_MEMBERSHIP_REPORT during the join, and (2)
|
||||
* the timer is canceled before sending the ICMPV6_MCAST_LISTEN_DONE_V1
|
||||
* during a leave.
|
||||
*/
|
||||
/* Check if this a new join to the multicast group. */
|
||||
|
||||
if (!IS_MLD_IDLEMEMBER(group->flags))
|
||||
if (IS_MLD_STARTUP(group->flags))
|
||||
{
|
||||
/* Schedule (and forget) the Report. NOTE: Since we are executing
|
||||
* from a timer interrupt, we cannot wait for the message to be sent.
|
||||
*/
|
||||
/* Schedule (and forget) the Report. */
|
||||
|
||||
MLD_STATINCR(g_netstats.mld.report_sched);
|
||||
mld_schedmsg(group, ICMPV6_MCAST_LISTEN_REPORT_V1);
|
||||
mld_schedmsg(group, MLD_SEND_REPORT);
|
||||
|
||||
/* Also note: The Report is sent at most two times because the timer
|
||||
* is not reset here. Hmm.. does this mean that the group is stranded
|
||||
* if both reports were lost? This is consistent with the
|
||||
* RFC that states: "To cover the possibility of the initial Report
|
||||
* being lost or damaged, it is recommended that it be repeated once
|
||||
* or twice after short delays [Unsolicited Report Interval]...."
|
||||
* (RFC 2710).
|
||||
/* Send the report until the unsolicited report count goes to zero
|
||||
* then terminate the start-up sequence.
|
||||
*/
|
||||
|
||||
if (group->count > 1)
|
||||
{
|
||||
/* Decrement the count and restart the timer */
|
||||
|
||||
group->count--;
|
||||
mld_starttimer(group, MSEC2TICK(MLD_UNSOLREPORT_MSEC));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Terminate the start-up sequence */
|
||||
|
||||
CLR_MLD_STARTUP(group->flags);
|
||||
|
||||
/* If in Querier mode, start the Querier timer */
|
||||
|
||||
if (IS_MLD_QUERIER(group->flags))
|
||||
{
|
||||
mld_starttimer(group, MSEC2TICK(MLD_QUERY_MSEC));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if this is querier */
|
||||
|
||||
else if (IS_MLD_QUERIER(group->flags))
|
||||
{
|
||||
/* Schedule (and forget) the general query. */
|
||||
|
||||
MLD_STATINCR(g_netstats.mld.query_sched);
|
||||
mld_schedmsg(group, MLD_SEND_GENQUERY);
|
||||
|
||||
/* Restart the Querier timer */
|
||||
|
||||
mld_starttimer(group, MSEC2TICK(MLD_QUERY_MSEC));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -142,23 +165,23 @@ static void mld_timeout(int argc, uint32_t arg, ...)
|
|||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: mld_startticks and mld_starttimer
|
||||
* Name: mld_starttimer
|
||||
*
|
||||
* Description:
|
||||
* Start the MLD timer with differing time units (ticks or deciseconds).
|
||||
* Start the MLD timer.
|
||||
*
|
||||
* Assumptions:
|
||||
* This function may be called from most any context.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void mld_startticks(FAR struct mld_group_s *group, unsigned int ticks)
|
||||
void mld_starttimer(FAR struct mld_group_s *group, clock_t ticks)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* Start the timer */
|
||||
|
||||
gtmrinfo("ticks: %d\n", ticks);
|
||||
mtmrinfo("ticks: %ld\n", (unsigned long)ticks);
|
||||
|
||||
ret = wd_start(group->wdog, ticks, mld_timeout, 1, (uint32_t)group);
|
||||
|
||||
|
@ -166,16 +189,6 @@ void mld_startticks(FAR struct mld_group_s *group, unsigned int ticks)
|
|||
UNUSED(ret);
|
||||
}
|
||||
|
||||
void mld_starttimer(FAR struct mld_group_s *group, uint8_t decisecs)
|
||||
{
|
||||
/* Convert the decisec value to system clock ticks and start the timer.
|
||||
* Important!! this should be a random timer from 0 to decisecs
|
||||
*/
|
||||
|
||||
gtmrinfo("decisecs: %d\n", decisecs);
|
||||
mld_startticks(group, net_dsec2tick(decisecs));
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: mld_cmptimer
|
||||
*
|
||||
|
@ -186,7 +199,7 @@ void mld_starttimer(FAR struct mld_group_s *group, uint8_t decisecs)
|
|||
*
|
||||
* Assumptions:
|
||||
* This function may be called from most any context. If true is returned
|
||||
* then the caller must call mld_startticks() to restart the timer
|
||||
* then the caller must call mld_starttimer() to restart the timer
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
|
@ -212,7 +225,7 @@ bool mld_cmptimer(FAR struct mld_group_s *group, int maxticks)
|
|||
* test as well.
|
||||
*/
|
||||
|
||||
gtmrinfo("maxticks: %d remaining: %d\n", maxticks, remaining);
|
||||
mtmrinfo("maxticks: %d remaining: %d\n", maxticks, remaining);
|
||||
if (maxticks > remaining)
|
||||
{
|
||||
/* Cancel the watchdog timer and return true */
|
||||
|
|
Loading…
Reference in a new issue