net/mld: Implement MLDv1 compatibility mode. This completes coding of MLD. MLD is, howeer, still completely untested.
This commit is contained in:
parent
b1a61834d9
commit
9a75a14800
|
@ -271,12 +271,17 @@
|
|||
|
||||
struct mld_mcast_listen_query_s
|
||||
{
|
||||
/* The initial fields are common for MLDv1 and MLDv2 (24-bytes) */
|
||||
|
||||
uint8_t type; /* Message Type: ICMPV6_MCAST_LISTEN_QUERY */
|
||||
uint8_t reserved1; /* Reserved, must be zero on transmission */
|
||||
uint16_t chksum; /* Checksum of ICMP header and data */
|
||||
uint16_t mrc; /* Maximum response code */
|
||||
uint16_t reserved2; /* Reserved, must be zero on transmission */
|
||||
net_ipv6addr_t grpaddr; /* 128-bit IPv6 multicast group address */
|
||||
|
||||
/* These fields apply only to the MLDv2 query */
|
||||
|
||||
uint8_t flags; /* See S and QRV flag definitions */
|
||||
uint8_t qqic; /* Querier's Query Interval Code */
|
||||
uint16_t nsources; /* Number of sources that follow */
|
||||
|
@ -329,7 +334,7 @@ struct mld_mcast_addrec_v2_s
|
|||
#define SIZEOF_MLD_MCAST_ADDREC_V2_S(nsources, auxdatlen) \
|
||||
(sizeof(struct mld_mcast_addrec_v2_s) + \
|
||||
sizeof(net_ipv6addr_t) * ((nsources) - 1) + \
|
||||
(auxdatlen)
|
||||
(auxdatlen))
|
||||
|
||||
struct mld_mcast_listen_report_v2_s
|
||||
{
|
||||
|
@ -348,10 +353,10 @@ struct mld_mcast_listen_report_v2_s
|
|||
* size of each variable length address record (addreclen).
|
||||
*/
|
||||
|
||||
#define SIZEOF_MLD_MCAST_ADDREC_V2_S(addreclen) \
|
||||
#define SIZEOF_MLD_MCAST_LISTEN_REPORT_V2_S(addreclen) \
|
||||
(sizeof(struct mld_mcast_addrec_v2_s) - \
|
||||
sizeof(net_ipv6addr_t) + \
|
||||
(addreclen)
|
||||
(addreclen))
|
||||
|
||||
/* Version 1 Multicast Listener Done (RFC 2710) */
|
||||
|
||||
|
|
|
@ -91,18 +91,20 @@ EXTERN uint16_t g_ipid;
|
|||
/* Well-known IPv6 addresses */
|
||||
|
||||
#ifdef CONFIG_NET_IPv6
|
||||
EXTERN const net_ipv6addr_t g_ipv6_unspecaddr; /* An address of all zeroes */
|
||||
EXTERN const net_ipv6addr_t g_ipv6_allnodes; /* All link local nodes */
|
||||
EXTERN const net_ipv6addr_t g_ipv6_unspecaddr; /* An address of all zeroes */
|
||||
EXTERN const net_ipv6addr_t g_ipv6_allnodes; /* All link local nodes */
|
||||
|
||||
#if defined(CONFIG_NET_ICMPv6_AUTOCONF) || defined(CONFIG_NET_ICMPv6_ROUTER) || \
|
||||
defined(CONFIG_NET_MLD)
|
||||
/* IPv6 Multi-cast IP addresses. See RFC 2375 */
|
||||
|
||||
EXTERN const net_ipv6addr_t g_ipv6_allrouters; /* All link local routers */
|
||||
EXTERN const net_ipv6addr_t g_ipv6_allrouters; /* All link local routers */
|
||||
#ifdef CONFIG_NET_ICMPv6_AUTOCONF
|
||||
EXTERN const net_ipv6addr_t g_ipv6_llnetmask; /* Netmask for local link address */
|
||||
EXTERN const net_ipv6addr_t g_ipv6_llnetmask; /* Netmask for local link address */
|
||||
#endif
|
||||
#ifdef CONFIG_NET_MLD
|
||||
EXTERN const net_ipv6addr_t g_ipv6_allmldv2routers; /* All MLDv2 link local routers */
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_NET_ETHERNET
|
||||
/* IPv6 Multi-cast Ethernet addresses. Formed from the 16-bit prefix:
|
||||
*
|
||||
|
@ -111,8 +113,8 @@ EXTERN const net_ipv6addr_t g_ipv6_llnetmask; /* Netmask for local link addres
|
|||
* and the last 32-bits of the IPv6 IP address
|
||||
*/
|
||||
|
||||
EXTERN const struct ether_addr g_ipv6_ethallnodes; /* All link local nodes */
|
||||
EXTERN const struct ether_addr g_ipv6_ethallrouters; /* All link local routers */
|
||||
EXTERN const struct ether_addr g_ipv6_ethallnodes; /* All link local nodes */
|
||||
EXTERN const struct ether_addr g_ipv6_ethallrouters; /* All link local routers */
|
||||
|
||||
#endif /* CONFIG_NET_ETHERNET */
|
||||
#endif /* CONFIG_NET_ICMPv6_AUTOCONF || CONFIG_NET_ICMPv6_ROUTER || CONFIG_NET_MLD */
|
||||
|
|
|
@ -98,6 +98,20 @@ const net_ipv6addr_t g_ipv6_llnetmask = /* Netmask for local link address */
|
|||
};
|
||||
#endif /* CONFIG_NET_ICMPv6_AUTOCONF */
|
||||
|
||||
#ifdef CONFIG_NET_MLD
|
||||
/* Version 2 Multicast Listener Reports are sent with an IP destination
|
||||
* address of FF02:0:0:0:0:0:0:16, to which all MLDv2-capable multicast
|
||||
* routers listen (RFC 3810)
|
||||
*/
|
||||
|
||||
const net_ipv6addr_t g_ipv6_allmldv2routers = /* All MLDv2 link local routers */
|
||||
{
|
||||
HTONS(0xff02),
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
HTONS(0x0016)
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_NET_ETHERNET
|
||||
|
||||
/* IPv6 Multi-cast Ethernet addresses. Formed from the 16-bit prefix:
|
||||
|
|
|
@ -164,8 +164,9 @@ 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 */
|
||||
MLD_SEND_V1REPORT, /* Send MLDv1 Report message */
|
||||
MLD_SEND_V2REPORT, /* Send MLDv2 Report message */
|
||||
MLD_SEND_V1DONE /* Send MLDv1 Done message */
|
||||
};
|
||||
|
||||
/* This structure represents one group member. There is a list of groups
|
||||
|
@ -182,7 +183,8 @@ struct mld_group_s
|
|||
struct mld_group_s *next; /* Implements a singly-linked list */
|
||||
net_ipv6addr_t grpaddr; /* Group IPv6 address */
|
||||
struct work_s work; /* For deferred timeout operations */
|
||||
WDOG_ID wdog; /* WDOG used to detect timeouts */
|
||||
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 */
|
||||
uint8_t ifindex; /* Interface index */
|
||||
uint8_t flags; /* See MLD_ flags definitions */
|
||||
|
@ -427,29 +429,24 @@ int mld_joingroup(FAR const struct ipv6_mreq *mrec);
|
|||
int mld_leavegroup(FAR const struct ipv6_mreq *mrec);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: mld_starttimer
|
||||
* Name: mld_start_polltimer
|
||||
*
|
||||
* Description:
|
||||
* Start the MLD timer with differing time units (ticks or deciseconds).
|
||||
* Start the MLD poll timer.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void mld_starttimer(FAR struct mld_group_s *group, clock_t ticks);
|
||||
void mld_start_polltimer(FAR struct mld_group_s *group, clock_t ticks);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: mld_cmptimer
|
||||
* Name: mld_start_v1timer
|
||||
*
|
||||
* Description:
|
||||
* Compare the timer remaining on the watching timer to the deci-second
|
||||
* 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_starttimer() to
|
||||
* restart the timer
|
||||
* Start the MLDv1 compatibility timer.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
bool mld_cmptimer(FAR struct mld_group_s *group, int maxticks);
|
||||
void mld_start_v1timer(FAR struct mld_group_s *group, clock_t ticks);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: mld_addmcastmac
|
||||
|
|
|
@ -130,10 +130,13 @@ FAR struct mld_group_s *mld_grpalloc(FAR struct net_driver_s *dev,
|
|||
nxsem_init(&group->sem, 0, 0);
|
||||
nxsem_setprotocol(&group->sem, SEM_PRIO_NONE);
|
||||
|
||||
/* Initialize the group timer (but don't start it yet) */
|
||||
/* Initialize the group timers */
|
||||
|
||||
group->wdog = wd_create();
|
||||
DEBUGASSERT(group->wdog);
|
||||
group->polldog = wd_create();
|
||||
DEBUGASSERT(group->polldog);
|
||||
|
||||
group->v1dog = wd_create();
|
||||
DEBUGASSERT(group->v1dog);
|
||||
|
||||
/* Save the interface index */
|
||||
|
||||
|
@ -231,9 +234,10 @@ void mld_grpfree(FAR struct net_driver_s *dev, FAR struct mld_group_s *group)
|
|||
{
|
||||
grpinfo("Free: %p flags: %02x\n", group, group->flags);
|
||||
|
||||
/* Cancel the wdog */
|
||||
/* Cancel the timers */
|
||||
|
||||
wd_cancel(group->wdog);
|
||||
wd_cancel(group->polldog);
|
||||
wd_cancel(group->v1dog);
|
||||
|
||||
/* Remove the group structure from the group list in the device structure */
|
||||
|
||||
|
@ -243,9 +247,10 @@ void mld_grpfree(FAR struct net_driver_s *dev, FAR struct mld_group_s *group)
|
|||
|
||||
(void)nxsem_destroy(&group->sem);
|
||||
|
||||
/* Destroy the wdog */
|
||||
/* Destroy the timers */
|
||||
|
||||
wd_delete(group->wdog);
|
||||
wd_delete(group->polldog);
|
||||
wd_delete(group->v1dog);
|
||||
|
||||
/* Then release the group structure resources. */
|
||||
|
||||
|
|
|
@ -85,6 +85,7 @@ void mld_devinit(struct net_driver_s *dev)
|
|||
|
||||
/* Allow the MLD messages at the MAC level */
|
||||
|
||||
mld_addmcastmac(dev, g_ipv6_allrouters);
|
||||
mld_addmcastmac(dev, g_ipv6_allnodes);
|
||||
mld_addmcastmac(dev, g_ipv6_allrouters);
|
||||
mld_addmcastmac(dev, g_ipv6_allmldv2routers);
|
||||
}
|
||||
|
|
|
@ -132,13 +132,15 @@ int mld_joingroup(FAR const struct ipv6_mreq *mrec)
|
|||
|
||||
MLD_STATINCR(g_netstats.mld.joins);
|
||||
|
||||
/* Send the Version 1 Multicast Listener Report */
|
||||
/* Send the Version 2 Multicast Listener Report (Assumes MLDv2 mode
|
||||
* initially?).
|
||||
*/
|
||||
|
||||
MLD_STATINCR(g_netstats.mld.report_sched);
|
||||
ret = mld_waitmsg(group, MLD_SEND_REPORT);
|
||||
ret = mld_waitmsg(group, MLD_SEND_V2REPORT);
|
||||
if (ret < 0)
|
||||
{
|
||||
nerr("ERROR: Failed to schedule message: %d\n", ret);
|
||||
nerr("ERROR: Failed to schedule Report: %d\n", ret);
|
||||
mld_grpfree(dev, group);
|
||||
return ret;
|
||||
}
|
||||
|
@ -147,7 +149,7 @@ int mld_joingroup(FAR const struct ipv6_mreq *mrec)
|
|||
|
||||
SET_MLD_STARTUP(group->flags);
|
||||
group->count = MLD_UNSOLREPORT_COUNT - 1;
|
||||
mld_starttimer(group, MSEC2TICK(MLD_UNSOLREPORT_MSEC));
|
||||
mld_start_polltimer(group, MSEC2TICK(MLD_UNSOLREPORT_MSEC));
|
||||
|
||||
/* Add the group (MAC) address to the Ethernet drivers MAC filter list */
|
||||
|
||||
|
|
|
@ -122,13 +122,14 @@ int mld_leavegroup(FAR const struct ipv6_mreq *mrec)
|
|||
{
|
||||
ninfo("Leaving group: %p\n", group);
|
||||
|
||||
/* Cancel the timer and discard any queued Reports. Canceling the
|
||||
/* Cancel the timers and discard any queued Reports. Canceling the
|
||||
* timer will prevent any new Reports from being sent; clearing the
|
||||
* flags will discard any pending Reports that could interfere with
|
||||
* leaving the group.
|
||||
*/
|
||||
|
||||
wd_cancel(group->wdog);
|
||||
wd_cancel(group->polldog);
|
||||
wd_cancel(group->v1dog);
|
||||
CLR_MLD_SCHEDMSG(group->flags);
|
||||
CLR_MLD_WAITMSG(group->flags);
|
||||
|
||||
|
@ -139,9 +140,12 @@ int mld_leavegroup(FAR const struct ipv6_mreq *mrec)
|
|||
* LAST REPORT flag. In this case we know that there are other
|
||||
* members of the group and we do not have to send the Done message.
|
||||
*
|
||||
* The router responds to the Done message with a multicast-address-s
|
||||
* pecific (MAS) Query. If any other node responds to the Query with a
|
||||
* The MLDv1 router responds to the Done message with a multicast-address-
|
||||
* specific (MAS) Query. If any other node responds to the Query with a
|
||||
* Report message the there are still listeners present.
|
||||
*
|
||||
* REVISIT: What if we are in MLDv2 mode? There is no Done MLDv2 Done
|
||||
* messages. What should be sent (if anything) instead?
|
||||
*/
|
||||
|
||||
if (IS_MLD_LASTREPORT(group->flags))
|
||||
|
@ -150,7 +154,7 @@ int mld_leavegroup(FAR const struct ipv6_mreq *mrec)
|
|||
|
||||
MLD_STATINCR(g_netstats.mld.done_sched);
|
||||
|
||||
ret = mld_waitmsg(group, MLD_SEND_DONE);
|
||||
ret = mld_waitmsg(group, MLD_SEND_V1DONE);
|
||||
if (ret < 0)
|
||||
{
|
||||
nerr("ERROR: Failed to schedule message: %d\n", ret);
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <assert.h>
|
||||
#include <debug.h>
|
||||
|
||||
|
@ -61,6 +62,97 @@
|
|||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: mld_setup_v1compat
|
||||
*
|
||||
* Description:
|
||||
* If this is for MLDv1 query, then select MLDv1 compatibility mode and
|
||||
* start (or re-start) the compatibility timer. We need to make this
|
||||
* check BEFORE sending the report.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void mld_setup_v1compat(FAR struct mld_group_s *group,
|
||||
FAR const struct mld_mcast_listen_query_s *query,
|
||||
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
|
||||
* an MLDv1 query is received, MLDv2 hosts set their Older Version
|
||||
* Querier Present Timer to [Older Version Querier Present Timeout].
|
||||
*
|
||||
* "This value MUST be ([Robustness Variable] times (the [Query
|
||||
* Interval] in the last Query received)) plus ([Query Response
|
||||
* Interval])."
|
||||
*
|
||||
* I am not sure how to do that since the MLDv1 version has no QQI
|
||||
* field. That is an MLDv2 extension.
|
||||
*/
|
||||
|
||||
respmsec = MLD_QUERY_MSEC;
|
||||
#endif
|
||||
|
||||
/* Select MLDv1 compatibility mode (might already be selected) */
|
||||
|
||||
SET_MLD_V1COMPAT(group->flags);
|
||||
|
||||
/* Whenever a host changes its compatibility mode, it cancels all its
|
||||
* pending responses and retransmission timers.
|
||||
*/
|
||||
|
||||
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)));
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: mld_report_msgtype
|
||||
*
|
||||
* Description:
|
||||
* Determine which type of Report to send, MLDv1 or MLDv2, depending on
|
||||
* current state of compatibility mode flag.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static inline uint8_t mld_report_msgtype(FAR struct mld_group_s *group)
|
||||
{
|
||||
if (IS_MLD_V1COMPAT(group->flags))
|
||||
{
|
||||
return MLD_SEND_V1REPORT;
|
||||
}
|
||||
else
|
||||
{
|
||||
return MLD_SEND_V2REPORT;
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: mld_mrc2mrd
|
||||
*
|
||||
|
@ -125,7 +217,7 @@ static bool mld_cmpaddr(FAR struct net_driver_s *dev,
|
|||
*
|
||||
* Description:
|
||||
* Check if we are still the querier for this group (assuming that we are
|
||||
* currently the querier). This comparies the IPv6 Source Address of the
|
||||
* 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.
|
||||
|
@ -152,9 +244,9 @@ static void mld_check_querier(FAR struct net_driver_s *dev,
|
|||
|
||||
if (!IS_MLD_STARTUP(group->flags))
|
||||
{
|
||||
/* Yes.. cancel the timer */
|
||||
/* Yes.. cancel the poll timer */
|
||||
|
||||
wd_cancel(group->wdog);
|
||||
wd_cancel(group->polldog);
|
||||
}
|
||||
|
||||
/* Switch to non-Querier mode */
|
||||
|
@ -196,6 +288,8 @@ int mld_query(FAR struct net_driver_s *dev,
|
|||
{
|
||||
FAR struct ipv6_hdr_s *ipv6 = IPv6BUF;
|
||||
FAR struct mld_group_s *group;
|
||||
unsigned int mldsize;
|
||||
bool mldv1 = false;
|
||||
|
||||
ninfo("Multicast Listener Query\n");
|
||||
|
||||
|
@ -207,6 +301,29 @@ int mld_query(FAR struct net_driver_s *dev,
|
|||
mrc = NTOHS(query->mrc);
|
||||
#endif
|
||||
|
||||
/* The MLD version of a Multicast Listener Query message is determined
|
||||
* as follows:
|
||||
*
|
||||
* MLDv1 Query: length = 24 octets
|
||||
* MLDv2 Query: length >= 28 octets
|
||||
*
|
||||
* Query messages that do not match any of the above conditions (e.g., a
|
||||
* Query of length 26 octets) MUST be silently ignored.
|
||||
*/
|
||||
|
||||
mldsize = ipv6->len[0] << 8 | ipv6->len[1];
|
||||
if (mldsize == sizeof(struct mld_mcast_listen_report_v1_s))
|
||||
{
|
||||
mldv1 = true;
|
||||
}
|
||||
else if (mldsize < SIZEOF_MLD_MCAST_LISTEN_QUERY_S(0))
|
||||
{
|
||||
nwarn("WARNING: Invalid size for MLD query: %u\n", mldsize);
|
||||
|
||||
dev->d_len = 0;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* There are three variants of the Query message (RFC 3810):
|
||||
*
|
||||
* 1. A "General Query" is sent by the Querier to learn which
|
||||
|
@ -267,6 +384,16 @@ int mld_query(FAR struct net_driver_s *dev,
|
|||
/* 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))
|
||||
{
|
||||
nwarn("WARNING: MLDv2 query received in MLDv1 "
|
||||
"compatibility mode\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -290,9 +417,14 @@ int mld_query(FAR struct net_driver_s *dev,
|
|||
|
||||
if (!net_ipv6addr_cmp(member->grpaddr, g_ipv6_allnodes))
|
||||
{
|
||||
|
||||
/* Check MLDv1 compatibility mode */
|
||||
|
||||
mld_setup_v1compat(member, query, mldv1);
|
||||
|
||||
/* Send one report and break out of the loop */
|
||||
|
||||
mld_send(dev, member, MLD_SEND_REPORT);
|
||||
mld_send(dev, member, mld_report_msgtype(member));
|
||||
rptsent = true;
|
||||
break;
|
||||
}
|
||||
|
@ -326,6 +458,13 @@ int mld_query(FAR struct net_driver_s *dev,
|
|||
|
||||
mld_check_querier(dev, ipv6, group);
|
||||
|
||||
/* Warn if we received a MLDv2 query in MLDv1 compatibility mode. */
|
||||
|
||||
if (!mldv1 && IS_MLD_V1COMPAT(group->flags))
|
||||
{
|
||||
nwarn("WARNING: MLDv2 query received in MLDv1 compatibility mode\n");
|
||||
}
|
||||
|
||||
/* Check for Multicast Address Specific Query */
|
||||
|
||||
if (net_ipv6addr_cmp(ipv6->destipaddr, g_ipv6_allrouters))
|
||||
|
@ -341,9 +480,13 @@ int mld_query(FAR struct net_driver_s *dev,
|
|||
MLD_STATINCR(g_netstats.mld.massq_query_received);
|
||||
}
|
||||
|
||||
/* Check MLDv1 compatibility mode */
|
||||
|
||||
mld_setup_v1compat(group, query, mldv1);
|
||||
|
||||
/* Send the report */
|
||||
|
||||
mld_send(dev, group, MLD_SEND_REPORT);
|
||||
mld_send(dev, group, mld_report_msgtype(group));
|
||||
}
|
||||
|
||||
/* Not sent to all systems. Check for Unicast General Query */
|
||||
|
@ -353,9 +496,13 @@ int mld_query(FAR struct net_driver_s *dev,
|
|||
ninfo("Unicast query\n");
|
||||
MLD_STATINCR(g_netstats.mld.ucast_query_received);
|
||||
|
||||
/* Check MLDv1 compatibility mode */
|
||||
|
||||
mld_setup_v1compat(group, query, mldv1);
|
||||
|
||||
/* Send the report */
|
||||
|
||||
mld_send(dev, group, MLD_SEND_REPORT);
|
||||
mld_send(dev, group, mld_report_msgtype(group));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -48,12 +48,6 @@
|
|||
#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)])
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
@ -67,9 +61,8 @@
|
|||
*
|
||||
****************************************************************************/
|
||||
|
||||
int mld_report(FAR struct net_driver_s *dev)
|
||||
int mld_report(FAR struct net_driver_s *dev, FAR const net_ipv6addr_t grpaddr)
|
||||
{
|
||||
FAR struct ipv6_hdr_s *ipv6 = IPv6BUF;
|
||||
FAR struct mld_group_s *group;
|
||||
|
||||
/* Reports are send to the group multicast address. Hence, the IPv6
|
||||
|
@ -77,9 +70,8 @@ int mld_report(FAR struct net_driver_s *dev)
|
|||
*/
|
||||
|
||||
ninfo("grpaddr: %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]);
|
||||
grpaddr[0], grpaddr[1], grpaddr[2], grpaddr[3],
|
||||
grpaddr[4], grpaddr[5], grpaddr[6], grpaddr[7]);
|
||||
|
||||
/* Find the group (or create a new one) using the incoming IP address.
|
||||
* If we are not a router (and I assume we are not), then can ignore
|
||||
|
@ -89,7 +81,7 @@ int mld_report(FAR struct net_driver_s *dev)
|
|||
*/
|
||||
|
||||
#ifdef CONFIG_MLD_ROUTER
|
||||
group = mld_grpallocfind(dev, ipv6->destipaddr);
|
||||
group = mld_grpallocfind(dev, grpaddr);
|
||||
if (group == NULL)
|
||||
{
|
||||
nerr("ERROR: Failed to allocate group\n");
|
||||
|
@ -97,7 +89,7 @@ int mld_report(FAR struct net_driver_s *dev)
|
|||
}
|
||||
|
||||
#else
|
||||
group = mld_grpfind(dev, ipv6->destipaddr);
|
||||
group = mld_grpfind(dev, grpaddr);
|
||||
if (group == NULL)
|
||||
{
|
||||
nwarn("WARNING: Ignoring group. We are not a member\n");
|
||||
|
@ -144,15 +136,20 @@ int mld_report(FAR struct net_driver_s *dev)
|
|||
* so it is deleted from the list and its disappearance is made known to
|
||||
* the multicast routing component.
|
||||
*
|
||||
* A node MUST accept and process any version 1 Report whose IP
|
||||
* Destination Address field contains *any* of the IPv6 addresses (unicast
|
||||
* or multicast) assigned to the interface on which the Report arrives.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int mld_report_v1(FAR struct net_driver_s *dev,
|
||||
FAR const struct mld_mcast_listen_report_v1_s *report)
|
||||
{
|
||||
ninfo("Version 1 Multicast Listener Report\n");
|
||||
DEBUGASSERT(dev != NULL && report != NULL);
|
||||
|
||||
MLD_STATINCR(g_netstats.mld.v1report_received);
|
||||
return mld_report(dev);
|
||||
return mld_report(dev, report->mcastaddr);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
@ -169,13 +166,42 @@ int mld_report_v1(FAR struct net_driver_s *dev,
|
|||
* 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.
|
||||
*
|
||||
* Version 2 Multicast Listener Reports are sent with an IP destination
|
||||
* address of FF02:0:0:0:0:0:0:16, to which all MLDv2-capable multicast
|
||||
* routers listen
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int mld_report_v2(FAR struct net_driver_s *dev,
|
||||
FAR const struct mld_mcast_listen_report_v2_s *report)
|
||||
{
|
||||
int ret = -ENOENT;
|
||||
int i;
|
||||
|
||||
ninfo("Version 2 Multicast Listener Report\n");
|
||||
DEBUGASSERT(dev != NULL && report != NULL);
|
||||
|
||||
MLD_STATINCR(g_netstats.mld.v2report_received);
|
||||
return mld_report(dev);
|
||||
|
||||
for (i = 0; i < report->naddrec; i++)
|
||||
{
|
||||
/* Handle this mcast address in the list */
|
||||
|
||||
int status = mld_report(dev, report->addrec[i].mcast);
|
||||
if (status == OK)
|
||||
{
|
||||
/* Return success if any address in the listed was processed */
|
||||
|
||||
ret = OK;
|
||||
}
|
||||
else if (status != -ENOENT)
|
||||
{
|
||||
/* Any result other than -ENOENT would be a problem */
|
||||
|
||||
ret = status;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -76,16 +76,18 @@
|
|||
|
||||
/* Buffer layout */
|
||||
|
||||
#define IPv6BUF ((FAR struct ipv6_hdr_s *)&dev->d_buf[NET_LL_HDRLEN(dev)])
|
||||
#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 *) \
|
||||
&dev->d_buf[NET_LL_HDRLEN(dev)] + IPv6_HDRLEN + RASIZE)
|
||||
#define IPv6BUF ((FAR struct ipv6_hdr_s *)&dev->d_buf[NET_LL_HDRLEN(dev)])
|
||||
#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 V1REPORTBUF ((FAR struct mld_mcast_listen_report_v1_s *) \
|
||||
&dev->d_buf[NET_LL_HDRLEN(dev)] + IPv6_HDRLEN + RASIZE)
|
||||
#define V2REPORTBUF ((FAR struct mld_mcast_listen_report_v2_s *) \
|
||||
&dev->d_buf[NET_LL_HDRLEN(dev)] + IPv6_HDRLEN + RASIZE)
|
||||
#define DONEBUF ((FAR struct mld_mcast_listen_done_v1_s *) \
|
||||
&dev->d_buf[NET_LL_HDRLEN(dev)] + IPv6_HDRLEN + RASIZE)
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
|
@ -124,31 +126,46 @@ void mld_send(FAR struct net_driver_s *dev, FAR struct mld_group_s *group,
|
|||
|
||||
IFF_SET_IPv6(dev->d_flags);
|
||||
|
||||
/* What is the size of the ICMPv6 payload? Currently only Version 1
|
||||
* REPORT and DONE packets are sent (these are actually the same size).
|
||||
* This will change.
|
||||
*/
|
||||
/* What is the size of the ICMPv6 payload? */
|
||||
|
||||
switch (msgtype)
|
||||
{
|
||||
case MLD_SEND_GENQUERY: /* Send General Query */
|
||||
ninfo("Send General Query, flags=%02x\n", group->flags);
|
||||
mldsize = SIZEOF_MLD_MCAST_LISTEN_QUERY_S(0);
|
||||
{
|
||||
ninfo("Send General Query, flags=%02x\n", group->flags);
|
||||
mldsize = SIZEOF_MLD_MCAST_LISTEN_QUERY_S(0);
|
||||
}
|
||||
break;
|
||||
|
||||
case MLD_SEND_REPORT: /* Send Unsolicited report */
|
||||
ninfo("Send Report, flags=%02x\n", group->flags);
|
||||
mldsize = sizeof(struct mld_mcast_listen_report_v1_s);
|
||||
case MLD_SEND_V1REPORT: /* Send MLDv1 Report message */
|
||||
{
|
||||
ninfo("Send MLDv1 Report, flags=%02x\n", group->flags);
|
||||
mldsize = sizeof(struct mld_mcast_listen_report_v1_s);
|
||||
}
|
||||
break;
|
||||
|
||||
case MLD_SEND_DONE: /* Send Done message */
|
||||
ninfo("Send Done message, flags=%02x\n", group->flags);
|
||||
mldsize = sizeof(struct mld_mcast_listen_done_v1_s);
|
||||
case MLD_SEND_V2REPORT: /* Send MLDv2 Report message */
|
||||
{
|
||||
unsigned int addreclen;
|
||||
|
||||
ninfo("Send MLDv2 Report, flags=%02x\n", group->flags);
|
||||
addreclen = SIZEOF_MLD_MCAST_ADDREC_V2_S(0, 0);
|
||||
mldsize = SIZEOF_MLD_MCAST_LISTEN_REPORT_V2_S(addreclen);
|
||||
}
|
||||
break;
|
||||
|
||||
case MLD_SEND_V1DONE: /* Send MLDv1 Done message */
|
||||
{
|
||||
ninfo("Send Done message, flags=%02x\n", group->flags);
|
||||
mldsize = sizeof(struct mld_mcast_listen_done_v1_s);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
nerr("Bad msgtype: %02x \n", msgtype);
|
||||
DEBUGPANIC();
|
||||
{
|
||||
nerr("Bad msgtype: %02x \n", msgtype);
|
||||
DEBUGPANIC();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -196,11 +213,15 @@ void mld_send(FAR struct net_driver_s *dev, FAR struct mld_group_s *group,
|
|||
destipaddr = g_ipv6_allnodes;
|
||||
break;
|
||||
|
||||
case MLD_SEND_REPORT: /* Send Unsolicited report */
|
||||
case MLD_SEND_V1REPORT: /* Send MLDv1 Report message */
|
||||
destipaddr = group->grpaddr;
|
||||
break;
|
||||
|
||||
case MLD_SEND_DONE: /* Send Done message */
|
||||
case MLD_SEND_V2REPORT: /* Send MLDv2 Report message */
|
||||
destipaddr = g_ipv6_allmldv2routers;
|
||||
break;
|
||||
|
||||
case MLD_SEND_V1DONE: /* Send MLDv1 Done message */
|
||||
destipaddr = g_ipv6_allrouters;
|
||||
break;
|
||||
}
|
||||
|
@ -234,17 +255,26 @@ void mld_send(FAR struct net_driver_s *dev, FAR struct mld_group_s *group,
|
|||
{
|
||||
FAR struct mld_mcast_listen_query_s *query = QUERYBUF;
|
||||
|
||||
/* Initializer the Query payload. In a General Query, both the
|
||||
/* Initialize the Query payload. In a General Query, both the
|
||||
* Multicast Address field and the Number of Sources (N)
|
||||
* field are zero.
|
||||
*
|
||||
* Careful here. In MLDv1 compatibility mode, the MRC is not
|
||||
* encoded and must follow the rules for MLDv1.
|
||||
*/
|
||||
|
||||
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;
|
||||
|
||||
/* Fields unique to the extended MLDv2 query */
|
||||
|
||||
if (!IS_MLD_V1COMPAT(group->flags))
|
||||
{
|
||||
query->flags = MLD_ROBUSTNESS;
|
||||
query->qqic = MLD_QRESP_SEC;
|
||||
}
|
||||
|
||||
/* Calculate the ICMPv6 checksum. */
|
||||
|
||||
|
@ -255,11 +285,11 @@ void mld_send(FAR struct net_driver_s *dev, FAR struct mld_group_s *group,
|
|||
}
|
||||
break;
|
||||
|
||||
case MLD_SEND_REPORT:
|
||||
case MLD_SEND_V1REPORT: /* Send MLDv1 Report message */
|
||||
{
|
||||
FAR struct mld_mcast_listen_report_v1_s *report = REPORTBUF;
|
||||
FAR struct mld_mcast_listen_report_v1_s *report = V1REPORTBUF;
|
||||
|
||||
/* Initializer the Report payload */
|
||||
/* Initialize the Report payload */
|
||||
|
||||
memset(report, 0, sizeof(struct mld_mcast_listen_report_v1_s));
|
||||
net_ipv6addr_hdrcopy(report->mcastaddr, &group->grpaddr);
|
||||
|
@ -275,11 +305,36 @@ void mld_send(FAR struct net_driver_s *dev, FAR struct mld_group_s *group,
|
|||
}
|
||||
break;
|
||||
|
||||
case MLD_SEND_DONE:
|
||||
case MLD_SEND_V2REPORT: /* Send MLDv2 Report message */
|
||||
{
|
||||
FAR struct mld_mcast_listen_report_v2_s *report = V2REPORTBUF;
|
||||
FAR struct mld_mcast_addrec_v2_s *addrec;
|
||||
|
||||
/* Initialize the Report payload */
|
||||
|
||||
memset(report, 0, mldsize);
|
||||
report->type = ICMPV6_MCAST_LISTEN_REPORT_V2;
|
||||
report->naddrec = 1;
|
||||
|
||||
addrec = report->addrec;
|
||||
addrec->rectype = MODE_IS_INCLUDE;
|
||||
net_ipv6addr_hdrcopy(addrec->mcast, &group->grpaddr);
|
||||
|
||||
/* Calculate the ICMPv6 checksum. */
|
||||
|
||||
report->chksum = 0;
|
||||
report->chksum = ~icmpv6_chksum(dev);
|
||||
|
||||
SET_MLD_LASTREPORT(group->flags); /* Remember we were the last to report */
|
||||
MLD_STATINCR(g_netstats.mld.report_sent);
|
||||
}
|
||||
break;
|
||||
|
||||
case MLD_SEND_V1DONE: /* Send MLDv1 Done message */
|
||||
{
|
||||
FAR struct mld_mcast_listen_done_v1_s *done = DONEBUF;
|
||||
|
||||
/* Initializer the Done payload */
|
||||
/* Initialize the Done payload */
|
||||
|
||||
memset(done, 0, sizeof(struct mld_mcast_listen_done_v1_s));
|
||||
done->type = ICMPV6_MCAST_LISTEN_DONE_V1;
|
||||
|
|
|
@ -90,7 +90,28 @@
|
|||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: mld_timeout_work
|
||||
* Name: mld_report_msgtype
|
||||
*
|
||||
* Description:
|
||||
* Determine which type of Report to send, MLDv1 or MLDv2, depending on
|
||||
* current state of compatibility mode flag.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static inline uint8_t mld_report_msgtype(FAR struct mld_group_s *group)
|
||||
{
|
||||
if (IS_MLD_V1COMPAT(group->flags))
|
||||
{
|
||||
return MLD_SEND_V1REPORT;
|
||||
}
|
||||
else
|
||||
{
|
||||
return MLD_SEND_V2REPORT;
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: mld_polldog_work
|
||||
*
|
||||
* Description:
|
||||
* Timeout watchdog work
|
||||
|
@ -100,7 +121,7 @@
|
|||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void mld_timeout_work(FAR void *arg)
|
||||
static void mld_polldog_work(FAR void *arg)
|
||||
{
|
||||
FAR struct mld_group_s *group;
|
||||
int ret;
|
||||
|
@ -118,7 +139,7 @@ static void mld_timeout_work(FAR void *arg)
|
|||
/* Schedule (and forget) the Report. */
|
||||
|
||||
MLD_STATINCR(g_netstats.mld.report_sched);
|
||||
ret = mld_schedmsg(group, MLD_SEND_REPORT);
|
||||
ret = mld_schedmsg(group, mld_report_msgtype(group));
|
||||
if (ret < 0)
|
||||
{
|
||||
nerr("ERROR: Failed to schedule message: %d\n", ret);
|
||||
|
@ -133,7 +154,7 @@ static void mld_timeout_work(FAR void *arg)
|
|||
/* Decrement the count and restart the timer */
|
||||
|
||||
group->count--;
|
||||
mld_starttimer(group, MSEC2TICK(MLD_UNSOLREPORT_MSEC));
|
||||
mld_start_polltimer(group, MSEC2TICK(MLD_UNSOLREPORT_MSEC));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -145,7 +166,7 @@ static void mld_timeout_work(FAR void *arg)
|
|||
|
||||
if (IS_MLD_QUERIER(group->flags))
|
||||
{
|
||||
mld_starttimer(group, MSEC2TICK(MLD_QUERY_MSEC));
|
||||
mld_start_polltimer(group, MSEC2TICK(MLD_QUERY_MSEC));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -165,25 +186,25 @@ static void mld_timeout_work(FAR void *arg)
|
|||
|
||||
/* Restart the Querier timer */
|
||||
|
||||
mld_starttimer(group, MSEC2TICK(MLD_QUERY_MSEC));
|
||||
mld_start_polltimer(group, MSEC2TICK(MLD_QUERY_MSEC));
|
||||
}
|
||||
|
||||
net_unlock();
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: mld_timeout
|
||||
* Name: mld_polldog_timout
|
||||
*
|
||||
* Description:
|
||||
* Timeout watchdog handler.
|
||||
*
|
||||
* Assumptions:
|
||||
* This function is called from the wdog timer handler which runs in the
|
||||
* This function is called from the polldog timer handler which runs in the
|
||||
* context of the timer interrupt handler.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void mld_timeout(int argc, uint32_t arg, ...)
|
||||
static void mld_polldog_timout(int argc, uint32_t arg, ...)
|
||||
{
|
||||
FAR struct mld_group_s *group;
|
||||
int ret;
|
||||
|
@ -199,7 +220,92 @@ static void mld_timeout(int argc, uint32_t arg, ...)
|
|||
* work queue.
|
||||
*/
|
||||
|
||||
ret = work_queue(LPWORK, &group->work, mld_timeout_work, group, 0);
|
||||
ret = work_queue(LPWORK, &group->work, mld_polldog_work, group, 0);
|
||||
if (ret < 0)
|
||||
{
|
||||
nerr("ERROR: Failed to queue timeout work: %d\n", ret);
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: mld_v1dog_work
|
||||
*
|
||||
* Description:
|
||||
* Timeout watchdog work
|
||||
*
|
||||
* Assumptions:
|
||||
* This function is called from a work queue thread.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void mld_v1dog_work(FAR void *arg)
|
||||
{
|
||||
FAR struct mld_group_s *group;
|
||||
|
||||
/* Recover the reference to the group */
|
||||
|
||||
group = (FAR struct mld_group_s *)arg;
|
||||
DEBUGASSERT(group != NULL);
|
||||
|
||||
net_lock();
|
||||
if (IS_MLD_V1COMPAT(group->flags))
|
||||
{
|
||||
/* Exit MLDv1 compatibility mode. */
|
||||
|
||||
CLR_MLD_V1COMPAT(group->flags);
|
||||
|
||||
/* Whenever a host changes its compatibility mode, it cancels all its
|
||||
* pending responses and retransmission timers.
|
||||
*/
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
net_unlock();
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: mld_v1dog_timout
|
||||
*
|
||||
* Description:
|
||||
* Timeout watchdog handler.
|
||||
*
|
||||
* Assumptions:
|
||||
* This function is called from the v1dog timer handler which runs in the
|
||||
* context of the timer interrupt handler.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void mld_v1dog_timout(int argc, uint32_t arg, ...)
|
||||
{
|
||||
FAR struct mld_group_s *group;
|
||||
int ret;
|
||||
|
||||
ninfo("Timeout!\n");
|
||||
|
||||
/* Recover the reference to the group */
|
||||
|
||||
group = (FAR struct mld_group_s *)arg;
|
||||
DEBUGASSERT(argc == 1 && group != NULL);
|
||||
|
||||
/* Cancels all its pending responses and retransmission timers */
|
||||
|
||||
wd_cancel(group->polldog);
|
||||
|
||||
/* Perform the timeout-related operations on (preferably) the low priority
|
||||
* work queue.
|
||||
*/
|
||||
|
||||
ret = work_queue(LPWORK, &group->work, mld_v1dog_work, group, 0);
|
||||
if (ret < 0)
|
||||
{
|
||||
nerr("ERROR: Failed to queue timeout work: %d\n", ret);
|
||||
|
@ -211,78 +317,47 @@ static void mld_timeout(int argc, uint32_t arg, ...)
|
|||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: mld_starttimer
|
||||
* Name: mld_start_polltimer
|
||||
*
|
||||
* Description:
|
||||
* Start the MLD timer.
|
||||
*
|
||||
* Assumptions:
|
||||
* This function may be called from most any context.
|
||||
* Start the MLD poll timer.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void mld_starttimer(FAR struct mld_group_s *group, clock_t ticks)
|
||||
void mld_start_polltimer(FAR struct mld_group_s *group, clock_t ticks)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* Start the timer */
|
||||
|
||||
mtmrinfo("ticks: %ld\n", (unsigned long)ticks);
|
||||
mtmrinfo("ticks: %lu\n", (unsigned long)ticks);
|
||||
|
||||
ret = wd_start(group->wdog, ticks, mld_timeout, 1, (uint32_t)group);
|
||||
ret = wd_start(group->polldog, ticks, mld_polldog_timout, 1, (uint32_t)group);
|
||||
|
||||
DEBUGASSERT(ret == OK);
|
||||
UNUSED(ret);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: mld_cmptimer
|
||||
* Name: mld_start_v1timer
|
||||
*
|
||||
* Description:
|
||||
* Compare the timer remaining on the watching timer to the deci-second
|
||||
* value. If maxticks > ticks-remaining, then (1) cancel the timer (to
|
||||
* avoid race conditions) and return true.
|
||||
*
|
||||
* Assumptions:
|
||||
* This function may be called from most any context. If true is returned
|
||||
* then the caller must call mld_starttimer() to restart the timer
|
||||
* Start the MLDv1 compatibility timer.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
bool mld_cmptimer(FAR struct mld_group_s *group, int maxticks)
|
||||
void mld_start_v1timer(FAR struct mld_group_s *group, clock_t ticks)
|
||||
{
|
||||
irqstate_t flags;
|
||||
int remaining;
|
||||
int ret;
|
||||
|
||||
/* Disable interrupts so that there is no race condition with the actual
|
||||
* timer expiration.
|
||||
*/
|
||||
/* Start the timer */
|
||||
|
||||
flags = enter_critical_section();
|
||||
mtmrinfo("ticks: %lu\n", (unsigned long)ticks);
|
||||
|
||||
/* Get the timer remaining on the watchdog. A time of <= zero means that
|
||||
* the watchdog was never started.
|
||||
*/
|
||||
ret = wd_start(group->v1dog, ticks, mld_v1dog_timout, 1, (uint32_t)group);
|
||||
|
||||
remaining = wd_gettime(group->wdog);
|
||||
|
||||
/* A remaining time of zero means that the watchdog was never started
|
||||
* or has already expired. That case should be covered in the following
|
||||
* test as well.
|
||||
*/
|
||||
|
||||
mtmrinfo("maxticks: %d remaining: %d\n", maxticks, remaining);
|
||||
if (maxticks > remaining)
|
||||
{
|
||||
/* Cancel the watchdog timer and return true */
|
||||
|
||||
wd_cancel(group->wdog);
|
||||
leave_critical_section(flags);
|
||||
return true;
|
||||
}
|
||||
|
||||
leave_critical_section(flags);
|
||||
return false;
|
||||
DEBUGASSERT(ret == OK);
|
||||
UNUSED(ret);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_NET_MLD */
|
||||
|
|
Loading…
Reference in New Issue