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

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);