Compare commits

...

20 Commits

Author SHA1 Message Date
Bananymous 2138eeb87f Userspace: Implement super simple DHCP client 2024-02-03 02:41:06 +02:00
Bananymous 102aa50a41 BuildSystem: Use E1000E network controller in qemu 2024-02-03 02:40:15 +02:00
Bananymous 5cfe249945 Kernel: Cleanup network code and implement basic ARP request 2024-02-03 02:39:26 +02:00
Bananymous a0138955cd Kernel: Implement barebones arp table 2024-02-03 01:50:10 +02:00
Bananymous e1ffbb710b Kernel/LibC: Implement basic ioctl for network addresses 2024-02-03 01:50:10 +02:00
Bananymous c18f72ceb9 BAN: Add more APIs for IPv4 address 2024-02-03 01:50:10 +02:00
Bananymous bc1441a5eb LibC: add stropts.h 2024-02-02 14:29:20 +02:00
Bananymous 0f154c3173 Kernel: Implement basic recvfrom 2024-02-02 13:50:00 +02:00
Bananymous 7b287a1d5b BAN: Add types for IPv4 and MAC addresses 2024-02-02 13:48:07 +02:00
Bananymous 4b332b5d42 Kernel: Cleanup PCI code 2024-02-02 03:16:37 +02:00
Bananymous ec2f21bb9f Kernel/LibC: Implement SYS_SENDTO 2024-02-02 03:16:01 +02:00
Bananymous acd6c86f98 BAN: Add NetworkEndian to Endianness 2024-02-02 03:13:14 +02:00
Bananymous ab150b458a Kernel/LibC: Implement basic socket binding 2024-02-02 01:31:58 +02:00
Bananymous cf28ecd5a6 Kernel/LibC: Add SYS_SOCKET 2024-02-01 23:39:09 +02:00
Bananymous 99eed9c37a Kernel: Start work on network stack 2024-02-01 23:38:06 +02:00
Bananymous f4e86028d0 Kernel: Write simple working E1000 and E1000E drivers 2024-02-01 22:08:59 +02:00
Bananymous 7cb71ec6fb test-sort: Test more algorithms and cleanup output format 2024-02-01 15:22:28 +02:00
Bananymous d054e5b4b7 BAN: Implement basic radix sort for unsigned integers 2024-02-01 15:22:28 +02:00
Bananymous c69efc040c Kernel: Scheduler now uses the new LinkedList API for moving threads
Scheduler doesn't have to depend on the fact that allocations should
work when same amount of memory is just deallocated
2024-02-01 15:22:28 +02:00
Bananymous c4bf1641bd BAN: Add cool API for LinkedList
You can now move elements between LinkedLists without allocations or
deallocations. Same node moves from source to destination
2024-02-01 14:19:02 +02:00
50 changed files with 2753 additions and 576 deletions

View File

@ -58,6 +58,11 @@ namespace BAN
template<integral T>
struct LittleEndian
{
constexpr LittleEndian(T value)
{
raw = host_to_little_endian(value);
}
constexpr operator T() const
{
return host_to_little_endian(raw);
@ -69,6 +74,11 @@ namespace BAN
template<integral T>
struct BigEndian
{
constexpr BigEndian(T value)
{
raw = host_to_big_endian(value);
}
constexpr operator T() const
{
return host_to_big_endian(raw);
@ -77,4 +87,7 @@ namespace BAN
T raw;
};
template<integral T>
using NetworkEndian = BigEndian<T>;
}

73
BAN/include/BAN/IPv4.h Normal file
View File

@ -0,0 +1,73 @@
#pragma once
#include <BAN/Formatter.h>
#include <BAN/Hash.h>
namespace BAN
{
struct IPv4Address
{
constexpr IPv4Address(uint32_t u32_address)
{
address[0] = u32_address >> 24;
address[1] = u32_address >> 16;
address[2] = u32_address >> 8;
address[3] = u32_address >> 0;
}
constexpr uint32_t as_u32() const
{
return
((uint32_t)address[0] << 24) |
((uint32_t)address[1] << 16) |
((uint32_t)address[2] << 8) |
((uint32_t)address[3] << 0);
}
constexpr bool operator==(const IPv4Address& other) const
{
return
address[0] == other.address[0] &&
address[1] == other.address[1] &&
address[2] == other.address[2] &&
address[3] == other.address[3];
}
uint8_t address[4];
};
static_assert(sizeof(IPv4Address) == 4);
template<>
struct hash<IPv4Address>
{
constexpr hash_t operator()(IPv4Address ipv4) const
{
return hash<uint32_t>()(ipv4.as_u32());
}
};
}
namespace BAN::Formatter
{
template<typename F>
void print_argument(F putc, const IPv4Address& ipv4, const ValueFormat&)
{
ValueFormat format {
.base = 10,
.percision = 0,
.fill = 0,
.upper = false,
};
print_argument(putc, ipv4.address[0], format);
for (size_t i = 1; i < 4; i++)
{
putc('.');
print_argument(putc, ipv4.address[i], format);
}
}
}

View File

@ -42,6 +42,8 @@ namespace BAN
iterator remove(iterator);
void clear();
iterator move_element_to_other_linked_list(LinkedList& dest_list, iterator dest_iter, iterator src_iter);
iterator begin() { return iterator(m_data, empty()); }
const_iterator begin() const { return const_iterator(m_data, empty()); }
iterator end() { return iterator(m_last, true); }
@ -65,7 +67,11 @@ namespace BAN
Node* prev;
};
ErrorOr<Node*> allocate_node() const;
template<typename... Args>
ErrorOr<Node*> allocate_node(Args&&...) const;
Node* remove_node(iterator);
void insert_node(iterator, Node*);
Node* m_data = nullptr;
Node* m_last = nullptr;
@ -137,6 +143,31 @@ namespace BAN
return *this;
}
template<typename T>
LinkedList<T>::Node* LinkedList<T>::remove_node(iterator iter)
{
ASSERT(!empty() && iter);
Node* node = iter.m_current;
Node* prev = node->prev;
Node* next = node->next;
(prev ? prev->next : m_data) = next;
(next ? next->prev : m_last) = prev;
m_size--;
return node;
}
template<typename T>
void LinkedList<T>::insert_node(iterator iter, Node* node)
{
Node* next = iter.m_past_end ? nullptr : iter.m_current;
Node* prev = next ? next->prev : m_last;
node->next = next;
node->prev = prev;
(prev ? prev->next : m_data) = node;
(next ? next->prev : m_last) = node;
m_size++;
}
template<typename T>
ErrorOr<void> LinkedList<T>::push_back(const T& value)
{
@ -158,15 +189,8 @@ namespace BAN
template<typename T>
ErrorOr<void> LinkedList<T>::insert(iterator iter, T&& value)
{
Node* next = iter.m_past_end ? nullptr : iter.m_current;
Node* prev = next ? next->prev : m_last;
Node* new_node = TRY(allocate_node());
new (&new_node->value) T(move(value));
new_node->next = next;
new_node->prev = prev;
(prev ? prev->next : m_data) = new_node;
(next ? next->prev : m_last) = new_node;
m_size++;
Node* new_node = TRY(allocate_node(move(value)));
insert_node(iter, new_node);
return {};
}
@ -181,21 +205,15 @@ namespace BAN
template<typename... Args>
ErrorOr<void> LinkedList<T>::emplace(iterator iter, Args&&... args)
{
Node* next = iter.m_past_end ? nullptr : iter.m_current;
Node* prev = next ? next->prev : m_last;
Node* new_node = TRY(allocate_node());
new (&new_node->value) T(forward<Args>(args)...);
new_node->next = next;
new_node->prev = prev;
(prev ? prev->next : m_data) = new_node;
(next ? next->prev : m_last) = new_node;
m_size++;
Node* new_node = TRY(allocate_node(forward<Args>(args)...));
insert_node(iter, new_node);
return {};
}
template<typename T>
void LinkedList<T>::pop_back()
{
ASSERT(!empty());
remove(iterator(m_last, false));
}
@ -203,14 +221,10 @@ namespace BAN
LinkedList<T>::iterator LinkedList<T>::remove(iterator iter)
{
ASSERT(!empty() && iter);
Node* node = iter.m_current;
Node* prev = node->prev;
Node* node = remove_node(iter);
Node* next = node->next;
node->value.~T();
BAN::deallocator(node);
(prev ? prev->next : m_data) = next;
(next ? next->prev : m_last) = prev;
m_size--;
return next ? iterator(next, false) : iterator(m_last, true);
}
@ -230,6 +244,16 @@ namespace BAN
m_size = 0;
}
template<typename T>
LinkedList<T>::iterator LinkedList<T>::move_element_to_other_linked_list(LinkedList& dest_list, iterator dest_iter, iterator src_iter)
{
ASSERT(!empty() && src_iter);
Node* node = remove_node(src_iter);
iterator ret = node->next ? iterator(node->next, false) : iterator(m_last, true);
dest_list.insert_node(dest_iter, node);
return ret;
}
template<typename T>
const T& LinkedList<T>::back() const
{
@ -284,11 +308,13 @@ namespace BAN
}
template<typename T>
ErrorOr<typename LinkedList<T>::Node*> LinkedList<T>::allocate_node() const
template<typename... Args>
ErrorOr<typename LinkedList<T>::Node*> LinkedList<T>::allocate_node(Args&&... args) const
{
Node* node = (Node*)BAN::allocator(sizeof(Node));
if (node == nullptr)
return Error::from_errno(ENOMEM);
new (&node->value) T(forward<Args>(args)...);
return node;
}

36
BAN/include/BAN/MAC.h Normal file
View File

@ -0,0 +1,36 @@
#pragma once
#include <BAN/Formatter.h>
namespace BAN
{
struct MACAddress
{
uint8_t address[6];
};
}
namespace BAN::Formatter
{
template<typename F>
void print_argument(F putc, const MACAddress& mac, const ValueFormat&)
{
ValueFormat format {
.base = 16,
.percision = 0,
.fill = 2,
.upper = true,
};
print_argument(putc, mac.address[0], format);
for (size_t i = 1; i < 6; i++)
{
putc(':');
print_argument(putc, mac.address[i], format);
}
}
}

View File

@ -1,8 +1,9 @@
#pragma once
#include <BAN/Math.h>
#include <BAN/Swap.h>
#include <BAN/Traits.h>
#include <BAN/Math.h>
#include <BAN/Vector.h>
namespace BAN::sort
{
@ -175,6 +176,61 @@ namespace BAN::sort
detail::intro_sort_impl(begin, end, 2 * Math::ilog2(len), comp);
}
namespace detail
{
template<unsigned_integral T>
consteval T lsb_index(T value)
{
for (T result = 0;; result++)
if (value & (1 << result))
return result;
}
}
template<typename It, size_t radix = 256>
requires is_unsigned_v<typename It::value_type> && (radix > 0 && (radix & (radix - 1)) == 0)
BAN::ErrorOr<void> radix_sort(It begin, It end)
{
using value_type = typename It::value_type;
const size_t len = distance(begin, end);
if (len <= 1)
return {};
Vector<value_type> temp;
TRY(temp.resize(len));
Vector<size_t> counts;
TRY(counts.resize(radix));
constexpr size_t mask = radix - 1;
constexpr size_t shift = detail::lsb_index(radix);
for (size_t s = 0; s < sizeof(value_type) * 8; s += shift)
{
for (auto& cnt : counts)
cnt = 0;
for (It it = begin; it != end; ++it)
counts[(*it >> s) & mask]++;
for (size_t i = 0; i < radix - 1; i++)
counts[i + 1] += counts[i];
for (It it = end; it != begin;)
{
--it;
temp[--counts[(*it >> s) & mask]] = *it;
}
for (size_t j = 0; j < temp.size(); j++)
*next(begin, j) = temp[j];
}
return {};
}
template<typename It, typename Comp = less<typename It::value_type>>
void sort(It begin, It end, Comp comp = {})
{

View File

@ -49,7 +49,14 @@ set(KERNEL_SOURCES
kernel/Memory/MemoryRegion.cpp
kernel/Memory/PhysicalRange.cpp
kernel/Memory/VirtualRange.cpp
kernel/Networking/E1000.cpp
kernel/Networking/ARPTable.cpp
kernel/Networking/E1000/E1000.cpp
kernel/Networking/E1000/E1000E.cpp
kernel/Networking/IPv4.cpp
kernel/Networking/NetworkInterface.cpp
kernel/Networking/NetworkManager.cpp
kernel/Networking/NetworkSocket.cpp
kernel/Networking/UDPSocket.cpp
kernel/OpenFileDescriptorSet.cpp
kernel/Panic.cpp
kernel/PCI.cpp

View File

@ -11,6 +11,7 @@
#include <kernel/Credentials.h>
#include <kernel/SpinLock.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <time.h>
@ -86,6 +87,8 @@ namespace Kernel
virtual bool is_pipe() const { return false; }
virtual bool is_tty() const { return false; }
void on_close();
// Directory API
BAN::ErrorOr<BAN::RefPtr<Inode>> find_inode(BAN::StringView);
BAN::ErrorOr<void> list_next_inodes(off_t, DirectoryEntryList*, size_t);
@ -96,6 +99,11 @@ namespace Kernel
// Link API
BAN::ErrorOr<BAN::String> link_target();
// Socket API
BAN::ErrorOr<void> bind(const sockaddr* address, socklen_t address_len);
BAN::ErrorOr<ssize_t> sendto(const sys_sendto_t*);
BAN::ErrorOr<ssize_t> recvfrom(sys_recvfrom_t*);
// General API
BAN::ErrorOr<size_t> read(off_t, BAN::ByteSpan buffer);
BAN::ErrorOr<size_t> write(off_t, BAN::ConstByteSpan buffer);
@ -104,7 +112,11 @@ namespace Kernel
BAN::ErrorOr<void> chown(uid_t, gid_t);
bool has_data() const;
BAN::ErrorOr<long> ioctl(int request, void* arg);
protected:
virtual void on_close_impl() {}
// Directory API
virtual BAN::ErrorOr<BAN::RefPtr<Inode>> find_inode_impl(BAN::StringView) { return BAN::Error::from_errno(ENOTSUP); }
virtual BAN::ErrorOr<void> list_next_inodes_impl(off_t, DirectoryEntryList*, size_t) { return BAN::Error::from_errno(ENOTSUP); }
@ -115,6 +127,11 @@ namespace Kernel
// Link API
virtual BAN::ErrorOr<BAN::String> link_target_impl() { return BAN::Error::from_errno(ENOTSUP); }
// Socket API
virtual BAN::ErrorOr<void> bind_impl(const sockaddr*, socklen_t) { return BAN::Error::from_errno(ENOTSUP); }
virtual BAN::ErrorOr<ssize_t> sendto_impl(const sys_sendto_t*) { return BAN::Error::from_errno(ENOTSUP); }
virtual BAN::ErrorOr<ssize_t> recvfrom_impl(sys_recvfrom_t*) { return BAN::Error::from_errno(ENOTSUP); }
// General API
virtual BAN::ErrorOr<size_t> read_impl(off_t, BAN::ByteSpan) { return BAN::Error::from_errno(ENOTSUP); }
virtual BAN::ErrorOr<size_t> write_impl(off_t, BAN::ConstByteSpan) { return BAN::Error::from_errno(ENOTSUP); }
@ -123,6 +140,8 @@ namespace Kernel
virtual BAN::ErrorOr<void> chown_impl(uid_t, gid_t) { return BAN::Error::from_errno(ENOTSUP); }
virtual bool has_data_impl() const { dwarnln("nonblock not supported"); return true; }
virtual BAN::ErrorOr<long> ioctl_impl(int request, void* arg) { return BAN::Error::from_errno(ENOTSUP); }
protected:
mutable RecursivePrioritySpinLock m_lock;

View File

@ -0,0 +1,43 @@
#pragma once
#include <BAN/HashMap.h>
#include <BAN/UniqPtr.h>
#include <kernel/Networking/NetworkInterface.h>
namespace Kernel
{
class ARPTable
{
BAN_NON_COPYABLE(ARPTable);
BAN_NON_MOVABLE(ARPTable);
public:
static BAN::ErrorOr<BAN::UniqPtr<ARPTable>> create();
BAN::ErrorOr<BAN::MACAddress> get_mac_from_ipv4(NetworkInterface&, BAN::IPv4Address);
void handle_arp_packet(BAN::ConstByteSpan);
private:
ARPTable();
private:
struct ARPReply
{
BAN::IPv4Address ipv4_address { 0 };
BAN::MACAddress mac_address;
};
private:
SpinLock m_lock;
BAN::HashMap<BAN::IPv4Address, BAN::MACAddress> m_arp_table;
BAN::Atomic<bool> m_has_got_reply;
ARPReply m_reply;
friend class BAN::UniqPtr<ARPTable>;
};
}

View File

@ -1,62 +0,0 @@
#pragma once
#include <BAN/UniqPtr.h>
#include <kernel/InterruptController.h>
#include <kernel/Networking/NetworkDriver.h>
#include <kernel/PCI.h>
#define E1000_NUM_RX_DESC 32
#define E1000_NUM_TX_DESC 8
namespace Kernel
{
class E1000 final : public NetworkDriver, public Interruptable
{
public:
static bool probe(PCI::Device&);
static BAN::ErrorOr<BAN::UniqPtr<E1000>> create(PCI::Device&);
~E1000();
virtual uint8_t* get_mac_address() override { return m_mac_address; }
virtual BAN::ErrorOr<void> send_packet(const void* data, uint16_t len) override;
virtual bool link_up() override { return m_link_up; }
virtual int link_speed() override;
virtual void handle_irq() override { ASSERT_NOT_REACHED(); }
private:
E1000(PCI::Device& pci_device) : m_pci_device(pci_device) {}
BAN::ErrorOr<void> initialize();
static void interrupt_handler();
uint32_t read32(uint16_t reg);
void write32(uint16_t reg, uint32_t value);
void detect_eeprom();
uint32_t eeprom_read(uint8_t addr);
BAN::ErrorOr<void> read_mac_address();
void initialize_rx();
void initialize_tx();
void enable_link();
BAN::ErrorOr<void> enable_interrupts();
void handle_receive();
private:
PCI::Device& m_pci_device;
BAN::UniqPtr<PCI::BarRegion> m_bar_region;
bool m_has_eerprom { false };
uint8_t m_mac_address[6] {};
uint16_t m_rx_current {};
uint16_t m_tx_current {};
struct e1000_rx_desc* m_rx_descs[E1000_NUM_RX_DESC] {};
struct e1000_tx_desc* m_tx_descs[E1000_NUM_TX_DESC] {};
bool m_link_up { false };
};
}

View File

@ -0,0 +1,202 @@
#pragma once
#include <stdint.h>
namespace Kernel
{
enum E1000_REG : uint32_t
{
REG_CTRL = 0x0000,
REG_STATUS = 0x0008,
REG_EERD = 0x0014,
REG_ICR = 0x00C0,
REG_ITR = 0x00C4,
REG_IMS = 0x00D0,
REG_IMC = 0x00D8,
REG_IVAR = 0x00E4,
REG_EITR = 0x00E8,
REG_RCTL = 0x0100,
REG_TCTL = 0x0400,
REG_TIPG = 0x0410,
REG_RDBAL0 = 0x2800,
REG_RDBAH0 = 0x2804,
REG_RDLEN0 = 0x2808,
REG_RDH0 = 0x2810,
REG_RDT0 = 0x2818,
REG_TDBAL = 0x3800,
REG_TDBAH = 0x3804,
REG_TDLEN = 0x3808,
REG_TDH = 0x3810,
REG_TDT = 0x3818,
REG_MTA = 0x5200,
};
enum E1000_CTRL : uint32_t
{
CTRL_FD = 1u << 0,
CTRL_GIOMD = 1u << 2,
CTRL_ASDE = 1u << 5,
CTRL_SLU = 1u << 6,
CTRL_FRCSPD = 1u << 11,
CTRL_FCRDBLX = 1u << 12,
CTRL_ADVD3WUC = 1u << 20,
CTRL_RST = 1u << 26,
CTRL_RFCE = 1u << 27,
CTRL_TFCE = 1u << 28,
CTRL_VME = 1u << 30,
CTRL_PHY_RST = 1u << 31,
CTRL_SPEED_10MB = 0b00 << 8,
CTRL_SPEED_100MB = 0b01 << 8,
CTRL_SPEED_1000MB1 = 0b10 << 8,
CTRL_SPEED_1000MB2 = 0b11 << 8,
};
enum E1000_STATUS : uint32_t
{
STATUS_LU = 1 << 1,
STATUS_SPEED_MASK = 0b11 << 6,
STATUS_SPEED_10MB = 0b00 << 6,
STATUS_SPEED_100MB = 0b01 << 6,
STATUS_SPEED_1000MB1 = 0b10 << 6,
STATUS_SPEED_1000MB2 = 0b11 << 6,
};
enum E1000_ICR : uint32_t
{
ICR_TXDW = 1 << 0,
ICR_TXQE = 1 << 1,
ICR_LSC = 1 << 2,
ICR_RXDMT0 = 1 << 4,
ICR_RXO = 1 << 6,
ICR_RXT0 = 1 << 7,
ICR_MDAC = 1 << 9,
ICR_TXD_LOW = 1 << 15,
ICR_SRPD = 1 << 16,
ICR_ACK = 1 << 17,
ICR_MNG = 1 << 18,
ICR_RxQ0 = 1 << 20,
ICR_RxQ1 = 1 << 21,
ICR_TxQ0 = 1 << 22,
ICR_TxQ1 = 1 << 23,
ICR_Other = 1 << 24,
};
enum E1000_IMS : uint32_t
{
IMS_TXDW = 1 << 0,
IMS_TXQE = 1 << 1,
IMS_LSC = 1 << 2,
IMS_RXDMT0 = 1 << 4,
IMS_RXO = 1 << 6,
IMS_RXT0 = 1 << 7,
IMS_MDAC = 1 << 9,
IMS_TXD_LOW = 1 << 15,
IMS_SRPD = 1 << 16,
IMS_ACK = 1 << 17,
IMS_MNG = 1 << 18,
IMS_RxQ0 = 1 << 20,
IMS_RxQ1 = 1 << 21,
IMS_TxQ0 = 1 << 22,
IMS_TxQ1 = 1 << 23,
IMS_Other = 1 << 24,
};
enum E1000_IMC : uint32_t
{
IMC_TXDW = 1 << 0,
IMC_TXQE = 1 << 1,
IMC_LSC = 1 << 2,
IMC_RXDMT0 = 1 << 4,
IMC_RXO = 1 << 6,
IMC_RXT0 = 1 << 7,
IMC_MDAC = 1 << 9,
IMC_TXD_LOW = 1 << 15,
IMC_SRPD = 1 << 16,
IMC_ACK = 1 << 17,
IMC_MNG = 1 << 18,
IMC_RxQ0 = 1 << 20,
IMC_RxQ1 = 1 << 21,
IMC_TxQ0 = 1 << 22,
IMC_TxQ1 = 1 << 23,
IMC_Other = 1 << 24,
};
enum E1000_TCTL : uint32_t
{
TCTL_EN = 1 << 1,
TCTL_PSP = 1 << 3,
TCTL_CT_IEEE = 15 << 4,
TCTL_SWXOFF = 1 << 22,
TCTL_PBE = 1 << 23,
TCTL_RCTL = 1 << 24,
TCTL_UNORTX = 1 << 25,
TCTL_MULR = 1 << 28,
};
enum E1000_RCTL : uint32_t
{
RCTL_EN = 1 << 1,
RCTL_SBP = 1 << 2,
RCTL_UPE = 1 << 3,
RCTL_MPE = 1 << 4,
RCTL_BAM = 1 << 15,
RCTL_VFE = 1 << 18,
RCTL_CFIEN = 1 << 19,
RCTL_CFI = 1 << 20,
RCTL_DPF = 1 << 22,
RCTL_PMCF = 1 << 23,
RCTL_BSEX = 1 << 25,
RCTL_SECRC = 1 << 26,
RCTL_RDMTS_1_2 = 0b00 << 8,
RCTL_RDMTS_1_4 = 0b01 << 8,
RCTL_RDMTS_1_8 = 0b10 << 8,
RCTL_LBM_NORMAL = 0b00 << 6,
RCTL_LBM_MAC = 0b01 << 6,
RCTL_BSIZE_256 = (0b11 << 16),
RCTL_BSIZE_512 = (0b10 << 16),
RCTL_BSIZE_1024 = (0b01 << 16),
RCTL_BSIZE_2048 = (0b00 << 16),
RCTL_BSIZE_4096 = (0b11 << 16) | RCTL_BSEX,
RCTL_BSIZE_8192 = (0b10 << 16) | RCTL_BSEX,
RCTL_BSIZE_16384 = (0b01 << 16) | RCTL_BSEX,
};
enum E1000_CMD : uint8_t
{
CMD_EOP = 1 << 0,
CMD_IFCS = 1 << 1,
CMD_IC = 1 << 2,
CMD_RS = 1 << 3,
CMD_DEXT = 1 << 5,
CMD_VLE = 1 << 6,
CMD_IDE = 1 << 7,
};
struct e1000_rx_desc
{
uint64_t addr;
uint16_t length;
uint16_t checksum;
uint8_t status;
uint8_t errors;
uint16_t special;
} __attribute__((packed));
struct e1000_tx_desc
{
uint64_t addr;
uint16_t length;
uint8_t cso;
uint8_t cmd;
uint8_t status;
uint8_t css;
uint16_t special;
} __attribute__((packed));
}

View File

@ -0,0 +1,75 @@
#pragma once
#include <BAN/UniqPtr.h>
#include <kernel/InterruptController.h>
#include <kernel/Memory/DMARegion.h>
#include <kernel/Networking/E1000/Definitions.h>
#include <kernel/Networking/NetworkInterface.h>
#include <kernel/PCI.h>
#define E1000_RX_DESCRIPTOR_COUNT 256
#define E1000_TX_DESCRIPTOR_COUNT 256
#define E1000_RX_BUFFER_SIZE 8192
#define E1000_TX_BUFFER_SIZE 8192
namespace Kernel
{
class E1000 : public NetworkInterface, public Interruptable
{
public:
static bool probe(PCI::Device&);
static BAN::ErrorOr<BAN::RefPtr<E1000>> create(PCI::Device&);
~E1000();
virtual BAN::MACAddress get_mac_address() const override { return m_mac_address; }
virtual bool link_up() override { return m_link_up; }
virtual int link_speed() override;
virtual void handle_irq() final override;
protected:
E1000(PCI::Device& pci_device)
: m_pci_device(pci_device)
{ }
BAN::ErrorOr<void> initialize();
virtual void detect_eeprom();
virtual uint32_t eeprom_read(uint8_t addr);
uint32_t read32(uint16_t reg);
void write32(uint16_t reg, uint32_t value);
virtual BAN::ErrorOr<void> send_raw_bytes(BAN::ConstByteSpan) override;
private:
BAN::ErrorOr<void> read_mac_address();
BAN::ErrorOr<void> initialize_rx();
BAN::ErrorOr<void> initialize_tx();
void enable_link();
BAN::ErrorOr<void> enable_interrupt();
void handle_receive();
protected:
PCI::Device& m_pci_device;
BAN::UniqPtr<PCI::BarRegion> m_bar_region;
bool m_has_eerprom { false };
private:
BAN::UniqPtr<DMARegion> m_rx_buffer_region;
BAN::UniqPtr<DMARegion> m_tx_buffer_region;
BAN::UniqPtr<DMARegion> m_rx_descriptor_region;
BAN::UniqPtr<DMARegion> m_tx_descriptor_region;
BAN::MACAddress m_mac_address {};
bool m_link_up { false };
friend class BAN::RefPtr<E1000>;
};
}

View File

@ -0,0 +1,27 @@
#pragma once
#include <kernel/Networking/E1000/E1000.h>
namespace Kernel
{
class E1000E final : public E1000
{
public:
static bool probe(PCI::Device&);
static BAN::ErrorOr<BAN::RefPtr<E1000E>> create(PCI::Device&);
protected:
virtual void detect_eeprom() override;
virtual uint32_t eeprom_read(uint8_t addr) override;
private:
E1000E(PCI::Device& pci_device)
: E1000(pci_device)
{ }
private:
friend class BAN::RefPtr<E1000E>;
};
}

View File

@ -0,0 +1,38 @@
#pragma once
#include <BAN/ByteSpan.h>
#include <BAN/Endianness.h>
#include <BAN/IPv4.h>
#include <BAN/Vector.h>
namespace Kernel
{
struct IPv4Header
{
uint8_t version_IHL;
uint8_t DSCP_ECN;
BAN::NetworkEndian<uint16_t> total_length { 0 };
BAN::NetworkEndian<uint16_t> identification { 0 };
BAN::NetworkEndian<uint16_t> flags_frament { 0 };
uint8_t time_to_live;
uint8_t protocol;
BAN::NetworkEndian<uint16_t> checksum { 0 };
BAN::IPv4Address src_address;
BAN::IPv4Address dst_address;
constexpr uint16_t calculate_checksum() const
{
return 0xFFFF
- (((uint16_t)version_IHL << 8) | DSCP_ECN)
- total_length
- identification
- flags_frament
- (((uint16_t)time_to_live << 8) | protocol);
}
};
static_assert(sizeof(IPv4Header) == 20);
void add_ipv4_header(BAN::ByteSpan packet, BAN::IPv4Address src_ipv4, BAN::IPv4Address dst_ipv4, uint8_t protocol);
}

View File

@ -1,20 +0,0 @@
#pragma once
#include <BAN/Errors.h>
namespace Kernel
{
class NetworkDriver
{
public:
virtual ~NetworkDriver() {}
virtual uint8_t* get_mac_address() = 0;
virtual BAN::ErrorOr<void> send_packet(const void* data, uint16_t len) = 0;
virtual bool link_up() = 0;
virtual int link_speed() = 0;
};
}

View File

@ -0,0 +1,70 @@
#pragma once
#include <BAN/Errors.h>
#include <BAN/ByteSpan.h>
#include <BAN/MAC.h>
#include <kernel/Device/Device.h>
#include <kernel/Networking/IPv4.h>
namespace Kernel
{
struct EthernetHeader
{
BAN::MACAddress dst_mac;
BAN::MACAddress src_mac;
BAN::NetworkEndian<uint16_t> ether_type;
};
static_assert(sizeof(EthernetHeader) == 14);
enum EtherType : uint16_t
{
IPv4 = 0x0800,
ARP = 0x0806,
};
class NetworkInterface : public CharacterDevice
{
BAN_NON_COPYABLE(NetworkInterface);
BAN_NON_MOVABLE(NetworkInterface);
public:
enum class Type
{
Ethernet,
};
public:
NetworkInterface();
virtual ~NetworkInterface() {}
virtual BAN::MACAddress get_mac_address() const = 0;
BAN::IPv4Address get_ipv4_address() const { return m_ipv4_address; }
void set_ipv4_address(BAN::IPv4Address new_address) { m_ipv4_address = new_address; }
BAN::IPv4Address get_netmask() const { return m_netmask; }
void set_netmask(BAN::IPv4Address new_netmask) { m_netmask = new_netmask; }
virtual bool link_up() = 0;
virtual int link_speed() = 0;
size_t interface_header_size() const;
void add_interface_header(BAN::ByteSpan packet, BAN::MACAddress destination);
virtual dev_t rdev() const override { return m_rdev; }
virtual BAN::StringView name() const override { return m_name; }
virtual BAN::ErrorOr<void> send_raw_bytes(BAN::ConstByteSpan) = 0;
private:
const Type m_type;
const dev_t m_rdev;
char m_name[10];
BAN::IPv4Address m_ipv4_address { 0 };
BAN::IPv4Address m_netmask { 0 };
};
}

View File

@ -0,0 +1,52 @@
#pragma once
#include <BAN/Vector.h>
#include <kernel/FS/TmpFS/FileSystem.h>
#include <kernel/Networking/ARPTable.h>
#include <kernel/Networking/NetworkInterface.h>
#include <kernel/Networking/NetworkSocket.h>
#include <kernel/PCI.h>
#include <netinet/in.h>
namespace Kernel
{
class NetworkManager : public TmpFileSystem
{
BAN_NON_COPYABLE(NetworkManager);
BAN_NON_MOVABLE(NetworkManager);
public:
enum class SocketType
{
STREAM,
DGRAM,
SEQPACKET,
};
public:
static BAN::ErrorOr<void> initialize();
static NetworkManager& get();
ARPTable& arp_table() { return *m_arp_table; }
BAN::ErrorOr<void> add_interface(PCI::Device& pci_device);
void unbind_socket(uint16_t port, BAN::RefPtr<NetworkSocket>);
BAN::ErrorOr<void> bind_socket(uint16_t port, BAN::RefPtr<NetworkSocket>);
BAN::ErrorOr<BAN::RefPtr<NetworkSocket>> create_socket(SocketType, mode_t, uid_t, gid_t);
void on_receive(BAN::ConstByteSpan);
private:
NetworkManager();
private:
BAN::UniqPtr<ARPTable> m_arp_table;
BAN::Vector<BAN::RefPtr<NetworkInterface>> m_interfaces;
BAN::HashMap<int, BAN::WeakPtr<NetworkSocket>> m_bound_sockets;
};
}

View File

@ -0,0 +1,53 @@
#pragma once
#include <BAN/WeakPtr.h>
#include <kernel/FS/TmpFS/Inode.h>
#include <kernel/Networking/NetworkInterface.h>
#include <netinet/in.h>
namespace Kernel
{
enum NetworkProtocol : uint8_t
{
UDP = 0x11,
};
class NetworkSocket : public TmpInode, public BAN::Weakable<NetworkSocket>
{
BAN_NON_COPYABLE(NetworkSocket);
BAN_NON_MOVABLE(NetworkSocket);
public:
static constexpr uint16_t PORT_NONE = 0;
public:
void bind_interface_and_port(NetworkInterface*, uint16_t port);
~NetworkSocket();
virtual size_t protocol_header_size() const = 0;
virtual void add_protocol_header(BAN::ByteSpan packet, uint16_t src_port, uint16_t dst_port) = 0;
virtual NetworkProtocol protocol() const = 0;
virtual void add_packet(BAN::ConstByteSpan, BAN::IPv4Address sender_address, uint16_t sender_port) = 0;
protected:
NetworkSocket(mode_t mode, uid_t uid, gid_t gid);
virtual BAN::ErrorOr<size_t> read_packet(BAN::ByteSpan, sockaddr_in* sender_address) = 0;
virtual void on_close_impl() override;
virtual BAN::ErrorOr<void> bind_impl(const sockaddr* address, socklen_t address_len) override;
virtual BAN::ErrorOr<ssize_t> sendto_impl(const sys_sendto_t*) override;
virtual BAN::ErrorOr<ssize_t> recvfrom_impl(sys_recvfrom_t*) override;
virtual BAN::ErrorOr<long> ioctl_impl(int request, void* arg) override;
protected:
NetworkInterface* m_interface = nullptr;
uint16_t m_port = PORT_NONE;
};
}

View File

@ -0,0 +1,55 @@
#pragma once
#include <BAN/CircularQueue.h>
#include <BAN/Endianness.h>
#include <kernel/Memory/VirtualRange.h>
#include <kernel/Networking/NetworkInterface.h>
#include <kernel/Networking/NetworkSocket.h>
#include <kernel/Semaphore.h>
namespace Kernel
{
struct UDPHeader
{
BAN::NetworkEndian<uint16_t> src_port;
BAN::NetworkEndian<uint16_t> dst_port;
BAN::NetworkEndian<uint16_t> length;
BAN::NetworkEndian<uint16_t> checksum;
};
static_assert(sizeof(UDPHeader) == 8);
class UDPSocket final : public NetworkSocket
{
public:
static BAN::ErrorOr<BAN::RefPtr<UDPSocket>> create(mode_t, uid_t, gid_t);
virtual size_t protocol_header_size() const override { return sizeof(UDPHeader); }
virtual void add_protocol_header(BAN::ByteSpan packet, uint16_t src_port, uint16_t dst_port) override;
virtual NetworkProtocol protocol() const override { return NetworkProtocol::UDP; }
protected:
virtual void add_packet(BAN::ConstByteSpan, BAN::IPv4Address sender_addr, uint16_t sender_port) override;
virtual BAN::ErrorOr<size_t> read_packet(BAN::ByteSpan, sockaddr_in* sender_address) override;
private:
UDPSocket(mode_t, uid_t, gid_t);
struct PacketInfo
{
BAN::IPv4Address sender_addr;
uint16_t sender_port;
size_t packet_size;
};
private:
static constexpr size_t packet_buffer_size = 10 * PAGE_SIZE;
BAN::UniqPtr<VirtualRange> m_packet_buffer;
BAN::CircularQueue<PacketInfo, 128> m_packets;
size_t m_packet_total_size { 0 };
Semaphore m_semaphore;
friend class BAN::RefPtr<UDPSocket>;
};
}

View File

@ -23,6 +23,8 @@ namespace Kernel
BAN::ErrorOr<int> open(BAN::StringView absolute_path, int flags);
BAN::ErrorOr<int> socket(int domain, int type, int protocol);
BAN::ErrorOr<void> pipe(int fds[2]);
BAN::ErrorOr<int> dup(int);

View File

@ -16,6 +16,7 @@
#include <sys/banan-os.h>
#include <sys/mman.h>
#include <sys/socket.h>
#include <termios.h>
namespace LibELF { class LoadableELF; }
@ -111,6 +112,13 @@ namespace Kernel
BAN::ErrorOr<long> sys_chmod(const char*, mode_t);
BAN::ErrorOr<long> sys_chown(const char*, uid_t, gid_t);
BAN::ErrorOr<long> sys_socket(int domain, int type, int protocol);
BAN::ErrorOr<long> sys_bind(int socket, const sockaddr* address, socklen_t address_len);
BAN::ErrorOr<long> sys_sendto(const sys_sendto_t*);
BAN::ErrorOr<long> sys_recvfrom(sys_recvfrom_t*);
BAN::ErrorOr<long> sys_ioctl(int fildes, int request, void* arg);
BAN::ErrorOr<long> sys_pipe(int fildes[2]);
BAN::ErrorOr<long> sys_dup(int fildes);
BAN::ErrorOr<long> sys_dup2(int fildes, int fildes2);

View File

@ -44,34 +44,26 @@ namespace Kernel
BAN::ErrorOr<void> add_thread(Thread*);
private:
struct ActiveThread
struct SchedulerThread
{
ActiveThread(Thread* thread) : thread(thread) {}
Thread* thread;
uint64_t padding;
};
SchedulerThread(Thread* thread)
: thread(thread)
{}
struct SleepingThread
{
SleepingThread(Thread* thread, uint64_t wake_time) : thread(thread), wake_time(wake_time) {}
Thread* thread;
uint64_t wake_time;
};
struct BlockingThread
{
BlockingThread(Thread* thread, Semaphore* semaphore) : thread(thread), semaphore(semaphore) {}
Thread* thread;
Semaphore* semaphore;
uint8_t padding[sizeof(uint64_t) - sizeof(Semaphore*)];
union
{
uint64_t wake_time;
Semaphore* semaphore;
};
};
Thread* m_idle_thread { nullptr };
BAN::LinkedList<ActiveThread> m_active_threads;
BAN::LinkedList<SleepingThread> m_sleeping_threads;
BAN::LinkedList<BlockingThread> m_blocking_threads;
BAN::LinkedList<SchedulerThread> m_active_threads;
BAN::LinkedList<SchedulerThread> m_sleeping_threads;
BAN::LinkedList<SchedulerThread> m_blocking_threads;
BAN::LinkedList<ActiveThread>::iterator m_current_thread;
BAN::LinkedList<SchedulerThread>::iterator m_current_thread;
friend class Process;
};

View File

@ -56,6 +56,12 @@ namespace Kernel
return true;
}
void Inode::on_close()
{
LockGuard _(m_lock);
on_close_impl();
}
BAN::ErrorOr<BAN::RefPtr<Inode>> Inode::find_inode(BAN::StringView name)
{
LockGuard _(m_lock);
@ -110,6 +116,30 @@ namespace Kernel
return link_target_impl();
}
BAN::ErrorOr<void> Inode::bind(const sockaddr* address, socklen_t address_len)
{
LockGuard _(m_lock);
if (!mode().ifsock())
return BAN::Error::from_errno(ENOTSOCK);
return bind_impl(address, address_len);
}
BAN::ErrorOr<ssize_t> Inode::sendto(const sys_sendto_t* arguments)
{
LockGuard _(m_lock);
if (!mode().ifsock())
return BAN::Error::from_errno(ENOTSOCK);
return sendto_impl(arguments);
};
BAN::ErrorOr<ssize_t> Inode::recvfrom(sys_recvfrom_t* arguments)
{
LockGuard _(m_lock);
if (!mode().ifsock())
return BAN::Error::from_errno(ENOTSOCK);
return recvfrom_impl(arguments);
};
BAN::ErrorOr<size_t> Inode::read(off_t offset, BAN::ByteSpan buffer)
{
LockGuard _(m_lock);
@ -153,4 +183,10 @@ namespace Kernel
return has_data_impl();
}
BAN::ErrorOr<long> Inode::ioctl(int request, void* arg)
{
LockGuard _(m_lock);
return ioctl_impl(request, arg);
}
}

