mirror of
https://github.com/BoredDevNL/BoredOS.git
synced 2026-05-15 10:48:38 +00:00
V1.10
New feature(s): - Network stack - Piping commands into a udpsend message Bug fix(es): -N/A
This commit is contained in:
parent
d9fc8fbeda
commit
89bdb860dd
34 changed files with 1322 additions and 16 deletions
3
Makefile
3
Makefile
|
|
@ -119,4 +119,5 @@ clean:
|
|||
|
||||
run: $(ISO_IMAGE)
|
||||
qemu-system-x86_64 -m 2G -serial stdio -cdrom $(ISO_IMAGE) -boot d \
|
||||
-audiodev coreaudio,id=audio0 -machine pcspk-audiodev=audio0
|
||||
-audiodev coreaudio,id=audio0 -machine pcspk-audiodev=audio0 \
|
||||
-netdev user,id=net0 -device e1000,netdev=net0
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
# Brew OS 1.03 Pre-Alpha
|
||||
# Brew OS 1.10 Alpha
|
||||
|
||||
## Brewkernel is now BrewOS!
|
||||
Brewkernel will from now on be deprecated as it's core became too messy. I have built a less bloated kernel and wrote a DE above it, which is why it is now an OS instead of a kernel (in my opinion).
|
||||
|
|
@ -9,6 +9,7 @@ Brew Kernel is a simple x86_64 hobbyist operating system.
|
|||
It features a DE (and WM), a FAT32 filesystem, customizable UI and much much more!
|
||||
|
||||
## Features
|
||||
- Basic Networking Stack
|
||||
- Brew WM
|
||||
- Fat 32 FS
|
||||
- 64-bit long mode support
|
||||
|
|
|
|||
BIN
brewos.iso
BIN
brewos.iso
Binary file not shown.
BIN
build/brewos.elf
BIN
build/brewos.elf
Binary file not shown.
BIN
build/cli_apps/net.o
Normal file
BIN
build/cli_apps/net.o
Normal file
Binary file not shown.
BIN
build/cli_apps/pci_list.o
Normal file
BIN
build/cli_apps/pci_list.o
Normal file
Binary file not shown.
BIN
build/cmd.o
BIN
build/cmd.o
Binary file not shown.
BIN
build/e1000.o
Normal file
BIN
build/e1000.o
Normal file
Binary file not shown.
BIN
build/idt.o
BIN
build/idt.o
Binary file not shown.
BIN
build/main.o
BIN
build/main.o
Binary file not shown.
BIN
build/network.o
Normal file
BIN
build/network.o
Normal file
Binary file not shown.
BIN
build/pci.o
Normal file
BIN
build/pci.o
Normal file
Binary file not shown.
BIN
build/platform.o
Normal file
BIN
build/platform.o
Normal file
Binary file not shown.
BIN
build/ps2.o
BIN
build/ps2.o
Binary file not shown.
BIN
build/wm.o
BIN
build/wm.o
Binary file not shown.
|
|
@ -1,4 +1,4 @@
|
|||
# Brew OS 1.01 Alpha
|
||||
# Brew OS 1.03 Pre-Alpha
|
||||
|
||||
## Brewkernel is now BrewOS!
|
||||
Brewkernel will from now on be deprecated as it's core became too messy. I have built a less bloated kernel and wrote a DE above it, which is why it is now an OS instead of a kernel (in my opinion).
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -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.03", COLOR_BLACK);
|
||||
draw_string(offset_x, offset_y + 135, "Kernel Version 2.0.3", COLOR_BLACK);
|
||||
draw_string(offset_x, offset_y + 120, "BrewOS Version 1.10", COLOR_BLACK);
|
||||
draw_string(offset_x, offset_y + 135, "Kernel Version 2.1.0", COLOR_BLACK);
|
||||
|
||||
// Copyright
|
||||
draw_string(offset_x, offset_y + 150, "(C) 2026 boreddevnl.", COLOR_BLACK);
|
||||
|
|
|
|||
|
|
@ -2,6 +2,6 @@
|
|||
|
||||
void cli_cmd_brewver(char *args) {
|
||||
(void)args;
|
||||
cli_write("BrewOS v1.03 Alpha\n");
|
||||
cli_write("BrewOS Kernel V2.0.3 Pre-Alpha\n");
|
||||
cli_write("BrewOS v1.10 Alpha\n");
|
||||
cli_write("BrewOS Kernel V2.1.0 Pre-Alpha\n");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,4 +37,14 @@ void cli_cmd_memblock(char *args);
|
|||
void cli_cmd_memvalid(char *args);
|
||||
void cli_cmd_memtest(char *args);
|
||||
|
||||
// Network commands
|
||||
void cli_cmd_netinit(char *args);
|
||||
void cli_cmd_netinfo(char *args);
|
||||
void cli_cmd_ipset(char *args);
|
||||
void cli_cmd_udpsend(char *args);
|
||||
void cli_cmd_udptest(char *args);
|
||||
|
||||
// PCI commands
|
||||
void cli_cmd_pcilist(char *args);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
112
src/kernel/cli_apps/net.c
Normal file
112
src/kernel/cli_apps/net.c
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
#include "cli_utils.h"
|
||||
#include "network.h"
|
||||
|
||||
static void print_mac(const mac_address_t* mac){
|
||||
char buf[64];
|
||||
int p=0;
|
||||
for(int i=0;i<6;i++){
|
||||
int v=mac->bytes[i];
|
||||
int hi=(v>>4)&0xF, lo=v&0xF;
|
||||
buf[p++]= (hi<10)?('0'+hi):('A'+(hi-10));
|
||||
buf[p++]= (lo<10)?('0'+lo):('A'+(lo-10));
|
||||
if(i<5) buf[p++]=':';
|
||||
}
|
||||
buf[p]=0;
|
||||
cli_write(buf);
|
||||
}
|
||||
|
||||
void cli_cmd_netinit(char *args){
|
||||
(void)args;
|
||||
int r=network_init();
|
||||
if(r==0){
|
||||
cli_write("Network initialized\n");
|
||||
int d=network_dhcp_acquire();
|
||||
if(d==0){
|
||||
cli_write("DHCP acquired\n");
|
||||
} else {
|
||||
cli_write("DHCP failed\n");
|
||||
}
|
||||
} else {
|
||||
cli_write("Network init failed\n");
|
||||
}
|
||||
}
|
||||
|
||||
void cli_cmd_netinfo(char *args){
|
||||
(void)args;
|
||||
mac_address_t mac;
|
||||
ipv4_address_t ip;
|
||||
if(network_get_mac_address(&mac)==0){
|
||||
cli_write("MAC: "); print_mac(&mac); cli_write("\n");
|
||||
}
|
||||
if(network_get_ipv4_address(&ip)==0){
|
||||
cli_write("IP: ");
|
||||
for(int i=0;i<4;i++){ cli_write_int(ip.bytes[i]); if(i<3) cli_write("."); }
|
||||
cli_write("\n");
|
||||
}
|
||||
cli_write("Frames: "); cli_write_int(network_get_frames_received()); cli_write("\n");
|
||||
cli_write("UDP packets: "); cli_write_int(network_get_udp_packets_received()); cli_write("\n");
|
||||
cli_write("UDP callbacks: "); cli_write_int(network_get_udp_callbacks_called()); cli_write("\n");
|
||||
cli_write("E1000 receive calls: "); cli_write_int(network_get_e1000_receive_calls()); cli_write("\n");
|
||||
cli_write("E1000 receive empty: "); cli_write_int(network_get_e1000_receive_empty()); cli_write("\n");
|
||||
cli_write("Process calls: "); cli_write_int(network_get_process_calls()); cli_write("\n");
|
||||
}
|
||||
|
||||
void cli_cmd_ipset(char *args){
|
||||
if(!args||!*args){ cli_write("Usage: IPSET a.b.c.d\n"); return; }
|
||||
ipv4_address_t ip={{0,0,0,0}};
|
||||
int part=0; int val=0; int i=0;
|
||||
while(args[i]){
|
||||
char ch=args[i++];
|
||||
if(ch>='0'&&ch<='9'){ val=val*10+(ch-'0'); if(val>255){ cli_write("Invalid IP\n"); return; } }
|
||||
else if(ch=='.'){ if(part>3){ cli_write("Invalid IP\n"); return; } ip.bytes[part++]=(uint8_t)val; val=0; }
|
||||
else { cli_write("Invalid IP\n"); return; }
|
||||
}
|
||||
if(part!=3){ cli_write("Invalid IP\n"); return; }
|
||||
ip.bytes[3]=(uint8_t)val;
|
||||
if(network_set_ipv4_address(&ip)==0){ cli_write("IP set\n"); } else { cli_write("IP set failed\n"); }
|
||||
}
|
||||
|
||||
void cli_cmd_udpsend(char *args){
|
||||
if(!args||!*args){ cli_write("Usage: UDPSEND ip port data\n"); return; }
|
||||
char ipstr[32]; int pos=0;
|
||||
while(args[pos] && args[pos]!=' '){ ipstr[pos]=args[pos]; pos++; }
|
||||
ipstr[pos]=0;
|
||||
while(args[pos]==' ') pos++;
|
||||
char portstr[16]; int p=0;
|
||||
while(args[pos] && args[pos]!=' '){ portstr[p++]=args[pos++]; }
|
||||
portstr[p]=0;
|
||||
while(args[pos]==' ') pos++;
|
||||
char* datastr = args+pos;
|
||||
ipv4_address_t ip={{0,0,0,0}};
|
||||
int idx=0; int val=0; int j=0;
|
||||
while(ipstr[j]){
|
||||
char ch=ipstr[j++];
|
||||
if(ch>='0'&&ch<='9'){ val=val*10+(ch-'0'); if(val>255){ cli_write("Invalid IP\n"); return; } }
|
||||
else if(ch=='.'){ if(idx>3){ cli_write("Invalid IP\n"); return; } ip.bytes[idx++]=(uint8_t)val; val=0; }
|
||||
else { cli_write("Invalid IP\n"); return; }
|
||||
}
|
||||
if(idx!=3){ cli_write("Invalid IP\n"); return; }
|
||||
ip.bytes[3]=(uint8_t)val;
|
||||
int port=0; int k=0; while(portstr[k]){ char ch=portstr[k++]; if(ch<'0'||ch>'9'){ cli_write("Invalid port\n"); return; } port=port*10+(ch-'0'); }
|
||||
if(port<=0||port>65535){ cli_write("Invalid port\n"); return; }
|
||||
int len=(int)cli_strlen(datastr);
|
||||
if(len<=0){ cli_write("No data\n"); return; }
|
||||
int r=udp_send_packet(&ip,(uint16_t)port,12345,datastr,(size_t)len);
|
||||
if(r==0) cli_write("Sent\n"); else cli_write("Send failed\n");
|
||||
}
|
||||
|
||||
static void udp_print_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_mac;
|
||||
cli_write("UDP from ");
|
||||
for(int i=0;i<4;i++){ cli_write_int(src_ip->bytes[i]); if(i<3) cli_write("."); }
|
||||
cli_write(":"); cli_write_int(src_port); cli_write(" ");
|
||||
for(size_t i=0;i<length;i++){ cli_putchar(((const char*)data)[i]); }
|
||||
cli_write("\n");
|
||||
}
|
||||
|
||||
void cli_cmd_udptest(char *args){
|
||||
if(!args||!*args){ cli_write("Usage: UDPTEST port\n"); return; }
|
||||
int port=cli_atoi(args);
|
||||
if(port<=0||port>65535){ cli_write("Invalid port\n"); return; }
|
||||
if(udp_register_callback((uint16_t)port,udp_print_callback)==0) cli_write("UDP callback registered\n"); else cli_write("Register failed\n");
|
||||
}
|
||||
44
src/kernel/cli_apps/pci_list.c
Normal file
44
src/kernel/cli_apps/pci_list.c
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
#include "cli_utils.h"
|
||||
#include "pci.h"
|
||||
|
||||
static void print_hex16(uint16_t v){
|
||||
char buf[7]; buf[0]='0'; buf[1]='x';
|
||||
for(int i=0;i<4;i++){
|
||||
int nyb=(v >> ((3-i)*4)) & 0xF;
|
||||
buf[2+i]= nyb<10?('0'+nyb):('A'+(nyb-10));
|
||||
}
|
||||
buf[6]=0;
|
||||
cli_write(buf);
|
||||
}
|
||||
|
||||
static void print_hex8(uint8_t v){
|
||||
char buf[5]; buf[0]='0'; buf[1]='x';
|
||||
int hi=(v>>4)&0xF, lo=v&0xF;
|
||||
buf[2]= hi<10?('0'+hi):('A'+(hi-10));
|
||||
buf[3]= lo<10?('0'+lo):('A'+(lo-10));
|
||||
buf[4]=0;
|
||||
cli_write(buf);
|
||||
}
|
||||
|
||||
void cli_cmd_pcilist(char *args){
|
||||
(void)args;
|
||||
pci_device_t devs[64];
|
||||
int n=pci_enumerate_devices(devs,64);
|
||||
cli_write("PCI devices:\n");
|
||||
for(int i=0;i<n;i++){
|
||||
cli_write(" ");
|
||||
cli_write_int(devs[i].bus); cli_write(":");
|
||||
cli_write_int(devs[i].device); cli_write(".");
|
||||
cli_write_int(devs[i].function); cli_write(" ");
|
||||
cli_write("vendor="); print_hex16(devs[i].vendor_id); cli_write(" ");
|
||||
cli_write("device="); print_hex16(devs[i].device_id); cli_write(" ");
|
||||
cli_write("class="); print_hex8(devs[i].class_code); cli_write(" ");
|
||||
cli_write("subclass="); print_hex8(devs[i].subclass); cli_write(" ");
|
||||
cli_write("prog_if="); print_hex8(devs[i].prog_if);
|
||||
if(devs[i].vendor_id==0x8086 && devs[i].device_id==0x100E){
|
||||
cli_write(" [e1000]");
|
||||
}
|
||||
cli_write("\n");
|
||||
}
|
||||
cli_write_int(n); cli_write(" device(s)\n");
|
||||
}
|
||||
202
src/kernel/cmd.c
202
src/kernel/cmd.c
|
|
@ -13,6 +13,7 @@
|
|||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "network.h"
|
||||
|
||||
#define CMD_COLS 116
|
||||
#define CMD_ROWS 41
|
||||
|
|
@ -112,6 +113,9 @@ int boot_time_init = 0;
|
|||
// Output redirection state
|
||||
static FAT32_FileHandle *redirect_file = NULL;
|
||||
static char redirect_mode = 0; // '>' for write, 'a' for append, 0 for normal output
|
||||
static bool pipe_capture_mode = false;
|
||||
static char pipe_buffer[8192];
|
||||
static int pipe_buffer_pos = 0;
|
||||
int boot_year, boot_month, boot_day, boot_hour, boot_min, boot_sec;
|
||||
|
||||
// --- Helpers ---
|
||||
|
|
@ -197,6 +201,14 @@ static void cmd_scroll_up() {
|
|||
|
||||
// Public for CLI apps to use
|
||||
void cmd_putchar(char c) {
|
||||
// If pipe capture mode is enabled, write to pipe buffer
|
||||
if (pipe_capture_mode) {
|
||||
if (pipe_buffer_pos < (int)sizeof(pipe_buffer) - 1) {
|
||||
pipe_buffer[pipe_buffer_pos++] = c;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// If output is being redirected to a file, write there instead
|
||||
if (redirect_file && redirect_mode) {
|
||||
fat32_write(redirect_file, &c, 1);
|
||||
|
|
@ -235,6 +247,14 @@ void cmd_putchar(char c) {
|
|||
|
||||
// Public for CLI apps to use
|
||||
void cmd_write(const char *str) {
|
||||
// If pipe capture mode is enabled, write to pipe buffer
|
||||
if (pipe_capture_mode) {
|
||||
while (*str && pipe_buffer_pos < (int)sizeof(pipe_buffer) - 1) {
|
||||
pipe_buffer[pipe_buffer_pos++] = *str++;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// If output is being redirected to a file, write there instead
|
||||
if (redirect_file && redirect_mode) {
|
||||
fat32_write(redirect_file, (void *)str, cmd_strlen(str));
|
||||
|
|
@ -402,19 +422,33 @@ static const CommandEntry commands[] = {
|
|||
{"memvalid", cli_cmd_memvalid},
|
||||
{"MEMTEST", cli_cmd_memtest},
|
||||
{"memtest", cli_cmd_memtest},
|
||||
// Network Commands
|
||||
{"NETINIT", cli_cmd_netinit},
|
||||
{"netinit", cli_cmd_netinit},
|
||||
{"NETINFO", cli_cmd_netinfo},
|
||||
{"netinfo", cli_cmd_netinfo},
|
||||
{"IPSET", cli_cmd_ipset},
|
||||
{"ipset", cli_cmd_ipset},
|
||||
{"UDPSEND", cli_cmd_udpsend},
|
||||
{"udpsend", cli_cmd_udpsend},
|
||||
{"UDPTEST", cli_cmd_udptest},
|
||||
{"udptest", cli_cmd_udptest},
|
||||
{"PCILIST", cli_cmd_pcilist},
|
||||
{"pcilist", cli_cmd_pcilist},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
// --- Dispatcher ---
|
||||
|
||||
// Buffer for capturing command output
|
||||
static char pipe_buffer[8192];
|
||||
static int pipe_buffer_pos = 0;
|
||||
|
||||
static void pipe_capture_write(const char *str) {
|
||||
while (*str && pipe_buffer_pos < (int)sizeof(pipe_buffer) - 1) {
|
||||
pipe_buffer[pipe_buffer_pos++] = *str++;
|
||||
// Find pipe operator in command string (||)
|
||||
static const char* find_pipe(const char* cmd) {
|
||||
while (*cmd) {
|
||||
if (*cmd == '|' && *(cmd + 1) == '|') {
|
||||
return cmd;
|
||||
}
|
||||
cmd++;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Execute a single command
|
||||
|
|
@ -445,6 +479,160 @@ static void cmd_exec_single(char *cmd) {
|
|||
|
||||
// Execute command with redirection and pipe support
|
||||
static void cmd_exec(char *cmd) {
|
||||
// Check for pipe operator first
|
||||
const char* pipe_pos = find_pipe(cmd);
|
||||
if (pipe_pos) {
|
||||
// Handle piped commands
|
||||
char left_cmd[256] = {0};
|
||||
char right_cmd[256] = {0};
|
||||
|
||||
// Extract left command (before pipe)
|
||||
size_t left_len = pipe_pos - cmd;
|
||||
if (left_len >= sizeof(left_cmd)) left_len = sizeof(left_cmd) - 1;
|
||||
for (size_t j = 0; j < left_len; j++) {
|
||||
left_cmd[j] = cmd[j];
|
||||
}
|
||||
left_cmd[left_len] = '\0';
|
||||
|
||||
// Trim trailing spaces from left command
|
||||
while (left_len > 0 && left_cmd[left_len - 1] == ' ') {
|
||||
left_cmd[--left_len] = '\0';
|
||||
}
|
||||
|
||||
// Extract right command (after pipe ||)
|
||||
const char* right_start = pipe_pos + 2; // Skip both '|' characters
|
||||
while (*right_start == ' ') right_start++;
|
||||
|
||||
size_t right_len = 0;
|
||||
while (right_start[right_len] && right_len < sizeof(right_cmd) - 1) {
|
||||
right_cmd[right_len] = right_start[right_len];
|
||||
right_len++;
|
||||
}
|
||||
right_cmd[right_len] = '\0';
|
||||
|
||||
// Trim trailing spaces from right command
|
||||
while (right_len > 0 && right_cmd[right_len - 1] == ' ') {
|
||||
right_cmd[--right_len] = '\0';
|
||||
}
|
||||
|
||||
// Check if right command is UDPSEND
|
||||
char right_upper[256] = {0};
|
||||
for (int i = 0; right_cmd[i] && i < 255; i++) {
|
||||
right_upper[i] = right_cmd[i] >= 'a' && right_cmd[i] <= 'z'
|
||||
? right_cmd[i] - 32
|
||||
: right_cmd[i];
|
||||
}
|
||||
|
||||
if (right_upper[0] == 'U' && right_upper[1] == 'D' && right_upper[2] == 'P' &&
|
||||
right_upper[3] == 'S' && right_upper[4] == 'E' && right_upper[5] == 'N' &&
|
||||
right_upper[6] == 'D' && (right_upper[7] == ' ' || right_upper[7] == '\0')) {
|
||||
|
||||
// Parse UDPSEND arguments (IP and PORT only)
|
||||
const char* args = right_cmd + 7;
|
||||
while (*args == ' ') args++;
|
||||
|
||||
if (!network_is_initialized()) {
|
||||
cmd_write("Error: Network not initialized. Use NETINIT first.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// Parse IP address
|
||||
ipv4_address_t dest_ip;
|
||||
int ip_bytes[4] = {0};
|
||||
int ip_idx = 0;
|
||||
int current = 0;
|
||||
const char* p = args;
|
||||
|
||||
// Parse IP
|
||||
while (*p && ip_idx < 4) {
|
||||
if (*p >= '0' && *p <= '9') {
|
||||
current = current * 10 + (*p - '0');
|
||||
} else if (*p == '.' || *p == ' ') {
|
||||
ip_bytes[ip_idx++] = current;
|
||||
current = 0;
|
||||
if (*p == ' ') break;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
if (ip_idx < 4 && current > 0) {
|
||||
ip_bytes[ip_idx++] = current;
|
||||
}
|
||||
|
||||
if (ip_idx < 4) {
|
||||
cmd_write("Error: Invalid IP address\n");
|
||||
return;
|
||||
}
|
||||
|
||||
for (int k = 0; k < 4; k++) {
|
||||
dest_ip.bytes[k] = (uint8_t)ip_bytes[k];
|
||||
}
|
||||
|
||||
// Parse port
|
||||
while (*p == ' ') p++;
|
||||
int port = 0;
|
||||
while (*p >= '0' && *p <= '9') {
|
||||
port = port * 10 + (*p - '0');
|
||||
p++;
|
||||
}
|
||||
|
||||
if (port == 0 || port > 65535) {
|
||||
cmd_write("Error: Invalid port number\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// Initialize pipe buffer
|
||||
pipe_buffer_pos = 0;
|
||||
pipe_capture_mode = true;
|
||||
|
||||
// Execute the left command and capture its output
|
||||
cmd_exec_single(left_cmd);
|
||||
|
||||
// Disable pipe capture mode
|
||||
pipe_capture_mode = false;
|
||||
|
||||
// Null-terminate the captured output
|
||||
pipe_buffer[pipe_buffer_pos] = '\0';
|
||||
|
||||
if (pipe_buffer_pos == 0) {
|
||||
cmd_write("Error: No output to send\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// Send UDP packet(s) with captured output (chunked if necessary)
|
||||
const size_t chunk_size = 512;
|
||||
size_t offset = 0;
|
||||
int sent_bytes = 0;
|
||||
|
||||
while (offset < (size_t)pipe_buffer_pos) {
|
||||
size_t to_send = pipe_buffer_pos - offset;
|
||||
if (to_send > chunk_size) {
|
||||
to_send = chunk_size;
|
||||
}
|
||||
|
||||
// Send directly from pipe buffer
|
||||
int result = udp_send_packet(&dest_ip, (uint16_t)port, 54321,
|
||||
(const void*)(pipe_buffer + offset), to_send);
|
||||
if (result == 0) {
|
||||
sent_bytes += to_send;
|
||||
}
|
||||
offset += to_send;
|
||||
}
|
||||
|
||||
if (sent_bytes > 0) {
|
||||
cmd_write("UDP packets sent successfully (");
|
||||
cmd_write_int(sent_bytes);
|
||||
cmd_write(" bytes)\n");
|
||||
} else {
|
||||
cmd_write("Error: Failed to send UDP packets\n");
|
||||
}
|
||||
|
||||
return;
|
||||
} else {
|
||||
cmd_write("Error: Only UDPSEND is supported after pipe operator\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Check for redirection operators (> or >>)
|
||||
char *redirect_ptr = NULL;
|
||||
char redirect_op = 0; // '>' or 'a' for append
|
||||
|
|
|
|||
145
src/kernel/e1000.c
Normal file
145
src/kernel/e1000.c
Normal file
|
|
@ -0,0 +1,145 @@
|
|||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "e1000.h"
|
||||
#include "pci.h"
|
||||
#include "io.h"
|
||||
#include "platform.h"
|
||||
|
||||
static e1000_device_t e1000_dev;
|
||||
static int e1000_initialized = 0;
|
||||
static e1000_tx_desc_t tx_descriptors[E1000_TX_RING_SIZE] __attribute__((aligned(16)));
|
||||
static e1000_rx_desc_t rx_descriptors[E1000_RX_RING_SIZE] __attribute__((aligned(16)));
|
||||
static uint8_t tx_buffers[E1000_TX_RING_SIZE][2048] __attribute__((aligned(16)));
|
||||
static uint8_t rx_buffers[E1000_RX_RING_SIZE][2048] __attribute__((aligned(16)));
|
||||
|
||||
static void* kmemcpy(void* dest, const void* src, size_t n) {
|
||||
uint8_t* d = (uint8_t*)dest;
|
||||
const uint8_t* s = (const uint8_t*)src;
|
||||
for (size_t i = 0; i < n; i++) d[i] = s[i];
|
||||
return dest;
|
||||
}
|
||||
|
||||
int e1000_init(pci_device_t* pci_dev) {
|
||||
if (e1000_initialized) return 0;
|
||||
uint32_t bar0 = pci_read_config(pci_dev->bus, pci_dev->device, pci_dev->function, 0x10);
|
||||
if (bar0 == 0 || bar0 == 0xFFFFFFFF) return -1;
|
||||
if (bar0 & 1) return -1;
|
||||
uint64_t mmio_base_phys = (uint64_t)(bar0 & ~0xF);
|
||||
volatile uint32_t* mmio_base = (volatile uint32_t*)(uintptr_t)p2v(mmio_base_phys);
|
||||
e1000_dev.mmio_base = mmio_base;
|
||||
e1000_dev.pci_dev = *pci_dev;
|
||||
e1000_dev.initialized = 0;
|
||||
|
||||
uint32_t command = pci_read_config(pci_dev->bus, pci_dev->device, pci_dev->function, 0x04);
|
||||
command |= (1 << 2);
|
||||
command |= (1 << 1);
|
||||
pci_write_config(pci_dev->bus, pci_dev->device, pci_dev->function, 0x04, command);
|
||||
|
||||
uint32_t status = e1000_read_reg(mmio_base, E1000_REG_STATUS);
|
||||
(void)status;
|
||||
uint32_t ctrl = e1000_read_reg(mmio_base, E1000_REG_CTRL);
|
||||
e1000_write_reg(mmio_base, E1000_REG_CTRL, ctrl | E1000_CTRL_RST);
|
||||
for (int i = 0; i < 100000; i++) {
|
||||
ctrl = e1000_read_reg(mmio_base, E1000_REG_CTRL);
|
||||
if (!(ctrl & E1000_CTRL_RST)) break;
|
||||
}
|
||||
|
||||
uint32_t ral = e1000_read_reg(mmio_base, E1000_REG_RAL);
|
||||
uint32_t rah = e1000_read_reg(mmio_base, E1000_REG_RAH);
|
||||
e1000_dev.mac_address.bytes[0] = (uint8_t)(ral & 0xFF);
|
||||
e1000_dev.mac_address.bytes[1] = (uint8_t)((ral >> 8) & 0xFF);
|
||||
e1000_dev.mac_address.bytes[2] = (uint8_t)((ral >> 16) & 0xFF);
|
||||
e1000_dev.mac_address.bytes[3] = (uint8_t)((ral >> 24) & 0xFF);
|
||||
e1000_dev.mac_address.bytes[4] = (uint8_t)(rah & 0xFF);
|
||||
e1000_dev.mac_address.bytes[5] = (uint8_t)((rah >> 8) & 0xFF);
|
||||
|
||||
e1000_dev.tx_descriptors = tx_descriptors;
|
||||
e1000_dev.tx_head = 0;
|
||||
e1000_dev.tx_tail = 0;
|
||||
for (int i = 0; i < E1000_TX_RING_SIZE; i++) {
|
||||
e1000_dev.tx_buffers[i] = tx_buffers[i];
|
||||
e1000_dev.tx_descriptors[i].buffer_addr = v2p((uint64_t)(uintptr_t)tx_buffers[i]);
|
||||
e1000_dev.tx_descriptors[i].length = 0;
|
||||
e1000_dev.tx_descriptors[i].cso = 0;
|
||||
e1000_dev.tx_descriptors[i].cmd = 0;
|
||||
e1000_dev.tx_descriptors[i].status = 0;
|
||||
e1000_dev.tx_descriptors[i].css = 0;
|
||||
e1000_dev.tx_descriptors[i].special = 0;
|
||||
}
|
||||
uint64_t tx_desc_phys = v2p((uint64_t)(uintptr_t)tx_descriptors);
|
||||
e1000_write_reg(mmio_base, E1000_REG_TDBAL, (uint32_t)(tx_desc_phys & 0xFFFFFFFF));
|
||||
e1000_write_reg(mmio_base, E1000_REG_TDBAH, (uint32_t)(tx_desc_phys >> 32));
|
||||
e1000_write_reg(mmio_base, E1000_REG_TDLEN, E1000_TX_RING_SIZE * sizeof(e1000_tx_desc_t));
|
||||
e1000_write_reg(mmio_base, E1000_REG_TDH, 0);
|
||||
e1000_write_reg(mmio_base, E1000_REG_TDT, 0);
|
||||
uint32_t tctl = E1000_TCTL_EN | E1000_TCTL_PSP | (E1000_TCTL_CT & (0x10 << 4)) | (E1000_TCTL_COLD & (0x40 << 12));
|
||||
e1000_write_reg(mmio_base, E1000_REG_TCTL, tctl);
|
||||
e1000_write_reg(mmio_base, E1000_REG_TIPG, 0x0060200A);
|
||||
|
||||
e1000_dev.rx_descriptors = rx_descriptors;
|
||||
e1000_dev.rx_head = 0;
|
||||
e1000_dev.rx_tail = E1000_RX_RING_SIZE - 1;
|
||||
for (int i = 0; i < E1000_RX_RING_SIZE; i++) {
|
||||
e1000_dev.rx_buffers[i] = rx_buffers[i];
|
||||
e1000_dev.rx_descriptors[i].buffer_addr = v2p((uint64_t)(uintptr_t)rx_buffers[i]);
|
||||
e1000_dev.rx_descriptors[i].length = 0;
|
||||
e1000_dev.rx_descriptors[i].checksum = 0;
|
||||
e1000_dev.rx_descriptors[i].status = 0;
|
||||
e1000_dev.rx_descriptors[i].errors = 0;
|
||||
e1000_dev.rx_descriptors[i].special = 0;
|
||||
}
|
||||
uint64_t rx_desc_phys = v2p((uint64_t)(uintptr_t)rx_descriptors);
|
||||
e1000_write_reg(mmio_base, E1000_REG_RDBAL, (uint32_t)(rx_desc_phys & 0xFFFFFFFF));
|
||||
e1000_write_reg(mmio_base, E1000_REG_RDBAH, (uint32_t)(rx_desc_phys >> 32));
|
||||
e1000_write_reg(mmio_base, E1000_REG_RDLEN, E1000_RX_RING_SIZE * sizeof(e1000_rx_desc_t));
|
||||
e1000_write_reg(mmio_base, E1000_REG_RDH, 0);
|
||||
e1000_write_reg(mmio_base, E1000_REG_RDT, E1000_RX_RING_SIZE - 1);
|
||||
uint32_t rctl = E1000_RCTL_EN | E1000_RCTL_SBP | E1000_RCTL_UPE | E1000_RCTL_MPE |
|
||||
E1000_RCTL_LPE | E1000_RCTL_LBM_NONE | E1000_RCTL_RDMTS_HALF |
|
||||
E1000_RCTL_MO_36 | E1000_RCTL_BAM | E1000_RCTL_BSIZE_2048 | E1000_RCTL_SECRC;
|
||||
e1000_write_reg(mmio_base, E1000_REG_RCTL, rctl);
|
||||
ctrl = e1000_read_reg(mmio_base, E1000_REG_CTRL);
|
||||
e1000_write_reg(mmio_base, E1000_REG_CTRL, ctrl | E1000_CTRL_SLU);
|
||||
e1000_dev.initialized = 1;
|
||||
e1000_initialized = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
e1000_device_t* e1000_get_device(void) {
|
||||
if (!e1000_initialized) return NULL;
|
||||
return &e1000_dev;
|
||||
}
|
||||
|
||||
int e1000_send_packet(const void* data, size_t length) {
|
||||
if (!e1000_initialized || !e1000_dev.initialized) return -1;
|
||||
if (length > 2048) return -1;
|
||||
volatile uint32_t* mmio = e1000_dev.mmio_base;
|
||||
uint16_t next_tail = (e1000_dev.tx_tail + 1) % E1000_TX_RING_SIZE;
|
||||
if (next_tail == e1000_dev.tx_head) return -1;
|
||||
kmemcpy(e1000_dev.tx_buffers[e1000_dev.tx_tail], data, length);
|
||||
e1000_dev.tx_descriptors[e1000_dev.tx_tail].length = (uint16_t)length;
|
||||
e1000_dev.tx_descriptors[e1000_dev.tx_tail].cmd = 0x0B;
|
||||
e1000_dev.tx_descriptors[e1000_dev.tx_tail].status = 0;
|
||||
e1000_dev.tx_tail = next_tail;
|
||||
e1000_write_reg(mmio, E1000_REG_TDT, e1000_dev.tx_tail);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int e1000_receive_packet(void* buffer, size_t buffer_size) {
|
||||
if (!e1000_initialized || !e1000_dev.initialized) return 0;
|
||||
volatile uint32_t* mmio = e1000_dev.mmio_base;
|
||||
uint16_t hw_head = e1000_read_reg(mmio, E1000_REG_RDH);
|
||||
uint16_t tail = e1000_read_reg(mmio, E1000_REG_RDT);
|
||||
uint16_t next_idx = (tail + 1) % E1000_RX_RING_SIZE;
|
||||
if (hw_head == next_idx) return 0;
|
||||
if (!(e1000_dev.rx_descriptors[next_idx].status & 1)) return 0;
|
||||
uint16_t length = e1000_dev.rx_descriptors[next_idx].length - 4;
|
||||
if (length > buffer_size) length = (uint16_t)buffer_size;
|
||||
kmemcpy(buffer, e1000_dev.rx_buffers[next_idx], length);
|
||||
e1000_dev.rx_descriptors[next_idx].status = 0;
|
||||
e1000_dev.rx_descriptors[next_idx].length = 0;
|
||||
tail = next_idx;
|
||||
e1000_write_reg(mmio, E1000_REG_RDT, tail);
|
||||
e1000_dev.rx_tail = tail;
|
||||
return (int)length;
|
||||
}
|
||||
99
src/kernel/e1000.h
Normal file
99
src/kernel/e1000.h
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
#ifndef E1000_H
|
||||
#define E1000_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "pci.h"
|
||||
|
||||
#define E1000_VENDOR_ID 0x8086
|
||||
#define E1000_DEVICE_ID_82540EM 0x100E
|
||||
|
||||
#define E1000_REG_CTRL 0x0000
|
||||
#define E1000_REG_STATUS 0x0008
|
||||
#define E1000_REG_EERD 0x0014
|
||||
#define E1000_REG_ICR 0x00C0
|
||||
#define E1000_REG_IMS 0x00D0
|
||||
#define E1000_REG_RCTL 0x0100
|
||||
#define E1000_REG_TCTL 0x0400
|
||||
#define E1000_REG_TIPG 0x0410
|
||||
#define E1000_REG_RDBAL 0x2800
|
||||
#define E1000_REG_RDBAH 0x2804
|
||||
#define E1000_REG_RDLEN 0x2808
|
||||
#define E1000_REG_RDH 0x2810
|
||||
#define E1000_REG_RDT 0x2818
|
||||
#define E1000_REG_TDBAL 0x3800
|
||||
#define E1000_REG_TDBAH 0x3804
|
||||
#define E1000_REG_TDLEN 0x3808
|
||||
#define E1000_REG_TDH 0x3810
|
||||
#define E1000_REG_TDT 0x3818
|
||||
#define E1000_REG_RAL 0x5400
|
||||
#define E1000_REG_RAH 0x5404
|
||||
|
||||
#define E1000_CTRL_RST (1 << 26)
|
||||
#define E1000_CTRL_SLU (1 << 6)
|
||||
|
||||
#define E1000_RCTL_EN (1 << 1)
|
||||
#define E1000_RCTL_SBP (1 << 2)
|
||||
#define E1000_RCTL_UPE (1 << 3)
|
||||
#define E1000_RCTL_MPE (1 << 4)
|
||||
#define E1000_RCTL_LPE (1 << 5)
|
||||
#define E1000_RCTL_LBM_NONE (0 << 6)
|
||||
#define E1000_RCTL_RDMTS_HALF (0 << 8)
|
||||
#define E1000_RCTL_MO_36 (0 << 12)
|
||||
#define E1000_RCTL_BAM (1 << 15)
|
||||
#define E1000_RCTL_BSIZE_2048 (1 << 16)
|
||||
#define E1000_RCTL_SECRC (1 << 26)
|
||||
|
||||
#define E1000_TCTL_EN (1 << 1)
|
||||
#define E1000_TCTL_PSP (1 << 3)
|
||||
#define E1000_TCTL_CT (0xF << 4)
|
||||
#define E1000_TCTL_COLD (0x3F << 12)
|
||||
|
||||
#define E1000_ICR_TXDW (1 << 0)
|
||||
#define E1000_ICR_RXT0 (1 << 7)
|
||||
|
||||
#define E1000_TX_RING_SIZE 32
|
||||
#define E1000_RX_RING_SIZE 32
|
||||
|
||||
typedef struct {
|
||||
uint64_t buffer_addr;
|
||||
uint16_t length;
|
||||
uint8_t cso;
|
||||
uint8_t cmd;
|
||||
uint8_t status;
|
||||
uint8_t css;
|
||||
uint16_t special;
|
||||
} __attribute__((packed)) e1000_tx_desc_t;
|
||||
|
||||
typedef struct {
|
||||
uint64_t buffer_addr;
|
||||
uint16_t length;
|
||||
uint16_t checksum;
|
||||
uint8_t status;
|
||||
uint8_t errors;
|
||||
uint16_t special;
|
||||
} __attribute__((packed)) e1000_rx_desc_t;
|
||||
|
||||
typedef struct {
|
||||
volatile uint32_t* mmio_base;
|
||||
pci_device_t pci_dev;
|
||||
int initialized;
|
||||
struct { uint8_t bytes[6]; } mac_address;
|
||||
e1000_tx_desc_t* tx_descriptors;
|
||||
void* tx_buffers[E1000_TX_RING_SIZE];
|
||||
uint16_t tx_head;
|
||||
uint16_t tx_tail;
|
||||
e1000_rx_desc_t* rx_descriptors;
|
||||
void* rx_buffers[E1000_RX_RING_SIZE];
|
||||
uint16_t rx_head;
|
||||
uint16_t rx_tail;
|
||||
} e1000_device_t;
|
||||
|
||||
int e1000_init(pci_device_t* pci_dev);
|
||||
static inline uint32_t e1000_read_reg(volatile uint32_t* mmio_base, uint16_t offset) { return mmio_base[offset / 4]; }
|
||||
static inline void e1000_write_reg(volatile uint32_t* mmio_base, uint16_t offset, uint32_t value) { mmio_base[offset / 4] = value; }
|
||||
e1000_device_t* e1000_get_device(void);
|
||||
int e1000_send_packet(const void* data, size_t length);
|
||||
int e1000_receive_packet(void* buffer, size_t buffer_size);
|
||||
|
||||
#endif
|
||||
|
|
@ -17,6 +17,16 @@ static inline uint8_t inb(uint16_t port) {
|
|||
return ret;
|
||||
}
|
||||
|
||||
static inline void outl(uint16_t port, uint32_t val) {
|
||||
asm volatile ("outl %0, %1" : : "a"(val), "Nd"(port));
|
||||
}
|
||||
|
||||
static inline uint32_t inl(uint16_t port) {
|
||||
uint32_t ret;
|
||||
asm volatile ("inl %1, %0" : "=a"(ret) : "Nd"(port));
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void io_wait(void) {
|
||||
outb(0x80, 0);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
#include "wm.h"
|
||||
#include "io.h"
|
||||
#include "memory_manager.h"
|
||||
#include "platform.h"
|
||||
|
||||
// --- Limine Requests ---
|
||||
__attribute__((used, section(".requests")))
|
||||
|
|
@ -46,6 +47,7 @@ static void hcf(void) {
|
|||
|
||||
// Kernel Entry Point
|
||||
void kmain(void) {
|
||||
platform_init();
|
||||
// 1. Graphics Init
|
||||
if (LIMINE_BASE_REVISION_SUPPORTED == false) {
|
||||
// Warning
|
||||
|
|
@ -103,4 +105,4 @@ void kmain(void) {
|
|||
while (1) {
|
||||
asm("hlt");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
433
src/kernel/network.c
Normal file
433
src/kernel/network.c
Normal file
|
|
@ -0,0 +1,433 @@
|
|||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "network.h"
|
||||
#include "e1000.h"
|
||||
#include "pci.h"
|
||||
|
||||
static int network_initialized = 0;
|
||||
static mac_address_t our_mac;
|
||||
static ipv4_address_t our_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;
|
||||
#define ARP_CACHE_SIZE 16
|
||||
static arp_cache_entry_t arp_cache[ARP_CACHE_SIZE];
|
||||
static int arp_cache_initialized = 0;
|
||||
|
||||
#define UDP_MAX_CALLBACKS 8
|
||||
typedef struct { uint16_t port; udp_callback_t callback; int valid; } udp_callback_entry_t;
|
||||
static udp_callback_entry_t udp_callbacks[UDP_MAX_CALLBACKS];
|
||||
|
||||
static int frames_received_count = 0;
|
||||
static int udp_packets_received_count = 0;
|
||||
static int udp_callbacks_called_count = 0;
|
||||
static int e1000_receive_calls = 0;
|
||||
static int e1000_receive_empty = 0;
|
||||
static int network_process_calls = 0;
|
||||
|
||||
static void* kmemcpy(void* d, const void* s, size_t n){uint8_t*D=d;const uint8_t*S=s;for(size_t i=0;i<n;i++)D[i]=S[i];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 uint16_t htons(uint16_t x){return (uint16_t)(((x&0xFF)<<8)|((x>>8)&0xFF));}
|
||||
static uint16_t ntohs(uint16_t x){return htons(x);}
|
||||
static uint32_t htonl(uint32_t v){return ((v&0xFF)<<24)|((v&0xFF00)<<8)|((v>>8)&0xFF00)|((v>>24)&0xFF);}
|
||||
|
||||
static uint16_t ipv4_checksum(const ipv4_header_t* h){
|
||||
uint32_t sum=0;const uint16_t* w=(const uint16_t*)h;
|
||||
for(int i=0;i<10;i++) sum+=w[i];
|
||||
while(sum>>16) sum=(sum&0xFFFF)+(sum>>16);
|
||||
return (uint16_t)(~sum);
|
||||
}
|
||||
|
||||
static void arp_cache_init(void){ if(arp_cache_initialized) return; kmemset(arp_cache,0,sizeof(arp_cache)); arp_cache_initialized=1; }
|
||||
static arp_cache_entry_t* arp_cache_find(const ipv4_address_t* ip){ for(int i=0;i<ARP_CACHE_SIZE;i++){ if(arp_cache[i].valid && kmemcmp(&arp_cache[i].ip, ip, sizeof(ipv4_address_t))==0) return &arp_cache[i]; } return NULL; }
|
||||
static void arp_cache_add(const ipv4_address_t* ip,const mac_address_t* mac){ arp_cache_entry_t* e=arp_cache_find(ip); if(e){ kmemcpy(&e->mac,mac,sizeof(mac_address_t)); e->timestamp=0; return;} for(int i=0;i<ARP_CACHE_SIZE;i++){ if(!arp_cache[i].valid){ kmemcpy(&arp_cache[i].ip,ip,sizeof(ipv4_address_t)); kmemcpy(&arp_cache[i].mac,mac,sizeof(mac_address_t)); arp_cache[i].timestamp=0; arp_cache[i].valid=1; return; } } kmemcpy(&arp_cache[0].ip,ip,sizeof(ipv4_address_t)); kmemcpy(&arp_cache[0].mac,mac,sizeof(mac_address_t)); arp_cache[0].timestamp=0; arp_cache[0].valid=1; }
|
||||
|
||||
int network_init(void){
|
||||
if(network_initialized) return 0;
|
||||
pci_device_t device;
|
||||
if(!pci_find_device(E1000_VENDOR_ID,E1000_DEVICE_ID_82540EM,&device)) return -1;
|
||||
if(e1000_init(&device)!=0) return -1;
|
||||
if(network_get_mac_address(&our_mac)!=0) return -1;
|
||||
arp_cache_init();
|
||||
kmemset(udp_callbacks,0,sizeof(udp_callbacks));
|
||||
network_initialized=1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int network_get_mac_address(mac_address_t* mac){
|
||||
e1000_device_t* dev=e1000_get_device();
|
||||
if(!dev) return -1;
|
||||
*mac=*(mac_address_t*)&dev->mac_address;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int network_get_ipv4_address(ipv4_address_t* ip){ if(!network_initialized) return -1; *ip=our_ip; return 0; }
|
||||
int network_set_ipv4_address(const ipv4_address_t* ip){ if(!network_initialized) return -1; our_ip=*ip; return 0; }
|
||||
|
||||
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){
|
||||
if(!network_initialized) return 0;
|
||||
e1000_receive_calls++;
|
||||
int result=e1000_receive_packet(buffer,buffer_size);
|
||||
if(result==0) e1000_receive_empty++;
|
||||
return result;
|
||||
}
|
||||
|
||||
void network_process_frames(void){
|
||||
network_process_calls++;
|
||||
if(!network_initialized) return;
|
||||
uint8_t frame_buffer[ETH_FRAME_MAX_SIZE];
|
||||
int frame_length;
|
||||
while((frame_length=network_receive_frame(frame_buffer,sizeof(frame_buffer)))>0){
|
||||
frames_received_count++;
|
||||
if(frame_length<(int)sizeof(eth_header_t)) continue;
|
||||
eth_header_t* eth=(eth_header_t*)frame_buffer;
|
||||
uint16_t ethertype=ntohs(eth->ethertype);
|
||||
int is_broadcast=1; int is_for_us=1;
|
||||
for(int i=0;i<6;i++){ if(eth->dest_mac[i]!=0xFF) is_broadcast=0; if(eth->dest_mac[i]!=our_mac.bytes[i]) is_for_us=0; }
|
||||
if(!is_broadcast && !is_for_us) continue;
|
||||
void* payload=frame_buffer+sizeof(eth_header_t);
|
||||
size_t payload_length=frame_length-sizeof(eth_header_t);
|
||||
if(ethertype==ETH_ETHERTYPE_ARP){
|
||||
if(payload_length>=sizeof(arp_header_t)) arp_process_packet((arp_header_t*)payload,payload_length);
|
||||
} else if(ethertype==ETH_ETHERTYPE_IPV4){
|
||||
if(payload_length>=sizeof(ipv4_header_t)){
|
||||
ipv4_header_t* ip=(ipv4_header_t*)payload;
|
||||
uint16_t checksum=ip->checksum;
|
||||
ip->checksum=0;
|
||||
uint16_t calc=ipv4_checksum(ip);
|
||||
ip->checksum=checksum;
|
||||
if(checksum==calc){
|
||||
int for_our_ip=1;
|
||||
for(int i=0;i<4;i++){ if(ip->dest_ip[i]!=our_ip.bytes[i]) { for_our_ip=0; break; } }
|
||||
if(for_our_ip || ip->dest_ip[0]==255){
|
||||
mac_address_t src_mac;
|
||||
kmemcpy(src_mac.bytes,eth->src_mac,6);
|
||||
ipv4_process_packet(ip,&src_mac,payload_length);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int arp_send_request(const ipv4_address_t* target_ip){
|
||||
if(!network_initialized) return -1;
|
||||
uint8_t frame[ETH_FRAME_MAX_SIZE];
|
||||
eth_header_t* eth=(eth_header_t*)frame;
|
||||
arp_header_t* arp=(arp_header_t*)(frame+sizeof(eth_header_t));
|
||||
for(int i=0;i<6;i++) eth->dest_mac[i]=0xFF;
|
||||
kmemcpy(eth->src_mac,our_mac.bytes,6);
|
||||
eth->ethertype=htons(ETH_ETHERTYPE_ARP);
|
||||
arp->hw_type=htons(1);
|
||||
arp->proto_type=htons(ETH_ETHERTYPE_IPV4);
|
||||
arp->hw_len=6;
|
||||
arp->proto_len=4;
|
||||
arp->opcode=htons(ARP_OP_REQUEST);
|
||||
kmemcpy(arp->sender_mac,our_mac.bytes,6);
|
||||
kmemcpy(arp->sender_ip,our_ip.bytes,4);
|
||||
for(int i=0;i<6;i++) arp->target_mac[i]=0;
|
||||
kmemcpy(arp->target_ip,target_ip->bytes,4);
|
||||
size_t frame_length=sizeof(eth_header_t)+sizeof(arp_header_t);
|
||||
return network_send_frame(frame,frame_length);
|
||||
}
|
||||
|
||||
int arp_lookup(const ipv4_address_t* ip,mac_address_t* mac){
|
||||
if(!network_initialized) return -1;
|
||||
arp_cache_entry_t* e=arp_cache_find(ip);
|
||||
if(e && e->valid){ *mac=e->mac; return 0; }
|
||||
arp_send_request(ip);
|
||||
return -1;
|
||||
}
|
||||
|
||||
void arp_process_packet(const arp_header_t* arp,size_t length){
|
||||
if(length<sizeof(arp_header_t)) return;
|
||||
if(ntohs(arp->hw_type)!=1 || ntohs(arp->proto_type)!=ETH_ETHERTYPE_IPV4) return;
|
||||
uint16_t opcode=ntohs(arp->opcode);
|
||||
ipv4_address_t sender_ip; mac_address_t sender_mac;
|
||||
kmemcpy(sender_ip.bytes,arp->sender_ip,4);
|
||||
kmemcpy(sender_mac.bytes,arp->sender_mac,6);
|
||||
arp_cache_add(&sender_ip,&sender_mac);
|
||||
if(opcode==ARP_OP_REQUEST){
|
||||
int is_for_us=1;
|
||||
for(int i=0;i<4;i++){ if(arp->target_ip[i]!=our_ip.bytes[i]) { is_for_us=0; break; } }
|
||||
if(is_for_us){
|
||||
uint8_t frame[ETH_FRAME_MAX_SIZE];
|
||||
eth_header_t* eth=(eth_header_t*)frame;
|
||||
arp_header_t* r=(arp_header_t*)(frame+sizeof(eth_header_t));
|
||||
kmemcpy(eth->dest_mac,arp->sender_mac,6);
|
||||
kmemcpy(eth->src_mac,our_mac.bytes,6);
|
||||
eth->ethertype=htons(ETH_ETHERTYPE_ARP);
|
||||
r->hw_type=htons(1);
|
||||
r->proto_type=htons(ETH_ETHERTYPE_IPV4);
|
||||
r->hw_len=6;
|
||||
r->proto_len=4;
|
||||
r->opcode=htons(ARP_OP_REPLY);
|
||||
kmemcpy(r->sender_mac,our_mac.bytes,6);
|
||||
kmemcpy(r->sender_ip,our_ip.bytes,4);
|
||||
kmemcpy(r->target_mac,arp->sender_mac,6);
|
||||
kmemcpy(r->target_ip,arp->sender_ip,4);
|
||||
size_t frame_length=sizeof(eth_header_t)+sizeof(arp_header_t);
|
||||
network_send_frame(frame,frame_length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int ipv4_send_packet(const ipv4_address_t* dest_ip,uint8_t protocol,const void* data,size_t data_length){
|
||||
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; } }
|
||||
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));
|
||||
void* ip_payload=frame+sizeof(eth_header_t)+sizeof(ipv4_header_t);
|
||||
kmemcpy(eth->dest_mac,dest_mac.bytes,6);
|
||||
kmemcpy(eth->src_mac,our_mac.bytes,6);
|
||||
eth->ethertype=htons(ETH_ETHERTYPE_IPV4);
|
||||
ip->version_ihl=(4<<4)|5;
|
||||
ip->tos=0;
|
||||
ip->total_length=htons(sizeof(ipv4_header_t)+data_length);
|
||||
ip->id=htons(ipv4_id_counter++);
|
||||
ip->flags_frag=0;
|
||||
ip->ttl=64;
|
||||
ip->protocol=protocol;
|
||||
ip->checksum=0;
|
||||
kmemcpy(ip->src_ip,our_ip.bytes,4);
|
||||
kmemcpy(ip->dest_ip,dest_ip->bytes,4);
|
||||
ip->checksum=ipv4_checksum(ip);
|
||||
kmemcpy(ip_payload,data,data_length);
|
||||
size_t frame_length=sizeof(eth_header_t)+sizeof(ipv4_header_t)+data_length;
|
||||
return network_send_frame(frame,frame_length);
|
||||
}
|
||||
|
||||
int ipv4_send_packet_to_mac(const ipv4_address_t* dest_ip,const mac_address_t* dest_mac,uint8_t protocol,const void* data,size_t data_length){
|
||||
if(!network_initialized) return -1;
|
||||
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));
|
||||
void* ip_payload=frame+sizeof(eth_header_t)+sizeof(ipv4_header_t);
|
||||
kmemcpy(eth->dest_mac,dest_mac->bytes,6);
|
||||
kmemcpy(eth->src_mac,our_mac.bytes,6);
|
||||
eth->ethertype=htons(ETH_ETHERTYPE_IPV4);
|
||||
ip->version_ihl=(4<<4)|5;
|
||||
ip->tos=0;
|
||||
ip->total_length=htons(sizeof(ipv4_header_t)+data_length);
|
||||
ip->id=htons(ipv4_id_counter++);
|
||||
ip->flags_frag=0;
|
||||
ip->ttl=64;
|
||||
ip->protocol=protocol;
|
||||
ip->checksum=0;
|
||||
kmemcpy(ip->src_ip,our_ip.bytes,4);
|
||||
kmemcpy(ip->dest_ip,dest_ip->bytes,4);
|
||||
ip->checksum=ipv4_checksum(ip);
|
||||
kmemcpy(ip_payload,data,data_length);
|
||||
size_t frame_length=sizeof(eth_header_t)+sizeof(ipv4_header_t)+data_length;
|
||||
return network_send_frame(frame,frame_length);
|
||||
}
|
||||
|
||||
void ipv4_process_packet(const ipv4_header_t* ip,const mac_address_t* src_mac,size_t length){
|
||||
if(length<sizeof(ipv4_header_t)) return;
|
||||
uint8_t ihl=(ip->version_ihl & 0x0F)*4;
|
||||
if(ihl<20 || length<ihl) return;
|
||||
uint16_t total_length=ntohs(ip->total_length);
|
||||
if(total_length>length) return;
|
||||
void* payload=(void*)ip+ihl;
|
||||
size_t payload_length=total_length-ihl;
|
||||
if(ip->protocol==IP_PROTO_UDP){
|
||||
if(payload_length>=sizeof(udp_header_t)){
|
||||
udp_packets_received_count++;
|
||||
ipv4_address_t src_ip;
|
||||
kmemcpy(src_ip.bytes,ip->src_ip,4);
|
||||
udp_header_t* udp=(udp_header_t*)payload;
|
||||
uint16_t dest_port=ntohs(udp->dest_port);
|
||||
uint16_t src_port=ntohs(udp->src_port);
|
||||
uint16_t udp_length=ntohs(udp->length);
|
||||
if(udp_length>payload_length) return;
|
||||
void* udp_payload=(void*)udp+sizeof(udp_header_t);
|
||||
size_t udp_payload_length=udp_length-sizeof(udp_header_t);
|
||||
for(int i=0;i<UDP_MAX_CALLBACKS;i++){
|
||||
if(udp_callbacks[i].valid && udp_callbacks[i].port==dest_port){
|
||||
udp_callbacks_called_count++;
|
||||
udp_callbacks[i].callback(&src_ip,src_port,src_mac,udp_payload,udp_payload_length);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int udp_send_packet(const ipv4_address_t* dest_ip,uint16_t dest_port,uint16_t src_port,const void* data,size_t data_length){
|
||||
if(!network_initialized) return -1;
|
||||
uint8_t udp_packet[ETH_FRAME_MAX_SIZE];
|
||||
udp_header_t* udp=(udp_header_t*)udp_packet;
|
||||
void* udp_payload=udp_packet+sizeof(udp_header_t);
|
||||
udp->src_port=htons(src_port);
|
||||
udp->dest_port=htons(dest_port);
|
||||
udp->length=htons(sizeof(udp_header_t)+data_length);
|
||||
udp->checksum=0;
|
||||
kmemcpy(udp_payload,data,data_length);
|
||||
size_t udp_packet_length=sizeof(udp_header_t)+data_length;
|
||||
return ipv4_send_packet(dest_ip,IP_PROTO_UDP,udp_packet,udp_packet_length);
|
||||
}
|
||||
|
||||
int udp_send_packet_to_mac(const ipv4_address_t* dest_ip,const mac_address_t* dest_mac,uint16_t dest_port,uint16_t src_port,const void* data,size_t data_length){
|
||||
if(!network_initialized) return -1;
|
||||
uint8_t udp_packet[ETH_FRAME_MAX_SIZE];
|
||||
udp_header_t* udp=(udp_header_t*)udp_packet;
|
||||
void* udp_payload=udp_packet+sizeof(udp_header_t);
|
||||
udp->src_port=htons(src_port);
|
||||
udp->dest_port=htons(dest_port);
|
||||
udp->length=htons(sizeof(udp_header_t)+data_length);
|
||||
udp->checksum=0;
|
||||
kmemcpy(udp_payload,data,data_length);
|
||||
size_t udp_packet_length=sizeof(udp_header_t)+data_length;
|
||||
return ipv4_send_packet_to_mac(dest_ip,dest_mac,IP_PROTO_UDP,udp_packet,udp_packet_length);
|
||||
}
|
||||
|
||||
int udp_register_callback(uint16_t port,udp_callback_t callback){
|
||||
if(!network_initialized) return -1;
|
||||
for(int i=0;i<UDP_MAX_CALLBACKS;i++){
|
||||
if(!udp_callbacks[i].valid || udp_callbacks[i].port==port){
|
||||
udp_callbacks[i].port=port;
|
||||
udp_callbacks[i].callback=callback;
|
||||
udp_callbacks[i].valid=1;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int network_is_initialized(void){ return network_initialized; }
|
||||
int network_get_frames_received(void){ return frames_received_count; }
|
||||
int network_get_udp_packets_received(void){ return udp_packets_received_count; }
|
||||
int network_get_udp_callbacks_called(void){ return udp_callbacks_called_count; }
|
||||
int network_get_e1000_receive_calls(void){ return e1000_receive_calls; }
|
||||
int network_get_e1000_receive_empty(void){ return e1000_receive_empty; }
|
||||
int network_get_process_calls(void){ return network_process_calls; }
|
||||
|
||||
#define DHCP_CLIENT_PORT 68
|
||||
#define DHCP_SERVER_PORT 67
|
||||
#define DHCP_MAGIC_COOKIE 0x63825363U
|
||||
#define DHCP_OP_BOOTREQUEST 1
|
||||
#define DHCP_OP_BOOTREPLY 2
|
||||
#define DHCP_HTYPE_ETHERNET 1
|
||||
#define DHCP_HLEN_ETHERNET 6
|
||||
#define DHCP_MSG_DISCOVER 1
|
||||
#define DHCP_MSG_OFFER 2
|
||||
#define DHCP_MSG_REQUEST 3
|
||||
#define DHCP_MSG_ACK 5
|
||||
#define DHCP_MSG_NAK 6
|
||||
#define DHCP_OPT_MSG_TYPE 53
|
||||
#define DHCP_OPT_SERVER_ID 54
|
||||
#define DHCP_OPT_REQ_IP 50
|
||||
#define DHCP_OPT_PARAM_REQ_LIST 55
|
||||
#define DHCP_OPT_END 255
|
||||
|
||||
typedef struct {
|
||||
uint8_t op;
|
||||
uint8_t htype;
|
||||
uint8_t hlen;
|
||||
uint8_t hops;
|
||||
uint32_t xid;
|
||||
uint16_t secs;
|
||||
uint16_t flags;
|
||||
uint32_t ciaddr;
|
||||
uint32_t yiaddr;
|
||||
uint32_t siaddr;
|
||||
uint32_t giaddr;
|
||||
uint8_t chaddr[16];
|
||||
uint8_t sname[64];
|
||||
uint8_t file[128];
|
||||
uint32_t magic_cookie;
|
||||
uint8_t options[312];
|
||||
} __attribute__((packed)) dhcp_packet_t;
|
||||
|
||||
static volatile int dhcp_state = 0;
|
||||
static uint32_t dhcp_xid = 0;
|
||||
static ipv4_address_t dhcp_offered_ip;
|
||||
static uint32_t dhcp_server_id = 0;
|
||||
|
||||
static uint32_t htonl32(uint32_t v){return ((v&0xFF)<<24)|((v&0xFF00)<<8)|((v>>8)&0xFF00)|((v>>24)&0xFF);}
|
||||
static uint32_t ntohl32(uint32_t v){return htonl32(v);}
|
||||
static uint16_t htons16(uint16_t v){return (uint16_t)(((v&0xFF)<<8)|((v>>8)&0xFF));}
|
||||
|
||||
static void dhcp_build_discover(dhcp_packet_t* pkt){
|
||||
kmemset(pkt,0,sizeof(dhcp_packet_t));
|
||||
pkt->op=DHCP_OP_BOOTREQUEST; pkt->htype=DHCP_HTYPE_ETHERNET; pkt->hlen=DHCP_HLEN_ETHERNET; pkt->xid=htonl32(dhcp_xid); pkt->flags=htons16(0x8000);
|
||||
kmemcpy(pkt->chaddr,our_mac.bytes,6);
|
||||
pkt->magic_cookie=htonl32(DHCP_MAGIC_COOKIE);
|
||||
uint8_t* opt=pkt->options;
|
||||
*opt++=DHCP_OPT_MSG_TYPE; *opt++=1; *opt++=DHCP_MSG_DISCOVER;
|
||||
*opt++=DHCP_OPT_PARAM_REQ_LIST; *opt++=3; *opt++=1; *opt++=3; *opt++=6;
|
||||
*opt++=DHCP_OPT_END;
|
||||
}
|
||||
|
||||
static void dhcp_build_request(dhcp_packet_t* pkt){
|
||||
kmemset(pkt,0,sizeof(dhcp_packet_t));
|
||||
pkt->op=DHCP_OP_BOOTREQUEST; pkt->htype=DHCP_HTYPE_ETHERNET; pkt->hlen=DHCP_HLEN_ETHERNET; pkt->xid=htonl32(dhcp_xid); pkt->flags=htons16(0x8000);
|
||||
kmemcpy(pkt->chaddr,our_mac.bytes,6);
|
||||
pkt->magic_cookie=htonl32(DHCP_MAGIC_COOKIE);
|
||||
uint8_t* opt=pkt->options;
|
||||
*opt++=DHCP_OPT_MSG_TYPE; *opt++=1; *opt++=DHCP_MSG_REQUEST;
|
||||
*opt++=DHCP_OPT_REQ_IP; *opt++=4; *opt++=dhcp_offered_ip.bytes[0]; *opt++=dhcp_offered_ip.bytes[1]; *opt++=dhcp_offered_ip.bytes[2]; *opt++=dhcp_offered_ip.bytes[3];
|
||||
*opt++=DHCP_OPT_SERVER_ID; *opt++=4;
|
||||
*opt++=(uint8_t)((dhcp_server_id>>24)&0xFF); *opt++=(uint8_t)((dhcp_server_id>>16)&0xFF); *opt++=(uint8_t)((dhcp_server_id>>8)&0xFF); *opt++=(uint8_t)(dhcp_server_id&0xFF);
|
||||
*opt++=DHCP_OPT_END;
|
||||
}
|
||||
|
||||
static uint8_t dhcp_get_option(const uint8_t* opts,uint8_t code){
|
||||
const uint8_t* p=opts;
|
||||
while(*p!=DHCP_OPT_END){ uint8_t c=*p++; uint8_t l=*p++; if(c==code) return p[0]; p+=l; }
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dhcp_udp_callback(const ipv4_address_t* src_ip,uint16_t src_port,const mac_address_t* src_mac,const void* payload,size_t payload_length){
|
||||
(void)src_ip; (void)src_mac;
|
||||
if(src_port!=DHCP_SERVER_PORT || payload_length<sizeof(dhcp_packet_t)-312) return;
|
||||
dhcp_packet_t* pkt=(dhcp_packet_t*)payload;
|
||||
if(pkt->op!=DHCP_OP_BOOTREPLY) return;
|
||||
if(ntohl32(pkt->xid)!=dhcp_xid) return;
|
||||
if(ntohl32(pkt->magic_cookie)!=DHCP_MAGIC_COOKIE) return;
|
||||
uint8_t mtype=dhcp_get_option(pkt->options,DHCP_OPT_MSG_TYPE);
|
||||
if(mtype==DHCP_MSG_OFFER){
|
||||
uint32_t yi_host=ntohl32(pkt->yiaddr);
|
||||
dhcp_offered_ip.bytes[0]=(uint8_t)((yi_host>>24)&0xFF);
|
||||
dhcp_offered_ip.bytes[1]=(uint8_t)((yi_host>>16)&0xFF);
|
||||
dhcp_offered_ip.bytes[2]=(uint8_t)((yi_host>>8)&0xFF);
|
||||
dhcp_offered_ip.bytes[3]=(uint8_t)(yi_host&0xFF);
|
||||
const uint8_t* p=pkt->options; dhcp_server_id=0;
|
||||
while(*p!=DHCP_OPT_END){ uint8_t c=*p++; uint8_t l=*p++; if(c==DHCP_OPT_SERVER_ID && l==4){ dhcp_server_id=((uint32_t)p[0]<<24)|((uint32_t)p[1]<<16)|((uint32_t)p[2]<<8)|(uint32_t)p[3]; break; } p+=l; }
|
||||
if(dhcp_server_id!=0) dhcp_state=1;
|
||||
} else if(mtype==DHCP_MSG_ACK){
|
||||
uint32_t yi_host=ntohl32(pkt->yiaddr);
|
||||
our_ip.bytes[0]=(uint8_t)((yi_host>>24)&0xFF);
|
||||
our_ip.bytes[1]=(uint8_t)((yi_host>>16)&0xFF);
|
||||
our_ip.bytes[2]=(uint8_t)((yi_host>>8)&0xFF);
|
||||
our_ip.bytes[3]=(uint8_t)(yi_host&0xFF);
|
||||
dhcp_state=2;
|
||||
} else if(mtype==DHCP_MSG_NAK){
|
||||
dhcp_state=-1;
|
||||
}
|
||||
}
|
||||
|
||||
int network_dhcp_acquire(void){
|
||||
if(!network_initialized) return -1;
|
||||
if(udp_register_callback(DHCP_CLIENT_PORT,dhcp_udp_callback)!=0) return -1;
|
||||
dhcp_xid += 0x12345u + (uint32_t)ipv4_id_counter;
|
||||
dhcp_state=0; dhcp_server_id=0;
|
||||
dhcp_packet_t pkt;
|
||||
dhcp_build_discover(&pkt);
|
||||
ipv4_address_t bcast={{255,255,255,255}};
|
||||
udp_send_packet(&bcast,DHCP_SERVER_PORT,DHCP_CLIENT_PORT,&pkt,sizeof(dhcp_packet_t));
|
||||
for(int i=0;i<500000 && dhcp_state==0;i++){ network_process_frames(); if(i%1000==0){ for(volatile int d=0; d<100000; d++){} } }
|
||||
if(dhcp_state!=1) return -1;
|
||||
dhcp_build_request(&pkt);
|
||||
udp_send_packet(&bcast,DHCP_SERVER_PORT,DHCP_CLIENT_PORT,&pkt,sizeof(dhcp_packet_t));
|
||||
for(int i=0;i<500000 && dhcp_state==1;i++){ network_process_frames(); if(i%1000==0){ for(volatile int d=0; d<100000; d++){} } }
|
||||
return (dhcp_state==2)?0:-1;
|
||||
}
|
||||
85
src/kernel/network.h
Normal file
85
src/kernel/network.h
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
#ifndef NETWORK_H
|
||||
#define NETWORK_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "e1000.h"
|
||||
|
||||
#define ETH_FRAME_MAX_SIZE 1518
|
||||
#define ETH_HEADER_SIZE 14
|
||||
#define ETH_ETHERTYPE_ARP 0x0806
|
||||
#define ETH_ETHERTYPE_IPV4 0x0800
|
||||
|
||||
typedef struct { uint8_t bytes[6]; } mac_address_t;
|
||||
typedef struct { uint8_t bytes[4]; } ipv4_address_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t dest_mac[6];
|
||||
uint8_t src_mac[6];
|
||||
uint16_t ethertype;
|
||||
} __attribute__((packed)) eth_header_t;
|
||||
|
||||
#define ARP_OP_REQUEST 1
|
||||
#define ARP_OP_REPLY 2
|
||||
|
||||
typedef struct {
|
||||
uint16_t hw_type;
|
||||
uint16_t proto_type;
|
||||
uint8_t hw_len;
|
||||
uint8_t proto_len;
|
||||
uint16_t opcode;
|
||||
uint8_t sender_mac[6];
|
||||
uint8_t sender_ip[4];
|
||||
uint8_t target_mac[6];
|
||||
uint8_t target_ip[4];
|
||||
} __attribute__((packed)) arp_header_t;
|
||||
|
||||
#define IP_PROTO_UDP 17
|
||||
|
||||
typedef struct {
|
||||
uint8_t version_ihl;
|
||||
uint8_t tos;
|
||||
uint16_t total_length;
|
||||
uint16_t id;
|
||||
uint16_t flags_frag;
|
||||
uint8_t ttl;
|
||||
uint8_t protocol;
|
||||
uint16_t checksum;
|
||||
uint8_t src_ip[4];
|
||||
uint8_t dest_ip[4];
|
||||
} __attribute__((packed)) ipv4_header_t;
|
||||
|
||||
typedef struct {
|
||||
uint16_t src_port;
|
||||
uint16_t dest_port;
|
||||
uint16_t length;
|
||||
uint16_t checksum;
|
||||
} __attribute__((packed)) udp_header_t;
|
||||
|
||||
int network_init(void);
|
||||
int network_get_mac_address(mac_address_t* mac);
|
||||
int network_get_ipv4_address(ipv4_address_t* ip);
|
||||
int network_set_ipv4_address(const ipv4_address_t* ip);
|
||||
int network_send_frame(const void* data, size_t length);
|
||||
int network_receive_frame(void* buffer, size_t buffer_size);
|
||||
void network_process_frames(void);
|
||||
int arp_send_request(const ipv4_address_t* target_ip);
|
||||
int arp_lookup(const ipv4_address_t* ip, mac_address_t* mac);
|
||||
void arp_process_packet(const arp_header_t* arp, size_t length);
|
||||
int ipv4_send_packet(const ipv4_address_t* dest_ip, uint8_t protocol, const void* data, size_t data_length);
|
||||
int ipv4_send_packet_to_mac(const ipv4_address_t* dest_ip, const mac_address_t* dest_mac, uint8_t protocol, const void* data, size_t data_length);
|
||||
void ipv4_process_packet(const ipv4_header_t* ip, const mac_address_t* src_mac, size_t length);
|
||||
int udp_send_packet(const ipv4_address_t* dest_ip, uint16_t dest_port, uint16_t src_port, const void* data, size_t data_length);
|
||||
int udp_send_packet_to_mac(const ipv4_address_t* dest_ip, const mac_address_t* dest_mac, uint16_t dest_port, uint16_t src_port, const void* data, size_t data_length);
|
||||
typedef void (*udp_callback_t)(const ipv4_address_t* src_ip, uint16_t src_port, const mac_address_t* src_mac, const void* data, size_t length);
|
||||
int udp_register_callback(uint16_t port, udp_callback_t callback);
|
||||
int network_is_initialized(void);
|
||||
int network_get_frames_received(void);
|
||||
int network_get_udp_packets_received(void);
|
||||
int network_get_udp_callbacks_called(void);
|
||||
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);
|
||||
|
||||
#endif
|
||||
96
src/kernel/pci.c
Normal file
96
src/kernel/pci.c
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
#include <stdint.h>
|
||||
#include "pci.h"
|
||||
#include "io.h"
|
||||
|
||||
uint32_t pci_read_config(uint8_t bus, uint8_t device, uint8_t function, uint8_t offset) {
|
||||
uint32_t address = (uint32_t)((1u << 31) | (bus << 16) | (device << 11) | (function << 8) | (offset & 0xFC));
|
||||
outl(PCI_CONFIG_ADDRESS, address);
|
||||
return inl(PCI_CONFIG_DATA);
|
||||
}
|
||||
|
||||
void pci_write_config(uint8_t bus, uint8_t device, uint8_t function, uint8_t offset, uint32_t value) {
|
||||
uint32_t address = (uint32_t)((1u << 31) | (bus << 16) | (device << 11) | (function << 8) | (offset & 0xFC));
|
||||
outl(PCI_CONFIG_ADDRESS, address);
|
||||
outl(PCI_CONFIG_DATA, value);
|
||||
}
|
||||
|
||||
int pci_device_exists(uint8_t bus, uint8_t device, uint8_t function) {
|
||||
uint16_t vendor_id = pci_get_vendor_id(bus, device, function);
|
||||
return vendor_id != 0xFFFF;
|
||||
}
|
||||
|
||||
uint16_t pci_get_vendor_id(uint8_t bus, uint8_t device, uint8_t function) {
|
||||
uint32_t config = pci_read_config(bus, device, function, 0x00);
|
||||
return (uint16_t)(config & 0xFFFF);
|
||||
}
|
||||
|
||||
uint16_t pci_get_device_id(uint8_t bus, uint8_t device, uint8_t function) {
|
||||
uint32_t config = pci_read_config(bus, device, function, 0x00);
|
||||
return (uint16_t)((config >> 16) & 0xFFFF);
|
||||
}
|
||||
|
||||
uint8_t pci_get_class_code(uint8_t bus, uint8_t device, uint8_t function) {
|
||||
uint32_t config = pci_read_config(bus, device, function, 0x08);
|
||||
return (uint8_t)((config >> 24) & 0xFF);
|
||||
}
|
||||
|
||||
uint8_t pci_get_subclass(uint8_t bus, uint8_t device, uint8_t function) {
|
||||
uint32_t config = pci_read_config(bus, device, function, 0x08);
|
||||
return (uint8_t)((config >> 16) & 0xFF);
|
||||
}
|
||||
|
||||
uint8_t pci_get_prog_if(uint8_t bus, uint8_t device, uint8_t function) {
|
||||
uint32_t config = pci_read_config(bus, device, function, 0x08);
|
||||
return (uint8_t)((config >> 8) & 0xFF);
|
||||
}
|
||||
|
||||
int pci_enumerate_devices(pci_device_t* devices, int max_devices) {
|
||||
int count = 0;
|
||||
for (uint8_t bus = 0; bus < 256 && count < max_devices; bus++) {
|
||||
for (uint8_t dev = 0; dev < 32 && count < max_devices; dev++) {
|
||||
if (pci_device_exists(bus, dev, 0)) {
|
||||
uint32_t config_val = pci_read_config(bus, dev, 0, 0x0C);
|
||||
uint8_t header_type = (uint8_t)((config_val >> 16) & 0xFF);
|
||||
uint8_t num_functions = (header_type & 0x80) ? 8 : 1;
|
||||
for (uint8_t fn = 0; fn < num_functions && count < max_devices; fn++) {
|
||||
if (pci_device_exists(bus, dev, fn)) {
|
||||
devices[count].bus = bus;
|
||||
devices[count].device = dev;
|
||||
devices[count].function = fn;
|
||||
devices[count].vendor_id = pci_get_vendor_id(bus, dev, fn);
|
||||
devices[count].device_id = pci_get_device_id(bus, dev, fn);
|
||||
devices[count].class_code = pci_get_class_code(bus, dev, fn);
|
||||
devices[count].subclass = pci_get_subclass(bus, dev, fn);
|
||||
devices[count].prog_if = pci_get_prog_if(bus, dev, fn);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
int pci_find_device(uint16_t vendor_id, uint16_t device_id, pci_device_t* device) {
|
||||
pci_device_t devices[32];
|
||||
int count = pci_enumerate_devices(devices, 32);
|
||||
for (int i = 0; i < count; i++) {
|
||||
if (devices[i].vendor_id == vendor_id && devices[i].device_id == device_id) {
|
||||
*device = devices[i];
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pci_find_device_by_class(uint8_t class_code, uint8_t subclass, pci_device_t* device) {
|
||||
pci_device_t devices[32];
|
||||
int count = pci_enumerate_devices(devices, 32);
|
||||
for (int i = 0; i < count; i++) {
|
||||
if (devices[i].class_code == class_code && devices[i].subclass == subclass) {
|
||||
*device = devices[i];
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
35
src/kernel/pci.h
Normal file
35
src/kernel/pci.h
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
#ifndef PCI_H
|
||||
#define PCI_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define PCI_CONFIG_ADDRESS 0xCF8
|
||||
#define PCI_CONFIG_DATA 0xCFC
|
||||
|
||||
typedef struct {
|
||||
uint16_t vendor_id;
|
||||
uint16_t device_id;
|
||||
uint8_t bus;
|
||||
uint8_t device;
|
||||
uint8_t function;
|
||||
uint8_t class_code;
|
||||
uint8_t subclass;
|
||||
uint8_t prog_if;
|
||||
} pci_device_t;
|
||||
|
||||
#define PCI_CLASS_NETWORK_CONTROLLER 0x02
|
||||
#define PCI_CLASS_ETHERNET_CONTROLLER 0x00
|
||||
|
||||
uint32_t pci_read_config(uint8_t bus, uint8_t device, uint8_t function, uint8_t offset);
|
||||
void pci_write_config(uint8_t bus, uint8_t device, uint8_t function, uint8_t offset, uint32_t value);
|
||||
int pci_device_exists(uint8_t bus, uint8_t device, uint8_t function);
|
||||
uint16_t pci_get_vendor_id(uint8_t bus, uint8_t device, uint8_t function);
|
||||
uint16_t pci_get_device_id(uint8_t bus, uint8_t device, uint8_t function);
|
||||
uint8_t pci_get_class_code(uint8_t bus, uint8_t device, uint8_t function);
|
||||
uint8_t pci_get_subclass(uint8_t bus, uint8_t device, uint8_t function);
|
||||
uint8_t pci_get_prog_if(uint8_t bus, uint8_t device, uint8_t function);
|
||||
int pci_enumerate_devices(pci_device_t* devices, int max_devices);
|
||||
int pci_find_device(uint16_t vendor_id, uint16_t device_id, pci_device_t* device);
|
||||
int pci_find_device_by_class(uint8_t class_code, uint8_t subclass, pci_device_t* device);
|
||||
|
||||
#endif
|
||||
33
src/kernel/platform.c
Normal file
33
src/kernel/platform.c
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
#include <stdint.h>
|
||||
#include "limine.h"
|
||||
#include <stddef.h>
|
||||
static volatile struct limine_hhdm_request hhdm_request __attribute__((used, section(".requests"))) = {
|
||||
.id = LIMINE_HHDM_REQUEST,
|
||||
.revision = 0,
|
||||
.response = NULL
|
||||
};
|
||||
static volatile struct limine_kernel_address_request kernel_addr_request __attribute__((used, section(".requests"))) = {
|
||||
.id = LIMINE_KERNEL_ADDRESS_REQUEST,
|
||||
.revision = 0,
|
||||
.response = NULL
|
||||
};
|
||||
static uint64_t hhdm_offset = 0;
|
||||
static uint64_t kernel_phys_base = 0;
|
||||
static uint64_t kernel_virt_base = 0;
|
||||
void platform_init(void) {
|
||||
if (hhdm_request.response) { hhdm_offset = hhdm_request.response->offset; }
|
||||
if (kernel_addr_request.response) {
|
||||
kernel_phys_base = kernel_addr_request.response->physical_base;
|
||||
kernel_virt_base = kernel_addr_request.response->virtual_base;
|
||||
}
|
||||
}
|
||||
uint64_t p2v(uint64_t phys) { return phys + hhdm_offset; }
|
||||
uint64_t v2p(uint64_t virt) {
|
||||
if (kernel_virt_base && virt >= kernel_virt_base) {
|
||||
return virt - kernel_virt_base + kernel_phys_base;
|
||||
}
|
||||
if (hhdm_offset && virt >= hhdm_offset) {
|
||||
return virt - hhdm_offset;
|
||||
}
|
||||
return virt;
|
||||
}
|
||||
10
src/kernel/platform.h
Normal file
10
src/kernel/platform.h
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
#ifndef PLATFORM_H
|
||||
#define PLATFORM_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
void platform_init(void);
|
||||
uint64_t p2v(uint64_t phys);
|
||||
uint64_t v2p(uint64_t virt);
|
||||
|
||||
#endif
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
#include "ps2.h"
|
||||
#include "io.h"
|
||||
#include "wm.h"
|
||||
#include "network.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
extern void serial_print(const char *s);
|
||||
|
|
@ -9,6 +10,7 @@ extern void serial_print_hex(uint64_t n);
|
|||
// --- Timer Handler ---
|
||||
void timer_handler(void) {
|
||||
wm_timer_tick();
|
||||
network_process_frames();
|
||||
outb(0x20, 0x20); // EOI to Master PIC
|
||||
}
|
||||
|
||||
|
|
@ -164,4 +166,4 @@ void mouse_handler(void) {
|
|||
|
||||
void ps2_init(void) {
|
||||
mouse_init();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue