fix(baremetal,net): fix bare-metal boot freezes and implement real internet stack

- Zero user PML4 and allocated page tables in VMM to prevent dirty RAM crash on real hardware
- Probe UART existence and add timeout to prevent infinite freeze on motherboards without COM1
- Clamp SMP AP boot to MAX_CPUS to prevent GDT/TSS corruption on multi-core CPUs
- Add kernel early framebuffer console (FbConsole) with 8x16 font for direct HDMI/DP screen output
- Configure Limine resolution and dynamic 4K draw buffers in gui_server to fix 1080p black screen
- Implement RFC 793 TCP pseudo-header checksum and full TCP 3-way handshake
- Implement DHCP client (UDP 67/68) and DNS client (UDP 53)
- Add dns, dhcp commands to shell and update web browser with live URL loading
This commit is contained in:
RarDog
2026-09-03 10:40:23 +03:00
parent ca75e961f9
commit de772a2de0
12 changed files with 863 additions and 174 deletions
+522 -115
View File
@@ -2,23 +2,41 @@
#include "rtl8139.h"
#include "string.h"
#include "stdio.h"
#include <stdbool.h>
// Default QEMU User Networking (SLIRP) Configuration
// Guest IP: 10.0.2.15
// Gateway: 10.0.2.2 (Default QEMU MAC: 52:55:0a:00:02:02)
// DNS: 10.0.2.3
net_config_t g_net_cfg = {
.ip = (10) | (0 << 8) | (2 << 16) | (15 << 24),
.gateway = (10) | (0 << 8) | (2 << 16) | (2 << 24),
.dns_server = (10) | (0 << 8) | (2 << 16) | (3 << 24),
.netmask = (255) | (255 << 8) | (255 << 16) | (0 << 24),
.mac = {0x52, 0x54, 0x00, 0x12, 0x34, 0x56}
};
static uint8_t g_gateway_mac[6] = {0x52, 0x55, 0x0a, 0x00, 0x02, 0x02};
static uint16_t htons(uint16_t v) {
static inline uint16_t htons(uint16_t v) {
return (uint16_t)(((v & 0xFF) << 8) | ((v >> 8) & 0xFF));
}
static inline uint16_t ntohs(uint16_t v) {
return htons(v);
}
static inline uint32_t htonl(uint32_t v) {
return (((v & 0x000000FF) << 24) |
((v & 0x0000FF00) << 8) |
((v & 0x00FF0000) >> 8) |
((v & 0xFF000000) >> 24));
}
static inline uint32_t ntohl(uint32_t v) {
return htonl(v);
}
uint16_t net_checksum(const void *buf, size_t len) {
const uint16_t *data = (const uint16_t *)buf;
uint32_t sum = 0;
@@ -36,6 +54,43 @@ uint16_t net_checksum(const void *buf, size_t len) {
return (uint16_t)(~sum);
}
// RFC 793 TCP Pseudo-Header Checksum
uint16_t net_tcp_checksum(uint32_t src_ip, uint32_t dst_ip, const tcp_hdr_t *tcp, size_t tcp_len) {
struct __attribute__((packed)) {
uint32_t src;
uint32_t dst;
uint8_t zero;
uint8_t proto;
uint16_t length;
} ph;
ph.src = src_ip;
ph.dst = dst_ip;
ph.zero = 0;
ph.proto = IP_PROTO_TCP;
ph.length = htons((uint16_t)tcp_len);
uint32_t sum = 0;
const uint16_t *p = (const uint16_t *)&ph;
for (size_t i = 0; i < sizeof(ph) / 2; i++) {
sum += p[i];
}
const uint16_t *data = (const uint16_t *)tcp;
size_t len = tcp_len;
while (len > 1) {
sum += *data++;
len -= 2;
}
if (len == 1) {
sum += *(const uint8_t *)data;
}
while (sum >> 16) {
sum = (sum & 0xFFFF) + (sum >> 16);
}
return (uint16_t)(~sum);
}
void net_init(void) {
rtl8139_init();
for (int i = 0; i < 6; i++) {
@@ -50,17 +105,15 @@ int net_send_arp_request(uint32_t target_ip) {
eth_hdr_t *eth = (eth_hdr_t *)packet;
arp_hdr_t *arp = (arp_hdr_t *)(packet + sizeof(eth_hdr_t));
// Broadcast Ethernet Header
memset(eth->dest_mac, 0xFF, 6);
memcpy(eth->src_mac, g_net_cfg.mac, 6);
eth->ethertype = htons(ETHERTYPE_ARP);
// ARP Payload (Who has target_ip? Tell sender_ip)
arp->hw_type = htons(1); // Ethernet
arp->proto_type = htons(0x0800); // IPv4
arp->hw_type = htons(1);
arp->proto_type = htons(0x0800);
arp->hw_len = 6;
arp->proto_len = 4;
arp->opcode = htons(1); // Request
arp->opcode = htons(1); // ARP Request
memcpy(arp->sender_mac, g_net_cfg.mac, 6);
arp->sender_ip = g_net_cfg.ip;
memset(arp->target_mac, 0x00, 6);
@@ -76,17 +129,15 @@ int net_send_icmp_ping(uint32_t target_ip, uint16_t seq) {
icmp_hdr_t *icmp = (icmp_hdr_t *)(packet + sizeof(eth_hdr_t) + sizeof(ipv4_hdr_t));
uint8_t *payload = packet + sizeof(eth_hdr_t) + sizeof(ipv4_hdr_t) + sizeof(icmp_hdr_t);
// 1. Ethernet Header (Direct unicast to resolved gateway MAC)
memcpy(eth->dest_mac, g_gateway_mac, 6);
memcpy(eth->src_mac, g_net_cfg.mac, 6);
eth->ethertype = htons(ETHERTYPE_IPv4);
// 2. IPv4 Header
ip->version_ihl = 0x45; // Version 4, Header Length 5 (20 bytes)
ip->version_ihl = 0x45;
ip->tos = 0;
ip->total_length = htons(20 + 8 + 32); // IP + ICMP + 32-byte payload = 60 bytes
ip->total_length = htons(20 + 8 + 32);
ip->id = htons(seq);
ip->flags_fragment = htons(0x4000); // Don't Fragment
ip->flags_fragment = htons(0x4000);
ip->ttl = 64;
ip->protocol = IP_PROTO_ICMP;
ip->src_ip = g_net_cfg.ip;
@@ -94,120 +145,352 @@ int net_send_icmp_ping(uint32_t target_ip, uint16_t seq) {
ip->checksum = 0;
ip->checksum = net_checksum(ip, 20);
// 3. ICMP Echo Request Header
icmp->type = ICMP_ECHO_REQUEST;
icmp->code = 0;
icmp->id = htons(0x1234);
icmp->sequence = htons(seq);
for (int i = 0; i < 32; i++) {
payload[i] = (uint8_t)('a' + (i % 26));
payload[i] = (uint8_t)('A' + (i % 26));
}
icmp->checksum = 0;
icmp->checksum = net_checksum(icmp, 8 + 32);
size_t total_len = sizeof(eth_hdr_t) + 20 + 8 + 32;
return rtl8139_send_packet(packet, (uint16_t)total_len);
return rtl8139_send_packet(packet, sizeof(eth_hdr_t) + 20 + 8 + 32);
}
int net_poll_icmp_reply(uint32_t *from_ip, uint16_t *seq) {
uint8_t buffer[1600];
int len = rtl8139_poll_packet(buffer, sizeof(buffer));
if (len < (int)sizeof(eth_hdr_t)) {
return 0;
uint8_t buf[1600];
int len = rtl8139_poll_packet(buf, sizeof(buf));
if (len < (int)(sizeof(eth_hdr_t) + sizeof(ipv4_hdr_t) + sizeof(icmp_hdr_t))) {
return -1;
}
eth_hdr_t *eth = (eth_hdr_t *)buffer;
// Handle ARP Reply to dynamically update gateway MAC
if (htons(eth->ethertype) == ETHERTYPE_ARP && len >= (int)(sizeof(eth_hdr_t) + sizeof(arp_hdr_t))) {
arp_hdr_t *arp = (arp_hdr_t *)(buffer + sizeof(eth_hdr_t));
if (htons(arp->opcode) == 2) { // ARP Reply
eth_hdr_t *eth = (eth_hdr_t *)buf;
if (htons(eth->ethertype) == ETHERTYPE_ARP) {
arp_hdr_t *arp = (arp_hdr_t *)(buf + sizeof(eth_hdr_t));
if (htons(arp->opcode) == 2 && arp->sender_ip == g_net_cfg.gateway) {
memcpy(g_gateway_mac, arp->sender_mac, 6);
}
return 0;
return -1;
}
if (htons(eth->ethertype) != ETHERTYPE_IPv4 || len < (int)(sizeof(eth_hdr_t) + sizeof(ipv4_hdr_t) + sizeof(icmp_hdr_t))) {
return 0;
}
ipv4_hdr_t *ip = (ipv4_hdr_t *)(buffer + sizeof(eth_hdr_t));
if (ip->protocol != IP_PROTO_ICMP) {
return 0;
}
if (htons(eth->ethertype) != ETHERTYPE_IPv4) return -1;
ipv4_hdr_t *ip = (ipv4_hdr_t *)(buf + sizeof(eth_hdr_t));
if (ip->protocol != IP_PROTO_ICMP) return -1;
int ip_hdr_len = (ip->version_ihl & 0x0F) * 4;
icmp_hdr_t *icmp = (icmp_hdr_t *)(buffer + sizeof(eth_hdr_t) + ip_hdr_len);
icmp_hdr_t *icmp = (icmp_hdr_t *)(buf + sizeof(eth_hdr_t) + ip_hdr_len);
if (icmp->type == ICMP_ECHO_REPLY) {
if (from_ip) *from_ip = ip->src_ip;
if (seq) *seq = htons(icmp->sequence);
return 1; // Genuine Echo Reply received!
return 0;
}
return 0;
return -1;
}
uint32_t parse_ip(const char *str) {
uint32_t parts[4] = {0};
int idx = 0;
while (*str && idx < 4) {
uint32_t ip = 0;
int octet = 0;
int shift = 0;
while (*str) {
if (*str >= '0' && *str <= '9') {
parts[idx] = parts[idx] * 10 + (*str - '0');
octet = octet * 10 + (*str - '0');
} else if (*str == '.') {
idx++;
ip |= ((uint32_t)(octet & 0xFF) << shift);
shift += 8;
octet = 0;
}
str++;
}
return (parts[0]) | (parts[1] << 8) | (parts[2] << 16) | (parts[3] << 24);
ip |= ((uint32_t)(octet & 0xFF) << shift);
return ip;
}
void format_ip(uint32_t ip, char *buf) {
uint8_t *b = (uint8_t *)&ip;
int len = 0;
for (int i = 0; i < 4; i++) {
uint8_t val = b[i];
if (val >= 100) {
buf[len++] = '0' + (val / 100);
val %= 100;
buf[len++] = '0' + (val / 10);
val %= 10;
} else if (val >= 10) {
buf[len++] = '0' + (val / 10);
val %= 10;
uint8_t b = (uint8_t)((ip >> (i * 8)) & 0xFF);
if (b >= 100) {
buf[len++] = '0' + (b / 100);
b %= 100;
buf[len++] = '0' + (b / 10);
b %= 10;
} else if (b >= 10) {
buf[len++] = '0' + (b / 10);
b %= 10;
}
buf[len++] = '0' + val;
buf[len++] = '0' + b;
if (i < 3) buf[len++] = '.';
}
buf[len] = '\0';
}
int net_http_get(uint32_t target_ip, uint16_t port, const char *path, char *out_body, size_t max_body_len) {
if (!out_body || max_body_len == 0) return -1;
if (!path || !*path) path = "/";
// =========================================================================
// DNS CLIENT (UDP Port 53) - Resolves Hostnames to Real IPv4 Addresses
// =========================================================================
int net_dns_resolve(const char *domain, uint32_t *out_ip) {
if (!domain || !*domain || !out_ip) return -1;
// 1. Craft TCP SYN packet
uint8_t packet[128] = {0};
eth_hdr_t *eth = (eth_hdr_t *)packet;
ipv4_hdr_t *ip = (ipv4_hdr_t *)(packet + sizeof(eth_hdr_t));
tcp_hdr_t *tcp = (tcp_hdr_t *)(packet + sizeof(eth_hdr_t) + sizeof(ipv4_hdr_t));
// Check if domain is already a numerical IPv4 address
bool is_numeric = true;
for (const char *p = domain; *p; p++) {
if (!((*p >= '0' && *p <= '9') || *p == '.')) {
is_numeric = false;
break;
}
}
if (is_numeric) {
*out_ip = parse_ip(domain);
return 0;
}
uint16_t local_port = 49152 + (uint16_t)(target_ip & 0x3FF);
uint32_t my_seq = 0x10002000;
uint8_t packet[512] = {0};
eth_hdr_t *eth = (eth_hdr_t *)packet;
ipv4_hdr_t *ip = (ipv4_hdr_t *)(packet + sizeof(eth_hdr_t));
udp_hdr_t *udp = (udp_hdr_t *)(packet + sizeof(eth_hdr_t) + sizeof(ipv4_hdr_t));
uint8_t *dns_payload = packet + sizeof(eth_hdr_t) + sizeof(ipv4_hdr_t) + sizeof(udp_hdr_t);
// Build DNS Header
dns_hdr_t *dns = (dns_hdr_t *)dns_payload;
uint16_t query_id = 0x5A5A;
dns->id = htons(query_id);
dns->flags = htons(0x0100); // Standard query with recursion desired
dns->qdcount = htons(1); // 1 question
dns->ancount = 0;
dns->nscount = 0;
dns->arcount = 0;
// Format QNAME: e.g. "httpbin.org" -> \x07httpbin\x03org\x00
uint8_t *qname = dns_payload + sizeof(dns_hdr_t);
const char *src = domain;
while (*src) {
const char *dot = strchr(src, '.');
size_t len = dot ? (size_t)(dot - src) : strlen(src);
*qname++ = (uint8_t)len;
memcpy(qname, src, len);
qname += len;
src += len;
if (*src == '.') src++;
}
*qname++ = 0x00; // Null terminator for QNAME
// QTYPE (A = 1) and QCLASS (IN = 1)
*qname++ = 0x00; *qname++ = 0x01; // Type A
*qname++ = 0x00; *qname++ = 0x01; // Class IN
size_t dns_len = (size_t)(qname - dns_payload);
size_t udp_len = sizeof(udp_hdr_t) + dns_len;
size_t ip_len = sizeof(ipv4_hdr_t) + udp_len;
size_t total_packet_len = sizeof(eth_hdr_t) + ip_len;
// Ethernet Header
memcpy(eth->dest_mac, g_gateway_mac, 6);
uint8_t target_mac[6];
if ((g_net_cfg.dns_server & 0x00FFFFFF) == (g_net_cfg.ip & 0x00FFFFFF)) {
// Local subnet (e.g. QEMU 10.0.2.3): match last octet
memcpy(target_mac, g_gateway_mac, 6);
target_mac[5] = (uint8_t)(g_net_cfg.dns_server >> 24);
} else {
// External DNS (e.g. 1.1.1.1 or 8.8.8.8): route via Gateway
memcpy(target_mac, g_gateway_mac, 6);
}
memcpy(eth->dest_mac, target_mac, 6);
memcpy(eth->src_mac, g_net_cfg.mac, 6);
eth->ethertype = htons(ETHERTYPE_IPv4);
// IPv4 Header
ip->version_ihl = 0x45;
ip->tos = 0;
ip->total_length = htons((uint16_t)ip_len);
ip->id = htons(0x7788);
ip->flags_fragment = htons(0x4000);
ip->ttl = 64;
ip->protocol = IP_PROTO_UDP;
ip->src_ip = g_net_cfg.ip;
ip->dst_ip = g_net_cfg.dns_server;
ip->checksum = 0;
ip->checksum = net_checksum(ip, sizeof(ipv4_hdr_t));
// UDP Header
uint16_t src_port = 52345;
udp->src_port = htons(src_port);
udp->dst_port = htons(53); // DNS Port
udp->length = htons((uint16_t)udp_len);
udp->checksum = 0; // Optional in IPv4 UDP
// Transmit DNS Query (ensure minimum Ethernet frame size 60 bytes)
rtl8139_send_packet(packet, total_packet_len < 60 ? 60 : total_packet_len);
// Poll for DNS response with realistic WAN timeout (~1.5 seconds)
uint8_t rx_buf[1600];
for (int retry = 0; retry < 300; retry++) {
int rx_len = rtl8139_poll_packet(rx_buf, sizeof(rx_buf));
if (rx_len > (int)(sizeof(eth_hdr_t) + sizeof(ipv4_hdr_t) + sizeof(udp_hdr_t) + sizeof(dns_hdr_t))) {
eth_hdr_t *rx_eth = (eth_hdr_t *)rx_buf;
if (htons(rx_eth->ethertype) == ETHERTYPE_IPv4) {
ipv4_hdr_t *rx_ip = (ipv4_hdr_t *)(rx_buf + sizeof(eth_hdr_t));
if (rx_ip->protocol == IP_PROTO_UDP) {
udp_hdr_t *rx_udp = (udp_hdr_t *)(rx_buf + sizeof(eth_hdr_t) + sizeof(ipv4_hdr_t));
if (htons(rx_udp->dst_port) == src_port) {
uint8_t *resp_dns = rx_buf + sizeof(eth_hdr_t) + sizeof(ipv4_hdr_t) + sizeof(udp_hdr_t);
dns_hdr_t *rx_dns_hdr = (dns_hdr_t *)resp_dns;
if (ntohs(rx_dns_hdr->id) == query_id && (ntohs(rx_dns_hdr->flags) & 0x8000) && ntohs(rx_dns_hdr->ancount) > 0) {
// Skip DNS Question section to reach Answer section
uint8_t *ptr = resp_dns + sizeof(dns_hdr_t);
// Skip QNAME
while (*ptr && ptr < rx_buf + rx_len) {
if ((*ptr & 0xC0) == 0xC0) { ptr += 2; break; } // Compression pointer
ptr += (*ptr + 1);
}
if (*ptr == 0) ptr++;
ptr += 4; // Skip QTYPE (2) + QCLASS (2)
// Parse Answers
int answers = ntohs(rx_dns_hdr->ancount);
for (int a = 0; a < answers && ptr < rx_buf + rx_len - 10; a++) {
// Name: either pointer (0xC0XX) or label
if ((*ptr & 0xC0) == 0xC0) {
ptr += 2;
} else {
while (*ptr && ptr < rx_buf + rx_len) ptr += (*ptr + 1);
if (*ptr == 0) ptr++;
}
uint16_t a_type = (uint16_t)((ptr[0] << 8) | ptr[1]);
uint16_t a_len = (uint16_t)((ptr[8] << 8) | ptr[9]);
ptr += 10; // Type(2), Class(2), TTL(4), DataLen(2)
if (a_type == 1 && a_len == 4) { // IPv4 Address (Type A)
uint32_t resolved = 0;
memcpy(&resolved, ptr, 4);
*out_ip = resolved;
return 0; // Success!
}
ptr += a_len;
}
}
}
}
}
}
for (volatile int d = 0; d < 20000; d++);
}
return -1; // Timeout
}
// =========================================================================
// DHCP AUTO-CONFIGURATION (UDP Port 67/68)
// =========================================================================
int net_dhcp_discover(void) {
// Send DHCP Discover packet broadcast
uint8_t packet[350] = {0};
eth_hdr_t *eth = (eth_hdr_t *)packet;
ipv4_hdr_t *ip = (ipv4_hdr_t *)(packet + sizeof(eth_hdr_t));
udp_hdr_t *udp = (udp_hdr_t *)(packet + sizeof(eth_hdr_t) + sizeof(ipv4_hdr_t));
uint8_t *dhcp = packet + sizeof(eth_hdr_t) + sizeof(ipv4_hdr_t) + sizeof(udp_hdr_t);
memset(eth->dest_mac, 0xFF, 6);
memcpy(eth->src_mac, g_net_cfg.mac, 6);
eth->ethertype = htons(ETHERTYPE_IPv4);
ip->version_ihl = 0x45;
ip->tos = 0;
ip->total_length = htons(sizeof(ipv4_hdr_t) + sizeof(udp_hdr_t) + 300);
ip->id = htons(0x1010);
ip->flags_fragment = 0;
ip->ttl = 64;
ip->protocol = IP_PROTO_UDP;
ip->src_ip = 0x00000000;
ip->dst_ip = 0xFFFFFFFF; // 255.255.255.255
ip->checksum = 0;
ip->checksum = net_checksum(ip, sizeof(ipv4_hdr_t));
udp->src_port = htons(68); // DHCP Client
udp->dst_port = htons(67); // DHCP Server
udp->length = htons(sizeof(udp_hdr_t) + 300);
udp->checksum = 0;
// BOOTP / DHCP Request fields
dhcp[0] = 1; // Boot Request
dhcp[1] = 1; // 10Mb Ethernet
dhcp[2] = 6; // HW Address length
dhcp[3] = 0; // Hops
dhcp[4] = 0x39; dhcp[5] = 0x03; dhcp[6] = 0xF3; dhcp[7] = 0x26; // Transaction ID
memcpy(dhcp + 28, g_net_cfg.mac, 6); // Client MAC
// Magic Cookie: 99, 130, 83, 99
dhcp[236] = 99; dhcp[237] = 130; dhcp[238] = 83; dhcp[239] = 99;
// Option 53: DHCP Discover
dhcp[240] = 53; dhcp[241] = 1; dhcp[242] = 1;
// Option 55: Parameter Request List (Subnet Mask, Router, DNS)
dhcp[243] = 55; dhcp[244] = 3; dhcp[245] = 1; dhcp[246] = 3; dhcp[247] = 6;
dhcp[248] = 255; // End
rtl8139_send_packet(packet, sizeof(packet));
// Listen for DHCP Offer
uint8_t rx[1600];
for (int retry = 0; retry < 40; retry++) {
int rx_len = rtl8139_poll_packet(rx, sizeof(rx));
if (rx_len > (int)(sizeof(eth_hdr_t) + sizeof(ipv4_hdr_t) + sizeof(udp_hdr_t) + 240)) {
ipv4_hdr_t *rx_ip = (ipv4_hdr_t *)(rx + sizeof(eth_hdr_t));
if (rx_ip->protocol == IP_PROTO_UDP) {
udp_hdr_t *rx_udp = (udp_hdr_t *)(rx + sizeof(eth_hdr_t) + sizeof(ipv4_hdr_t));
if (htons(rx_udp->dst_port) == 68) {
uint8_t *rx_dhcp = rx + sizeof(eth_hdr_t) + sizeof(ipv4_hdr_t) + sizeof(udp_hdr_t);
uint32_t offered_ip = 0;
memcpy(&offered_ip, rx_dhcp + 16, 4); // "Your (client) IP address" (yiaddr)
if (offered_ip != 0) {
g_net_cfg.ip = offered_ip;
// Parse options
uint8_t *opt = rx_dhcp + 240;
while (*opt != 255 && opt < rx + rx_len) {
uint8_t code = *opt++;
uint8_t len = *opt++;
if (code == 1 && len == 4) memcpy(&g_net_cfg.netmask, opt, 4);
if (code == 3 && len == 4) memcpy(&g_net_cfg.gateway, opt, 4);
if (code == 6 && len >= 4) memcpy(&g_net_cfg.dns_server, opt, 4);
opt += len;
}
return 0; // Success!
}
}
}
}
for (volatile int d = 0; d < 20000; d++);
}
return -1;
}
// =========================================================================
// FULL TCP 3-WAY HANDSHAKE & HTTP CLIENT (Live Internet Access)
// =========================================================================
int net_http_get(uint32_t target_ip, uint16_t port, const char *path, const char *host_header, char *out_body, size_t max_body_len) {
if (!out_body || max_body_len == 0) return -1;
if (!path || !*path) path = "/";
uint16_t local_port = 49152 + (uint16_t)(target_ip & 0x1FF) + (uint16_t)(port & 0x1F);
uint32_t my_seq = 0x20001000;
uint32_t srv_seq = 0;
uint8_t packet[1500] = {0};
eth_hdr_t *eth = (eth_hdr_t *)packet;
ipv4_hdr_t *ip = (ipv4_hdr_t *)(packet + sizeof(eth_hdr_t));
tcp_hdr_t *tcp = (tcp_hdr_t *)(packet + sizeof(eth_hdr_t) + sizeof(ipv4_hdr_t));
// -------------------------------------------------------------
// STEP 1: SEND TCP SYN (with RFC 793 TCP Checksum)
// -------------------------------------------------------------
memcpy(eth->dest_mac, g_gateway_mac, 6);
memcpy(eth->src_mac, g_net_cfg.mac, 6);
eth->ethertype = htons(ETHERTYPE_IPv4);
ip->version_ihl = 0x45;
ip->tos = 0;
ip->total_length = htons(sizeof(ipv4_hdr_t) + sizeof(tcp_hdr_t));
ip->id = htons(0x4321);
ip->id = htons(0x1122);
ip->flags_fragment = htons(0x4000);
ip->ttl = 64;
ip->protocol = IP_PROTO_TCP;
@@ -216,73 +499,197 @@ int net_http_get(uint32_t target_ip, uint16_t port, const char *path, char *out_
ip->checksum = 0;
ip->checksum = net_checksum(ip, sizeof(ipv4_hdr_t));
// TCP SYN Header
tcp->src_port = htons(local_port);
tcp->dst_port = htons(port);
tcp->seq_num = (uint32_t)(((my_seq & 0xFF) << 24) | ((my_seq & 0xFF00) << 8) | ((my_seq >> 8) & 0xFF00) | ((my_seq >> 24) & 0xFF));
tcp->seq_num = htonl(my_seq);
tcp->ack_num = 0;
tcp->data_offset_reserved = (5 << 4); // 20 bytes header
tcp->data_offset_reserved = (5 << 4);
tcp->flags = TCP_FLAG_SYN;
tcp->window_size = htons(65535);
tcp->checksum = 0;
tcp->urgent_ptr = 0;
tcp->checksum = net_tcp_checksum(ip->src_ip, ip->dst_ip, tcp, sizeof(tcp_hdr_t));
// Send SYN
rtl8139_send_packet(packet, sizeof(eth_hdr_t) + sizeof(ipv4_hdr_t) + sizeof(tcp_hdr_t));
// Poll for packet
uint8_t rx_buf[1600];
for (int retry = 0; retry < 30; retry++) {
int rx_len = rtl8139_poll_packet(rx_buf, sizeof(rx_buf));
// -------------------------------------------------------------
// STEP 2: WAIT FOR TCP SYN-ACK
// -------------------------------------------------------------
uint8_t rx[1600];
bool got_synack = false;
for (int retry = 0; retry < 300; retry++) {
int rx_len = rtl8139_poll_packet(rx, sizeof(rx));
if (rx_len > (int)(sizeof(eth_hdr_t) + sizeof(ipv4_hdr_t) + sizeof(tcp_hdr_t))) {
eth_hdr_t *rx_eth = (eth_hdr_t *)rx_buf;
eth_hdr_t *rx_eth = (eth_hdr_t *)rx;
if (htons(rx_eth->ethertype) == ETHERTYPE_IPv4) {
ipv4_hdr_t *rx_ip = (ipv4_hdr_t *)(rx_buf + sizeof(eth_hdr_t));
ipv4_hdr_t *rx_ip = (ipv4_hdr_t *)(rx + sizeof(eth_hdr_t));
if (rx_ip->protocol == IP_PROTO_TCP) {
int ip_hl = (rx_ip->version_ihl & 0x0F) * 4;
tcp_hdr_t *rx_tcp = (tcp_hdr_t *)(rx_buf + sizeof(eth_hdr_t) + ip_hl);
tcp_hdr_t *rx_tcp = (tcp_hdr_t *)(rx + sizeof(eth_hdr_t) + ip_hl);
if (htons(rx_tcp->dst_port) == local_port) {
int tcp_hl = (rx_tcp->data_offset_reserved >> 4) * 4;
int data_offset = sizeof(eth_hdr_t) + ip_hl + tcp_hl;
int payload_len = rx_len - data_offset;
if (payload_len > 0) {
int copy_bytes = (payload_len < (int)max_body_len - 1) ? payload_len : ((int)max_body_len - 1);
memcpy(out_body, rx_buf + data_offset, copy_bytes);
out_body[copy_bytes] = '\0';
return 200;
if ((rx_tcp->flags & (TCP_FLAG_SYN | TCP_FLAG_ACK)) == (TCP_FLAG_SYN | TCP_FLAG_ACK)) {
srv_seq = ntohl(rx_tcp->seq_num) + 1;
my_seq++;
got_synack = true;
break;
} else if (rx_tcp->flags & TCP_FLAG_RST) {
printf("[TCP] Connection refused by remote host (RST received)\n");
break;
}
}
}
}
}
for (volatile int d = 0; d < 30000; d++) {}
for (volatile int d = 0; d < 60000; d++);
}
// Default Fallback Demo Page
const char *demo_html =
"<!DOCTYPE html>\n"
"<html>\n"
"<head>\n"
" <title>opencoreC Web Browser</title>\n"
"</head>\n"
"<body>\n"
" <h1>Welcome to opencoreC Web!</h1>\n"
" <p>Status: <b>200 OK</b> (Connected via TCP/IPv4)</p>\n"
" <p>Local IP: <b>10.0.2.15</b> | Gateway: <b>10.0.2.2</b></p>\n"
" <p>Driver: Realtek RTL8139 Fast Ethernet PCI Bus Master</p>\n"
" <hr/>\n"
" <h3>Available Links & Subsystems:</h3>\n"
" <ul>\n"
" <li><b>Architecture:</b> 4-Core SMP x86_64 Microkernel</li>\n"
" <li><b>IPC:</b> Fast-Path Capability & Synchronous Rendezvous</li>\n"
" <li><b>Compositor:</b> LVGL v8.3 with SSE2 SIMD Acceleration</li>\n"
" <li><b>Binaries:</b> Native .OPC Binary Format with Sandboxing</li>\n"
" <li><b>Hardware:</b> PCI GPU Detection & VRAM Management</li>\n"
" </ul>\n"
"</body>\n"
"</html>\n";
if (!got_synack) {
// Fallback response for offline environments
snprintf(out_body, max_body_len,
"<!DOCTYPE html>\n<html>\n<head><title>opencoreC Web</title></head>\n"
"<body>\n<h1>opencoreC Web Browser</h1>\n"
"<p>Host unreachable via TCP port %u (SYN-ACK timeout).</p>\n"
"<p>Target IP: 0x%08x</p>\n</body>\n</html>\n",
(unsigned int)port, (unsigned int)target_ip);
return 504; // Gateway Timeout
}
strncpy(out_body, demo_html, max_body_len - 1);
out_body[max_body_len - 1] = '\0';
return 200;
// -------------------------------------------------------------
// STEP 3: SEND ACK + HTTP GET REQUEST
// -------------------------------------------------------------
char http_req[512];
snprintf(http_req, sizeof(http_req),
"GET %s HTTP/1.1\r\n"
"Host: %s\r\n"
"User-Agent: opencoreC/1.0 (x86_64 SMP)\r\n"
"Accept: */*\r\n"
"Connection: close\r\n\r\n",
path, host_header ? host_header : "10.0.2.2");
size_t req_len = strlen(http_req);
size_t tcp_payload_len = sizeof(tcp_hdr_t) + req_len;
ip->total_length = htons((uint16_t)(sizeof(ipv4_hdr_t) + tcp_payload_len));
ip->id = htons(0x1123);
ip->checksum = 0;
ip->checksum = net_checksum(ip, sizeof(ipv4_hdr_t));
tcp->seq_num = htonl(my_seq);
tcp->ack_num = htonl(srv_seq);
tcp->data_offset_reserved = (5 << 4);
tcp->flags = TCP_FLAG_ACK | TCP_FLAG_PSH;
tcp->checksum = 0;
uint8_t *payload_ptr = packet + sizeof(eth_hdr_t) + sizeof(ipv4_hdr_t) + sizeof(tcp_hdr_t);
memcpy(payload_ptr, http_req, req_len);
tcp->checksum = net_tcp_checksum(ip->src_ip, ip->dst_ip, tcp, tcp_payload_len);
rtl8139_send_packet(packet, sizeof(eth_hdr_t) + sizeof(ipv4_hdr_t) + tcp_payload_len);
my_seq += (uint32_t)req_len;
// -------------------------------------------------------------
// STEP 4: RECEIVE HTTP DATA STREAM
// -------------------------------------------------------------
size_t total_body_read = 0;
out_body[0] = '\0';
int empty_polls = 0;
for (int retry = 0; retry < 400; retry++) {
int rx_len = rtl8139_poll_packet(rx, sizeof(rx));
if (rx_len > (int)(sizeof(eth_hdr_t) + sizeof(ipv4_hdr_t) + sizeof(tcp_hdr_t))) {
eth_hdr_t *rx_eth = (eth_hdr_t *)rx;
if (htons(rx_eth->ethertype) == ETHERTYPE_IPv4) {
ipv4_hdr_t *rx_ip = (ipv4_hdr_t *)(rx + sizeof(eth_hdr_t));
if (rx_ip->protocol == IP_PROTO_TCP && rx_ip->src_ip == target_ip) {
int ip_hl = (rx_ip->version_ihl & 0x0F) * 4;
tcp_hdr_t *rx_tcp = (tcp_hdr_t *)(rx + sizeof(eth_hdr_t) + ip_hl);
if (htons(rx_tcp->dst_port) == local_port) {
int tcp_hl = (rx_tcp->data_offset_reserved >> 4) * 4;
int data_offset = sizeof(eth_hdr_t) + ip_hl + tcp_hl;
uint16_t ip_total_len = ntohs(rx_ip->total_length);
int data_bytes = (int)ip_total_len - (ip_hl + tcp_hl);
if (data_bytes > 0) {
empty_polls = 0;
size_t space = max_body_len - 1 - total_body_read;
size_t to_copy = (size_t)data_bytes < space ? (size_t)data_bytes : space;
memcpy(out_body + total_body_read, rx + data_offset, to_copy);
total_body_read += to_copy;
out_body[total_body_read] = '\0';
// Acknowledge received data
srv_seq = ntohl(rx_tcp->seq_num) + (uint32_t)data_bytes;
tcp->seq_num = htonl(my_seq);
tcp->ack_num = htonl(srv_seq);
tcp->flags = TCP_FLAG_ACK;
tcp->checksum = 0;
tcp->checksum = net_tcp_checksum(ip->src_ip, ip->dst_ip, tcp, sizeof(tcp_hdr_t));
ip->total_length = htons(sizeof(ipv4_hdr_t) + sizeof(tcp_hdr_t));
ip->checksum = 0;
ip->checksum = net_checksum(ip, sizeof(ipv4_hdr_t));
rtl8139_send_packet(packet, sizeof(eth_hdr_t) + sizeof(ipv4_hdr_t) + sizeof(tcp_hdr_t));
}
if (rx_tcp->flags & TCP_FLAG_FIN) {
// Server closed connection cleanly
break;
}
}
}
}
} else {
if (total_body_read > 0) {
empty_polls++;
if (empty_polls > 25) {
break; // Finished receiving body stream
}
}
}
for (volatile int d = 0; d < 60000; d++);
}
if (total_body_read > 0) {
return 200; // Success HTTP 200 OK
}
// Default response if connected but empty
snprintf(out_body, max_body_len,
"<!DOCTYPE html>\n<html>\n<head><title>opencoreC Web</title></head>\n"
"<body>\n<h1>opencoreC Web Browser</h1>\n"
"<p>Connected to %s via TCP/IPv4, but server returned 0 bytes.</p>\n</body>\n</html>\n",
host_header ? host_header : "remote host");
return 204;
}
int net_http_get_url(const char *url, char *out_body, size_t max_body_len) {
if (!url || !*url) return -1;
if (strncmp(url, "http://", 7) == 0) url += 7;
char host[128] = {0};
uint16_t port = 80;
const char *path = "/";
int hi = 0;
while (*url && *url != '/' && *url != ':' && hi < 127) {
host[hi++] = *url++;
}
if (*url == ':') {
url++;
port = 0;
while (*url >= '0' && *url <= '9') {
port = port * 10 + (*url - '0');
url++;
}
}
if (*url == '/') {
path = url;
}
uint32_t target_ip = 0;
if (net_dns_resolve(host, &target_ip) != 0) {
target_ip = g_net_cfg.gateway; // Fallback to gateway
}
return net_http_get(target_ip, port, path, host, out_body, max_body_len);
}