V1.30 (Alpha)

New Features:
-TCP/IP Updated network stack
-Ping (usage ping >ip<) does 4 8 byte echo pings to the inputted IP.
-DNS Grabs the IP address from a domain name (Broken)
-HTTPGET Gets http from a site (broken aswell lol)

Bug fix:
Moved the cmd apps out of the ISR so the system wouldn't hang on a ping or while trying to get DNS info.
This commit is contained in:
Chris 2026-02-06 20:12:13 +01:00
parent 931f235372
commit 62bc5d4017
29 changed files with 869 additions and 90 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
build/dns.o Normal file

Binary file not shown.

BIN
build/http.o Normal file

Binary file not shown.

BIN
build/icmp.o Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
build/tcp.o Normal file

Binary file not shown.

Binary file not shown.

65
icmp.c Normal file
View file

@ -0,0 +1,65 @@
#include "net_defs.h"
#include "cmd.h"
#include "memory_manager.h"
static volatile bool ping_reply_received = false;
static uint16_t ping_id_counter = 0;
void icmp_handle_packet(ipv4_address_t src, void *data, uint16_t len) {
icmp_header_t *icmp = (icmp_header_t *)data;
if (icmp->type == 0) { // Echo Reply
ping_reply_received = true;
char buf[64];
// Simple output
cmd_write("Reply from ");
cmd_write_int(src.bytes[0]); cmd_write(".");
cmd_write_int(src.bytes[1]); cmd_write(".");
cmd_write_int(src.bytes[2]); cmd_write(".");
cmd_write_int(src.bytes[3]);
cmd_write(": bytes=");
cmd_write_int(len - sizeof(icmp_header_t));
cmd_write(" seq=");
cmd_write_int(ntohs(icmp->sequence));
cmd_write("\n");
}
}
void cli_cmd_ping(char *args) {
if (!args || !*args) {
cmd_write("Usage: ping <ip>\n");
return;
}
// Parse IP (Simplified)
ipv4_address_t dest;
int ip_parts[4];
const char *p = args;
for(int i=0; i<4; i++) {
ip_parts[i] = 0;
while(*p >= '0' && *p <= '9') {
ip_parts[i] = ip_parts[i]*10 + (*p - '0');
p++;
}
if(*p == '.') p++;
dest.bytes[i] = (uint8_t)ip_parts[i];
}
cmd_write("Pinging...\n");
for (int i = 0; i < 4; i++) {
icmp_header_t icmp;
icmp.type = 8; // Echo Request
icmp.code = 0;
icmp.id = htons(++ping_id_counter);
icmp.sequence = htons(i + 1);
icmp.checksum = 0;
icmp.checksum = net_checksum(&icmp, sizeof(icmp_header_t));
ping_reply_received = false;
ip_send_packet(dest, IP_PROTO_ICMP, &icmp, sizeof(icmp_header_t));
// Simple busy wait for ~1 second (assuming loop speed)
for(volatile int w=0; w<100000000 && !ping_reply_received; w++);
}
}

Binary file not shown.

2
limine

@ -1 +1 @@
Subproject commit 5468ab25166aed2f4cce9fe1a71066acf492f5ea
Subproject commit 36783ec43af4db4841a1e80770355fd1e98f091b

99
net_defs.h Normal file
View file

