Skip to main content

ant_quic/nat_traversal/
frames.rs

1// Copyright 2024 Saorsa Labs Ltd.
2//
3// This Saorsa Network Software is licensed under the General Public License (GPL), version 3.
4// Please see the file LICENSE-GPL, or visit <http://www.gnu.org/licenses/> for the full text.
5//
6// Full details available at https://saorsalabs.com/licenses
7
8//! NAT Traversal Frame Implementations
9//!
10//! This module implements the three required QUIC extension frames for NAT traversal
11//! as defined in draft-seemann-quic-nat-traversal-01:
12//! - ADD_ADDRESS
13//! - PUNCH_ME_NOW
14//! - REMOVE_ADDRESS
15//!
16//! These frames are used to coordinate NAT traversal between peers using a pure QUIC-native
17//! approach without relying on external protocols like STUN or ICE.
18//!
19//! # Multi-Transport Extension
20//!
21//! The ADD_ADDRESS frame has been extended to support multiple transport types beyond
22//! UDP/IP. The wire format includes a transport type indicator that allows peers to
23//! advertise addresses on different transports (BLE, LoRa, etc.).
24//!
25//! # Capability Flags
26//!
27//! The ADD_ADDRESS frame can optionally include capability flags that summarize the
28//! transport's characteristics. This allows peers to make informed routing decisions
29//! without a full capability exchange.
30//!
31//! ```text
32//! CapabilityFlags (u16 bitfield):
33//!   Bit 0: supports_full_quic - Can run full QUIC protocol
34//!   Bit 1: half_duplex - Link can only send OR receive at once
35//!   Bit 2: broadcast - Supports broadcast/multicast
36//!   Bit 3: metered - Connection has per-byte cost
37//!   Bit 4: power_constrained - Battery-operated device
38//!   Bit 5: link_layer_acks - Transport provides acknowledgements
39//!   Bits 6-7: mtu_tier - MTU classification (0=<500, 1=500-1200, 2=1200-4096, 3=>4096)
40//!   Bits 8-9: bandwidth_tier - Bandwidth classification (0=VeryLow, 1=Low, 2=Medium, 3=High)
41//!   Bits 10-11: latency_tier - RTT classification (0=>2s, 1=500ms-2s, 2=100ms-500ms, 3=<100ms)
42//!   Bits 12-15: Reserved for future use
43//! ```
44
45use bytes::{Buf, BufMut};
46use std::net::{IpAddr, SocketAddr};
47use std::time::Duration;
48
49use crate::coding::{self, Codec};
50use crate::transport::{TransportAddr, TransportCapabilities, TransportType};
51use crate::varint::VarInt;
52
53/// Compact capability flags for wire transmission in ADD_ADDRESS frames
54///
55/// This is a compact 16-bit representation of transport capabilities suitable
56/// for wire transmission. It summarizes the most important routing-relevant
57/// characteristics without the full detail of [`TransportCapabilities`].
58///
59/// # Wire Format
60///
61/// ```text
62/// Bit 0: supports_full_quic
63/// Bit 1: half_duplex
64/// Bit 2: broadcast
65/// Bit 3: metered
66/// Bit 4: power_constrained
67/// Bit 5: link_layer_acks
68/// Bits 6-7: mtu_tier (0=<500, 1=500-1200, 2=1200-4096, 3=>4096)
69/// Bits 8-9: bandwidth_tier (0=VeryLow, 1=Low, 2=Medium, 3=High)
70/// Bits 10-11: latency_tier (0=>2s, 1=500ms-2s, 2=100ms-500ms, 3=<100ms)
71/// Bits 12-15: Reserved
72/// ```
73#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
74pub struct CapabilityFlags(u16);
75
76impl CapabilityFlags {
77    /// Bit positions for capability flags
78    const SUPPORTS_FULL_QUIC: u16 = 1 << 0;
79    const HALF_DUPLEX: u16 = 1 << 1;
80    const BROADCAST: u16 = 1 << 2;
81    const METERED: u16 = 1 << 3;
82    const POWER_CONSTRAINED: u16 = 1 << 4;
83    const LINK_LAYER_ACKS: u16 = 1 << 5;
84    const MTU_TIER_SHIFT: u16 = 6;
85    const MTU_TIER_MASK: u16 = 0b11 << 6;
86    const BANDWIDTH_TIER_SHIFT: u16 = 8;
87    const BANDWIDTH_TIER_MASK: u16 = 0b11 << 8;
88    const LATENCY_TIER_SHIFT: u16 = 10;
89    const LATENCY_TIER_MASK: u16 = 0b11 << 10;
90
91    /// Create empty capability flags (all false, tier 0)
92    pub const fn empty() -> Self {
93        Self(0)
94    }
95
96    /// Create capability flags from raw u16 value
97    pub const fn from_raw(raw: u16) -> Self {
98        Self(raw)
99    }
100
101    /// Get the raw u16 value
102    pub const fn to_raw(self) -> u16 {
103        self.0
104    }
105
106    /// Create capability flags from full TransportCapabilities
107    pub fn from_capabilities(caps: &TransportCapabilities) -> Self {
108        let mut flags = 0u16;
109
110        if caps.supports_full_quic() {
111            flags |= Self::SUPPORTS_FULL_QUIC;
112        }
113        if caps.half_duplex {
114            flags |= Self::HALF_DUPLEX;
115        }
116        if caps.broadcast {
117            flags |= Self::BROADCAST;
118        }
119        if caps.metered {
120            flags |= Self::METERED;
121        }
122        if caps.power_constrained {
123            flags |= Self::POWER_CONSTRAINED;
124        }
125        if caps.link_layer_acks {
126            flags |= Self::LINK_LAYER_ACKS;
127        }
128
129        // MTU tier: 0=<500, 1=500-1200, 2=1200-4096, 3=>4096
130        let mtu_tier = match caps.mtu {
131            0..=499 => 0,
132            500..=1199 => 1,
133            1200..=4095 => 2,
134            _ => 3,
135        };
136        flags |= (mtu_tier as u16) << Self::MTU_TIER_SHIFT;
137
138        // Bandwidth tier: matches BandwidthClass
139        let bandwidth_tier = match caps.bandwidth_class() {
140            crate::transport::BandwidthClass::VeryLow => 0,
141            crate::transport::BandwidthClass::Low => 1,
142            crate::transport::BandwidthClass::Medium => 2,
143            crate::transport::BandwidthClass::High => 3,
144        };
145        flags |= (bandwidth_tier as u16) << Self::BANDWIDTH_TIER_SHIFT;
146
147        // Latency tier: 0=>2s, 1=500ms-2s, 2=100ms-500ms, 3=<100ms
148        let latency_tier = if caps.typical_rtt >= Duration::from_secs(2) {
149            0
150        } else if caps.typical_rtt >= Duration::from_millis(500) {
151            1
152        } else if caps.typical_rtt >= Duration::from_millis(100) {
153            2
154        } else {
155            3
156        };
157        flags |= (latency_tier as u16) << Self::LATENCY_TIER_SHIFT;
158
159        Self(flags)
160    }
161
162    /// Check if this transport supports full QUIC protocol
163    pub const fn supports_full_quic(self) -> bool {
164        (self.0 & Self::SUPPORTS_FULL_QUIC) != 0
165    }
166
167    /// Check if this is a half-duplex link
168    pub const fn half_duplex(self) -> bool {
169        (self.0 & Self::HALF_DUPLEX) != 0
170    }
171
172    /// Check if this transport supports broadcast
173    pub const fn broadcast(self) -> bool {
174        (self.0 & Self::BROADCAST) != 0
175    }
176
177    /// Check if this is a metered connection
178    pub const fn metered(self) -> bool {
179        (self.0 & Self::METERED) != 0
180    }
181
182    /// Check if this is a power-constrained device
183    pub const fn power_constrained(self) -> bool {
184        (self.0 & Self::POWER_CONSTRAINED) != 0
185    }
186
187    /// Check if link layer provides acknowledgements
188    pub const fn link_layer_acks(self) -> bool {
189        (self.0 & Self::LINK_LAYER_ACKS) != 0
190    }
191
192    /// Get MTU tier (0-3)
193    pub const fn mtu_tier(self) -> u8 {
194        ((self.0 & Self::MTU_TIER_MASK) >> Self::MTU_TIER_SHIFT) as u8
195    }
196
197    /// Get bandwidth tier (0-3, maps to BandwidthClass)
198    pub const fn bandwidth_tier(self) -> u8 {
199        ((self.0 & Self::BANDWIDTH_TIER_MASK) >> Self::BANDWIDTH_TIER_SHIFT) as u8
200    }
201
202    /// Get latency tier (0-3, 3 being fastest)
203    pub const fn latency_tier(self) -> u8 {
204        ((self.0 & Self::LATENCY_TIER_MASK) >> Self::LATENCY_TIER_SHIFT) as u8
205    }
206
207    /// Get approximate MTU range for this tier
208    pub fn mtu_range(self) -> (usize, usize) {
209        match self.mtu_tier() {
210            0 => (0, 499),
211            1 => (500, 1199),
212            2 => (1200, 4095),
213            _ => (4096, 65535),
214        }
215    }
216
217    /// Get approximate RTT range for this tier
218    pub fn latency_range(self) -> (Duration, Duration) {
219        match self.latency_tier() {
220            0 => (Duration::from_secs(2), Duration::from_secs(60)),
221            1 => (Duration::from_millis(500), Duration::from_secs(2)),
222            2 => (Duration::from_millis(100), Duration::from_millis(500)),
223            _ => (Duration::ZERO, Duration::from_millis(100)),
224        }
225    }
226
227    /// Builder-style method to set supports_full_quic flag
228    pub const fn with_supports_full_quic(mut self, value: bool) -> Self {
229        if value {
230            self.0 |= Self::SUPPORTS_FULL_QUIC;
231        } else {
232            self.0 &= !Self::SUPPORTS_FULL_QUIC;
233        }
234        self
235    }
236
237    /// Builder-style method to set half_duplex flag
238    pub const fn with_half_duplex(mut self, value: bool) -> Self {
239        if value {
240            self.0 |= Self::HALF_DUPLEX;
241        } else {
242            self.0 &= !Self::HALF_DUPLEX;
243        }
244        self
245    }
246
247    /// Builder-style method to set broadcast flag
248    pub const fn with_broadcast(mut self, value: bool) -> Self {
249        if value {
250            self.0 |= Self::BROADCAST;
251        } else {
252            self.0 &= !Self::BROADCAST;
253        }
254        self
255    }
256
257    /// Builder-style method to set metered flag
258    pub const fn with_metered(mut self, value: bool) -> Self {
259        if value {
260            self.0 |= Self::METERED;
261        } else {
262            self.0 &= !Self::METERED;
263        }
264        self
265    }
266
267    /// Builder-style method to set power_constrained flag
268    pub const fn with_power_constrained(mut self, value: bool) -> Self {
269        if value {
270            self.0 |= Self::POWER_CONSTRAINED;
271        } else {
272            self.0 &= !Self::POWER_CONSTRAINED;
273        }
274        self
275    }
276
277    /// Builder-style method to set link_layer_acks flag
278    pub const fn with_link_layer_acks(mut self, value: bool) -> Self {
279        if value {
280            self.0 |= Self::LINK_LAYER_ACKS;
281        } else {
282            self.0 &= !Self::LINK_LAYER_ACKS;
283        }
284        self
285    }
286
287    /// Builder-style method to set MTU tier (clamped to 0-3)
288    pub const fn with_mtu_tier(mut self, tier: u8) -> Self {
289        let tier = if tier > 3 { 3 } else { tier };
290        self.0 = (self.0 & !Self::MTU_TIER_MASK) | ((tier as u16) << Self::MTU_TIER_SHIFT);
291        self
292    }
293
294    /// Builder-style method to set bandwidth tier (clamped to 0-3)
295    pub const fn with_bandwidth_tier(mut self, tier: u8) -> Self {
296        let tier = if tier > 3 { 3 } else { tier };
297        self.0 =
298            (self.0 & !Self::BANDWIDTH_TIER_MASK) | ((tier as u16) << Self::BANDWIDTH_TIER_SHIFT);
299        self
300    }
301
302    /// Builder-style method to set latency tier (clamped to 0-3)
303    pub const fn with_latency_tier(mut self, tier: u8) -> Self {
304        let tier = if tier > 3 { 3 } else { tier };
305        self.0 = (self.0 & !Self::LATENCY_TIER_MASK) | ((tier as u16) << Self::LATENCY_TIER_SHIFT);
306        self
307    }
308
309    /// Create flags for typical UDP/IP broadband connection
310    pub const fn broadband() -> Self {
311        Self::empty()
312            .with_supports_full_quic(true)
313            .with_broadcast(true)
314            .with_mtu_tier(2) // 1200-4096
315            .with_bandwidth_tier(3) // High
316            .with_latency_tier(3) // <100ms
317    }
318
319    /// Create flags for typical BLE connection
320    pub const fn ble() -> Self {
321        Self::empty()
322            .with_broadcast(true)
323            .with_power_constrained(true)
324            .with_link_layer_acks(true)
325            .with_mtu_tier(0) // <500
326            .with_bandwidth_tier(2) // Medium
327            .with_latency_tier(2) // 100-500ms
328    }
329
330    /// Create flags for typical LoRa long-range connection
331    pub const fn lora_long_range() -> Self {
332        Self::empty()
333            .with_half_duplex(true)
334            .with_broadcast(true)
335            .with_power_constrained(true)
336            .with_mtu_tier(0) // <500
337            .with_bandwidth_tier(0) // VeryLow
338            .with_latency_tier(0) // >2s
339    }
340}
341
342/// Frame type for ADD_ADDRESS (draft-seemann-quic-nat-traversal-01)
343pub const FRAME_TYPE_ADD_ADDRESS: u64 = 0x3d7e90;
344/// Frame type for PUNCH_ME_NOW (draft-seemann-quic-nat-traversal-01)
345pub const FRAME_TYPE_PUNCH_ME_NOW: u64 = 0x3d7e91;
346/// Frame type for REMOVE_ADDRESS (draft-seemann-quic-nat-traversal-01)
347pub const FRAME_TYPE_REMOVE_ADDRESS: u64 = 0x3d7e92;
348
349/// ADD_ADDRESS frame for advertising candidate addresses
350///
351/// As defined in draft-seemann-quic-nat-traversal-01, this frame includes:
352/// - Sequence number (VarInt)
353/// - Priority (VarInt)
354/// - Transport type (VarInt) - extension for multi-transport support
355/// - Address (transport-specific format)
356/// - Capability flags (VarInt, optional) - extension for capability advertisement
357///
358/// # Wire Format
359///
360/// ```text
361/// Sequence (VarInt)
362/// Priority (VarInt)
363/// TransportType (VarInt): 0=UDP, 1=BLE, 2=LoRa, 3=Serial, etc.
364/// AddressType (1 byte): depends on transport type
365/// Address (variable): transport-specific address bytes
366/// Port (2 bytes): for UDP addresses only
367/// HasCapabilities (1 byte): 0=no, 1=yes
368/// Capabilities (2 bytes): if HasCapabilities==1, CapabilityFlags bitfield
369/// ```
370///
371/// # Backward Compatibility
372///
373/// When decoding, if transport_type is not present (legacy frames), UDP is assumed.
374/// When encoding, transport_type 0 (UDP) uses the legacy format for compatibility.
375/// Capability flags are optional and default to None for backward compatibility.
376#[derive(Debug, Clone, PartialEq, Eq)]
377pub struct AddAddress {
378    /// Sequence number for the address (used for referencing in other frames)
379    pub sequence: u64,
380    /// Priority of this address candidate (higher values are preferred)
381    pub priority: u64,
382    /// Transport type for this address (UDP, BLE, LoRa, etc.)
383    pub transport_type: TransportType,
384    /// The transport address being advertised
385    pub address: TransportAddr,
386    /// Optional capability flags summarizing transport characteristics
387    pub capabilities: Option<CapabilityFlags>,
388}
389
390impl AddAddress {
391    /// Create a new ADD_ADDRESS frame for a UDP address
392    ///
393    /// This is the most common case and maintains backward compatibility.
394    /// No capability flags are included by default.
395    pub fn udp(sequence: u64, priority: u64, socket_addr: SocketAddr) -> Self {
396        Self {
397            sequence,
398            priority,
399            transport_type: TransportType::Udp,
400            address: TransportAddr::Udp(socket_addr),
401            capabilities: None,
402        }
403    }
404
405    /// Create a new ADD_ADDRESS frame for any transport address
406    ///
407    /// No capability flags are included by default. Use `with_capabilities()`
408    /// to add capability information.
409    pub fn new(sequence: u64, priority: u64, address: TransportAddr) -> Self {
410        Self {
411            sequence,
412            priority,
413            transport_type: address.transport_type(),
414            address,
415            capabilities: None,
416        }
417    }
418
419    /// Create a new ADD_ADDRESS frame with capability flags
420    pub fn with_capabilities(
421        sequence: u64,
422        priority: u64,
423        address: TransportAddr,
424        capabilities: CapabilityFlags,
425    ) -> Self {
426        Self {
427            sequence,
428            priority,
429            transport_type: address.transport_type(),
430            address,
431            capabilities: Some(capabilities),
432        }
433    }
434
435    /// Create a new ADD_ADDRESS frame from a TransportAddr and TransportCapabilities
436    ///
437    /// This automatically converts the full capabilities to compact CapabilityFlags.
438    pub fn from_capabilities(
439        sequence: u64,
440        priority: u64,
441        address: TransportAddr,
442        capabilities: &TransportCapabilities,
443    ) -> Self {
444        Self {
445            sequence,
446            priority,
447            transport_type: address.transport_type(),
448            address,
449            capabilities: Some(CapabilityFlags::from_capabilities(capabilities)),
450        }
451    }
452
453    /// Get the socket address if this is a UDP transport
454    ///
455    /// Returns `None` for non-UDP transports.
456    pub fn socket_addr(&self) -> Option<SocketAddr> {
457        self.address.as_socket_addr()
458    }
459
460    /// Check if this address has capability information
461    pub fn has_capabilities(&self) -> bool {
462        self.capabilities.is_some()
463    }
464
465    /// Get the capability flags if present
466    pub fn capability_flags(&self) -> Option<CapabilityFlags> {
467        self.capabilities
468    }
469
470    /// Check if this transport supports full QUIC (if capability info is available)
471    pub fn supports_full_quic(&self) -> Option<bool> {
472        self.capabilities.map(|c| c.supports_full_quic())
473    }
474}
475
476/// PUNCH_ME_NOW frame for coordinating hole punching
477///
478/// As defined in draft-seemann-quic-nat-traversal-01, this frame includes:
479/// - Round number (VarInt) for coordination
480/// - Target sequence number (VarInt) referencing an ADD_ADDRESS frame
481/// - Local address for this punch attempt
482/// - Optional target peer ID for relay by bootstrap nodes
483#[derive(Debug, Clone, PartialEq, Eq)]
484pub struct PunchMeNow {
485    /// Round number for coordination
486    pub round: u64,
487    /// Sequence number of the address to punch (references an ADD_ADDRESS frame)
488    pub paired_with_sequence_number: u64,
489    /// Address for this punch attempt
490    pub address: SocketAddr,
491    /// Target peer ID for relay by bootstrap nodes (optional)
492    pub target_peer_id: Option<[u8; 32]>,
493}
494
495/// REMOVE_ADDRESS frame for removing candidate addresses
496#[derive(Debug, Clone, PartialEq, Eq)]
497pub struct RemoveAddress {
498    /// Sequence number of the address to remove
499    pub sequence: u64,
500}
501
502/// Wire format transport type values
503const TRANSPORT_TYPE_UDP: u64 = 0;
504const TRANSPORT_TYPE_BLE: u64 = 1;
505const TRANSPORT_TYPE_LORA: u64 = 2;
506const TRANSPORT_TYPE_SERIAL: u64 = 3;
507const TRANSPORT_TYPE_AX25: u64 = 4;
508const TRANSPORT_TYPE_I2P: u64 = 5;
509const TRANSPORT_TYPE_YGGDRASIL: u64 = 6;
510
511impl Codec for AddAddress {
512    fn decode<B: Buf>(buf: &mut B) -> coding::Result<Self> {
513        if buf.remaining() < 1 {
514            return Err(coding::UnexpectedEnd);
515        }
516
517        // Decode sequence number (VarInt)
518        let sequence = VarInt::decode(buf)?.into_inner();
519
520        // Decode priority (VarInt)
521        let priority = VarInt::decode(buf)?.into_inner();
522
523        // Decode transport type (VarInt) - extension field
524        // Default to UDP for backward compatibility with legacy frames
525        let transport_type_raw = if buf.remaining() > 0 {
526            VarInt::decode(buf)?.into_inner()
527        } else {
528            TRANSPORT_TYPE_UDP
529        };
530
531        let transport_type = match transport_type_raw {
532            TRANSPORT_TYPE_UDP => TransportType::Udp,
533            TRANSPORT_TYPE_BLE => TransportType::Ble,
534            TRANSPORT_TYPE_LORA => TransportType::LoRa,
535            TRANSPORT_TYPE_SERIAL => TransportType::Serial,
536            TRANSPORT_TYPE_AX25 => TransportType::Ax25,
537            TRANSPORT_TYPE_I2P => TransportType::I2p,
538            TRANSPORT_TYPE_YGGDRASIL => TransportType::Yggdrasil,
539            _ => TransportType::Udp, // Unknown types fall back to UDP
540        };
541
542        // Decode transport-specific address
543        let address = match transport_type {
544            TransportType::Udp => {
545                // UDP: address type (1 byte) + IP (4 or 16 bytes) + port (2 bytes)
546                if buf.remaining() < 1 {
547                    return Err(coding::UnexpectedEnd);
548                }
549                let addr_type = buf.get_u8();
550                let ip = match addr_type {
551                    4 => {
552                        if buf.remaining() < 4 {
553                            return Err(coding::UnexpectedEnd);
554                        }
555                        let mut addr = [0u8; 4];
556                        buf.copy_to_slice(&mut addr);
557                        IpAddr::from(addr)
558                    }
559                    6 => {
560                        if buf.remaining() < 16 {
561                            return Err(coding::UnexpectedEnd);
562                        }
563                        let mut addr = [0u8; 16];
564                        buf.copy_to_slice(&mut addr);
565                        IpAddr::from(addr)
566                    }
567                    _ => return Err(coding::UnexpectedEnd),
568                };
569
570                if buf.remaining() < 2 {
571                    return Err(coding::UnexpectedEnd);
572                }
573                let port = buf.get_u16();
574                TransportAddr::Udp(SocketAddr::new(ip, port))
575            }
576            TransportType::Ble => {
577                // BLE: device ID (6 bytes) + optional service UUID flag (1 byte) + UUID (16 bytes if present)
578                if buf.remaining() < 6 {
579                    return Err(coding::UnexpectedEnd);
580                }
581                let mut device_id = [0u8; 6];
582                buf.copy_to_slice(&mut device_id);
583
584                let service_uuid = if buf.remaining() > 0 {
585                    let has_uuid = buf.get_u8();
586                    if has_uuid == 1 && buf.remaining() >= 16 {
587                        let mut uuid = [0u8; 16];
588                        buf.copy_to_slice(&mut uuid);
589                        Some(uuid)
590                    } else {
591                        None
592                    }
593                } else {
594                    None
595                };
596
597                TransportAddr::Ble {
598                    device_id,
599                    service_uuid,
600                }
601            }
602            TransportType::LoRa => {
603                // LoRa: device address (4 bytes) + SF (1 byte) + BW (2 bytes) + CR (1 byte)
604                if buf.remaining() < 8 {
605                    return Err(coding::UnexpectedEnd);
606                }
607                let mut device_addr = [0u8; 4];
608                buf.copy_to_slice(&mut device_addr);
609                let spreading_factor = buf.get_u8();
610                let bandwidth_khz = buf.get_u16();
611                let coding_rate = buf.get_u8();
612
613                TransportAddr::LoRa {
614                    device_addr,
615                    params: crate::transport::LoRaParams {
616                        spreading_factor,
617                        bandwidth_khz,
618                        coding_rate,
619                    },
620                }
621            }
622            TransportType::Serial => {
623                // Serial: port name length (VarInt) + port name (UTF-8 string)
624                let name_len = VarInt::decode(buf)?.into_inner() as usize;
625                if buf.remaining() < name_len {
626                    return Err(coding::UnexpectedEnd);
627                }
628                let mut name_bytes = vec![0u8; name_len];
629                buf.copy_to_slice(&mut name_bytes);
630                let port_name =
631                    String::from_utf8(name_bytes).unwrap_or_else(|_| String::from("/dev/null"));
632                TransportAddr::Serial { port: port_name }
633            }
634            TransportType::Ax25 | TransportType::I2p | TransportType::Yggdrasil => {
635                // Other transports: fall back to raw bytes storage
636                // For now, skip remaining bytes and return a placeholder
637                // TODO: Implement proper decoding for these transport types
638                TransportAddr::Udp(SocketAddr::new(IpAddr::from([0, 0, 0, 0]), 0))
639            }
640        };
641
642        // Decode optional capability flags
643        let capabilities = if buf.remaining() > 0 {
644            let has_caps = buf.get_u8();
645            if has_caps == 1 && buf.remaining() >= 2 {
646                Some(CapabilityFlags::from_raw(buf.get_u16()))
647            } else {
648                None
649            }
650        } else {
651            None
652        };
653
654        Ok(Self {
655            sequence,
656            priority,
657            transport_type,
658            address,
659            capabilities,
660        })
661    }
662
663    fn encode<B: BufMut>(&self, buf: &mut B) {
664        // Encode sequence number (VarInt)
665        VarInt::from_u64(self.sequence)
666            .unwrap_or(VarInt::from_u32(0))
667            .encode(buf);
668
669        // Encode priority (VarInt)
670        VarInt::from_u64(self.priority)
671            .unwrap_or(VarInt::from_u32(0))
672            .encode(buf);
673
674        // Encode transport type (VarInt)
675        let transport_type_raw = match self.transport_type {
676            TransportType::Udp => TRANSPORT_TYPE_UDP,
677            TransportType::Ble => TRANSPORT_TYPE_BLE,
678            TransportType::LoRa => TRANSPORT_TYPE_LORA,
679            TransportType::Serial => TRANSPORT_TYPE_SERIAL,
680            TransportType::Ax25 => TRANSPORT_TYPE_AX25,
681            TransportType::I2p => TRANSPORT_TYPE_I2P,
682            TransportType::Yggdrasil => TRANSPORT_TYPE_YGGDRASIL,
683        };
684        VarInt::from_u64(transport_type_raw)
685            .unwrap_or(VarInt::from_u32(0))
686            .encode(buf);
687
688        // Encode transport-specific address
689        match &self.address {
690            TransportAddr::Udp(socket_addr) => {
691                match socket_addr.ip() {
692                    IpAddr::V4(ipv4) => {
693                        buf.put_u8(4); // IPv4 type
694                        buf.put_slice(&ipv4.octets());
695                    }
696                    IpAddr::V6(ipv6) => {
697                        buf.put_u8(6); // IPv6 type
698                        buf.put_slice(&ipv6.octets());
699                    }
700                }
701                buf.put_u16(socket_addr.port());
702            }
703            TransportAddr::Ble {
704                device_id,
705                service_uuid,
706            } => {
707                buf.put_slice(device_id);
708                match service_uuid {
709                    Some(uuid) => {
710                        buf.put_u8(1); // Has UUID
711                        buf.put_slice(uuid);
712                    }
713                    None => {
714                        buf.put_u8(0); // No UUID
715                    }
716                }
717            }
718            TransportAddr::LoRa {
719                device_addr,
720                params,
721            } => {
722                buf.put_slice(device_addr);
723                buf.put_u8(params.spreading_factor);
724                buf.put_u16(params.bandwidth_khz);
725                buf.put_u8(params.coding_rate);
726            }
727            TransportAddr::Serial { port } => {
728                let name_bytes = port.as_bytes();
729                VarInt::from_u64(name_bytes.len() as u64)
730                    .unwrap_or(VarInt::from_u32(0))
731                    .encode(buf);
732                buf.put_slice(name_bytes);
733            }
734            TransportAddr::Ax25 { callsign, ssid } => {
735                // AX.25: callsign length (VarInt) + callsign (UTF-8) + SSID (1 byte)
736                let callsign_bytes = callsign.as_bytes();
737                VarInt::from_u64(callsign_bytes.len() as u64)
738                    .unwrap_or(VarInt::from_u32(0))
739                    .encode(buf);
740                buf.put_slice(callsign_bytes);
741                buf.put_u8(*ssid);
742            }
743            TransportAddr::I2p { destination } => {
744                // I2P: 387-byte destination
745                buf.put_slice(destination.as_ref());
746            }
747            TransportAddr::Yggdrasil { address } => {
748                // Yggdrasil: 16-byte address
749                buf.put_slice(address);
750            }
751            TransportAddr::Broadcast { transport_type: _ } => {
752                // Broadcast addresses are not advertised over the wire
753                // Encode as empty UDP placeholder
754                buf.put_u8(4);
755                buf.put_slice(&[0, 0, 0, 0]);
756                buf.put_u16(0);
757            }
758        }
759
760        // Encode optional capability flags
761        match &self.capabilities {
762            Some(caps) => {
763                buf.put_u8(1); // Has capabilities
764                buf.put_u16(caps.to_raw());
765            }
766            None => {
767                buf.put_u8(0); // No capabilities
768            }
769        }
770    }
771}
772
773impl Codec for PunchMeNow {
774    fn decode<B: Buf>(buf: &mut B) -> coding::Result<Self> {
775        if buf.remaining() < 1 {
776            return Err(coding::UnexpectedEnd);
777        }
778
779        // Decode round number (VarInt)
780        let round = VarInt::decode(buf)?.into_inner();
781
782        // Decode target sequence (VarInt)
783        let paired_with_sequence_number = VarInt::decode(buf)?.into_inner();
784
785        // Decode local address
786        let addr_type = buf.get_u8();
787        let ip = match addr_type {
788            4 => {
789                if buf.remaining() < 4 {
790                    return Err(coding::UnexpectedEnd);
791                }
792                let mut addr = [0u8; 4];
793                buf.copy_to_slice(&mut addr);
794                IpAddr::from(addr)
795            }
796            6 => {
797                if buf.remaining() < 16 {
798                    return Err(coding::UnexpectedEnd);
799                }
800                let mut addr = [0u8; 16];
801                buf.copy_to_slice(&mut addr);
802                IpAddr::from(addr)
803            }
804            _ => return Err(coding::UnexpectedEnd),
805        };
806
807        // Decode port
808        if buf.remaining() < 2 {
809            return Err(coding::UnexpectedEnd);
810        }
811        let port = buf.get_u16();
812
813        // Decode target peer ID if present
814        let target_peer_id = if buf.remaining() > 0 {
815            let has_peer_id = buf.get_u8();
816            if has_peer_id == 1 {
817                if buf.remaining() < 32 {
818                    return Err(coding::UnexpectedEnd);
819                }
820                let mut peer_id = [0u8; 32];
821                buf.copy_to_slice(&mut peer_id);
822                Some(peer_id)
823            } else {
824                None
825            }
826        } else {
827            None
828        };
829
830        Ok(Self {
831            round,
832            paired_with_sequence_number,
833            address: SocketAddr::new(ip, port),
834            target_peer_id,
835        })
836    }
837
838    fn encode<B: BufMut>(&self, buf: &mut B) {
839        // Encode round number (VarInt)
840        VarInt::from_u64(self.round)
841            .unwrap_or(VarInt::from_u32(0))
842            .encode(buf);
843
844        // Encode target sequence (VarInt)
845        VarInt::from_u64(self.paired_with_sequence_number)
846            .unwrap_or(VarInt::from_u32(0))
847            .encode(buf);
848
849        // Encode local address
850        match self.address.ip() {
851            IpAddr::V4(ipv4) => {
852                buf.put_u8(4); // IPv4 type
853                buf.put_slice(&ipv4.octets());
854            }
855            IpAddr::V6(ipv6) => {
856                buf.put_u8(6); // IPv6 type
857                buf.put_slice(&ipv6.octets());
858            }
859        }
860
861        // Encode port
862        buf.put_u16(self.address.port());
863
864        // Encode target peer ID if present
865        match &self.target_peer_id {
866            Some(peer_id) => {
867                buf.put_u8(1); // Has peer ID
868                buf.put_slice(peer_id);
869            }
870            None => {
871                buf.put_u8(0); // No peer ID
872            }
873        }
874    }
875}
876
877impl Codec for RemoveAddress {
878    fn decode<B: Buf>(buf: &mut B) -> coding::Result<Self> {
879        if buf.remaining() < 1 {
880            return Err(coding::UnexpectedEnd);
881        }
882
883        let sequence = VarInt::decode(buf)?.into_inner();
884
885        Ok(Self { sequence })
886    }
887
888    fn encode<B: BufMut>(&self, buf: &mut B) {
889        VarInt::from_u64(self.sequence)
890            .unwrap_or(VarInt::from_u32(0))
891            .encode(buf);
892    }
893}
894
895impl AddAddress {
896    /// Encode this frame with its type prefix for transmission
897    pub fn encode_with_type<B: BufMut>(&self, buf: &mut B) {
898        VarInt::from_u64(FRAME_TYPE_ADD_ADDRESS)
899            .unwrap_or(VarInt::from_u32(0))
900            .encode(buf);
901        Codec::encode(self, buf);
902    }
903}
904
905impl PunchMeNow {
906    /// Encode this frame with its type prefix for transmission
907    pub fn encode_with_type<B: BufMut>(&self, buf: &mut B) {
908        VarInt::from_u64(FRAME_TYPE_PUNCH_ME_NOW)
909            .unwrap_or(VarInt::from_u32(0))
910            .encode(buf);
911        Codec::encode(self, buf);
912    }
913}
914
915impl RemoveAddress {
916    /// Encode this frame with its type prefix for transmission
917    pub fn encode_with_type<B: BufMut>(&self, buf: &mut B) {
918        VarInt::from_u64(FRAME_TYPE_REMOVE_ADDRESS)
919            .unwrap_or(VarInt::from_u32(0))
920            .encode(buf);
921        Codec::encode(self, buf);
922    }
923}
924
925#[cfg(test)]
926mod tests {
927    use super::*;
928    use bytes::BytesMut;
929
930    fn test_socket_addr_v4() -> SocketAddr {
931        "192.168.1.100:9000".parse().expect("valid addr")
932    }
933
934    fn test_socket_addr_v6() -> SocketAddr {
935        "[::1]:9000".parse().expect("valid addr")
936    }
937
938    #[test]
939    fn test_add_address_udp_ipv4_roundtrip() {
940        let original = AddAddress::udp(42, 100, test_socket_addr_v4());
941
942        // Encode
943        let mut buf = BytesMut::new();
944        Codec::encode(&original, &mut buf);
945
946        // Decode
947        let decoded = AddAddress::decode(&mut buf.freeze()).expect("decode failed");
948
949        assert_eq!(decoded.sequence, 42);
950        assert_eq!(decoded.priority, 100);
951        assert_eq!(decoded.transport_type, TransportType::Udp);
952        assert_eq!(decoded.socket_addr(), Some(test_socket_addr_v4()));
953    }
954
955    #[test]
956    fn test_add_address_udp_ipv6_roundtrip() {
957        let original = AddAddress::udp(1, 50, test_socket_addr_v6());
958
959        let mut buf = BytesMut::new();
960        Codec::encode(&original, &mut buf);
961
962        let decoded = AddAddress::decode(&mut buf.freeze()).expect("decode failed");
963
964        assert_eq!(decoded.sequence, 1);
965        assert_eq!(decoded.transport_type, TransportType::Udp);
966        assert_eq!(decoded.socket_addr(), Some(test_socket_addr_v6()));
967    }
968
969    #[test]
970    fn test_add_address_ble_roundtrip() {
971        let device_id = [0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC];
972        let original = AddAddress::new(
973            10,
974            200,
975            TransportAddr::Ble {
976                device_id,
977                service_uuid: None,
978            },
979        );
980
981        let mut buf = BytesMut::new();
982        Codec::encode(&original, &mut buf);
983
984        let decoded = AddAddress::decode(&mut buf.freeze()).expect("decode failed");
985
986        assert_eq!(decoded.sequence, 10);
987        assert_eq!(decoded.priority, 200);
988        assert_eq!(decoded.transport_type, TransportType::Ble);
989
990        if let TransportAddr::Ble {
991            device_id: decoded_id,
992            service_uuid,
993        } = decoded.address
994        {
995            assert_eq!(decoded_id, device_id);
996            assert!(service_uuid.is_none());
997        } else {
998            panic!("Expected BLE address");
999        }
1000    }
1001
1002    #[test]
1003    fn test_add_address_ble_with_uuid_roundtrip() {
1004        let device_id = [0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF];
1005        let service_uuid = [
1006            0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,
1007            0x0F, 0x10,
1008        ];
1009        let original = AddAddress::new(
1010            5,
1011            300,
1012            TransportAddr::Ble {
1013                device_id,
1014                service_uuid: Some(service_uuid),
1015            },
1016        );
1017
1018        let mut buf = BytesMut::new();
1019        Codec::encode(&original, &mut buf);
1020
1021        let decoded = AddAddress::decode(&mut buf.freeze()).expect("decode failed");
1022
1023        if let TransportAddr::Ble {
1024            device_id: decoded_id,
1025            service_uuid: decoded_uuid,
1026        } = decoded.address
1027        {
1028            assert_eq!(decoded_id, device_id);
1029            assert_eq!(decoded_uuid, Some(service_uuid));
1030        } else {
1031            panic!("Expected BLE address");
1032        }
1033    }
1034
1035    #[test]
1036    fn test_add_address_lora_roundtrip() {
1037        let device_addr = [0xDE, 0xAD, 0xBE, 0xEF];
1038        let params = crate::transport::LoRaParams {
1039            spreading_factor: 10,
1040            bandwidth_khz: 250,
1041            coding_rate: 6,
1042        };
1043        let original = AddAddress::new(
1044            99,
1045            500,
1046            TransportAddr::LoRa {
1047                device_addr,
1048                params: params.clone(),
1049            },
1050        );
1051
1052        let mut buf = BytesMut::new();
1053        Codec::encode(&original, &mut buf);
1054
1055        let decoded = AddAddress::decode(&mut buf.freeze()).expect("decode failed");
1056
1057        assert_eq!(decoded.sequence, 99);
1058        assert_eq!(decoded.transport_type, TransportType::LoRa);
1059
1060        if let TransportAddr::LoRa {
1061            device_addr: decoded_addr,
1062            params: decoded_params,
1063        } = decoded.address
1064        {
1065            assert_eq!(decoded_addr, device_addr);
1066            assert_eq!(decoded_params.spreading_factor, 10);
1067            assert_eq!(decoded_params.bandwidth_khz, 250);
1068            assert_eq!(decoded_params.coding_rate, 6);
1069        } else {
1070            panic!("Expected LoRa address");
1071        }
1072    }
1073
1074    #[test]
1075    fn test_add_address_serial_roundtrip() {
1076        let original = AddAddress::new(
1077            7,
1078            50,
1079            TransportAddr::Serial {
1080                port: "/dev/ttyUSB0".to_string(),
1081            },
1082        );
1083
1084        let mut buf = BytesMut::new();
1085        Codec::encode(&original, &mut buf);
1086
1087        let decoded = AddAddress::decode(&mut buf.freeze()).expect("decode failed");
1088
1089        assert_eq!(decoded.sequence, 7);
1090        assert_eq!(decoded.transport_type, TransportType::Serial);
1091
1092        if let TransportAddr::Serial { port } = decoded.address {
1093            assert_eq!(port, "/dev/ttyUSB0");
1094        } else {
1095            panic!("Expected Serial address");
1096        }
1097    }
1098
1099    #[test]
1100    fn test_add_address_helper_methods() {
1101        let socket_addr = test_socket_addr_v4();
1102        let frame = AddAddress::udp(1, 100, socket_addr);
1103
1104        assert_eq!(frame.socket_addr(), Some(socket_addr));
1105
1106        let ble_frame = AddAddress::new(
1107            2,
1108            100,
1109            TransportAddr::Ble {
1110                device_id: [0; 6],
1111                service_uuid: None,
1112            },
1113        );
1114        assert_eq!(ble_frame.socket_addr(), None);
1115    }
1116
1117    #[test]
1118    fn test_punch_me_now_roundtrip() {
1119        let original = PunchMeNow {
1120            round: 3,
1121            paired_with_sequence_number: 42,
1122            address: test_socket_addr_v4(),
1123            target_peer_id: None,
1124        };
1125
1126        let mut buf = BytesMut::new();
1127        Codec::encode(&original, &mut buf);
1128
1129        let decoded = PunchMeNow::decode(&mut buf.freeze()).expect("decode failed");
1130
1131        assert_eq!(decoded.round, 3);
1132        assert_eq!(decoded.paired_with_sequence_number, 42);
1133        assert_eq!(decoded.address, test_socket_addr_v4());
1134        assert!(decoded.target_peer_id.is_none());
1135    }
1136
1137    #[test]
1138    fn test_punch_me_now_with_peer_id_roundtrip() {
1139        let peer_id = [0x42u8; 32];
1140        let original = PunchMeNow {
1141            round: 5,
1142            paired_with_sequence_number: 10,
1143            address: test_socket_addr_v6(),
1144            target_peer_id: Some(peer_id),
1145        };
1146
1147        let mut buf = BytesMut::new();
1148        Codec::encode(&original, &mut buf);
1149
1150        let decoded = PunchMeNow::decode(&mut buf.freeze()).expect("decode failed");
1151
1152        assert_eq!(decoded.round, 5);
1153        assert_eq!(decoded.target_peer_id, Some(peer_id));
1154    }
1155
1156    #[test]
1157    fn test_remove_address_roundtrip() {
1158        let original = RemoveAddress { sequence: 123 };
1159
1160        let mut buf = BytesMut::new();
1161        Codec::encode(&original, &mut buf);
1162
1163        let decoded = RemoveAddress::decode(&mut buf.freeze()).expect("decode failed");
1164
1165        assert_eq!(decoded.sequence, 123);
1166    }
1167
1168    #[test]
1169    fn test_transport_type_wire_values() {
1170        // Verify our wire format constants
1171        assert_eq!(TRANSPORT_TYPE_UDP, 0);
1172        assert_eq!(TRANSPORT_TYPE_BLE, 1);
1173        assert_eq!(TRANSPORT_TYPE_LORA, 2);
1174        assert_eq!(TRANSPORT_TYPE_SERIAL, 3);
1175    }
1176
1177    #[test]
1178    fn test_frame_types() {
1179        // Verify frame type constants match the spec
1180        assert_eq!(FRAME_TYPE_ADD_ADDRESS, 0x3d7e90);
1181        assert_eq!(FRAME_TYPE_PUNCH_ME_NOW, 0x3d7e91);
1182        assert_eq!(FRAME_TYPE_REMOVE_ADDRESS, 0x3d7e92);
1183    }
1184
1185    // ============ Capability Flags Tests ============
1186
1187    #[test]
1188    fn test_capability_flags_empty() {
1189        let flags = CapabilityFlags::empty();
1190        assert_eq!(flags.to_raw(), 0);
1191        assert!(!flags.supports_full_quic());
1192        assert!(!flags.half_duplex());
1193        assert!(!flags.broadcast());
1194        assert!(!flags.metered());
1195        assert!(!flags.power_constrained());
1196        assert!(!flags.link_layer_acks());
1197        assert_eq!(flags.mtu_tier(), 0);
1198        assert_eq!(flags.bandwidth_tier(), 0);
1199        assert_eq!(flags.latency_tier(), 0);
1200    }
1201
1202    #[test]
1203    fn test_capability_flags_individual_bits() {
1204        // Test each flag individually
1205        let flags = CapabilityFlags::empty().with_supports_full_quic(true);
1206        assert!(flags.supports_full_quic());
1207        assert_eq!(flags.to_raw(), 1);
1208
1209        let flags = CapabilityFlags::empty().with_half_duplex(true);
1210        assert!(flags.half_duplex());
1211        assert_eq!(flags.to_raw(), 2);
1212
1213        let flags = CapabilityFlags::empty().with_broadcast(true);
1214        assert!(flags.broadcast());
1215        assert_eq!(flags.to_raw(), 4);
1216
1217        let flags = CapabilityFlags::empty().with_metered(true);
1218        assert!(flags.metered());
1219        assert_eq!(flags.to_raw(), 8);
1220
1221        let flags = CapabilityFlags::empty().with_power_constrained(true);
1222        assert!(flags.power_constrained());
1223        assert_eq!(flags.to_raw(), 16);
1224
1225        let flags = CapabilityFlags::empty().with_link_layer_acks(true);
1226        assert!(flags.link_layer_acks());
1227        assert_eq!(flags.to_raw(), 32);
1228    }
1229
1230    #[test]
1231    fn test_capability_flags_tiers() {
1232        // MTU tiers: bits 6-7
1233        let flags = CapabilityFlags::empty().with_mtu_tier(0);
1234        assert_eq!(flags.mtu_tier(), 0);
1235        assert_eq!(flags.mtu_range(), (0, 499));
1236
1237        let flags = CapabilityFlags::empty().with_mtu_tier(1);
1238        assert_eq!(flags.mtu_tier(), 1);
1239        assert_eq!(flags.mtu_range(), (500, 1199));
1240
1241        let flags = CapabilityFlags::empty().with_mtu_tier(2);
1242        assert_eq!(flags.mtu_tier(), 2);
1243        assert_eq!(flags.mtu_range(), (1200, 4095));
1244
1245        let flags = CapabilityFlags::empty().with_mtu_tier(3);
1246        assert_eq!(flags.mtu_tier(), 3);
1247        assert_eq!(flags.mtu_range(), (4096, 65535));
1248
1249        // Bandwidth tiers: bits 8-9
1250        let flags = CapabilityFlags::empty().with_bandwidth_tier(0);
1251        assert_eq!(flags.bandwidth_tier(), 0);
1252
1253        let flags = CapabilityFlags::empty().with_bandwidth_tier(3);
1254        assert_eq!(flags.bandwidth_tier(), 3);
1255
1256        // Latency tiers: bits 10-11
1257        let flags = CapabilityFlags::empty().with_latency_tier(0);
1258        assert_eq!(flags.latency_tier(), 0);
1259        assert_eq!(flags.latency_range().0, Duration::from_secs(2));
1260
1261        let flags = CapabilityFlags::empty().with_latency_tier(3);
1262        assert_eq!(flags.latency_tier(), 3);
1263        assert_eq!(flags.latency_range().1, Duration::from_millis(100));
1264    }
1265
1266    #[test]
1267    fn test_capability_flags_tier_clamping() {
1268        // Tiers should be clamped to 0-3
1269        let flags = CapabilityFlags::empty().with_mtu_tier(10);
1270        assert_eq!(flags.mtu_tier(), 3);
1271
1272        let flags = CapabilityFlags::empty().with_bandwidth_tier(255);
1273        assert_eq!(flags.bandwidth_tier(), 3);
1274
1275        let flags = CapabilityFlags::empty().with_latency_tier(100);
1276        assert_eq!(flags.latency_tier(), 3);
1277    }
1278
1279    #[test]
1280    fn test_capability_flags_presets() {
1281        // Broadband preset
1282        let broadband = CapabilityFlags::broadband();
1283        assert!(broadband.supports_full_quic());
1284        assert!(broadband.broadcast());
1285        assert!(!broadband.half_duplex());
1286        assert!(!broadband.power_constrained());
1287        assert_eq!(broadband.mtu_tier(), 2);
1288        assert_eq!(broadband.bandwidth_tier(), 3);
1289        assert_eq!(broadband.latency_tier(), 3);
1290
1291        // BLE preset
1292        let ble = CapabilityFlags::ble();
1293        assert!(!ble.supports_full_quic());
1294        assert!(ble.broadcast());
1295        assert!(ble.power_constrained());
1296        assert!(ble.link_layer_acks());
1297        assert_eq!(ble.mtu_tier(), 0);
1298        assert_eq!(ble.bandwidth_tier(), 2);
1299        assert_eq!(ble.latency_tier(), 2);
1300
1301        // LoRa preset
1302        let lora = CapabilityFlags::lora_long_range();
1303        assert!(!lora.supports_full_quic());
1304        assert!(lora.half_duplex());
1305        assert!(lora.broadcast());
1306        assert!(lora.power_constrained());
1307        assert_eq!(lora.mtu_tier(), 0);
1308        assert_eq!(lora.bandwidth_tier(), 0);
1309        assert_eq!(lora.latency_tier(), 0);
1310    }
1311
1312    #[test]
1313    fn test_capability_flags_from_transport_capabilities() {
1314        // Test conversion from full TransportCapabilities
1315        let caps = TransportCapabilities::broadband();
1316        let flags = CapabilityFlags::from_capabilities(&caps);
1317
1318        assert!(flags.supports_full_quic());
1319        assert!(!flags.half_duplex());
1320        assert!(flags.broadcast());
1321        assert!(!flags.metered());
1322        assert!(!flags.power_constrained());
1323        assert_eq!(flags.bandwidth_tier(), 3); // High
1324
1325        // BLE caps
1326        let caps = TransportCapabilities::ble();
1327        let flags = CapabilityFlags::from_capabilities(&caps);
1328
1329        assert!(!flags.supports_full_quic()); // MTU too small
1330        assert!(flags.power_constrained());
1331        assert!(flags.link_layer_acks());
1332        assert_eq!(flags.bandwidth_tier(), 2); // Medium (125kbps)
1333
1334        // LoRa long range
1335        let caps = TransportCapabilities::lora_long_range();
1336        let flags = CapabilityFlags::from_capabilities(&caps);
1337
1338        assert!(!flags.supports_full_quic());
1339        assert!(flags.half_duplex());
1340        assert!(flags.broadcast());
1341        assert!(flags.power_constrained());
1342        assert_eq!(flags.bandwidth_tier(), 0); // VeryLow
1343        assert_eq!(flags.latency_tier(), 0); // >2s RTT
1344    }
1345
1346    #[test]
1347    fn test_capability_flags_roundtrip() {
1348        // Test encode/decode through raw value
1349        let original = CapabilityFlags::empty()
1350            .with_supports_full_quic(true)
1351            .with_broadcast(true)
1352            .with_mtu_tier(2)
1353            .with_bandwidth_tier(3)
1354            .with_latency_tier(1);
1355
1356        let raw = original.to_raw();
1357        let decoded = CapabilityFlags::from_raw(raw);
1358
1359        assert_eq!(decoded.supports_full_quic(), original.supports_full_quic());
1360        assert_eq!(decoded.broadcast(), original.broadcast());
1361        assert_eq!(decoded.mtu_tier(), original.mtu_tier());
1362        assert_eq!(decoded.bandwidth_tier(), original.bandwidth_tier());
1363        assert_eq!(decoded.latency_tier(), original.latency_tier());
1364    }
1365
1366    #[test]
1367    fn test_add_address_with_capabilities_roundtrip() {
1368        let caps = CapabilityFlags::broadband();
1369        let original =
1370            AddAddress::with_capabilities(42, 100, TransportAddr::Udp(test_socket_addr_v4()), caps);
1371
1372        assert!(original.has_capabilities());
1373        assert_eq!(original.capability_flags(), Some(caps));
1374        assert_eq!(original.supports_full_quic(), Some(true));
1375
1376        // Encode and decode
1377        let mut buf = BytesMut::new();
1378        Codec::encode(&original, &mut buf);
1379
1380        let decoded = AddAddress::decode(&mut buf.freeze()).expect("decode failed");
1381
1382        assert_eq!(decoded.sequence, 42);
1383        assert_eq!(decoded.priority, 100);
1384        assert!(decoded.has_capabilities());
1385        assert_eq!(decoded.capability_flags(), Some(caps));
1386        assert_eq!(decoded.supports_full_quic(), Some(true));
1387    }
1388
1389    #[test]
1390    fn test_add_address_without_capabilities_roundtrip() {
1391        let original = AddAddress::udp(1, 50, test_socket_addr_v4());
1392
1393        assert!(!original.has_capabilities());
1394        assert_eq!(original.capability_flags(), None);
1395        assert_eq!(original.supports_full_quic(), None);
1396
1397        // Encode and decode
1398        let mut buf = BytesMut::new();
1399        Codec::encode(&original, &mut buf);
1400
1401        let decoded = AddAddress::decode(&mut buf.freeze()).expect("decode failed");
1402
1403        assert!(!decoded.has_capabilities());
1404        assert_eq!(decoded.capability_flags(), None);
1405    }
1406
1407    #[test]
1408    fn test_add_address_from_transport_capabilities() {
1409        let caps = TransportCapabilities::ble();
1410        let original = AddAddress::from_capabilities(
1411            10,
1412            200,
1413            TransportAddr::Ble {
1414                device_id: [0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC],
1415                service_uuid: None,
1416            },
1417            &caps,
1418        );
1419
1420        assert!(original.has_capabilities());
1421        // BLE doesn't support full QUIC (MTU too small)
1422        assert_eq!(original.supports_full_quic(), Some(false));
1423
1424        // Encode and decode
1425        let mut buf = BytesMut::new();
1426        Codec::encode(&original, &mut buf);
1427
1428        let decoded = AddAddress::decode(&mut buf.freeze()).expect("decode failed");
1429
1430        assert!(decoded.has_capabilities());
1431        let flags = decoded.capability_flags().expect("expected flags");
1432        assert!(!flags.supports_full_quic());
1433        assert!(flags.power_constrained());
1434        assert!(flags.link_layer_acks());
1435    }
1436
1437    #[test]
1438    fn test_add_address_ble_with_capabilities_roundtrip() {
1439        let caps = CapabilityFlags::ble();
1440        let device_id = [0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF];
1441        let original = AddAddress::with_capabilities(
1442            5,
1443            300,
1444            TransportAddr::Ble {
1445                device_id,
1446                service_uuid: None,
1447            },
1448            caps,
1449        );
1450
1451        let mut buf = BytesMut::new();
1452        Codec::encode(&original, &mut buf);
1453
1454        let decoded = AddAddress::decode(&mut buf.freeze()).expect("decode failed");
1455
1456        assert_eq!(decoded.transport_type, TransportType::Ble);
1457        assert!(decoded.has_capabilities());
1458        let flags = decoded.capability_flags().expect("expected flags");
1459        assert!(flags.power_constrained());
1460        assert_eq!(flags.mtu_tier(), 0);
1461    }
1462
1463    #[test]
1464    fn test_add_address_lora_with_capabilities_roundtrip() {
1465        let caps = CapabilityFlags::lora_long_range();
1466        let device_addr = [0xDE, 0xAD, 0xBE, 0xEF];
1467        let params = crate::transport::LoRaParams {
1468            spreading_factor: 12,
1469            bandwidth_khz: 125,
1470            coding_rate: 5,
1471        };
1472        let original = AddAddress::with_capabilities(
1473            99,
1474            500,
1475            TransportAddr::LoRa {
1476                device_addr,
1477                params,
1478            },
1479            caps,
1480        );
1481
1482        let mut buf = BytesMut::new();
1483        Codec::encode(&original, &mut buf);
1484
1485        let decoded = AddAddress::decode(&mut buf.freeze()).expect("decode failed");
1486
1487        assert_eq!(decoded.transport_type, TransportType::LoRa);
1488        assert!(decoded.has_capabilities());
1489        let flags = decoded.capability_flags().expect("expected flags");
1490        assert!(flags.half_duplex());
1491        assert!(flags.power_constrained());
1492        assert_eq!(flags.bandwidth_tier(), 0); // VeryLow
1493        assert_eq!(flags.latency_tier(), 0); // >2s
1494    }
1495}