18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
28c2ecf20Sopenharmony_ci#ifndef LINUX_MLD_H
38c2ecf20Sopenharmony_ci#define LINUX_MLD_H
48c2ecf20Sopenharmony_ci
58c2ecf20Sopenharmony_ci#include <linux/in6.h>
68c2ecf20Sopenharmony_ci#include <linux/icmpv6.h>
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci/* MLDv1 Query/Report/Done */
98c2ecf20Sopenharmony_cistruct mld_msg {
108c2ecf20Sopenharmony_ci	struct icmp6hdr		mld_hdr;
118c2ecf20Sopenharmony_ci	struct in6_addr		mld_mca;
128c2ecf20Sopenharmony_ci};
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#define mld_type		mld_hdr.icmp6_type
158c2ecf20Sopenharmony_ci#define mld_code		mld_hdr.icmp6_code
168c2ecf20Sopenharmony_ci#define mld_cksum		mld_hdr.icmp6_cksum
178c2ecf20Sopenharmony_ci#define mld_maxdelay		mld_hdr.icmp6_maxdelay
188c2ecf20Sopenharmony_ci#define mld_reserved		mld_hdr.icmp6_dataun.un_data16[1]
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci/* Multicast Listener Discovery version 2 headers */
218c2ecf20Sopenharmony_ci/* MLDv2 Report */
228c2ecf20Sopenharmony_cistruct mld2_grec {
238c2ecf20Sopenharmony_ci	__u8		grec_type;
248c2ecf20Sopenharmony_ci	__u8		grec_auxwords;
258c2ecf20Sopenharmony_ci	__be16		grec_nsrcs;
268c2ecf20Sopenharmony_ci	struct in6_addr	grec_mca;
278c2ecf20Sopenharmony_ci	struct in6_addr	grec_src[];
288c2ecf20Sopenharmony_ci};
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_cistruct mld2_report {
318c2ecf20Sopenharmony_ci	struct icmp6hdr		mld2r_hdr;
328c2ecf20Sopenharmony_ci	struct mld2_grec	mld2r_grec[];
338c2ecf20Sopenharmony_ci};
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci#define mld2r_type		mld2r_hdr.icmp6_type
368c2ecf20Sopenharmony_ci#define mld2r_resv1		mld2r_hdr.icmp6_code
378c2ecf20Sopenharmony_ci#define mld2r_cksum		mld2r_hdr.icmp6_cksum
388c2ecf20Sopenharmony_ci#define mld2r_resv2		mld2r_hdr.icmp6_dataun.un_data16[0]
398c2ecf20Sopenharmony_ci#define mld2r_ngrec		mld2r_hdr.icmp6_dataun.un_data16[1]
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci/* MLDv2 Query */
428c2ecf20Sopenharmony_cistruct mld2_query {
438c2ecf20Sopenharmony_ci	struct icmp6hdr		mld2q_hdr;
448c2ecf20Sopenharmony_ci	struct in6_addr		mld2q_mca;
458c2ecf20Sopenharmony_ci#if defined(__LITTLE_ENDIAN_BITFIELD)
468c2ecf20Sopenharmony_ci	__u8			mld2q_qrv:3,
478c2ecf20Sopenharmony_ci				mld2q_suppress:1,
488c2ecf20Sopenharmony_ci				mld2q_resv2:4;
498c2ecf20Sopenharmony_ci#elif defined(__BIG_ENDIAN_BITFIELD)
508c2ecf20Sopenharmony_ci	__u8			mld2q_resv2:4,
518c2ecf20Sopenharmony_ci				mld2q_suppress:1,
528c2ecf20Sopenharmony_ci				mld2q_qrv:3;
538c2ecf20Sopenharmony_ci#else
548c2ecf20Sopenharmony_ci#error "Please fix <asm/byteorder.h>"
558c2ecf20Sopenharmony_ci#endif
568c2ecf20Sopenharmony_ci	__u8			mld2q_qqic;
578c2ecf20Sopenharmony_ci	__be16			mld2q_nsrcs;
588c2ecf20Sopenharmony_ci	struct in6_addr		mld2q_srcs[];
598c2ecf20Sopenharmony_ci};
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci#define mld2q_type		mld2q_hdr.icmp6_type
628c2ecf20Sopenharmony_ci#define mld2q_code		mld2q_hdr.icmp6_code
638c2ecf20Sopenharmony_ci#define mld2q_cksum		mld2q_hdr.icmp6_cksum
648c2ecf20Sopenharmony_ci#define mld2q_mrc		mld2q_hdr.icmp6_maxdelay
658c2ecf20Sopenharmony_ci#define mld2q_resv1		mld2q_hdr.icmp6_dataun.un_data16[1]
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci/* RFC3810, 5.1.3. Maximum Response Code:
688c2ecf20Sopenharmony_ci *
698c2ecf20Sopenharmony_ci * If Maximum Response Code >= 32768, Maximum Response Code represents a
708c2ecf20Sopenharmony_ci * floating-point value as follows:
718c2ecf20Sopenharmony_ci *
728c2ecf20Sopenharmony_ci *  0 1 2 3 4 5 6 7 8 9 A B C D E F
738c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
748c2ecf20Sopenharmony_ci * |1| exp |          mant         |
758c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
768c2ecf20Sopenharmony_ci */
778c2ecf20Sopenharmony_ci#define MLDV2_MRC_EXP(value)	(((value) >> 12) & 0x0007)
788c2ecf20Sopenharmony_ci#define MLDV2_MRC_MAN(value)	((value) & 0x0fff)
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci/* RFC3810, 5.1.9. QQIC (Querier's Query Interval Code):
818c2ecf20Sopenharmony_ci *
828c2ecf20Sopenharmony_ci * If QQIC >= 128, QQIC represents a floating-point value as follows:
838c2ecf20Sopenharmony_ci *
848c2ecf20Sopenharmony_ci *  0 1 2 3 4 5 6 7
858c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+
868c2ecf20Sopenharmony_ci * |1| exp | mant  |
878c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+
888c2ecf20Sopenharmony_ci */
898c2ecf20Sopenharmony_ci#define MLDV2_QQIC_EXP(value)	(((value) >> 4) & 0x07)
908c2ecf20Sopenharmony_ci#define MLDV2_QQIC_MAN(value)	((value) & 0x0f)
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci#define MLD_EXP_MIN_LIMIT	32768UL
938c2ecf20Sopenharmony_ci#define MLDV1_MRD_MAX_COMPAT	(MLD_EXP_MIN_LIMIT - 1)
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_cistatic inline unsigned long mldv2_mrc(const struct mld2_query *mlh2)
968c2ecf20Sopenharmony_ci{
978c2ecf20Sopenharmony_ci	/* RFC3810, 5.1.3. Maximum Response Code */
988c2ecf20Sopenharmony_ci	unsigned long ret, mc_mrc = ntohs(mlh2->mld2q_mrc);
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci	if (mc_mrc < MLD_EXP_MIN_LIMIT) {
1018c2ecf20Sopenharmony_ci		ret = mc_mrc;
1028c2ecf20Sopenharmony_ci	} else {
1038c2ecf20Sopenharmony_ci		unsigned long mc_man, mc_exp;
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci		mc_exp = MLDV2_MRC_EXP(mc_mrc);
1068c2ecf20Sopenharmony_ci		mc_man = MLDV2_MRC_MAN(mc_mrc);
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci		ret = (mc_man | 0x1000) << (mc_exp + 3);
1098c2ecf20Sopenharmony_ci	}
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci	return ret;
1128c2ecf20Sopenharmony_ci}
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci#endif
115