+#define MLD_QRI_INIT 10 /* Query Response Interval (s) */
+#define MLD_QRI_MIN 1
+#define MLD_QRI_MAX 255
+
+#define MLD_URI_INIT 3 /* Unsolicited Report Interval (s) */
+#define MLD_URI_MIN 0
+#define MLD_URI_MAX 10
+
+#define MLD_MAX_GS_SOURCES 256 /* # of sources in rx GS query */
+#define MLD_MAX_G_GS_PACKETS 8 /* # of packets to answer G/GS */
+#define MLD_MAX_STATE_CHANGE_PACKETS 8 /* # of packets per state change */
+#define MLD_MAX_RESPONSE_PACKETS 16 /* # of packets for general query */
+#define MLD_MAX_RESPONSE_BURST 4 /* # of responses to send at once */
+#define MLD_RESPONSE_BURST_INTERVAL (PR_SLOWHZ) /* 500ms */
+
+/*
+ * MLD-specific mbuf flags.
+ */
+#define M_MLDV1 M_PROTO1 /* Packet is MLDv1 */
+#define M_GROUPREC M_PROTO3 /* mbuf chain is a group record */
+
+/*
+ * Leading space for MLDv2 reports inside MTU.
+ *
+ * NOTE: This differs from IGMPv3 significantly. KAME IPv6 requires
+ * that a fully formed mbuf chain *without* the Router Alert option
+ * is passed to ip6_output(), however we must account for it in the
+ * MTU if we need to split an MLDv2 report into several packets.
+ *
+ * We now put the MLDv2 report header in the initial mbuf containing
+ * the IPv6 header.
+ */
+#define MLD_MTUSPACE (sizeof(struct ip6_hdr) + sizeof(struct mld_raopt) + \
+ sizeof(struct icmp6_hdr))
+
+struct mld_ifinfo {
+ decl_lck_mtx_data(, mli_lock);
+ uint32_t mli_refcnt; /* reference count */
+ uint32_t mli_debug; /* see ifa_debug flags */
+ LIST_ENTRY(mld_ifinfo) mli_link;
+ struct ifnet *mli_ifp; /* interface this instance belongs to */
+ uint32_t mli_version; /* MLDv1 Host Compatibility Mode */
+ uint32_t mli_v1_timer; /* MLDv1 Querier Present timer (s) */
+ uint32_t mli_v2_timer; /* MLDv2 General Query (interface) timer (s)*/
+ uint32_t mli_flags; /* MLD per-interface flags */
+ uint32_t mli_rv; /* MLDv2 Robustness Variable */
+ uint32_t mli_qi; /* MLDv2 Query Interval (s) */
+ uint32_t mli_qri; /* MLDv2 Query Response Interval (s) */
+ uint32_t mli_uri; /* MLDv2 Unsolicited Report Interval (s) */
+ SLIST_HEAD(,in6_multi) mli_relinmhead; /* released groups */
+ struct ifqueue mli_gq; /* queue of general query responses */
+ struct ifqueue mli_v1q; /* MLDv1 message queue */
+};
+
+#define MLI_LOCK_ASSERT_HELD(_mli) \
+ lck_mtx_assert(&(_mli)->mli_lock, LCK_MTX_ASSERT_OWNED)
+
+#define MLI_LOCK_ASSERT_NOTHELD(_mli) \
+ lck_mtx_assert(&(_mli)->mli_lock, LCK_MTX_ASSERT_NOTOWNED)
+
+#define MLI_LOCK(_mli) \
+ lck_mtx_lock(&(_mli)->mli_lock)
+
+#define MLI_LOCK_SPIN(_mli) \
+ lck_mtx_lock_spin(&(_mli)->mli_lock)
+
+#define MLI_CONVERT_LOCK(_mli) do { \
+ MLI_LOCK_ASSERT_HELD(_mli); \
+ lck_mtx_convert_spin(&(_mli)->mli_lock); \
+} while (0)
+
+#define MLI_UNLOCK(_mli) \
+ lck_mtx_unlock(&(_mli)->mli_lock)
+
+#define MLI_ADDREF(_mli) \
+ mli_addref(_mli, 0)
+
+#define MLI_ADDREF_LOCKED(_mli) \
+ mli_addref(_mli, 1)
+
+#define MLI_REMREF(_mli) \
+ mli_remref(_mli)