1#[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#[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#[derive(Debug)]
74pub enum NetworkError {
75 InvalidNpdu(String),
77 RoutingError(String),
79 NetworkUnreachable(u16),
81 HopCountExceeded,
83 InvalidAddress,
85 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#[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#[derive(Debug, Clone, Copy, Default)]
149pub struct NpduControl {
150 pub network_message: bool,
152 pub destination_present: bool,
154 pub source_present: bool,
156 pub expecting_reply: bool,
158 pub priority: u8,
160}
161
162impl NpduControl {
163 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 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#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
196#[derive(Debug, Clone, PartialEq, Eq, Hash)]
197pub struct NetworkAddress {
198 pub network: u16,
200 pub address: Vec<u8>,
202}
203
204impl NetworkAddress {
205 pub fn new(network: u16, address: Vec<u8>) -> Self {
207 Self { network, address }
208 }
209
210 pub fn is_broadcast(&self) -> bool {
212 self.network == 0xFFFF
213 }
214
215 pub fn is_local(&self) -> bool {
217 self.network == 0
218 }
219}
220
221#[derive(Debug, Clone)]
223pub struct Npdu {
224 pub version: u8,
226 pub control: NpduControl,
228 pub destination: Option<NetworkAddress>,
230 pub source: Option<NetworkAddress>,
232 pub hop_count: Option<u8>,
234}
235
236impl Npdu {
237 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 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, 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 pub fn is_network_message(&self) -> bool {
270 self.control.network_message
271 }
272
273 pub fn set_source(&mut self, source: NetworkAddress) {
275 self.source = Some(source);
276 self.control.source_present = true;
277 }
278
279 pub fn set_destination(&mut self, destination: NetworkAddress) {
281 self.destination = Some(destination);
282 self.control.destination_present = true;
283 }
284}
285
286#[derive(Debug, Clone)]
288pub struct RouterInfo {
289 pub networks: Vec<u16>,
291 pub address: NetworkAddress,
293 pub performance_index: Option<u8>,
295}
296
297impl Npdu {
298 pub fn encode(&self) -> Vec<u8> {
300 let mut buffer = Vec::new();
301
302 buffer.push(self.version);
304
305 buffer.push(self.control.to_byte());
307
308 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 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 if self.destination.is_some() {
324 buffer.push(self.hop_count.unwrap_or(255));
325 }
326
327 buffer
328 }
329
330 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 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 let control = NpduControl::from_byte(data[pos]);
351 pos += 1;
352
353 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 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 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
439pub struct NetworkLayerMessage {
441 pub message_type: NetworkMessageType,
443 pub data: Option<Vec<u8>>,
445}
446
447impl NetworkLayerMessage {
448 pub fn new(message_type: NetworkMessageType, data: Option<Vec<u8>>) -> Self {
450 Self { message_type, data }
451 }
452
453 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 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#[derive(Debug, Clone)]
490pub struct RoutingTable {
491 pub entries: Vec<RouterInfo>,
493}
494
495impl RoutingTable {
496 pub fn new() -> Self {
498 Self {
499 entries: Vec::new(),
500 }
501 }
502
503 pub fn add_router(&mut self, router: RouterInfo) {
505 self.entries.retain(|r| r.address != router.address);
507 self.entries.push(router);
508 }
509
510 pub fn find_route(&self, network: u16) -> Option<&RouterInfo> {
512 self.entries.iter().find(|r| r.networks.contains(&network))
513 }
514
515 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#[derive(Debug)]
529pub struct RouterManager {
530 pub local_network: u16,
532 pub routing_table: RoutingTable,
534 pub max_hop_count: u8,
536 pub busy_networks: Vec<u16>,
538 pub performance_metrics: RouterPerformanceMetrics,
540}
541
542#[derive(Debug, Clone, Default)]
544pub struct RouterPerformanceMetrics {
545 pub messages_routed: u64,
547 pub routing_errors: u64,
549 pub hop_count_exceeded: u64,
551 pub network_unreachable_count: u64,
553}
554
555impl RouterManager {
556 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 pub fn route_message(&mut self, npdu: &mut Npdu) -> Result<Option<NetworkAddress>> {
569 if let Some(ref dest) = npdu.destination {
571 if dest.network == self.local_network || dest.network == 0 {
572 return Ok(None); }
574
575 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 if self.busy_networks.contains(&dest.network) {
586 return Err(NetworkError::RoutingError("Network busy".to_string()));
587 }
588
589 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) }
600 }
601
602 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), }
623 }
624
625 fn handle_who_is_router_to_network(
627 &self,
628 data: Option<&[u8]>,
629 ) -> Result<Option<NetworkLayerMessage>> {
630 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]]; return Ok(Some(NetworkLayerMessage::new(
637 NetworkMessageType::IAmRouterToNetwork,
638 Some(response_data),
639 )));
640 }
641 }
642 }
643 Ok(None)
644 }
645
646 fn handle_i_am_router_to_network(
648 &mut self,
649 data: Option<&[u8]>,
650 ) -> Result<Option<NetworkLayerMessage>> {
651 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 Ok(None)
667 }
668
669 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 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 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 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 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 pub fn get_performance_metrics(&self) -> &RouterPerformanceMetrics {
736 &self.performance_metrics
737 }
738
739 pub fn reset_performance_metrics(&mut self) {
741 self.performance_metrics = RouterPerformanceMetrics::default();
742 }
743}
744
745#[derive(Debug)]
747pub struct PathDiscovery {
748 pub network_topology: Vec<NetworkLink>,
750 pub path_cache: Vec<(u16, Vec<u16>)>, }
753
754#[derive(Debug, Clone)]
756pub struct NetworkLink {
757 pub source_network: u16,
759 pub destination_network: u16,
761 pub cost: u16,
763 pub router_address: NetworkAddress,
765}
766
767impl PathDiscovery {
768 pub fn new() -> Self {
770 Self {
771 network_topology: Vec::new(),
772 path_cache: Vec::new(),
773 }
774 }
775
776 pub fn add_link(&mut self, link: NetworkLink) {
778 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 self.path_cache.clear();
786 }
787
788 pub fn find_path(&mut self, source: u16, destination: u16) -> Option<Vec<u16>> {
790 if let Some((_, path)) = self
792 .path_cache
793 .iter()
794 .find(|(dest, _)| *dest == destination)
795 {
796 return Some(path.clone());
797 }
798
799 let path = self.dijkstra_shortest_path(source, destination);
801
802 if let Some(ref p) = path {
804 self.path_cache.push((destination, p.clone()));
805 }
806
807 path
808 }
809
810 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 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 let current = *unvisited
833 .iter()
834 .min_by_key(|&&node| distances.get(&node).unwrap_or(&u16::MAX))
835 .unwrap();
836
837 if *distances.get(¤t).unwrap_or(&u16::MAX) == u16::MAX {
838 break; }
840
841 unvisited.remove(¤t);
842
843 if current == destination {
844 let mut path = Vec::new();
846 let mut current_node = destination;
847 while let Some(&prev) = previous.get(¤t_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 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[¤t].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 }
873
874 pub fn clear_cache(&mut self) {
876 self.path_cache.clear();
877 }
878
879 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#[derive(Debug, Default)]
893pub struct NetworkDiagnostics {
894 pub network_status: Vec<(u16, NetworkStatus)>,
896 pub router_health: Vec<(NetworkAddress, RouterHealth)>,
898 pub latency_measurements: Vec<(u16, u32)>, }
901
902#[derive(Debug, Clone, Copy, PartialEq, Eq)]
904pub enum NetworkStatus {
905 Reachable,
906 Unreachable,
907 Degraded,
908 Unknown,
909}
910
911#[derive(Debug, Clone)]
913pub struct RouterHealth {
914 pub responsive: bool,
916 #[cfg(feature = "std")]
918 pub last_response: Option<std::time::Instant>,
919 pub error_count: u32,
921 pub performance_index: u8,
923}
924
925impl NetworkDiagnostics {
926 pub fn new() -> Self {
928 Self::default()
929 }
930
931 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 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 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 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 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 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 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 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 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#[derive(Debug, Clone)]
1051pub struct NetworkHealthSummary {
1052 pub total_networks: usize,
1054 pub reachable_count: usize,
1056 pub unreachable_count: usize,
1058 pub degraded_count: usize,
1060 pub average_latency: Option<f32>,
1062}
1063
1064#[derive(Debug)]
1066pub struct NetworkLayerHandler {
1067 pub local_network: u16,
1069 pub routers: Vec<RouterInfo>,
1071 _processors: NetworkMessageProcessors,
1073 pub stats: NetworkStatistics,
1075}
1076
1077type WhoIsRouterHandler = fn(&NetworkAddress, Option<u16>) -> Option<NetworkLayerMessage>;
1079type IAmRouterHandler = fn(&NetworkAddress, &[u16]) -> Option<NetworkLayerMessage>;
1080
1081#[derive(Debug, Default)]
1083struct NetworkMessageProcessors {
1084 _who_is_router_handler: Option<WhoIsRouterHandler>,
1086 _i_am_router_handler: Option<IAmRouterHandler>,
1088}
1089
1090impl NetworkLayerHandler {
1091 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 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 Ok(Some(NetworkResponse::ApplicationData))
1114 }
1115 }
1116
1117 fn process_network_message(
1119 &mut self,
1120 _npdu: &Npdu,
1121 _source_address: &NetworkAddress,
1122 ) -> Result<Option<NetworkResponse>> {
1123 Ok(None)
1126 }
1127
1128 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; npdu
1138 }
1139
1140 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 npdu
1150 }
1151
1152 pub fn update_router(&mut self, router_info: RouterInfo) {
1154 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 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#[derive(Debug)]
1178pub enum NetworkResponse {
1179 ApplicationData,
1181 NetworkMessage(Npdu),
1183 RoutingUpdate(Vec<RouterInfo>),
1185}
1186
1187#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1189#[repr(u8)]
1190pub enum NetworkPriority {
1191 LifeSafety = 3,
1193 CriticalEquipment = 2,
1195 Urgent = 1,
1197 Normal = 0,
1199}
1200
1201impl NetworkPriority {
1202 pub fn to_bits(self) -> u8 {
1204 self as u8
1205 }
1206
1207 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#[derive(Debug, Default)]
1220pub struct NetworkStatistics {
1221 pub npdus_received: u64,
1223 pub npdus_sent: u64,
1225 pub routing_failures: u64,
1227 pub messages_forwarded: u64,
1229 pub network_errors: u64,
1231 #[cfg(feature = "std")]
1233 pub last_update: Option<std::time::Instant>,
1234}
1235
1236impl NetworkStatistics {
1237 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 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 pub fn record_routing_failure(&mut self) {
1257 self.routing_failures += 1;
1258 self.network_errors += 1;
1259 }
1260
1261 pub fn record_forwarded(&mut self) {
1263 self.messages_forwarded += 1;
1264 }
1265}
1266
1267#[derive(Debug, Clone)]
1269pub struct BdtEntry {
1270 pub networks: Vec<u16>,
1272 pub address: NetworkAddress,
1274 pub valid: bool,
1276}
1277
1278#[derive(Debug)]
1280pub struct BroadcastDistributionTable {
1281 entries: Vec<BdtEntry>,
1283 max_entries: usize,
1285}
1286
1287impl BroadcastDistributionTable {
1288 pub fn new(max_entries: usize) -> Self {
1290 Self {
1291 entries: Vec::with_capacity(max_entries),
1292 max_entries,
1293 }
1294 }
1295
1296 pub fn update_entry(&mut self, entry: BdtEntry) -> Result<()> {
1298 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 pub fn remove_entry(&mut self, address: &NetworkAddress) {
1311 self.entries.retain(|e| e.address != *address);
1312 }
1313
1314 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 pub fn clear(&mut self) {
1325 self.entries.clear();
1326 }
1327}
1328
1329#[derive(Debug, Clone)]
1331pub struct FdtEntry {
1332 pub address: NetworkAddress,
1334 pub ttl: u16,
1336 pub remaining_time: u16,
1338 #[cfg(feature = "std")]
1340 pub registered_at: std::time::Instant,
1341}
1342
1343#[derive(Debug)]
1345pub struct ForeignDeviceTable {
1346 entries: Vec<FdtEntry>,
1348 max_entries: usize,
1350}
1351
1352impl ForeignDeviceTable {
1353 pub fn new(max_entries: usize) -> Self {
1355 Self {
1356 entries: Vec::with_capacity(max_entries),
1357 max_entries,
1358 }
1359 }
1360
1361 pub fn register(&mut self, address: NetworkAddress, ttl: u16) -> Result<()> {
1363 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 pub fn delete(&mut self, address: &NetworkAddress) -> Result<()> {
1387 self.entries.retain(|e| e.address != *address);
1388 Ok(())
1389 }
1390
1391 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 }
1400 });
1401 }
1402
1403 pub fn get_active_devices(&self) -> Vec<&NetworkAddress> {
1405 self.entries.iter().map(|e| &e.address).collect()
1406 }
1407
1408 pub fn is_registered(&self, address: &NetworkAddress) -> bool {
1410 self.entries.iter().any(|e| e.address == *address)
1411 }
1412}
1413
1414#[derive(Debug)]
1416pub struct NetworkSecurityManager {
1417 allowed_networks: Vec<u16>,
1419 blocked_networks: Vec<u16>,
1421 allow_broadcasts: bool,
1423 security_stats: SecurityStatistics,
1425}
1426
1427#[derive(Debug, Default)]
1429pub struct SecurityStatistics {
1430 pub accepted: u64,
1432 pub rejected: u64,
1434 pub blocked_attempts: u64,
1436}
1437
1438impl NetworkSecurityManager {
1439 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 pub fn check_message(&mut self, npdu: &Npdu) -> bool {
1451 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 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 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 pub fn block_network(&mut self, network: u16) {
1489 if !self.blocked_networks.contains(&network) {
1490 self.blocked_networks.push(network);
1491 }
1492 self.allowed_networks.retain(|&n| n != network);
1494 }
1495
1496 pub fn set_allow_broadcasts(&mut self, allow: bool) {
1498 self.allow_broadcasts = allow;
1499 }
1500
1501 pub fn get_stats(&self) -> &SecurityStatistics {
1503 &self.security_stats
1504 }
1505
1506 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); 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(), );
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 manager.add_discovered_router(
1612 vec![100],
1613 NetworkAddress::new(0, vec![192, 168, 1, 1]),
1614 Some(10),
1615 );
1616
1617 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)); 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()); 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 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 manager.add_discovered_router(
1650 vec![100],
1651 NetworkAddress::new(0, vec![192, 168, 1, 1]),
1652 Some(10),
1653 );
1654
1655 let who_is_msg = NetworkLayerMessage::new(
1657 NetworkMessageType::WhoIsRouterToNetwork,
1658 vec![0x00, 0x64].into(), );
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 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()); }
1675
1676 let busy_msg = NetworkLayerMessage::new(
1678 NetworkMessageType::RouterBusyToNetwork,
1679 vec![0x00, 0x64].into(), );
1681 manager.process_network_message(&busy_msg).unwrap();
1682 assert!(manager.busy_networks.contains(&100));
1683
1684 let available_msg = NetworkLayerMessage::new(
1686 NetworkMessageType::RouterAvailableToNetwork,
1687 vec![0x00, 0x64].into(), );
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 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 let path = discovery.find_path(1, 3);
1714 assert!(path.is_some());
1715 assert_eq!(path.unwrap(), vec![1, 2, 3]);
1716
1717 let same_path = discovery.find_path(1, 1);
1719 assert_eq!(same_path.unwrap(), vec![1]);
1720
1721 let no_path = discovery.find_path(1, 999);
1723 assert!(no_path.is_none());
1724
1725 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 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 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 let unhealthy = diagnostics.get_unhealthy_networks();
1759 assert_eq!(unhealthy.len(), 2);
1760 assert!(unhealthy.contains(&200));
1761 assert!(unhealthy.contains(&300));
1762
1763 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); }
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 manager.add_discovered_router(
1817 vec![100],
1818 NetworkAddress::new(0, vec![192, 168, 1, 1]),
1819 Some(10),
1820 );
1821
1822 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 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 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 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}