View File

@ -0,0 +1,108 @@
#include <kernel/LockGuard.h>
#include <kernel/Networking/ARPTable.h>
#include <kernel/Timer/Timer.h>
namespace Kernel
{
struct ARPPacket
{
BAN::NetworkEndian<uint16_t> htype;
BAN::NetworkEndian<uint16_t> ptype;
BAN::NetworkEndian<uint8_t> hlen;
BAN::NetworkEndian<uint8_t> plen;
BAN::NetworkEndian<uint16_t> oper;
BAN::MACAddress sha;
BAN::IPv4Address spa;
BAN::MACAddress tha;
BAN::IPv4Address tpa;
};
static_assert(sizeof(ARPPacket) == 28);
enum ARPOperation : uint16_t
{
Request = 1,
Reply = 2,
};
static constexpr BAN::IPv4Address s_broadcast_ipv4 { 0xFFFFFFFF };
static constexpr BAN::MACAddress s_broadcast_mac {{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }};
BAN::ErrorOr<BAN::UniqPtr<ARPTable>> ARPTable::create()
{
return TRY(BAN::UniqPtr<ARPTable>::create());
}
ARPTable::ARPTable()
{
}
BAN::ErrorOr<BAN::MACAddress> ARPTable::get_mac_from_ipv4(NetworkInterface& interface, BAN::IPv4Address ipv4_address)
{
LockGuard _(m_lock);
if (ipv4_address == s_broadcast_ipv4)
return s_broadcast_mac;
if (m_arp_table.contains(ipv4_address))
return m_arp_table[ipv4_address];
BAN::Vector<uint8_t> full_packet_buffer;
TRY(full_packet_buffer.resize(sizeof(ARPPacket) + sizeof(EthernetHeader)));
auto full_packet = BAN::ByteSpan { full_packet_buffer.span() };
auto& ethernet_header = full_packet.as<EthernetHeader>();
ethernet_header.dst_mac = s_broadcast_mac;
ethernet_header.src_mac = interface.get_mac_address();
ethernet_header.ether_type = EtherType::ARP;
auto& arp_request = full_packet.slice(sizeof(EthernetHeader)).as<ARPPacket>();
arp_request.htype = 0x0001;
arp_request.ptype = EtherType::IPv4;
arp_request.hlen = 0x06;
arp_request.plen = 0x04;
arp_request.oper = ARPOperation::Request;
arp_request.sha = interface.get_mac_address();
arp_request.spa = interface.get_ipv4_address();
arp_request.tha = {{ 0, 0, 0, 0, 0, 0 }};
arp_request.tpa = ipv4_address;
TRY(interface.send_raw_bytes(full_packet));
uint64_t timeout = SystemTimer::get().ms_since_boot() + 5'000;
while (!m_has_got_reply)
if (SystemTimer::get().ms_since_boot() >= timeout)
return BAN::Error::from_errno(ETIMEDOUT);
ASSERT_EQ(m_reply.ipv4_address, ipv4_address);
BAN::MACAddress mac_address = m_reply.mac_address;
(void)m_arp_table.insert(ipv4_address, m_reply.mac_address);
m_has_got_reply = false;
dprintln("IPv4 {} resolved to MAC {}", ipv4_address, mac_address);
return mac_address;
}
void ARPTable::handle_arp_packet(BAN::ConstByteSpan buffer)
{
auto& arp_packet = buffer.as<const ARPPacket>();
if (arp_packet.oper != ARPOperation::Reply)
{
dprintln("Unhandled non-rely ARP packet (operation {2H})", (uint16_t)arp_packet.oper);
return;
}
if (arp_packet.ptype != EtherType::IPv4)
{
dprintln("Unhandled non-ipv4 ARP packet (ptype {2H})", (uint16_t)arp_packet.ptype);
return;
}
ASSERT(!m_has_got_reply);
m_has_got_reply = true;
m_reply.ipv4_address = arp_packet.spa;
m_reply.mac_address = arp_packet.sha;
}
}

View File

@ -1,374 +0,0 @@
#include <kernel/IDT.h>
#include <kernel/InterruptController.h>
#include <kernel/IO.h>
#include <kernel/Memory/PageTable.h>
#include <kernel/MMIO.h>
#include <kernel/Networking/E1000.h>
#define DEBUG_E1000 1
#define E1000_REG_CTRL 0x0000
#define E1000_REG_STATUS 0x0008
#define E1000_REG_EEPROM 0x0014
#define E1000_REG_INT_CAUSE_READ 0x00C0
#define E1000_REG_INT_RATE 0x00C4
#define E1000_REG_INT_MASK_SET 0x00D0
#define E1000_REG_INT_MASK_CLEAR 0x00D8
#define E1000_REG_RCTRL 0x0100
#define E1000_REG_RXDESCLO 0x2800
#define E1000_REG_RXDESCHI 0x2804
#define E1000_REG_RXDESCLEN 0x2808
#define E1000_REG_RXDESCHEAD 0x2810
#define E1000_REG_RXDESCTAIL 0x2818
#define E1000_REG_TXDESCLO 0x3800
#define E1000_REG_TXDESCHI 0x3804
#define E1000_REG_TXDESCLEN 0x3808
#define E1000_REG_TXDESCHEAD 0x3810
#define E1000_REG_TXDESCTAIL 0x3818
#define E1000_REG_TCTRL 0x0400
#define E1000_REG_TIPG 0x0410
#define E1000_STATUS_LINK_UP 0x02
#define E1000_STATUS_SPEED_MASK 0xC0
#define E1000_STATUS_SPEED_10MB 0x00
#define E1000_STATUS_SPEED_100MB 0x40
#define E1000_STATUS_SPEED_1000MB1 0x80
#define E1000_STATUS_SPEED_1000MB2 0xC0
#define E1000_CTRL_SET_LINK_UP 0x40
#define E1000_INT_TXDW (1 << 0)
#define E1000_INT_TXQE (1 << 1)
#define E1000_INT_LSC (1 << 2)
#define E1000_INT_RXSEQ (1 << 3)
#define E1000_INT_RXDMT0 (1 << 4)
#define E1000_INT_RXO (1 << 6)
#define E1000_INT_RXT0 (1 << 7)
#define E1000_INT_MDAC (1 << 9)
#define E1000_INT_RXCFG (1 << 10)
#define E1000_INT_PHYINT (1 << 12)
#define E1000_INT_TXD_LOW (1 << 15)
#define E1000_INT_SRPD (1 << 16)
#define E1000_TCTL_EN (1 << 1)
#define E1000_TCTL_PSP (1 << 3)
#define E1000_TCTL_CT_SHIFT 4
#define E1000_TCTL_COLD_SHIFT 12
#define E1000_TCTL_SWXOFF (1 << 22)
#define E1000_TCTL_RTLC (1 << 24)
#define E1000_RCTL_EN (1 << 1)
#define E1000_RCTL_SBP (1 << 2)
#define E1000_RCTL_UPE (1 << 3)
#define E1000_RCTL_MPE (1 << 4)
#define E1000_RCTL_LPE (1 << 5)
#define E1000_RCTL_LBM_NONE (0 << 6)
#define E1000_RCTL_LBM_PHY (3 << 6)
#define E1000_RTCL_RDMTS_HALF (0 << 8)
#define E1000_RTCL_RDMTS_QUARTER (1 << 8)
#define E1000_RTCL_RDMTS_EIGHTH (2 << 8)
#define E1000_RCTL_MO_36 (0 << 12)
#define E1000_RCTL_MO_35 (1 << 12)
#define E1000_RCTL_MO_34 (2 << 12)
#define E1000_RCTL_MO_32 (3 << 12)
#define E1000_RCTL_BAM (1 << 15)
#define E1000_RCTL_VFE (1 << 18)
#define E1000_RCTL_CFIEN (1 << 19)
#define E1000_RCTL_CFI (1 << 20)
#define E1000_RCTL_DPF (1 << 22)
#define E1000_RCTL_PMCF (1 << 23)
#define E1000_RCTL_SECRC (1 << 26)
#define E1000_RCTL_BSIZE_256 (3 << 16)
#define E1000_RCTL_BSIZE_512 (2 << 16)
#define E1000_RCTL_BSIZE_1024 (1 << 16)
#define E1000_RCTL_BSIZE_2048 (0 << 16)
#define E1000_RCTL_BSIZE_4096 ((3 << 16) | (1 << 25))
#define E1000_RCTL_BSIZE_8192 ((2 << 16) | (1 << 25))
#define E1000_RCTL_BSIZE_16384 ((1 << 16) | (1 << 25))
namespace Kernel
{
struct e1000_rx_desc
{
volatile uint64_t addr;
volatile uint16_t length;
volatile uint16_t checksum;
volatile uint8_t status;
volatile uint8_t errors;
volatile uint16_t special;
} __attribute__((packed));
struct e1000_tx_desc
{
volatile uint64_t addr;
volatile uint16_t length;
volatile uint8_t cso;
volatile uint8_t cmd;
volatile uint8_t status;
volatile uint8_t css;
volatile uint16_t special;
} __attribute__((packed));
// https://www.intel.com/content/dam/doc/manual/pci-pci-x-family-gbe-controllers-software-dev-manual.pdf (section 5.2)
bool E1000::probe(PCI::Device& pci_device)
{
// Intel device
if (pci_device.vendor_id() != 0x8086)
return false;
switch (pci_device.device_id())
{
case 0x1019:
case 0x101A:
case 0x1010:
case 0x1012:
case 0x101D:
case 0x1079:
case 0x107A:
case 0x107B:
case 0x100F:
case 0x1011:
case 0x1026:
case 0x1027:
case 0x1028:
case 0x1107:
case 0x1112:
case 0x1013:
case 0x1018:
case 0x1076:
case 0x1077:
case 0x1078:
case 0x1017:
case 0x1016:
case 0x100e:
case 0x1015:
return true;
default:
return false;
}
}
BAN::ErrorOr<BAN::UniqPtr<E1000>> E1000::create(PCI::Device& pci_device)
{
E1000* e1000 = new E1000();
ASSERT(e1000);
if (auto ret = e1000->initialize(pci_device); ret.is_error())
{
delete e1000;
return ret.release_error();
}
return BAN::UniqPtr<E1000>::adopt(e1000);
}
E1000::~E1000()
{
}
BAN::ErrorOr<void> E1000::initialize(PCI::Device& pci_device)
{
m_bar_region = TRY(pci_device.allocate_bar_region(0));
pci_device.enable_bus_mastering();
detect_eeprom();
TRY(read_mac_address());
initialize_rx();
initialize_tx();
enable_link();
enable_interrupts();
#if DEBUG_E1000
dprintln("E1000 at PCI {}:{}.{}", pci_device.bus(), pci_device.dev(), pci_device.func());
dprintln(" MAC: {2H}:{2H}:{2H}:{2H}:{2H}:{2H}",
m_mac_address[0],
m_mac_address[1],
m_mac_address[2],
m_mac_address[3],
m_mac_address[4],
m_mac_address[5]
);
dprintln(" link up: {}", link_up());
if (link_up())
dprintln(" link speed: {} Mbps", link_speed());
#endif
return {};
}
void E1000::write32(uint16_t reg, uint32_t value)
{
m_bar_region->write32(reg, value);
}
uint32_t E1000::read32(uint16_t reg)
{
return m_bar_region->read32(reg);
}
void E1000::detect_eeprom()
{
m_has_eerprom = false;
write32(E1000_REG_EEPROM, 0x01);
for (int i = 0; i < 1000 && !m_has_eerprom; i++)
if (read32(E1000_REG_EEPROM) & 0x10)
m_has_eerprom = true;
}
uint32_t E1000::eeprom_read(uint8_t address)
{
uint32_t tmp = 0;
if (m_has_eerprom)
{
write32(E1000_REG_EEPROM, ((uint32_t)address << 8) | 1);
while (!((tmp = read32(E1000_REG_EEPROM)) & (1 << 4)))
continue;
}
else
{
write32(E1000_REG_EEPROM, ((uint32_t)address << 2) | 1);
while (!((tmp = read32(E1000_REG_EEPROM)) & (1 << 1)))
continue;
}
return (tmp >> 16) & 0xFFFF;
}
BAN::ErrorOr<void> E1000::read_mac_address()
{
if (m_has_eerprom)
{
uint32_t temp = eeprom_read(0);
m_mac_address[0] = temp;
m_mac_address[1] = temp >> 8;
temp = eeprom_read(1);
m_mac_address[2] = temp;
m_mac_address[3] = temp >> 8;
temp = eeprom_read(2);
m_mac_address[4] = temp;
m_mac_address[5] = temp >> 8;
return {};
}
if (read32(0x5400) == 0)
{
dwarnln("no mac address");
return BAN::Error::from_errno(EINVAL);
}
for (int i = 0; i < 6; i++)
m_mac_address[i] = (uint8_t)read32(0x5400 + i * 8);
return {};
}
void E1000::initialize_rx()
{
uint8_t* ptr = (uint8_t*)kmalloc(sizeof(e1000_rx_desc) * E1000_NUM_RX_DESC + 16, 16, true);
ASSERT(ptr);
e1000_rx_desc* descs = (e1000_rx_desc*)ptr;
for (int i = 0; i < E1000_NUM_RX_DESC; i++)
{
// FIXME
m_rx_descs[i] = &descs[i];
m_rx_descs[i]->addr = 0;
m_rx_descs[i]->status = 0;
}
write32(E1000_REG_RXDESCLO, (uintptr_t)ptr >> 32);
write32(E1000_REG_RXDESCHI, (uintptr_t)ptr & 0xFFFFFFFF);
write32(E1000_REG_RXDESCLEN, E1000_NUM_RX_DESC * sizeof(e1000_rx_desc));
write32(E1000_REG_RXDESCHEAD, 0);
write32(E1000_REG_RXDESCTAIL, E1000_NUM_RX_DESC - 1);
m_rx_current = 0;
uint32_t rctrl = 0;
rctrl |= E1000_RCTL_EN;
rctrl |= E1000_RCTL_SBP;
rctrl |= E1000_RCTL_UPE;
rctrl |= E1000_RCTL_MPE;
rctrl |= E1000_RCTL_LBM_NONE;
rctrl |= E1000_RTCL_RDMTS_HALF;
rctrl |= E1000_RCTL_BAM;
rctrl |= E1000_RCTL_SECRC;
rctrl |= E1000_RCTL_BSIZE_8192;
write32(E1000_REG_RCTRL, rctrl);
}
void E1000::initialize_tx()
{
auto* ptr = (uint8_t*)kmalloc(sizeof(e1000_tx_desc) * E1000_NUM_TX_DESC + 16, 16, true);
ASSERT(ptr);
auto* descs = (e1000_tx_desc*)ptr;
for(int i = 0; i < E1000_NUM_TX_DESC; i++)
{
// FIXME
m_tx_descs[i] = &descs[i];
m_tx_descs[i]->addr = 0;
m_tx_descs[i]->cmd = 0;
}
write32(E1000_REG_TXDESCHI, (uintptr_t)ptr >> 32);
write32(E1000_REG_TXDESCLO, (uintptr_t)ptr & 0xFFFFFFFF);
write32(E1000_REG_TXDESCLEN, E1000_NUM_TX_DESC * sizeof(e1000_tx_desc));
write32(E1000_REG_TXDESCHEAD, 0);
write32(E1000_REG_TXDESCTAIL, 0);
m_tx_current = 0;
write32(E1000_REG_TCTRL, read32(E1000_REG_TCTRL) | E1000_TCTL_EN | E1000_TCTL_PSP);
write32(E1000_REG_TIPG, 0x0060200A);
}
void E1000::enable_link()
{
write32(E1000_REG_CTRL, read32(E1000_REG_CTRL) | E1000_CTRL_SET_LINK_UP);
m_link_up = !!(read32(E1000_REG_STATUS) & E1000_STATUS_LINK_UP);
}
int E1000::link_speed()
{
if (!link_up())
return 0;
uint32_t speed = read32(E1000_REG_STATUS) & E1000_STATUS_SPEED_MASK;
if (speed == E1000_STATUS_SPEED_10MB)
return 10;
if (speed == E1000_STATUS_SPEED_100MB)
return 100;
if (speed == E1000_STATUS_SPEED_1000MB1)
return 1000;
if (speed == E1000_STATUS_SPEED_1000MB2)
return 1000;
return 0;
}
void E1000::enable_interrupts()
{
write32(E1000_REG_INT_RATE, 6000);
write32(E1000_REG_INT_MASK_SET, E1000_INT_LSC | E1000_INT_RXT0 | E1000_INT_RXO);
read32(E1000_REG_INT_CAUSE_READ);
// FIXME: implement PCI interrupt allocation
//IDT::register_irq_handler(irq, E1000::interrupt_handler);
//InterruptController::enable_irq(irq);
}
BAN::ErrorOr<void> E1000::send_packet(const void* data, uint16_t len)
{
(void)data;
(void)len;
return BAN::Error::from_errno(ENOTSUP);
}
}

View File

