diff --git a/brewos.iso b/brewos.iso index d33e468..8654b31 100644 Binary files a/brewos.iso and b/brewos.iso differ diff --git a/build/about.o b/build/about.o index 2cf7426..2481993 100644 Binary files a/build/about.o and b/build/about.o differ diff --git a/build/brewos.elf b/build/brewos.elf index baac746..257bd0d 100755 Binary files a/build/brewos.elf and b/build/brewos.elf differ diff --git a/build/cli_apps/about.o b/build/cli_apps/about.o index 84c1a51..19001a8 100644 Binary files a/build/cli_apps/about.o and b/build/cli_apps/about.o differ diff --git a/build/cmd.o b/build/cmd.o index 13fc27c..b93ccad 100644 Binary files a/build/cmd.o and b/build/cmd.o differ diff --git a/build/dns.o b/build/dns.o new file mode 100644 index 0000000..fccdc31 Binary files /dev/null and b/build/dns.o differ diff --git a/build/http.o b/build/http.o new file mode 100644 index 0000000..b6d5e81 Binary files /dev/null and b/build/http.o differ diff --git a/build/icmp.o b/build/icmp.o new file mode 100644 index 0000000..0f25c43 Binary files /dev/null and b/build/icmp.o differ diff --git a/build/main.o b/build/main.o index 9ae7591..3c87b9b 100644 Binary files a/build/main.o and b/build/main.o differ diff --git a/build/network.o b/build/network.o index b02c1b3..b42e845 100644 Binary files a/build/network.o and b/build/network.o differ diff --git a/build/tcp.o b/build/tcp.o new file mode 100644 index 0000000..5509d88 Binary files /dev/null and b/build/tcp.o differ diff --git a/build/wm.o b/build/wm.o index f35305e..84b9702 100644 Binary files a/build/wm.o and b/build/wm.o differ diff --git a/icmp.c b/icmp.c new file mode 100644 index 0000000..c7d2a83 --- /dev/null +++ b/icmp.c @@ -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 \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++); + } +} \ No newline at end of file diff --git a/iso_root/brewos.elf b/iso_root/brewos.elf index baac746..257bd0d 100755 Binary files a/iso_root/brewos.elf and b/iso_root/brewos.elf differ diff --git a/limine b/limine index 5468ab2..36783ec 160000 --- a/limine +++ b/limine @@ -1 +1 @@ -Subproject commit 5468ab25166aed2f4cce9fe1a71066acf492f5ea +Subproject commit 36783ec43af4db4841a1e80770355fd1e98f091b diff --git a/net_defs.h b/net_defs.h new file mode 100644 index 0000000..cfd1f73 --- /dev/null +++ b/net_defs.h @@ -0,0 +1,99 @@ +#ifndef NET_DEFS_H +#define NET_DEFS_H + +#include +#include +#include + +// 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 \ No newline at end of file diff --git a/src/kernel/about.c b/src/kernel/about.c index 1086782..a3c3a3e 100644 --- a/src/kernel/about.c +++ b/src/kernel/about.c @@ -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); diff --git a/src/kernel/cli_apps/about.c b/src/kernel/cli_apps/about.c index b051ccb..93df31c 100644 --- a/src/kernel/cli_apps/about.c +++ b/src/kernel/cli_apps/about.c @@ -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"); } diff --git a/src/kernel/cmd.c b/src/kernel/cmd.c index c284e87..2f3d543 100644 --- a/src/kernel/cmd.c +++ b/src/kernel/cmd.c @@ -15,6 +15,7 @@ #include #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(); diff --git a/src/kernel/dns.c b/src/kernel/dns.c new file mode 100644 index 0000000..08adb1b --- /dev/null +++ b/src/kernel/dns.c @@ -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; iq_count); i++) { + while(*p != 0) p += (*p) + 1; // Skip name + p += 5; // Skip null + type + class + } + + // Parse Answers + for(int i=0; ians_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 \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"); + } +} \ No newline at end of file diff --git a/src/kernel/http.c b/src/kernel/http.c new file mode 100644 index 0000000..7c32f84 --- /dev/null +++ b/src/kernel/http.c @@ -0,0 +1,56 @@ +#include "net_defs.h" +#include "cmd.h" + +void cli_cmd_httpget(char *args) { + if (!args || !*args) { + cmd_write("Usage: httpget \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); +} \ No newline at end of file diff --git a/src/kernel/icmp.c b/src/kernel/icmp.c new file mode 100644 index 0000000..ec3c25d --- /dev/null +++ b/src/kernel/icmp.c @@ -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 \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; +} \ No newline at end of file diff --git a/src/kernel/main.c b/src/kernel/main.c index 902ac19..3e0a1a9 100644 --- a/src/kernel/main.c +++ b/src/kernel/main.c @@ -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"); } } diff --git a/src/kernel/net_defs.h b/src/kernel/net_defs.h new file mode 100644 index 0000000..4aede5e --- /dev/null +++ b/src/kernel/net_defs.h @@ -0,0 +1,112 @@ +#ifndef NET_DEFS_H +#define NET_DEFS_H + +#include +#include +#include + +// 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 diff --git a/src/kernel/network.c b/src/kernel/network.c index b2d5d81..5e7fcd4 100644 --- a/src/kernel/network.c +++ b/src/kernel/network.c @@ -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>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; diff --git a/src/kernel/network.h b/src/kernel/network.h index 95a2406..acedd93 100644 --- a/src/kernel/network.h +++ b/src/kernel/network.h @@ -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 diff --git a/src/kernel/tcp.c b/src/kernel/tcp.c new file mode 100644 index 0000000..8c0a1d9 --- /dev/null +++ b/src/kernel/tcp.c @@ -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 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; ichecksum = 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; irx_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; +} \ No newline at end of file diff --git a/src/kernel/wm.c b/src/kernel/wm.c index 66074b9..348563c 100644 --- a/src/kernel/wm.c +++ b/src/kernel/wm.c @@ -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); } diff --git a/src/kernel/wm.h b/src/kernel/wm.h index 13bf266..d2682f1 100644 --- a/src/kernel/wm.h +++ b/src/kernel/wm.h @@ -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);