mirror of
https://github.com/BoredDevNL/BoredOS.git
synced 2026-05-15 10:48:38 +00:00
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:
parent
931f235372
commit
62bc5d4017
29 changed files with 869 additions and 90 deletions
BIN
brewos.iso
BIN
brewos.iso
Binary file not shown.
BIN
build/about.o
BIN
build/about.o
Binary file not shown.
BIN
build/brewos.elf
BIN
build/brewos.elf
Binary file not shown.
Binary file not shown.
BIN
build/cmd.o
BIN
build/cmd.o
Binary file not shown.
BIN
build/dns.o
Normal file
BIN
build/dns.o
Normal file
Binary file not shown.
BIN
build/http.o
Normal file
BIN
build/http.o
Normal file
Binary file not shown.
BIN
build/icmp.o
Normal file
BIN
build/icmp.o
Normal file
Binary file not shown.
BIN
build/main.o
BIN
build/main.o
Binary file not shown.
BIN
build/network.o
BIN
build/network.o
Binary file not shown.
BIN
build/tcp.o
Normal file
BIN
build/tcp.o
Normal file
Binary file not shown.
BIN
build/wm.o
BIN
build/wm.o
Binary file not shown.
65
icmp.c
Normal file
65
icmp.c
Normal 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
2
limine
|
|
@ -1 +1 @@
|
||||||
Subproject commit 5468ab25166aed2f4cce9fe1a71066acf492f5ea
|
Subproject commit 36783ec43af4db4841a1e80770355fd1e98f091b
|
||||||
99
net_defs.h
Normal file
99
net_defs.h
Normal 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
|
||||||
|
|
@ -35,8 +35,8 @@ static void about_paint(Window *win) {
|
||||||
|
|
||||||
// Version info
|
// Version info
|
||||||
draw_string(offset_x, offset_y + 105, "BrewOS", COLOR_BLACK);
|
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 + 120, "BrewOS Version 1.30", COLOR_BLACK);
|
||||||
draw_string(offset_x, offset_y + 135, "Kernel Version 2.2.0", COLOR_BLACK);
|
draw_string(offset_x, offset_y + 135, "Kernel Version 2.3.0", COLOR_BLACK);
|
||||||
|
|
||||||
// Copyright
|
// Copyright
|
||||||
draw_string(offset_x, offset_y + 150, "(C) 2026 boreddevnl.", COLOR_BLACK);
|
draw_string(offset_x, offset_y + 150, "(C) 2026 boreddevnl.", COLOR_BLACK);
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,6 @@
|
||||||
|
|
||||||
void cli_cmd_brewver(char *args) {
|
void cli_cmd_brewver(char *args) {
|
||||||
(void)args;
|
(void)args;
|
||||||
cli_write("BrewOS v1.20 Alpha\n");
|
cli_write("BrewOS v1.30 Alpha\n");
|
||||||
cli_write("BrewOS Kernel V2.2.0 Pre-Alpha\n");
|
cli_write("BrewOS Kernel V2.3.0 Pre-Alpha\n");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include "network.h"
|
#include "network.h"
|
||||||
#include "vm.h"
|
#include "vm.h"
|
||||||
|
#include "net_defs.h"
|
||||||
|
|
||||||
#define CMD_COLS 116
|
#define CMD_COLS 116
|
||||||
#define CMD_ROWS 41
|
#define CMD_ROWS 41
|
||||||
|
|
@ -27,61 +28,6 @@
|
||||||
#define TXT_BUFFER_SIZE 4096
|
#define TXT_BUFFER_SIZE 4096
|
||||||
#define TXT_VISIBLE_LINES (CMD_ROWS - 2)
|
#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 ---
|
// --- Structs ---
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char c;
|
char c;
|
||||||
|
|
@ -131,11 +77,6 @@ void cmd_reset_msg_count(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Helpers ---
|
// --- 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) {
|
static size_t cmd_strlen(const char *str) {
|
||||||
size_t len = 0;
|
size_t len = 0;
|
||||||
while (str[len]) len++;
|
while (str[len]) len++;
|
||||||
|
|
@ -155,23 +96,6 @@ static void cmd_strcpy(char *dest, const char *src) {
|
||||||
*dest = 0;
|
*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) {
|
static void itoa(int n, char *buf) {
|
||||||
if (n == 0) {
|
if (n == 0) {
|
||||||
buf[0] = '0'; buf[1] = 0; return;
|
buf[0] = '0'; buf[1] = 0; return;
|
||||||
|
|
@ -490,6 +414,12 @@ static const CommandEntry commands[] = {
|
||||||
{"udpsend", cli_cmd_udpsend},
|
{"udpsend", cli_cmd_udpsend},
|
||||||
{"UDPTEST", cli_cmd_udptest},
|
{"UDPTEST", cli_cmd_udptest},
|
||||||
{"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},
|
||||||
{"pcilist", cli_cmd_pcilist},
|
{"pcilist", cli_cmd_pcilist},
|
||||||
{"MSGRC", cli_cmd_msgrc},
|
{"MSGRC", cli_cmd_msgrc},
|
||||||
|
|
@ -1121,7 +1051,6 @@ static void create_test_files(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void cmd_init(void) {
|
void cmd_init(void) {
|
||||||
fs_init(); // Init RAMFS
|
|
||||||
fat32_init(); // Init FAT32 filesystem
|
fat32_init(); // Init FAT32 filesystem
|
||||||
create_test_files();
|
create_test_files();
|
||||||
|
|
||||||
|
|
|
||||||
130
src/kernel/dns.c
Normal file
130
src/kernel/dns.c
Normal 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
56
src/kernel/http.c
Normal 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
87
src/kernel/icmp.c
Normal 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;
|
||||||
|
}
|
||||||
|
|
@ -103,6 +103,7 @@ void kmain(void) {
|
||||||
// 5. Main loop - just wait for interrupts
|
// 5. Main loop - just wait for interrupts
|
||||||
// Timer interrupt will drive the redraw system
|
// Timer interrupt will drive the redraw system
|
||||||
while (1) {
|
while (1) {
|
||||||
|
wm_process_input();
|
||||||
asm("hlt");
|
asm("hlt");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
112
src/kernel/net_defs.h
Normal file
112
src/kernel/net_defs.h
Normal 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
|
||||||
|
|
@ -3,10 +3,15 @@
|
||||||
#include "network.h"
|
#include "network.h"
|
||||||
#include "e1000.h"
|
#include "e1000.h"
|
||||||
#include "pci.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 int network_initialized = 0;
|
||||||
static mac_address_t our_mac;
|
static mac_address_t our_mac;
|
||||||
static ipv4_address_t ip_address = {{0,0,0,0}};
|
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;
|
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;
|
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 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 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){
|
static uint16_t ipv4_checksum(const ipv4_header_t* h){
|
||||||
uint32_t sum=0;const uint16_t* w=(const uint16_t*)h;
|
uint32_t sum=0;const uint16_t* w=(const uint16_t*)h;
|
||||||
for(int i=0;i<10;i++) sum+=w[i];
|
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_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_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_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){
|
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;
|
if(!network_initialized) return -1;
|
||||||
mac_address_t dest_mac;
|
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);
|
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];
|
uint8_t frame[ETH_FRAME_MAX_SIZE];
|
||||||
eth_header_t* eth=(eth_header_t*)frame;
|
eth_header_t* eth=(eth_header_t*)frame;
|
||||||
ipv4_header_t* ip=(ipv4_header_t*)(frame+sizeof(eth_header_t));
|
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_MSG_TYPE 53
|
||||||
#define DHCP_OPT_SERVER_ID 54
|
#define DHCP_OPT_SERVER_ID 54
|
||||||
#define DHCP_OPT_REQ_IP 50
|
#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_PARAM_REQ_LIST 55
|
||||||
#define DHCP_OPT_END 255
|
#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[1]=(uint8_t)((yi_host>>16)&0xFF);
|
||||||
ip_address.bytes[2]=(uint8_t)((yi_host>>8)&0xFF);
|
ip_address.bytes[2]=(uint8_t)((yi_host>>8)&0xFF);
|
||||||
ip_address.bytes[3]=(uint8_t)(yi_host&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;
|
dhcp_state=2;
|
||||||
} else if(mtype==DHCP_MSG_NAK){
|
} else if(mtype==DHCP_MSG_NAK){
|
||||||
dhcp_state=-1;
|
dhcp_state=-1;
|
||||||
|
|
|
||||||
|
|
@ -81,5 +81,7 @@ int network_get_e1000_receive_calls(void);
|
||||||
int network_get_e1000_receive_empty(void);
|
int network_get_e1000_receive_empty(void);
|
||||||
int network_get_process_calls(void);
|
int network_get_process_calls(void);
|
||||||
int network_dhcp_acquire(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
|
#endif
|
||||||
|
|
|
||||||
205
src/kernel/tcp.c
Normal file
205
src/kernel/tcp.c
Normal 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;
|
||||||
|
}
|
||||||
|
|
@ -682,7 +682,13 @@ void wm_handle_right_click(int x, int y) {
|
||||||
prev_left = left;
|
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;
|
Window *target = NULL;
|
||||||
if (win_notepad.focused && win_notepad.visible) target = &win_notepad;
|
if (win_notepad.focused && win_notepad.visible) target = &win_notepad;
|
||||||
else if (win_cmd.focused && win_cmd.visible) target = &win_cmd;
|
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);
|
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) {
|
void wm_mark_dirty(int x, int y, int w, int h) {
|
||||||
graphics_mark_dirty(x, y, w, h);
|
graphics_mark_dirty(x, y, w, 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_key(char c);
|
||||||
void wm_handle_click(int x, int y);
|
void wm_handle_click(int x, int y);
|
||||||
void wm_handle_right_click(int x, int y);
|
void wm_handle_right_click(int x, int y);
|
||||||
|
void wm_process_input(void);
|
||||||
|
|
||||||
// Redraw system
|
// Redraw system
|
||||||
void wm_mark_dirty(int x, int y, int w, int h);
|
void wm_mark_dirty(int x, int y, int w, int h);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue