ya_relay_stack/
packet.rs

1#![allow(unused)]
2
3use self::field::*;
4use smoltcp::wire::{IpAddress, Ipv4Address, Ipv6Address};
5use std::convert::TryFrom;
6use std::ops::Deref;
7
8use crate::{Error, Protocol};
9
10pub const ETHERNET_HDR_SIZE: usize = 14;
11pub const IP4_HDR_SIZE: usize = 20;
12pub const IP6_HDR_SIZE: usize = 40;
13pub const TCP_HDR_SIZE: usize = 20;
14pub const UDP_HDR_SIZE: usize = 20;
15
16mod field {
17    /// Field slice range within packet bytes
18    pub type Field = std::ops::Range<usize>;
19    /// Field bit range within a packet byte
20    pub type BitField = (usize, std::ops::Range<usize>);
21    /// Unhandled packet data range
22    pub type Rest = std::ops::RangeFrom<usize>;
23}
24
25pub struct EtherField;
26impl EtherField {
27    pub const DST_MAC: Field = 0..6;
28    pub const SRC_MAC: Field = 6..12;
29    pub const ETHER_TYPE: Field = 12..14;
30    pub const PAYLOAD: Rest = 14..;
31}
32
33#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
34#[non_exhaustive]
35pub enum EtherType {
36    Ip,
37    Arp,
38}
39
40#[non_exhaustive]
41pub enum EtherFrame {
42    /// EtherType IP
43    Ip(Box<[u8]>),
44    /// EtherType ARP
45    Arp(Box<[u8]>),
46}
47
48impl EtherFrame {
49    pub fn peek_type(data: &[u8]) -> Result<EtherType, Error> {
50        if data.len() < ETHERNET_HDR_SIZE {
51            return Err(Error::PacketMalformed("Ethernet: frame too short".into()));
52        }
53
54        let proto = &data[EtherField::ETHER_TYPE];
55        match proto {
56            &[0x08, 0x00] | &[0x86, 0xdd] => {
57                IpPacket::peek(&data[ETHERNET_HDR_SIZE..])?;
58                Ok(EtherType::Ip)
59            }
60            &[0x08, 0x06] => {
61                ArpPacket::peek(&data[ETHERNET_HDR_SIZE..])?;
62                Ok(EtherType::Arp)
63            }
64            _ => Err(Error::ProtocolNotSupported(format!("0x{:02x?}", proto))),
65        }
66    }
67
68    pub fn peek_payload(data: &[u8]) -> Result<&[u8], Error> {
69        if data.len() < ETHERNET_HDR_SIZE {
70            return Err(Error::PacketMalformed("Ethernet: frame too short".into()));
71        }
72        Ok(&data[EtherField::PAYLOAD])
73    }
74
75    pub const fn payload_off() -> usize {
76        ETHERNET_HDR_SIZE
77    }
78
79    pub fn payload(&self) -> &[u8] {
80        &self.as_ref()[EtherField::PAYLOAD]
81    }
82}
83
84impl TryFrom<Box<[u8]>> for EtherFrame {
85    type Error = Error;
86
87    fn try_from(data: Box<[u8]>) -> Result<Self, Self::Error> {
88        match Self::peek_type(&data)? {
89            EtherType::Ip => Ok(EtherFrame::Ip(data)),
90            EtherType::Arp => Ok(EtherFrame::Arp(data)),
91        }
92    }
93}
94
95impl TryFrom<Vec<u8>> for EtherFrame {
96    type Error = Error;
97
98    #[inline]
99    fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
100        Self::try_from(value.into_boxed_slice())
101    }
102}
103
104impl From<EtherFrame> for Box<[u8]> {
105    fn from(frame: EtherFrame) -> Self {
106        match frame {
107            EtherFrame::Ip(b) | EtherFrame::Arp(b) => b,
108        }
109    }
110}
111
112impl From<EtherFrame> for Vec<u8> {
113    fn from(frame: EtherFrame) -> Self {
114        Into::<Box<[u8]>>::into(frame).into()
115    }
116}
117
118impl AsRef<Box<[u8]>> for EtherFrame {
119    fn as_ref(&self) -> &Box<[u8]> {
120        match self {
121            Self::Ip(b) | Self::Arp(b) => b,
122        }
123    }
124}
125
126impl std::fmt::Display for EtherFrame {
127    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
128        match self {
129            EtherFrame::Ip(_) => write!(f, "IP"),
130            EtherFrame::Arp(_) => write!(f, "ARP"),
131        }
132    }
133}
134
135pub trait PeekPacket<'a> {
136    fn peek(data: &'a [u8]) -> Result<(), Error>;
137    fn packet(data: &'a [u8]) -> Self;
138}
139
140pub enum IpPacket<'a> {
141    V4(IpV4Packet<'a>),
142    V6(IpV6Packet<'a>),
143}
144
145impl<'a> IpPacket<'a> {
146    pub fn protocol(&self) -> u8 {
147        match self {
148            Self::V4(ip) => ip.protocol,
149            Self::V6(ip) => ip.protocol,
150        }
151    }
152
153    pub fn src_address(&self) -> &'a [u8] {
154        match self {
155            Self::V4(ip) => ip.src_address,
156            Self::V6(ip) => ip.src_address,
157        }
158    }
159
160    pub fn dst_address(&self) -> &'a [u8] {
161        match self {
162            Self::V4(ip) => ip.dst_address,
163            Self::V6(ip) => ip.inferred_dst_address(),
164        }
165    }
166
167    pub fn payload(&self) -> &'a [u8] {
168        match self {
169            Self::V4(ip) => ip.payload,
170            Self::V6(ip) => ip.payload,
171        }
172    }
173
174    pub fn payload_off(&self) -> usize {
175        match self {
176            Self::V4(ip) => ip.payload_off(),
177            Self::V6(ip) => ip.payload_off(),
178        }
179    }
180
181    pub fn to_tcp(&self) -> Option<TcpPacket> {
182        match self.protocol() {
183            6 => Some(TcpPacket::packet(self.payload())),
184            _ => None,
185        }
186    }
187
188    pub fn is_broadcast(&self) -> bool {
189        match self {
190            Self::V4(ip) => ip.dst_address[0..4] == [255, 255, 255, 255],
191            Self::V6(_) => false,
192        }
193    }
194
195    pub fn is_multicast(&self) -> bool {
196        match self {
197            Self::V4(ip) => ip.dst_address[0] & 0xf0 == 224,
198            Self::V6(ip) => ip.dst_address[0] == 0xff,
199        }
200    }
201}
202
203impl<'a> PeekPacket<'a> for IpPacket<'a> {
204    fn peek(data: &'a [u8]) -> Result<(), Error> {
205        match data[0] >> 4 {
206            4 => IpV4Packet::peek(data),
207            6 => IpV6Packet::peek(data),
208            _ => Err(Error::PacketMalformed("IP: invalid version".into())),
209        }
210    }
211
212    fn packet(data: &'a [u8]) -> Self {
213        if data[0] >> 4 == 4 {
214            Self::V4(IpV4Packet::packet(data))
215        } else {
216            Self::V6(IpV6Packet::packet(data))
217        }
218    }
219}
220
221pub struct IpV4Field;
222impl IpV4Field {
223    pub const IHL: BitField = (0, 4..8);
224    pub const TOTAL_LEN: Field = 2..4;
225    pub const PROTOCOL: Field = 9..10;
226    pub const SRC_ADDR: Field = 12..16;
227    pub const DST_ADDR: Field = 16..20;
228}
229
230pub struct IpV4Packet<'a> {
231    pub src_address: &'a [u8],
232    pub dst_address: &'a [u8],
233    pub protocol: u8,
234    pub payload: &'a [u8],
235    pub payload_off: usize,
236}
237
238impl<'a> IpV4Packet<'a> {
239    pub const MIN_HEADER_LEN: usize = 20;
240
241    #[inline]
242    pub fn payload_off(&self) -> usize {
243        self.payload_off
244    }
245
246    fn read_header_len(data: &'a [u8]) -> usize {
247        let ihl = get_bit_field(data, IpV4Field::IHL) as usize;
248        if ihl >= 5 {
249            4 * ihl
250        } else {
251            Self::MIN_HEADER_LEN
252        }
253    }
254}
255
256impl<'a> PeekPacket<'a> for IpV4Packet<'a> {
257    fn peek(data: &'a [u8]) -> Result<(), Error> {
258        let data_len = data.len();
259        if data_len < Self::MIN_HEADER_LEN {
260            return Err(Error::PacketMalformed("IPv4: header too short".into()));
261        }
262
263        let len = ntoh_u16(&data[IpV4Field::TOTAL_LEN]).unwrap() as usize;
264        let payload_off = Self::read_header_len(data);
265
266        if len < payload_off {
267            return Err(Error::PacketMalformed("IPv4: payload too short".into()));
268        }
269        Ok(())
270    }
271
272    fn packet(data: &'a [u8]) -> Self {
273        let payload_off = Self::read_header_len(data);
274
275        Self {
276            src_address: &data[IpV4Field::SRC_ADDR],
277            dst_address: &data[IpV4Field::DST_ADDR],
278            protocol: data[IpV4Field::PROTOCOL][0],
279            payload: &data[payload_off..],
280            payload_off,
281        }
282    }
283}
284
285pub struct IpV6Field;
286impl IpV6Field {
287    pub const PAYLOAD_LEN: Field = 4..6;
288    pub const PROTOCOL: Field = 6..7;
289    pub const SRC_ADDR: Field = 8..24;
290    pub const DST_ADDR: Field = 24..40;
291    pub const PAYLOAD: Rest = 40..; // extension headers are not supported
292}
293
294pub struct IpV6Packet<'a> {
295    pub src_address: &'a [u8],
296    dst_address: &'a [u8],
297    pub protocol: u8,
298    pub payload: &'a [u8],
299    pub next_header: IpV6NextHeader<'a>,
300}
301
302impl<'a> IpV6Packet<'a> {
303    pub const MIN_HEADER_LEN: usize = 40;
304
305    #[inline]
306    pub fn payload_off(&self) -> usize {
307        IpV6Field::PAYLOAD.start
308    }
309
310    pub fn inferred_dst_address(&self) -> &'a [u8] {
311        match &self.next_header {
312            IpV6NextHeader::IcmpV6(icmp_v6) => icmp_v6.dst_address().unwrap_or(self.dst_address),
313            IpV6NextHeader::Other => self.dst_address,
314        }
315    }
316}
317
318impl<'a> PeekPacket<'a> for IpV6Packet<'a> {
319    fn peek(data: &'a [u8]) -> Result<(), Error> {
320        let data_len = data.len();
321        if data_len < Self::MIN_HEADER_LEN {
322            return Err(Error::PacketMalformed("IPv6: header too short".into()));
323        }
324
325        let len = Self::MIN_HEADER_LEN + ntoh_u16(&data[IpV6Field::PAYLOAD_LEN]).unwrap() as usize;
326        if data_len < len {
327            return Err(Error::PacketMalformed("IPv6: payload too short".into()));
328        } else if len == Self::MIN_HEADER_LEN {
329            return Err(Error::ProtocolNotSupported("IPv6: jumbogram".into()));
330        }
331
332        if data[IpV6Field::PROTOCOL][0] == 58 {
333            IcmpV6Packet::peek(&data[IpV6Field::PAYLOAD])?;
334        };
335
336        Ok(())
337    }
338
339    fn packet(data: &'a [u8]) -> Self {
340        let payload = &data[IpV6Field::PAYLOAD];
341        let protocol = data[IpV6Field::PROTOCOL][0];
342        let next_header = match protocol {
343            58 => IpV6NextHeader::IcmpV6(IcmpV6Packet::packet(payload)),
344            _ => IpV6NextHeader::Other,
345        };
346
347        Self {
348            src_address: &data[IpV6Field::SRC_ADDR],
349            dst_address: &data[IpV6Field::DST_ADDR],
350            protocol,
351            payload,
352            next_header,
353        }
354    }
355}
356
357pub enum IpV6NextHeader<'a> {
358    IcmpV6(IcmpV6Packet<'a>),
359    Other,
360}
361
362pub struct IcmpV6Field;
363impl IcmpV6Field {
364    pub const TYPE: Field = 0..1;
365    pub const CODE: Field = 1..2;
366    pub const CHECKSUM: Field = 2..4;
367    pub const PAYLOAD: Rest = 4..;
368}
369
370pub struct IcmpV6Packet<'a> {
371    pub type_: u8,
372    pub message: IcmpV6Message<'a>,
373}
374
375impl<'a> IcmpV6Packet<'a> {
376    pub const MIN_HEADER_SIZE: usize = 4;
377
378    pub fn dst_address(&self) -> Option<&'a [u8]> {
379        match &self.message {
380            IcmpV6Message::NdpNeighborSolicitation { dst_address, .. } => Some(dst_address),
381            _ => None,
382        }
383    }
384}
385
386impl<'a> PeekPacket<'a> for IcmpV6Packet<'a> {
387    fn peek(data: &'a [u8]) -> Result<(), Error> {
388        let data_len = data.len();
389        if data_len < Self::MIN_HEADER_SIZE {
390            return Err(Error::PacketMalformed("ICMPv6: packet too short".into()));
391        }
392
393        match data[IcmpV6Field::TYPE][0] {
394            135 => {
395                if data_len < Self::MIN_HEADER_SIZE + 16 {
396                    return Err(Error::PacketMalformed("ICMPv6: payload too short".into()));
397                }
398            }
399            _ => {
400                if data_len < Self::MIN_HEADER_SIZE {
401                    return Err(Error::PacketMalformed("ICMPv6: payload too short".into()));
402                }
403            }
404        }
405
406        Ok(())
407    }
408
409    fn packet(data: &'a [u8]) -> Self {
410        let type_ = data[IcmpV6Field::TYPE][0];
411        let payload = &data[IcmpV6Field::PAYLOAD];
412        Self {
413            type_,
414            message: match type_ {
415                IcmpV6Message::NDP_ROUTER_SOLICITATION => IcmpV6Message::NdpRouterSolicitation {},
416                IcmpV6Message::NDP_ROUTER_ADVERTISEMENT => IcmpV6Message::NdpRouterAdvertisement {},
417                IcmpV6Message::NDP_NEIGHBOR_SOLICITATION => {
418                    IcmpV6Message::NdpNeighborSolicitation {
419                        dst_address: &payload[NdpNeighborSolicitationField::TARGET_ADDRESS],
420                    }
421                }
422                IcmpV6Message::NDP_NEIGHBOR_ADVERTISEMENT => {
423                    IcmpV6Message::NdpNeighborAdvertisement {}
424                }
425                IcmpV6Message::NDP_REDIRECT => IcmpV6Message::NdpRedirect {},
426                _ => IcmpV6Message::Other,
427            },
428        }
429    }
430}
431
432pub enum IcmpV6Message<'a> {
433    NdpRouterSolicitation {},
434    NdpRouterAdvertisement {},
435    NdpNeighborSolicitation { dst_address: &'a [u8] },
436    NdpNeighborAdvertisement {},
437    NdpRedirect {},
438    Other,
439}
440
441impl<'a> IcmpV6Message<'a> {
442    pub const NDP_ROUTER_SOLICITATION: u8 = 133;
443    pub const NDP_ROUTER_ADVERTISEMENT: u8 = 134;
444    pub const NDP_NEIGHBOR_SOLICITATION: u8 = 135;
445    pub const NDP_NEIGHBOR_ADVERTISEMENT: u8 = 136;
446    pub const NDP_REDIRECT: u8 = 137;
447}
448
449pub struct NdpNeighborSolicitationField;
450impl NdpNeighborSolicitationField {
451    pub const TARGET_ADDRESS: Field = 4..20;
452}
453
454pub struct NdpRouterAdvertisementField;
455impl NdpRouterAdvertisementField {
456    /// Hop count to set
457    pub const CUR_HOP_LIMIT: Field = 0..1;
458    /// Managed address configuration flag
459    pub const M: BitField = (1, 0..1);
460    /// Other configuration flag
461    pub const O: BitField = (1, 1..2);
462    /// Router lifetime in seconds
463    pub const ROUTER_LIFETIME: Field = 2..4;
464    /// The time, in milliseconds, that a node assumes a neighbor is
465    /// reachable after having received a reachability confirmation
466    pub const REACHABLE_TIME: Field = 4..8;
467    /// The time, in milliseconds, between retransmitted Neighbor Solicitation messages
468    pub const RETRANS_TIMER: Field = 8..16;
469}
470
471pub struct NdpNeighborAdvertisementField;
472impl NdpNeighborAdvertisementField {
473    /// Router flag
474    pub const R: BitField = (0, 0..1);
475    /// Solicited flag
476    pub const S: BitField = (0, 1..2);
477    /// Override flag
478    pub const O: BitField = (0, 2..3);
479    /// Target address
480    pub const TARGET_ADDRESS: Field = 4..20;
481}
482
483pub struct ArpField;
484impl ArpField {
485    /// Hardware type
486    pub const HTYPE: Field = 0..2;
487    /// Protocol type
488    pub const PTYPE: Field = 2..4;
489    /// Hardware length
490    pub const HLEN: Field = 4..5;
491    /// Protocol length
492    pub const PLEN: Field = 5..6;
493    /// Operation
494    pub const OP: Field = 6..8;
495    /// Sender hardware address
496    pub const SHA: Field = 8..14;
497    /// Sender protocol address
498    pub const SPA: Field = 14..18;
499    /// Target hardware address
500    pub const THA: Field = 18..24;
501    /// Target protocol address
502    pub const TPA: Field = 24..28;
503}
504
505pub struct ArpPacket<'a> {
506    inner: &'a [u8],
507}
508
509impl<'a> ArpPacket<'a> {
510    #[inline(always)]
511    pub fn get_field(&self, field: Field) -> &[u8] {
512        &self.inner[field]
513    }
514}
515
516impl<'a> PeekPacket<'a> for ArpPacket<'a> {
517    fn peek(data: &'a [u8]) -> Result<(), Error> {
518        if data.len() < 28 {
519            return Err(Error::PacketMalformed("ARP: packet too short".into()));
520        }
521        Ok(())
522    }
523
524    fn packet(data: &'a [u8]) -> Self {
525        Self { inner: data }
526    }
527}
528
529pub struct ArpPacketMut<'a> {
530    inner: &'a mut [u8],
531}
532
533impl<'a> ArpPacketMut<'a> {
534    pub fn set_field(&mut self, field: Field, value: &[u8]) {
535        let value = &value[..field.end];
536        self.inner[field].copy_from_slice(value);
537    }
538
539    pub fn freeze(self) -> ArpPacket<'a> {
540        ArpPacket { inner: self.inner }
541    }
542}
543
544pub struct TcpField;
545impl TcpField {
546    pub const SRC_PORT: Field = 0..2;
547    pub const DST_PORT: Field = 2..4;
548    pub const DATA_OFF: BitField = (12, 0..4);
549}
550
551pub struct TcpPacket<'a> {
552    pub src_port: &'a [u8],
553    pub dst_port: &'a [u8],
554    pub payload_off: usize,
555    pub payload_size: usize,
556}
557
558impl<'a> TcpPacket<'a> {
559    pub fn src_port(&self) -> u16 {
560        ntoh_u16(self.src_port).unwrap()
561    }
562
563    pub fn dst_port(&self) -> u16 {
564        ntoh_u16(self.dst_port).unwrap()
565    }
566}
567
568impl<'a> PeekPacket<'a> for TcpPacket<'a> {
569    fn peek(data: &'a [u8]) -> Result<(), Error> {
570        if data.len() < 20 {
571            return Err(Error::PacketMalformed("TCP: packet too short".into()));
572        }
573
574        let payload_off = get_bit_field(data, TcpField::DATA_OFF) as usize;
575        if data.len() < payload_off {
576            return Err(Error::PacketMalformed("TCP: packet too short".into()));
577        }
578
579        Ok(())
580    }
581
582    fn packet(data: &'a [u8]) -> Self {
583        let payload_off = get_bit_field(data, TcpField::DATA_OFF) as usize;
584        let payload_size = data.len().saturating_sub(payload_off);
585        Self {
586            src_port: &data[TcpField::SRC_PORT],
587            dst_port: &data[TcpField::DST_PORT],
588            payload_off,
589            payload_size,
590        }
591    }
592}
593
594pub struct UdpField;
595impl UdpField {
596    pub const SRC_PORT: Field = 0..2;
597    pub const DST_PORT: Field = 2..4;
598    pub const LEN: Field = 4..6;
599    pub const PAYLOAD: Rest = 8..;
600}
601
602pub struct UdpPacket<'a> {
603    pub src_port: &'a [u8],
604    pub dst_port: &'a [u8],
605    pub payload_size: usize,
606}
607
608impl<'a> UdpPacket<'a> {
609    pub fn src_port(&self) -> u16 {
610        ntoh_u16(self.src_port).unwrap()
611    }
612
613    pub fn dst_port(&self) -> u16 {
614        ntoh_u16(self.dst_port).unwrap()
615    }
616}
617
618impl<'a> PeekPacket<'a> for UdpPacket<'a> {
619    fn peek(data: &'a [u8]) -> Result<(), Error> {
620        if data.len() < 8 {
621            return Err(Error::PacketMalformed("UDP: packet too short".into()));
622        }
623
624        let len = ntoh_u16(&data[UdpField::LEN]).unwrap() as usize;
625        if data.len() < len {
626            return Err(Error::PacketMalformed("UDP: packet too short".into()));
627        }
628
629        Ok(())
630    }
631
632    fn packet(data: &'a [u8]) -> Self {
633        let payload_size = data.len().saturating_sub(UdpField::PAYLOAD.start);
634        Self {
635            src_port: &data[UdpField::SRC_PORT],
636            dst_port: &data[UdpField::DST_PORT],
637            payload_size,
638        }
639    }
640}
641
642/// Convert `IpAddress` to boxed bytes
643#[inline(always)]
644pub fn ip_hton(ip: IpAddress) -> Box<[u8]> {
645    match ip {
646        IpAddress::Ipv4(ip) => ip.as_bytes().into(),
647        IpAddress::Ipv6(ip) => ip.as_bytes().into(),
648        _ => vec![0, 0, 0, 0].into(),
649    }
650}
651
652/// Convert a byte slice to `IpAddress`
653#[inline(always)]
654pub fn ip_ntoh(data: &[u8]) -> Option<IpAddress> {
655    if data.len() == 4 {
656        Some(IpAddress::v4(data[0], data[1], data[2], data[3]))
657    } else if data.len() == 16 {
658        Some(IpAddress::Ipv6(Ipv6Address::from_bytes(data)))
659    } else {
660        None
661    }
662}
663
664pub fn write_field(data: &mut [u8], field: Field, value: &[u8]) -> bool {
665    if value.len() == field.len() && data.len() >= field.end {
666        data[field].copy_from_slice(value);
667        true
668    } else {
669        false
670    }
671}
672
673/// Read a bit field spanning over a single byte
674#[inline(always)]
675pub fn read_bit_field(data: &[u8], bit_field: BitField) -> Option<u8> {
676    if data.len() >= bit_field.0 && bit_field.1.len() <= 8 {
677        Some(get_bit_field(data, bit_field))
678    } else {
679        None
680    }
681}
682
683/// Write a bit field spanning over a single byte
684#[inline(always)]
685pub fn write_bit_field(data: &mut [u8], bit_field: BitField, value: u8) -> bool {
686    if data.len() >= bit_field.0 && bit_field.1.len() <= 8 {
687        set_bit_field(data, bit_field, value);
688        true
689    } else {
690        false
691    }
692}
693
694#[inline(always)]
695fn get_bit_field(data: &[u8], bit_field: BitField) -> u8 {
696    (data[bit_field.0] << bit_field.1.start) >> (8 - bit_field.1.len())
697}
698
699#[inline(always)]
700fn set_bit_field(data: &mut [u8], bit_field: BitField, value: u8) {
701    let bit_len = bit_field.1.len();
702    let mask = (0xff_u8 << (8 - bit_len)) >> bit_field.1.start;
703    data[bit_field.0] &= !mask;
704    data[bit_field.0] |= (value << (8 - bit_len)) >> bit_field.1.start;
705}
706
707macro_rules! impl_ntoh_n {
708    ($ident:ident, $ty:ty, $n:tt) => {
709        fn $ident(data: &[u8]) -> Option<$ty> {
710            match data.len() {
711                $n => {
712                    let mut result = [0u8; $n];
713                    result.copy_from_slice(&data[0..$n]);
714                    Some(<$ty>::from_be_bytes(result))
715                }
716                _ => None,
717            }
718        }
719    };
720}
721
722impl_ntoh_n!(ntoh_u16, u16, 2);
723impl_ntoh_n!(ntoh_u32, u32, 4);
724impl_ntoh_n!(ntoh_u64, u64, 8);
725
726#[cfg(test)]
727mod tests {
728    use crate::packet::{get_bit_field, set_bit_field};
729
730    #[test]
731    fn change_bit_field() {
732        for len in 1..8 {
733            for off in 0..8 {
734                let mut bytes = [0u8; 1];
735                let range = off..8.min(off + len);
736                println!("range: {:?}", range);
737
738                set_bit_field(&mut bytes, (0, range.clone()), 0xff);
739                println!("byte: {:#010b}", bytes[0]);
740
741                assert_eq!(
742                    get_bit_field(&bytes, (0, range.clone())),
743                    0xff_u8 >> (8 - range.len())
744                );
745            }
746        }
747    }
748}