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>
|
template<integral T>
|
||||||
struct LittleEndian
|
struct LittleEndian
|
||||||
{
|
{
|
||||||
|
constexpr LittleEndian(T value)
|
||||||
|
{
|
||||||
|
raw = host_to_little_endian(value);
|
||||||
|
}
|
||||||
|
|
||||||
constexpr operator T() const
|
constexpr operator T() const
|
||||||
{
|
{
|
||||||
return host_to_little_endian(raw);
|
return host_to_little_endian(raw);
|
||||||
|
@ -69,6 +74,11 @@ namespace BAN
|
||||||
template<integral T>
|
template<integral T>
|
||||||
struct BigEndian
|
struct BigEndian
|
||||||
{
|
{
|
||||||
|
constexpr BigEndian(T value)
|
||||||
|
{
|
||||||
|
raw = host_to_big_endian(value);
|
||||||
|
}
|
||||||
|
|
||||||
constexpr operator T() const
|
constexpr operator T() const
|
||||||
{
|
{
|
||||||
return host_to_big_endian(raw);
|
return host_to_big_endian(raw);
|
||||||
|
@ -77,4 +87,7 @@ namespace BAN
|
||||||
T raw;
|
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);
|
iterator remove(iterator);
|
||||||
void clear();
|
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()); }
|
iterator begin() { return iterator(m_data, empty()); }
|
||||||
const_iterator begin() const { return const_iterator(m_data, empty()); }
|
const_iterator begin() const { return const_iterator(m_data, empty()); }
|
||||||
iterator end() { return iterator(m_last, true); }
|
iterator end() { return iterator(m_last, true); }
|
||||||
|
@ -65,7 +67,11 @@ namespace BAN
|
||||||
Node* prev;
|
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_data = nullptr;
|
||||||
Node* m_last = nullptr;
|
Node* m_last = nullptr;
|
||||||
|
@ -137,6 +143,31 @@ namespace BAN
|
||||||
return *this;
|
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>
|
template<typename T>
|
||||||
ErrorOr<void> LinkedList<T>::push_back(const T& value)
|
ErrorOr<void> LinkedList<T>::push_back(const T& value)
|
||||||
{
|
{
|
||||||
|
@ -158,15 +189,8 @@ namespace BAN
|
||||||
template<typename T>
|
template<typename T>
|
||||||
ErrorOr<void> LinkedList<T>::insert(iterator iter, T&& value)
|
ErrorOr<void> LinkedList<T>::insert(iterator iter, T&& value)
|
||||||
{
|
{
|
||||||
Node* next = iter.m_past_end ? nullptr : iter.m_current;
|
Node* new_node = TRY(allocate_node(move(value)));
|
||||||
Node* prev = next ? next->prev : m_last;
|
insert_node(iter, new_node);
|
||||||
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++;
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -181,21 +205,15 @@ namespace BAN
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
ErrorOr<void> LinkedList<T>::emplace(iterator iter, Args&&... args)
|
ErrorOr<void> LinkedList<T>::emplace(iterator iter, Args&&... args)
|
||||||
{
|
{
|
||||||
Node* next = iter.m_past_end ? nullptr : iter.m_current;
|
Node* new_node = TRY(allocate_node(forward<Args>(args)...));
|
||||||
Node* prev = next ? next->prev : m_last;
|
insert_node(iter, new_node);
|
||||||
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++;
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void LinkedList<T>::pop_back()
|
void LinkedList<T>::pop_back()
|
||||||
{
|
{
|
||||||
|
ASSERT(!empty());
|
||||||
remove(iterator(m_last, false));
|
remove(iterator(m_last, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -203,14 +221,10 @@ namespace BAN
|
||||||
LinkedList<T>::iterator LinkedList<T>::remove(iterator iter)
|
LinkedList<T>::iterator LinkedList<T>::remove(iterator iter)
|
||||||
{
|
{
|
||||||
ASSERT(!empty() && iter);
|
ASSERT(!empty() && iter);
|
||||||
Node* node = iter.m_current;
|
Node* node = remove_node(iter);
|
||||||
Node* prev = node->prev;
|
|
||||||
Node* next = node->next;
|
Node* next = node->next;
|
||||||
node->value.~T();
|
node->value.~T();
|
||||||
BAN::deallocator(node);
|
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);
|
return next ? iterator(next, false) : iterator(m_last, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -230,6 +244,16 @@ namespace BAN
|
||||||
m_size = 0;
|
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>
|
template<typename T>
|
||||||
const T& LinkedList<T>::back() const
|
const T& LinkedList<T>::back() const
|
||||||
{
|
{
|
||||||
|
@ -284,11 +308,13 @@ namespace BAN
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
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));
|
Node* node = (Node*)BAN::allocator(sizeof(Node));
|
||||||
if (node == nullptr)
|
if (node == nullptr)
|
||||||
return Error::from_errno(ENOMEM);
|
return Error::from_errno(ENOMEM);
|
||||||
|
new (&node->value) T(forward<Args>(args)...);
|
||||||
return node;
|
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
|
#pragma once
|
||||||
|
|
||||||
|
#include <BAN/Math.h>
|
||||||
#include <BAN/Swap.h>
|
#include <BAN/Swap.h>
|
||||||
#include <BAN/Traits.h>
|
#include <BAN/Traits.h>
|
||||||
#include <BAN/Math.h>
|
#include <BAN/Vector.h>
|
||||||
|
|
||||||
namespace BAN::sort
|
namespace BAN::sort
|
||||||
{
|
{
|
||||||
|
@ -175,6 +176,61 @@ namespace BAN::sort
|
||||||
detail::intro_sort_impl(begin, end, 2 * Math::ilog2(len), comp);
|
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>>
|
template<typename It, typename Comp = less<typename It::value_type>>
|
||||||
void sort(It begin, It end, Comp comp = {})
|
void sort(It begin, It end, Comp comp = {})
|
||||||
{
|
{
|
||||||
|
|
|
@ -49,7 +49,14 @@ set(KERNEL_SOURCES
|
||||||
kernel/Memory/MemoryRegion.cpp
|
kernel/Memory/MemoryRegion.cpp
|
||||||
kernel/Memory/PhysicalRange.cpp
|
kernel/Memory/PhysicalRange.cpp
|
||||||
kernel/Memory/VirtualRange.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/OpenFileDescriptorSet.cpp
|
||||||
kernel/Panic.cpp
|
kernel/Panic.cpp
|
||||||
kernel/PCI.cpp
|
kernel/PCI.cpp
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include <kernel/Credentials.h>
|
#include <kernel/Credentials.h>
|
||||||
#include <kernel/SpinLock.h>
|
#include <kernel/SpinLock.h>
|
||||||
|
|
||||||
|
#include <sys/socket.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
|
@ -86,6 +87,8 @@ namespace Kernel
|
||||||
virtual bool is_pipe() const { return false; }
|
virtual bool is_pipe() const { return false; }
|
||||||
virtual bool is_tty() const { return false; }
|
virtual bool is_tty() const { return false; }
|
||||||
|
|
||||||
|
void on_close();
|
||||||
|
|
||||||
// Directory API
|
// Directory API
|
||||||
BAN::ErrorOr<BAN::RefPtr<Inode>> find_inode(BAN::StringView);
|
BAN::ErrorOr<BAN::RefPtr<Inode>> find_inode(BAN::StringView);
|
||||||
BAN::ErrorOr<void> list_next_inodes(off_t, DirectoryEntryList*, size_t);
|
BAN::ErrorOr<void> list_next_inodes(off_t, DirectoryEntryList*, size_t);
|
||||||
|
@ -96,6 +99,11 @@ namespace Kernel
|
||||||
// Link API
|
// Link API
|
||||||
BAN::ErrorOr<BAN::String> link_target();
|
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
|
// General API
|
||||||
BAN::ErrorOr<size_t> read(off_t, BAN::ByteSpan buffer);
|
BAN::ErrorOr<size_t> read(off_t, BAN::ByteSpan buffer);
|
||||||
BAN::ErrorOr<size_t> write(off_t, BAN::ConstByteSpan 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);
|
BAN::ErrorOr<void> chown(uid_t, gid_t);
|
||||||
bool has_data() const;
|
bool has_data() const;
|
||||||
|
|
||||||
|
BAN::ErrorOr<long> ioctl(int request, void* arg);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
virtual void on_close_impl() {}
|
||||||
|
|
||||||
// Directory API
|
// Directory API
|
||||||
virtual BAN::ErrorOr<BAN::RefPtr<Inode>> find_inode_impl(BAN::StringView) { return BAN::Error::from_errno(ENOTSUP); }
|
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); }
|
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
|
// Link API
|
||||||
virtual BAN::ErrorOr<BAN::String> link_target_impl() { return BAN::Error::from_errno(ENOTSUP); }
|
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
|
// General API
|
||||||
virtual BAN::ErrorOr<size_t> read_impl(off_t, BAN::ByteSpan) { return BAN::Error::from_errno(ENOTSUP); }
|
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); }
|
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 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 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:
|
protected:
|
||||||
mutable RecursivePrioritySpinLock m_lock;
|
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> 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<void> pipe(int fds[2]);
|
||||||
|
|
||||||
BAN::ErrorOr<int> dup(int);
|
BAN::ErrorOr<int> dup(int);
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
#include <sys/banan-os.h>
|
#include <sys/banan-os.h>
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
#include <termios.h>
|
#include <termios.h>
|
||||||
|
|
||||||
namespace LibELF { class LoadableELF; }
|
namespace LibELF { class LoadableELF; }
|
||||||
|
@ -111,6 +112,13 @@ namespace Kernel
|
||||||
BAN::ErrorOr<long> sys_chmod(const char*, mode_t);
|
BAN::ErrorOr<long> sys_chmod(const char*, mode_t);
|
||||||
BAN::ErrorOr<long> sys_chown(const char*, uid_t, gid_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_pipe(int fildes[2]);
|
||||||
BAN::ErrorOr<long> sys_dup(int fildes);
|
BAN::ErrorOr<long> sys_dup(int fildes);
|
||||||
BAN::ErrorOr<long> sys_dup2(int fildes, int fildes2);
|
BAN::ErrorOr<long> sys_dup2(int fildes, int fildes2);
|
||||||
|
|
|
@ -44,34 +44,26 @@ namespace Kernel
|
||||||
BAN::ErrorOr<void> add_thread(Thread*);
|
BAN::ErrorOr<void> add_thread(Thread*);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct ActiveThread
|
struct SchedulerThread
|
||||||
{
|
{
|
||||||
ActiveThread(Thread* thread) : thread(thread) {}
|
SchedulerThread(Thread* thread)
|
||||||
Thread* thread;
|
: thread(thread)
|
||||||
uint64_t padding;
|
{}
|
||||||
};
|
|
||||||
|
|
||||||
struct SleepingThread
|
|
||||||
{
|
|
||||||
SleepingThread(Thread* thread, uint64_t wake_time) : thread(thread), wake_time(wake_time) {}
|
|
||||||
Thread* thread;
|
Thread* thread;
|
||||||
|
union
|
||||||
|
{
|
||||||
uint64_t wake_time;
|
uint64_t wake_time;
|
||||||
};
|
|
||||||
|
|
||||||
struct BlockingThread
|
|
||||||
{
|
|
||||||
BlockingThread(Thread* thread, Semaphore* semaphore) : thread(thread), semaphore(semaphore) {}
|
|
||||||
Thread* thread;
|
|
||||||
Semaphore* semaphore;
|
Semaphore* semaphore;
|
||||||
uint8_t padding[sizeof(uint64_t) - sizeof(Semaphore*)];
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
Thread* m_idle_thread { nullptr };
|
Thread* m_idle_thread { nullptr };
|
||||||
BAN::LinkedList<ActiveThread> m_active_threads;
|
BAN::LinkedList<SchedulerThread> m_active_threads;
|
||||||
BAN::LinkedList<SleepingThread> m_sleeping_threads;
|
BAN::LinkedList<SchedulerThread> m_sleeping_threads;
|
||||||
BAN::LinkedList<BlockingThread> m_blocking_threads;
|
BAN::LinkedList<SchedulerThread> m_blocking_threads;
|
||||||
|
|
||||||
BAN::LinkedList<ActiveThread>::iterator m_current_thread;
|
BAN::LinkedList<SchedulerThread>::iterator m_current_thread;
|
||||||
|
|
||||||
friend class Process;
|
friend class Process;
|
||||||
};
|
};
|
||||||
|
|
|
@ -56,6 +56,12 @@ namespace Kernel
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Inode::on_close()
|
||||||
|
{
|
||||||
|
LockGuard _(m_lock);
|
||||||
|
on_close_impl();
|
||||||
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<BAN::RefPtr<Inode>> Inode::find_inode(BAN::StringView name)
|
BAN::ErrorOr<BAN::RefPtr<Inode>> Inode::find_inode(BAN::StringView name)
|
||||||
{
|
{
|
||||||
LockGuard _(m_lock);
|
LockGuard _(m_lock);
|
||||||
|
@ -110,6 +116,30 @@ namespace Kernel
|
||||||
return link_target_impl();
|
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)
|
BAN::ErrorOr<size_t> Inode::read(off_t offset, BAN::ByteSpan buffer)
|
||||||
{
|
{
|
||||||
LockGuard _(m_lock);
|
LockGuard _(m_lock);
|
||||||
|
@ -153,4 +183,10 @@ namespace Kernel
|
||||||
return has_data_impl();
|
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/Pipe.h>
|
||||||
#include <kernel/FS/VirtualFileSystem.h>
|
#include <kernel/FS/VirtualFileSystem.h>
|
||||||
|
#include <kernel/Networking/NetworkManager.h>
|
||||||
#include <kernel/OpenFileDescriptorSet.h>
|
#include <kernel/OpenFileDescriptorSet.h>
|
||||||
|
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
|
||||||
namespace Kernel
|
namespace Kernel
|
||||||
{
|
{
|
||||||
|
@ -76,6 +78,38 @@ namespace Kernel
|
||||||
return fd;
|
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])
|
BAN::ErrorOr<void> OpenFileDescriptorSet::pipe(int fds[2])
|
||||||
{
|
{
|
||||||
TRY(get_free_fd_pair(fds));
|
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())
|
if (m_open_files[fd]->flags & O_WRONLY && m_open_files[fd]->inode->is_pipe())
|
||||||
((Pipe*)m_open_files[fd]->inode.ptr())->close_writing();
|
((Pipe*)m_open_files[fd]->inode.ptr())->close_writing();
|
||||||
|
|
||||||
|
m_open_files[fd]->inode->on_close();
|
||||||
|
|
||||||
m_open_files[fd].clear();
|
m_open_files[fd].clear();
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
#include <kernel/IO.h>
|
#include <kernel/IO.h>
|
||||||
#include <kernel/Memory/PageTable.h>
|
#include <kernel/Memory/PageTable.h>
|
||||||
#include <kernel/MMIO.h>
|
#include <kernel/MMIO.h>
|
||||||
#include <kernel/Networking/E1000.h>
|
#include <kernel/Networking/NetworkManager.h>
|
||||||
#include <kernel/PCI.h>
|
#include <kernel/PCI.h>
|
||||||
#include <kernel/Storage/ATA/AHCI/Controller.h>
|
#include <kernel/Storage/ATA/AHCI/Controller.h>
|
||||||
#include <kernel/Storage/ATA/ATAController.h>
|
#include <kernel/Storage/ATA/ATAController.h>
|
||||||
|
@ -183,17 +183,8 @@ namespace Kernel::PCI
|
||||||
}
|
}
|
||||||
case 0x02:
|
case 0x02:
|
||||||
{
|
{
|
||||||
switch (pci_device.subclass())
|
if (auto res = NetworkManager::get().add_interface(pci_device); res.is_error())
|
||||||
{
|
dprintln("{}", res.error());
|
||||||
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;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
@ -259,7 +250,7 @@ namespace Kernel::PCI
|
||||||
device.write_word(PCI_REG_COMMAND, command);
|
device.write_word(PCI_REG_COMMAND, command);
|
||||||
|
|
||||||
#if DEBUG_PCI
|
#if DEBUG_PCI
|
||||||
dprintln("created BAR region for PCI {}:{}.{}",
|
dprintln("created BAR region for PCI {2H}:{2H}.{2H}",
|
||||||
device.bus(),
|
device.bus(),
|
||||||
device.dev(),
|
device.dev(),
|
||||||
device.func()
|
device.func()
|
||||||
|
@ -493,12 +484,12 @@ namespace Kernel::PCI
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint64_t msi_message_address()
|
static constexpr uint64_t msi_message_address()
|
||||||
{
|
{
|
||||||
return 0xFEE00000;
|
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;
|
return (IRQ_VECTOR_BASE + irq) & 0xFF;
|
||||||
}
|
}
|
||||||
|
|
|
@ -895,6 +895,70 @@ namespace Kernel
|
||||||
return 0;
|
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])
|
BAN::ErrorOr<long> Process::sys_pipe(int fildes[2])
|
||||||
{
|
{
|
||||||
LockGuard _(m_lock);
|
LockGuard _(m_lock);
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
#include <kernel/InterruptController.h>
|
#include <kernel/InterruptController.h>
|
||||||
#include <kernel/Process.h>
|
#include <kernel/Process.h>
|
||||||
#include <kernel/Scheduler.h>
|
#include <kernel/Scheduler.h>
|
||||||
#include <kernel/Timer/PIT.h>
|
#include <kernel/Timer/Timer.h>
|
||||||
|
|
||||||
#define SCHEDULER_VERIFY_STACK 1
|
#define SCHEDULER_VERIFY_STACK 1
|
||||||
#define SCHEDULER_VERIFY_INTERRUPT_STATE 1
|
#define SCHEDULER_VERIFY_INTERRUPT_STATE 1
|
||||||
|
@ -116,12 +116,11 @@ namespace Kernel
|
||||||
uint64_t current_time = SystemTimer::get().ms_since_boot();
|
uint64_t current_time = SystemTimer::get().ms_since_boot();
|
||||||
while (!m_sleeping_threads.empty() && m_sleeping_threads.front().wake_time <= current_time)
|
while (!m_sleeping_threads.empty() && m_sleeping_threads.front().wake_time <= current_time)
|
||||||
{
|
{
|
||||||
Thread* thread = m_sleeping_threads.front().thread;
|
m_sleeping_threads.move_element_to_other_linked_list(
|
||||||
m_sleeping_threads.remove(m_sleeping_threads.begin());
|
m_active_threads,
|
||||||
|
m_active_threads.end(),
|
||||||
// This should work as we released enough memory from sleeping thread
|
m_sleeping_threads.begin()
|
||||||
static_assert(sizeof(ActiveThread) == sizeof(SleepingThread));
|
);
|
||||||
MUST(m_active_threads.emplace_back(thread));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -286,23 +285,26 @@ namespace Kernel
|
||||||
|
|
||||||
ASSERT(m_current_thread);
|
ASSERT(m_current_thread);
|
||||||
|
|
||||||
Thread* sleeping = m_current_thread->thread;
|
|
||||||
|
|
||||||
if (save_current_thread())
|
if (save_current_thread())
|
||||||
{
|
{
|
||||||
ENABLE_INTERRUPTS();
|
ENABLE_INTERRUPTS();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
remove_and_advance_current_thread();
|
|
||||||
|
|
||||||
auto it = m_sleeping_threads.begin();
|
auto it = m_sleeping_threads.begin();
|
||||||
for (; it != m_sleeping_threads.end(); it++)
|
for (; it != m_sleeping_threads.end(); it++)
|
||||||
if (wake_time <= it->wake_time)
|
if (wake_time <= it->wake_time)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// This should work as we released enough memory from active thread
|
m_current_thread->wake_time = wake_time;
|
||||||
static_assert(sizeof(ActiveThread) == sizeof(SleepingThread));
|
m_active_threads.move_element_to_other_linked_list(
|
||||||
MUST(m_sleeping_threads.emplace(it, sleeping, wake_time));
|
m_sleeping_threads,
|
||||||
|
it,
|
||||||
|
m_current_thread
|
||||||
|
);
|
||||||
|
|
||||||
|
m_current_thread = {};
|
||||||
|
advance_current_thread();
|
||||||
|
|
||||||
execute_current_thread();
|
execute_current_thread();
|
||||||
ASSERT_NOT_REACHED();
|
ASSERT_NOT_REACHED();
|
||||||
|
@ -315,18 +317,21 @@ namespace Kernel
|
||||||
|
|
||||||
ASSERT(m_current_thread);
|
ASSERT(m_current_thread);
|
||||||
|
|
||||||
Thread* blocking = m_current_thread->thread;
|
|
||||||
|
|
||||||
if (save_current_thread())
|
if (save_current_thread())
|
||||||
{
|
{
|
||||||
ENABLE_INTERRUPTS();
|
ENABLE_INTERRUPTS();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
remove_and_advance_current_thread();
|
|
||||||
|
|
||||||
// This should work as we released enough memory from active thread
|
m_current_thread->semaphore = semaphore;
|
||||||
static_assert(sizeof(ActiveThread) == sizeof(BlockingThread));
|
m_active_threads.move_element_to_other_linked_list(
|
||||||
MUST(m_blocking_threads.emplace_back(blocking, semaphore));
|
m_blocking_threads,
|
||||||
|
m_blocking_threads.end(),
|
||||||
|
m_current_thread
|
||||||
|
);
|
||||||
|
|
||||||
|
m_current_thread = {};
|
||||||
|
advance_current_thread();
|
||||||
|
|
||||||
execute_current_thread();
|
execute_current_thread();
|
||||||
ASSERT_NOT_REACHED();
|
ASSERT_NOT_REACHED();
|
||||||
|
@ -340,12 +345,11 @@ namespace Kernel
|
||||||
{
|
{
|
||||||
if (it->semaphore == semaphore)
|
if (it->semaphore == semaphore)
|
||||||
{
|
{
|
||||||
auto thread = it->thread;
|
it = m_blocking_threads.move_element_to_other_linked_list(
|
||||||
it = m_blocking_threads.remove(it);
|
m_active_threads,
|
||||||
|
m_active_threads.end(),
|
||||||
// This should work as we released enough memory from active thread
|
it
|
||||||
static_assert(sizeof(ActiveThread) == sizeof(BlockingThread));
|
);
|
||||||
MUST(m_active_threads.emplace_back(thread));
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -362,13 +366,11 @@ namespace Kernel
|
||||||
{
|
{
|
||||||
if (it->thread->tid() == tid)
|
if (it->thread->tid() == tid)
|
||||||
{
|
{
|
||||||
Thread* thread = it->thread;
|
m_blocking_threads.move_element_to_other_linked_list(
|
||||||
m_blocking_threads.remove(it);
|
m_active_threads,
|
||||||
|
m_active_threads.end(),
|
||||||
// This should work as we released enough memory from active thread
|
it
|
||||||
static_assert(sizeof(ActiveThread) == sizeof(BlockingThread));
|
);
|
||||||
MUST(m_active_threads.emplace_back(thread));
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -377,13 +379,11 @@ namespace Kernel
|
||||||
{
|
{
|
||||||
if (it->thread->tid() == tid)
|
if (it->thread->tid() == tid)
|
||||||
{
|
{
|
||||||
Thread* thread = it->thread;
|
m_sleeping_threads.move_element_to_other_linked_list(
|
||||||
m_sleeping_threads.remove(it);
|
m_active_threads,
|
||||||
|
m_active_threads.end(),
|
||||||
// This should work as we released enough memory from active thread
|
it
|
||||||
static_assert(sizeof(ActiveThread) == sizeof(BlockingThread));
|
);
|
||||||
MUST(m_active_threads.emplace_back(thread));
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -213,6 +213,21 @@ namespace Kernel
|
||||||
case SYS_LOAD_KEYMAP:
|
case SYS_LOAD_KEYMAP:
|
||||||
ret = Process::current().sys_load_keymap((const char*)arg1);
|
ret = Process::current().sys_load_keymap((const char*)arg1);
|
||||||
break;
|
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:
|
default:
|
||||||
dwarnln("Unknown syscall {}", syscall);
|
dwarnln("Unknown syscall {}", syscall);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include <kernel/Memory/Heap.h>
|
#include <kernel/Memory/Heap.h>
|
||||||
#include <kernel/Memory/kmalloc.h>
|
#include <kernel/Memory/kmalloc.h>
|
||||||
#include <kernel/Memory/PageTable.h>
|
#include <kernel/Memory/PageTable.h>
|
||||||
|
#include <kernel/Networking/NetworkManager.h>
|
||||||
#include <kernel/PCI.h>
|
#include <kernel/PCI.h>
|
||||||
#include <kernel/PIC.h>
|
#include <kernel/PIC.h>
|
||||||
#include <kernel/Process.h>
|
#include <kernel/Process.h>
|
||||||
|
@ -187,6 +188,8 @@ static void init2(void*)
|
||||||
if (auto res = PS2Controller::initialize(); res.is_error())
|
if (auto res = PS2Controller::initialize(); res.is_error())
|
||||||
dprintln("{}", res.error());
|
dprintln("{}", res.error());
|
||||||
|
|
||||||
|
MUST(NetworkManager::initialize());
|
||||||
|
|
||||||
// NOTE: PCI devices are the last ones to be initialized
|
// NOTE: PCI devices are the last ones to be initialized
|
||||||
// so other devices can reserve predefined interrupts
|
// so other devices can reserve predefined interrupts
|
||||||
PCI::PCIManager::initialize();
|
PCI::PCIManager::initialize();
|
||||||
|
|
|
@ -17,8 +17,10 @@ set(LIBC_SOURCES
|
||||||
stdlib.cpp
|
stdlib.cpp
|
||||||
string.cpp
|
string.cpp
|
||||||
strings.cpp
|
strings.cpp
|
||||||
|
stropts.cpp
|
||||||
sys/banan-os.cpp
|
sys/banan-os.cpp
|
||||||
sys/mman.cpp
|
sys/mman.cpp
|
||||||
|
sys/socket.cpp
|
||||||
sys/stat.cpp
|
sys/stat.cpp
|
||||||
sys/wait.cpp
|
sys/wait.cpp
|
||||||
termios.cpp
|
termios.cpp
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
|
|
||||||
#include <sys/cdefs.h>
|
#include <sys/cdefs.h>
|
||||||
|
|
||||||
|
#include <sys/socket.h>
|
||||||
|
|
||||||
#define IF_NAMESIZE 16
|
#define IF_NAMESIZE 16
|
||||||
|
|
||||||
__BEGIN_DECLS
|
__BEGIN_DECLS
|
||||||
|
@ -15,6 +17,22 @@ struct if_nameindex
|
||||||
char* if_name; /* Null-terminated name of the interface. */
|
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);
|
void if_freenameindex(struct if_nameindex* ptr);
|
||||||
char* if_indextoname(unsigned ifindex, char* ifname);
|
char* if_indextoname(unsigned ifindex, char* ifname);
|
||||||
struct if_nameindex* if_nameindex(void);
|
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_WR 0x02
|
||||||
#define SHUT_RDWR (SHUT_RD | SHUT_WR)
|
#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 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 bind(int socket, const struct sockaddr* address, socklen_t address_len);
|
||||||
int connect(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_PREAD 62
|
||||||
#define SYS_CHOWN 63
|
#define SYS_CHOWN 63
|
||||||
#define SYS_LOAD_KEYMAP 64
|
#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
|
__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
|
fi
|
||||||
|
|
||||||
qemu-system-$BANAN_ARCH \
|
qemu-system-$BANAN_ARCH \
|
||||||
-m 128 \
|
-m 1G \
|
||||||
-smp 2 \
|
-smp 2 \
|
||||||
$BIOS_ARGS \
|
$BIOS_ARGS \
|
||||||
-drive format=raw,id=disk,file=${BANAN_DISK_IMAGE_PATH},if=none \
|
-drive format=raw,id=disk,file=${BANAN_DISK_IMAGE_PATH},if=none \
|
||||||
|
-device e1000e,netdev=net \
|
||||||
|
-netdev user,id=net \
|
||||||
$DISK_ARGS \
|
$DISK_ARGS \
|
||||||
$@ \
|
$@ \
|
||||||
|
|
|
@ -8,6 +8,7 @@ set(USERSPACE_PROJECTS
|
||||||
chmod
|
chmod
|
||||||
cp
|
cp
|
||||||
dd
|
dd
|
||||||
|
dhcp-client
|
||||||
echo
|
echo
|
||||||
id
|
id
|
||||||
init
|
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)
|
if (load_keymap("/usr/share/keymaps/fi.keymap") == -1)
|
||||||
perror("load_keymap");
|
perror("load_keymap");
|
||||||
|
|
||||||
|
if (fork() == 0)
|
||||||
|
{
|
||||||
|
execl("/bin/dhcp-client", "dhcp-client", NULL);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
bool first = true;
|
bool first = true;
|
||||||
|
|
||||||
termios termios;
|
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 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 { \
|
#define TEST_ALGORITHM(ms, function) do { \
|
||||||
BAN::Vector<int> ivec(count, 0); \
|
uint64_t duration_us = 0; \
|
||||||
for (int& i : ivec) \
|
printf(#function "\n"); \
|
||||||
i = rand() % 100; \
|
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(); \
|
uint64_t start_ns = CURRENT_NS(); \
|
||||||
function(ivec.begin(), ivec.end()); \
|
(void)function(data.begin(), data.end()); \
|
||||||
uint64_t end_ns = CURRENT_NS(); \
|
uint64_t stop_ns = CURRENT_NS(); \
|
||||||
uint64_t dur_us = (end_ns - start_ns) / 1000; \
|
if (!is_sorted(data)) { \
|
||||||
printf(name " (" #count "): %s\n", is_sorted(ivec) ? "success" : "fail"); \
|
printf(" \e[31mFAILED!\e[m\n"); \
|
||||||
printf(" took %" PRIu64 ".%03" PRIu64 " ms\n", dur_us / 1000, dur_us % 1000); \
|
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)
|
} while (0)
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
srand(time(0));
|
srand(time(0));
|
||||||
TEST("exchange sort", BAN::sort::exchange_sort, 100);
|
TEST_ALGORITHM(100, BAN::sort::exchange_sort);
|
||||||
TEST("exchange sort", BAN::sort::exchange_sort, 1000);
|
TEST_ALGORITHM(100, BAN::sort::quick_sort);
|
||||||
TEST("exchange sort", BAN::sort::exchange_sort, 10000);
|
TEST_ALGORITHM(100, BAN::sort::insertion_sort);
|
||||||
|
TEST_ALGORITHM(100, BAN::sort::heap_sort);
|
||||||
TEST("quick sort", BAN::sort::quick_sort, 100);
|
TEST_ALGORITHM(100, BAN::sort::intro_sort);
|
||||||
TEST("quick sort", BAN::sort::quick_sort, 1000);
|
TEST_ALGORITHM(1000, BAN::sort::sort);
|
||||||
TEST("quick sort", BAN::sort::quick_sort, 10000);
|
TEST_ALGORITHM(1000, BAN::sort::radix_sort);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue