Files
BoredOS/src/kernel/tcp.c
Chris e939d50be6 1.44 Beta
[BUG FIX UPDATE]
Updates until 1.50 will be bug fix updates as 1.50 will be a full release.
Bug fixes for 1.44:
-Stopped the crashing when moving stuff onto the desktop
-Fixed codeblock formatting in the markdown viewer.
2026-02-09 21:00:32 +01:00

204 lines
6.1 KiB
C

#include "net_defs.h"
#include "cmd.h"
#include "memory_manager.h"
// Simplified TCP State
typedef enum {
TCP_CLOSED,
TCP_SYN_SENT,
TCP_ESTABLISHED,
TCP_FIN_WAIT
} tcp_state_enum;
struct tcp_socket_t {
ipv4_address_t remote_ip;
uint16_t remote_port;
uint16_t local_port;
uint32_t seq_num;
uint32_t ack_num;
tcp_state_enum state;
// Receive Buffer
uint8_t *rx_buffer;
int rx_size;
int rx_pos;
bool connected;
};
static tcp_socket_t *active_socket = NULL; // Single socket support for simplicity
// Pseudo Header for Checksum
typedef struct {
uint32_t src_ip;
uint32_t dst_ip;
uint8_t reserved;
uint8_t protocol;
uint16_t tcp_len;
} __attribute__((packed)) tcp_pseudo_header_t;
static uint16_t tcp_checksum(tcp_socket_t *sock, tcp_header_t *tcp, const void *data, uint16_t len) {
uint32_t sum = 0;
// Pseudo Header
ipv4_address_t local = get_local_ip();
tcp_pseudo_header_t ph;
ph.src_ip = *(uint32_t*)local.bytes;
ph.dst_ip = *(uint32_t*)sock->remote_ip.bytes;
ph.reserved = 0;
ph.protocol = IP_PROTO_TCP;
ph.tcp_len = htons(sizeof(tcp_header_t) + len);
uint16_t *p = (uint16_t*)&ph;
for(int i=0; i<sizeof(tcp_pseudo_header_t)/2; i++) sum += p[i];
// TCP Header + Data
p = (uint16_t*)tcp;
for(int i=0; i<sizeof(tcp_header_t)/2; i++) sum += p[i];
p = (uint16_t*)data;
int dlen = len;
while(dlen > 1) {
sum += *p++;
dlen -= 2;
}
if(dlen) sum += *(uint8_t*)p;
while(sum >> 16) sum = (sum & 0xFFFF) + (sum >> 16);
return (uint16_t)~sum;
}
void tcp_send_packet(tcp_socket_t *sock, uint8_t flags, const void *data, uint16_t len) {
uint16_t total_len = sizeof(tcp_header_t) + len;
uint8_t *packet = kmalloc(total_len);
tcp_header_t *tcp = (tcp_header_t*)packet;
tcp->src_port = htons(sock->local_port);
tcp->dst_port = htons(sock->remote_port);
tcp->seq_num = htonl(sock->seq_num);
tcp->ack_num = htonl(sock->ack_num);
tcp->data_offset = (sizeof(tcp_header_t) / 4) << 4;
tcp->flags = flags;
tcp->window_size = htons(8192);
tcp->urgent_ptr = 0;
tcp->checksum = 0;
if (data) {
// Copy data
uint8_t *payload = packet + sizeof(tcp_header_t);
const uint8_t *d = (const uint8_t*)data;
for(int i=0; i<len; i++) payload[i] = d[i];
}
tcp->checksum = tcp_checksum(sock, tcp, data, len);
ip_send_packet(sock->remote_ip, IP_PROTO_TCP, packet, total_len);
kfree(packet);
// Advance sequence for SYN/FIN or data
if (len > 0 || (flags & (TCP_SYN|TCP_FIN))) {
sock->seq_num += (len > 0 ? len : 1);
}
}
void tcp_handle_packet(ipv4_address_t src, void *data, uint16_t len) {
if (!active_socket) return;
tcp_header_t *tcp = (tcp_header_t*)data;
uint16_t data_len = len - ((tcp->data_offset >> 4) * 4);
uint8_t *payload = (uint8_t*)data + ((tcp->data_offset >> 4) * 4);
// Check ports
if (ntohs(tcp->dst_port) != active_socket->local_port) return;
// State Machine
if (active_socket->state == TCP_SYN_SENT) {
if ((tcp->flags & TCP_SYN) && (tcp->flags & TCP_ACK)) {
active_socket->ack_num = ntohl(tcp->seq_num) + 1;
active_socket->state = TCP_ESTABLISHED;
active_socket->connected = true;
// Send ACK
tcp_send_packet(active_socket, TCP_ACK, NULL, 0);
}
} else if (active_socket->state == TCP_ESTABLISHED) {
if (tcp->flags & TCP_FIN) {
active_socket->ack_num = ntohl(tcp->seq_num) + 1;
tcp_send_packet(active_socket, TCP_ACK | TCP_FIN, NULL, 0);
active_socket->state = TCP_CLOSED;
active_socket->connected = false;
} else if (data_len > 0) {
// Accept data
if (active_socket->rx_pos < active_socket->rx_size) {
for(int i=0; i<data_len && active_socket->rx_pos < active_socket->rx_size - 1; i++) {
active_socket->rx_buffer[active_socket->rx_pos++] = payload[i];
}
active_socket->rx_buffer[active_socket->rx_pos] = 0; // Null terminate for text
}
active_socket->ack_num = ntohl(tcp->seq_num) + data_len;
tcp_send_packet(active_socket, TCP_ACK, NULL, 0);
}
}
}
tcp_socket_t* tcp_connect(ipv4_address_t ip, uint16_t port) {
if (active_socket) kfree(active_socket);
active_socket = kmalloc(sizeof(tcp_socket_t));
active_socket->remote_ip = ip;
active_socket->remote_port = port;
active_socket->local_port = 49152 + (port % 1000); // Random-ish ephemeral
active_socket->seq_num = 1000;
active_socket->ack_num = 0;
active_socket->state = TCP_SYN_SENT;
active_socket->connected = false;
active_socket->rx_buffer = kmalloc(65536); // 64KB buffer
active_socket->rx_size = 65536;
active_socket->rx_pos = 0;
// Send SYN
tcp_send_packet(active_socket, TCP_SYN, NULL, 0);
// Wait for connection (Blocking)
int timeout = 100000000;
while (!active_socket->connected && timeout-- > 0);
if (!active_socket->connected) {
kfree(active_socket->rx_buffer);
kfree(active_socket);
active_socket = NULL;
return NULL;
}
return active_socket;
}
void tcp_send(tcp_socket_t *sock, const char *data, int len) {
if (!sock || !sock->connected) return;
if (len == 0) {
// Calculate strlen
const char *p = data;
while(*p++) len++;
}
tcp_send_packet(sock, TCP_PSH | TCP_ACK, data, len);
}
void tcp_close(tcp_socket_t *sock) {
if (!sock) return;
tcp_send_packet(sock, TCP_FIN | TCP_ACK, NULL, 0);
sock->state = TCP_CLOSED;
sock->connected = false;
// Give time for packet to go out
for(volatile int i=0; i<1000000; i++);
kfree(sock->rx_buffer);
kfree(sock);
active_socket = NULL;
}
int tcp_read(tcp_socket_t *sock, char *buffer, int max_len) {
if (!sock) return 0;
int count = 0;
for (int i = 0; i < sock->rx_pos && i < max_len; i++) {
buffer[i] = sock->rx_buffer[i];
count++;
}
return count;
}