#2205 - feat: Implement AirSpace and WirelessRouter for Enhanced Network Simulations
This commit introduces the AirSpace and WirelessRouter classes, expanding the PrimAITE's capabilities to simulate wireless networking environments. The AirSpace class manages wireless communications, ensuring seamless transmission across different frequencies. Meanwhile, the WirelessRouter class integrates both wired and wireless networking functionalities.
This commit is contained in:
@@ -77,6 +77,10 @@ SessionManager.
|
||||
- Interface configuration to establish connectivity and define network parameters for external, internal, and DMZ interfaces.
|
||||
- Protocol and service management to oversee traffic and enforce security policies.
|
||||
- Dynamic traffic processing and filtering to ensure network security and integrity.
|
||||
- `AirSpace` class to simulate wireless communications, managing wireless interfaces and facilitating the transmission of frames within specified frequencies.
|
||||
- `AirSpaceFrequency` enum for defining standard wireless frequencies, including 2.4 GHz and 5 GHz bands, to support realistic wireless network simulations.
|
||||
- `WirelessRouter` class, extending the `Router` class, to incorporate wireless networking capabilities alongside traditional wired connections. This class allows the configuration of wireless access points with specific IP settings and operating frequencies.
|
||||
|
||||
|
||||
### Changed
|
||||
- Integrated the RouteTable into the Routers frame processing.
|
||||
|
||||
308
src/primaite/simulator/network/airspace.py
Normal file
308
src/primaite/simulator/network/airspace.py
Normal file
@@ -0,0 +1,308 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from abc import ABC, abstractmethod
|
||||
from enum import Enum
|
||||
from typing import Any, Dict, Final, List, Optional
|
||||
|
||||
from prettytable import PrettyTable
|
||||
|
||||
from primaite import getLogger
|
||||
from primaite.simulator.network.hardware.base import Layer3Interface, NetworkInterface, WiredNetworkInterface
|
||||
from primaite.simulator.network.hardware.node_operating_state import NodeOperatingState
|
||||
from primaite.simulator.network.transmission.data_link_layer import Frame
|
||||
from primaite.simulator.system.core.packet_capture import PacketCapture
|
||||
|
||||
_LOGGER = getLogger(__name__)
|
||||
|
||||
__all__ = ["AIR_SPACE", "AirSpaceFrequency", "WirelessNetworkInterface", "IPWirelessNetworkInterface"]
|
||||
|
||||
|
||||
class AirSpace:
|
||||
"""Represents a wireless airspace, managing wireless network interfaces and handling wireless transmission."""
|
||||
|
||||
def __init__(self):
|
||||
self._wireless_interfaces: Dict[str, WirelessNetworkInterface] = {}
|
||||
self._wireless_interfaces_by_frequency: Dict[AirSpaceFrequency, List[WirelessNetworkInterface]] = {}
|
||||
|
||||
def show(self, frequency: Optional[AirSpaceFrequency] = None):
|
||||
"""
|
||||
Displays a summary of wireless interfaces in the airspace, optionally filtered by a specific frequency.
|
||||
|
||||
:param frequency: The frequency band to filter devices by. If None, devices for all frequencies are shown.
|
||||
"""
|
||||
table = PrettyTable()
|
||||
table.field_names = ["Connected Node", "MAC Address", "IP Address", "Subnet Mask", "Frequency", "Status"]
|
||||
|
||||
# If a specific frequency is provided, filter by it; otherwise, use all frequencies.
|
||||
frequencies_to_show = [frequency] if frequency else self._wireless_interfaces_by_frequency.keys()
|
||||
|
||||
for freq in frequencies_to_show:
|
||||
interfaces = self._wireless_interfaces_by_frequency.get(freq, [])
|
||||
for interface in interfaces:
|
||||
status = "Enabled" if interface.enabled else "Disabled"
|
||||
table.add_row(
|
||||
[
|
||||
interface._connected_node.hostname, # noqa
|
||||
interface.mac_address,
|
||||
interface.ip_address if hasattr(interface, "ip_address") else None,
|
||||
interface.subnet_mask if hasattr(interface, "subnet_mask") else None,
|
||||
str(freq),
|
||||
status,
|
||||
]
|
||||
)
|
||||
|
||||
print(table)
|
||||
|
||||
def add_wireless_interface(self, wireless_interface: WirelessNetworkInterface):
|
||||
"""
|
||||
Adds a wireless network interface to the airspace if it's not already present.
|
||||
|
||||
:param wireless_interface: The wireless network interface to be added.
|
||||
"""
|
||||
if wireless_interface.mac_address not in self._wireless_interfaces:
|
||||
self._wireless_interfaces[wireless_interface.mac_address] = wireless_interface
|
||||
if wireless_interface.frequency not in self._wireless_interfaces_by_frequency:
|
||||
self._wireless_interfaces_by_frequency[wireless_interface.frequency] = []
|
||||
self._wireless_interfaces_by_frequency[wireless_interface.frequency].append(wireless_interface)
|
||||
|
||||
def remove_wireless_interface(self, wireless_interface: WirelessNetworkInterface):
|
||||
"""
|
||||
Removes a wireless network interface from the airspace if it's present.
|
||||
|
||||
:param wireless_interface: The wireless network interface to be removed.
|
||||
"""
|
||||
if wireless_interface.mac_address in self._wireless_interfaces:
|
||||
self._wireless_interfaces.pop(wireless_interface.mac_address)
|
||||
self._wireless_interfaces_by_frequency[wireless_interface.frequency].remove(wireless_interface)
|
||||
|
||||
def clear(self):
|
||||
"""
|
||||
Clears all wireless network interfaces and their frequency associations from the airspace.
|
||||
|
||||
After calling this method, the airspace will contain no wireless network interfaces, and transmissions cannot
|
||||
occur until new interfaces are added again.
|
||||
"""
|
||||
self._wireless_interfaces.clear()
|
||||
self._wireless_interfaces_by_frequency.clear()
|
||||
|
||||
def transmit(self, frame: Frame, sender_network_interface: WirelessNetworkInterface):
|
||||
"""
|
||||
Transmits a frame to all enabled wireless network interfaces on a specific frequency within the airspace.
|
||||
|
||||
This ensures that a wireless interface does not receive its own transmission.
|
||||
|
||||
:param frame: The frame to be transmitted.
|
||||
:param sender_network_interface: The wireless network interface sending the frame. This interface will be
|
||||
excluded from the list of receivers to prevent it from receiving its own transmission.
|
||||
"""
|
||||
for wireless_interface in self._wireless_interfaces_by_frequency.get(sender_network_interface.frequency, []):
|
||||
if wireless_interface != sender_network_interface and wireless_interface.enabled:
|
||||
wireless_interface.receive_frame(frame)
|
||||
|
||||
|
||||
AIR_SPACE: Final[AirSpace] = AirSpace()
|
||||
"""
|
||||
A singleton instance of the AirSpace class, representing the global wireless airspace.
|
||||
|
||||
This instance acts as the central management point for all wireless communications within the simulated network
|
||||
environment. By default, there is only one airspace in the simulation, making this variable a singleton that
|
||||
manages the registration, removal, and transmission of wireless frames across all wireless network interfaces configured
|
||||
in the simulation. It ensures that wireless frames are appropriately transmitted to and received by wireless
|
||||
interfaces based on their operational status and frequency band.
|
||||
"""
|
||||
|
||||
|
||||
class AirSpaceFrequency(Enum):
|
||||
"""Enumeration representing the operating frequencies for wireless communications."""
|
||||
|
||||
WIFI_2_4 = 2.4e9
|
||||
"""WiFi 2.4 GHz. Known for its extensive range and ability to penetrate solid objects effectively."""
|
||||
WIFI_5 = 5e9
|
||||
"""WiFi 5 GHz. Known for its higher data transmission speeds and reduced interference from other devices."""
|
||||
|
||||
def __str__(self) -> str:
|
||||
if self == AirSpaceFrequency.WIFI_2_4:
|
||||
return "WiFi 2.4 GHz"
|
||||
elif self == AirSpaceFrequency.WIFI_5:
|
||||
return "WiFi 5 GHz"
|
||||
else:
|
||||
return "Unknown Frequency"
|
||||
|
||||
|
||||
class WirelessNetworkInterface(NetworkInterface, ABC):
|
||||
"""
|
||||
Represents a wireless network interface in a network device.
|
||||
|
||||
This abstract base class models wireless network interfaces, encapsulating properties and behaviors specific to
|
||||
wireless connectivity. It provides a framework for managing wireless connections, including signal strength,
|
||||
security protocols, and other wireless-specific attributes and methods.
|
||||
|
||||
Wireless network interfaces differ from wired ones in their medium of communication, relying on radio frequencies
|
||||
for data transmission and reception. This class serves as a base for more specific types of wireless network
|
||||
interfaces, such as Wi-Fi adapters or radio network interfaces, ensuring that essential wireless functionality is
|
||||
defined and standardised.
|
||||
|
||||
Inherits from:
|
||||
- NetworkInterface: Provides basic network interface properties and methods.
|
||||
|
||||
As an abstract base class, it requires subclasses to implement specific methods related to wireless communication
|
||||
and may define additional properties and methods specific to wireless technology.
|
||||
"""
|
||||
|
||||
frequency: AirSpaceFrequency = AirSpaceFrequency.WIFI_2_4
|
||||
|
||||
def enable(self):
|
||||
"""Attempt to enable the network interface."""
|
||||
if self.enabled:
|
||||
return
|
||||
|
||||
if not self._connected_node:
|
||||
_LOGGER.error(f"Interface {self} cannot be enabled as it is not connected to a Node")
|
||||
return
|
||||
|
||||
if self._connected_node.operating_state != NodeOperatingState.ON:
|
||||
self._connected_node.sys_log.info(
|
||||
f"Interface {self} cannot be enabled as the connected Node is not powered on"
|
||||
)
|
||||
return
|
||||
|
||||
self.enabled = True
|
||||
self._connected_node.sys_log.info(f"Network Interface {self} enabled")
|
||||
self.pcap = PacketCapture(hostname=self._connected_node.hostname, interface_num=self.port_num)
|
||||
AIR_SPACE.add_wireless_interface(self)
|
||||
|
||||
def disable(self):
|
||||
"""Disable the network interface."""
|
||||
if not self.enabled:
|
||||
return
|
||||
self.enabled = False
|
||||
if self._connected_node:
|
||||
self._connected_node.sys_log.info(f"Network Interface {self} disabled")
|
||||
else:
|
||||
_LOGGER.debug(f"Interface {self} disabled")
|
||||
AIR_SPACE.remove_wireless_interface(self)
|
||||
|
||||
def send_frame(self, frame: Frame) -> bool:
|
||||
"""
|
||||
Attempts to send a network frame over the airspace.
|
||||
|
||||
This method sends a frame if the network interface is enabled and connected to a wireless airspace. It captures
|
||||
the frame using PCAP (if available) and transmits it through the airspace. Returns True if the frame is
|
||||
successfully sent, False otherwise (e.g., if the network interface is disabled).
|
||||
|
||||
:param frame: The network frame to be sent.
|
||||
:return: True if the frame is sent successfully, False if the network interface is disabled.
|
||||
"""
|
||||
if self.enabled:
|
||||
frame.set_sent_timestamp()
|
||||
self.pcap.capture_outbound(frame)
|
||||
AIR_SPACE.transmit(frame, self)
|
||||
return True
|
||||
# Cannot send Frame as the network interface is not enabled
|
||||
return False
|
||||
|
||||
@abstractmethod
|
||||
def receive_frame(self, frame: Frame) -> bool:
|
||||
"""
|
||||
Receives a network frame on the network interface.
|
||||
|
||||
:param frame: The network frame being received.
|
||||
:return: A boolean indicating whether the frame was successfully received.
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class IPWirelessNetworkInterface(WirelessNetworkInterface, Layer3Interface, ABC):
|
||||
"""
|
||||
Represents an IP wireless network interface.
|
||||
|
||||
This interface operates at both the data link layer (Layer 2) and the network layer (Layer 3) of the OSI model,
|
||||
specifically tailored for IP-based communication over wireless connections. This abstract class provides a
|
||||
template for creating specific wireless network interfaces that support Internet Protocol (IP) functionalities.
|
||||
|
||||
As this class is a combination of its parent classes without additional attributes or methods, please refer to
|
||||
the documentation of `WirelessNetworkInterface` and `Layer3Interface` for more details on the supported operations
|
||||
and functionalities.
|
||||
|
||||
The class inherits from:
|
||||
- `WirelessNetworkInterface`: Providing the functionalities and characteristics of a wireless connection, such as
|
||||
managing wireless signal transmission, reception, and associated wireless protocols.
|
||||
- `Layer3Interface`: Enabling network layer capabilities, including IP address assignment, routing, and
|
||||
potentially, Layer 3 protocols like IPsec.
|
||||
|
||||
As an abstract class, `IPWirelessNetworkInterface` does not implement specific methods but ensures that any derived
|
||||
class provides implementations for the functionalities of both `WirelessNetworkInterface` and `Layer3Interface`.
|
||||
This setup is ideal for representing network interfaces in devices that require wireless connections and are capable
|
||||
of IP routing and addressing, such as wireless routers, access points, and wireless end-host devices like
|
||||
smartphones and laptops.
|
||||
|
||||
This class should be extended by concrete classes that define specific behaviors and properties of an IP-capable
|
||||
wireless network interface.
|
||||
"""
|
||||
|
||||
def model_post_init(self, __context: Any) -> None:
|
||||
"""
|
||||
Performs post-initialisation checks to ensure the model's IP configuration is valid.
|
||||
|
||||
This method is invoked after the initialisation of a network model object to validate its network settings,
|
||||
particularly to ensure that the assigned IP address is not a network address. This validation is crucial for
|
||||
maintaining the integrity of network simulations and avoiding configuration errors that could lead to
|
||||
unrealistic or incorrect behavior.
|
||||
|
||||
:param __context: Contextual information or parameters passed to the method, used for further initializing or
|
||||
validating the model post-creation.
|
||||
:raises ValueError: If the IP address is the same as the network address, indicating an incorrect configuration.
|
||||
"""
|
||||
if self.ip_network.network_address == self.ip_address:
|
||||
raise ValueError(f"{self.ip_address}/{self.subnet_mask} must not be a network address")
|
||||
|
||||
def describe_state(self) -> Dict:
|
||||
"""
|
||||
Produce a dictionary describing the current state of this object.
|
||||
|
||||
:return: Current state of this object and child objects.
|
||||
:rtype: Dict
|
||||
"""
|
||||
# Get the state from the WiredNetworkInterface
|
||||
state = WiredNetworkInterface.describe_state(self)
|
||||
|
||||
# Update the state with information from Layer3Interface
|
||||
state.update(Layer3Interface.describe_state(self))
|
||||
|
||||
state["frequency"] = self.frequency
|
||||
|
||||
return state
|
||||
|
||||
def set_original_state(self):
|
||||
"""Sets the original state."""
|
||||
vals_to_include = {"ip_address", "subnet_mask", "mac_address", "speed", "mtu", "wake_on_lan", "enabled"}
|
||||
self._original_state = self.model_dump(include=vals_to_include)
|
||||
|
||||
def enable(self):
|
||||
"""
|
||||
Enables this wired network interface and attempts to send a "hello" message to the default gateway.
|
||||
|
||||
This method activates the network interface, making it operational for network communications. After enabling,
|
||||
it tries to initiate a default gateway "hello" process, typically to establish initial connectivity and resolve
|
||||
the default gateway's MAC address. This step is crucial for ensuring the interface can successfully send data
|
||||
to and receive data from the network.
|
||||
|
||||
The method safely handles cases where the connected node might not have a default gateway set or the
|
||||
`default_gateway_hello` method is not defined, ignoring such errors to proceed without interruption.
|
||||
"""
|
||||
super().enable()
|
||||
try:
|
||||
pass
|
||||
self._connected_node.default_gateway_hello()
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def receive_frame(self, frame: Frame) -> bool:
|
||||
"""
|
||||
Receives a network frame on the interface.
|
||||
|
||||
:param frame: The network frame being received.
|
||||
:return: A boolean indicating whether the frame was successfully received.
|
||||
"""
|
||||
pass
|
||||
@@ -420,86 +420,6 @@ class IPWiredNetworkInterface(WiredNetworkInterface, Layer3Interface, ABC):
|
||||
pass
|
||||
|
||||
|
||||
class WirelessNetworkInterface(NetworkInterface, ABC):
|
||||
"""
|
||||
Represents a wireless network interface in a network device.
|
||||
|
||||
This abstract base class models wireless network interfaces, encapsulating properties and behaviors specific to
|
||||
wireless connectivity. It provides a framework for managing wireless connections, including signal strength,
|
||||
security protocols, and other wireless-specific attributes and methods.
|
||||
|
||||
Wireless network interfaces differ from wired ones in their medium of communication, relying on radio frequencies
|
||||
for data transmission and reception. This class serves as a base for more specific types of wireless interfaces,
|
||||
such as Wi-Fi adapters or radio network interfaces, ensuring that essential wireless functionality is defined
|
||||
and standardised.
|
||||
|
||||
Inherits from:
|
||||
- NetworkInterface: Provides basic network interface properties and methods.
|
||||
|
||||
As an abstract base class, it requires subclasses to implement specific methods related to wireless communication
|
||||
and may define additional properties and methods specific to wireless technology.
|
||||
"""
|
||||
|
||||
|
||||
class IPWirelessNetworkInterface(WiredNetworkInterface, Layer3Interface, ABC):
|
||||
"""
|
||||
Represents an IP wireless network interface.
|
||||
|
||||
This interface operates at both the data link layer (Layer 2) and the network layer (Layer 3) of the OSI model,
|
||||
specifically tailored for IP-based communication over wireless connections. This abstract class provides a
|
||||
template for creating specific wireless network interfaces that support Internet Protocol (IP) functionalities.
|
||||
|
||||
As this class is a combination of its parent classes without additional attributes or methods, please refer to
|
||||
the documentation of `WirelessNetworkInterface` and `Layer3Interface` for more details on the supported operations
|
||||
and functionalities.
|
||||
|
||||
The class inherits from:
|
||||
- `WirelessNetworkInterface`: Providing the functionalities and characteristics of a wireless connection, such as
|
||||
managing wireless signal transmission, reception, and associated wireless protocols.
|
||||
- `Layer3Interface`: Enabling network layer capabilities, including IP address assignment, routing, and
|
||||
potentially, Layer 3 protocols like IPsec.
|
||||
|
||||
As an abstract class, `IPWirelessNetworkInterface` does not implement specific methods but ensures that any derived
|
||||
class provides implementations for the functionalities of both `WirelessNetworkInterface` and `Layer3Interface`.
|
||||
This setup is ideal for representing network interfaces in devices that require wireless connections and are capable
|
||||
of IP routing and addressing, such as wireless routers, access points, and wireless end-host devices like
|
||||
smartphones and laptops.
|
||||
|
||||
This class should be extended by concrete classes that define specific behaviors and properties of an IP-capable
|
||||
wireless network interface.
|
||||
"""
|
||||
|
||||
@abstractmethod
|
||||
def enable(self):
|
||||
"""Enable the interface."""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def disable(self):
|
||||
"""Disable the interface."""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def send_frame(self, frame: Frame) -> bool:
|
||||
"""
|
||||
Attempts to send a network frame through the interface.
|
||||
|
||||
:param frame: The network frame to be sent.
|
||||
:return: A boolean indicating whether the frame was successfully sent.
|
||||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def receive_frame(self, frame: Frame) -> bool:
|
||||
"""
|
||||
Receives a network frame on the interface.
|
||||
|
||||
:param frame: The network frame being received.
|
||||
:return: A boolean indicating whether the frame was successfully received.
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class Link(SimComponent):
|
||||
"""
|
||||
Represents a network link between NIC<-->NIC, NIC<-->SwitchPort, or SwitchPort<-->SwitchPort.
|
||||
|
||||
@@ -0,0 +1,217 @@
|
||||
from typing import Any, Dict, Union
|
||||
|
||||
from pydantic import validate_call
|
||||
|
||||
from primaite.simulator.network.airspace import AirSpaceFrequency, IPWirelessNetworkInterface
|
||||
from primaite.simulator.network.hardware.nodes.network.router import Router, RouterInterface
|
||||
from primaite.simulator.network.transmission.data_link_layer import Frame
|
||||
from primaite.utils.validators import IPV4Address
|
||||
|
||||
|
||||
class WirelessAccessPoint(IPWirelessNetworkInterface):
|
||||
"""
|
||||
Represents a Wireless Access Point (AP) in a network.
|
||||
|
||||
This class models a Wireless Access Point, a device that allows wireless devices to connect to a wired network
|
||||
using Wi-Fi or other wireless standards. The Wireless Access Point bridges the wireless and wired segments of
|
||||
the network, allowing wireless devices to communicate with other devices on the network.
|
||||
|
||||
As an integral component of wireless networking, a Wireless Access Point provides functionalities for network
|
||||
management, signal broadcasting, security enforcement, and connection handling. It also possesses Layer 3
|
||||
capabilities such as IP addressing and subnetting, allowing for network segmentation and routing.
|
||||
|
||||
Inherits from:
|
||||
- WirelessNetworkInterface: Provides basic properties and methods specific to wireless interfaces.
|
||||
- Layer3Interface: Provides Layer 3 properties like ip_address and subnet_mask, enabling the device to manage
|
||||
network traffic and routing.
|
||||
|
||||
This class can be further specialised or extended to support specific features or standards related to wireless
|
||||
networking, such as different Wi-Fi versions, frequency bands, or advanced security protocols.
|
||||
"""
|
||||
|
||||
def model_post_init(self, __context: Any) -> None:
|
||||
"""
|
||||
Performs post-initialisation checks to ensure the model's IP configuration is valid.
|
||||
|
||||
This method is invoked after the initialisation of a network model object to validate its network settings,
|
||||
particularly to ensure that the assigned IP address is not a network address. This validation is crucial for
|
||||
maintaining the integrity of network simulations and avoiding configuration errors that could lead to
|
||||
unrealistic or incorrect behavior.
|
||||
|
||||
:param __context: Contextual information or parameters passed to the method, used for further initializing or
|
||||
validating the model post-creation.
|
||||
:raises ValueError: If the IP address is the same as the network address, indicating an incorrect configuration.
|
||||
"""
|
||||
if self.ip_network.network_address == self.ip_address:
|
||||
raise ValueError(f"{self.ip_address}/{self.subnet_mask} must not be a network address")
|
||||
|
||||
def describe_state(self) -> Dict:
|
||||
"""
|
||||
Produce a dictionary describing the current state of this object.
|
||||
|
||||
:return: Current state of this object and child objects.
|
||||
:rtype: Dict
|
||||
"""
|
||||
return super().describe_state()
|
||||
|
||||
def receive_frame(self, frame: Frame) -> bool:
|
||||
"""
|
||||
Receives a network frame on the interface.
|
||||
|
||||
:param frame: The network frame being received.
|
||||
:return: A boolean indicating whether the frame was successfully received.
|
||||
"""
|
||||
if self.enabled:
|
||||
frame.decrement_ttl()
|
||||
if frame.ip and frame.ip.ttl < 1:
|
||||
self._connected_node.sys_log.info("Frame discarded as TTL limit reached")
|
||||
return False
|
||||
frame.set_received_timestamp()
|
||||
self.pcap.capture_inbound(frame)
|
||||
# If this destination or is broadcast
|
||||
if frame.ethernet.dst_mac_addr == self.mac_address or frame.ethernet.dst_mac_addr == "ff:ff:ff:ff:ff:ff":
|
||||
self._connected_node.receive_frame(frame=frame, from_network_interface=self)
|
||||
return True
|
||||
return False
|
||||
|
||||
def __str__(self) -> str:
|
||||
"""
|
||||
String representation of the NIC.
|
||||
|
||||
:return: A string combining the port number, MAC address and IP address of the NIC.
|
||||
"""
|
||||
return f"Port {self.port_num}: {self.mac_address}/{self.ip_address} ({self.frequency})"
|
||||
|
||||
|
||||
class WirelessRouter(Router):
|
||||
"""
|
||||
A WirelessRouter class that extends the functionality of a standard Router to include wireless capabilities.
|
||||
|
||||
This class represents a network device that performs routing functions similar to a traditional router but also
|
||||
includes the functionality of a wireless access point. This allows the WirelessRouter to not only direct traffic
|
||||
between wired networks but also to manage and facilitate wireless network connections.
|
||||
|
||||
A WirelessRouter is instantiated and configured with both wired and wireless interfaces. The wired interfaces are
|
||||
managed similarly to those in a standard Router, while the wireless interfaces require additional configuration
|
||||
specific to wireless settings, such as setting the frequency band (e.g., 2.4 GHz or 5 GHz for Wi-Fi).
|
||||
|
||||
The WirelessRouter facilitates creating a network environment where devices can be interconnected via both
|
||||
Ethernet (wired) and Wi-Fi (wireless), making it an essential component for simulating more complex and realistic
|
||||
network topologies within PrimAITE.
|
||||
|
||||
Example:
|
||||
>>> wireless_router = WirelessRouter(hostname="wireless_router_1")
|
||||
>>> wireless_router.configure_router_interface(
|
||||
... ip_address="192.168.1.1",
|
||||
... subnet_mask="255.255.255.0"
|
||||
... )
|
||||
>>> wireless_router.configure_wireless_access_point(
|
||||
... ip_address="10.10.10.1",
|
||||
... subnet_mask="255.255.255.0"
|
||||
... frequency=AirSpaceFrequency.WIFI_2_4
|
||||
... )
|
||||
"""
|
||||
|
||||
network_interfaces: Dict[str, Union[RouterInterface, WirelessAccessPoint]] = {}
|
||||
network_interface: Dict[int, Union[RouterInterface, WirelessAccessPoint]] = {}
|
||||
|
||||
def __init__(self, hostname: str, **kwargs):
|
||||
super().__init__(hostname=hostname, num_ports=0, **kwargs)
|
||||
|
||||
wap = WirelessAccessPoint(ip_address="127.0.0.1", subnet_mask="255.0.0.0", gateway="0.0.0.0")
|
||||
wap.port_num = 1
|
||||
self.connect_nic(wap)
|
||||
self.network_interface[1] = wap
|
||||
|
||||
router_interface = RouterInterface(ip_address="127.0.0.1", subnet_mask="255.0.0.0", gateway="0.0.0.0")
|
||||
router_interface.port_num = 2
|
||||
self.connect_nic(router_interface)
|
||||
self.network_interface[2] = router_interface
|
||||
|
||||
self.set_original_state()
|
||||
|
||||
@property
|
||||
def wireless_access_point(self) -> WirelessAccessPoint:
|
||||
"""
|
||||
Retrieves the wireless access point interface associated with this wireless router.
|
||||
|
||||
This property provides direct access to the WirelessAccessPoint interface of the router, facilitating wireless
|
||||
communications. Specifically, it returns the interface configured on port 1, dedicated to establishing and
|
||||
managing wireless network connections. This interface is essential for enabling wireless connectivity,
|
||||
allowing devices within connect to the network wirelessly.
|
||||
|
||||
:return: The WirelessAccessPoint instance representing the wireless connection interface on port 1 of the
|
||||
wireless router.
|
||||
"""
|
||||
return self.network_interface[1]
|
||||
|
||||
@validate_call()
|
||||
def configure_wireless_access_point(
|
||||
self,
|
||||
ip_address: IPV4Address,
|
||||
subnet_mask: IPV4Address,
|
||||
frequency: AirSpaceFrequency = AirSpaceFrequency.WIFI_2_4,
|
||||
):
|
||||
"""
|
||||
Configures a wireless access point (WAP).
|
||||
|
||||
Sets its IP address, subnet mask, and operating frequency. This method ensures the wireless access point is
|
||||
properly set up to manage wireless communication over the specified frequency band.
|
||||
|
||||
The method first disables the WAP to safely apply configuration changes. After configuring the IP settings,
|
||||
it sets the WAP to operate on the specified frequency band and then re-enables the WAP for operation.
|
||||
|
||||
:param ip_address: The IP address to be assigned to the wireless access point.
|
||||
:param subnet_mask: The subnet mask associated with the IP address
|
||||
:param frequency: The operating frequency of the wireless access point, defined by the AirSpaceFrequency
|
||||
enum. This determines the frequency band (e.g., 2.4 GHz or 5 GHz) the access point will use for wireless
|
||||
communication. Default is AirSpaceFrequency.WIFI_2_4.
|
||||
"""
|
||||
self.wireless_access_point.disable() # Temporarily disable the WAP for reconfiguration
|
||||
network_interface = self.network_interface[1]
|
||||
network_interface.ip_address = ip_address
|
||||
network_interface.subnet_mask = subnet_mask
|
||||
self.sys_log.info(f"Configured WAP {network_interface}")
|
||||
self.set_original_state()
|
||||
self.wireless_access_point.frequency = frequency # Set operating frequency
|
||||
self.wireless_access_point.enable() # Re-enable the WAP with new settings
|
||||
|
||||
@property
|
||||
def router_interface(self) -> RouterInterface:
|
||||
"""
|
||||
Retrieves the router interface associated with this wireless router.
|
||||
|
||||
This property provides access to the router interface configured for wired connections. It specifically
|
||||
returns the interface configured on port 2, which is reserved for wired LAN/WAN connections.
|
||||
|
||||
:return: The RouterInterface instance representing the wired LAN/WAN connection on port 2 of the wireless
|
||||
router.
|
||||
"""
|
||||
return self.network_interface[2]
|
||||
|
||||
@validate_call()
|
||||
def configure_router_interface(
|
||||
self,
|
||||
ip_address: IPV4Address,
|
||||
subnet_mask: IPV4Address,
|
||||
):
|
||||
"""
|
||||
Configures a router interface.
|
||||
|
||||
Sets its IP address and subnet mask.
|
||||
|
||||
The method first disables the router interface to safely apply configuration changes. After configuring the IP
|
||||
settings, it re-enables the router interface for operation.
|
||||
|
||||
:param ip_address: The IP address to be assigned to the router interface.
|
||||
:param subnet_mask: The subnet mask associated with the IP address
|
||||
"""
|
||||
self.router_interface.disable() # Temporarily disable the router interface for reconfiguration
|
||||
super().configure_port(port=2, ip_address=ip_address, subnet_mask=subnet_mask) # Set IP configuration
|
||||
self.router_interface.enable() # Re-enable the router interface with new settings
|
||||
|
||||
def configure_port(self, port: int, ip_address: Union[IPV4Address, str], subnet_mask: Union[IPV4Address, str]):
|
||||
"""Not Implemented."""
|
||||
raise NotImplementedError(
|
||||
"Please use the 'configure_wireless_access_point' and 'configure_router_interface' functions."
|
||||
)
|
||||
Reference in New Issue
Block a user