]>
Commit | Line | Data |
---|---|---|
acddc0ed | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
5e5034b0 DL |
2 | /* |
3 | * MLD protocol definitions | |
4 | * Copyright (C) 2022 David Lamparter for NetDEF, Inc. | |
5e5034b0 DL |
5 | */ |
6 | ||
7 | #ifndef _PIM6_MLD_PROTOCOL_H | |
8 | #define _PIM6_MLD_PROTOCOL_H | |
9 | ||
10 | #include <stdalign.h> | |
11 | #include <stdint.h> | |
12 | ||
13 | /* There is a struct icmp6_hdr provided by OS, but it includes 4 bytes of data. | |
14 | * Not helpful for us if we want to put the MLD struct after it. | |
15 | */ | |
16 | ||
17 | struct icmp6_plain_hdr { | |
18 | uint8_t icmp6_type; | |
19 | uint8_t icmp6_code; | |
20 | uint16_t icmp6_cksum; | |
21 | }; | |
22 | static_assert(sizeof(struct icmp6_plain_hdr) == 4, "struct mismatch"); | |
23 | static_assert(alignof(struct icmp6_plain_hdr) <= 4, "struct mismatch"); | |
24 | ||
25 | /* for MLDv1 query, report and leave all use the same packet format */ | |
26 | struct mld_v1_pkt { | |
27 | uint16_t max_resp_code; | |
28 | uint16_t rsvd0; | |
29 | struct in6_addr grp; | |
30 | }; | |
31 | static_assert(sizeof(struct mld_v1_pkt) == 20, "struct mismatch"); | |
32 | static_assert(alignof(struct mld_v1_pkt) <= 4, "struct mismatch"); | |
33 | ||
34 | ||
35 | struct mld_v2_query_hdr { | |
36 | uint16_t max_resp_code; | |
37 | uint16_t rsvd0; | |
38 | struct in6_addr grp; | |
39 | uint8_t flags; | |
40 | uint8_t qqic; | |
41 | uint16_t n_src; | |
42 | struct in6_addr srcs[0]; | |
43 | }; | |
44 | static_assert(sizeof(struct mld_v2_query_hdr) == 24, "struct mismatch"); | |
45 | static_assert(alignof(struct mld_v2_query_hdr) <= 4, "struct mismatch"); | |
46 | ||
47 | ||
48 | struct mld_v2_report_hdr { | |
49 | uint16_t rsvd; | |
50 | uint16_t n_records; | |
51 | }; | |
52 | static_assert(sizeof(struct mld_v2_report_hdr) == 4, "struct mismatch"); | |
53 | static_assert(alignof(struct mld_v2_report_hdr) <= 4, "struct mismatch"); | |
54 | ||
55 | ||
56 | struct mld_v2_rec_hdr { | |
57 | uint8_t type; | |
58 | uint8_t aux_len; | |
59 | uint16_t n_src; | |
60 | struct in6_addr grp; | |
61 | struct in6_addr srcs[0]; | |
62 | }; | |
63 | static_assert(sizeof(struct mld_v2_rec_hdr) == 20, "struct mismatch"); | |
64 | static_assert(alignof(struct mld_v2_rec_hdr) <= 4, "struct mismatch"); | |
65 | ||
66 | /* clang-format off */ | |
67 | enum icmp6_mld_type { | |
68 | ICMP6_MLD_QUERY = 130, | |
69 | ICMP6_MLD_V1_REPORT = 131, | |
70 | ICMP6_MLD_V1_DONE = 132, | |
71 | ICMP6_MLD_V2_REPORT = 143, | |
72 | }; | |
73 | ||
74 | enum mld_v2_rec_type { | |
75 | MLD_RECTYPE_IS_INCLUDE = 1, | |
76 | MLD_RECTYPE_IS_EXCLUDE = 2, | |
77 | MLD_RECTYPE_CHANGE_TO_INCLUDE = 3, | |
78 | MLD_RECTYPE_CHANGE_TO_EXCLUDE = 4, | |
79 | MLD_RECTYPE_ALLOW_NEW_SOURCES = 5, | |
80 | MLD_RECTYPE_BLOCK_OLD_SOURCES = 6, | |
81 | }; | |
82 | /* clang-format on */ | |
83 | ||
84 | /* helper functions */ | |
85 | ||
86 | static inline unsigned int mld_max_resp_decode(uint16_t wire) | |
87 | { | |
88 | uint16_t code = ntohs(wire); | |
89 | uint8_t exp; | |
90 | ||
91 | if (code < 0x8000) | |
92 | return code; | |
93 | exp = (code >> 12) & 0x7; | |
94 | return ((code & 0xfff) | 0x1000) << (exp + 3); | |
95 | } | |
96 | ||
97 | static inline uint16_t mld_max_resp_encode(uint32_t value) | |
98 | { | |
99 | uint16_t code; | |
100 | uint8_t exp; | |
101 | ||
102 | if (value < 0x8000) | |
103 | code = value; | |
104 | else { | |
105 | exp = 16 - __builtin_clz(value); | |
106 | code = (value >> (exp + 3)) & 0xfff; | |
107 | code |= 0x8000 | (exp << 12); | |
108 | } | |
109 | return htons(code); | |
110 | } | |
111 | ||
112 | #endif /* _PIM6_MLD_PROTOCOL_H */ |