#[cfg(feature = "std")]
use std::error::Error;
#[cfg(feature = "std")]
use std::fmt;
#[cfg(not(feature = "std"))]
use core::fmt;
#[cfg(not(feature = "std"))]
extern crate alloc;
#[cfg(not(feature = "std"))]
use alloc::{
collections::{BTreeMap, BTreeSet},
string::String,
vec::Vec,
};
#[cfg(feature = "std")]
use std::collections::{BTreeMap, BTreeSet};
#[cfg(feature = "std")]
pub type Result<T> = std::result::Result<T, NetworkError>;
#[cfg(not(feature = "std"))]
pub type Result<T> = core::result::Result<T, NetworkError>;
#[derive(Debug)]
pub enum NetworkError {
InvalidNpdu(String),
RoutingError(String),
NetworkUnreachable(u16),
HopCountExceeded,
InvalidAddress,
}
impl fmt::Display for NetworkError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
NetworkError::InvalidNpdu(msg) => write!(f, "Invalid NPDU: {}", msg),
NetworkError::RoutingError(msg) => write!(f, "Routing error: {}", msg),
NetworkError::NetworkUnreachable(net) => write!(f, "Network {} unreachable", net),
NetworkError::HopCountExceeded => write!(f, "Hop count exceeded"),
NetworkError::InvalidAddress => write!(f, "Invalid network address"),
}
}
}
#[cfg(feature = "std")]
impl Error for NetworkError {}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum NetworkMessageType {
WhoIsRouterToNetwork = 0x00,
IAmRouterToNetwork = 0x01,
ICouldBeRouterToNetwork = 0x02,
RejectMessageToNetwork = 0x03,
RouterBusyToNetwork = 0x04,
RouterAvailableToNetwork = 0x05,
InitializeRoutingTable = 0x06,
InitializeRoutingTableAck = 0x07,
EstablishConnectionToNetwork = 0x08,
DisconnectConnectionToNetwork = 0x09,
WhatIsNetworkNumber = 0x12,
NetworkNumberIs = 0x13,
}
#[derive(Debug, Clone, Copy, Default)]
pub struct NpduControl {
pub network_message: bool,
pub destination_present: bool,
pub source_present: bool,
pub expecting_reply: bool,
pub priority: u8,
}
impl NpduControl {
pub fn to_byte(&self) -> u8 {
let mut byte = 0u8;
if self.network_message {
byte |= 0x80;
}
if self.destination_present {
byte |= 0x20;
}
if self.source_present {
byte |= 0x08;
}
if self.expecting_reply {
byte |= 0x04;
}
byte |= self.priority & 0x03;
byte
}
pub fn from_byte(byte: u8) -> Self {
Self {
network_message: (byte & 0x80) != 0,
destination_present: (byte & 0x20) != 0,
source_present: (byte & 0x08) != 0,
expecting_reply: (byte & 0x04) != 0,
priority: byte & 0x03,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct NetworkAddress {
pub network: u16,
pub address: Vec<u8>,
}
impl NetworkAddress {
pub fn new(network: u16, address: Vec<u8>) -> Self {
Self { network, address }
}
pub fn is_broadcast(&self) -> bool {
self.network == 0xFFFF
}
pub fn is_local(&self) -> bool {
self.network == 0
}
}
#[derive(Debug, Clone)]
pub struct Npdu {
pub version: u8,
pub control: NpduControl,
pub destination: Option<NetworkAddress>,
pub source: Option<NetworkAddress>,
pub hop_count: Option<u8>,
}
impl Npdu {
pub fn new() -> Self {
Self {
version: 1,
control: NpduControl::default(),
destination: None,
source: None,
hop_count: None,
}
}
pub fn global_broadcast() -> Self {
Self {
version: 1,
control: NpduControl {
network_message: false,
destination_present: true,
source_present: false,
expecting_reply: false, priority: 0,
},
destination: Some(NetworkAddress {
network: 0xFFFF,
address: vec![],
}),
source: None,
hop_count: Some(255),
}
}
pub fn is_network_message(&self) -> bool {
self.control.network_message
}
}
#[derive(Debug, Clone)]
pub struct RouterInfo {
pub networks: Vec<u16>,
pub address: NetworkAddress,
pub performance_index: Option<u8>,
}
impl Npdu {
pub fn encode(&self) -> Vec<u8> {
let mut buffer = Vec::new();
buffer.push(self.version);
buffer.push(self.control.to_byte());
if let Some(ref dest) = self.destination {
buffer.extend_from_slice(&dest.network.to_be_bytes());
buffer.push(dest.address.len() as u8);
buffer.extend_from_slice(&dest.address);
}
if let Some(ref src) = self.source {
buffer.extend_from_slice(&src.network.to_be_bytes());
buffer.push(src.address.len() as u8);
buffer.extend_from_slice(&src.address);
}
if self.destination.is_some() {
buffer.push(self.hop_count.unwrap_or(255));
}
buffer
}
pub fn decode(data: &[u8]) -> Result<(Self, usize)> {
if data.len() < 2 {
return Err(NetworkError::InvalidNpdu("NPDU too short".to_string()));
}
let mut pos = 0;
let version = data[pos];
pos += 1;
if version != 1 {
return Err(NetworkError::InvalidNpdu(format!(
"Invalid NPDU version: {}",
version
)));
}
let control = NpduControl::from_byte(data[pos]);
pos += 1;
let destination = if control.destination_present {
if pos + 3 > data.len() {
return Err(NetworkError::InvalidNpdu(
"Invalid destination address".to_string(),
));
}
let network = u16::from_be_bytes([data[pos], data[pos + 1]]);
pos += 2;
let addr_len = data[pos] as usize;
pos += 1;
if pos + addr_len > data.len() {
return Err(NetworkError::InvalidNpdu(
"Invalid destination address length".to_string(),
));
}
let address = data[pos..pos + addr_len].to_vec();
pos += addr_len;
Some(NetworkAddress::new(network, address))
} else {
None
};
let source = if control.source_present {
if pos + 3 > data.len() {
return Err(NetworkError::InvalidNpdu(
"Invalid source address".to_string(),
));
}
let network = u16::from_be_bytes([data[pos], data[pos + 1]]);
pos += 2;
let addr_len = data[pos] as usize;
pos += 1;
if pos + addr_len > data.len() {
return Err(NetworkError::InvalidNpdu(
"Invalid source address length".to_string(),
));
}
let address = data[pos..pos + addr_len].to_vec();
pos += addr_len;
Some(NetworkAddress::new(network, address))
} else {
None
};
let hop_count = if destination.is_some() {
if pos >= data.len() {
return Err(NetworkError::InvalidNpdu("Missing hop count".to_string()));
}
let hc = data[pos];
pos += 1;
Some(hc)
} else {
None
};
let npdu = Npdu {
version,
control,
destination,
source,
hop_count,
};
Ok((npdu, pos))
}
}
impl Default for Npdu {
fn default() -> Self {
Self::new()
}
}
pub struct NetworkLayerMessage {
pub message_type: NetworkMessageType,
pub data: Vec<u8>,
}
impl NetworkLayerMessage {
pub fn new(message_type: NetworkMessageType, data: Vec<u8>) -> Self {
Self { message_type, data }
}
pub fn encode(&self) -> Vec<u8> {
let mut buffer = vec![self.message_type as u8];
buffer.extend_from_slice(&self.data);
buffer
}
pub fn decode(data: &[u8]) -> Result<Self> {
if data.is_empty() {
return Err(NetworkError::InvalidNpdu(
"Empty network message".to_string(),
));
}
let message_type = match data[0] {
0x00 => NetworkMessageType::WhoIsRouterToNetwork,
0x01 => NetworkMessageType::IAmRouterToNetwork,
0x02 => NetworkMessageType::ICouldBeRouterToNetwork,
0x03 => NetworkMessageType::RejectMessageToNetwork,
0x04 => NetworkMessageType::RouterBusyToNetwork,
0x05 => NetworkMessageType::RouterAvailableToNetwork,
0x06 => NetworkMessageType::InitializeRoutingTable,
0x07 => NetworkMessageType::InitializeRoutingTableAck,
0x08 => NetworkMessageType::EstablishConnectionToNetwork,
0x09 => NetworkMessageType::DisconnectConnectionToNetwork,
0x12 => NetworkMessageType::WhatIsNetworkNumber,
0x13 => NetworkMessageType::NetworkNumberIs,
_ => {
return Err(NetworkError::InvalidNpdu(format!(
"Unknown network message type: {}",
data[0]
)))
}
};
let message_data = if data.len() > 1 {
data[1..].to_vec()
} else {
Vec::new()
};
Ok(NetworkLayerMessage::new(message_type, message_data))
}
}
#[derive(Debug, Clone)]
pub struct RoutingTable {
pub entries: Vec<RouterInfo>,
}
impl RoutingTable {
pub fn new() -> Self {
Self {
entries: Vec::new(),
}
}
pub fn add_router(&mut self, router: RouterInfo) {
self.entries.retain(|r| r.address != router.address);
self.entries.push(router);
}
pub fn find_route(&self, network: u16) -> Option<&RouterInfo> {
self.entries.iter().find(|r| r.networks.contains(&network))
}
pub fn remove_router(&mut self, address: &NetworkAddress) {
self.entries.retain(|r| &r.address != address);
}
}
impl Default for RoutingTable {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug)]
pub struct RouterManager {
pub local_network: u16,
pub routing_table: RoutingTable,
pub max_hop_count: u8,
pub busy_networks: Vec<u16>,
pub performance_metrics: RouterPerformanceMetrics,
}
#[derive(Debug, Clone, Default)]
pub struct RouterPerformanceMetrics {
pub messages_routed: u64,
pub routing_errors: u64,
pub hop_count_exceeded: u64,
pub network_unreachable_count: u64,
}
impl RouterManager {
pub fn new(local_network: u16) -> Self {
Self {
local_network,
routing_table: RoutingTable::new(),
max_hop_count: 255,
busy_networks: Vec::new(),
performance_metrics: RouterPerformanceMetrics::default(),
}
}
pub fn route_message(&mut self, npdu: &mut Npdu) -> Result<Option<NetworkAddress>> {
if let Some(ref dest) = npdu.destination {
if dest.network == self.local_network || dest.network == 0 {
return Ok(None); }
if let Some(hops) = npdu.hop_count {
if hops == 0 {
self.performance_metrics.hop_count_exceeded += 1;
return Err(NetworkError::HopCountExceeded);
}
npdu.hop_count = Some(hops - 1);
}
if self.busy_networks.contains(&dest.network) {
return Err(NetworkError::RoutingError("Network busy".to_string()));
}
if let Some(router) = self.routing_table.find_route(dest.network) {
self.performance_metrics.messages_routed += 1;
Ok(Some(router.address.clone()))
} else {
self.performance_metrics.network_unreachable_count += 1;
Err(NetworkError::NetworkUnreachable(dest.network))
}
} else {
Ok(None) }
}
pub fn process_network_message(
&mut self,
message: &NetworkLayerMessage,
) -> Result<Option<NetworkLayerMessage>> {
match message.message_type {
NetworkMessageType::WhoIsRouterToNetwork => {
self.handle_who_is_router_to_network(&message.data)
}
NetworkMessageType::IAmRouterToNetwork => {
self.handle_i_am_router_to_network(&message.data)
}
NetworkMessageType::RouterBusyToNetwork => {
self.handle_router_busy_to_network(&message.data)
}
NetworkMessageType::RouterAvailableToNetwork => {
self.handle_router_available_to_network(&message.data)
}
NetworkMessageType::WhatIsNetworkNumber => self.handle_what_is_network_number(),
_ => Ok(None), }
}
fn handle_who_is_router_to_network(&self, data: &[u8]) -> Result<Option<NetworkLayerMessage>> {
if data.len() >= 2 {
let requested_network = u16::from_be_bytes([data[0], data[1]]);
if self.routing_table.find_route(requested_network).is_some() {
let response_data = vec![data[0], data[1]]; return Ok(Some(NetworkLayerMessage::new(
NetworkMessageType::IAmRouterToNetwork,
response_data,
)));
}
}
Ok(None)
}
fn handle_i_am_router_to_network(
&mut self,
data: &[u8],
) -> Result<Option<NetworkLayerMessage>> {
let mut pos = 0;
let mut networks = Vec::new();
while pos + 1 < data.len() {
let network = u16::from_be_bytes([data[pos], data[pos + 1]]);
networks.push(network);
pos += 2;
}
Ok(None)
}
fn handle_router_busy_to_network(
&mut self,
data: &[u8],
) -> Result<Option<NetworkLayerMessage>> {
if data.len() >= 2 {
let network = u16::from_be_bytes([data[0], data[1]]);
if !self.busy_networks.contains(&network) {
self.busy_networks.push(network);
}
}
Ok(None)
}
fn handle_router_available_to_network(
&mut self,
data: &[u8],
) -> Result<Option<NetworkLayerMessage>> {
if data.len() >= 2 {
let network = u16::from_be_bytes([data[0], data[1]]);
self.busy_networks.retain(|&n| n != network);
}
Ok(None)
}
fn handle_what_is_network_number(&self) -> Result<Option<NetworkLayerMessage>> {
let response_data = self.local_network.to_be_bytes().to_vec();
Ok(Some(NetworkLayerMessage::new(
NetworkMessageType::NetworkNumberIs,
response_data,
)))
}
pub fn add_discovered_router(
&mut self,
networks: Vec<u16>,
address: NetworkAddress,
performance_index: Option<u8>,
) {
let router = RouterInfo {
networks,
address,
performance_index,
};
self.routing_table.add_router(router);
}
pub fn set_network_busy(&mut self, network: u16, busy: bool) {
if busy {
if !self.busy_networks.contains(&network) {
self.busy_networks.push(network);
}
} else {
self.busy_networks.retain(|&n| n != network);
}
}
pub fn get_performance_metrics(&self) -> &RouterPerformanceMetrics {
&self.performance_metrics
}
pub fn reset_performance_metrics(&mut self) {
self.performance_metrics = RouterPerformanceMetrics::default();
}
}
#[derive(Debug)]
pub struct PathDiscovery {
pub network_topology: Vec<NetworkLink>,
pub path_cache: Vec<(u16, Vec<u16>)>, }
#[derive(Debug, Clone)]
pub struct NetworkLink {
pub source_network: u16,
pub destination_network: u16,
pub cost: u16,
pub router_address: NetworkAddress,
}
impl PathDiscovery {
pub fn new() -> Self {
Self {
network_topology: Vec::new(),
path_cache: Vec::new(),
}
}
pub fn add_link(&mut self, link: NetworkLink) {
self.network_topology.retain(|l| {
!(l.source_network == link.source_network
&& l.destination_network == link.destination_network)
});
self.network_topology.push(link);
self.path_cache.clear();
}
pub fn find_path(&mut self, source: u16, destination: u16) -> Option<Vec<u16>> {
if let Some((_, path)) = self
.path_cache
.iter()
.find(|(dest, _)| *dest == destination)
{
return Some(path.clone());
}
let path = self.dijkstra_shortest_path(source, destination);
if let Some(ref p) = path {
self.path_cache.push((destination, p.clone()));
}
path
}
fn dijkstra_shortest_path(&self, source: u16, destination: u16) -> Option<Vec<u16>> {
if source == destination {
return Some(vec![source]);
}
let mut distances: BTreeMap<u16, u16> = BTreeMap::new();
let mut previous: BTreeMap<u16, u16> = BTreeMap::new();
let mut unvisited: BTreeSet<u16> = BTreeSet::new();
for link in &self.network_topology {
distances.insert(link.source_network, u16::MAX);
distances.insert(link.destination_network, u16::MAX);
unvisited.insert(link.source_network);
unvisited.insert(link.destination_network);
}
distances.insert(source, 0);
while !unvisited.is_empty() {
let current = *unvisited
.iter()
.min_by_key(|&&node| distances.get(&node).unwrap_or(&u16::MAX))
.unwrap();
if *distances.get(¤t).unwrap_or(&u16::MAX) == u16::MAX {
break; }
unvisited.remove(¤t);
if current == destination {
let mut path = Vec::new();
let mut current_node = destination;
while let Some(&prev) = previous.get(¤t_node) {
path.push(current_node);
current_node = prev;
}
path.push(source);
path.reverse();
return Some(path);
}
for link in &self.network_topology {
if link.source_network == current {
let neighbor = link.destination_network;
if unvisited.contains(&neighbor) {
let new_distance = distances[¤t].saturating_add(link.cost);
if new_distance < *distances.get(&neighbor).unwrap_or(&u16::MAX) {
distances.insert(neighbor, new_distance);
previous.insert(neighbor, current);
}
}
}
}
}
None }
pub fn clear_cache(&mut self) {
self.path_cache.clear();
}
pub fn get_topology(&self) -> &[NetworkLink] {
&self.network_topology
}
}
impl Default for PathDiscovery {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Default)]
pub struct NetworkDiagnostics {
pub network_status: Vec<(u16, NetworkStatus)>,
pub router_health: Vec<(NetworkAddress, RouterHealth)>,
pub latency_measurements: Vec<(u16, u32)>, }
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum NetworkStatus {
Reachable,
Unreachable,
Degraded,
Unknown,
}
#[derive(Debug, Clone)]
pub struct RouterHealth {
pub responsive: bool,
#[cfg(feature = "std")]
pub last_response: Option<std::time::Instant>,
pub error_count: u32,
pub performance_index: u8,
}
impl NetworkDiagnostics {
pub fn new() -> Self {
Self::default()
}
pub fn update_network_status(&mut self, network: u16, status: NetworkStatus) {
if let Some((_, existing_status)) = self
.network_status
.iter_mut()
.find(|(net, _)| *net == network)
{
*existing_status = status;
} else {
self.network_status.push((network, status));
}
}
pub fn update_router_health(&mut self, address: NetworkAddress, health: RouterHealth) {
if let Some((_, existing_health)) = self
.router_health
.iter_mut()
.find(|(addr, _)| *addr == address)
{
*existing_health = health;
} else {
self.router_health.push((address, health));
}
}
pub fn record_latency(&mut self, network: u16, latency_ms: u32) {
if let Some((_, existing_latency)) = self
.latency_measurements
.iter_mut()
.find(|(net, _)| *net == network)
{
*existing_latency = latency_ms;
} else {
self.latency_measurements.push((network, latency_ms));
}
}
pub fn get_network_status(&self, network: u16) -> NetworkStatus {
self.network_status
.iter()
.find(|(net, _)| *net == network)
.map(|(_, status)| *status)
.unwrap_or(NetworkStatus::Unknown)
}
pub fn get_router_health(&self, address: &NetworkAddress) -> Option<&RouterHealth> {
self.router_health
.iter()
.find(|(addr, _)| addr == address)
.map(|(_, health)| health)
}
pub fn get_average_latency(&self, network: u16) -> Option<u32> {
self.latency_measurements
.iter()
.find(|(net, _)| *net == network)
.map(|(_, latency)| *latency)
}
pub fn get_unhealthy_networks(&self) -> Vec<u16> {
self.network_status
.iter()
.filter(|(_, status)| {
matches!(status, NetworkStatus::Unreachable | NetworkStatus::Degraded)
})
.map(|(network, _)| *network)
.collect()
}
pub fn get_health_summary(&self) -> NetworkHealthSummary {
let total_networks = self.network_status.len();
let reachable_count = self
.network_status
.iter()
.filter(|(_, status)| matches!(status, NetworkStatus::Reachable))
.count();
let unreachable_count = self
.network_status
.iter()
.filter(|(_, status)| matches!(status, NetworkStatus::Unreachable))
.count();
let degraded_count = self
.network_status
.iter()
.filter(|(_, status)| matches!(status, NetworkStatus::Degraded))
.count();
NetworkHealthSummary {
total_networks,
reachable_count,
unreachable_count,
degraded_count,
average_latency: self.calculate_average_latency(),
}
}
fn calculate_average_latency(&self) -> Option<f32> {
if self.latency_measurements.is_empty() {
return None;
}
let total: u32 = self
.latency_measurements
.iter()
.map(|(_, latency)| *latency)
.sum();
Some(total as f32 / self.latency_measurements.len() as f32)
}
}
#[derive(Debug, Clone)]
pub struct NetworkHealthSummary {
pub total_networks: usize,
pub reachable_count: usize,
pub unreachable_count: usize,
pub degraded_count: usize,
pub average_latency: Option<f32>,
}
#[derive(Debug)]
pub struct NetworkLayerHandler {
pub local_network: u16,
pub routers: Vec<RouterInfo>,
_processors: NetworkMessageProcessors,
pub stats: NetworkStatistics,
}
type WhoIsRouterHandler = fn(&NetworkAddress, Option<u16>) -> Option<NetworkLayerMessage>;
type IAmRouterHandler = fn(&NetworkAddress, &[u16]) -> Option<NetworkLayerMessage>;
#[derive(Debug, Default)]
struct NetworkMessageProcessors {
_who_is_router_handler: Option<WhoIsRouterHandler>,
_i_am_router_handler: Option<IAmRouterHandler>,
}
impl NetworkLayerHandler {
pub fn new(local_network: u16) -> Self {
Self {
local_network,
routers: Vec::new(),
_processors: NetworkMessageProcessors::default(),
stats: NetworkStatistics::default(),
}
}
pub fn process_npdu(
&mut self,
npdu: &Npdu,
source_address: &NetworkAddress,
) -> Result<Option<NetworkResponse>> {
self.stats.record_received();
if npdu.is_network_message() {
self.process_network_message(npdu, source_address)
} else {
Ok(Some(NetworkResponse::ApplicationData))
}
}
fn process_network_message(
&mut self,
_npdu: &Npdu,
_source_address: &NetworkAddress,
) -> Result<Option<NetworkResponse>> {
Ok(None)
}
pub fn who_is_router(&mut self, _network: Option<u16>) -> Npdu {
self.stats.record_sent();
let mut npdu = Npdu::new();
npdu.control.network_message = true;
npdu.control.priority = 3;
npdu
}
pub fn i_am_router(&mut self, _networks: &[u16]) -> Npdu {
self.stats.record_sent();
let mut npdu = Npdu::new();
npdu.control.network_message = true;
npdu.control.priority = 3;
npdu
}
pub fn update_router(&mut self, router_info: RouterInfo) {
if let Some(existing) = self
.routers
.iter_mut()
.find(|r| r.address == router_info.address)
{
existing.networks = router_info.networks;
existing.performance_index = router_info.performance_index;
} else {
self.routers.push(router_info);
}
}
pub fn find_router(&self, network: u16) -> Option<&RouterInfo> {
self.routers
.iter()
.filter(|r| r.networks.contains(&network))
.min_by_key(|r| r.performance_index.unwrap_or(255))
}
}
#[derive(Debug)]
pub enum NetworkResponse {
ApplicationData,
NetworkMessage(Npdu),
RoutingUpdate(Vec<RouterInfo>),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum NetworkPriority {
LifeSafety = 3,
CriticalEquipment = 2,
Urgent = 1,
Normal = 0,
}
impl NetworkPriority {
pub fn to_bits(self) -> u8 {
self as u8
}
pub fn from_bits(bits: u8) -> Self {
match bits & 0x03 {
3 => NetworkPriority::LifeSafety,
2 => NetworkPriority::CriticalEquipment,
1 => NetworkPriority::Urgent,
_ => NetworkPriority::Normal,
}
}
}
#[derive(Debug, Default)]
pub struct NetworkStatistics {
pub npdus_received: u64,
pub npdus_sent: u64,
pub routing_failures: u64,
pub messages_forwarded: u64,
pub network_errors: u64,
#[cfg(feature = "std")]
pub last_update: Option<std::time::Instant>,
}
impl NetworkStatistics {
pub fn record_received(&mut self) {
self.npdus_received += 1;
#[cfg(feature = "std")]
{
self.last_update = Some(std::time::Instant::now());
}
}
pub fn record_sent(&mut self) {
self.npdus_sent += 1;
#[cfg(feature = "std")]
{
self.last_update = Some(std::time::Instant::now());
}
}
pub fn record_routing_failure(&mut self) {
self.routing_failures += 1;
self.network_errors += 1;
}
pub fn record_forwarded(&mut self) {
self.messages_forwarded += 1;
}
}
#[derive(Debug, Clone)]
pub struct BdtEntry {
pub networks: Vec<u16>,
pub address: NetworkAddress,
pub valid: bool,
}
#[derive(Debug)]
pub struct BroadcastDistributionTable {
entries: Vec<BdtEntry>,
max_entries: usize,
}
impl BroadcastDistributionTable {
pub fn new(max_entries: usize) -> Self {
Self {
entries: Vec::with_capacity(max_entries),
max_entries,
}
}
pub fn update_entry(&mut self, entry: BdtEntry) -> Result<()> {
if let Some(existing) = self.entries.iter_mut().find(|e| e.address == entry.address) {
*existing = entry;
} else if self.entries.len() < self.max_entries {
self.entries.push(entry);
} else {
return Err(NetworkError::InvalidNpdu("BDT full".to_string()));
}
Ok(())
}
pub fn remove_entry(&mut self, address: &NetworkAddress) {
self.entries.retain(|e| e.address != *address);
}
pub fn get_broadcast_addresses(&self, network: u16) -> Vec<&NetworkAddress> {
self.entries
.iter()
.filter(|e| e.valid && e.networks.contains(&network))
.map(|e| &e.address)
.collect()
}
pub fn clear(&mut self) {
self.entries.clear();
}
}
#[derive(Debug, Clone)]
pub struct FdtEntry {
pub address: NetworkAddress,
pub ttl: u16,
pub remaining_time: u16,
#[cfg(feature = "std")]
pub registered_at: std::time::Instant,
}
#[derive(Debug)]
pub struct ForeignDeviceTable {
entries: Vec<FdtEntry>,
max_entries: usize,
}
impl ForeignDeviceTable {
pub fn new(max_entries: usize) -> Self {
Self {
entries: Vec::with_capacity(max_entries),
max_entries,
}
}
pub fn register(&mut self, address: NetworkAddress, ttl: u16) -> Result<()> {
if let Some(existing) = self.entries.iter_mut().find(|e| e.address == address) {
existing.ttl = ttl;
existing.remaining_time = ttl;
#[cfg(feature = "std")]
{
existing.registered_at = std::time::Instant::now();
}
} else if self.entries.len() < self.max_entries {
self.entries.push(FdtEntry {
address,
ttl,
remaining_time: ttl,
#[cfg(feature = "std")]
registered_at: std::time::Instant::now(),
});
} else {
return Err(NetworkError::InvalidNpdu("FDT full".to_string()));
}
Ok(())
}
pub fn delete(&mut self, address: &NetworkAddress) -> Result<()> {
self.entries.retain(|e| e.address != *address);
Ok(())
}
pub fn update_times(&mut self, elapsed_seconds: u16) {
self.entries.retain_mut(|entry| {
if entry.remaining_time > elapsed_seconds {
entry.remaining_time -= elapsed_seconds;
true
} else {
false }
});
}
pub fn get_active_devices(&self) -> Vec<&NetworkAddress> {
self.entries.iter().map(|e| &e.address).collect()
}
pub fn is_registered(&self, address: &NetworkAddress) -> bool {
self.entries.iter().any(|e| e.address == *address)
}
}
#[derive(Debug)]
pub struct NetworkSecurityManager {
allowed_networks: Vec<u16>,
blocked_networks: Vec<u16>,
allow_broadcasts: bool,
security_stats: SecurityStatistics,
}
#[derive(Debug, Default)]
pub struct SecurityStatistics {
pub accepted: u64,
pub rejected: u64,
pub blocked_attempts: u64,
}
impl NetworkSecurityManager {
pub fn new() -> Self {
Self {
allowed_networks: Vec::new(),
blocked_networks: Vec::new(),
allow_broadcasts: true,
security_stats: SecurityStatistics::default(),
}
}
pub fn check_message(&mut self, npdu: &Npdu) -> bool {
if let Some(ref source) = npdu.source {
if self.blocked_networks.contains(&source.network) {
self.security_stats.blocked_attempts += 1;
self.security_stats.rejected += 1;
return false;
}
if !self.allowed_networks.is_empty() && !self.allowed_networks.contains(&source.network)
{
self.security_stats.rejected += 1;
return false;
}
}
if !self.allow_broadcasts {
if let Some(ref dest) = npdu.destination {
if dest.is_broadcast() {
self.security_stats.rejected += 1;
return false;
}
}
}
self.security_stats.accepted += 1;
true
}
pub fn allow_network(&mut self, network: u16) {
if !self.allowed_networks.contains(&network) {
self.allowed_networks.push(network);
}
}
pub fn block_network(&mut self, network: u16) {
if !self.blocked_networks.contains(&network) {
self.blocked_networks.push(network);
}
self.allowed_networks.retain(|&n| n != network);
}
pub fn set_allow_broadcasts(&mut self, allow: bool) {
self.allow_broadcasts = allow;
}
pub fn get_stats(&self) -> &SecurityStatistics {
&self.security_stats
}
pub fn reset_stats(&mut self) {
self.security_stats = SecurityStatistics::default();
}
}
impl Default for NetworkSecurityManager {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_npdu_control() {
let control = NpduControl {
network_message: true,
destination_present: false,
source_present: true,
expecting_reply: false,
priority: 2,
};
let byte = control.to_byte();
let decoded = NpduControl::from_byte(byte);
assert_eq!(control.network_message, decoded.network_message);
assert_eq!(control.destination_present, decoded.destination_present);
assert_eq!(control.source_present, decoded.source_present);
assert_eq!(control.expecting_reply, decoded.expecting_reply);
assert_eq!(control.priority, decoded.priority);
}
#[test]
fn test_npdu_encode_decode_basic() {
let npdu = Npdu::new();
let encoded = npdu.encode();
let (decoded, consumed) = Npdu::decode(&encoded).unwrap();
assert_eq!(decoded.version, 1);
assert_eq!(consumed, 2); assert_eq!(decoded.destination, None);
assert_eq!(decoded.source, None);
}
#[test]
fn test_npdu_with_destination() {
let mut npdu = Npdu::new();
npdu.control.destination_present = true;
npdu.destination = Some(NetworkAddress::new(100, vec![192, 168, 1, 1]));
npdu.hop_count = Some(5);
let encoded = npdu.encode();
let (decoded, _) = Npdu::decode(&encoded).unwrap();
assert_eq!(decoded.destination.as_ref().unwrap().network, 100);
assert_eq!(
decoded.destination.as_ref().unwrap().address,
vec![192, 168, 1, 1]
);
assert_eq!(decoded.hop_count, Some(5));
}
#[test]
fn test_network_message() {
let message = NetworkLayerMessage::new(
NetworkMessageType::WhoIsRouterToNetwork,
vec![0x00, 0x64], );
let encoded = message.encode();
let decoded = NetworkLayerMessage::decode(&encoded).unwrap();
assert_eq!(
decoded.message_type,
NetworkMessageType::WhoIsRouterToNetwork
);
assert_eq!(decoded.data, vec![0x00, 0x64]);
}
#[test]
fn test_routing_table() {
let mut table = RoutingTable::new();
let router = RouterInfo {
networks: vec![100, 200],
address: NetworkAddress::new(0, vec![192, 168, 1, 1]),
performance_index: Some(10),
};
table.add_router(router);
assert!(table.find_route(100).is_some());
assert!(table.find_route(200).is_some());
assert!(table.find_route(300).is_none());
}
#[test]
fn test_router_manager() {
let mut manager = RouterManager::new(1);
manager.add_discovered_router(
vec![100],
NetworkAddress::new(0, vec![192, 168, 1, 1]),
Some(10),
);
let mut npdu = Npdu::new();
npdu.destination = Some(NetworkAddress::new(100, vec![10, 0, 0, 1]));
npdu.hop_count = Some(5);
let result = manager.route_message(&mut npdu).unwrap();
assert!(result.is_some());
assert_eq!(npdu.hop_count, Some(4));
let mut local_npdu = Npdu::new();
local_npdu.destination = Some(NetworkAddress::new(1, vec![10, 0, 0, 1]));
let local_result = manager.route_message(&mut local_npdu).unwrap();
assert!(local_result.is_none());
let mut hopless_npdu = Npdu::new();
hopless_npdu.destination = Some(NetworkAddress::new(100, vec![10, 0, 0, 1]));
hopless_npdu.hop_count = Some(0);
assert!(manager.route_message(&mut hopless_npdu).is_err());
let mut unreachable_npdu = Npdu::new();
unreachable_npdu.destination = Some(NetworkAddress::new(999, vec![10, 0, 0, 1]));
assert!(manager.route_message(&mut unreachable_npdu).is_err());
}
#[test]
fn test_router_manager_network_messages() {
let mut manager = RouterManager::new(1);
manager.add_discovered_router(
vec![100],
NetworkAddress::new(0, vec![192, 168, 1, 1]),
Some(10),
);
let who_is_msg = NetworkLayerMessage::new(
NetworkMessageType::WhoIsRouterToNetwork,
vec![0x00, 0x64], );
let response = manager.process_network_message(&who_is_msg).unwrap();
assert!(response.is_some());
if let Some(resp) = response {
assert_eq!(resp.message_type, NetworkMessageType::IAmRouterToNetwork);
assert_eq!(resp.data, vec![0x00, 0x64]);
}
let what_is_msg = NetworkLayerMessage::new(NetworkMessageType::WhatIsNetworkNumber, vec![]);
let response = manager.process_network_message(&what_is_msg).unwrap();
assert!(response.is_some());
if let Some(resp) = response {
assert_eq!(resp.message_type, NetworkMessageType::NetworkNumberIs);
assert_eq!(resp.data, vec![0x00, 0x01]); }
let busy_msg = NetworkLayerMessage::new(
NetworkMessageType::RouterBusyToNetwork,
vec![0x00, 0x64], );
manager.process_network_message(&busy_msg).unwrap();
assert!(manager.busy_networks.contains(&100));
let available_msg = NetworkLayerMessage::new(
NetworkMessageType::RouterAvailableToNetwork,
vec![0x00, 0x64], );
manager.process_network_message(&available_msg).unwrap();
assert!(!manager.busy_networks.contains(&100));
}
#[test]
fn test_path_discovery() {
let mut discovery = PathDiscovery::new();
discovery.add_link(NetworkLink {
source_network: 1,
destination_network: 2,
cost: 10,
router_address: NetworkAddress::new(0, vec![192, 168, 1, 1]),
});
discovery.add_link(NetworkLink {
source_network: 2,
destination_network: 3,
cost: 15,
router_address: NetworkAddress::new(0, vec![192, 168, 2, 1]),
});
let path = discovery.find_path(1, 3);
assert!(path.is_some());
assert_eq!(path.unwrap(), vec![1, 2, 3]);
let same_path = discovery.find_path(1, 1);
assert_eq!(same_path.unwrap(), vec![1]);
let no_path = discovery.find_path(1, 999);
assert!(no_path.is_none());
let cached_path = discovery.find_path(1, 3);
assert!(cached_path.is_some());
}
#[test]
fn test_network_diagnostics() {
let mut diagnostics = NetworkDiagnostics::new();
diagnostics.update_network_status(100, NetworkStatus::Reachable);
diagnostics.update_network_status(200, NetworkStatus::Unreachable);
diagnostics.update_network_status(300, NetworkStatus::Degraded);
assert_eq!(
diagnostics.get_network_status(100),
NetworkStatus::Reachable
);
assert_eq!(
diagnostics.get_network_status(200),
NetworkStatus::Unreachable
);
assert_eq!(diagnostics.get_network_status(999), NetworkStatus::Unknown);
diagnostics.record_latency(100, 50);
diagnostics.record_latency(200, 100);
diagnostics.record_latency(300, 200);
assert_eq!(diagnostics.get_average_latency(100), Some(50));
assert_eq!(diagnostics.get_average_latency(200), Some(100));
let unhealthy = diagnostics.get_unhealthy_networks();
assert_eq!(unhealthy.len(), 2);
assert!(unhealthy.contains(&200));
assert!(unhealthy.contains(&300));
let summary = diagnostics.get_health_summary();
assert_eq!(summary.total_networks, 3);
assert_eq!(summary.reachable_count, 1);
assert_eq!(summary.unreachable_count, 1);
assert_eq!(summary.degraded_count, 1);
assert!(summary.average_latency.is_some());
let avg = summary.average_latency.unwrap();
assert!((avg - 116.67).abs() < 0.1); }
#[test]
fn test_router_health() {
let mut diagnostics = NetworkDiagnostics::new();
let router_addr = NetworkAddress::new(0, vec![192, 168, 1, 1]);
let health = RouterHealth {
responsive: true,
#[cfg(feature = "std")]
last_response: Some(std::time::Instant::now()),
error_count: 5,
performance_index: 10,
};
diagnostics.update_router_health(router_addr.clone(), health);
let retrieved_health = diagnostics.get_router_health(&router_addr);
assert!(retrieved_health.is_some());
assert!(retrieved_health.unwrap().responsive);
assert_eq!(retrieved_health.unwrap().error_count, 5);
assert_eq!(retrieved_health.unwrap().performance_index, 10);
}
#[test]
fn test_network_address_properties() {
let local_addr = NetworkAddress::new(0, vec![192, 168, 1, 1]);
assert!(local_addr.is_local());
assert!(!local_addr.is_broadcast());
let broadcast_addr = NetworkAddress::new(0xFFFF, vec![]);
assert!(broadcast_addr.is_broadcast());
assert!(!broadcast_addr.is_local());
let remote_addr = NetworkAddress::new(100, vec![10, 0, 0, 1]);
assert!(!remote_addr.is_local());
assert!(!remote_addr.is_broadcast());
}
#[test]
fn test_performance_metrics() {
let mut manager = RouterManager::new(1);
manager.add_discovered_router(
vec![100],
NetworkAddress::new(0, vec![192, 168, 1, 1]),
Some(10),
);
let mut npdu1 = Npdu::new();
npdu1.destination = Some(NetworkAddress::new(100, vec![10, 0, 0, 1]));
npdu1.hop_count = Some(5);
manager.route_message(&mut npdu1).unwrap();
let mut npdu2 = Npdu::new();
npdu2.destination = Some(NetworkAddress::new(100, vec![10, 0, 0, 2]));
npdu2.hop_count = Some(1);
manager.route_message(&mut npdu2).unwrap();
let mut npdu3 = Npdu::new();
npdu3.destination = Some(NetworkAddress::new(999, vec![10, 0, 0, 1]));
let _ = manager.route_message(&mut npdu3);
let mut npdu4 = Npdu::new();
npdu4.destination = Some(NetworkAddress::new(100, vec![10, 0, 0, 1]));
npdu4.hop_count = Some(0);
let _ = manager.route_message(&mut npdu4);
let metrics = manager.get_performance_metrics();
assert_eq!(metrics.messages_routed, 2);
assert_eq!(metrics.network_unreachable_count, 1);
assert_eq!(metrics.hop_count_exceeded, 1);
manager.reset_performance_metrics();
let reset_metrics = manager.get_performance_metrics();
assert_eq!(reset_metrics.messages_routed, 0);
assert_eq!(reset_metrics.network_unreachable_count, 0);
assert_eq!(reset_metrics.hop_count_exceeded, 0);
}
}