@ -0,0 +1,99 @@
#ifndef NET_DEFS_H
#define NET_DEFS_H
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
// Ensure we have the IP type from your existing stack
#include "network.h"
// Protocol Numbers
#define IP_PROTO_ICMP 1
#define IP_PROTO_TCP 6
#define IP_PROTO_UDP 17
// Byte Order Utils
static inline uint16_t htons(uint16_t v) {
return (v << 8) | (v >> 8);
}
static inline uint16_t ntohs(uint16_t v) {
return (v << 8) | (v >> 8);
}
static inline uint32_t htonl(uint32_t v) {
return ((v & 0xFF) << 24) | ((v & 0xFF00) << 8) | ((v & 0xFF0000) >> 8) | ((v >> 24) & 0xFF);
}
static inline uint32_t ntohl(uint32_t v) {
return htonl(v);
}
// Checksum Calculation
static inline uint16_t net_checksum(void *data, int len) {
uint32_t sum = 0;
uint16_t *p = (uint16_t *)data;
while (len > 1) {
sum += *p++;
len -= 2;
}
if (len) {
sum += *(uint8_t *)p;
}
while (sum >> 16) {
sum = (sum & 0xFFFF) + (sum >> 16);
}
return (uint16_t)~sum;
}
// --- Headers ---
typedef struct {
uint8_t type;
uint8_t code;
uint16_t checksum;
uint16_t id;
uint16_t sequence;
} __attribute__((packed)) icmp_header_t;
typedef struct {
uint16_t src_port;
uint16_t dst_port;
uint32_t seq_num;
uint32_t ack_num;
uint8_t data_offset; // High 4 bits: offset, Low 4 bits: reserved/NS
uint8_t flags;
uint16_t window_size;
uint16_t checksum;
uint16_t urgent_ptr;
} __attribute__((packed)) tcp_header_t;
#define TCP_FIN 0x01
#define TCP_SYN 0x02
#define TCP_RST 0x04
#define TCP_PSH 0x08
#define TCP_ACK 0x10
#define TCP_URG 0x20
typedef struct {
uint16_t id;
uint16_t flags;
uint16_t q_count;
uint16_t ans_count;
uint16_t auth_count;
uint16_t add_count;
} __attribute__((packed)) dns_header_t;
// External dependencies from your existing IP layer
// You must ensure these are implemented in network.c
extern int ip_send_packet(ipv4_address_t dst, uint8_t protocol, const void *data, uint16_t len);
extern ipv4_address_t get_local_ip(void);
// New functions exposed by modules
void icmp_handle_packet(ipv4_address_t src, void *data, uint16_t len);
void tcp_handle_packet(ipv4_address_t src, void *data, uint16_t len);
// CLI Commands
void cli_cmd_ping(char *args);
void cli_cmd_dns(char *args);
void cli_cmd_httpget(char *args);
#endif

View file