@ -0,0 +1,305 @@
#include <kernel/IDT.h>
#include <kernel/InterruptController.h>
#include <kernel/IO.h>
#include <kernel/Memory/PageTable.h>
#include <kernel/MMIO.h>
#include <kernel/Networking/E1000/E1000.h>
#include <kernel/Networking/NetworkManager.h>
#define DEBUG_E1000 1
namespace Kernel
{
// https://www.intel.com/content/dam/doc/manual/pci-pci-x-family-gbe-controllers-software-dev-manual.pdf (section 5.2)
bool E1000::probe(PCI::Device& pci_device)
{
// Intel device
if (pci_device.vendor_id() != 0x8086)
return false;
switch (pci_device.device_id())
{
case 0x1019:
case 0x101A:
case 0x1010:
case 0x1012:
case 0x101D:
case 0x1079:
case 0x107A:
case 0x107B:
case 0x100F:
case 0x1011:
case 0x1026:
case 0x1027:
case 0x1028:
case 0x1107:
case 0x1112:
case 0x1013:
case 0x1018:
case 0x1076:
case 0x1077:
case 0x1078:
case 0x1017:
case 0x1016:
case 0x100e:
case 0x1015:
return true;
default:
return false;
}
}
BAN::ErrorOr<BAN::RefPtr<E1000>> E1000::create(PCI::Device& pci_device)
{
auto e1000 = TRY(BAN::RefPtr<E1000>::create(pci_device));
TRY(e1000->initialize());
return e1000;
}
E1000::~E1000()
{
}
BAN::ErrorOr<void> E1000::initialize()
{
m_bar_region = TRY(m_pci_device.allocate_bar_region(0));
m_pci_device.enable_bus_mastering();
detect_eeprom();
TRY(read_mac_address());
#if DEBUG_E1000
dprintln("E1000 at PCI {}:{}.{}", m_pci_device.bus(), m_pci_device.dev(), m_pci_device.func());
dprintln(" MAC: {}", m_mac_address);
#endif
TRY(initialize_rx());
TRY(initialize_tx());
enable_link();
TRY(enable_interrupt());
m_link_up = !!(read32(REG_STATUS) & STATUS_LU);
#if DEBUG_E1000
dprintln(" link up: {}", link_up());
if (link_up())
{
int speed = link_speed();
dprintln(" link speed: {} Mbps", speed);
}
#endif
return {};
}
void E1000::write32(uint16_t reg, uint32_t value)
{
m_bar_region->write32(reg, value);
}
uint32_t E1000::read32(uint16_t reg)
{
return m_bar_region->read32(reg);
}
void E1000::detect_eeprom()
{
m_has_eerprom = false;
write32(REG_EERD, 0x01);
for (int i = 0; i < 1000 && !m_has_eerprom; i++)
if (read32(REG_EERD) & 0x10)
m_has_eerprom = true;
}
uint32_t E1000::eeprom_read(uint8_t address)
{
uint32_t tmp = 0;
if (m_has_eerprom)
{
write32(REG_EERD, ((uint32_t)address << 8) | 1);
while (!((tmp = read32(REG_EERD)) & (1 << 4)))
continue;
}
else
{
write32(REG_EERD, ((uint32_t)address << 2) | 1);
while (!((tmp = read32(REG_EERD)) & (1 << 1)))
continue;
}
return (tmp >> 16) & 0xFFFF;
}
BAN::ErrorOr<void> E1000::read_mac_address()
{
if (m_has_eerprom)
{
uint32_t temp = eeprom_read(0);
m_mac_address.address[0] = temp;
m_mac_address.address[1] = temp >> 8;
temp = eeprom_read(1);
m_mac_address.address[2] = temp;
m_mac_address.address[3] = temp >> 8;
temp = eeprom_read(2);
m_mac_address.address[4] = temp;
m_mac_address.address[5] = temp >> 8;
return {};
}
if (read32(0x5400) == 0)
{
dwarnln("no mac address");
return BAN::Error::from_errno(EINVAL);
}
for (int i = 0; i < 6; i++)
m_mac_address.address[i] = (uint8_t)read32(0x5400 + i * 8);
return {};
}
BAN::ErrorOr<void> E1000::initialize_rx()
{
m_rx_buffer_region = TRY(DMARegion::create(E1000_RX_BUFFER_SIZE * E1000_RX_DESCRIPTOR_COUNT));
m_rx_descriptor_region = TRY(DMARegion::create(sizeof(e1000_rx_desc) * E1000_RX_DESCRIPTOR_COUNT));
auto* rx_descriptors = reinterpret_cast<volatile e1000_rx_desc*>(m_rx_descriptor_region->vaddr());
for (size_t i = 0; i < E1000_RX_DESCRIPTOR_COUNT; i++)
{
rx_descriptors[i].addr = m_rx_buffer_region->paddr() + E1000_RX_BUFFER_SIZE * i;
rx_descriptors[i].status = 0;
}
write32(REG_RDBAL0, m_rx_descriptor_region->paddr() & 0xFFFFFFFF);
write32(REG_RDBAH0, m_rx_descriptor_region->paddr() >> 32);
write32(REG_RDLEN0, E1000_RX_DESCRIPTOR_COUNT * sizeof(e1000_rx_desc));
write32(REG_RDH0, 0);
write32(REG_RDT0, E1000_RX_DESCRIPTOR_COUNT - 1);
uint32_t rctrl = 0;
rctrl |= RCTL_EN;
rctrl |= RCTL_SBP;
rctrl |= RCTL_UPE;
rctrl |= RCTL_MPE;
rctrl |= RCTL_LBM_NORMAL;
rctrl |= RCTL_RDMTS_1_2;
rctrl |= RCTL_BAM;
rctrl |= RCTL_SECRC;
rctrl |= RCTL_BSIZE_8192;
write32(REG_RCTL, rctrl);
return {};
}
BAN::ErrorOr<void> E1000::initialize_tx()
{
m_tx_buffer_region = TRY(DMARegion::create(E1000_TX_BUFFER_SIZE * E1000_TX_DESCRIPTOR_COUNT));
m_tx_descriptor_region = TRY(DMARegion::create(sizeof(e1000_tx_desc) * E1000_TX_DESCRIPTOR_COUNT));
auto* tx_descriptors = reinterpret_cast<volatile e1000_tx_desc*>(m_tx_descriptor_region->vaddr());
for (size_t i = 0; i < E1000_TX_DESCRIPTOR_COUNT; i++)
{
tx_descriptors[i].addr = m_tx_buffer_region->paddr() + E1000_TX_BUFFER_SIZE * i;
tx_descriptors[i].cmd = 0;
}
write32(REG_TDBAL, m_tx_descriptor_region->paddr() & 0xFFFFFFFF);
write32(REG_TDBAH, m_tx_descriptor_region->paddr() >> 32);
write32(REG_TDLEN, E1000_TX_DESCRIPTOR_COUNT * sizeof(e1000_tx_desc));
write32(REG_TDH, 0);
write32(REG_TDT, 0);
write32(REG_TCTL, TCTL_EN | TCTL_PSP);
write32(REG_TIPG, 0x0060200A);
return {};
}
void E1000::enable_link()
{
write32(REG_CTRL, read32(REG_CTRL) | CTRL_SLU);
}
int E1000::link_speed()
{
if (!link_up())
return 0;
uint32_t speed = read32(REG_STATUS) & STATUS_SPEED_MASK;
if (speed == STATUS_SPEED_10MB)
return 10;
if (speed == STATUS_SPEED_100MB)
return 100;
if (speed == STATUS_SPEED_1000MB1)
return 1000;
if (speed == STATUS_SPEED_1000MB2)
return 1000;
return 0;
}
BAN::ErrorOr<void> E1000::enable_interrupt()
{
write32(REG_ITR, 0x1000);
write32(REG_IVAR, 1 << 3);
write32(REG_EITR, 0x1000);
write32(REG_IMS, IMC_RxQ0);
read32(REG_ICR);
TRY(m_pci_device.reserve_irqs(1));
set_irq(m_pci_device.get_irq(0));
Interruptable::enable_interrupt();
return {};
}
BAN::ErrorOr<void> E1000::send_raw_bytes(BAN::ConstByteSpan buffer)
{
ASSERT_LTE(buffer.size(), E1000_TX_BUFFER_SIZE);
CriticalScope _;
size_t tx_current = read32(REG_TDT) % E1000_TX_DESCRIPTOR_COUNT;
auto* tx_buffer = reinterpret_cast<void*>(m_tx_buffer_region->vaddr() + E1000_TX_BUFFER_SIZE * tx_current);
memcpy(tx_buffer, buffer.data(), buffer.size());
auto& descriptor = reinterpret_cast<volatile e1000_tx_desc*>(m_tx_descriptor_region->vaddr())[tx_current];
descriptor.length = buffer.size();
descriptor.status = 0;
descriptor.cmd = CMD_EOP | CMD_IFCS | CMD_RS;
write32(REG_TDT, (tx_current + 1) % E1000_TX_DESCRIPTOR_COUNT);
while (descriptor.status == 0)
continue;
return {};
}
void E1000::handle_irq()
{
if (read32(REG_ICR) & ICR_RxQ0)
return;
for (;;) {
uint32_t rx_current = (read32(REG_RDT0) + 1) % E1000_RX_DESCRIPTOR_COUNT;
auto& descriptor = reinterpret_cast<volatile e1000_rx_desc*>(m_rx_descriptor_region->vaddr())[rx_current];
if (!(descriptor.status & 1))
break;
ASSERT_LTE((uint16_t)descriptor.length, E1000_RX_BUFFER_SIZE);
NetworkManager::get().on_receive(BAN::ConstByteSpan {
reinterpret_cast<const uint8_t*>(m_rx_buffer_region->vaddr() + rx_current * E1000_RX_BUFFER_SIZE),
descriptor.length
});
descriptor.status = 0;
write32(REG_RDT0, rx_current);
}
}
}

View File

@ -0,0 +1,43 @@
#include <kernel/Networking/E1000/E1000E.h>
#include <kernel/Timer/Timer.h>
#define E1000E_VENDOR_INTEL 0x8086
#define E1000E_DEVICE_82574 0x10D3
namespace Kernel
{
bool E1000E::probe(PCI::Device& pci_device)
{
if (pci_device.vendor_id() != E1000E_VENDOR_INTEL)
return false;
switch (pci_device.device_id())
{
case E1000E_DEVICE_82574:
return true;
}
return false;
}
BAN::ErrorOr<BAN::RefPtr<E1000E>> E1000E::create(PCI::Device& pci_device)
{
auto e1000e = TRY(BAN::RefPtr<E1000E>::create(pci_device));
TRY(e1000e->initialize());
return e1000e;
}
void E1000E::detect_eeprom()
{
m_has_eerprom = true;
}
uint32_t E1000E::eeprom_read(uint8_t addr)
{
uint32_t tmp;
write32(REG_EERD, ((uint32_t)addr << 2) | 1);
while (!((tmp = read32(REG_EERD)) & (1 << 1)))
continue;
return tmp >> 16;
}
}

View File

@ -0,0 +1,22 @@
#include <BAN/Endianness.h>
#include <kernel/Networking/IPv4.h>
namespace Kernel
{
void add_ipv4_header(BAN::ByteSpan packet, BAN::IPv4Address src_ipv4, BAN::IPv4Address dst_ipv4, uint8_t protocol)
{
auto& header = packet.as<IPv4Header>();
header.version_IHL = 0x45;
header.DSCP_ECN = 0x10;
header.total_length = packet.size();
header.identification = 1;
header.flags_frament = 0x00;
header.time_to_live = 0x40;
header.protocol = protocol;
header.checksum = header.calculate_checksum();
header.src_address = src_ipv4;
header.dst_address = dst_ipv4;
}
}

View File

@ -0,0 +1,50 @@
#include <BAN/Endianness.h>
#include <kernel/FS/DevFS/FileSystem.h>
#include <kernel/Networking/NetworkInterface.h>
#include <sys/sysmacros.h>
#include <string.h>
namespace Kernel
{
static dev_t get_network_rdev_major()
{
static dev_t major = DevFileSystem::get().get_next_dev();
return major;
}
static dev_t get_network_rdev_minor()
{
static dev_t minor = 0;
return minor++;
}
NetworkInterface::NetworkInterface()
: CharacterDevice(0400, 0, 0)
, m_type(Type::Ethernet)
, m_rdev(makedev(get_network_rdev_major(), get_network_rdev_minor()))
{
ASSERT(minor(m_rdev) < 10);
ASSERT(m_type == Type::Ethernet);
strcpy(m_name, "ethx");
m_name[3] = minor(m_rdev) + '0';
}
size_t NetworkInterface::interface_header_size() const
{
ASSERT(m_type == Type::Ethernet);
return sizeof(EthernetHeader);
}
void NetworkInterface::add_interface_header(BAN::ByteSpan packet, BAN::MACAddress destination)
{
ASSERT(m_type == Type::Ethernet);
auto& header = packet.as<EthernetHeader>();
header.dst_mac = destination;
header.src_mac = get_mac_address();
header.ether_type = 0x0800;
}
}

View File

@ -0,0 +1,159 @@
#include <BAN/Endianness.h>
#include <BAN/UniqPtr.h>
#include <kernel/FS/DevFS/FileSystem.h>
#include <kernel/Networking/E1000/E1000.h>
#include <kernel/Networking/E1000/E1000E.h>
#include <kernel/Networking/IPv4.h>
#include <kernel/Networking/NetworkManager.h>
#include <kernel/Networking/UDPSocket.h>
namespace Kernel
{
static BAN::UniqPtr<NetworkManager> s_instance;
BAN::ErrorOr<void> NetworkManager::initialize()
{
ASSERT(!s_instance);
NetworkManager* manager_ptr = new NetworkManager();
if (manager_ptr == nullptr)
return BAN::Error::from_errno(ENOMEM);
auto manager = BAN::UniqPtr<NetworkManager>::adopt(manager_ptr);
manager->m_arp_table = TRY(ARPTable::create());
TRY(manager->TmpFileSystem::initialize(0777, 0, 0));
s_instance = BAN::move(manager);
return {};
}
NetworkManager& NetworkManager::get()
{
ASSERT(s_instance);
return *s_instance;
}
NetworkManager::NetworkManager()
: TmpFileSystem(128)
{ }
BAN::ErrorOr<void> NetworkManager::add_interface(PCI::Device& pci_device)
{
BAN::RefPtr<NetworkInterface> interface;
switch (pci_device.subclass())
{
case 0x00:
if (E1000::probe(pci_device))
{
interface = TRY(E1000::create(pci_device));
break;
}
if (E1000E::probe(pci_device))
{
interface = TRY(E1000E::create(pci_device));
break;
}
// fall through
default:
dprintln("unsupported network controller (pci {2H}.{2H}.{2H})", pci_device.class_code(), pci_device.subclass(), pci_device.prog_if());
dprintln(" vendor id: {4H}", pci_device.vendor_id());
dprintln(" device id: {4H}", pci_device.device_id());
return BAN::Error::from_errno(ENOTSUP);
}
ASSERT(interface);
TRY(m_interfaces.push_back(interface));
DevFileSystem::get().add_device(interface);
return {};
}
BAN::ErrorOr<BAN::RefPtr<NetworkSocket>> NetworkManager::create_socket(SocketType type, mode_t mode, uid_t uid, gid_t gid)
{
ASSERT((mode & Inode::Mode::TYPE_MASK) == 0);
if (type != SocketType::DGRAM)
return BAN::Error::from_errno(EPROTOTYPE);
auto udp_socket = TRY(UDPSocket::create(mode | Inode::Mode::IFSOCK, uid, gid));
return BAN::RefPtr<NetworkSocket>(udp_socket);
}
void NetworkManager::unbind_socket(uint16_t port, BAN::RefPtr<NetworkSocket> socket)
{
if (m_bound_sockets.contains(port))
{
ASSERT(m_bound_sockets[port].valid());
ASSERT(m_bound_sockets[port].lock() == socket);
m_bound_sockets.remove(port);
}
NetworkManager::get().remove_from_cache(socket);
}
BAN::ErrorOr<void> NetworkManager::bind_socket(uint16_t port, BAN::RefPtr<NetworkSocket> socket)
{
if (m_interfaces.empty())
return BAN::Error::from_errno(EADDRNOTAVAIL);
if (port != NetworkSocket::PORT_NONE)
{
if (m_bound_sockets.contains(port))
return BAN::Error::from_errno(EADDRINUSE);
TRY(m_bound_sockets.insert(port, socket));
}
// FIXME: actually determine proper interface
auto interface = m_interfaces.front();
socket->bind_interface_and_port(interface.ptr(), port);
return {};
}
void NetworkManager::on_receive(BAN::ConstByteSpan packet)
{
auto ethernet_header = packet.as<const EthernetHeader>();
switch (ethernet_header.ether_type)
{
case EtherType::ARP:
{
m_arp_table->handle_arp_packet(packet.slice(sizeof(EthernetHeader)));
break;
}
case EtherType::IPv4:
{
auto ipv4 = packet.slice(sizeof(EthernetHeader));
auto& ipv4_header = ipv4.as<const IPv4Header>();
auto src_ipv4 = ipv4_header.src_address;
switch (ipv4_header.protocol)
{
case NetworkProtocol::UDP:
{
auto udp = ipv4.slice(sizeof(IPv4Header));
auto& udp_header = udp.as<const UDPHeader>();
uint16_t src_port = udp_header.src_port;
uint16_t dst_port = udp_header.dst_port;
if (!m_bound_sockets.contains(dst_port))
{
dprintln("no one is listening on port {}", dst_port);
return;
}
auto raw = udp.slice(8);
m_bound_sockets[dst_port].lock()->add_packet(raw, src_ipv4, src_port);
break;
}
default:
dprintln("Unknown network protocol 0x{2H}", ipv4_header.protocol);
break;
}
break;
}
default:
dprintln("Unknown EtherType 0x{4H}", (uint16_t)ethernet_header.ether_type);
break;
}
}
}

View File

@ -0,0 +1,185 @@
#include <kernel/Networking/IPv4.h>
#include <kernel/Networking/NetworkManager.h>
#include <kernel/Networking/NetworkSocket.h>
#include <net/if.h>
namespace Kernel
{
NetworkSocket::NetworkSocket(mode_t mode, uid_t uid, gid_t gid)
// FIXME: what the fuck is this
: TmpInode(
NetworkManager::get(),
MUST(NetworkManager::get().allocate_inode(create_inode_info(mode, uid, gid))),
create_inode_info(mode, uid, gid)
)
{ }
NetworkSocket::~NetworkSocket()
{
}
void NetworkSocket::on_close_impl()
{
if (m_interface)
NetworkManager::get().unbind_socket(m_port, this);
}
void NetworkSocket::bind_interface_and_port(NetworkInterface* interface, uint16_t port)
{
ASSERT(!m_interface);
ASSERT(interface);
m_interface = interface;
m_port = port;
}
BAN::ErrorOr<void> NetworkSocket::bind_impl(const sockaddr* address, socklen_t address_len)
{
if (address_len != sizeof(sockaddr_in))
return BAN::Error::from_errno(EINVAL);
auto* addr_in = reinterpret_cast<const sockaddr_in*>(address);
return NetworkManager::get().bind_socket(addr_in->sin_port, this);
}
BAN::ErrorOr<ssize_t> NetworkSocket::sendto_impl(const sys_sendto_t* arguments)
{
if (arguments->dest_len != sizeof(sockaddr_in))
return BAN::Error::from_errno(EINVAL);
if (arguments->flags)
{
dprintln("flags not supported");
return BAN::Error::from_errno(ENOTSUP);
}
if (!m_interface)
TRY(NetworkManager::get().bind_socket(PORT_NONE, this));
auto* destination = reinterpret_cast<const sockaddr_in*>(arguments->dest_addr);
auto message = BAN::ConstByteSpan((const uint8_t*)arguments->message, arguments->length);
uint16_t dst_port = destination->sin_port;
if (dst_port == PORT_NONE)
return BAN::Error::from_errno(EINVAL);
auto dst_addr = BAN::IPv4Address(destination->sin_addr.s_addr);
auto dst_mac = TRY(NetworkManager::get().arp_table().get_mac_from_ipv4(*m_interface, dst_addr));
const size_t interface_header_offset = 0;
const size_t interface_header_size = m_interface->interface_header_size();
const size_t ipv4_header_offset = interface_header_offset + interface_header_size;
const size_t ipv4_header_size = sizeof(IPv4Header);
const size_t protocol_header_offset = ipv4_header_offset + ipv4_header_size;
const size_t protocol_header_size = this->protocol_header_size();
const size_t payload_offset = protocol_header_offset + protocol_header_size;
const size_t payload_size = message.size();
BAN::Vector<uint8_t> full_packet;
TRY(full_packet.resize(payload_offset + payload_size));
BAN::ByteSpan packet_bytespan { full_packet.span() };
memcpy(full_packet.data() + payload_offset, message.data(), payload_size);
add_protocol_header(packet_bytespan.slice(protocol_header_offset), m_port, dst_port);
add_ipv4_header(packet_bytespan.slice(ipv4_header_offset), m_interface->get_ipv4_address(), dst_addr, protocol());
m_interface->add_interface_header(packet_bytespan.slice(interface_header_offset), dst_mac);
TRY(m_interface->send_raw_bytes(packet_bytespan));
return arguments->length;
}
BAN::ErrorOr<ssize_t> NetworkSocket::recvfrom_impl(sys_recvfrom_t* arguments)
{
sockaddr_in* sender_addr = nullptr;
if (arguments->address)
{
ASSERT(arguments->address_len);
if (*arguments->address_len < (socklen_t)sizeof(sockaddr_in))
*arguments->address_len = 0;
else
{
sender_addr = reinterpret_cast<sockaddr_in*>(arguments->address);
*arguments->address_len = sizeof(sockaddr_in);
}
}
if (!m_interface)
{
dprintln("No interface bound");
return BAN::Error::from_errno(EINVAL);
}
if (m_port == PORT_NONE)
{
dprintln("No port bound");
return BAN::Error::from_errno(EINVAL);
}
return TRY(read_packet(BAN::ByteSpan { reinterpret_cast<uint8_t*>(arguments->buffer), arguments->length }, sender_addr));
}
BAN::ErrorOr<long> NetworkSocket::ioctl_impl(int request, void* arg)
{
if (!arg)
{
dprintln("No argument provided");
return BAN::Error::from_errno(EINVAL);
}
if (m_interface == nullptr)
{
dprintln("No interface bound");
return BAN::Error::from_errno(EADDRNOTAVAIL);
}
auto* ifreq = reinterpret_cast<struct ifreq*>(arg);
switch (request)
{
case SIOCGIFADDR:
{
auto ipv4_address = m_interface->get_ipv4_address();
ifreq->ifr_ifru.ifru_addr.sa_family = AF_INET;
memcpy(ifreq->ifr_ifru.ifru_addr.sa_data, &ipv4_address, sizeof(ipv4_address));
return 0;
}
case SIOCSIFADDR:
{
if (ifreq->ifr_ifru.ifru_addr.sa_family != AF_INET)
return BAN::Error::from_errno(EADDRNOTAVAIL);
BAN::IPv4Address ipv4_address { *reinterpret_cast<uint32_t*>(ifreq->ifr_ifru.ifru_addr.sa_data) };
m_interface->set_ipv4_address(ipv4_address);
dprintln("IPv4 address set to {}", m_interface->get_ipv4_address());
return 0;
}
case SIOCGIFNETMASK:
{
auto netmask_address = m_interface->get_netmask();
ifreq->ifr_ifru.ifru_netmask.sa_family = AF_INET;
memcpy(ifreq->ifr_ifru.ifru_netmask.sa_data, &netmask_address, sizeof(netmask_address));
return 0;
}
case SIOCSIFNETMASK:
{
if (ifreq->ifr_ifru.ifru_netmask.sa_family != AF_INET)
return BAN::Error::from_errno(EADDRNOTAVAIL);
BAN::IPv4Address netmask { *reinterpret_cast<uint32_t*>(ifreq->ifr_ifru.ifru_netmask.sa_data) };
m_interface->set_netmask(netmask);
dprintln("Netmask set to {}", m_interface->get_netmask());
return 0;
}
case SIOCGIFHWADDR:
{
auto mac_address = m_interface->get_mac_address();
ifreq->ifr_ifru.ifru_hwaddr.sa_family = AF_INET;
memcpy(ifreq->ifr_ifru.ifru_hwaddr.sa_data, &mac_address, sizeof(mac_address));
return 0;
}
default:
return BAN::Error::from_errno(EINVAL);
}
}
}

View File

@ -0,0 +1,101 @@
#include <kernel/Memory/Heap.h>
#include <kernel/Networking/UDPSocket.h>
#include <kernel/Thread.h>
namespace Kernel
{
BAN::ErrorOr<BAN::RefPtr<UDPSocket>> UDPSocket::create(mode_t mode, uid_t uid, gid_t gid)
{
auto socket = TRY(BAN::RefPtr<UDPSocket>::create(mode, uid, gid));
socket->m_packet_buffer = TRY(VirtualRange::create_to_vaddr_range(
PageTable::kernel(),
KERNEL_OFFSET,
~(uintptr_t)0,
packet_buffer_size,
PageTable::Flags::ReadWrite | PageTable::Flags::Present,
true
));
return socket;
}
UDPSocket::UDPSocket(mode_t mode, uid_t uid, gid_t gid)
: NetworkSocket(mode, uid, gid)
{ }
void UDPSocket::add_protocol_header(BAN::ByteSpan packet, uint16_t src_port, uint16_t dst_port)
{
auto& header = packet.as<UDPHeader>();
header.src_port = src_port;
header.dst_port = dst_port;
header.length = packet.size();
header.checksum = 0;
}
void UDPSocket::add_packet(BAN::ConstByteSpan packet, BAN::IPv4Address sender_addr, uint16_t sender_port)
{
CriticalScope _;
if (m_packets.full())
{
dprintln("Packet buffer full, dropping packet");
return;
}
if (!m_packets.empty() && m_packet_total_size > m_packet_buffer->size())
{
dprintln("Packet buffer full, dropping packet");
return;
}
void* buffer = reinterpret_cast<void*>(m_packet_buffer->vaddr() + m_packet_total_size);
memcpy(buffer, packet.data(), packet.size());
m_packets.push(PacketInfo {
.sender_addr = sender_addr,
.sender_port = sender_port,
.packet_size = packet.size()
});
m_packet_total_size += packet.size();
m_semaphore.unblock();
}
BAN::ErrorOr<size_t> UDPSocket::read_packet(BAN::ByteSpan buffer, sockaddr_in* sender_addr)
{
while (m_packets.empty())
TRY(Thread::current().block_or_eintr(m_semaphore));
CriticalScope _;
if (m_packets.empty())
return read_packet(buffer, sender_addr);
auto packet_info = m_packets.front();
m_packets.pop();
size_t nread = BAN::Math::min<size_t>(packet_info.packet_size, buffer.size());
memcpy(
buffer.data(),
(const void*)m_packet_buffer->vaddr(),
nread
);
memmove(
(void*)m_packet_buffer->vaddr(),
(void*)(m_packet_buffer->vaddr() + packet_info.packet_size),
m_packet_total_size - packet_info.packet_size
);
m_packet_total_size -= packet_info.packet_size;
if (sender_addr)
{
sender_addr->sin_family = AF_INET;
sender_addr->sin_port = packet_info.sender_port;
sender_addr->sin_addr.s_addr = packet_info.sender_addr.as_u32();
}
return nread;
}
}

View File

