Skip to main content

bacnet_rs/network/
mod.rs

1//! BACnet Network Layer Module
2//!
3//! This module implements the network layer functionality for BACnet according to ASHRAE 135.
4//! The network layer provides routing capabilities and enables communication between different
5//! BACnet networks.
6//!
7//! # Overview
8//!
9//! The network layer is responsible for:
10//! - Routing messages between different BACnet networks
11//! - Network address translation
12//! - Broadcast management
13//! - Router discovery and management
14//! - Network layer protocol messages (Who-Is-Router-To-Network, I-Am-Router-To-Network, etc.)
15//!
16//! # Network Layer Protocol Data Unit (NPDU)
17//!
18//! The NPDU contains:
19//! - Protocol version
20//! - Control information (priority, data expecting reply, etc.)
21//! - Destination network address (DNET, DADR)
22//! - Source network address (SNET, SADR)
23//! - Hop count for routing
24//!
25//! # Example
26//!
27//! ```no_run
28//! use bacnet_rs::network::*;
29//!
30//! // Example of creating a network message
31//! let npdu = Npdu {
32//!     version: 1,
33//!     control: NpduControl::default(),
34//!     destination: None,
35//!     source: None,
36//!     hop_count: None,
37//! };
38//! ```
39
40#[cfg(feature = "std")]
41use std::error::Error;
42
43#[cfg(feature = "std")]
44use std::fmt;
45
46#[cfg(not(feature = "std"))]
47use core::fmt;
48
49#[cfg(not(feature = "std"))]
50extern crate alloc;
51
52#[cfg(not(feature = "std"))]
53use alloc::{
54    collections::{BTreeMap, BTreeSet},
55    string::String,
56    vec::Vec,
57};
58
59#[cfg(feature = "serde")]
60use serde::{Deserialize, Serialize};
61
62#[cfg(feature = "std")]
63use std::collections::{BTreeMap, BTreeSet};
64
65/// Result type for network operations
66#[cfg(feature = "std")]
67pub type Result<T> = std::result::Result<T, NetworkError>;
68
69#[cfg(not(feature = "std"))]
70pub type Result<T> = core::result::Result<T, NetworkError>;
71
72/// Errors that can occur in network operations
73#[derive(Debug)]
74pub enum NetworkError {
75    /// Invalid NPDU format
76    InvalidNpdu(String),
77    /// Routing error
78    RoutingError(String),
79    /// Network unreachable
80    NetworkUnreachable(u16),
81    /// Hop count exceeded
82    HopCountExceeded,
83    /// Invalid network address
84    InvalidAddress,
85    /// Unsupported network message type
86    UnsupportedNetworkMessageType(u8),
87}
88
89impl fmt::Display for NetworkError {
90    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
91        match self {
92            NetworkError::InvalidNpdu(msg) => write!(f, "Invalid NPDU: {}", msg),
93            NetworkError::RoutingError(msg) => write!(f, "Routing error: {}", msg),
94            NetworkError::NetworkUnreachable(net) => write!(f, "Network {} unreachable", net),
95            NetworkError::HopCountExceeded => write!(f, "Hop count exceeded"),
96            NetworkError::InvalidAddress => write!(f, "Invalid network address"),
97            NetworkError::UnsupportedNetworkMessageType(msg) => {
98                write!(f, "Unsupported network message type: {}", msg)
99            }
100        }
101    }
102}
103
104#[cfg(feature = "std")]
105impl Error for NetworkError {}
106
107/// Network layer message types
108#[derive(Debug, Clone, Copy, PartialEq, Eq)]
109#[repr(u8)]
110pub enum NetworkMessageType {
111    WhoIsRouterToNetwork = 0x00,
112    IAmRouterToNetwork = 0x01,
113    ICouldBeRouterToNetwork = 0x02,
114    RejectMessageToNetwork = 0x03,
115    RouterBusyToNetwork = 0x04,
116    RouterAvailableToNetwork = 0x05,
117    InitializeRoutingTable = 0x06,
118    InitializeRoutingTableAck = 0x07,
119    EstablishConnectionToNetwork = 0x08,
120    DisconnectConnectionToNetwork = 0x09,
121    WhatIsNetworkNumber = 0x12,
122    NetworkNumberIs = 0x13,
123}
124
125impl TryFrom<u8> for NetworkMessageType {
126    type Error = NetworkError;
127
128    fn try_from(value: u8) -> core::result::Result<Self, Self::Error> {
129        match value {
130            0x00 => Ok(Self::WhoIsRouterToNetwork),
131            0x01 => Ok(Self::IAmRouterToNetwork),
132            0x02 => Ok(Self::ICouldBeRouterToNetwork),
133            0x03 => Ok(Self::RejectMessageToNetwork),
134            0x04 => Ok(Self::RouterBusyToNetwork),
135            0x05 => Ok(Self::RouterAvailableToNetwork),
136            0x06 => Ok(Self::InitializeRoutingTable),
137            0x07 => Ok(Self::InitializeRoutingTableAck),
138            0x08 => Ok(Self::EstablishConnectionToNetwork),
139            0x09 => Ok(Self::DisconnectConnectionToNetwork),
140            0x12 => Ok(Self::WhatIsNetworkNumber),
141            0x13 => Ok(Self::NetworkNumberIs),
142            _ => Err(NetworkError::UnsupportedNetworkMessageType(value)),
143        }
144    }
145}
146
147/// NPDU control flags
148#[derive(Debug, Clone, Copy, Default)]
149pub struct NpduControl {
150    /// Network layer message
151    pub network_message: bool,
152    /// Destination specifier present
153    pub destination_present: bool,
154    /// Source specifier present
155    pub source_present: bool,
156    /// Data expecting reply
157    pub expecting_reply: bool,
158    /// Network priority (0-3)
159    pub priority: u8,
160}
161
162impl NpduControl {
163    /// Create control byte from flags
164    pub fn to_byte(&self) -> u8 {
165        let mut byte = 0u8;
166        if self.network_message {
167            byte |= 0x80;
168        }
169        if self.destination_present {
170            byte |= 0x20;
171        }
172        if self.source_present {
173            byte |= 0x08;
174        }
175        if self.expecting_reply {
176            byte |= 0x04;
177        }
178        byte |= self.priority & 0x03;
179        byte
180    }
181
182    /// Parse control byte into flags
183    pub fn from_byte(byte: u8) -> Self {
184        Self {
185            network_message: (byte & 0x80) != 0,
186            destination_present: (byte & 0x20) != 0,
187            source_present: (byte & 0x08) != 0,
188            expecting_reply: (byte & 0x04) != 0,
189            priority: byte & 0x03,
190        }
191    }
192}
193
194/// Network address (network number + MAC address)
195#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
196#[derive(Debug, Clone, PartialEq, Eq, Hash)]
197pub struct NetworkAddress {
198    /// Network number (0 = local network, 65535 = broadcast)
199    pub network: u16,
200    /// MAC address on that network
201    pub address: Vec<u8>,
202}
203
204impl NetworkAddress {
205    /// Create a new network address
206    pub fn new(network: u16, address: Vec<u8>) -> Self {
207        Self { network, address }
208    }
209
210    /// Check if this is a broadcast address
211    pub fn is_broadcast(&self) -> bool {
212        self.network == 0xFFFF
213    }
214
215    /// Check if this is a local network address
216    pub fn is_local(&self) -> bool {
217        self.network == 0
218    }
219}
220
221/// Network Protocol Data Unit (NPDU)
222#[derive(Debug, Clone)]
223pub struct Npdu {
224    /// Protocol version (always 1)
225    pub version: u8,
226    /// Control information
227    pub control: NpduControl,
228    /// Destination network address
229    pub destination: Option<NetworkAddress>,
230    /// Source network address
231    pub source: Option<NetworkAddress>,
232    /// Hop count (only present if destination is present)
233    pub hop_count: Option<u8>,
234}
235
236impl Npdu {
237    /// Create a new NPDU with default values
238    pub fn new() -> Self {
239        Self {
240            version: 1,
241            control: NpduControl::default(),
242            destination: None,
243            source: None,
244            hop_count: None,
245        }
246    }
247
248    /// Create NPDU for global broadcast (matching YABE/bacnet-stack)
249    pub fn global_broadcast() -> Self {
250        Self {
251            version: 1,
252            control: NpduControl {
253                network_message: false,
254                destination_present: true,
255                source_present: false,
256                expecting_reply: false, // YABE uses 0x20 (no expecting_reply bit)
257                priority: 0,
258            },
259            destination: Some(NetworkAddress {
260                network: 0xFFFF,
261                address: vec![],
262            }),
263            source: None,
264            hop_count: Some(255),
265        }
266    }
267
268    /// Check if this is a network layer message
269    pub fn is_network_message(&self) -> bool {
270        self.control.network_message
271    }
272
273    /// Set source address
274    pub fn set_source(&mut self, source: NetworkAddress) {
275        self.source = Some(source);
276        self.control.source_present = true;
277    }
278
279    /// Set destination address
280    pub fn set_destination(&mut self, destination: NetworkAddress) {
281        self.destination = Some(destination);
282        self.control.destination_present = true;
283    }
284}
285
286/// Router information
287#[derive(Debug, Clone)]
288pub struct RouterInfo {
289    /// Networks this router can reach
290    pub networks: Vec<u16>,
291    /// Router's address
292    pub address: NetworkAddress,
293    /// Performance index (lower is better)
294    pub performance_index: Option<u8>,
295}
296
297impl Npdu {
298    /// Encode NPDU to bytes
299    pub fn encode(&self) -> Vec<u8> {
300        let mut buffer = Vec::new();
301
302        // Version
303        buffer.push(self.version);
304
305        // Control byte
306        buffer.push(self.control.to_byte());
307
308        // Destination network address
309        if let Some(ref dest) = self.destination {
310            buffer.extend_from_slice(&dest.network.to_be_bytes());
311            buffer.push(dest.address.len() as u8);
312            buffer.extend_from_slice(&dest.address);
313        }
314
315        // Source network address
316        if let Some(ref src) = self.source {
317            buffer.extend_from_slice(&src.network.to_be_bytes());
318            buffer.push(src.address.len() as u8);
319            buffer.extend_from_slice(&src.address);
320        }
321
322        // Hop count (only if destination is present)
323        if self.destination.is_some() {
324            buffer.push(self.hop_count.unwrap_or(255));
325        }
326
327        buffer
328    }
329
330    /// Decode NPDU from bytes
331    pub fn decode(data: &[u8]) -> Result<(Self, usize)> {
332        if data.len() < 2 {
333            return Err(NetworkError::InvalidNpdu("NPDU too short".to_string()));
334        }
335
336        let mut pos = 0;
337
338        // Version
339        let version = data[pos];
340        pos += 1;
341
342        if version != 1 {
343            return Err(NetworkError::InvalidNpdu(format!(
344                "Invalid NPDU version: {}",
345                version
346            )));
347        }
348
349        // Control byte
350        let control = NpduControl::from_byte(data[pos]);
351        pos += 1;
352
353        // Destination network address
354        let destination = if control.destination_present {
355            if pos + 3 > data.len() {
356                return Err(NetworkError::InvalidNpdu(
357                    "Invalid destination address".to_string(),
358                ));
359            }
360
361            let network = u16::from_be_bytes([data[pos], data[pos + 1]]);
362            pos += 2;
363
364            let addr_len = data[pos] as usize;
365            pos += 1;
366
367            if pos + addr_len > data.len() {
368                return Err(NetworkError::InvalidNpdu(
369                    "Invalid destination address length".to_string(),
370                ));
371            }
372
373            let address = data[pos..pos + addr_len].to_vec();
374            pos += addr_len;
375
376            Some(NetworkAddress::new(network, address))
377        } else {
378            None
379        };
380
381        // Source network address
382        let source = if control.source_present {
383            if pos + 3 > data.len() {
384                return Err(NetworkError::InvalidNpdu(
385                    "Invalid source address".to_string(),
386                ));
387            }
388
389            let network = u16::from_be_bytes([data[pos], data[pos + 1]]);
390            pos += 2;
391
392            let addr_len = data[pos] as usize;
393            pos += 1;
394
395            if pos + addr_len > data.len() {
396                return Err(NetworkError::InvalidNpdu(
397                    "Invalid source address length".to_string(),
398                ));
399            }
400
401            let address = data[pos..pos + addr_len].to_vec();
402            pos += addr_len;
403
404            Some(NetworkAddress::new(network, address))
405        } else {
406            None
407        };
408
409        // Hop count (only if destination is present)
410        let hop_count = if destination.is_some() {
411            if pos >= data.len() {
412                return Err(NetworkError::InvalidNpdu("Missing hop count".to_string()));
413            }
414            let hc = data[pos];
415            pos += 1;
416            Some(hc)
417        } else {
418            None
419        };
420
421        let npdu = Npdu {
422            version,
423            control,
424            destination,
425            source,
426            hop_count,
427        };
428
429        Ok((npdu, pos))
430    }
431}
432
433impl Default for Npdu {
434    fn default() -> Self {
435        Self::new()
436    }
437}
438
439/// Network layer message handling
440pub struct NetworkLayerMessage {
441    /// Message type
442    pub message_type: NetworkMessageType,
443    /// Message data
444    pub data: Option<Vec<u8>>,
445}
446
447impl NetworkLayerMessage {
448    /// Create a new network layer message
449    pub fn new(message_type: NetworkMessageType, data: Option<Vec<u8>>) -> Self {
450        Self { message_type, data }
451    }
452
453    /// Encode network layer message
454    pub fn encode(&self) -> Vec<u8> {
455        let mut buffer = vec![self.message_type as u8];
456
457        if let Some(data) = &self.data {
458            buffer.extend_from_slice(data);
459        }
460
461        buffer
462    }
463
464    /// Decode network layer message
465    pub fn decode(data: &[u8]) -> Result<Self> {
466        if data.is_empty() {
467            return Err(NetworkError::InvalidNpdu(
468                "Empty network message".to_string(),
469            ));
470        }
471
472        let message_type = data[0].try_into()?;
473
474        let message_data = if data.len() > 1 {
475            Some(data[1..].to_vec())
476        } else {
477            None
478        };
479
480        Ok(NetworkLayerMessage::new(message_type, message_data))
481    }
482
483    pub fn data(&self) -> Option<&[u8]> {
484        self.data.as_deref()
485    }
486}
487
488/// Basic routing table implementation
489#[derive(Debug, Clone)]
490pub struct RoutingTable {
491    /// Router entries
492    pub entries: Vec<RouterInfo>,
493}
494
495impl RoutingTable {
496    /// Create a new routing table
497    pub fn new() -> Self {
498        Self {
499            entries: Vec::new(),
500        }
501    }
502
503    /// Add a router entry
504    pub fn add_router(&mut self, router: RouterInfo) {
505        // Remove existing entry for the same address
506        self.entries.retain(|r| r.address != router.address);
507        self.entries.push(router);
508    }
509
510    /// Find route to network
511    pub fn find_route(&self, network: u16) -> Option<&RouterInfo> {
512        self.entries.iter().find(|r| r.networks.contains(&network))
513    }
514
515    /// Remove router by address
516    pub fn remove_router(&mut self, address: &NetworkAddress) {
517        self.entries.retain(|r| &r.address != address);
518    }
519}
520
521impl Default for RoutingTable {
522    fn default() -> Self {
523        Self::new()
524    }
525}
526
527/// Network layer router manager for handling routing operations
528#[derive(Debug)]
529pub struct RouterManager {
530    /// Local network number
531    pub local_network: u16,
532    /// Routing table
533    pub routing_table: RoutingTable,
534    /// Maximum hop count allowed
535    pub max_hop_count: u8,
536    /// Router busy status per network
537    pub busy_networks: Vec<u16>,
538    /// Performance metrics
539    pub performance_metrics: RouterPerformanceMetrics,
540}
541
542/// Router performance metrics
543#[derive(Debug, Clone, Default)]
544pub struct RouterPerformanceMetrics {
545    /// Total messages routed
546    pub messages_routed: u64,
547    /// Total routing errors
548    pub routing_errors: u64,
549    /// Messages dropped due to hop count
550    pub hop_count_exceeded: u64,
551    /// Network unreachable count
552    pub network_unreachable_count: u64,
553}
554
555impl RouterManager {
556    /// Create a new router manager
557    pub fn new(local_network: u16) -> Self {
558        Self {
559            local_network,
560            routing_table: RoutingTable::new(),
561            max_hop_count: 255,
562            busy_networks: Vec::new(),
563            performance_metrics: RouterPerformanceMetrics::default(),
564        }
565    }
566
567    /// Process a routing request
568    pub fn route_message(&mut self, npdu: &mut Npdu) -> Result<Option<NetworkAddress>> {
569        // Check if this is a local message
570        if let Some(ref dest) = npdu.destination {
571            if dest.network == self.local_network || dest.network == 0 {
572                return Ok(None); // Local delivery
573            }
574
575            // Check hop count
576            if let Some(hops) = npdu.hop_count {
577                if hops == 0 {
578                    self.performance_metrics.hop_count_exceeded += 1;
579                    return Err(NetworkError::HopCountExceeded);
580                }
581                npdu.hop_count = Some(hops - 1);
582            }
583
584            // Check if network is busy
585            if self.busy_networks.contains(&dest.network) {
586                return Err(NetworkError::RoutingError("Network busy".to_string()));
587            }
588
589            // Find route
590            if let Some(router) = self.routing_table.find_route(dest.network) {
591                self.performance_metrics.messages_routed += 1;
592                Ok(Some(router.address.clone()))
593            } else {
594                self.performance_metrics.network_unreachable_count += 1;
595                Err(NetworkError::NetworkUnreachable(dest.network))
596            }
597        } else {
598            Ok(None) // No destination specified
599        }
600    }
601
602    /// Process network layer messages
603    pub fn process_network_message(
604        &mut self,
605        message: &NetworkLayerMessage,
606    ) -> Result<Option<NetworkLayerMessage>> {
607        match message.message_type {
608            NetworkMessageType::WhoIsRouterToNetwork => {
609                self.handle_who_is_router_to_network(message.data())
610            }
611            NetworkMessageType::IAmRouterToNetwork => {
612                self.handle_i_am_router_to_network(message.data())
613            }
614            NetworkMessageType::RouterBusyToNetwork => {
615                self.handle_router_busy_to_network(message.data())
616            }
617            NetworkMessageType::RouterAvailableToNetwork => {
618                self.handle_router_available_to_network(message.data())
619            }
620            NetworkMessageType::WhatIsNetworkNumber => self.handle_what_is_network_number(),
621            _ => Ok(None), // Other messages not handled here
622        }
623    }
624
625    /// Handle Who-Is-Router-To-Network message
626    fn handle_who_is_router_to_network(
627        &self,
628        data: Option<&[u8]>,
629    ) -> Result<Option<NetworkLayerMessage>> {
630        // If we know routes to the requested networks, respond with I-Am-Router-To-Network
631        if let Some(data) = data {
632            if data.len() >= 2 {
633                let requested_network = u16::from_be_bytes([data[0], data[1]]);
634                if self.routing_table.find_route(requested_network).is_some() {
635                    let response_data = vec![data[0], data[1]]; // Echo the network number
636                    return Ok(Some(NetworkLayerMessage::new(
637                        NetworkMessageType::IAmRouterToNetwork,
638                        Some(response_data),
639                    )));
640                }
641            }
642        }
643        Ok(None)
644    }
645
646    /// Handle I-Am-Router-To-Network message
647    fn handle_i_am_router_to_network(
648        &mut self,
649        data: Option<&[u8]>,
650    ) -> Result<Option<NetworkLayerMessage>> {
651        // Parse networks this router can reach
652        let mut pos = 0;
653        let mut networks = Vec::new();
654
655        if let Some(data) = data {
656            while pos + 1 < data.len() {
657                let network = u16::from_be_bytes([data[pos], data[pos + 1]]);
658                networks.push(network);
659                pos += 2;
660            }
661        }
662
663        // Add router to routing table (would need router address from NPDU source)
664        // This is a simplified implementation
665
666        Ok(None)
667    }
668
669    /// Handle Router-Busy-To-Network message
670    fn handle_router_busy_to_network(
671        &mut self,
672        data: Option<&[u8]>,
673    ) -> Result<Option<NetworkLayerMessage>> {
674        if let Some(data) = data {
675            if data.len() >= 2 {
676                let network = u16::from_be_bytes([data[0], data[1]]);
677                if !self.busy_networks.contains(&network) {
678                    self.busy_networks.push(network);
679                }
680            }
681        }
682        Ok(None)
683    }
684
685    /// Handle Router-Available-To-Network message
686    fn handle_router_available_to_network(
687        &mut self,
688        data: Option<&[u8]>,
689    ) -> Result<Option<NetworkLayerMessage>> {
690        if let Some(data) = data {
691            if data.len() >= 2 {
692                let network = u16::from_be_bytes([data[0], data[1]]);
693                self.busy_networks.retain(|&n| n != network);
694            }
695        }
696        Ok(None)
697    }
698
699    /// Handle What-Is-Network-Number message
700    fn handle_what_is_network_number(&self) -> Result<Option<NetworkLayerMessage>> {
701        let response_data = self.local_network.to_be_bytes().to_vec();
702        Ok(Some(NetworkLayerMessage::new(
703            NetworkMessageType::NetworkNumberIs,
704            Some(response_data),
705        )))
706    }
707
708    /// Add a discovered router
709    pub fn add_discovered_router(
710        &mut self,
711        networks: Vec<u16>,
712        address: NetworkAddress,
713        performance_index: Option<u8>,
714    ) {
715        let router = RouterInfo {
716            networks,
717            address,
718            performance_index,
719        };
720        self.routing_table.add_router(router);
721    }
722
723    /// Set network busy status
724    pub fn set_network_busy(&mut self, network: u16, busy: bool) {
725        if busy {
726            if !self.busy_networks.contains(&network) {
727                self.busy_networks.push(network);
728            }
729        } else {
730            self.busy_networks.retain(|&n| n != network);
731        }
732    }
733
734    /// Get router statistics
735    pub fn get_performance_metrics(&self) -> &RouterPerformanceMetrics {
736        &self.performance_metrics
737    }
738
739    /// Reset performance metrics
740    pub fn reset_performance_metrics(&mut self) {
741        self.performance_metrics = RouterPerformanceMetrics::default();
742    }
743}
744
745/// Network path discovery for finding optimal routes
746#[derive(Debug)]
747pub struct PathDiscovery {
748    /// Known network topology
749    pub network_topology: Vec<NetworkLink>,
750    /// Path cache for faster lookups
751    pub path_cache: Vec<(u16, Vec<u16>)>, // (destination_network, path)
752}
753
754/// Network link information
755#[derive(Debug, Clone)]
756pub struct NetworkLink {
757    /// Source network
758    pub source_network: u16,
759    /// Destination network
760    pub destination_network: u16,
761    /// Cost metric (lower is better)
762    pub cost: u16,
763    /// Router address
764    pub router_address: NetworkAddress,
765}
766
767impl PathDiscovery {
768    /// Create a new path discovery instance
769    pub fn new() -> Self {
770        Self {
771            network_topology: Vec::new(),
772            path_cache: Vec::new(),
773        }
774    }
775
776    /// Add a network link
777    pub fn add_link(&mut self, link: NetworkLink) {
778        // Remove existing link between same networks
779        self.network_topology.retain(|l| {
780            !(l.source_network == link.source_network
781                && l.destination_network == link.destination_network)
782        });
783        self.network_topology.push(link);
784        // Clear cache as topology changed
785        self.path_cache.clear();
786    }
787
788    /// Find optimal path to destination network using Dijkstra's algorithm
789    pub fn find_path(&mut self, source: u16, destination: u16) -> Option<Vec<u16>> {
790        // Check cache first
791        if let Some((_, path)) = self
792            .path_cache
793            .iter()
794            .find(|(dest, _)| *dest == destination)
795        {
796            return Some(path.clone());
797        }
798
799        // Simple implementation of shortest path finding
800        let path = self.dijkstra_shortest_path(source, destination);
801
802        // Cache the result
803        if let Some(ref p) = path {
804            self.path_cache.push((destination, p.clone()));
805        }
806
807        path
808    }
809
810    /// Dijkstra's shortest path algorithm (simplified)
811    fn dijkstra_shortest_path(&self, source: u16, destination: u16) -> Option<Vec<u16>> {
812        if source == destination {
813            return Some(vec![source]);
814        }
815
816        let mut distances: BTreeMap<u16, u16> = BTreeMap::new();
817        let mut previous: BTreeMap<u16, u16> = BTreeMap::new();
818        let mut unvisited: BTreeSet<u16> = BTreeSet::new();
819
820        // Initialize distances
821        for link in &self.network_topology {
822            distances.insert(link.source_network, u16::MAX);
823            distances.insert(link.destination_network, u16::MAX);
824            unvisited.insert(link.source_network);
825            unvisited.insert(link.destination_network);
826        }
827
828        distances.insert(source, 0);
829
830        while !unvisited.is_empty() {
831            // Find unvisited node with minimum distance
832            let current = *unvisited
833                .iter()
834                .min_by_key(|&&node| distances.get(&node).unwrap_or(&u16::MAX))
835                .unwrap();
836
837            if *distances.get(&current).unwrap_or(&u16::MAX) == u16::MAX {
838                break; // No more reachable nodes
839            }
840
841            unvisited.remove(&current);
842
843            if current == destination {
844                // Reconstruct path
845                let mut path = Vec::new();
846                let mut current_node = destination;
847                while let Some(&prev) = previous.get(&current_node) {
848                    path.push(current_node);
849                    current_node = prev;
850                }
851                path.push(source);
852                path.reverse();
853                return Some(path);
854            }
855
856            // Update distances to neighbors
857            for link in &self.network_topology {
858                if link.source_network == current {
859                    let neighbor = link.destination_network;
860                    if unvisited.contains(&neighbor) {
861                        let new_distance = distances[&current].saturating_add(link.cost);
862                        if new_distance < *distances.get(&neighbor).unwrap_or(&u16::MAX) {
863                            distances.insert(neighbor, new_distance);
864                            previous.insert(neighbor, current);
865                        }
866                    }
867                }
868            }
869        }
870
871        None // No path found
872    }
873
874    /// Clear the path cache
875    pub fn clear_cache(&mut self) {
876        self.path_cache.clear();
877    }
878
879    /// Get network topology
880    pub fn get_topology(&self) -> &[NetworkLink] {
881        &self.network_topology
882    }
883}
884
885impl Default for PathDiscovery {
886    fn default() -> Self {
887        Self::new()
888    }
889}
890
891/// Network diagnostics for monitoring network health
892#[derive(Debug, Default)]
893pub struct NetworkDiagnostics {
894    /// Network reachability status
895    pub network_status: Vec<(u16, NetworkStatus)>,
896    /// Router health information
897    pub router_health: Vec<(NetworkAddress, RouterHealth)>,
898    /// Network latency measurements
899    pub latency_measurements: Vec<(u16, u32)>, // (network, latency_ms)
900}
901
902/// Network status enumeration
903#[derive(Debug, Clone, Copy, PartialEq, Eq)]
904pub enum NetworkStatus {
905    Reachable,
906    Unreachable,
907    Degraded,
908    Unknown,
909}
910
911/// Router health information
912#[derive(Debug, Clone)]
913pub struct RouterHealth {
914    /// Router is responding
915    pub responsive: bool,
916    /// Last response time
917    #[cfg(feature = "std")]
918    pub last_response: Option<std::time::Instant>,
919    /// Error count
920    pub error_count: u32,
921    /// Performance index
922    pub performance_index: u8,
923}
924
925impl NetworkDiagnostics {
926    /// Create new network diagnostics
927    pub fn new() -> Self {
928        Self::default()
929    }
930
931    /// Update network status
932    pub fn update_network_status(&mut self, network: u16, status: NetworkStatus) {
933        if let Some((_, existing_status)) = self
934            .network_status
935            .iter_mut()
936            .find(|(net, _)| *net == network)
937        {
938            *existing_status = status;
939        } else {
940            self.network_status.push((network, status));
941        }
942    }
943
944    /// Update router health
945    pub fn update_router_health(&mut self, address: NetworkAddress, health: RouterHealth) {
946        if let Some((_, existing_health)) = self
947            .router_health
948            .iter_mut()
949            .find(|(addr, _)| *addr == address)
950        {
951            *existing_health = health;
952        } else {
953            self.router_health.push((address, health));
954        }
955    }
956
957    /// Record latency measurement
958    pub fn record_latency(&mut self, network: u16, latency_ms: u32) {
959        if let Some((_, existing_latency)) = self
960            .latency_measurements
961            .iter_mut()
962            .find(|(net, _)| *net == network)
963        {
964            *existing_latency = latency_ms;
965        } else {
966            self.latency_measurements.push((network, latency_ms));
967        }
968    }
969
970    /// Get network status
971    pub fn get_network_status(&self, network: u16) -> NetworkStatus {
972        self.network_status
973            .iter()
974            .find(|(net, _)| *net == network)
975            .map(|(_, status)| *status)
976            .unwrap_or(NetworkStatus::Unknown)
977    }
978
979    /// Get router health
980    pub fn get_router_health(&self, address: &NetworkAddress) -> Option<&RouterHealth> {
981        self.router_health
982            .iter()
983            .find(|(addr, _)| addr == address)
984            .map(|(_, health)| health)
985    }
986
987    /// Get average latency for a network
988    pub fn get_average_latency(&self, network: u16) -> Option<u32> {
989        self.latency_measurements
990            .iter()
991            .find(|(net, _)| *net == network)
992            .map(|(_, latency)| *latency)
993    }
994
995    /// Get unhealthy networks
996    pub fn get_unhealthy_networks(&self) -> Vec<u16> {
997        self.network_status
998            .iter()
999            .filter(|(_, status)| {
1000                matches!(status, NetworkStatus::Unreachable | NetworkStatus::Degraded)
1001            })
1002            .map(|(network, _)| *network)
1003            .collect()
1004    }
1005
1006    /// Get network health summary
1007    pub fn get_health_summary(&self) -> NetworkHealthSummary {
1008        let total_networks = self.network_status.len();
1009        let reachable_count = self
1010            .network_status
1011            .iter()
1012            .filter(|(_, status)| matches!(status, NetworkStatus::Reachable))
1013            .count();
1014        let unreachable_count = self
1015            .network_status
1016            .iter()
1017            .filter(|(_, status)| matches!(status, NetworkStatus::Unreachable))
1018            .count();
1019        let degraded_count = self
1020            .network_status
1021            .iter()
1022            .filter(|(_, status)| matches!(status, NetworkStatus::Degraded))
1023            .count();
1024
1025        NetworkHealthSummary {
1026            total_networks,
1027            reachable_count,
1028            unreachable_count,
1029            degraded_count,
1030            average_latency: self.calculate_average_latency(),
1031        }
1032    }
1033
1034    /// Calculate average latency across all networks
1035    fn calculate_average_latency(&self) -> Option<f32> {
1036        if self.latency_measurements.is_empty() {
1037            return None;
1038        }
1039
1040        let total: u32 = self
1041            .latency_measurements
1042            .iter()
1043            .map(|(_, latency)| *latency)
1044            .sum();
1045        Some(total as f32 / self.latency_measurements.len() as f32)
1046    }
1047}
1048
1049/// Network health summary
1050#[derive(Debug, Clone)]
1051pub struct NetworkHealthSummary {
1052    /// Total number of known networks
1053    pub total_networks: usize,
1054    /// Number of reachable networks
1055    pub reachable_count: usize,
1056    /// Number of unreachable networks
1057    pub unreachable_count: usize,
1058    /// Number of degraded networks
1059    pub degraded_count: usize,
1060    /// Average latency across all networks
1061    pub average_latency: Option<f32>,
1062}
1063
1064/// Network layer message handler
1065#[derive(Debug)]
1066pub struct NetworkLayerHandler {
1067    /// Local network number
1068    pub local_network: u16,
1069    /// Router information cache
1070    pub routers: Vec<RouterInfo>,
1071    /// Network message processors
1072    _processors: NetworkMessageProcessors,
1073    /// Network statistics
1074    pub stats: NetworkStatistics,
1075}
1076
1077// Type aliases for complex function pointer types
1078type WhoIsRouterHandler = fn(&NetworkAddress, Option<u16>) -> Option<NetworkLayerMessage>;
1079type IAmRouterHandler = fn(&NetworkAddress, &[u16]) -> Option<NetworkLayerMessage>;
1080
1081/// Network message processors
1082#[derive(Debug, Default)]
1083struct NetworkMessageProcessors {
1084    /// Process Who-Is-Router-To-Network messages
1085    _who_is_router_handler: Option<WhoIsRouterHandler>,
1086    /// Process I-Am-Router-To-Network messages
1087    _i_am_router_handler: Option<IAmRouterHandler>,
1088}
1089
1090impl NetworkLayerHandler {
1091    /// Create a new network layer handler
1092    pub fn new(local_network: u16) -> Self {
1093        Self {
1094            local_network,
1095            routers: Vec::new(),
1096            _processors: NetworkMessageProcessors::default(),
1097            stats: NetworkStatistics::default(),
1098        }
1099    }
1100
1101    /// Process an incoming NPDU
1102    pub fn process_npdu(
1103        &mut self,
1104        npdu: &Npdu,
1105        source_address: &NetworkAddress,
1106    ) -> Result<Option<NetworkResponse>> {
1107        self.stats.record_received();
1108
1109        if npdu.is_network_message() {
1110            self.process_network_message(npdu, source_address)
1111        } else {
1112            // Regular application layer message
1113            Ok(Some(NetworkResponse::ApplicationData))
1114        }
1115    }
1116
1117    /// Process a network layer message
1118    fn process_network_message(
1119        &mut self,
1120        _npdu: &Npdu,
1121        _source_address: &NetworkAddress,
1122    ) -> Result<Option<NetworkResponse>> {
1123        // Network messages have their type in the first byte after the NPDU header
1124        // This would need to be implemented based on the actual message content
1125        Ok(None)
1126    }
1127
1128    /// Send Who-Is-Router-To-Network message
1129    pub fn who_is_router(&mut self, _network: Option<u16>) -> Npdu {
1130        self.stats.record_sent();
1131
1132        let mut npdu = Npdu::new();
1133        npdu.control.network_message = true;
1134        npdu.control.priority = 3; // Normal priority
1135
1136        // Message content would include the network number if specified
1137        npdu
1138    }
1139
1140    /// Send I-Am-Router-To-Network message
1141    pub fn i_am_router(&mut self, _networks: &[u16]) -> Npdu {
1142        self.stats.record_sent();
1143
1144        let mut npdu = Npdu::new();
1145        npdu.control.network_message = true;
1146        npdu.control.priority = 3;
1147
1148        // Message content would include the list of networks
1149        npdu
1150    }
1151
1152    /// Update router information
1153    pub fn update_router(&mut self, router_info: RouterInfo) {
1154        // Check if router already exists
1155        if let Some(existing) = self
1156            .routers
1157            .iter_mut()
1158            .find(|r| r.address == router_info.address)
1159        {
1160            existing.networks = router_info.networks;
1161            existing.performance_index = router_info.performance_index;
1162        } else {
1163            self.routers.push(router_info);
1164        }
1165    }
1166
1167    /// Find best router for a network
1168    pub fn find_router(&self, network: u16) -> Option<&RouterInfo> {
1169        self.routers
1170            .iter()
1171            .filter(|r| r.networks.contains(&network))
1172            .min_by_key(|r| r.performance_index.unwrap_or(255))
1173    }
1174}
1175
1176/// Network layer response types
1177#[derive(Debug)]
1178pub enum NetworkResponse {
1179    /// Application layer data (pass through)
1180    ApplicationData,
1181    /// Network layer message response
1182    NetworkMessage(Npdu),
1183    /// Routing table update
1184    RoutingUpdate(Vec<RouterInfo>),
1185}
1186
1187/// Network priority levels
1188#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1189#[repr(u8)]
1190pub enum NetworkPriority {
1191    /// Life Safety messages (highest priority)
1192    LifeSafety = 3,
1193    /// Critical Equipment messages
1194    CriticalEquipment = 2,
1195    /// Urgent messages
1196    Urgent = 1,
1197    /// Normal messages (lowest priority)
1198    Normal = 0,
1199}
1200
1201impl NetworkPriority {
1202    /// Convert to NPDU priority bits
1203    pub fn to_bits(self) -> u8 {
1204        self as u8
1205    }
1206
1207    /// Create from NPDU priority bits
1208    pub fn from_bits(bits: u8) -> Self {
1209        match bits & 0x03 {
1210            3 => NetworkPriority::LifeSafety,
1211            2 => NetworkPriority::CriticalEquipment,
1212            1 => NetworkPriority::Urgent,
1213            _ => NetworkPriority::Normal,
1214        }
1215    }
1216}
1217
1218/// Network layer statistics
1219#[derive(Debug, Default)]
1220pub struct NetworkStatistics {
1221    /// Total NPDUs received
1222    pub npdus_received: u64,
1223    /// Total NPDUs sent
1224    pub npdus_sent: u64,
1225    /// Routing failures
1226    pub routing_failures: u64,
1227    /// Messages forwarded
1228    pub messages_forwarded: u64,
1229    /// Network layer errors
1230    pub network_errors: u64,
1231    /// Last update time
1232    #[cfg(feature = "std")]
1233    pub last_update: Option<std::time::Instant>,
1234}
1235
1236impl NetworkStatistics {
1237    /// Update statistics for received NPDU
1238    pub fn record_received(&mut self) {
1239        self.npdus_received += 1;
1240        #[cfg(feature = "std")]
1241        {
1242            self.last_update = Some(std::time::Instant::now());
1243        }
1244    }
1245
1246    /// Update statistics for sent NPDU
1247    pub fn record_sent(&mut self) {
1248        self.npdus_sent += 1;
1249        #[cfg(feature = "std")]
1250        {
1251            self.last_update = Some(std::time::Instant::now());
1252        }
1253    }
1254
1255    /// Record a routing failure
1256    pub fn record_routing_failure(&mut self) {
1257        self.routing_failures += 1;
1258        self.network_errors += 1;
1259    }
1260
1261    /// Record a forwarded message
1262    pub fn record_forwarded(&mut self) {
1263        self.messages_forwarded += 1;
1264    }
1265}
1266
1267/// Broadcast distribution table (BDT) entry
1268#[derive(Debug, Clone)]
1269pub struct BdtEntry {
1270    /// Broadcast distribution mask (network numbers)
1271    pub networks: Vec<u16>,
1272    /// Address to send broadcasts
1273    pub address: NetworkAddress,
1274    /// Entry is valid
1275    pub valid: bool,
1276}
1277
1278/// Broadcast distribution table manager
1279#[derive(Debug)]
1280pub struct BroadcastDistributionTable {
1281    /// BDT entries
1282    entries: Vec<BdtEntry>,
1283    /// Maximum number of entries
1284    max_entries: usize,
1285}
1286
1287impl BroadcastDistributionTable {
1288    /// Create a new BDT
1289    pub fn new(max_entries: usize) -> Self {
1290        Self {
1291            entries: Vec::with_capacity(max_entries),
1292            max_entries,
1293        }
1294    }
1295
1296    /// Add or update a BDT entry
1297    pub fn update_entry(&mut self, entry: BdtEntry) -> Result<()> {
1298        // Check if entry already exists
1299        if let Some(existing) = self.entries.iter_mut().find(|e| e.address == entry.address) {
1300            *existing = entry;
1301        } else if self.entries.len() < self.max_entries {
1302            self.entries.push(entry);
1303        } else {
1304            return Err(NetworkError::InvalidNpdu("BDT full".to_string()));
1305        }
1306        Ok(())
1307    }
1308
1309    /// Remove a BDT entry
1310    pub fn remove_entry(&mut self, address: &NetworkAddress) {
1311        self.entries.retain(|e| e.address != *address);
1312    }
1313
1314    /// Get addresses for broadcasting to a network
1315    pub fn get_broadcast_addresses(&self, network: u16) -> Vec<&NetworkAddress> {
1316        self.entries
1317            .iter()
1318            .filter(|e| e.valid && e.networks.contains(&network))
1319            .map(|e| &e.address)
1320            .collect()
1321    }
1322
1323    /// Clear all entries
1324    pub fn clear(&mut self) {
1325        self.entries.clear();
1326    }
1327}
1328
1329/// Foreign device table (FDT) entry
1330#[derive(Debug, Clone)]
1331pub struct FdtEntry {
1332    /// Foreign device address
1333    pub address: NetworkAddress,
1334    /// Time-to-live (seconds)
1335    pub ttl: u16,
1336    /// Remaining time (seconds)
1337    pub remaining_time: u16,
1338    /// Registration timestamp
1339    #[cfg(feature = "std")]
1340    pub registered_at: std::time::Instant,
1341}
1342
1343/// Foreign device table manager
1344#[derive(Debug)]
1345pub struct ForeignDeviceTable {
1346    /// FDT entries
1347    entries: Vec<FdtEntry>,
1348    /// Maximum number of entries
1349    max_entries: usize,
1350}
1351
1352impl ForeignDeviceTable {
1353    /// Create a new FDT
1354    pub fn new(max_entries: usize) -> Self {
1355        Self {
1356            entries: Vec::with_capacity(max_entries),
1357            max_entries,
1358        }
1359    }
1360
1361    /// Register a foreign device
1362    pub fn register(&mut self, address: NetworkAddress, ttl: u16) -> Result<()> {
1363        // Check if already registered
1364        if let Some(existing) = self.entries.iter_mut().find(|e| e.address == address) {
1365            existing.ttl = ttl;
1366            existing.remaining_time = ttl;
1367            #[cfg(feature = "std")]
1368            {
1369                existing.registered_at = std::time::Instant::now();
1370            }
1371        } else if self.entries.len() < self.max_entries {
1372            self.entries.push(FdtEntry {
1373                address,
1374                ttl,
1375                remaining_time: ttl,
1376                #[cfg(feature = "std")]
1377                registered_at: std::time::Instant::now(),
1378            });
1379        } else {
1380            return Err(NetworkError::InvalidNpdu("FDT full".to_string()));
1381        }
1382        Ok(())
1383    }
1384
1385    /// Delete a foreign device
1386    pub fn delete(&mut self, address: &NetworkAddress) -> Result<()> {
1387        self.entries.retain(|e| e.address != *address);
1388        Ok(())
1389    }
1390
1391    /// Update remaining times (called periodically)
1392    pub fn update_times(&mut self, elapsed_seconds: u16) {
1393        self.entries.retain_mut(|entry| {
1394            if entry.remaining_time > elapsed_seconds {
1395                entry.remaining_time -= elapsed_seconds;
1396                true
1397            } else {
1398                false // Remove expired entries
1399            }
1400        });
1401    }
1402
1403    /// Get all active foreign devices
1404    pub fn get_active_devices(&self) -> Vec<&NetworkAddress> {
1405        self.entries.iter().map(|e| &e.address).collect()
1406    }
1407
1408    /// Check if a device is registered
1409    pub fn is_registered(&self, address: &NetworkAddress) -> bool {
1410        self.entries.iter().any(|e| e.address == *address)
1411    }
1412}
1413
1414/// Network security manager
1415#[derive(Debug)]
1416pub struct NetworkSecurityManager {
1417    /// Allowed source networks
1418    allowed_networks: Vec<u16>,
1419    /// Blocked source networks
1420    blocked_networks: Vec<u16>,
1421    /// Allow broadcasts
1422    allow_broadcasts: bool,
1423    /// Security statistics
1424    security_stats: SecurityStatistics,
1425}
1426
1427/// Security statistics
1428#[derive(Debug, Default)]
1429pub struct SecurityStatistics {
1430    /// Messages accepted
1431    pub accepted: u64,
1432    /// Messages rejected
1433    pub rejected: u64,
1434    /// Blocked network attempts
1435    pub blocked_attempts: u64,
1436}
1437
1438impl NetworkSecurityManager {
1439    /// Create a new security manager
1440    pub fn new() -> Self {
1441        Self {
1442            allowed_networks: Vec::new(),
1443            blocked_networks: Vec::new(),
1444            allow_broadcasts: true,
1445            security_stats: SecurityStatistics::default(),
1446        }
1447    }
1448
1449    /// Check if a message should be accepted
1450    pub fn check_message(&mut self, npdu: &Npdu) -> bool {
1451        // Check source network if present
1452        if let Some(ref source) = npdu.source {
1453            if self.blocked_networks.contains(&source.network) {
1454                self.security_stats.blocked_attempts += 1;
1455                self.security_stats.rejected += 1;
1456                return false;
1457            }
1458
1459            if !self.allowed_networks.is_empty() && !self.allowed_networks.contains(&source.network)
1460            {
1461                self.security_stats.rejected += 1;
1462                return false;
1463            }
1464        }
1465
1466        // Check broadcast permission
1467        if !self.allow_broadcasts {
1468            if let Some(ref dest) = npdu.destination {
1469                if dest.is_broadcast() {
1470                    self.security_stats.rejected += 1;
1471                    return false;
1472                }
1473            }
1474        }
1475
1476        self.security_stats.accepted += 1;
1477        true
1478    }
1479
1480    /// Add allowed network
1481    pub fn allow_network(&mut self, network: u16) {
1482        if !self.allowed_networks.contains(&network) {
1483            self.allowed_networks.push(network);
1484        }
1485    }
1486
1487    /// Block a network
1488    pub fn block_network(&mut self, network: u16) {
1489        if !self.blocked_networks.contains(&network) {
1490            self.blocked_networks.push(network);
1491        }
1492        // Remove from allowed if present
1493        self.allowed_networks.retain(|&n| n != network);
1494    }
1495
1496    /// Set broadcast permission
1497    pub fn set_allow_broadcasts(&mut self, allow: bool) {
1498        self.allow_broadcasts = allow;
1499    }
1500
1501    /// Get security statistics
1502    pub fn get_stats(&self) -> &SecurityStatistics {
1503        &self.security_stats
1504    }
1505
1506    /// Reset security statistics
1507    pub fn reset_stats(&mut self) {
1508        self.security_stats = SecurityStatistics::default();
1509    }
1510}
1511
1512impl Default for NetworkSecurityManager {
1513    fn default() -> Self {
1514        Self::new()
1515    }
1516}
1517
1518#[cfg(test)]
1519mod tests {
1520    use super::*;
1521
1522    #[test]
1523    fn test_npdu_control() {
1524        let control = NpduControl {
1525            network_message: true,
1526            destination_present: false,
1527            source_present: true,
1528            expecting_reply: false,
1529            priority: 2,
1530        };
1531
1532        let byte = control.to_byte();
1533        let decoded = NpduControl::from_byte(byte);
1534
1535        assert_eq!(control.network_message, decoded.network_message);
1536        assert_eq!(control.destination_present, decoded.destination_present);
1537        assert_eq!(control.source_present, decoded.source_present);
1538        assert_eq!(control.expecting_reply, decoded.expecting_reply);
1539        assert_eq!(control.priority, decoded.priority);
1540    }
1541
1542    #[test]
1543    fn test_npdu_encode_decode_basic() {
1544        let npdu = Npdu::new();
1545        let encoded = npdu.encode();
1546        let (decoded, consumed) = Npdu::decode(&encoded).unwrap();
1547
1548        assert_eq!(decoded.version, 1);
1549        assert_eq!(consumed, 2); // version + control
1550        assert_eq!(decoded.destination, None);
1551        assert_eq!(decoded.source, None);
1552    }
1553
1554    #[test]
1555    fn test_npdu_with_destination() {
1556        let mut npdu = Npdu::new();
1557        npdu.control.destination_present = true;
1558        npdu.destination = Some(NetworkAddress::new(100, vec![192, 168, 1, 1]));
1559        npdu.hop_count = Some(5);
1560
1561        let encoded = npdu.encode();
1562        let (decoded, _) = Npdu::decode(&encoded).unwrap();
1563
1564        assert_eq!(decoded.destination.as_ref().unwrap().network, 100);
1565        assert_eq!(
1566            decoded.destination.as_ref().unwrap().address,
1567            vec![192, 168, 1, 1]
1568        );
1569        assert_eq!(decoded.hop_count, Some(5));
1570    }
1571
1572    #[test]
1573    fn test_network_message() {
1574        let message = NetworkLayerMessage::new(
1575            NetworkMessageType::WhoIsRouterToNetwork,
1576            vec![0x00, 0x64].into(), // Network 100
1577        );
1578
1579        let encoded = message.encode();
1580        let decoded = NetworkLayerMessage::decode(&encoded).unwrap();
1581
1582        assert_eq!(
1583            decoded.message_type,
1584            NetworkMessageType::WhoIsRouterToNetwork
1585        );
1586        assert_eq!(decoded.data, vec![0x00, 0x64].into());
1587    }
1588
1589    #[test]
1590    fn test_routing_table() {
1591        let mut table = RoutingTable::new();
1592
1593        let router = RouterInfo {
1594            networks: vec![100, 200],
1595            address: NetworkAddress::new(0, vec![192, 168, 1, 1]),
1596            performance_index: Some(10),
1597        };
1598
1599        table.add_router(router);
1600
1601        assert!(table.find_route(100).is_some());
1602        assert!(table.find_route(200).is_some());
1603        assert!(table.find_route(300).is_none());
1604    }
1605
1606    #[test]
1607    fn test_router_manager() {
1608        let mut manager = RouterManager::new(1);
1609
1610        // Add a router for network 100
1611        manager.add_discovered_router(
1612            vec![100],
1613            NetworkAddress::new(0, vec![192, 168, 1, 1]),
1614            Some(10),
1615        );
1616
1617        // Test routing a message to network 100
1618        let mut npdu = Npdu::new();
1619        npdu.destination = Some(NetworkAddress::new(100, vec![10, 0, 0, 1]));
1620        npdu.hop_count = Some(5);
1621
1622        let result = manager.route_message(&mut npdu).unwrap();
1623        assert!(result.is_some());
1624        assert_eq!(npdu.hop_count, Some(4)); // Hop count decremented
1625
1626        // Test local message routing
1627        let mut local_npdu = Npdu::new();
1628        local_npdu.destination = Some(NetworkAddress::new(1, vec![10, 0, 0, 1]));
1629        let local_result = manager.route_message(&mut local_npdu).unwrap();
1630        assert!(local_result.is_none()); // Local delivery
1631
1632        // Test hop count exceeded
1633        let mut hopless_npdu = Npdu::new();
1634        hopless_npdu.destination = Some(NetworkAddress::new(100, vec![10, 0, 0, 1]));
1635        hopless_npdu.hop_count = Some(0);
1636        assert!(manager.route_message(&mut hopless_npdu).is_err());
1637
1638        // Test network unreachable
1639        let mut unreachable_npdu = Npdu::new();
1640        unreachable_npdu.destination = Some(NetworkAddress::new(999, vec![10, 0, 0, 1]));
1641        assert!(manager.route_message(&mut unreachable_npdu).is_err());
1642    }
1643
1644    #[test]
1645    fn test_router_manager_network_messages() {
1646        let mut manager = RouterManager::new(1);
1647
1648        // Add router for network 100
1649        manager.add_discovered_router(
1650            vec![100],
1651            NetworkAddress::new(0, vec![192, 168, 1, 1]),
1652            Some(10),
1653        );
1654
1655        // Test Who-Is-Router-To-Network
1656        let who_is_msg = NetworkLayerMessage::new(
1657            NetworkMessageType::WhoIsRouterToNetwork,
1658            vec![0x00, 0x64].into(), // Network 100
1659        );
1660        let response = manager.process_network_message(&who_is_msg).unwrap();
1661        assert!(response.is_some());
1662        if let Some(resp) = response {
1663            assert_eq!(resp.message_type, NetworkMessageType::IAmRouterToNetwork);
1664            assert_eq!(resp.data, vec![0x00, 0x64].into());
1665        }
1666
1667        // Test What-Is-Network-Number
1668        let what_is_msg = NetworkLayerMessage::new(NetworkMessageType::WhatIsNetworkNumber, None);
1669        let response = manager.process_network_message(&what_is_msg).unwrap();
1670        assert!(response.is_some());
1671        if let Some(resp) = response {
1672            assert_eq!(resp.message_type, NetworkMessageType::NetworkNumberIs);
1673            assert_eq!(resp.data, vec![0x00, 0x01].into()); // Network 1
1674        }
1675
1676        // Test Router-Busy-To-Network
1677        let busy_msg = NetworkLayerMessage::new(
1678            NetworkMessageType::RouterBusyToNetwork,
1679            vec![0x00, 0x64].into(), // Network 100
1680        );
1681        manager.process_network_message(&busy_msg).unwrap();
1682        assert!(manager.busy_networks.contains(&100));
1683
1684        // Test Router-Available-To-Network
1685        let available_msg = NetworkLayerMessage::new(
1686            NetworkMessageType::RouterAvailableToNetwork,
1687            vec![0x00, 0x64].into(), // Network 100
1688        );
1689        manager.process_network_message(&available_msg).unwrap();
1690        assert!(!manager.busy_networks.contains(&100));
1691    }
1692
1693    #[test]
1694    fn test_path_discovery() {
1695        let mut discovery = PathDiscovery::new();
1696
1697        // Create a simple network topology: 1 -> 2 -> 3
1698        discovery.add_link(NetworkLink {
1699            source_network: 1,
1700            destination_network: 2,
1701            cost: 10,
1702            router_address: NetworkAddress::new(0, vec![192, 168, 1, 1]),
1703        });
1704
1705        discovery.add_link(NetworkLink {
1706            source_network: 2,
1707            destination_network: 3,
1708            cost: 15,
1709            router_address: NetworkAddress::new(0, vec![192, 168, 2, 1]),
1710        });
1711
1712        // Find path from 1 to 3
1713        let path = discovery.find_path(1, 3);
1714        assert!(path.is_some());
1715        assert_eq!(path.unwrap(), vec![1, 2, 3]);
1716
1717        // Test path to same network
1718        let same_path = discovery.find_path(1, 1);
1719        assert_eq!(same_path.unwrap(), vec![1]);
1720
1721        // Test path to unreachable network
1722        let no_path = discovery.find_path(1, 999);
1723        assert!(no_path.is_none());
1724
1725        // Test cache functionality
1726        let cached_path = discovery.find_path(1, 3);
1727        assert!(cached_path.is_some());
1728    }
1729
1730    #[test]
1731    fn test_network_diagnostics() {
1732        let mut diagnostics = NetworkDiagnostics::new();
1733
1734        // Update network status
1735        diagnostics.update_network_status(100, NetworkStatus::Reachable);
1736        diagnostics.update_network_status(200, NetworkStatus::Unreachable);
1737        diagnostics.update_network_status(300, NetworkStatus::Degraded);
1738
1739        assert_eq!(
1740            diagnostics.get_network_status(100),
1741            NetworkStatus::Reachable
1742        );
1743        assert_eq!(
1744            diagnostics.get_network_status(200),
1745            NetworkStatus::Unreachable
1746        );
1747        assert_eq!(diagnostics.get_network_status(999), NetworkStatus::Unknown);
1748
1749        // Record latency measurements
1750        diagnostics.record_latency(100, 50);
1751        diagnostics.record_latency(200, 100);
1752        diagnostics.record_latency(300, 200);
1753
1754        assert_eq!(diagnostics.get_average_latency(100), Some(50));
1755        assert_eq!(diagnostics.get_average_latency(200), Some(100));
1756
1757        // Test unhealthy networks
1758        let unhealthy = diagnostics.get_unhealthy_networks();
1759        assert_eq!(unhealthy.len(), 2);
1760        assert!(unhealthy.contains(&200));
1761        assert!(unhealthy.contains(&300));
1762
1763        // Test health summary
1764        let summary = diagnostics.get_health_summary();
1765        assert_eq!(summary.total_networks, 3);
1766        assert_eq!(summary.reachable_count, 1);
1767        assert_eq!(summary.unreachable_count, 1);
1768        assert_eq!(summary.degraded_count, 1);
1769        assert!(summary.average_latency.is_some());
1770        let avg = summary.average_latency.unwrap();
1771        assert!((avg - 116.67).abs() < 0.1); // (50 + 100 + 200) / 3
1772    }
1773
1774    #[test]
1775    fn test_router_health() {
1776        let mut diagnostics = NetworkDiagnostics::new();
1777        let router_addr = NetworkAddress::new(0, vec![192, 168, 1, 1]);
1778
1779        let health = RouterHealth {
1780            responsive: true,
1781            #[cfg(feature = "std")]
1782            last_response: Some(std::time::Instant::now()),
1783            error_count: 5,
1784            performance_index: 10,
1785        };
1786
1787        diagnostics.update_router_health(router_addr.clone(), health);
1788
1789        let retrieved_health = diagnostics.get_router_health(&router_addr);
1790        assert!(retrieved_health.is_some());
1791        assert!(retrieved_health.unwrap().responsive);
1792        assert_eq!(retrieved_health.unwrap().error_count, 5);
1793        assert_eq!(retrieved_health.unwrap().performance_index, 10);
1794    }
1795
1796    #[test]
1797    fn test_network_address_properties() {
1798        let local_addr = NetworkAddress::new(0, vec![192, 168, 1, 1]);
1799        assert!(local_addr.is_local());
1800        assert!(!local_addr.is_broadcast());
1801
1802        let broadcast_addr = NetworkAddress::new(0xFFFF, vec![]);
1803        assert!(broadcast_addr.is_broadcast());
1804        assert!(!broadcast_addr.is_local());
1805
1806        let remote_addr = NetworkAddress::new(100, vec![10, 0, 0, 1]);
1807        assert!(!remote_addr.is_local());
1808        assert!(!remote_addr.is_broadcast());
1809    }
1810
1811    #[test]
1812    fn test_performance_metrics() {
1813        let mut manager = RouterManager::new(1);
1814
1815        // Add a router
1816        manager.add_discovered_router(
1817            vec![100],
1818            NetworkAddress::new(0, vec![192, 168, 1, 1]),
1819            Some(10),
1820        );
1821
1822        // Route some messages to generate metrics
1823        let mut npdu1 = Npdu::new();
1824        npdu1.destination = Some(NetworkAddress::new(100, vec![10, 0, 0, 1]));
1825        npdu1.hop_count = Some(5);
1826        manager.route_message(&mut npdu1).unwrap();
1827
1828        let mut npdu2 = Npdu::new();
1829        npdu2.destination = Some(NetworkAddress::new(100, vec![10, 0, 0, 2]));
1830        npdu2.hop_count = Some(1);
1831        manager.route_message(&mut npdu2).unwrap();
1832
1833        // Try routing to unreachable network
1834        let mut npdu3 = Npdu::new();
1835        npdu3.destination = Some(NetworkAddress::new(999, vec![10, 0, 0, 1]));
1836        let _ = manager.route_message(&mut npdu3);
1837
1838        // Try with hop count 0
1839        let mut npdu4 = Npdu::new();
1840        npdu4.destination = Some(NetworkAddress::new(100, vec![10, 0, 0, 1]));
1841        npdu4.hop_count = Some(0);
1842        let _ = manager.route_message(&mut npdu4);
1843
1844        let metrics = manager.get_performance_metrics();
1845        assert_eq!(metrics.messages_routed, 2);
1846        assert_eq!(metrics.network_unreachable_count, 1);
1847        assert_eq!(metrics.hop_count_exceeded, 1);
1848
1849        // Test reset
1850        manager.reset_performance_metrics();
1851        let reset_metrics = manager.get_performance_metrics();
1852        assert_eq!(reset_metrics.messages_routed, 0);
1853        assert_eq!(reset_metrics.network_unreachable_count, 0);
1854        assert_eq!(reset_metrics.hop_count_exceeded, 0);
1855    }
1856}