1
0
Fork 0
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:
Gregory Nutt 2018-11-03 13:45:33 -06:00
parent 46cf69c93e
commit 1c15aa3b2d
14 changed files with 517 additions and 230 deletions

View file

@ -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

View file

@ -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 */

View file

@ -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
****************************************************************************/

View file

@ -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
*
****************************************************************************/

View file

@ -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;
}

View file

@ -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();

View file

@ -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 */

View file

@ -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).
*
****************************************************************************/

View file

@ -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 */

View file

@ -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 */

View file

@ -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;

View file

@ -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);
}

View file

@ -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;

View file

@ -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 */