summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLiav A <liavalb@gmail.com>2021-06-04 07:43:16 +0300
committerAli Mohammad Pur <Ali.mpfard@gmail.com>2021-06-09 22:44:09 +0430
commit1c94b5e8eb9723149a76ef54d38224c995c1a765 (patch)
treeaee54ac8ce3e7f2195f3a575aa8848e0e7635343
parent8b1d4d1b8ea7cc0a801b097c977f4d39a39ba5aa (diff)
downloadserenity-1c94b5e8eb9723149a76ef54d38224c995c1a765.zip
Kernel: Introduce the NetworkingManagement singleton
Instead of initializing network adapters in init.cpp, let's move that logic into a separate class to handle this. Also, it seems like a good idea to shift responsiblity on enumeration of network adapters after the boot process, so this singleton will take care of finding the appropriate network adapter when asked to with an IPv4 address or interface name. With this change being merged, we simplify the creation logic of NetworkAdapter derived classes, so we enumerate the PCI bus only once, searching for driver candidates when doing so, and we let each driver to test if it is resposible for the specified PCI device.
-rw-r--r--Kernel/CMakeLists.txt1
-rw-r--r--Kernel/FileSystem/ProcFS.cpp3
-rw-r--r--Kernel/Net/E1000NetworkAdapter.cpp19
-rw-r--r--Kernel/Net/E1000NetworkAdapter.h4
-rw-r--r--Kernel/Net/IPv4Socket.cpp5
-rw-r--r--Kernel/Net/LoopbackAdapter.cpp8
-rw-r--r--Kernel/Net/LoopbackAdapter.h6
-rw-r--r--Kernel/Net/NE2000NetworkAdapter.cpp15
-rw-r--r--Kernel/Net/NE2000NetworkAdapter.h4
-rw-r--r--Kernel/Net/NetworkAdapter.cpp40
-rw-r--r--Kernel/Net/NetworkAdapter.h12
-rw-r--r--Kernel/Net/NetworkTask.cpp15
-rw-r--r--Kernel/Net/NetworkingManagement.cpp101
-rw-r--r--Kernel/Net/NetworkingManagement.h46
-rw-r--r--Kernel/Net/RTL8139NetworkAdapter.cpp15
-rw-r--r--Kernel/Net/RTL8139NetworkAdapter.h4
-rw-r--r--Kernel/Net/Routing.cpp11
-rw-r--r--Kernel/Net/Socket.cpp3
-rw-r--r--Kernel/Net/TCPSocket.cpp3
-rw-r--r--Kernel/init.cpp12
20 files changed, 211 insertions, 116 deletions
diff --git a/Kernel/CMakeLists.txt b/Kernel/CMakeLists.txt
index 023ab811fe..93f0fd58ee 100644
--- a/Kernel/CMakeLists.txt
+++ b/Kernel/CMakeLists.txt
@@ -121,6 +121,7 @@ set(KERNEL_SOURCES
Net/LoopbackAdapter.cpp
Net/NE2000NetworkAdapter.cpp
Net/NetworkAdapter.cpp
+ Net/NetworkingManagement.cpp
Net/NetworkTask.cpp
Net/RTL8139NetworkAdapter.cpp
Net/Routing.cpp
diff --git a/Kernel/FileSystem/ProcFS.cpp b/Kernel/FileSystem/ProcFS.cpp
index 434ba03257..10adb72459 100644
--- a/Kernel/FileSystem/ProcFS.cpp
+++ b/Kernel/FileSystem/ProcFS.cpp
@@ -30,6 +30,7 @@
#include <Kernel/Module.h>
#include <Kernel/Net/LocalSocket.h>
#include <Kernel/Net/NetworkAdapter.h>
+#include <Kernel/Net/NetworkingManagement.h>
#include <Kernel/Net/Routing.h>
#include <Kernel/Net/TCPSocket.h>
#include <Kernel/Net/UDPSocket.h>
@@ -477,7 +478,7 @@ static bool procfs$pid_perf_events(InodeIdentifier identifier, KBufferBuilder& b
static bool procfs$net_adapters(InodeIdentifier, KBufferBuilder& builder)
{
JsonArraySerializer array { builder };
- NetworkAdapter::for_each([&array](auto& adapter) {
+ NetworkingManagement::the().for_each([&array](auto& adapter) {
auto obj = array.add_object();
obj.add("name", adapter.name());
obj.add("class_name", adapter.class_name());
diff --git a/Kernel/Net/E1000NetworkAdapter.cpp b/Kernel/Net/E1000NetworkAdapter.cpp
index 69cb0fa588..03d1fce700 100644
--- a/Kernel/Net/E1000NetworkAdapter.cpp
+++ b/Kernel/Net/E1000NetworkAdapter.cpp
@@ -156,18 +156,15 @@ UNMAP_AFTER_INIT static bool is_valid_device_id(u16 device_id)
}
}
-UNMAP_AFTER_INIT void E1000NetworkAdapter::detect()
+UNMAP_AFTER_INIT RefPtr<E1000NetworkAdapter> E1000NetworkAdapter::try_to_initialize(PCI::Address address)
{
- PCI::enumerate([&](const PCI::Address& address, PCI::ID id) {
- if (address.is_null())
- return;
- if (id.vendor_id != (u16)PCIVendorID::Intel)
- return;
- if (!is_valid_device_id(id.device_id))
- return;
- u8 irq = PCI::get_interrupt_line(address);
- [[maybe_unused]] auto& unused = adopt_ref(*new E1000NetworkAdapter(address, irq)).leak_ref();
- });
+ auto id = PCI::get_id(address);
+ if (id.vendor_id != (u16)PCIVendorID::Intel)
+ return {};
+ if (!is_valid_device_id(id.device_id))
+ return {};
+ u8 irq = PCI::get_interrupt_line(address);
+ return adopt_ref_if_nonnull(new E1000NetworkAdapter(address, irq));
}
UNMAP_AFTER_INIT E1000NetworkAdapter::E1000NetworkAdapter(PCI::Address address, u8 irq)
diff --git a/Kernel/Net/E1000NetworkAdapter.h b/Kernel/Net/E1000NetworkAdapter.h
index e7fa10ad70..6458ae9d45 100644
--- a/Kernel/Net/E1000NetworkAdapter.h
+++ b/Kernel/Net/E1000NetworkAdapter.h
@@ -20,9 +20,8 @@ namespace Kernel {
class E1000NetworkAdapter final : public NetworkAdapter
, public PCI::Device {
public:
- static void detect();
+ static RefPtr<E1000NetworkAdapter> try_to_initialize(PCI::Address);
- E1000NetworkAdapter(PCI::Address, u8 irq);
virtual ~E1000NetworkAdapter() override;
virtual void send_raw(ReadonlyBytes) override;
@@ -31,6 +30,7 @@ public:
virtual const char* purpose() const override { return class_name(); }
private:
+ E1000NetworkAdapter(PCI::Address, u8 irq);
virtual void handle_irq(const RegisterState&) override;
virtual const char* class_name() const override { return "E1000NetworkAdapter"; }
diff --git a/Kernel/Net/IPv4Socket.cpp b/Kernel/Net/IPv4Socket.cpp
index 260c878e22..c1c1d5bb1d 100644
--- a/Kernel/Net/IPv4Socket.cpp
+++ b/Kernel/Net/IPv4Socket.cpp
@@ -13,6 +13,7 @@
#include <Kernel/Net/IPv4.h>
#include <Kernel/Net/IPv4Socket.h>
#include <Kernel/Net/NetworkAdapter.h>
+#include <Kernel/Net/NetworkingManagement.h>
#include <Kernel/Net/Routing.h>
#include <Kernel/Net/TCP.h>
#include <Kernel/Net/TCPSocket.h>
@@ -582,7 +583,7 @@ int IPv4Socket::ioctl(FileDescription&, unsigned request, FlatPtr arg)
if (copied_ifname.is_null())
return -EFAULT;
- auto adapter = NetworkAdapter::lookup_by_name(copied_ifname);
+ auto adapter = NetworkingManagement::the().lookup_by_name(copied_ifname);
if (!adapter)
return -ENODEV;
@@ -615,7 +616,7 @@ int IPv4Socket::ioctl(FileDescription&, unsigned request, FlatPtr arg)
memcpy(namebuf, ifr.ifr_name, IFNAMSIZ);
namebuf[sizeof(namebuf) - 1] = '\0';
- auto adapter = NetworkAdapter::lookup_by_name(namebuf);
+ auto adapter = NetworkingManagement::the().lookup_by_name(namebuf);
if (!adapter)
return -ENODEV;
diff --git a/Kernel/Net/LoopbackAdapter.cpp b/Kernel/Net/LoopbackAdapter.cpp
index 2fd4fb7a50..647c168550 100644
--- a/Kernel/Net/LoopbackAdapter.cpp
+++ b/Kernel/Net/LoopbackAdapter.cpp
@@ -9,15 +9,17 @@
namespace Kernel {
-static AK::Singleton<LoopbackAdapter> s_loopback;
+static bool s_loopback_initialized = false;
-LoopbackAdapter& LoopbackAdapter::the()
+NonnullRefPtr<LoopbackAdapter> LoopbackAdapter::create()
{
- return *s_loopback;
+ return adopt_ref(*new LoopbackAdapter());
}
LoopbackAdapter::LoopbackAdapter()
{
+ VERIFY(!s_loopback_initialized);
+ s_loopback_initialized = true;
set_loopback_name();
set_mtu(65536);
set_mac_address({ 19, 85, 2, 9, 0x55, 0xaa });
diff --git a/Kernel/Net/LoopbackAdapter.h b/Kernel/Net/LoopbackAdapter.h
index ab5c3906f1..b7949793db 100644
--- a/Kernel/Net/LoopbackAdapter.h
+++ b/Kernel/Net/LoopbackAdapter.h
@@ -12,10 +12,12 @@ namespace Kernel {
class LoopbackAdapter final : public NetworkAdapter {
AK_MAKE_ETERNAL
-public:
+
+private:
LoopbackAdapter();
- static LoopbackAdapter& the();
+public:
+ static NonnullRefPtr<LoopbackAdapter> create();
virtual ~LoopbackAdapter() override;
virtual void send_raw(ReadonlyBytes) override;
diff --git a/Kernel/Net/NE2000NetworkAdapter.cpp b/Kernel/Net/NE2000NetworkAdapter.cpp
index 31b962d961..9c542579e7 100644
--- a/Kernel/Net/NE2000NetworkAdapter.cpp
+++ b/Kernel/Net/NE2000NetworkAdapter.cpp
@@ -135,7 +135,7 @@ struct [[gnu::packed]] received_packet_header {
u16 length;
};
-UNMAP_AFTER_INIT void NE2000NetworkAdapter::detect()
+UNMAP_AFTER_INIT RefPtr<NE2000NetworkAdapter> NE2000NetworkAdapter::try_to_initialize(PCI::Address address)
{
constexpr auto ne2k_ids = Array {
PCI::ID { 0x10EC, 0x8029 }, // RealTek RTL-8029(AS)
@@ -152,14 +152,11 @@ UNMAP_AFTER_INIT void NE2000NetworkAdapter::detect()
PCI::ID { 0x12c3, 0x5598 }, // Holtek HT80229
PCI::ID { 0x8c4a, 0x1980 }, // Winbond W89C940 (misprogrammed)
};
- PCI::enumerate([&](const PCI::Address& address, PCI::ID id) {
- if (address.is_null())
- return;
- if (!ne2k_ids.span().contains_slow(id))
- return;
- u8 irq = PCI::get_interrupt_line(address);
- [[maybe_unused]] auto& unused = adopt_ref(*new NE2000NetworkAdapter(address, irq)).leak_ref();
- });
+ auto id = PCI::get_id(address);
+ if (!ne2k_ids.span().contains_slow(id))
+ return {};
+ u8 irq = PCI::get_interrupt_line(address);
+ return adopt_ref_if_nonnull(new NE2000NetworkAdapter(address, irq));
}
UNMAP_AFTER_INIT NE2000NetworkAdapter::NE2000NetworkAdapter(PCI::Address address, u8 irq)
diff --git a/Kernel/Net/NE2000NetworkAdapter.h b/Kernel/Net/NE2000NetworkAdapter.h
index e70ea93ba4..2bab3cc0ed 100644
--- a/Kernel/Net/NE2000NetworkAdapter.h
+++ b/Kernel/Net/NE2000NetworkAdapter.h
@@ -18,9 +18,8 @@ namespace Kernel {
class NE2000NetworkAdapter final : public NetworkAdapter
, public PCI::Device {
public:
- static void detect();
+ static RefPtr<NE2000NetworkAdapter> try_to_initialize(PCI::Address);
- NE2000NetworkAdapter(PCI::Address, u8 irq);
virtual ~NE2000NetworkAdapter() override;
virtual void send_raw(ReadonlyBytes) override;
@@ -29,6 +28,7 @@ public:
virtual const char* purpose() const override { return class_name(); }
private:
+ NE2000NetworkAdapter(PCI::Address, u8 irq);
virtual void handle_irq(const RegisterState&) override;
virtual const char* class_name() const override { return "NE2000NetworkAdapter"; }
diff --git a/Kernel/Net/NetworkAdapter.cpp b/Kernel/Net/NetworkAdapter.cpp
index c61fb5872d..c386b7362c 100644
--- a/Kernel/Net/NetworkAdapter.cpp
+++ b/Kernel/Net/NetworkAdapter.cpp
@@ -12,53 +12,19 @@
#include <Kernel/Net/EtherType.h>
#include <Kernel/Net/LoopbackAdapter.h>
#include <Kernel/Net/NetworkAdapter.h>
+#include <Kernel/Net/NetworkingManagement.h>
#include <Kernel/Process.h>
#include <Kernel/Random.h>
#include <Kernel/StdLib.h>
namespace Kernel {
-static AK::Singleton<Lockable<HashTable<NetworkAdapter*>>> s_table;
-
-Lockable<HashTable<NetworkAdapter*>>& NetworkAdapter::all_adapters()
-{
- return *s_table;
-}
-
-RefPtr<NetworkAdapter> NetworkAdapter::from_ipv4_address(const IPv4Address& address)
-{
- Locker locker(all_adapters().lock());
- for (auto* adapter : all_adapters().resource()) {
- if (adapter->ipv4_address() == address || adapter->ipv4_broadcast() == address)
- return adapter;
- }
- if (address[0] == 0 && address[1] == 0 && address[2] == 0 && address[3] == 0)
- return LoopbackAdapter::the();
- if (address[0] == 127)
- return LoopbackAdapter::the();
- return nullptr;
-}
-
-RefPtr<NetworkAdapter> NetworkAdapter::lookup_by_name(const StringView& name)
-{
- NetworkAdapter* found_adapter = nullptr;
- for_each([&](auto& adapter) {
- if (adapter.name() == name)
- found_adapter = &adapter;
- });
- return found_adapter;
-}
-
NetworkAdapter::NetworkAdapter()
{
- // FIXME: I wanna lock :(
- all_adapters().resource().set(this);
}
NetworkAdapter::~NetworkAdapter()
{
- // FIXME: I wanna lock :(
- all_adapters().resource().remove(this);
}
void NetworkAdapter::send_packet(ReadonlyBytes packet)
@@ -199,14 +165,14 @@ void NetworkAdapter::set_interface_name(const PCI::Address& pci_address)
{
// Note: This stands for e - "Ethernet", p - "Port" as for PCI bus, "s" for slot as for PCI slot
auto name = String::formatted("ep{}s{}", pci_address.bus(), pci_address.device());
- VERIFY(!lookup_by_name(name));
+ VERIFY(!NetworkingManagement::the().lookup_by_name(name));
m_name = move(name);
}
void NetworkAdapter::set_loopback_name()
{
auto name = String("loop");
- VERIFY(!lookup_by_name(name));
+ VERIFY(!NetworkingManagement::the().lookup_by_name(name));
m_name = move(name);
}
}
diff --git a/Kernel/Net/NetworkAdapter.h b/Kernel/Net/NetworkAdapter.h
index a454ee7592..4ddee225e6 100644
--- a/Kernel/Net/NetworkAdapter.h
+++ b/Kernel/Net/NetworkAdapter.h
@@ -42,16 +42,6 @@ struct PacketWithTimestamp : public RefCounted<PacketWithTimestamp> {
class NetworkAdapter : public RefCounted<NetworkAdapter>
, public Weakable<NetworkAdapter> {
public:
- template<typename Callback>
- static inline void for_each(Callback callback)
- {
- Locker locker(all_adapters().lock());
- for (auto& it : all_adapters().resource())
- callback(*it);
- }
-
- static RefPtr<NetworkAdapter> from_ipv4_address(const IPv4Address&);
- static RefPtr<NetworkAdapter> lookup_by_name(const StringView&);
virtual ~NetworkAdapter();
virtual const char* class_name() const = 0;
@@ -103,8 +93,6 @@ protected:
void set_loopback_name();
private:
- static Lockable<HashTable<NetworkAdapter*>>& all_adapters();
-
MACAddress m_mac_address;
IPv4Address m_ipv4_address;
IPv4Address m_ipv4_netmask;
diff --git a/Kernel/Net/NetworkTask.cpp b/Kernel/Net/NetworkTask.cpp
index 99c5f7bc2c..f65d846b4e 100644
--- a/Kernel/Net/NetworkTask.cpp
+++ b/Kernel/Net/NetworkTask.cpp
@@ -14,6 +14,7 @@
#include <Kernel/Net/IPv4Socket.h>
#include <Kernel/Net/LoopbackAdapter.h>
#include <Kernel/Net/NetworkTask.h>
+#include <Kernel/Net/NetworkingManagement.h>
#include <Kernel/Net/Routing.h>
#include <Kernel/Net/TCP.h>
#include <Kernel/Net/TCPSocket.h>
@@ -55,7 +56,7 @@ void NetworkTask_main(void*)
WaitQueue packet_wait_queue;
int pending_packets = 0;
- NetworkAdapter::for_each([&](auto& adapter) {
+ NetworkingManagement::the().for_each([&](auto& adapter) {
dmesgln("NetworkTask: {} network adapter found: hw={}", adapter.class_name(), adapter.mac_address().to_string());
if (String(adapter.class_name()) == "LoopbackAdapter") {
@@ -74,7 +75,7 @@ void NetworkTask_main(void*)
if (pending_packets == 0)
return 0;
size_t packet_size = 0;
- NetworkAdapter::for_each([&](auto& adapter) {
+ NetworkingManagement::the().for_each([&](auto& adapter) {
if (packet_size || !adapter.has_queued_packets())
return;
packet_size = adapter.dequeue_packet(buffer, buffer_size, packet_timestamp);
@@ -155,7 +156,7 @@ void handle_arp(const EthernetFrameHeader& eth, size_t frame_size)
if (packet.operation() == ARPOperation::Request) {
// Who has this IP address?
- if (auto adapter = NetworkAdapter::from_ipv4_address(packet.target_protocol_address())) {
+ if (auto adapter = NetworkingManagement::the().from_ipv4_address(packet.target_protocol_address())) {
// We do!
dbgln("handle_arp: Responding to ARP request for my IPv4 address ({})", adapter->ipv4_address());
ARPPacket response;
@@ -193,7 +194,7 @@ void handle_ipv4(const EthernetFrameHeader& eth, size_t frame_size, const Time&
dbgln_if(IPV4_DEBUG, "handle_ipv4: source={}, destination={}", packet.source(), packet.destination());
- NetworkAdapter::for_each([&](auto& adapter) {
+ NetworkingManagement::the().for_each([&](auto& adapter) {
if (adapter.link_up()) {
auto my_net = adapter.ipv4_address().to_u32() & adapter.ipv4_netmask().to_u32();
auto their_net = packet.source().to_u32() & adapter.ipv4_netmask().to_u32();
@@ -234,7 +235,7 @@ void handle_icmp(const EthernetFrameHeader& eth, const IPv4Packet& ipv4_packet,
socket.did_receive(ipv4_packet.source(), 0, { &ipv4_packet, sizeof(IPv4Packet) + ipv4_packet.payload_size() }, packet_timestamp);
}
- auto adapter = NetworkAdapter::from_ipv4_address(ipv4_packet.destination());
+ auto adapter = NetworkingManagement::the().from_ipv4_address(ipv4_packet.destination());
if (!adapter)
return;
@@ -292,7 +293,7 @@ void handle_udp(const IPv4Packet& ipv4_packet, const Time& packet_timestamp)
auto& destination = ipv4_packet.destination();
- if (destination == IPv4Address(255, 255, 255, 255) || NetworkAdapter::from_ipv4_address(destination) || socket->multicast_memberships().contains_slow(destination))
+ if (destination == IPv4Address(255, 255, 255, 255) || NetworkingManagement::the().from_ipv4_address(destination) || socket->multicast_memberships().contains_slow(destination))
socket->did_receive(ipv4_packet.source(), udp_packet.source_port(), { &ipv4_packet, sizeof(IPv4Packet) + ipv4_packet.payload_size() }, packet_timestamp);
}
@@ -365,7 +366,7 @@ void handle_tcp(const IPv4Packet& ipv4_packet, const Time& packet_timestamp)
tcp_packet.window_size(),
payload_size);
- auto adapter = NetworkAdapter::from_ipv4_address(ipv4_packet.destination());
+ auto adapter = NetworkingManagement::the().from_ipv4_address(ipv4_packet.destination());
if (!adapter) {
dbgln("handle_tcp: this packet is not for me, it's for {}", ipv4_packet.destination());
return;
diff --git a/Kernel/Net/NetworkingManagement.cpp b/Kernel/Net/NetworkingManagement.cpp
new file mode 100644
index 0000000000..c2bb229b14
--- /dev/null
+++ b/Kernel/Net/NetworkingManagement.cpp
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2021, Liav A. <liavalb@hotmail.co.il>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <AK/Checked.h>
+#include <AK/Singleton.h>
+#include <Kernel/CommandLine.h>
+#include <Kernel/Debug.h>
+#include <Kernel/IO.h>
+#include <Kernel/Multiboot.h>
+#include <Kernel/Net/E1000NetworkAdapter.h>
+#include <Kernel/Net/LoopbackAdapter.h>
+#include <Kernel/Net/NE2000NetworkAdapter.h>
+#include <Kernel/Net/NetworkingManagement.h>
+#include <Kernel/Net/RTL8139NetworkAdapter.h>
+#include <Kernel/Panic.h>
+#include <Kernel/VM/AnonymousVMObject.h>
+
+namespace Kernel {
+
+static AK::Singleton<NetworkingManagement> s_the;
+
+NetworkingManagement& NetworkingManagement::the()
+{
+ return *s_the;
+}
+
+bool NetworkingManagement::is_initialized()
+{
+ return s_the.is_initialized();
+}
+
+UNMAP_AFTER_INIT NetworkingManagement::NetworkingManagement()
+{
+}
+
+NonnullRefPtr<NetworkAdapter> NetworkingManagement::loopback_adapter() const
+{
+ return *m_loopback_adapter;
+}
+
+void NetworkingManagement::for_each(Function<void(NetworkAdapter&)> callback)
+{
+ Locker locker(m_lock);
+ for (auto& it : m_adapters)
+ callback(it);
+}
+
+RefPtr<NetworkAdapter> NetworkingManagement::from_ipv4_address(const IPv4Address& address) const
+{
+ Locker locker(m_lock);
+ for (auto& adapter : m_adapters) {
+ if (adapter.ipv4_address() == address || adapter.ipv4_broadcast() == address)
+ return adapter;
+ }
+ if (address[0] == 0 && address[1] == 0 && address[2] == 0 && address[3] == 0)
+ return m_loopback_adapter;
+ if (address[0] == 127)
+ return m_loopback_adapter;
+ return {};
+}
+RefPtr<NetworkAdapter> NetworkingManagement::lookup_by_name(const StringView& name) const
+{
+ Locker locker(m_lock);
+ RefPtr<NetworkAdapter> found_adapter;
+ for (auto& it : m_adapters) {
+ if (it.name() == name)
+ found_adapter = it;
+ }
+ return found_adapter;
+}
+
+UNMAP_AFTER_INIT RefPtr<NetworkAdapter> NetworkingManagement::determine_network_device(PCI::Address address) const
+{
+ if (auto candidate = E1000NetworkAdapter::try_to_initialize(address); !candidate.is_null())
+ return candidate;
+ if (auto candidate = RTL8139NetworkAdapter::try_to_initialize(address); !candidate.is_null())
+ return candidate;
+ if (auto candidate = NE2000NetworkAdapter::try_to_initialize(address); !candidate.is_null())
+ return candidate;
+ return {};
+}
+
+bool NetworkingManagement::initialize()
+{
+ PCI::enumerate([&](const PCI::Address& address, PCI::ID) {
+ // Note: PCI class 2 is the class of Network devices
+ if (PCI::get_class(address) != 0x02)
+ return;
+ if (auto adapter = determine_network_device(address); !adapter.is_null())
+ m_adapters.append(adapter.release_nonnull());
+ });
+ auto loopback = LoopbackAdapter::create();
+ m_adapters.append(loopback);
+ m_loopback_adapter = loopback;
+ return true;
+}
+
+}
diff --git a/Kernel/Net/NetworkingManagement.h b/Kernel/Net/NetworkingManagement.h
new file mode 100644
index 0000000000..f8be65a6c8
--- /dev/null
+++ b/Kernel/Net/NetworkingManagement.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2021, Liav A. <liavalb@hotmail.co.il>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <AK/Function.h>
+#include <AK/NonnullOwnPtr.h>
+#include <AK/NonnullRefPtr.h>
+#include <AK/NonnullRefPtrVector.h>
+#include <AK/Types.h>
+#include <Kernel/PCI/Definitions.h>
+#include <Kernel/VM/Region.h>
+
+namespace Kernel {
+
+class NetworkAdapter;
+class NetworkingManagement {
+ friend class NetworkAdapter;
+ AK_MAKE_ETERNAL
+
+public:
+ static NetworkingManagement& the();
+ static bool is_initialized();
+ bool initialize();
+
+ NetworkingManagement();
+
+ void for_each(Function<void(NetworkAdapter&)>);
+
+ RefPtr<NetworkAdapter> from_ipv4_address(const IPv4Address&) const;
+ RefPtr<NetworkAdapter> lookup_by_name(const StringView&) const;
+
+ NonnullRefPtr<NetworkAdapter> loopback_adapter() const;
+
+private:
+ RefPtr<NetworkAdapter> determine_network_device(PCI::Address address) const;
+
+ NonnullRefPtrVector<NetworkAdapter> m_adapters;
+ RefPtr<NetworkAdapter> m_loopback_adapter;
+ mutable Lock m_lock { "Networking" };
+};
+
+}
diff --git a/Kernel/Net/RTL8139NetworkAdapter.cpp b/Kernel/Net/RTL8139NetworkAdapter.cpp
index 4ff9431856..e78bd93180 100644
--- a/Kernel/Net/RTL8139NetworkAdapter.cpp
+++ b/Kernel/Net/RTL8139NetworkAdapter.cpp
@@ -105,17 +105,14 @@ namespace Kernel {
#define RX_BUFFER_SIZE 32768
#define TX_BUFFER_SIZE PACKET_SIZE_MAX
-UNMAP_AFTER_INIT void RTL8139NetworkAdapter::detect()
+UNMAP_AFTER_INIT RefPtr<RTL8139NetworkAdapter> RTL8139NetworkAdapter::try_to_initialize(PCI::Address address)
{
constexpr PCI::ID rtl8139_id = { 0x10EC, 0x8139 };
- PCI::enumerate([&](const PCI::Address& address, PCI::ID id) {
- if (address.is_null())
- return;
- if (id != rtl8139_id)
- return;
- u8 irq = PCI::get_interrupt_line(address);
- [[maybe_unused]] auto& unused = adopt_ref(*new RTL8139NetworkAdapter(address, irq)).leak_ref();
- });
+ auto id = PCI::get_id(address);
+ if (id != rtl8139_id)
+ return {};
+ u8 irq = PCI::get_interrupt_line(address);
+ return adopt_ref_if_nonnull(new RTL8139NetworkAdapter(address, irq));
}
UNMAP_AFTER_INIT RTL8139NetworkAdapter::RTL8139NetworkAdapter(PCI::Address address, u8 irq)
diff --git a/Kernel/Net/RTL8139NetworkAdapter.h b/Kernel/Net/RTL8139NetworkAdapter.h
index 9d1ebe2f1a..b04ec65d1f 100644
--- a/Kernel/Net/RTL8139NetworkAdapter.h
+++ b/Kernel/Net/RTL8139NetworkAdapter.h
@@ -20,9 +20,8 @@ namespace Kernel {
class RTL8139NetworkAdapter final : public NetworkAdapter
, public PCI::Device {
public:
- static void detect();
+ static RefPtr<RTL8139NetworkAdapter> try_to_initialize(PCI::Address);
- RTL8139NetworkAdapter(PCI::Address, u8 irq);
virtual ~RTL8139NetworkAdapter() override;
virtual void send_raw(ReadonlyBytes) override;
@@ -31,6 +30,7 @@ public:
virtual const char* purpose() const override { return class_name(); }
private:
+ RTL8139NetworkAdapter(PCI::Address, u8 irq);
virtual void handle_irq(const RegisterState&) override;
virtual const char* class_name() const override { return "RTL8139NetworkAdapter"; }
diff --git a/Kernel/Net/Routing.cpp b/Kernel/Net/Routing.cpp
index 41f7e94587..90d7d268fe 100644
--- a/Kernel/Net/Routing.cpp
+++ b/Kernel/Net/Routing.cpp
@@ -9,6 +9,7 @@
#include <Kernel/Debug.h>
#include <Kernel/Net/LoopbackAdapter.h>
#include <Kernel/Net/NetworkTask.h>
+#include <Kernel/Net/NetworkingManagement.h>
#include <Kernel/Net/Routing.h>
#include <Kernel/Thread.h>
@@ -142,9 +143,9 @@ RoutingDecision route_to(const IPv4Address& target, const IPv4Address& source, c
};
if (target[0] == 0 && target[1] == 0 && target[2] == 0 && target[3] == 0)
- return if_matches(LoopbackAdapter::the(), LoopbackAdapter::the().mac_address());
+ return if_matches(*NetworkingManagement::the().loopback_adapter(), NetworkingManagement::the().loopback_adapter()->mac_address());
if (target[0] == 127)
- return if_matches(LoopbackAdapter::the(), LoopbackAdapter::the().mac_address());
+ return if_matches(*NetworkingManagement::the().loopback_adapter(), NetworkingManagement::the().loopback_adapter()->mac_address());
auto target_addr = target.to_u32();
auto source_addr = source.to_u32();
@@ -152,12 +153,12 @@ RoutingDecision route_to(const IPv4Address& target, const IPv4Address& source, c
RefPtr<NetworkAdapter> local_adapter = nullptr;
RefPtr<NetworkAdapter> gateway_adapter = nullptr;
- NetworkAdapter::for_each([source_addr, &target_addr, &local_adapter, &gateway_adapter, &matches, &through](auto& adapter) {
+ NetworkingManagement::the().for_each([source_addr, &target_addr, &local_adapter, &gateway_adapter, &matches, &through](NetworkAdapter& adapter) {
auto adapter_addr = adapter.ipv4_address().to_u32();
auto adapter_mask = adapter.ipv4_netmask().to_u32();
if (target_addr == adapter_addr) {
- local_adapter = LoopbackAdapter::the();
+ local_adapter = NetworkingManagement::the().loopback_adapter();
return;
}
@@ -213,7 +214,7 @@ RoutingDecision route_to(const IPv4Address& target, const IPv4Address& source, c
if (target_addr == 0xffffffff && matches(adapter))
return { adapter, { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } };
- if (adapter == LoopbackAdapter::the())
+ if (adapter == NetworkingManagement::the().loopback_adapter())
return { adapter, adapter->mac_address() };
if ((target_addr & IPv4Address { 240, 0, 0, 0 }.to_u32()) == IPv4Address { 224, 0, 0, 0 }.to_u32())
diff --git a/Kernel/Net/Socket.cpp b/Kernel/Net/Socket.cpp
index 2ff8c6ce69..1484ff260f 100644
--- a/Kernel/Net/Socket.cpp
+++ b/Kernel/Net/Socket.cpp
@@ -10,6 +10,7 @@
#include <Kernel/FileSystem/FileDescription.h>
#include <Kernel/Net/IPv4Socket.h>
#include <Kernel/Net/LocalSocket.h>
+#include <Kernel/Net/NetworkingManagement.h>
#include <Kernel/Net/Socket.h>
#include <Kernel/Process.h>
#include <Kernel/UnixTypes.h>
@@ -111,7 +112,7 @@ KResult Socket::setsockopt(int level, int option, Userspace<const void*> user_va
auto ifname = copy_string_from_user(user_string, user_value_size);
if (ifname.is_null())
return EFAULT;
- auto device = NetworkAdapter::lookup_by_name(ifname);
+ auto device = NetworkingManagement::the().lookup_by_name(ifname);
if (!device)
return ENODEV;
m_bound_interface = device;
diff --git a/Kernel/Net/TCPSocket.cpp b/Kernel/Net/TCPSocket.cpp
index bb42064366..0fdb838355 100644
--- a/Kernel/Net/TCPSocket.cpp
+++ b/Kernel/Net/TCPSocket.cpp
@@ -12,6 +12,7 @@
#include <Kernel/Net/EthernetFrameHeader.h>
#include <Kernel/Net/IPv4.h>
#include <Kernel/Net/NetworkAdapter.h>
+#include <Kernel/Net/NetworkingManagement.h>
#include <Kernel/Net/Routing.h>
#include <Kernel/Net/TCP.h>
#include <Kernel/Net/TCPSocket.h>
@@ -357,7 +358,7 @@ NetworkOrdered<u16> TCPSocket::compute_tcp_checksum(const IPv4Address& source, c
KResult TCPSocket::protocol_bind()
{
if (has_specific_local_address() && !m_adapter) {
- m_adapter = NetworkAdapter::from_ipv4_address(local_address());
+ m_adapter = NetworkingManagement::the().from_ipv4_address(local_address());
if (!m_adapter)
return EADDRNOTAVAIL;
}
diff --git a/Kernel/init.cpp b/Kernel/init.cpp
index df56ae26e7..3711ec7ed6 100644
--- a/Kernel/init.cpp
+++ b/Kernel/init.cpp
@@ -33,11 +33,8 @@
#include <Kernel/Interrupts/PIC.h>
#include <Kernel/KSyms.h>
#include <Kernel/Multiboot.h>
-#include <Kernel/Net/E1000NetworkAdapter.h>
-#include <Kernel/Net/LoopbackAdapter.h>
-#include <Kernel/Net/NE2000NetworkAdapter.h>
#include <Kernel/Net/NetworkTask.h>
-#include <Kernel/Net/RTL8139NetworkAdapter.h>
+#include <Kernel/Net/NetworkingManagement.h>
#include <Kernel/PCI/Access.h>
#include <Kernel/PCI/Initializer.h>
#include <Kernel/Panic.h>
@@ -243,12 +240,7 @@ void init_stage2(void*)
VirtIO::detect();
- E1000NetworkAdapter::detect();
- NE2000NetworkAdapter::detect();
- RTL8139NetworkAdapter::detect();
-
- LoopbackAdapter::the();
-
+ NetworkingManagement::the().initialize();
Syscall::initialize();
new MemoryDevice;