1 // Packet implementation for the Multicast Listener Discovery
2 // protocol. See [RFC 3810] and [RFC 2710].
3 //
4 // [RFC 3810]: https://tools.ietf.org/html/rfc3810
5 // [RFC 2710]: https://tools.ietf.org/html/rfc2710
6 
7 use byteorder::{ByteOrder, NetworkEndian};
8 
9 use super::{Error, Result};
10 use crate::wire::icmpv6::{field, Message, Packet};
11 use crate::wire::Ipv6Address;
12 
13 enum_with_unknown! {
14     /// MLDv2 Multicast Listener Report Record Type. See [RFC 3810 § 5.2.12] for
15     /// more details.
16     ///
17     /// [RFC 3810 § 5.2.12]: https://tools.ietf.org/html/rfc3010#section-5.2.12
18     pub enum RecordType(u8) {
19         /// Interface has a filter mode of INCLUDE for the specified multicast address.
20         ModeIsInclude   = 0x01,
21         /// Interface has a filter mode of EXCLUDE for the specified multicast address.
22         ModeIsExclude   = 0x02,
23         /// Interface has changed to a filter mode of INCLUDE for the specified
24         /// multicast address.
25         ChangeToInclude = 0x03,
26         /// Interface has changed to a filter mode of EXCLUDE for the specified
27         /// multicast address.
28         ChangeToExclude = 0x04,
29         /// Interface wishes to listen to the sources in the specified list.
30         AllowNewSources = 0x05,
31         /// Interface no longer wishes to listen to the sources in the specified list.
32         BlockOldSources = 0x06
33     }
34 }
35 
36 /// Getters for the Multicast Listener Query message header.
37 /// See [RFC 3810 § 5.1].
38 ///
39 /// [RFC 3810 § 5.1]: https://tools.ietf.org/html/rfc3010#section-5.1
40 impl<T: AsRef<[u8]>> Packet<T> {
41     /// Return the maximum response code field.
42     #[inline]
max_resp_code(&self) -> u1643     pub fn max_resp_code(&self) -> u16 {
44         let data = self.buffer.as_ref();
45         NetworkEndian::read_u16(&data[field::MAX_RESP_CODE])
46     }
47 
48     /// Return the address being queried.
49     #[inline]
mcast_addr(&self) -> Ipv6Address50     pub fn mcast_addr(&self) -> Ipv6Address {
51         let data = self.buffer.as_ref();
52         Ipv6Address::from_bytes(&data[field::QUERY_MCAST_ADDR])
53     }
54 
55     /// Return the Suppress Router-Side Processing flag.
56     #[inline]
s_flag(&self) -> bool57     pub fn s_flag(&self) -> bool {
58         let data = self.buffer.as_ref();
59         (data[field::SQRV] & 0x08) != 0
60     }
61 
62     /// Return the Querier's Robustness Variable.
63     #[inline]
qrv(&self) -> u864     pub fn qrv(&self) -> u8 {
65         let data = self.buffer.as_ref();
66         data[field::SQRV] & 0x7
67     }
68 
69     /// Return the Querier's Query Interval Code.
70     #[inline]
qqic(&self) -> u871     pub fn qqic(&self) -> u8 {
72         let data = self.buffer.as_ref();
73         data[field::QQIC]
74     }
75 
76     /// Return number of sources.
77     #[inline]
num_srcs(&self) -> u1678     pub fn num_srcs(&self) -> u16 {
79         let data = self.buffer.as_ref();
80         NetworkEndian::read_u16(&data[field::QUERY_NUM_SRCS])
81     }
82 }
83 
84 /// Getters for the Multicast Listener Report message header.
85 /// See [RFC 3810 § 5.2].
86 ///
87 /// [RFC 3810 § 5.2]: https://tools.ietf.org/html/rfc3010#section-5.2
88 impl<T: AsRef<[u8]>> Packet<T> {
89     /// Return the number of Multicast Address Records.
90     #[inline]
nr_mcast_addr_rcrds(&self) -> u1691     pub fn nr_mcast_addr_rcrds(&self) -> u16 {
92         let data = self.buffer.as_ref();
93         NetworkEndian::read_u16(&data[field::NR_MCAST_RCRDS])
94     }
95 }
96 
97 /// Setters for the Multicast Listener Query message header.
98 /// See [RFC 3810 § 5.1].
99 ///
100 /// [RFC 3810 § 5.1]: https://tools.ietf.org/html/rfc3010#section-5.1
101 impl<T: AsRef<[u8]> + AsMut<[u8]>> Packet<T> {
102     /// Set the maximum response code field.
103     #[inline]
set_max_resp_code(&mut self, code: u16)104     pub fn set_max_resp_code(&mut self, code: u16) {
105         let data = self.buffer.as_mut();
106         NetworkEndian::write_u16(&mut data[field::MAX_RESP_CODE], code);
107     }
108 
109     /// Set the address being queried.
110     #[inline]
set_mcast_addr(&mut self, addr: Ipv6Address)111     pub fn set_mcast_addr(&mut self, addr: Ipv6Address) {
112         let data = self.buffer.as_mut();
113         data[field::QUERY_MCAST_ADDR].copy_from_slice(addr.as_bytes());
114     }
115 
116     /// Set the Suppress Router-Side Processing flag.
117     #[inline]
set_s_flag(&mut self)118     pub fn set_s_flag(&mut self) {
119         let data = self.buffer.as_mut();
120         let current = data[field::SQRV];
121         data[field::SQRV] = 0x8 | (current & 0x7);
122     }
123 
124     /// Clear the Suppress Router-Side Processing flag.
125     #[inline]
clear_s_flag(&mut self)126     pub fn clear_s_flag(&mut self) {
127         let data = self.buffer.as_mut();
128         data[field::SQRV] &= 0x7;
129     }
130 
131     /// Set the Querier's Robustness Variable.
132     #[inline]
set_qrv(&mut self, value: u8)133     pub fn set_qrv(&mut self, value: u8) {
134         assert!(value < 8);
135         let data = self.buffer.as_mut();
136         data[field::SQRV] = (data[field::SQRV] & 0x8) | value & 0x7;
137     }
138 
139     /// Set the Querier's Query Interval Code.
140     #[inline]
set_qqic(&mut self, value: u8)141     pub fn set_qqic(&mut self, value: u8) {
142         let data = self.buffer.as_mut();
143         data[field::QQIC] = value;
144     }
145 
146     /// Set number of sources.
147     #[inline]
set_num_srcs(&mut self, value: u16)148     pub fn set_num_srcs(&mut self, value: u16) {
149         let data = self.buffer.as_mut();
150         NetworkEndian::write_u16(&mut data[field::QUERY_NUM_SRCS], value);
151     }
152 }
153 
154 /// Setters for the Multicast Listener Report message header.
155 /// See [RFC 3810 § 5.2].
156 ///
157 /// [RFC 3810 § 5.2]: https://tools.ietf.org/html/rfc3010#section-5.2
158 impl<T: AsRef<[u8]> + AsMut<[u8]>> Packet<T> {
159     /// Set the number of Multicast Address Records.
160     #[inline]
set_nr_mcast_addr_rcrds(&mut self, value: u16)161     pub fn set_nr_mcast_addr_rcrds(&mut self, value: u16) {
162         let data = self.buffer.as_mut();
163         NetworkEndian::write_u16(&mut data[field::NR_MCAST_RCRDS], value)
164     }
165 }
166 
167 /// A read/write wrapper around an MLDv2 Listener Report Message Address Record.
168 #[derive(Debug, PartialEq, Eq, Clone)]
169 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
170 pub struct AddressRecord<T: AsRef<[u8]>> {
171     buffer: T,
172 }
173 
174 impl<T: AsRef<[u8]>> AddressRecord<T> {
175     /// Imbue a raw octet buffer with a Address Record structure.
new_unchecked(buffer: T) -> Self176     pub const fn new_unchecked(buffer: T) -> Self {
177         Self { buffer }
178     }
179 
180     /// Shorthand for a combination of [new_unchecked] and [check_len].
181     ///
182     /// [new_unchecked]: #method.new_unchecked
183     /// [check_len]: #method.check_len
new_checked(buffer: T) -> Result<Self>184     pub fn new_checked(buffer: T) -> Result<Self> {
185         let packet = Self::new_unchecked(buffer);
186         packet.check_len()?;
187         Ok(packet)
188     }
189 
190     /// Ensure that no accessor method will panic if called.
191     /// Returns `Err(Error::Truncated)` if the buffer is too short.
check_len(&self) -> Result<()>192     pub fn check_len(&self) -> Result<()> {
193         let len = self.buffer.as_ref().len();
194         if len < field::RECORD_MCAST_ADDR.end {
195             Err(Error)
196         } else {
197             Ok(())
198         }
199     }
200 
201     /// Consume the packet, returning the underlying buffer.
into_inner(self) -> T202     pub fn into_inner(self) -> T {
203         self.buffer
204     }
205 }
206 
207 /// Getters for a MLDv2 Listener Report Message Address Record.
208 /// See [RFC 3810 § 5.2].
209 ///
210 /// [RFC 3810 § 5.2]: https://tools.ietf.org/html/rfc3010#section-5.2
211 impl<T: AsRef<[u8]>> AddressRecord<T> {
212     /// Return the record type for the given sources.
213     #[inline]
record_type(&self) -> RecordType214     pub fn record_type(&self) -> RecordType {
215         let data = self.buffer.as_ref();
216         RecordType::from(data[field::RECORD_TYPE])
217     }
218 
219     /// Return the length of the auxiliary data.
220     #[inline]
aux_data_len(&self) -> u8221     pub fn aux_data_len(&self) -> u8 {
222         let data = self.buffer.as_ref();
223         data[field::AUX_DATA_LEN]
224     }
225 
226     /// Return the number of sources field.
227     #[inline]
num_srcs(&self) -> u16228     pub fn num_srcs(&self) -> u16 {
229         let data = self.buffer.as_ref();
230         NetworkEndian::read_u16(&data[field::RECORD_NUM_SRCS])
231     }
232 
233     /// Return the multicast address field.
234     #[inline]
mcast_addr(&self) -> Ipv6Address235     pub fn mcast_addr(&self) -> Ipv6Address {
236         let data = self.buffer.as_ref();
237         Ipv6Address::from_bytes(&data[field::RECORD_MCAST_ADDR])
238     }
239 }
240 
241 impl<'a, T: AsRef<[u8]> + ?Sized> AddressRecord<&'a T> {
242     /// Return a pointer to the address records.
243     #[inline]
payload(&self) -> &'a [u8]244     pub fn payload(&self) -> &'a [u8] {
245         let data = self.buffer.as_ref();
246         &data[field::RECORD_MCAST_ADDR.end..]
247     }
248 }
249 
250 /// Setters for a MLDv2 Listener Report Message Address Record.
251 /// See [RFC 3810 § 5.2].
252 ///
253 /// [RFC 3810 § 5.2]: https://tools.ietf.org/html/rfc3010#section-5.2
254 impl<T: AsMut<[u8]> + AsRef<[u8]>> AddressRecord<T> {
255     /// Return the record type for the given sources.
256     #[inline]
set_record_type(&mut self, rty: RecordType)257     pub fn set_record_type(&mut self, rty: RecordType) {
258         let data = self.buffer.as_mut();
259         data[field::RECORD_TYPE] = rty.into();
260     }
261 
262     /// Return the length of the auxiliary data.
263     #[inline]
set_aux_data_len(&mut self, len: u8)264     pub fn set_aux_data_len(&mut self, len: u8) {
265         let data = self.buffer.as_mut();
266         data[field::AUX_DATA_LEN] = len;
267     }
268 
269     /// Return the number of sources field.
270     #[inline]
set_num_srcs(&mut self, num_srcs: u16)271     pub fn set_num_srcs(&mut self, num_srcs: u16) {
272         let data = self.buffer.as_mut();
273         NetworkEndian::write_u16(&mut data[field::RECORD_NUM_SRCS], num_srcs);
274     }
275 
276     /// Return the multicast address field.
277     ///
278     /// # Panics
279     /// This function panics if the given address is not a multicast address.
280     #[inline]
set_mcast_addr(&mut self, addr: Ipv6Address)281     pub fn set_mcast_addr(&mut self, addr: Ipv6Address) {
282         assert!(addr.is_multicast());
283         let data = self.buffer.as_mut();
284         data[field::RECORD_MCAST_ADDR].copy_from_slice(addr.as_bytes());
285     }
286 }
287 
288 impl<T: AsRef<[u8]> + AsMut<[u8]>> AddressRecord<T> {
289     /// Return a pointer to the address records.
290     #[inline]
payload_mut(&mut self) -> &mut [u8]291     pub fn payload_mut(&mut self) -> &mut [u8] {
292         let data = self.buffer.as_mut();
293         &mut data[field::RECORD_MCAST_ADDR.end..]
294     }
295 }
296 
297 /// A high-level representation of an MLDv2 packet header.
298 #[derive(Debug, PartialEq, Eq, Clone, Copy)]
299 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
300 pub enum Repr<'a> {
301     Query {
302         max_resp_code: u16,
303         mcast_addr: Ipv6Address,
304         s_flag: bool,
305         qrv: u8,
306         qqic: u8,
307         num_srcs: u16,
308         data: &'a [u8],
309     },
310     Report {
311         nr_mcast_addr_rcrds: u16,
312         data: &'a [u8],
313     },
314 }
315 
316 impl<'a> Repr<'a> {
317     /// Parse an MLDv2 packet and return a high-level representation.
parse<T>(packet: &Packet<&'a T>) -> Result<Repr<'a>> where T: AsRef<[u8]> + ?Sized,318     pub fn parse<T>(packet: &Packet<&'a T>) -> Result<Repr<'a>>
319     where
320         T: AsRef<[u8]> + ?Sized,
321     {
322         match packet.msg_type() {
323             Message::MldQuery => Ok(Repr::Query {
324                 max_resp_code: packet.max_resp_code(),
325                 mcast_addr: packet.mcast_addr(),
326                 s_flag: packet.s_flag(),
327                 qrv: packet.qrv(),
328                 qqic: packet.qqic(),
329                 num_srcs: packet.num_srcs(),
330                 data: packet.payload(),
331             }),
332             Message::MldReport => Ok(Repr::Report {
333                 nr_mcast_addr_rcrds: packet.nr_mcast_addr_rcrds(),
334                 data: packet.payload(),
335             }),
336             _ => Err(Error),
337         }
338     }
339 
340     /// Return the length of a packet that will be emitted from this high-level representation.
buffer_len(&self) -> usize341     pub const fn buffer_len(&self) -> usize {
342         match self {
343             Repr::Query { data, .. } => field::QUERY_NUM_SRCS.end + data.len(),
344             Repr::Report { data, .. } => field::NR_MCAST_RCRDS.end + data.len(),
345         }
346     }
347 
348     /// Emit a high-level representation into an MLDv2 packet.
emit<T>(&self, packet: &mut Packet<&mut T>) where T: AsRef<[u8]> + AsMut<[u8]> + ?Sized,349     pub fn emit<T>(&self, packet: &mut Packet<&mut T>)
350     where
351         T: AsRef<[u8]> + AsMut<[u8]> + ?Sized,
352     {
353         match self {
354             Repr::Query {
355                 max_resp_code,
356                 mcast_addr,
357                 s_flag,
358                 qrv,
359                 qqic,
360                 num_srcs,
361                 data,
362             } => {
363                 packet.set_msg_type(Message::MldQuery);
364                 packet.set_msg_code(0);
365                 packet.clear_reserved();
366                 packet.set_max_resp_code(*max_resp_code);
367                 packet.set_mcast_addr(*mcast_addr);
368                 if *s_flag {
369                     packet.set_s_flag();
370                 } else {
371                     packet.clear_s_flag();
372                 }
373                 packet.set_qrv(*qrv);
374                 packet.set_qqic(*qqic);
375                 packet.set_num_srcs(*num_srcs);
376                 packet.payload_mut().copy_from_slice(&data[..]);
377             }
378             Repr::Report {
379                 nr_mcast_addr_rcrds,
380                 data,
381             } => {
382                 packet.set_msg_type(Message::MldReport);
383                 packet.set_msg_code(0);
384                 packet.clear_reserved();
385                 packet.set_nr_mcast_addr_rcrds(*nr_mcast_addr_rcrds);
386                 packet.payload_mut().copy_from_slice(&data[..]);
387             }
388         }
389     }
390 }
391 
392 #[cfg(test)]
393 mod test {
394     use super::*;
395     use crate::phy::ChecksumCapabilities;
396     use crate::wire::icmpv6::Message;
397     use crate::wire::Icmpv6Repr;
398 
399     static QUERY_PACKET_BYTES: [u8; 44] = [
400         0x82, 0x00, 0x73, 0x74, 0x04, 0x00, 0x00, 0x00, 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
401         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0a, 0x12, 0x00, 0x01, 0xff, 0x02,
402         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
403     ];
404 
405     static QUERY_PACKET_PAYLOAD: [u8; 16] = [
406         0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
407         0x02,
408     ];
409 
410     static REPORT_PACKET_BYTES: [u8; 44] = [
411         0x8f, 0x00, 0x73, 0x85, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0xff, 0x02, 0x00,
412         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0x02,
413         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
414     ];
415 
416     static REPORT_PACKET_PAYLOAD: [u8; 36] = [
417         0x01, 0x00, 0x00, 0x01, 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
418         0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
419         0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
420     ];
421 
create_repr<'a>(ty: Message) -> Icmpv6Repr<'a>422     fn create_repr<'a>(ty: Message) -> Icmpv6Repr<'a> {
423         match ty {
424             Message::MldQuery => Icmpv6Repr::Mld(Repr::Query {
425                 max_resp_code: 0x400,
426                 mcast_addr: Ipv6Address::LINK_LOCAL_ALL_NODES,
427                 s_flag: true,
428                 qrv: 0x02,
429                 qqic: 0x12,
430                 num_srcs: 0x01,
431                 data: &QUERY_PACKET_PAYLOAD,
432             }),
433             Message::MldReport => Icmpv6Repr::Mld(Repr::Report {
434                 nr_mcast_addr_rcrds: 1,
435                 data: &REPORT_PACKET_PAYLOAD,
436             }),
437             _ => {
438                 panic!("Message type must be a MLDv2 message type");
439             }
440         }
441     }
442 
443     #[test]
test_query_deconstruct()444     fn test_query_deconstruct() {
445         let packet = Packet::new_unchecked(&QUERY_PACKET_BYTES[..]);
446         assert_eq!(packet.msg_type(), Message::MldQuery);
447         assert_eq!(packet.msg_code(), 0);
448         assert_eq!(packet.checksum(), 0x7374);
449         assert_eq!(packet.max_resp_code(), 0x0400);
450         assert_eq!(packet.mcast_addr(), Ipv6Address::LINK_LOCAL_ALL_NODES);
451         assert!(packet.s_flag());
452         assert_eq!(packet.qrv(), 0x02);
453         assert_eq!(packet.qqic(), 0x12);
454         assert_eq!(packet.num_srcs(), 0x01);
455         assert_eq!(
456             Ipv6Address::from_bytes(packet.payload()),
457             Ipv6Address::LINK_LOCAL_ALL_ROUTERS
458         );
459     }
460 
461     #[test]
test_query_construct()462     fn test_query_construct() {
463         let mut bytes = vec![0xff; 44];
464         let mut packet = Packet::new_unchecked(&mut bytes[..]);
465         packet.set_msg_type(Message::MldQuery);
466         packet.set_msg_code(0);
467         packet.set_max_resp_code(0x0400);
468         packet.set_mcast_addr(Ipv6Address::LINK_LOCAL_ALL_NODES);
469         packet.set_s_flag();
470         packet.set_qrv(0x02);
471         packet.set_qqic(0x12);
472         packet.set_num_srcs(0x01);
473         packet
474             .payload_mut()
475             .copy_from_slice(Ipv6Address::LINK_LOCAL_ALL_ROUTERS.as_bytes());
476         packet.clear_reserved();
477         packet.fill_checksum(
478             &Ipv6Address::LINK_LOCAL_ALL_NODES.into(),
479             &Ipv6Address::LINK_LOCAL_ALL_ROUTERS.into(),
480         );
481         assert_eq!(&*packet.into_inner(), &QUERY_PACKET_BYTES[..]);
482     }
483 
484     #[test]
test_record_deconstruct()485     fn test_record_deconstruct() {
486         let packet = Packet::new_unchecked(&REPORT_PACKET_BYTES[..]);
487         assert_eq!(packet.msg_type(), Message::MldReport);
488         assert_eq!(packet.msg_code(), 0);
489         assert_eq!(packet.checksum(), 0x7385);
490         assert_eq!(packet.nr_mcast_addr_rcrds(), 0x01);
491         let addr_rcrd = AddressRecord::new_unchecked(packet.payload());
492         assert_eq!(addr_rcrd.record_type(), RecordType::ModeIsInclude);
493         assert_eq!(addr_rcrd.aux_data_len(), 0x00);
494         assert_eq!(addr_rcrd.num_srcs(), 0x01);
495         assert_eq!(addr_rcrd.mcast_addr(), Ipv6Address::LINK_LOCAL_ALL_NODES);
496         assert_eq!(
497             Ipv6Address::from_bytes(addr_rcrd.payload()),
498             Ipv6Address::LINK_LOCAL_ALL_ROUTERS
499         );
500     }
501 
502     #[test]
test_record_construct()503     fn test_record_construct() {
504         let mut bytes = vec![0xff; 44];
505         let mut packet = Packet::new_unchecked(&mut bytes[..]);
506         packet.set_msg_type(Message::MldReport);
507         packet.set_msg_code(0);
508         packet.clear_reserved();
509         packet.set_nr_mcast_addr_rcrds(1);
510         {
511             let mut addr_rcrd = AddressRecord::new_unchecked(packet.payload_mut());
512             addr_rcrd.set_record_type(RecordType::ModeIsInclude);
513             addr_rcrd.set_aux_data_len(0);
514             addr_rcrd.set_num_srcs(1);
515             addr_rcrd.set_mcast_addr(Ipv6Address::LINK_LOCAL_ALL_NODES);
516             addr_rcrd
517                 .payload_mut()
518                 .copy_from_slice(Ipv6Address::LINK_LOCAL_ALL_ROUTERS.as_bytes());
519         }
520         packet.fill_checksum(
521             &Ipv6Address::LINK_LOCAL_ALL_NODES.into(),
522             &Ipv6Address::LINK_LOCAL_ALL_ROUTERS.into(),
523         );
524         assert_eq!(&*packet.into_inner(), &REPORT_PACKET_BYTES[..]);
525     }
526 
527     #[test]
test_query_repr_parse()528     fn test_query_repr_parse() {
529         let packet = Packet::new_unchecked(&QUERY_PACKET_BYTES[..]);
530         let repr = Icmpv6Repr::parse(
531             &Ipv6Address::LINK_LOCAL_ALL_NODES.into(),
532             &Ipv6Address::LINK_LOCAL_ALL_ROUTERS.into(),
533             &packet,
534             &ChecksumCapabilities::default(),
535         );
536         assert_eq!(repr, Ok(create_repr(Message::MldQuery)));
537     }
538 
539     #[test]
test_report_repr_parse()540     fn test_report_repr_parse() {
541         let packet = Packet::new_unchecked(&REPORT_PACKET_BYTES[..]);
542         let repr = Icmpv6Repr::parse(
543             &Ipv6Address::LINK_LOCAL_ALL_NODES.into(),
544             &Ipv6Address::LINK_LOCAL_ALL_ROUTERS.into(),
545             &packet,
546             &ChecksumCapabilities::default(),
547         );
548         assert_eq!(repr, Ok(create_repr(Message::MldReport)));
549     }
550 
551     #[test]
test_query_repr_emit()552     fn test_query_repr_emit() {
553         let mut bytes = [0x2a; 44];
554         let mut packet = Packet::new_unchecked(&mut bytes[..]);
555         let repr = create_repr(Message::MldQuery);
556         repr.emit(
557             &Ipv6Address::LINK_LOCAL_ALL_NODES.into(),
558             &Ipv6Address::LINK_LOCAL_ALL_ROUTERS.into(),
559             &mut packet,
560             &ChecksumCapabilities::default(),
561         );
562         assert_eq!(&*packet.into_inner(), &QUERY_PACKET_BYTES[..]);
563     }
564 
565     #[test]
test_report_repr_emit()566     fn test_report_repr_emit() {
567         let mut bytes = [0x2a; 44];
568         let mut packet = Packet::new_unchecked(&mut bytes[..]);
569         let repr = create_repr(Message::MldReport);
570         repr.emit(
571             &Ipv6Address::LINK_LOCAL_ALL_NODES.into(),
572             &Ipv6Address::LINK_LOCAL_ALL_ROUTERS.into(),
573             &mut packet,
574             &ChecksumCapabilities::default(),
575         );
576         assert_eq!(&*packet.into_inner(), &REPORT_PACKET_BYTES[..]);
577     }
578 }
579