162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
262306a36Sopenharmony_ci#ifndef LINUX_MLD_H
362306a36Sopenharmony_ci#define LINUX_MLD_H
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci#include <linux/in6.h>
662306a36Sopenharmony_ci#include <linux/icmpv6.h>
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci/* MLDv1 Query/Report/Done */
962306a36Sopenharmony_cistruct mld_msg {
1062306a36Sopenharmony_ci	struct icmp6hdr		mld_hdr;
1162306a36Sopenharmony_ci	struct in6_addr		mld_mca;
1262306a36Sopenharmony_ci};
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#define mld_type		mld_hdr.icmp6_type
1562306a36Sopenharmony_ci#define mld_code		mld_hdr.icmp6_code
1662306a36Sopenharmony_ci#define mld_cksum		mld_hdr.icmp6_cksum
1762306a36Sopenharmony_ci#define mld_maxdelay		mld_hdr.icmp6_maxdelay
1862306a36Sopenharmony_ci#define mld_reserved		mld_hdr.icmp6_dataun.un_data16[1]
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci/* Multicast Listener Discovery version 2 headers */
2162306a36Sopenharmony_ci/* MLDv2 Report */
2262306a36Sopenharmony_cistruct mld2_grec {
2362306a36Sopenharmony_ci	__u8		grec_type;
2462306a36Sopenharmony_ci	__u8		grec_auxwords;
2562306a36Sopenharmony_ci	__be16		grec_nsrcs;
2662306a36Sopenharmony_ci	struct in6_addr	grec_mca;
2762306a36Sopenharmony_ci	struct in6_addr	grec_src[];
2862306a36Sopenharmony_ci};
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_cistruct mld2_report {
3162306a36Sopenharmony_ci	struct icmp6hdr		mld2r_hdr;
3262306a36Sopenharmony_ci	struct mld2_grec	mld2r_grec[];
3362306a36Sopenharmony_ci};
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci#define mld2r_type		mld2r_hdr.icmp6_type
3662306a36Sopenharmony_ci#define mld2r_resv1		mld2r_hdr.icmp6_code
3762306a36Sopenharmony_ci#define mld2r_cksum		mld2r_hdr.icmp6_cksum
3862306a36Sopenharmony_ci#define mld2r_resv2		mld2r_hdr.icmp6_dataun.un_data16[0]
3962306a36Sopenharmony_ci#define mld2r_ngrec		mld2r_hdr.icmp6_dataun.un_data16[1]
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci/* MLDv2 Query */
4262306a36Sopenharmony_cistruct mld2_query {
4362306a36Sopenharmony_ci	struct icmp6hdr		mld2q_hdr;
4462306a36Sopenharmony_ci	struct in6_addr		mld2q_mca;
4562306a36Sopenharmony_ci#if defined(__LITTLE_ENDIAN_BITFIELD)
4662306a36Sopenharmony_ci	__u8			mld2q_qrv:3,
4762306a36Sopenharmony_ci				mld2q_suppress:1,
4862306a36Sopenharmony_ci				mld2q_resv2:4;
4962306a36Sopenharmony_ci#elif defined(__BIG_ENDIAN_BITFIELD)
5062306a36Sopenharmony_ci	__u8			mld2q_resv2:4,
5162306a36Sopenharmony_ci				mld2q_suppress:1,
5262306a36Sopenharmony_ci				mld2q_qrv:3;
5362306a36Sopenharmony_ci#else
5462306a36Sopenharmony_ci#error "Please fix <asm/byteorder.h>"
5562306a36Sopenharmony_ci#endif
5662306a36Sopenharmony_ci	__u8			mld2q_qqic;
5762306a36Sopenharmony_ci	__be16			mld2q_nsrcs;
5862306a36Sopenharmony_ci	struct in6_addr		mld2q_srcs[];
5962306a36Sopenharmony_ci};
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci#define mld2q_type		mld2q_hdr.icmp6_type
6262306a36Sopenharmony_ci#define mld2q_code		mld2q_hdr.icmp6_code
6362306a36Sopenharmony_ci#define mld2q_cksum		mld2q_hdr.icmp6_cksum
6462306a36Sopenharmony_ci#define mld2q_mrc		mld2q_hdr.icmp6_maxdelay
6562306a36Sopenharmony_ci#define mld2q_resv1		mld2q_hdr.icmp6_dataun.un_data16[1]
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci/* RFC3810, 5.1.3. Maximum Response Code:
6862306a36Sopenharmony_ci *
6962306a36Sopenharmony_ci * If Maximum Response Code >= 32768, Maximum Response Code represents a
7062306a36Sopenharmony_ci * floating-point value as follows:
7162306a36Sopenharmony_ci *
7262306a36Sopenharmony_ci *  0 1 2 3 4 5 6 7 8 9 A B C D E F
7362306a36Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
7462306a36Sopenharmony_ci * |1| exp |          mant         |
7562306a36Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
7662306a36Sopenharmony_ci */
7762306a36Sopenharmony_ci#define MLDV2_MRC_EXP(value)	(((value) >> 12) & 0x0007)
7862306a36Sopenharmony_ci#define MLDV2_MRC_MAN(value)	((value) & 0x0fff)
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci/* RFC3810, 5.1.9. QQIC (Querier's Query Interval Code):
8162306a36Sopenharmony_ci *
8262306a36Sopenharmony_ci * If QQIC >= 128, QQIC represents a floating-point value as follows:
8362306a36Sopenharmony_ci *
8462306a36Sopenharmony_ci *  0 1 2 3 4 5 6 7
8562306a36Sopenharmony_ci * +-+-+-+-+-+-+-+-+
8662306a36Sopenharmony_ci * |1| exp | mant  |
8762306a36Sopenharmony_ci * +-+-+-+-+-+-+-+-+
8862306a36Sopenharmony_ci */
8962306a36Sopenharmony_ci#define MLDV2_QQIC_EXP(value)	(((value) >> 4) & 0x07)
9062306a36Sopenharmony_ci#define MLDV2_QQIC_MAN(value)	((value) & 0x0f)
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci#define MLD_EXP_MIN_LIMIT	32768UL
9362306a36Sopenharmony_ci#define MLDV1_MRD_MAX_COMPAT	(MLD_EXP_MIN_LIMIT - 1)
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci#define MLD_MAX_QUEUE		8
9662306a36Sopenharmony_ci#define MLD_MAX_SKBS		32
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_cistatic inline unsigned long mldv2_mrc(const struct mld2_query *mlh2)
9962306a36Sopenharmony_ci{
10062306a36Sopenharmony_ci	/* RFC3810, 5.1.3. Maximum Response Code */
10162306a36Sopenharmony_ci	unsigned long ret, mc_mrc = ntohs(mlh2->mld2q_mrc);
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci	if (mc_mrc < MLD_EXP_MIN_LIMIT) {
10462306a36Sopenharmony_ci		ret = mc_mrc;
10562306a36Sopenharmony_ci	} else {
10662306a36Sopenharmony_ci		unsigned long mc_man, mc_exp;
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci		mc_exp = MLDV2_MRC_EXP(mc_mrc);
10962306a36Sopenharmony_ci		mc_man = MLDV2_MRC_MAN(mc_mrc);
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci		ret = (mc_man | 0x1000) << (mc_exp + 3);
11262306a36Sopenharmony_ci	}
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	return ret;
11562306a36Sopenharmony_ci}
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci#endif
118