@ -1,8 +1,10 @@
#include <kernel/FS/Pipe.h>
#include <kernel/FS/VirtualFileSystem.h>
#include <kernel/Networking/NetworkManager.h>
#include <kernel/OpenFileDescriptorSet.h>
#include <fcntl.h>
#include <sys/socket.h>
namespace Kernel
{
@ -76,6 +78,38 @@ namespace Kernel
return fd;
}
BAN::ErrorOr<int> OpenFileDescriptorSet::socket(int domain, int type, int protocol)
{
using SocketType = NetworkManager::SocketType;
if (domain != AF_INET)
return BAN::Error::from_errno(EAFNOSUPPORT);
if (protocol != 0)
return BAN::Error::from_errno(EPROTONOSUPPORT);
SocketType sock_type;
switch (type)
{
case SOCK_STREAM:
sock_type = SocketType::STREAM;
break;
case SOCK_DGRAM:
sock_type = SocketType::DGRAM;
break;
case SOCK_SEQPACKET:
sock_type = SocketType::SEQPACKET;
break;
default:
return BAN::Error::from_errno(EPROTOTYPE);
}
auto socket = TRY(NetworkManager::get().create_socket(sock_type, 0777, m_credentials.euid(), m_credentials.egid()));
int fd = TRY(get_free_fd());
m_open_files[fd] = TRY(BAN::RefPtr<OpenFileDescription>::create(socket, "no-path"sv, 0, O_RDWR));
return fd;
}
BAN::ErrorOr<void> OpenFileDescriptorSet::pipe(int fds[2])
{
TRY(get_free_fd_pair(fds));
@ -242,6 +276,8 @@ namespace Kernel
if (m_open_files[fd]->flags & O_WRONLY && m_open_files[fd]->inode->is_pipe())
((Pipe*)m_open_files[fd]->inode.ptr())->close_writing();
m_open_files[fd]->inode->on_close();
m_open_files[fd].clear();
return {};

View File

@ -2,7 +2,7 @@
#include <kernel/IO.h>
#include <kernel/Memory/PageTable.h>
#include <kernel/MMIO.h>
#include <kernel/Networking/E1000.h>
#include <kernel/Networking/NetworkManager.h>
#include <kernel/PCI.h>
#include <kernel/Storage/ATA/AHCI/Controller.h>
#include <kernel/Storage/ATA/ATAController.h>
@ -183,17 +183,8 @@ namespace Kernel::PCI
}
case 0x02:
{
switch (pci_device.subclass())
{
case 0x00:
if (E1000::probe(pci_device))
if (auto res = E1000::create(pci_device); res.is_error())
dprintln("E1000: {}", res.error());
break;
default:
dprintln("unsupported ethernet device (pci {2H}.{2H}.{2H})", pci_device.class_code(), pci_device.subclass(), pci_device.prog_if());
break;
}
if (auto res = NetworkManager::get().add_interface(pci_device); res.is_error())
dprintln("{}", res.error());
break;
}
default:
@ -259,7 +250,7 @@ namespace Kernel::PCI
device.write_word(PCI_REG_COMMAND, command);
#if DEBUG_PCI
dprintln("created BAR region for PCI {}:{}.{}",
dprintln("created BAR region for PCI {2H}:{2H}.{2H}",
device.bus(),
device.dev(),
device.func()
@ -493,12 +484,12 @@ namespace Kernel::PCI
return {};
}
static uint64_t msi_message_address()
static constexpr uint64_t msi_message_address()
{
return 0xFEE00000;
}
static uint32_t msi_message_data(uint8_t irq)
static constexpr uint32_t msi_message_data(uint8_t irq)
{
return (IRQ_VECTOR_BASE + irq) & 0xFF;
}

View File

@ -895,6 +895,70 @@ namespace Kernel
return 0;
}
BAN::ErrorOr<long> Process::sys_socket(int domain, int type, int protocol)
{
LockGuard _(m_lock);
return TRY(m_open_file_descriptors.socket(domain, type, protocol));
}
BAN::ErrorOr<long> Process::sys_bind(int socket, const sockaddr* address, socklen_t address_len)
{
LockGuard _(m_lock);
TRY(validate_pointer_access(address, address_len));
auto inode = TRY(m_open_file_descriptors.inode_of(socket));
if (!inode->mode().ifsock())
return BAN::Error::from_errno(ENOTSOCK);
TRY(inode->bind(address, address_len));
return 0;
}
BAN::ErrorOr<long> Process::sys_sendto(const sys_sendto_t* arguments)
{
LockGuard _(m_lock);
TRY(validate_pointer_access(arguments, sizeof(sys_sendto_t)));
TRY(validate_pointer_access(arguments->message, arguments->length));
TRY(validate_pointer_access(arguments->dest_addr, arguments->dest_len));
auto inode = TRY(m_open_file_descriptors.inode_of(arguments->socket));
if (!inode->mode().ifsock())
return BAN::Error::from_errno(ENOTSOCK);
return TRY(inode->sendto(arguments));
}
BAN::ErrorOr<long> Process::sys_recvfrom(sys_recvfrom_t* arguments)
{
if (arguments->address && !arguments->address_len)
return BAN::Error::from_errno(EINVAL);
if (!arguments->address && arguments->address_len)
return BAN::Error::from_errno(EINVAL);
LockGuard _(m_lock);
TRY(validate_pointer_access(arguments, sizeof(sys_recvfrom_t)));
TRY(validate_pointer_access(arguments->buffer, arguments->length));
if (arguments->address)
{
TRY(validate_pointer_access(arguments->address_len, sizeof(*arguments->address_len)));
TRY(validate_pointer_access(arguments->address, *arguments->address_len));
}
auto inode = TRY(m_open_file_descriptors.inode_of(arguments->socket));
if (!inode->mode().ifsock())
return BAN::Error::from_errno(ENOTSOCK);
return TRY(inode->recvfrom(arguments));
}
BAN::ErrorOr<long> Process::sys_ioctl(int fildes, int request, void* arg)
{
LockGuard _(m_lock);
auto inode = TRY(m_open_file_descriptors.inode_of(fildes));
return TRY(inode->ioctl(request, arg));
}
BAN::ErrorOr<long> Process::sys_pipe(int fildes[2])
{
LockGuard _(m_lock);

View File

@ -5,7 +5,7 @@
#include <kernel/InterruptController.h>
#include <kernel/Process.h>
#include <kernel/Scheduler.h>
#include <kernel/Timer/PIT.h>
#include <kernel/Timer/Timer.h>
#define SCHEDULER_VERIFY_STACK 1
#define SCHEDULER_VERIFY_INTERRUPT_STATE 1
@ -116,12 +116,11 @@ namespace Kernel
uint64_t current_time = SystemTimer::get().ms_since_boot();
while (!m_sleeping_threads.empty() && m_sleeping_threads.front().wake_time <= current_time)
{
Thread* thread = m_sleeping_threads.front().thread;
m_sleeping_threads.remove(m_sleeping_threads.begin());
// This should work as we released enough memory from sleeping thread
static_assert(sizeof(ActiveThread) == sizeof(SleepingThread));
MUST(m_active_threads.emplace_back(thread));
m_sleeping_threads.move_element_to_other_linked_list(
m_active_threads,
m_active_threads.end(),
m_sleeping_threads.begin()
);
}
}
@ -286,23 +285,26 @@ namespace Kernel
ASSERT(m_current_thread);
Thread* sleeping = m_current_thread->thread;
if (save_current_thread())
{
ENABLE_INTERRUPTS();
return;
}
remove_and_advance_current_thread();
auto it = m_sleeping_threads.begin();
for (; it != m_sleeping_threads.end(); it++)
if (wake_time <= it->wake_time)
break;
// This should work as we released enough memory from active thread
static_assert(sizeof(ActiveThread) == sizeof(SleepingThread));
MUST(m_sleeping_threads.emplace(it, sleeping, wake_time));
m_current_thread->wake_time = wake_time;
m_active_threads.move_element_to_other_linked_list(
m_sleeping_threads,
it,
m_current_thread
);
m_current_thread = {};
advance_current_thread();
execute_current_thread();
ASSERT_NOT_REACHED();
@ -315,18 +317,21 @@ namespace Kernel
ASSERT(m_current_thread);
Thread* blocking = m_current_thread->thread;
if (save_current_thread())
{
ENABLE_INTERRUPTS();
return;
}
remove_and_advance_current_thread();
// This should work as we released enough memory from active thread
static_assert(sizeof(ActiveThread) == sizeof(BlockingThread));
MUST(m_blocking_threads.emplace_back(blocking, semaphore));
m_current_thread->semaphore = semaphore;
m_active_threads.move_element_to_other_linked_list(
m_blocking_threads,
m_blocking_threads.end(),
m_current_thread
);
m_current_thread = {};
advance_current_thread();
execute_current_thread();
ASSERT_NOT_REACHED();
@ -340,12 +345,11 @@ namespace Kernel
{
if (it->semaphore == semaphore)
{
auto thread = it->thread;
it = m_blocking_threads.remove(it);
// This should work as we released enough memory from active thread
static_assert(sizeof(ActiveThread) == sizeof(BlockingThread));
MUST(m_active_threads.emplace_back(thread));
it = m_blocking_threads.move_element_to_other_linked_list(
m_active_threads,
m_active_threads.end(),
it
);
}
else
{
@ -362,13 +366,11 @@ namespace Kernel
{
if (it->thread->tid() == tid)
{
Thread* thread = it->thread;
m_blocking_threads.remove(it);
// This should work as we released enough memory from active thread
static_assert(sizeof(ActiveThread) == sizeof(BlockingThread));
MUST(m_active_threads.emplace_back(thread));
m_blocking_threads.move_element_to_other_linked_list(
m_active_threads,
m_active_threads.end(),
it
);
return;
}
}
@ -377,13 +379,11 @@ namespace Kernel
{
if (it->thread->tid() == tid)
{
Thread* thread = it->thread;
m_sleeping_threads.remove(it);
// This should work as we released enough memory from active thread
static_assert(sizeof(ActiveThread) == sizeof(BlockingThread));
MUST(m_active_threads.emplace_back(thread));
m_sleeping_threads.move_element_to_other_linked_list(
m_active_threads,
m_active_threads.end(),
it
);
return;
}
}

View File

@ -213,6 +213,21 @@ namespace Kernel
case SYS_LOAD_KEYMAP:
ret = Process::current().sys_load_keymap((const char*)arg1);
break;
case SYS_SOCKET:
ret = Process::current().sys_socket((int)arg1, (int)arg2, (int)arg3);
break;
case SYS_BIND:
ret = Process::current().sys_bind((int)arg1, (const sockaddr*)arg2, (socklen_t)arg3);
break;
case SYS_SENDTO:
ret = Process::current().sys_sendto((const sys_sendto_t*)arg1);
break;
case SYS_RECVFROM:
ret = Process::current().sys_recvfrom((sys_recvfrom_t*)arg1);
break;
case SYS_IOCTL:
ret = Process::current().sys_ioctl((int)arg1, (int)arg2, (void*)arg3);
break;
default:
dwarnln("Unknown syscall {}", syscall);
break;

View File

@ -15,6 +15,7 @@
#include <kernel/Memory/Heap.h>
#include <kernel/Memory/kmalloc.h>
#include <kernel/Memory/PageTable.h>
#include <kernel/Networking/NetworkManager.h>
#include <kernel/PCI.h>
#include <kernel/PIC.h>
#include <kernel/Process.h>
@ -187,6 +188,8 @@ static void init2(void*)
if (auto res = PS2Controller::initialize(); res.is_error())
dprintln("{}", res.error());
MUST(NetworkManager::initialize());
// NOTE: PCI devices are the last ones to be initialized
// so other devices can reserve predefined interrupts
PCI::PCIManager::initialize();

View File

@ -17,8 +17,10 @@ set(LIBC_SOURCES
stdlib.cpp
string.cpp
strings.cpp
stropts.cpp
sys/banan-os.cpp
sys/mman.cpp
sys/socket.cpp
sys/stat.cpp
sys/wait.cpp
termios.cpp

View File

@ -5,6 +5,8 @@
#include <sys/cdefs.h>
#include <sys/socket.h>
#define IF_NAMESIZE 16
__BEGIN_DECLS
@ -15,6 +17,22 @@ struct if_nameindex
char* if_name; /* Null-terminated name of the interface. */
};
struct ifreq
{
union {
struct sockaddr ifru_addr;
struct sockaddr ifru_netmask;
struct sockaddr ifru_hwaddr;
unsigned char __min_storage[sizeof(sockaddr) + 6];
} ifr_ifru;
};
#define SIOCGIFADDR 1 /* Get interface address */
#define SIOCSIFADDR 2 /* Set interface address */
#define SIOCGIFNETMASK 3 /* Get network mask */
#define SIOCSIFNETMASK 4 /* Set network mask */
#define SIOCGIFHWADDR 5 /* Get hardware address */
void if_freenameindex(struct if_nameindex* ptr);
char* if_indextoname(unsigned ifindex, char* ifname);
struct if_nameindex* if_nameindex(void);

153
libc/include/stropts.h Normal file
View File

@ -0,0 +1,153 @@
#ifndef _STROPTS_H
#define _STROPTS_H 1
// https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/stropts.h.html
#include <sys/cdefs.h>
__BEGIN_DECLS
#define __need_uid_t
#define __need_gid_t
#include <sys/types.h>
typedef __UINT32_TYPE__ t_uscalar_t;
typedef __INT32_TYPE__ t_scalar_t;
struct bandinfo
{
int bi_flag; /* Flushing type. */
unsigned char bi_pri; /* Priority band. */
};
struct strbuf
{
char* buf; /* Pointer to buffer. */
int len; /* Length of data. */
int maxlen; /* Maximum buffer length. */
};
struct strpeek
{
struct strbuf ctlbuf; /* The control portion of the message. */
struct strbuf databuf; /* The data portion of the message. */
t_uscalar_t flags; /* RS_HIPRI or 0. */
};
struct strfdinsert
{
struct strbuf ctlbuf; /* The control portion of the message. */
struct strbuf databuf; /* The data portion of the message. */
int fildes; /* File descriptor of the other STREAM. */
t_uscalar_t flags; /* RS_HIPRI or 0. */
int offset; /* Relative location of the stored value. */
};
struct strioctl
{
int ic_cmd; /* ioctl() command. */
char* ic_dp; /* Pointer to buffer. */
int ic_len; /* Length of data. */
int ic_timout; /* Timeout for response. */
};
struct strrecvfd
{
int fd; /* Received file descriptor. */
gid_t gid; /* GID of sender. */
uid_t uid; /* UID of sender. */
};
#define FMNAMESZ 128
struct str_mlist
{
char l_name[FMNAMESZ+1]; /* A STREAMS module name. */
};
struct str_list
{
struct str_mlist* sl_modlist; /* STREAMS module names. */
int sl_nmods; /* Number of STREAMS module names. */
};
#define I_ATMARK 1
#define I_CANPUT 2
#define I_CKBAND 3
#define I_FDINSERT 4
#define I_FIND 5
#define I_FLUSH 6
#define I_FLUSHBAND 7
#define I_GETBAND 8
#define I_GETCLTIME 9
#define I_GETSIG 10
#define I_GRDOPT 11
#define I_GWROPT 12
#define I_LINK 13
#define I_LIST 14
#define I_LOOK 15
#define I_NREAD 16
#define I_PEEK 17
#define I_PLINK 18
#define I_POP 19
#define I_PUNLINK 20
#define I_PUSH 21
#define I_RECVFD 22
#define I_SENDFD 23
#define I_SETCLTIME 24
#define I_SETSIG 25
#define I_SRDOPT 26
#define I_STR 27
#define I_SWROPT 28
#define I_UNLINK 29
#define FLUSHR 1
#define FLUSHRW 2
#define FLUSHW 3
#define S_BANDURG 1
#define S_ERROR 2
#define S_HANGUP 3
#define S_HIPRI 4
#define S_INPUT 5
#define S_MSG 6
#define S_OUTPUT 7
#define S_RDBAND 8
#define S_RDNORM 9
#define S_WRBAND 10
#define S_WRNORM 11
#define RS_HIPRI 1
#define RMSGD 1
#define RMSGN 2
#define RNORM 3
#define RPROTDAT 4
#define RPROTDIS 5
#define RPROTNORM 6
#define SNDZERO 1
#define ANYMARK 1
#define LASTMARK 2
#define MUXID_ALL 1
#define MORECTL 1
#define MOREDATA 2
#define MSG_ANY 3
#define MSG_BAND 4
#define MSG_HIPRI 5
int fattach(int, const char*);
int fdetach(const char*);
int getmsg(int, struct strbuf* __restrict, struct strbuf* __restrict, int* __restrict);
int getpmsg(int, struct strbuf* __restrict, struct strbuf* __restrict, int* __restrict, int* __restrict);
int ioctl(int, int, ...);
int isastream(int);
int putmsg(int, const struct strbuf*, const struct strbuf*, int);
int putpmsg(int, const struct strbuf*, const struct strbuf*, int, int);
__END_DECLS
#endif

View File

@ -105,6 +105,26 @@ struct linger
#define SHUT_WR 0x02
#define SHUT_RDWR (SHUT_RD | SHUT_WR)
struct sys_sendto_t
{
int socket;
const void* message;
size_t length;
int flags;
const struct sockaddr* dest_addr;
socklen_t dest_len;
};
struct sys_recvfrom_t
{
int socket;
void* buffer;
size_t length;
int flags;
struct sockaddr* address;
socklen_t* address_len;
};
int accept(int socket, struct sockaddr* __restrict address, socklen_t* __restrict address_len);
int bind(int socket, const struct sockaddr* address, socklen_t address_len);
int connect(int socket, const struct sockaddr* address, socklen_t address_len);

View File

@ -63,6 +63,11 @@ __BEGIN_DECLS
#define SYS_PREAD 62
#define SYS_CHOWN 63
#define SYS_LOAD_KEYMAP 64
#define SYS_SOCKET 65
#define SYS_BIND 66
#define SYS_SENDTO 67
#define SYS_RECVFROM 68
#define SYS_IOCTL 69
__END_DECLS

14
libc/stropts.cpp Normal file
View File

@ -0,0 +1,14 @@
#include <stdarg.h>
#include <stropts.h>
#include <sys/syscall.h>
#include <unistd.h>
int ioctl(int fildes, int request, ...)
{
va_list args;
va_start(args, request);
void* extra = va_arg(args, void*);
va_end(args);
return syscall(SYS_IOCTL, fildes, request, extra);
}

40
libc/sys/socket.cpp Normal file
View File

@ -0,0 +1,40 @@
#include <sys/socket.h>
#include <sys/syscall.h>
#include <unistd.h>
int bind(int socket, const struct sockaddr* address, socklen_t address_len)
{
return syscall(SYS_BIND, socket, address, address_len);
}
ssize_t recvfrom(int socket, void* __restrict buffer, size_t length, int flags, struct sockaddr* __restrict address, socklen_t* __restrict address_len)
{
sys_recvfrom_t arguments {
.socket = socket,
.buffer = buffer,
.length = length,
.flags = flags,
.address = address,
.address_len = address_len
};
return syscall(SYS_RECVFROM, &arguments);
}
ssize_t sendto(int socket, const void* message, size_t length, int flags, const struct sockaddr* dest_addr, socklen_t dest_len)
{
sys_sendto_t arguments {
.socket = socket,
.message = message,
.length = length,
.flags = flags,
.dest_addr = dest_addr,
.dest_len = dest_len
};
return syscall(SYS_SENDTO, &arguments);
}
int socket(int domain, int type, int protocol)
{
return syscall(SYS_SOCKET, domain, type, protocol);
}

View File

@ -20,9 +20,11 @@ else
fi
qemu-system-$BANAN_ARCH \
-m 128 \
-m 1G \
-smp 2 \
$BIOS_ARGS \
-drive format=raw,id=disk,file=${BANAN_DISK_IMAGE_PATH},if=none \
-device e1000e,netdev=net \
-netdev user,id=net \
$DISK_ARGS \
$@ \

View File

@ -8,6 +8,7 @@ set(USERSPACE_PROJECTS
chmod
cp
dd
dhcp-client
echo
id
init

View File

@ -0,0 +1,16 @@
cmake_minimum_required(VERSION 3.26)
project(dhcp-client CXX)
set(SOURCES
main.cpp
)
add_executable(dhcp-client ${SOURCES})
target_compile_options(dhcp-client PUBLIC -O2 -g)
target_link_libraries(dhcp-client PUBLIC libc)
add_custom_target(dhcp-client-install
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/dhcp-client ${BANAN_BIN}/
DEPENDS dhcp-client
)

View File

@ -0,0 +1,380 @@
#include <BAN/Endianness.h>
#include <BAN/IPv4.h>
#include <BAN/MAC.h>
#include <BAN/Vector.h>
#include <fcntl.h>
#include <net/if.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stropts.h>
#include <sys/socket.h>
#define DEBUG_DHCP 0
struct DHCPPacket
{
uint8_t op;
uint8_t htype { 0x01 };
uint8_t hlen { 0x06 };
uint8_t hops { 0x00 };
BAN::NetworkEndian<uint32_t> xid { 0x3903F326 };
BAN::NetworkEndian<uint16_t> secs { 0x0000 };
BAN::NetworkEndian<uint16_t> flags { 0x0000 };
BAN::NetworkEndian<uint32_t> ciaddr { 0 };
BAN::NetworkEndian<uint32_t> yiaddr { 0 };
BAN::NetworkEndian<uint32_t> siaddr { 0 };
BAN::NetworkEndian<uint32_t> giaddr { 0 };
BAN::MACAddress chaddr;
uint8_t padding[10] {};
uint8_t legacy[192] {};
BAN::NetworkEndian<uint32_t> magic_cookie { 0x63825363 };
uint8_t options[0x100];
};
static_assert(offsetof(DHCPPacket, options) == 240);
enum DHCPType
{
SubnetMask = 1,
Router = 3,
DomainNameServer = 6,
RequestedIPv4Address= 50,
DHCPMessageType = 53,
ServerIdentifier = 54,
ParameterRequestList = 55,
End = 255,
};
enum DHCPMessageType
{
INVALID = 0,
DHCPDISCOVER = 1,
DHCPOFFER = 2,
DHCPREQUEST = 3,
DHCPDECLINE = 4,
DHCPACK = 5,
};
BAN::MACAddress get_mac_address(int socket)
{
ifreq ifreq;
if (ioctl(socket, SIOCGIFHWADDR, &ifreq) == -1)
{
perror("ioctl");
exit(1);
}
BAN::MACAddress mac_address;
memcpy(&mac_address, ifreq.ifr_ifru.ifru_hwaddr.sa_data, sizeof(mac_address));
return mac_address;
}
void update_ipv4_info(int socket, BAN::IPv4Address address, BAN::IPv4Address subnet)
{
{
ifreq ifreq;
ifreq.ifr_ifru.ifru_addr.sa_family = AF_INET;
*(uint32_t*)ifreq.ifr_ifru.ifru_addr.sa_data = address.as_u32();
if (ioctl(socket, SIOCSIFADDR, &ifreq) == -1)
{
perror("ioctl");
exit(1);
}
}
{
ifreq ifreq;
ifreq.ifr_ifru.ifru_netmask.sa_family = AF_INET;
*(uint32_t*)ifreq.ifr_ifru.ifru_netmask.sa_data = subnet.as_u32();
if (ioctl(socket, SIOCSIFNETMASK, &ifreq) == -1)
{
perror("ioctl");
exit(1);
}
}
}
void send_dhcp_packet(int socket, const DHCPPacket& dhcp_packet, BAN::IPv4Address server_ipv4)
{
sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_port = 67;
server_addr.sin_addr.s_addr = server_ipv4.as_u32();;
if (sendto(socket, &dhcp_packet, sizeof(DHCPPacket), 0, (sockaddr*)&server_addr, sizeof(server_addr)) == -1)
{
perror("sendto");
exit(1);
}
}
void send_dhcp_discover(int socket, BAN::MACAddress mac_address)
{
DHCPPacket dhcp_packet;
dhcp_packet.op = 0x01;
dhcp_packet.chaddr = mac_address;
size_t idx = 0;
dhcp_packet.options[idx++] = DHCPMessageType;
dhcp_packet.options[idx++] = 0x01;
dhcp_packet.options[idx++] = DHCPDISCOVER;
dhcp_packet.options[idx++] = ParameterRequestList;
dhcp_packet.options[idx++] = 0x03;
dhcp_packet.options[idx++] = DomainNameServer;
dhcp_packet.options[idx++] = SubnetMask;
dhcp_packet.options[idx++] = Router;
dhcp_packet.options[idx++] = 0xFF;
send_dhcp_packet(socket, dhcp_packet, BAN::IPv4Address { 0xFFFFFFFF });
}
void send_dhcp_request(int socket, BAN::MACAddress mac_address, BAN::IPv4Address offered_ipv4, BAN::IPv4Address server_ipv4)
{
DHCPPacket dhcp_packet;
dhcp_packet.op = 0x01;
dhcp_packet.siaddr = server_ipv4.as_u32();
dhcp_packet.chaddr = mac_address;
size_t idx = 0;
dhcp_packet.options[idx++] = DHCPMessageType;
dhcp_packet.options[idx++] = 0x01;
dhcp_packet.options[idx++] = DHCPREQUEST;
dhcp_packet.options[idx++] = RequestedIPv4Address;
dhcp_packet.options[idx++] = 0x04;
dhcp_packet.options[idx++] = offered_ipv4.address[0];
dhcp_packet.options[idx++] = offered_ipv4.address[1];
dhcp_packet.options[idx++] = offered_ipv4.address[2];
dhcp_packet.options[idx++] = offered_ipv4.address[3];
dhcp_packet.options[idx++] = 0xFF;
send_dhcp_packet(socket, dhcp_packet, BAN::IPv4Address { 0xFFFFFFFF });
}
struct DHCPPacketInfo
{
enum DHCPMessageType message_type { INVALID };
BAN::IPv4Address address { 0 };
BAN::IPv4Address subnet { 0 };
BAN::IPv4Address server { 0 };
BAN::Vector<BAN::IPv4Address> routers;
BAN::Vector<BAN::IPv4Address> dns;
};
DHCPPacketInfo parse_dhcp_packet(const DHCPPacket& packet)
{
DHCPPacketInfo packet_info;
packet_info.address = BAN::IPv4Address(packet.yiaddr);
const uint8_t* options = packet.options;
while (*options != End)
{
uint8_t type = *options++;
uint8_t length = *options++;
switch (type)
{
case SubnetMask:
{
if (length != 4)
{
fprintf(stderr, "Subnet mask with invalid length %hhu\n", length);
break;
}
uint32_t raw = *reinterpret_cast<const BAN::NetworkEndian<uint32_t>*>(options);
packet_info.subnet = BAN::IPv4Address(raw);
break;
}
case Router:
{
if (length % 4 != 0)
{
fprintf(stderr, "Router with invalid length %hhu\n", length);
break;
}
for (int i = 0; i < length; i += 4)
{
uint32_t raw = *reinterpret_cast<const BAN::NetworkEndian<uint32_t>*>(options + i);
MUST(packet_info.routers.emplace_back(raw));
}
break;
}
case DomainNameServer:
{
if (length % 4 != 0)
{
fprintf(stderr, "DNS with invalid length %hhu\n", length);
break;
}
for (int i = 0; i < length; i += 4)
{
uint32_t raw = *reinterpret_cast<const BAN::NetworkEndian<uint32_t>*>(options + i);
MUST(packet_info.dns.emplace_back(raw));
}
break;
}
case DHCPMessageType:
{
if (length != 1)
{
fprintf(stderr, "DHCP Message Type with invalid length %hhu\n", length);
break;
}
switch (*options)
{
case DHCPDISCOVER: packet_info.message_type = DHCPDISCOVER; break;
case DHCPOFFER: packet_info.message_type = DHCPOFFER; break;
case DHCPREQUEST: packet_info.message_type = DHCPREQUEST; break;
case DHCPDECLINE: packet_info.message_type = DHCPDECLINE; break;
case DHCPACK: packet_info.message_type = DHCPACK; break;
}
break;
}
case ServerIdentifier:
{
if (length != 4)
{
fprintf(stderr, "Server identifier with invalid length %hhu\n", length);
break;
}
uint32_t raw = *reinterpret_cast<const BAN::NetworkEndian<uint32_t>*>(options);
packet_info.server = BAN::IPv4Address(raw);
break;
}
}
options += length;
}
return packet_info;
}
BAN::Optional<DHCPPacketInfo> read_dhcp_packet(int socket)
{
DHCPPacket dhcp_packet;
ssize_t nrecv = recvfrom(socket, &dhcp_packet, sizeof(dhcp_packet), 0, nullptr, nullptr);
if (nrecv == -1)
{
perror("revcfrom");
return {};
}
if (nrecv <= (ssize_t)offsetof(DHCPPacket, options))
{
fprintf(stderr, "invalid DHCP offer\n");
return {};
}
if (dhcp_packet.magic_cookie != 0x63825363)
{
fprintf(stderr, "invalid DHCP offer\n");
return {};
}
return parse_dhcp_packet(dhcp_packet);
}
int main()
{
int socket = ::socket(AF_INET, SOCK_DGRAM, 0);
if (socket == -1)
{
perror("socket");
return 1;
}
sockaddr_in client_addr;
client_addr.sin_family = AF_INET;
client_addr.sin_port = 68;
client_addr.sin_addr.s_addr = 0x00000000;
if (bind(socket, (sockaddr*)&client_addr, sizeof(client_addr)) == -1)
{
perror("bind");
return 1;
}
auto mac_address = get_mac_address(socket);
#if DEBUG_DHCP
BAN::Formatter::println(putchar, "MAC: {}", mac_address);
#endif
send_dhcp_discover(socket, mac_address);
#if DEBUG_DHCP
printf("DHCPDISCOVER sent\n");
#endif
auto dhcp_offer = read_dhcp_packet(socket);
if (!dhcp_offer.has_value())
return 1;
if (dhcp_offer->message_type != DHCPOFFER)
{
fprintf(stderr, "DHCP server did not respond with DHCPOFFER\n");
return 1;
}
#if DEBUG_DHCP
BAN::Formatter::println(putchar, "DHCPOFFER");
BAN::Formatter::println(putchar, " IP {}", dhcp_offer->address);
BAN::Formatter::println(putchar, " SUBNET {}", dhcp_offer->subnet);
BAN::Formatter::println(putchar, " SERVER {}", dhcp_offer->server);
#endif
send_dhcp_request(socket, mac_address, dhcp_offer->address, dhcp_offer->server);
#if DEBUG_DHCP
printf("DHCPREQUEST sent\n");
#endif
auto dhcp_ack = read_dhcp_packet(socket);
if (!dhcp_ack.has_value())
return 1;
if (dhcp_ack->message_type != DHCPACK)
{
fprintf(stderr, "DHCP server did not respond with DHCPACK\n");
return 1;
}
#if DEBUG_DHCP
BAN::Formatter::println(putchar, "DHCPACK");
BAN::Formatter::println(putchar, " IP {}", dhcp_ack->address);
BAN::Formatter::println(putchar, " SUBNET {}", dhcp_ack->subnet);
BAN::Formatter::println(putchar, " SERVER {}", dhcp_ack->server);
#endif
if (dhcp_offer->address != dhcp_ack->address)
{
fprintf(stderr, "DHCP server OFFER and ACK ips don't match\n");
return 1;
}
update_ipv4_info(socket, dhcp_ack->address, dhcp_ack->subnet);
if (true)
{
uint32_t packet = 0x12345678;
sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_port = 67;
server_addr.sin_addr.s_addr = dhcp_ack->routers.front().as_u32();
server_addr.sin_addr.s_addr = (192 << 24) | (168 << 16) | (1 << 8) | 203;
if (sendto(socket, &packet, sizeof(packet), 0, (sockaddr*)&server_addr, sizeof(server_addr)) == -1)
{
perror("sendto");
exit(1);
}
}
close(socket);
return 0;
}

View File

@ -29,6 +29,12 @@ int main()
if (load_keymap("/usr/share/keymaps/fi.keymap") == -1)
perror("load_keymap");
if (fork() == 0)
{
execl("/bin/dhcp-client", "dhcp-client", NULL);
exit(1);
}
bool first = true;
termios termios;

View File

@ -16,26 +16,37 @@ bool is_sorted(BAN::Vector<T>& vec)
#define CURRENT_NS() ({ timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts); ts.tv_sec * 1'000'000'000 + ts.tv_nsec; })
#define TEST(name, function, count) do { \
BAN::Vector<int> ivec(count, 0); \
for (int& i : ivec) \
i = rand() % 100; \
uint64_t start_ns = CURRENT_NS(); \
function(ivec.begin(), ivec.end()); \
uint64_t end_ns = CURRENT_NS(); \
uint64_t dur_us = (end_ns - start_ns) / 1000; \
printf(name " (" #count "): %s\n", is_sorted(ivec) ? "success" : "fail"); \
printf(" took %" PRIu64 ".%03" PRIu64 " ms\n", dur_us / 1000, dur_us % 1000); \
#define TEST_ALGORITHM(ms, function) do { \
uint64_t duration_us = 0; \
printf(#function "\n"); \
for (size_t size = 100; duration_us < ms * 1000; size *= 10) { \
BAN::Vector<unsigned> data(size, 0); \
for (auto& val : data) \
val = rand() % 100; \
uint64_t start_ns = CURRENT_NS(); \
(void)function(data.begin(), data.end()); \
uint64_t stop_ns = CURRENT_NS(); \
if (!is_sorted(data)) { \
printf(" \e[31mFAILED!\e[m\n"); \
break; \
} \
duration_us = (stop_ns - start_ns) / 1'000; \
printf(" %5d.%03d ms (%zu)\n", \
(int)(duration_us / 1000), \
(int)(duration_us % 1000), \
size \
); \
} \
} while (0)
int main()
{
srand(time(0));
TEST("exchange sort", BAN::sort::exchange_sort, 100);
TEST("exchange sort", BAN::sort::exchange_sort, 1000);
TEST("exchange sort", BAN::sort::exchange_sort, 10000);
TEST("quick sort", BAN::sort::quick_sort, 100);
TEST("quick sort", BAN::sort::quick_sort, 1000);
TEST("quick sort", BAN::sort::quick_sort, 10000);
TEST_ALGORITHM(100, BAN::sort::exchange_sort);
TEST_ALGORITHM(100, BAN::sort::quick_sort);
TEST_ALGORITHM(100, BAN::sort::insertion_sort);
TEST_ALGORITHM(100, BAN::sort::heap_sort);
TEST_ALGORITHM(100, BAN::sort::intro_sort);
TEST_ALGORITHM(1000, BAN::sort::sort);
TEST_ALGORITHM(1000, BAN::sort::radix_sort);
}