Compare commits
20 Commits
9213dd13bc
...
2138eeb87f
Author | SHA1 | Date |
---|---|---|
Bananymous | 2138eeb87f | |
Bananymous | 102aa50a41 | |
Bananymous | 5cfe249945 | |
Bananymous | a0138955cd | |
Bananymous | e1ffbb710b | |
Bananymous | c18f72ceb9 | |
Bananymous | bc1441a5eb | |
Bananymous | 0f154c3173 | |
Bananymous | 7b287a1d5b | |
Bananymous | 4b332b5d42 | |
Bananymous | ec2f21bb9f | |
Bananymous | acd6c86f98 | |
Bananymous | ab150b458a | |
Bananymous | cf28ecd5a6 | |
Bananymous | 99eed9c37a | |
Bananymous | f4e86028d0 | |
Bananymous | 7cb71ec6fb | |
Bananymous | d054e5b4b7 | |
Bananymous | c69efc040c | |
Bananymous | c4bf1641bd |
|
@ -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>;
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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 = {})
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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>;
|
||||
};
|
||||
|
||||
}
|
|
@ -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 };
|
||||
};
|
||||
|
||||
}
|
|
@ -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));
|
||||
|
||||
}
|
|
@ -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>;
|
||||
};
|
||||
|
||||
}
|
|
@ -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>;
|
||||
};
|
||||
|
||||
}
|
|
@ -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);
|
||||
|
||||
}
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
|
@ -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 };
|
||||
};
|
||||
|
||||
}
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
|
@ -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>;
|
||||
};
|
||||
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
union
|
||||
{
|
||||
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*)];
|
||||
};
|
||||
};
|
||||
|
||||
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;
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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 {};
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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 \
|
||||
$@ \
|
||||
|
|
|
@ -8,6 +8,7 @@ set(USERSPACE_PROJECTS
|
|||
chmod
|
||||
cp
|
||||
dd
|
||||
dhcp-client
|
||||
echo
|
||||
id
|
||||
init
|
||||
|
|
|
@ -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
|
||||
)
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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; \
|
||||
#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(); \
|
||||
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); \
|
||||
(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);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue