Skip to content
This repository was archived by the owner on Sep 11, 2024. It is now read-only.

Commit 6b82ea5

Browse files
committed
Kernel: TCP functionality (WIP)
Still need to retransmit unacked packets, and we probably need tests for this stuff. But, it works for both serving and receiving TCP packets, hooray!
1 parent abb0702 commit 6b82ea5

33 files changed

+1214
-103
lines changed

kernel/CMakeLists.txt

+2
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ SET(KERNEL_SRCS
9191
tasking/BooleanBlocker.cpp
9292
tasking/PollBlocker.cpp
9393
tasking/SleepBlocker.cpp
94+
tasking/FileBlockers.cpp
9495
device/VGADevice.cpp
9596
device/BochsVGADevice.cpp
9697
device/MultibootVGADevice.cpp
@@ -181,6 +182,7 @@ SET(KERNEL_SRCS
181182
net/Socket.cpp
182183
net/IPSocket.cpp
183184
net/UDPSocket.cpp
185+
net/TCPSocket.cpp
184186
net/Router.cpp)
185187

186188
add_custom_command(

kernel/Result.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
#include "Result.hpp"
2121
#include "kernel/kstd/kstdio.h"
2222

23+
const Result Result::Success {0};
24+
2325
Result::Result(int code): _code(code) {
2426
}
2527

kernel/Result.hpp

+9-1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
#include <kernel/kstd/Arc.h>
2323
#include <kernel/kstd/kstdio.h>
24+
#include <kernel/kstd/type_traits.h>
2425

2526
#define TRY(expr) \
2627
({ \
@@ -30,9 +31,16 @@
3031
res.value(); \
3132
})
3233

34+
#define TRYRES(expr) \
35+
({ \
36+
auto res = (expr); \
37+
if (res.is_error()) \
38+
return res; \
39+
})
40+
3341
class Result {
3442
public:
35-
static const int Success = 0;
43+
static const Result Success;
3644

3745
explicit Result(int code);
3846

kernel/api/ipv4.h

+12
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,18 @@ class __attribute__((packed)) IPv4Address {
4444
return m_data < other.m_data;
4545
}
4646

47+
inline constexpr bool operator<=(const IPv4Address& other) const {
48+
return m_data <= other.m_data;
49+
}
50+
51+
inline constexpr bool operator>(const IPv4Address& other) const {
52+
return m_data > other.m_data;
53+
}
54+
55+
inline constexpr bool operator>=(const IPv4Address& other) const {
56+
return m_data >= other.m_data;
57+
}
58+
4759
inline sockaddr_in as_sockaddr(in_port_t port) const {
4860
sockaddr_in ret;
4961
ret.sin_family = AF_INET;

kernel/api/socket.h

+9
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,15 @@ __DECL_BEGIN
2828
#define SO_BROADCAST 2
2929
#define SO_ERROR 3
3030

31+
// shutdown
32+
#define SHUT_RD 0x1
33+
#define SHUT_WR 0x2
34+
#define SHUT_RDWR (SHUT_RD | SHUT_WR)
35+
36+
// flags
37+
#define SOCK_NONBLOCK 0x1
38+
#define SOCK_CLOEXEC 0x2
39+
3140
typedef uint16_t sa_family_t;
3241
typedef uint32_t socklen_t;
3342

kernel/api/tcp.h

+106
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
/* SPDX-License-Identifier: GPL-3.0-or-later */
2+
/* Copyright © 2016-2024 Byteduck */
3+
4+
#pragma once
5+
6+
#include "endian.h"
7+
8+
#define TCP_FIN 0x01
9+
#define TCP_SYN 0x02
10+
#define TCP_RST 0x04
11+
#define TCP_PSH 0x08
12+
#define TCP_ACK 0x10
13+
#define TCP_URG 0x20
14+
15+
enum TCPOption {
16+
End = 0,
17+
Nop = 1,
18+
MSS = 2,
19+
WindowScale = 3,
20+
SACKPermit = 4,
21+
SACK = 5,
22+
Timestamp = 6
23+
};
24+
25+
struct TCPSegment {
26+
BigEndian<uint16_t> source_port;
27+
BigEndian<uint16_t> dest_port;
28+
BigEndian<uint32_t> sequence;
29+
BigEndian<uint32_t> ack;
30+
BigEndian<uint16_t> flags_and_offset;
31+
BigEndian<uint16_t> window_size;
32+
BigEndian<uint16_t> checksum;
33+
BigEndian<uint16_t> urgent_pointer;
34+
uint8_t data[];
35+
36+
[[nodiscard]] uint8_t data_offset() const { return (flags_and_offset.val() & 0xf000) >> 12; }
37+
void set_data_offset(uint8_t offset) { flags_and_offset = (flags_and_offset & 0xfff) | ((uint16_t) offset) << 12; }
38+
39+
[[nodiscard]] uint8_t flags() const { return flags_and_offset.val() & 0x01ff; }
40+
void set_flags(uint16_t flags) { flags_and_offset = (flags_and_offset & ~0x01ff) | (flags & 0x1ff); }
41+
42+
[[nodiscard]] const uint8_t* payload() const { return ((const uint8_t*) this) + (data_offset() * sizeof(uint32_t)); }
43+
[[nodiscard]] uint8_t* payload() { return ((uint8_t*) this) + (data_offset() * sizeof(uint32_t)); }
44+
45+
inline BigEndian<uint16_t> calculate_checksum(const IPv4Address& src, const IPv4Address& dest, size_t payload_size) {
46+
union PseudoHeader {
47+
struct __attribute__((packed)) {
48+
IPv4Address src;
49+
IPv4Address dest;
50+
uint8_t zero;
51+
uint8_t proto;
52+
BigEndian<uint16_t> payload_size;
53+
} data;
54+
uint16_t raw[6] = {0};
55+
};
56+
static_assert(sizeof(PseudoHeader::data) == sizeof(PseudoHeader::raw));
57+
58+
PseudoHeader pheader = {
59+
.data = {
60+
.src = src,
61+
.dest = dest,
62+
.zero = 0,
63+
.proto = IPv4Proto::TCP,
64+
.payload_size = data_offset() * sizeof(uint32_t) + payload_size
65+
}
66+
};
67+
68+
uint32_t sum = 0;
69+
70+
// Checksum of pseudo header
71+
auto* ptr = (uint16_t*) pheader.raw;
72+
for (size_t i = 0; i < sizeof(pheader) / sizeof(uint16_t); i++) {
73+
sum += as_big_endian(ptr[i]);
74+
if (sum > 0xffff)
75+
sum = (sum >> 16) + (sum & 0xffff);
76+
}
77+
78+
// Checksum of segment header
79+
const void* selfptr = this; // Necessary to suppress alignment errors
80+
ptr = (uint16_t*) selfptr;
81+
for (size_t i = 0; i < (data_offset() * sizeof(uint32_t)) / sizeof(uint16_t); i++) {
82+
sum += as_big_endian(ptr[i]);
83+
if (sum > 0xffff)
84+
sum = (sum >> 16) + (sum & 0xffff);
85+
}
86+
87+
// Checksum of payload
88+
ptr = (uint16_t*) payload();
89+
for (size_t i = 0; i < payload_size / sizeof(uint16_t); i++) {
90+
sum += as_big_endian(ptr[i]);
91+
if (sum > 0xffff)
92+
sum = (sum >> 16) + (sum & 0xffff);
93+
}
94+
95+
// Pad
96+
if (payload_size % 2 != 0) {
97+
sum += ((uint32_t) payload()[payload_size - 1]) << 8;
98+
if (sum > 0xffff)
99+
sum = (sum >> 16) + (sum & 0xffff);
100+
}
101+
102+
return ~(sum & 0xffff);
103+
}
104+
} __attribute__((packed));
105+
106+
static_assert(sizeof(TCPSegment) == 20);

kernel/net/E1000Adapter.cpp

+3-6
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@
112112
#define INT_RXO 0x40 // Receiver Overrun
113113
#define INT_RXT0 0x80 // Receiver Timer Interrupt
114114

115-
#define E1000_DBG true
115+
#define E1000_DBG false
116116

117117
void E1000Adapter::probe() {
118118
PCI::enumerate_devices([](PCI::Address address, PCI::ID id, uint16_t type, void* dataPtr) {
@@ -266,15 +266,12 @@ void E1000Adapter::receive() {
266266
ASSERT(desc.length <= rx_buffer_size);
267267
KLog::dbg_if<E1000_DBG>("E1000", "Received packet ({} bytes)", desc.length);
268268
desc.status = 0;
269-
{
270-
TaskManager::ScopedCritical crit;
271-
receive_bytes(KernelPointer((uint8_t*) (m_rx_buffer_region->start() + (rx_buffer_size * cur_desc))), desc.length);
272-
}
269+
receive_bytes({(uint8_t*) (m_rx_buffer_region->start() + (rx_buffer_size * cur_desc)), desc.length}, desc.length);
273270
m_window.out32(REG_RXDESCTAIL, cur_desc);
274271
}
275272
}
276273

277-
void E1000Adapter::send_bytes(SafePointer<uint8_t> bytes, size_t count) {
274+
void E1000Adapter::send_bytes(const ReadableBytes& bytes, size_t count) {
278275
ASSERT(count <= tx_buffer_size);
279276
PCI::disable_interrupt(m_pci_address);
280277
auto cur_tx_desc = m_window.in32(REG_TXDESCTAIL) % num_tx_descriptors;

kernel/net/E1000Adapter.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ class E1000Adapter: public NetworkAdapter, IRQHandler {
1515

1616
protected:
1717
void handle_irq(IRQRegisters *regs) override;
18-
void send_bytes(SafePointer<uint8_t> bytes, size_t count) override;
18+
void send_bytes(const ReadableBytes &bytes, size_t count) override;
1919

2020
private:
2121
explicit E1000Adapter(PCI::Address addr);

kernel/net/ICMP.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
#pragma once
55

6-
enum ICMPType {
6+
enum class ICMPType {
77
EchoReply = 0,
88
DestinationUnreachable = 3,
99
SourceQuench = 4,

0 commit comments

Comments
 (0)