summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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;