1use byteorder::{ByteOrder, NetworkEndian};
8
9use super::{Error, Result};
10use crate::wire::icmpv6::{field, Message, Packet};
11use crate::wire::{Ipv6Address, Ipv6AddressExt};
12
13enum_with_unknown! {
14 pub enum RecordType(u8) {
19 ModeIsInclude = 0x01,
21 ModeIsExclude = 0x02,
23 ChangeToInclude = 0x03,
26 ChangeToExclude = 0x04,
29 AllowNewSources = 0x05,
31 BlockOldSources = 0x06
33 }
34}
35
36impl<T: AsRef<[u8]>> Packet<T> {
41 #[inline]
43 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 #[inline]
50 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 #[inline]
57 pub fn s_flag(&self) -> bool {
58 let data = self.buffer.as_ref();
59 (data[field::SQRV] & 0x08) != 0
60 }
61
62 #[inline]
64 pub fn qrv(&self) -> u8 {
65 let data = self.buffer.as_ref();
66 data[field::SQRV] & 0x7
67 }
68
69 #[inline]
71 pub fn qqic(&self) -> u8 {
72 let data = self.buffer.as_ref();
73 data[field::QQIC]
74 }
75
76 #[inline]
78 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
84impl<T: AsRef<[u8]>> Packet<T> {
89 #[inline]
91 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
97impl<T: AsRef<[u8]> + AsMut<[u8]>> Packet<T> {
102 #[inline]
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 #[inline]
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.octets());
114 }
115
116 #[inline]
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 #[inline]
126 pub fn clear_s_flag(&mut self) {
127 let data = self.buffer.as_mut();
128 data[field::SQRV] &= 0x7;
129 }
130
131 #[inline]
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 #[inline]
141 pub fn set_qqic(&mut self, value: u8) {
142 let data = self.buffer.as_mut();
143 data[field::QQIC] = value;
144 }
145
146 #[inline]
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
154impl<T: AsRef<[u8]> + AsMut<[u8]>> Packet<T> {
159 #[inline]
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#[derive(Debug, PartialEq, Eq, Clone)]
169#[cfg_attr(feature = "defmt", derive(defmt::Format))]
170pub struct AddressRecord<T: AsRef<[u8]>> {
171 buffer: T,
172}
173
174impl<T: AsRef<[u8]>> AddressRecord<T> {
175 pub const fn new_unchecked(buffer: T) -> Self {
177 Self { buffer }
178 }
179
180 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 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 pub fn into_inner(self) -> T {
203 self.buffer
204 }
205}
206
207impl<T: AsRef<[u8]>> AddressRecord<T> {
212 #[inline]
214 pub fn record_type(&self) -> RecordType {
215 let data = self.buffer.as_ref();
216 RecordType::from(data[field::RECORD_TYPE])
217 }
218
219 #[inline]
221 pub fn aux_data_len(&self) -> u8 {
222 let data = self.buffer.as_ref();
223 data[field::AUX_DATA_LEN]
224 }
225
226 #[inline]
228 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 #[inline]
235 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
241impl<'a, T: AsRef<[u8]> + ?Sized> AddressRecord<&'a T> {
242 #[inline]
244 pub fn payload(&self) -> &'a [u8] {
245 let data = self.buffer.as_ref();
246 &data[field::RECORD_MCAST_ADDR.end..]
247 }
248}
249
250impl<T: AsMut<[u8]> + AsRef<[u8]>> AddressRecord<T> {
255 #[inline]
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 #[inline]
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 #[inline]
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 #[inline]
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.octets());
285 }
286}
287
288impl<T: AsRef<[u8]> + AsMut<[u8]>> AddressRecord<T> {
289 #[inline]
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#[derive(Debug, PartialEq, Eq, Clone, Copy)]
299#[cfg_attr(feature = "defmt", derive(defmt::Format))]
300pub struct AddressRecordRepr<'a> {
301 pub record_type: RecordType,
302 pub aux_data_len: u8,
303 pub num_srcs: u16,
304 pub mcast_addr: Ipv6Address,
305 pub payload: &'a [u8],
306}
307
308impl<'a> AddressRecordRepr<'a> {
309 pub const fn new(record_type: RecordType, mcast_addr: Ipv6Address) -> Self {
311 Self {
312 record_type,
313 aux_data_len: 0,
314 num_srcs: 0,
315 mcast_addr,
316 payload: &[],
317 }
318 }
319
320 pub fn parse<T>(record: &AddressRecord<&'a T>) -> Result<Self>
322 where
323 T: AsRef<[u8]> + ?Sized,
324 {
325 Ok(Self {
326 num_srcs: record.num_srcs(),
327 mcast_addr: record.mcast_addr(),
328 record_type: record.record_type(),
329 aux_data_len: record.aux_data_len(),
330 payload: record.payload(),
331 })
332 }
333
334 pub fn buffer_len(&self) -> usize {
337 field::RECORD_MCAST_ADDR.end
338 }
339
340 pub fn emit<T: AsRef<[u8]> + AsMut<[u8]>>(&self, record: &mut AddressRecord<T>) {
342 record.set_record_type(self.record_type);
343 record.set_aux_data_len(self.aux_data_len);
344 record.set_num_srcs(self.num_srcs);
345 record.set_mcast_addr(self.mcast_addr);
346 }
347}
348
349#[derive(Debug, PartialEq, Eq, Clone, Copy)]
351#[cfg_attr(feature = "defmt", derive(defmt::Format))]
352pub enum Repr<'a> {
353 Query {
354 max_resp_code: u16,
355 mcast_addr: Ipv6Address,
356 s_flag: bool,
357 qrv: u8,
358 qqic: u8,
359 num_srcs: u16,
360 data: &'a [u8],
361 },
362 Report {
363 nr_mcast_addr_rcrds: u16,
364 data: &'a [u8],
365 },
366 ReportRecordReprs(&'a [AddressRecordRepr<'a>]),
367}
368
369impl<'a> Repr<'a> {
370 pub fn parse<T>(packet: &Packet<&'a T>) -> Result<Repr<'a>>
372 where
373 T: AsRef<[u8]> + ?Sized,
374 {
375 packet.check_len()?;
376 match packet.msg_type() {
377 Message::MldQuery => Ok(Repr::Query {
378 max_resp_code: packet.max_resp_code(),
379 mcast_addr: packet.mcast_addr(),
380 s_flag: packet.s_flag(),
381 qrv: packet.qrv(),
382 qqic: packet.qqic(),
383 num_srcs: packet.num_srcs(),
384 data: packet.payload(),
385 }),
386 Message::MldReport => Ok(Repr::Report {
387 nr_mcast_addr_rcrds: packet.nr_mcast_addr_rcrds(),
388 data: packet.payload(),
389 }),
390 _ => Err(Error),
391 }
392 }
393
394 pub const fn buffer_len(&self) -> usize {
396 match self {
397 Repr::Query { data, .. } => field::QUERY_NUM_SRCS.end + data.len(),
398 Repr::Report { data, .. } => field::NR_MCAST_RCRDS.end + data.len(),
399 Repr::ReportRecordReprs(_data) => field::NR_MCAST_RCRDS.end,
400 }
401 }
402
403 pub fn emit<T>(&self, packet: &mut Packet<&mut T>)
405 where
406 T: AsRef<[u8]> + AsMut<[u8]> + ?Sized,
407 {
408 match self {
409 Repr::Query {
410 max_resp_code,
411 mcast_addr,
412 s_flag,
413 qrv,
414 qqic,
415 num_srcs,
416 data,
417 } => {
418 packet.set_msg_type(Message::MldQuery);
419 packet.set_msg_code(0);
420 packet.clear_reserved();
421 packet.set_max_resp_code(*max_resp_code);
422 packet.set_mcast_addr(*mcast_addr);
423 if *s_flag {
424 packet.set_s_flag();
425 } else {
426 packet.clear_s_flag();
427 }
428 packet.set_qrv(*qrv);
429 packet.set_qqic(*qqic);
430 packet.set_num_srcs(*num_srcs);
431 packet.payload_mut().copy_from_slice(&data[..]);
432 }
433 Repr::Report {
434 nr_mcast_addr_rcrds,
435 data,
436 } => {
437 packet.set_msg_type(Message::MldReport);
438 packet.set_msg_code(0);
439 packet.clear_reserved();
440 packet.set_nr_mcast_addr_rcrds(*nr_mcast_addr_rcrds);
441 packet.payload_mut().copy_from_slice(&data[..]);
442 }
443 Repr::ReportRecordReprs(records) => {
444 packet.set_msg_type(Message::MldReport);
445 packet.set_msg_code(0);
446 packet.clear_reserved();
447 packet.set_nr_mcast_addr_rcrds(records.len() as u16);
448 let mut payload = packet.payload_mut();
449 for record in *records {
450 record.emit(&mut AddressRecord::new_unchecked(&mut *payload));
451 payload = &mut payload[record.buffer_len()..];
452 }
453 }
454 }
455 }
456}
457
458#[cfg(test)]
459mod test {
460 use super::*;
461 use crate::phy::ChecksumCapabilities;
462 use crate::wire::icmpv6::Message;
463 use crate::wire::{Icmpv6Repr, IPV6_LINK_LOCAL_ALL_NODES, IPV6_LINK_LOCAL_ALL_ROUTERS};
464
465 static QUERY_PACKET_BYTES: [u8; 44] = [
466 0x82, 0x00, 0x73, 0x74, 0x04, 0x00, 0x00, 0x00, 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
467 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0a, 0x12, 0x00, 0x01, 0xff, 0x02,
468 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
469 ];
470
471 static QUERY_PACKET_PAYLOAD: [u8; 16] = [
472 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
473 0x02,
474 ];
475
476 static REPORT_PACKET_BYTES: [u8; 44] = [
477 0x8f, 0x00, 0x73, 0x85, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0xff, 0x02, 0x00,
478 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0x02,
479 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
480 ];
481
482 static REPORT_PACKET_PAYLOAD: [u8; 36] = [
483 0x01, 0x00, 0x00, 0x01, 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
484 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
485 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
486 ];
487
488 fn create_repr<'a>(ty: Message) -> Icmpv6Repr<'a> {
489 match ty {
490 Message::MldQuery => Icmpv6Repr::Mld(Repr::Query {
491 max_resp_code: 0x400,
492 mcast_addr: IPV6_LINK_LOCAL_ALL_NODES,
493 s_flag: true,
494 qrv: 0x02,
495 qqic: 0x12,
496 num_srcs: 0x01,
497 data: &QUERY_PACKET_PAYLOAD,
498 }),
499 Message::MldReport => Icmpv6Repr::Mld(Repr::Report {
500 nr_mcast_addr_rcrds: 1,
501 data: &REPORT_PACKET_PAYLOAD,
502 }),
503 _ => {
504 panic!("Message type must be a MLDv2 message type");
505 }
506 }
507 }
508
509 #[test]
510 fn test_query_deconstruct() {
511 let packet = Packet::new_unchecked(&QUERY_PACKET_BYTES[..]);
512 assert_eq!(packet.msg_type(), Message::MldQuery);
513 assert_eq!(packet.msg_code(), 0);
514 assert_eq!(packet.checksum(), 0x7374);
515 assert_eq!(packet.max_resp_code(), 0x0400);
516 assert_eq!(packet.mcast_addr(), IPV6_LINK_LOCAL_ALL_NODES);
517 assert!(packet.s_flag());
518 assert_eq!(packet.qrv(), 0x02);
519 assert_eq!(packet.qqic(), 0x12);
520 assert_eq!(packet.num_srcs(), 0x01);
521 assert_eq!(
522 Ipv6Address::from_bytes(packet.payload()),
523 IPV6_LINK_LOCAL_ALL_ROUTERS
524 );
525 }
526
527 #[test]
528 fn test_query_construct() {
529 let mut bytes = [0xff; 44];
530 let mut packet = Packet::new_unchecked(&mut bytes[..]);
531 packet.set_msg_type(Message::MldQuery);
532 packet.set_msg_code(0);
533 packet.set_max_resp_code(0x0400);
534 packet.set_mcast_addr(IPV6_LINK_LOCAL_ALL_NODES);
535 packet.set_s_flag();
536 packet.set_qrv(0x02);
537 packet.set_qqic(0x12);
538 packet.set_num_srcs(0x01);
539 packet
540 .payload_mut()
541 .copy_from_slice(&IPV6_LINK_LOCAL_ALL_ROUTERS.octets());
542 packet.clear_reserved();
543 packet.fill_checksum(&IPV6_LINK_LOCAL_ALL_NODES, &IPV6_LINK_LOCAL_ALL_ROUTERS);
544 assert_eq!(&*packet.into_inner(), &QUERY_PACKET_BYTES[..]);
545 }
546
547 #[test]
548 fn test_record_deconstruct() {
549 let packet = Packet::new_unchecked(&REPORT_PACKET_BYTES[..]);
550 assert_eq!(packet.msg_type(), Message::MldReport);
551 assert_eq!(packet.msg_code(), 0);
552 assert_eq!(packet.checksum(), 0x7385);
553 assert_eq!(packet.nr_mcast_addr_rcrds(), 0x01);
554 let addr_rcrd = AddressRecord::new_unchecked(packet.payload());
555 assert_eq!(addr_rcrd.record_type(), RecordType::ModeIsInclude);
556 assert_eq!(addr_rcrd.aux_data_len(), 0x00);
557 assert_eq!(addr_rcrd.num_srcs(), 0x01);
558 assert_eq!(addr_rcrd.mcast_addr(), IPV6_LINK_LOCAL_ALL_NODES);
559 assert_eq!(
560 Ipv6Address::from_bytes(addr_rcrd.payload()),
561 IPV6_LINK_LOCAL_ALL_ROUTERS
562 );
563 }
564
565 #[test]
566 fn test_record_construct() {
567 let mut bytes = [0xff; 44];
568 let mut packet = Packet::new_unchecked(&mut bytes[..]);
569 packet.set_msg_type(Message::MldReport);
570 packet.set_msg_code(0);
571 packet.clear_reserved();
572 packet.set_nr_mcast_addr_rcrds(1);
573 {
574 let mut addr_rcrd = AddressRecord::new_unchecked(packet.payload_mut());
575 addr_rcrd.set_record_type(RecordType::ModeIsInclude);
576 addr_rcrd.set_aux_data_len(0);
577 addr_rcrd.set_num_srcs(1);
578 addr_rcrd.set_mcast_addr(IPV6_LINK_LOCAL_ALL_NODES);
579 addr_rcrd
580 .payload_mut()
581 .copy_from_slice(&IPV6_LINK_LOCAL_ALL_ROUTERS.octets());
582 }
583 packet.fill_checksum(&IPV6_LINK_LOCAL_ALL_NODES, &IPV6_LINK_LOCAL_ALL_ROUTERS);
584 assert_eq!(&*packet.into_inner(), &REPORT_PACKET_BYTES[..]);
585 }
586
587 #[test]
588 fn test_query_repr_parse() {
589 let packet = Packet::new_unchecked(&QUERY_PACKET_BYTES[..]);
590 let repr = Icmpv6Repr::parse(
591 &IPV6_LINK_LOCAL_ALL_NODES,
592 &IPV6_LINK_LOCAL_ALL_ROUTERS,
593 &packet,
594 &ChecksumCapabilities::default(),
595 );
596 assert_eq!(repr, Ok(create_repr(Message::MldQuery)));
597 }
598
599 #[test]
600 fn test_report_repr_parse() {
601 let packet = Packet::new_unchecked(&REPORT_PACKET_BYTES[..]);
602 let repr = Icmpv6Repr::parse(
603 &IPV6_LINK_LOCAL_ALL_NODES,
604 &IPV6_LINK_LOCAL_ALL_ROUTERS,
605 &packet,
606 &ChecksumCapabilities::default(),
607 );
608 assert_eq!(repr, Ok(create_repr(Message::MldReport)));
609 }
610
611 #[test]
612 fn test_query_repr_emit() {
613 let mut bytes = [0x2a; 44];
614 let mut packet = Packet::new_unchecked(&mut bytes[..]);
615 let repr = create_repr(Message::MldQuery);
616 repr.emit(
617 &IPV6_LINK_LOCAL_ALL_NODES,
618 &IPV6_LINK_LOCAL_ALL_ROUTERS,
619 &mut packet,
620 &ChecksumCapabilities::default(),
621 );
622 assert_eq!(&*packet.into_inner(), &QUERY_PACKET_BYTES[..]);
623 }
624
625 #[test]
626 fn test_report_repr_emit() {
627 let mut bytes = [0x2a; 44];
628 let mut packet = Packet::new_unchecked(&mut bytes[..]);
629 let repr = create_repr(Message::MldReport);
630 repr.emit(
631 &IPV6_LINK_LOCAL_ALL_NODES,
632 &IPV6_LINK_LOCAL_ALL_ROUTERS,
633 &mut packet,
634 &ChecksumCapabilities::default(),
635 );
636 assert_eq!(&*packet.into_inner(), &REPORT_PACKET_BYTES[..]);
637 }
638}