@ -35,8 +35,8 @@ static void about_paint(Window *win) {
// Version info
draw_string(offset_x, offset_y + 105, "BrewOS", COLOR_BLACK);
draw_string(offset_x, offset_y + 120, "BrewOS Version 1.20", COLOR_BLACK);
draw_string(offset_x, offset_y + 135, "Kernel Version 2.2.0", COLOR_BLACK);
draw_string(offset_x, offset_y + 120, "BrewOS Version 1.30", COLOR_BLACK);
draw_string(offset_x, offset_y + 135, "Kernel Version 2.3.0", COLOR_BLACK);
// Copyright
draw_string(offset_x, offset_y + 150, "(C) 2026 boreddevnl.", COLOR_BLACK);

View file

@ -2,6 +2,6 @@
void cli_cmd_brewver(char *args) {
(void)args;
cli_write("BrewOS v1.20 Alpha\n");
cli_write("BrewOS Kernel V2.2.0 Pre-Alpha\n");
cli_write("BrewOS v1.30 Alpha\n");
cli_write("BrewOS Kernel V2.3.0 Pre-Alpha\n");
}

View file

@ -15,6 +15,7 @@
#include <stddef.h>
#include "network.h"
#include "vm.h"
#include "net_defs.h"
#define CMD_COLS 116
#define CMD_ROWS 41
@ -27,61 +28,6 @@
#define TXT_BUFFER_SIZE 4096
#define TXT_VISIBLE_LINES (CMD_ROWS - 2)
#define FS_MAX_FILES 16
#define FS_MAX_FILENAME 64
#define FS_MAX_SIZE 4096
typedef struct {
char name[FS_MAX_FILENAME];
char content[FS_MAX_SIZE];
int size;
bool used;
} RamFile;
static RamFile ram_fs[FS_MAX_FILES];
static void fs_init() {
for (int i = 0; i < FS_MAX_FILES; i++) {
ram_fs[i].used = false;
ram_fs[i].size = 0;
}
}
static RamFile* fs_find(const char *name) {
for (int i = 0; i < FS_MAX_FILES; i++) {
if (ram_fs[i].used) {
// Simple strcmp
const char *a = ram_fs[i].name;
const char *b = name;
bool match = true;
while (*a && *b) {
if (*a != *b) { match = false; break; }
a++; b++;
}
if (match && *a == *b) return &ram_fs[i];
}
}
return NULL;
}
static RamFile* fs_create(const char *name) {
if (fs_find(name)) return fs_find(name);
for (int i = 0; i < FS_MAX_FILES; i++) {
if (!ram_fs[i].used) {
ram_fs[i].used = true;
int j = 0;
while (name[j] && j < FS_MAX_FILENAME - 1) {
ram_fs[i].name[j] = name[j];
j++;
}
ram_fs[i].name[j] = 0;
ram_fs[i].size = 0;
return &ram_fs[i];
}
}
return NULL;
}
// --- Structs ---
typedef struct {
char c;
@ -131,11 +77,6 @@ void cmd_reset_msg_count(void) {
}
// --- Helpers ---
static void cmd_memset(void *dest, int val, size_t len) {
unsigned char *ptr = dest;
while (len-- > 0) *ptr++ = val;
}
static size_t cmd_strlen(const char *str) {
size_t len = 0;
while (str[len]) len++;
@ -155,23 +96,6 @@ static void cmd_strcpy(char *dest, const char *src) {
*dest = 0;
}
static int cmd_atoi(const char *str) {
int res = 0;
int sign = 1;
if (*str == '-') { sign = -1; str++; }
while (*str >= '0' && *str <= '9') {
res = res * 10 + (*str - '0');
str++;
}
return res * sign;
}
static void brewing(int iterations) {
for (volatile int i = 0; i < iterations; i++) {
__asm__ __volatile__("nop");
}
}
static void itoa(int n, char *buf) {
if (n == 0) {
buf[0] = '0'; buf[1] = 0; return;
@ -490,6 +414,12 @@ static const CommandEntry commands[] = {
{"udpsend", cli_cmd_udpsend},
{"UDPTEST", cli_cmd_udptest},
{"udptest", cli_cmd_udptest},
{"PING", cli_cmd_ping},
{"ping", cli_cmd_ping},
{"DNS", cli_cmd_dns},
{"dns", cli_cmd_dns},
{"HTTPGET", cli_cmd_httpget},
{"httpget", cli_cmd_httpget},
{"PCILIST", cli_cmd_pcilist},
{"pcilist", cli_cmd_pcilist},
{"MSGRC", cli_cmd_msgrc},
@ -1121,7 +1051,6 @@ static void create_test_files(void) {
}
void cmd_init(void) {
fs_init(); // Init RAMFS
fat32_init(); // Init FAT32 filesystem
create_test_files();

130
src/kernel/dns.c Normal file
View file

@ -0,0 +1,130 @@
#include "net_defs.h"
#include "cmd.h"
#include "memory_manager.h"
static ipv4_address_t dns_result_ip;
static bool dns_resolved = false;
void dns_handle_response(void *data, uint16_t len) {
dns_header_t *dns = (dns_header_t*)data;
if ((ntohs(dns->flags) & 0x8000) == 0) return; // Not a response
// Skip queries
uint8_t *p = (uint8_t*)(dns + 1);
for(int i=0; i<ntohs(dns->q_count); i++) {
while(*p != 0) p += (*p) + 1; // Skip name
p += 5; // Skip null + type + class
}
// Parse Answers
for(int i=0; i<ntohs(dns->ans_count); i++) {
// Name (pointer or label)
if ((*p & 0xC0) == 0xC0) p += 2;
else while(*p != 0) p += (*p) + 1;
uint16_t type = ntohs(*(uint16_t*)p); p += 2;
uint16_t class = ntohs(*(uint16_t*)p); p += 2;
uint32_t ttl = ntohl(*(uint32_t*)p); p += 4;
uint16_t dlen = ntohs(*(uint16_t*)p); p += 2;
if (type == 1 && dlen == 4) { // A Record
dns_result_ip.bytes[0] = p[0];
dns_result_ip.bytes[1] = p[1];
dns_result_ip.bytes[2] = p[2];
dns_result_ip.bytes[3] = p[3];
dns_resolved = true;
return;
}
p += dlen;
}
}
// Callback wrapper for the network stack
static void dns_udp_callback(const ipv4_address_t* src_ip, uint16_t src_port, const mac_address_t* src_mac, const void* data, size_t length) {
(void)src_ip; (void)src_port; (void)src_mac;
dns_handle_response((void*)data, (uint16_t)length);
}
ipv4_address_t dns_resolve(const char *hostname) {
dns_resolved = false;
dns_result_ip.bytes[0] = 0;
if (!network_is_initialized()) {
cmd_write("Error: Network not initialized. Run 'netinit' first.\n");
return dns_result_ip;
}
// Register callback
extern int udp_register_callback(uint16_t port, void (*callback)(const ipv4_address_t*, uint16_t, const mac_address_t*, const void*, size_t));
udp_register_callback(5353, dns_udp_callback);
// Construct Query
uint8_t buf[512];
dns_header_t *dns = (dns_header_t*)buf;
dns->id = htons(0x1234);
dns->flags = htons(0x0100); // Standard query
dns->q_count = htons(1);
dns->ans_count = 0;
dns->auth_count = 0;
dns->add_count = 0;
uint8_t *p = buf + sizeof(dns_header_t);
const char *h = hostname;
while (*h) {
const char *next = h;
while (*next && *next != '.') next++;
*p++ = (uint8_t)(next - h);
for(int i=0; i<(next-h); i++) *p++ = h[i];
h = next;
if (*h == '.') h++;
}
*p++ = 0; // End of name
*(uint16_t*)p = htons(1); p += 2; // Type A
*(uint16_t*)p = htons(1); p += 2; // Class IN
// Use DHCP provided DNS if available, otherwise fallback to Google
ipv4_address_t dns_server = get_dns_server_ip();
if (dns_server.bytes[0] == 0) {
dns_server.bytes[0] = 8; dns_server.bytes[1] = 8;
dns_server.bytes[2] = 8; dns_server.bytes[3] = 8;
}
extern int udp_send_packet(const ipv4_address_t *dest, uint16_t dest_port, uint16_t src_port, const void *data, size_t len);
// Retry loop to handle ARP resolution delay
for (int i = 0; i < 3 && !dns_resolved; i++) {
udp_send_packet(&dns_server, 53, 5353, buf, p - buf);
// Wait loop
int timeout = 20000000;
while (!dns_resolved && timeout-- > 0) {
extern void network_process_frames(void);
network_process_frames();
}
}
return dns_result_ip;
}
void cli_cmd_dns(char *args) {
if (!args || !*args) {
cmd_write("Usage: dns <hostname>\n");
return;
}
cmd_write("Resolving ");
cmd_write(args);
cmd_write("...\n");
ipv4_address_t ip = dns_resolve(args);
if (ip.bytes[0] == 0 && ip.bytes[1] == 0) {
cmd_write("Resolution failed.\n");
} else {
cmd_write("IP: ");
cmd_write_int(ip.bytes[0]); cmd_write(".");
cmd_write_int(ip.bytes[1]); cmd_write(".");
cmd_write_int(ip.bytes[2]); cmd_write(".");
cmd_write_int(ip.bytes[3]); cmd_write("\n");
}
}

56
src/kernel/http.c Normal file
View file

@ -0,0 +1,56 @@
#include "net_defs.h"
#include "cmd.h"
void cli_cmd_httpget(char *args) {
if (!args || !*args) {
cmd_write("Usage: httpget <hostname>\n");
return;
}
cmd_write("Resolving host...\n");
ipv4_address_t ip = dns_resolve(args);
if (ip.bytes[0] == 0 && ip.bytes[1] == 0) {
cmd_write("DNS Resolution failed.\n");
return;
}
cmd_write("Connecting to ");
cmd_write_int(ip.bytes[0]); cmd_write(".");
cmd_write_int(ip.bytes[1]); cmd_write(".");
cmd_write_int(ip.bytes[2]); cmd_write(".");
cmd_write_int(ip.bytes[3]); cmd_write("...\n");
tcp_socket_t *sock = tcp_connect(ip, 80);
if (!sock) {
cmd_write("Connection failed.\n");
return;
}
cmd_write("Sending Request...\n");
// Construct request
tcp_send(sock, "GET / HTTP/1.1\r\nHost: ", 0);
tcp_send(sock, args, 0);
tcp_send(sock, "\r\nConnection: close\r\n\r\n", 0);
cmd_write("Waiting for response...\n");
// Wait for data (simple delay loop for demo)
for(volatile int i=0; i<200000000; i++) {
extern void network_process_frames(void);
network_process_frames();
}
char buf[1024];
int len = tcp_read(sock, buf, 1023);
if (len > 0) {
buf[len] = 0;
cmd_write("\n--- Response ---\n");
cmd_write(buf);
cmd_write("\n----------------\n");
} else {
cmd_write("No data received.\n");
}
tcp_close(sock);
}

87
src/kernel/icmp.c Normal file
View file

@ -0,0 +1,87 @@
#include "net_defs.h"
#include "cmd.h"
#include "memory_manager.h"
static volatile bool ping_reply_received = false;
static uint16_t ping_id_counter = 0;
static uint16_t current_ping_id = 0;
static bool is_pinging = false;
void icmp_handle_packet(ipv4_address_t src, void *data, uint16_t len) {
icmp_header_t *icmp = (icmp_header_t *)data;
if (icmp->type == 0 && is_pinging && ntohs(icmp->id) == current_ping_id) { // Echo Reply
ping_reply_received = true;
// Simple output
cmd_write("Reply from ");
cmd_write_int(src.bytes[0]); cmd_write(".");
cmd_write_int(src.bytes[1]); cmd_write(".");
cmd_write_int(src.bytes[2]); cmd_write(".");
cmd_write_int(src.bytes[3]);
cmd_write(": bytes=");
cmd_write_int(len - sizeof(icmp_header_t));
cmd_write(" seq=");
cmd_write_int(ntohs(icmp->sequence));
cmd_write("\n");
}
}
void cli_cmd_ping(char *args) {
if (!args || !*args) {
cmd_write("Usage: ping <ip>\n");
return;
}
// Parse IP (Simplified)
ipv4_address_t dest;
int ip_parts[4];
const char *p = args;
for(int i=0; i<4; i++) {
ip_parts[i] = 0;
while(*p >= '0' && *p <= '9') {
ip_parts[i] = ip_parts[i]*10 + (*p - '0');
p++;
}
if(*p == '.') p++;
dest.bytes[i] = (uint8_t)ip_parts[i];
}
cmd_write("Pinging...\n");
is_pinging = true;
const int payload_size = 8;
uint8_t packet[sizeof(icmp_header_t) + payload_size];
icmp_header_t *icmp = (icmp_header_t *)packet;
for (int i = 0; i < 4; i++) {
current_ping_id = ++ping_id_counter;
icmp->type = 8; // Echo Request
icmp->code = 0;
icmp->id = htons(current_ping_id);
icmp->sequence = htons(i + 1);
icmp->checksum = 0;
// Fill payload
for (int j = 0; j < payload_size; j++) {
packet[sizeof(icmp_header_t) + j] = (uint8_t)('a' + (j % 26));
}
icmp->checksum = net_checksum(packet, sizeof(packet));
ping_reply_received = false;
ip_send_packet(dest, IP_PROTO_ICMP, packet, sizeof(packet));
// Busy wait for reply. Increased timeout to ensure reply is caught.
for(volatile int w=0; w<2000000 && !ping_reply_received; w++) {
network_process_frames();
}
if (!ping_reply_received) {
cmd_write("Request timed out.\n");
} else if (i < 3) {
// Wait a bit before next ping
for(volatile int w=0; w<500000; w++) network_process_frames();
}
}
is_pinging = false;
}

View file

@ -103,6 +103,7 @@ void kmain(void) {
// 5. Main loop - just wait for interrupts
// Timer interrupt will drive the redraw system
while (1) {
wm_process_input();
asm("hlt");
}
}

112
src/kernel/net_defs.h Normal file
View file

@ -0,0 +1,112 @@
#ifndef NET_DEFS_H
#define NET_DEFS_H
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
// Ensure we have the IP type from your existing stack
#include "network.h"
// Protocol Numbers
#define IP_PROTO_ICMP 1
#define IP_PROTO_TCP 6
#define IP_PROTO_UDP 17
// Byte Order Utils
static inline uint16_t htons(uint16_t v) {
return (v << 8) | (v >> 8);
}
static inline uint16_t ntohs(uint16_t v) {
return (v << 8) | (v >> 8);
}
static inline uint32_t htonl(uint32_t v) {
return ((v & 0xFF) << 24) | ((v & 0xFF00) << 8) | ((v & 0xFF0000) >> 8) | ((v >> 24) & 0xFF);
}
static inline uint32_t ntohl(uint32_t v) {
return htonl(v);
}
// Checksum Calculation
static inline uint16_t net_checksum(void *data, int len) {
uint32_t sum = 0;
uint16_t *p = (uint16_t *)data;
while (len > 1) {
sum += *p++;
len -= 2;
}
if (len) {
sum += *(uint8_t *)p;
}
while (sum >> 16) {
sum = (sum & 0xFFFF) + (sum >> 16);
}
return (uint16_t)~sum;
}
// --- Headers ---
typedef struct {
uint8_t type;
uint8_t code;
uint16_t checksum;
uint16_t id;
uint16_t sequence;
} __attribute__((packed)) icmp_header_t;
typedef struct {
uint16_t src_port;
uint16_t dst_port;
uint32_t seq_num;
uint32_t ack_num;
uint8_t data_offset; // High 4 bits: offset, Low 4 bits: reserved/NS
uint8_t flags;
uint16_t window_size;
uint16_t checksum;
uint16_t urgent_ptr;
} __attribute__((packed)) tcp_header_t;
#define TCP_FIN 0x01
#define TCP_SYN 0x02
#define TCP_RST 0x04
#define TCP_PSH 0x08
#define TCP_ACK 0x10
#define TCP_URG 0x20
typedef struct {
uint16_t id;
uint16_t flags;
uint16_t q_count;
uint16_t ans_count;
uint16_t auth_count;
uint16_t add_count;
} __attribute__((packed)) dns_header_t;
// --- TCP Socket API ---
typedef struct tcp_socket_t tcp_socket_t; // Opaque type
tcp_socket_t* tcp_connect(ipv4_address_t ip, uint16_t port);
void tcp_send(tcp_socket_t *sock, const char *data, int len);
void tcp_close(tcp_socket_t *sock);
bool tcp_is_connected(tcp_socket_t *sock);
int tcp_read(tcp_socket_t *sock, char *buffer, int max_len);
// --- DNS API ---
ipv4_address_t dns_resolve(const char *hostname);
// External dependencies from your existing IP layer
// You must ensure these are implemented in network.c
extern int ip_send_packet(ipv4_address_t dst, uint8_t protocol, const void *data, uint16_t len);
extern ipv4_address_t get_local_ip(void);
extern ipv4_address_t get_dns_server_ip(void);
// New functions exposed by modules
void icmp_handle_packet(ipv4_address_t src, void *data, uint16_t len);
void tcp_handle_packet(ipv4_address_t src, void *data, uint16_t len);
// CLI Commands
void cli_cmd_ping(char *args);
void cli_cmd_dns(char *args);
void cli_cmd_httpget(char *args);
#endif

View file

@ -3,10 +3,15 @@
#include "network.h"
#include "e1000.h"
#include "pci.h"
#undef IP_PROTO_UDP // Avoid redefinition warning from net_defs.h
#include "net_defs.h"
static int network_initialized = 0;
static mac_address_t our_mac;
static ipv4_address_t ip_address = {{0,0,0,0}};
static ipv4_address_t gateway_ip = {{0,0,0,0}};
static ipv4_address_t subnet_mask = {{0,0,0,0}};
static ipv4_address_t dns_server_ip = {{0,0,0,0}};
static uint16_t ipv4_id_counter = 0;
typedef struct { ipv4_address_t ip; mac_address_t mac; uint32_t timestamp; int valid; } arp_cache_entry_t;
@ -29,10 +34,6 @@ static void* kmemcpy(void* d, const void* s, size_t n){uint8_t*D=d;const uint8_t
static void* kmemset(void* d,int v,size_t n){uint8_t*D=d;for(size_t i=0;i<n;i++)D[i]=(uint8_t)v;return d;}
static int kmemcmp(const void* a,const void* b,size_t n){const uint8_t*A=a;const uint8_t*B=b;for(size_t i=0;i<n;i++){if(A[i]!=B[i])return (int)A[i]-(int)B[i];}return 0;}
static uint16_t htons(uint16_t x){return (uint16_t)(((x&0xFF)<<8)|((x>>8)&0xFF));}
static uint16_t ntohs(uint16_t x){return htons(x);}
static uint32_t htonl(uint32_t v){return ((v&0xFF)<<24)|((v&0xFF00)<<8)|((v>>8)&0xFF00)|((v>>24)&0xFF);}
static uint16_t ipv4_checksum(const ipv4_header_t* h){
uint32_t sum=0;const uint16_t* w=(const uint16_t*)h;
for(int i=0;i<10;i++) sum+=w[i];
@ -66,6 +67,20 @@ int network_get_mac_address(mac_address_t* mac){
int network_get_ipv4_address(ipv4_address_t* ip){ if(!network_initialized) return -1; *ip=ip_address; return 0; }
int network_set_ipv4_address(const ipv4_address_t* ip){ if(!network_initialized) return -1; ip_address=*ip; return 0; }
int network_get_gateway_ip(ipv4_address_t* ip){ if(!network_initialized) return -1; *ip=gateway_ip; return 0; }
int network_get_dns_ip(ipv4_address_t* ip){ if(!network_initialized) return -1; *ip=dns_server_ip; return 0; }
ipv4_address_t get_local_ip(void) {
return ip_address;
}
ipv4_address_t get_dns_server_ip(void) {
return dns_server_ip;
}
int ip_send_packet(ipv4_address_t dst, uint8_t protocol, const void *data, uint16_t len) {
return ipv4_send_packet(&dst, protocol, data, len);
}
int network_send_frame(const void* data,size_t length){ if(!network_initialized) return -1; if(length>ETH_FRAME_MAX_SIZE) return -1; return e1000_send_packet(data,length); }
int network_receive_frame(void* buffer,size_t buffer_size){
@ -185,8 +200,34 @@ int ipv4_send_packet(const ipv4_address_t* dest_ip,uint8_t protocol,const void*
if(!network_initialized) return -1;
mac_address_t dest_mac;
int is_bcast=(dest_ip->bytes[0]==255 && dest_ip->bytes[1]==255 && dest_ip->bytes[2]==255 && dest_ip->bytes[3]==255);
if(is_bcast){ for(int i=0;i<6;i++) dest_mac.bytes[i]=0xFF; }
else { int ok=arp_lookup(dest_ip,&dest_mac); if(ok!=0){ for(int i=0;i<6;i++) dest_mac.bytes[i]=0xFF; } }
ipv4_address_t target_ip = *dest_ip;
// Routing Logic: If dest is not local, send to Gateway
if (!is_bcast && gateway_ip.bytes[0] != 0 && subnet_mask.bytes[0] != 0) {
int is_local = 1;
for(int i=0; i<4; i++) {
if ((dest_ip->bytes[i] & subnet_mask.bytes[i]) != (ip_address.bytes[i] & subnet_mask.bytes[i])) {
is_local = 0;
break;
}
}
if (!is_local) {
target_ip = gateway_ip;
}
}
if(is_bcast){
for(int i=0;i<6;i++) dest_mac.bytes[i]=0xFF;
} else {
int ok=arp_lookup(&target_ip,&dest_mac);
if(ok!=0){
// ARP failed, maybe broadcast? Or fail?
// For now, keep existing behavior of broadcasting if ARP fails
for(int i=0;i<6;i++) dest_mac.bytes[i]=0xFF;
}
}
uint8_t frame[ETH_FRAME_MAX_SIZE];
eth_header_t* eth=(eth_header_t*)frame;
ipv4_header_t* ip=(ipv4_header_t*)(frame+sizeof(eth_header_t));
@ -263,6 +304,14 @@ void ipv4_process_packet(const ipv4_header_t* ip,const mac_address_t* src_mac,si
}
}
}
} else if (ip->protocol == IP_PROTO_ICMP) {
ipv4_address_t src_ip;
kmemcpy(src_ip.bytes, ip->src_ip, 4);
icmp_handle_packet(src_ip, payload, payload_length);
} else if (ip->protocol == IP_PROTO_TCP) {
ipv4_address_t src_ip;
kmemcpy(src_ip.bytes, ip->src_ip, 4);
tcp_handle_packet(src_ip, payload, payload_length);
}
}
@ -330,6 +379,9 @@ int network_get_process_calls(void){ return network_process_calls; }
#define DHCP_OPT_MSG_TYPE 53
#define DHCP_OPT_SERVER_ID 54
#define DHCP_OPT_REQ_IP 50
#define DHCP_OPT_SUBNET_MASK 1
#define DHCP_OPT_ROUTER 3
#define DHCP_OPT_DNS 6
#define DHCP_OPT_PARAM_REQ_LIST 55
#define DHCP_OPT_END 255
@ -414,6 +466,24 @@ static void dhcp_udp_callback(const ipv4_address_t* src_ip,uint16_t src_port,con
ip_address.bytes[1]=(uint8_t)((yi_host>>16)&0xFF);
ip_address.bytes[2]=(uint8_t)((yi_host>>8)&0xFF);
ip_address.bytes[3]=(uint8_t)(yi_host&0xFF);
// Parse Options for Gateway, Subnet, DNS
const uint8_t* p=pkt->options;
while(*p!=DHCP_OPT_END){
uint8_t c=*p++;
uint8_t l=*p++;
if(c==DHCP_OPT_SUBNET_MASK && l==4) {
kmemcpy(subnet_mask.bytes, p, 4);
} else if(c==DHCP_OPT_ROUTER && l>=4) {
// Take first router
kmemcpy(gateway_ip.bytes, p, 4);
} else if(c==DHCP_OPT_DNS && l>=4) {
// Take first DNS
kmemcpy(dns_server_ip.bytes, p, 4);
}
p+=l;
}
dhcp_state=2;
} else if(mtype==DHCP_MSG_NAK){
dhcp_state=-1;

View file

@ -81,5 +81,7 @@ int network_get_e1000_receive_calls(void);
int network_get_e1000_receive_empty(void);
int network_get_process_calls(void);
int network_dhcp_acquire(void);
int network_get_gateway_ip(ipv4_address_t* ip);
int network_get_dns_ip(ipv4_address_t* ip);
#endif

205
src/kernel/tcp.c Normal file
View file

@ -0,0 +1,205 @@
#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;
// Simple copy of what we have
int count = 0;
for (int i = 0; i < sock->rx_pos && i < max_len; i++) {
buffer[i] = sock->rx_buffer[i];
count++;
}
return count;
}

View file

@ -682,7 +682,13 @@ void wm_handle_right_click(int x, int y) {
prev_left = left;
}
void wm_handle_key(char c) {
// Input Queue
#define INPUT_QUEUE_SIZE 128
static char key_queue[INPUT_QUEUE_SIZE];
static volatile int key_head = 0;
static volatile int key_tail = 0;
static void wm_dispatch_key(char c) {
Window *target = NULL;
if (win_notepad.focused && win_notepad.visible) target = &win_notepad;
else if (win_cmd.focused && win_cmd.visible) target = &win_cmd;
@ -702,6 +708,22 @@ void wm_handle_key(char c) {
wm_mark_dirty(target->x, target->y, target->w, target->h);
}
void wm_handle_key(char c) {
int next = (key_head + 1) % INPUT_QUEUE_SIZE;
if (next != key_tail) {
key_queue[key_head] = c;
key_head = next;
}
}
void wm_process_input(void) {
while (key_head != key_tail) {
char c = key_queue[key_tail];
key_tail = (key_tail + 1) % INPUT_QUEUE_SIZE;
wm_dispatch_key(c);
}
}
void wm_mark_dirty(int x, int y, int w, int h) {
graphics_mark_dirty(x, y, w, h);
}

View file

@ -45,6 +45,7 @@ void wm_handle_mouse(int dx, int dy, uint8_t buttons);
void wm_handle_key(char c);
void wm_handle_click(int x, int y);
void wm_handle_right_click(int x, int y);
void wm_process_input(void);
// Redraw system
void wm_mark_dirty(int x, int y, int w, int h);