mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-13 11:42:38 +03:00
75ed262fe5
This defaults to 1500 for all adapters, but LoopbackAdapter increases it to 65536 on construction. If an IPv4 packet is larger than the MTU, we'll need to break it into smaller fragments before transmitting it. This part is a FIXME. :^)
142 lines
4.2 KiB
C++
142 lines
4.2 KiB
C++
#include <AK/HashTable.h>
|
|
#include <AK/StringBuilder.h>
|
|
#include <Kernel/Lock.h>
|
|
#include <Kernel/Net/EtherType.h>
|
|
#include <Kernel/Net/EthernetFrameHeader.h>
|
|
#include <Kernel/Net/NetworkAdapter.h>
|
|
#include <Kernel/StdLib.h>
|
|
#include <Kernel/Heap/kmalloc.h>
|
|
|
|
static Lockable<HashTable<NetworkAdapter*>>& all_adapters()
|
|
{
|
|
static Lockable<HashTable<NetworkAdapter*>>* table;
|
|
if (!table)
|
|
table = new Lockable<HashTable<NetworkAdapter*>>;
|
|
return *table;
|
|
}
|
|
|
|
void NetworkAdapter::for_each(Function<void(NetworkAdapter&)> callback)
|
|
{
|
|
LOCKER(all_adapters().lock());
|
|
for (auto& it : all_adapters().resource())
|
|
callback(*it);
|
|
}
|
|
|
|
WeakPtr<NetworkAdapter> NetworkAdapter::from_ipv4_address(const IPv4Address& address)
|
|
{
|
|
LOCKER(all_adapters().lock());
|
|
for (auto* adapter : all_adapters().resource()) {
|
|
if (adapter->ipv4_address() == address)
|
|
return adapter->make_weak_ptr();
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
WeakPtr<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 ? found_adapter->make_weak_ptr() : nullptr;
|
|
}
|
|
|
|
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(const MACAddress& destination, const ARPPacket& packet)
|
|
{
|
|
int size_in_bytes = sizeof(EthernetFrameHeader) + sizeof(ARPPacket);
|
|
auto buffer = ByteBuffer::create_zeroed(size_in_bytes);
|
|
auto* eth = (EthernetFrameHeader*)buffer.data();
|
|
eth->set_source(mac_address());
|
|
eth->set_destination(destination);
|
|
eth->set_ether_type(EtherType::ARP);
|
|
m_packets_out++;
|
|
m_bytes_out += size_in_bytes;
|
|
memcpy(eth->payload(), &packet, sizeof(ARPPacket));
|
|
send_raw((const u8*)eth, size_in_bytes);
|
|
}
|
|
|
|
void NetworkAdapter::send_ipv4(const MACAddress& destination_mac, const IPv4Address& destination_ipv4, IPv4Protocol protocol, const u8* payload, size_t payload_size, u8 ttl)
|
|
{
|
|
size_t ipv4_packet_size = sizeof(IPv4Packet) + payload_size;
|
|
if (ipv4_packet_size > mtu()) {
|
|
// FIXME: Implement IP fragmentation.
|
|
ASSERT_NOT_REACHED();
|
|
}
|
|
|
|
size_t ethernet_frame_size = sizeof(EthernetFrameHeader) + sizeof(IPv4Packet) + payload_size;
|
|
auto buffer = ByteBuffer::create_zeroed(ethernet_frame_size);
|
|
auto& eth = *(EthernetFrameHeader*)buffer.data();
|
|
eth.set_source(mac_address());
|
|
eth.set_destination(destination_mac);
|
|
eth.set_ether_type(EtherType::IPv4);
|
|
auto& ipv4 = *(IPv4Packet*)eth.payload();
|
|
ipv4.set_version(4);
|
|
ipv4.set_internet_header_length(5);
|
|
ipv4.set_source(ipv4_address());
|
|
ipv4.set_destination(destination_ipv4);
|
|
ipv4.set_protocol((u8)protocol);
|
|
ipv4.set_length(sizeof(IPv4Packet) + payload_size);
|
|
ipv4.set_ident(1);
|
|
ipv4.set_ttl(ttl);
|
|
ipv4.set_checksum(ipv4.compute_checksum());
|
|
m_packets_out++;
|
|
m_bytes_out += ethernet_frame_size;
|
|
memcpy(ipv4.payload(), payload, payload_size);
|
|
send_raw((const u8*)ð, ethernet_frame_size);
|
|
}
|
|
|
|
void NetworkAdapter::did_receive(const u8* data, int length)
|
|
{
|
|
InterruptDisabler disabler;
|
|
m_packets_in++;
|
|
m_bytes_in += length;
|
|
m_packet_queue.append(KBuffer::copy(data, length));
|
|
if (on_receive)
|
|
on_receive();
|
|
}
|
|
|
|
Optional<KBuffer> NetworkAdapter::dequeue_packet()
|
|
{
|
|
InterruptDisabler disabler;
|
|
if (m_packet_queue.is_empty())
|
|
return {};
|
|
return m_packet_queue.take_first();
|
|
}
|
|
|
|
void NetworkAdapter::set_ipv4_address(const IPv4Address& address)
|
|
{
|
|
m_ipv4_address = address;
|
|
}
|
|
|
|
void NetworkAdapter::set_ipv4_netmask(const IPv4Address& netmask)
|
|
{
|
|
m_ipv4_netmask = netmask;
|
|
}
|
|
|
|
void NetworkAdapter::set_ipv4_gateway(const IPv4Address& gateway)
|
|
{
|
|
m_ipv4_gateway = gateway;
|
|
}
|
|
|
|
void NetworkAdapter::set_interface_name(const StringView& basename)
|
|
{
|
|
// FIXME: Find a unique name for this interface, starting with $basename.
|
|
StringBuilder builder;
|
|
builder.append(basename);
|
|
builder.append('0');
|
|
m_name = builder.to_string();
|
|
}
|