/* * Copyright (c) 2021, Liav A. * * SPDX-License-Identifier: BSD-2-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace Kernel { static Singleton s_the; NetworkingManagement& NetworkingManagement::the() { return *s_the; } bool NetworkingManagement::is_initialized() { return s_the.is_initialized(); } UNMAP_AFTER_INIT NetworkingManagement::NetworkingManagement() { } NonnullLockRefPtr NetworkingManagement::loopback_adapter() const { return *m_loopback_adapter; } void NetworkingManagement::for_each(Function callback) { m_adapters.for_each([&](auto& adapter) { callback(adapter); }); } ErrorOr NetworkingManagement::try_for_each(Function(NetworkAdapter&)> callback) { return m_adapters.with([&](auto& adapters) -> ErrorOr { for (auto& adapter : adapters) TRY(callback(adapter)); return {}; }); } LockRefPtr NetworkingManagement::from_ipv4_address(IPv4Address const& address) const { 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 m_adapters.with([&](auto& adapters) -> LockRefPtr { for (auto& adapter : adapters) { if (adapter.ipv4_address() == address || adapter.ipv4_broadcast() == address) return adapter; } return nullptr; }); } LockRefPtr NetworkingManagement::lookup_by_name(StringView name) const { return m_adapters.with([&](auto& adapters) -> LockRefPtr { for (auto& adapter : adapters) { if (adapter.name() == name) return adapter; } return nullptr; }); } ErrorOr> NetworkingManagement::generate_interface_name_from_pci_address(PCI::DeviceIdentifier const& device_identifier) { VERIFY(device_identifier.class_code().value() == 0x2); // Note: This stands for e - "Ethernet", p - "Port" as for PCI bus, "s" for slot as for PCI slot auto name = TRY(KString::formatted("ep{}s{}", device_identifier.address().bus(), device_identifier.address().device())); VERIFY(!NetworkingManagement::the().lookup_by_name(name->view())); return name; } UNMAP_AFTER_INIT LockRefPtr NetworkingManagement::determine_network_device(PCI::DeviceIdentifier const& device_identifier) const { if (auto candidate = E1000NetworkAdapter::try_to_initialize(device_identifier); !candidate.is_null()) return candidate; if (auto candidate = E1000ENetworkAdapter::try_to_initialize(device_identifier); !candidate.is_null()) return candidate; if (auto candidate = RTL8139NetworkAdapter::try_to_initialize(device_identifier); !candidate.is_null()) return candidate; if (auto candidate = RTL8168NetworkAdapter::try_to_initialize(device_identifier); !candidate.is_null()) return candidate; if (auto candidate = NE2000NetworkAdapter::try_to_initialize(device_identifier); !candidate.is_null()) return candidate; return {}; } bool NetworkingManagement::initialize() { if (!kernel_command_line().is_physical_networking_disabled() && !PCI::Access::is_disabled()) { MUST(PCI::enumerate([&](PCI::DeviceIdentifier const& device_identifier) { // Note: PCI class 2 is the class of Network devices if (device_identifier.class_code().value() != 0x02) return; if (auto adapter = determine_network_device(device_identifier); !adapter.is_null()) m_adapters.with([&](auto& adapters) { adapters.append(adapter.release_nonnull()); }); })); } auto loopback = LoopbackAdapter::try_create(); VERIFY(loopback); m_adapters.with([&](auto& adapters) { adapters.append(*loopback); }); m_loopback_adapter = loopback; return true; } }