Implement ARP subsystem and arp app (AI)
- Created src/arp.h: ARP packet struct, cache entry struct, operation codes, lookup/request/resolve/receive API, sysfs registration - Created src/arp.c: ARP cache with 32 entries, request/reply handling, ARP response to incoming requests for our IP, sysfs /sys/arp/table with formatted IP/MAC/interface/state columns - Created apps/arp/arp.c: reads and displays /sys/arp/table - Kernel calls arp_init() at boot, registered sysfs 'arp' namespace - Tested: clean boot, ARP initialized, arp app in CPIO
This commit is contained in:
@@ -72,7 +72,7 @@ Once a task is completed, it should be checked off.
|
||||
- [x] Create a network driver for the 3C509B NIC. It should only support RJ45 and 10base-T.
|
||||
- [x] Create an ethernet subsytsem. Each ethernet device should be shown as a character device with the name `ethN`.
|
||||
- [x] Create a IPv4 stack. Create the `ip` app that shows curernt IPv4 configuration. It should read this information from `/sys`
|
||||
- [ ] Create a ARP subsystem. Create the `arp` command that shows current ARP tables. Again, this info should be found in `/sys`
|
||||
- [x] Create a ARP subsystem. Create the `arp` command that shows current ARP tables. Again, this info should be found in `/sys`
|
||||
- [ ] Create a DHCP subsystem. Create the `dhcp` command to show current DHCP status information.
|
||||
- [ ] Create a UDP and TCP stack.
|
||||
- [ ] Implement a simple version of `ftp` and `wget`.
|
||||
|
||||
30
apps/arp/arp.c
Normal file
30
apps/arp/arp.c
Normal file
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* @file arp.c
|
||||
* @brief Display the ARP table.
|
||||
*
|
||||
* Reads the ARP cache from /sys/arp/table and displays it.
|
||||
*
|
||||
* Usage:
|
||||
* arp - Show the ARP table
|
||||
*/
|
||||
|
||||
#include "syscalls.h"
|
||||
|
||||
int main(void) {
|
||||
/* Open the ARP table sysfs file */
|
||||
int32_t fd = open("/sys/arp/table", 0);
|
||||
if (fd < 0) {
|
||||
puts("arp: failed to open /sys/arp/table\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Read and display contents */
|
||||
char buf[512];
|
||||
int32_t n;
|
||||
while ((n = read(fd, buf, sizeof(buf))) > 0) {
|
||||
write(1, buf, (uint32_t)n);
|
||||
}
|
||||
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
14
build.log
14
build.log
@@ -2,6 +2,8 @@
|
||||
-- Generating done (0.2s)
|
||||
-- Build files have been written to: /workspaces/claude-os/build
|
||||
[ 2%] Building user-mode applications
|
||||
Building app: arp
|
||||
Built: /workspaces/claude-os/build/apps_bin/arp (214 bytes)
|
||||
Building app: cat
|
||||
Built: /workspaces/claude-os/build/apps_bin/cat (310 bytes)
|
||||
Building app: diskpart
|
||||
@@ -35,10 +37,10 @@ Building app: sh
|
||||
Built: /workspaces/claude-os/build/apps_bin/sh (3428 bytes)
|
||||
[ 2%] Built target apps
|
||||
[ 5%] Generating CPIO initial ramdisk
|
||||
Generated initrd: 24100 bytes
|
||||
Generated initrd: 24432 bytes
|
||||
[ 5%] Built target initrd
|
||||
[ 8%] Building C object src/CMakeFiles/kernel.dir/kernel.c.o
|
||||
[ 11%] Building C object src/CMakeFiles/kernel.dir/ipv4.c.o
|
||||
[ 10%] Building C object src/CMakeFiles/kernel.dir/arp.c.o
|
||||
[ 13%] Linking C executable ../bin/kernel
|
||||
[ 97%] Built target kernel
|
||||
[100%] Generating bootable ISO image
|
||||
@@ -48,14 +50,14 @@ Drive current: -outdev 'stdio:/workspaces/claude-os/release/claude-os.iso'
|
||||
Media current: stdio file, overwriteable
|
||||
Media status : is blank
|
||||
Media summary: 0 sessions, 0 data blocks, 0 data, 126g free
|
||||
Added to ISO image: directory '/'='/tmp/grub.JjepBC'
|
||||
Added to ISO image: directory '/'='/tmp/grub.OdkOfh'
|
||||
xorriso : UPDATE : 581 files added in 1 seconds
|
||||
Added to ISO image: directory '/'='/workspaces/claude-os/build/isodir'
|
||||
xorriso : UPDATE : 586 files added in 1 seconds
|
||||
xorriso : NOTE : Copying to System Area: 512 bytes from file '/usr/lib/grub/i386-pc/boot_hybrid.img'
|
||||
xorriso : UPDATE : 0.27% done
|
||||
ISO image produced: 5974 sectors
|
||||
Written to medium : 5974 sectors at LBA 0
|
||||
xorriso : UPDATE : 63.88% done
|
||||
ISO image produced: 5986 sectors
|
||||
Written to medium : 5986 sectors at LBA 0
|
||||
Writing to 'stdio:/workspaces/claude-os/release/claude-os.iso' completed successfully.
|
||||
|
||||
[100%] Built target iso
|
||||
|
||||
@@ -29,6 +29,7 @@ add_executable(kernel
|
||||
e3c509.c
|
||||
ethernet.c
|
||||
ipv4.c
|
||||
arp.c
|
||||
env.c
|
||||
keyboard.c
|
||||
interrupts.S
|
||||
|
||||
382
src/arp.c
Normal file
382
src/arp.c
Normal file
@@ -0,0 +1,382 @@
|
||||
/**
|
||||
* @file arp.c
|
||||
* @brief Address Resolution Protocol (ARP) implementation.
|
||||
*
|
||||
* Maintains an ARP cache mapping IPv4 addresses to Ethernet MAC
|
||||
* addresses. Sends ARP requests and processes ARP replies.
|
||||
* Also responds to incoming ARP requests for our own IP addresses.
|
||||
*
|
||||
* The ARP table is exposed via sysfs at /sys/arp.
|
||||
*/
|
||||
|
||||
#include "arp.h"
|
||||
#include "ethernet.h"
|
||||
#include "ipv4.h"
|
||||
#include "sysfs.h"
|
||||
#include <string.h>
|
||||
|
||||
/* Debug print helpers */
|
||||
extern void offset_print(const char *str);
|
||||
extern void print_hex(uint32_t val);
|
||||
|
||||
/* ================================================================
|
||||
* Global state
|
||||
* ================================================================ */
|
||||
|
||||
/** ARP cache table. */
|
||||
static arp_entry_t arp_table[ARP_TABLE_SIZE];
|
||||
|
||||
/** Number of active entries. */
|
||||
static uint32_t arp_count = 0;
|
||||
|
||||
/* ================================================================
|
||||
* ARP cache management
|
||||
* ================================================================ */
|
||||
|
||||
/**
|
||||
* Find an ARP entry by IP address.
|
||||
* @return Pointer to entry, or NULL if not found.
|
||||
*/
|
||||
static arp_entry_t *arp_find(uint32_t ip) {
|
||||
for (uint32_t i = 0; i < ARP_TABLE_SIZE; i++) {
|
||||
if (arp_table[i].state != ARP_STATE_FREE &&
|
||||
arp_table[i].ip_addr == ip) {
|
||||
return &arp_table[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocate a new ARP entry.
|
||||
* Reuses a free slot, or evicts the oldest entry.
|
||||
*/
|
||||
static arp_entry_t *arp_alloc(void) {
|
||||
/* Look for a free slot */
|
||||
for (uint32_t i = 0; i < ARP_TABLE_SIZE; i++) {
|
||||
if (arp_table[i].state == ARP_STATE_FREE) {
|
||||
return &arp_table[i];
|
||||
}
|
||||
}
|
||||
|
||||
/* Evict the oldest entry (lowest timestamp) */
|
||||
arp_entry_t *oldest = &arp_table[0];
|
||||
for (uint32_t i = 1; i < ARP_TABLE_SIZE; i++) {
|
||||
if (arp_table[i].timestamp < oldest->timestamp) {
|
||||
oldest = &arp_table[i];
|
||||
}
|
||||
}
|
||||
return oldest;
|
||||
}
|
||||
|
||||
/* ================================================================
|
||||
* ARP send
|
||||
* ================================================================ */
|
||||
|
||||
/**
|
||||
* Send an ARP packet.
|
||||
*/
|
||||
static int arp_send_packet(uint32_t iface_idx, uint16_t operation,
|
||||
const uint8_t *target_mac, uint32_t target_ip) {
|
||||
eth_iface_t *iface = ethernet_get_iface(iface_idx);
|
||||
if (!iface || !iface->active) return -1;
|
||||
|
||||
arp_packet_t pkt;
|
||||
pkt.hw_type = htons(ARP_HW_ETHER);
|
||||
pkt.proto_type = htons(ETHERTYPE_IPV4);
|
||||
pkt.hw_len = 6;
|
||||
pkt.proto_len = 4;
|
||||
pkt.operation = htons(operation);
|
||||
|
||||
/* Sender: our MAC and IP */
|
||||
memcpy(pkt.sender_mac, iface->mac, 6);
|
||||
pkt.sender_ip = htonl(iface->ip_addr);
|
||||
|
||||
/* Target */
|
||||
memcpy(pkt.target_mac, target_mac, 6);
|
||||
pkt.target_ip = htonl(target_ip);
|
||||
|
||||
/* For ARP requests, broadcast; for replies, send directly */
|
||||
const uint8_t *dst_mac;
|
||||
if (operation == ARP_OP_REQUEST) {
|
||||
static const uint8_t bcast[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
|
||||
dst_mac = bcast;
|
||||
} else {
|
||||
dst_mac = target_mac;
|
||||
}
|
||||
|
||||
return ethernet_send(iface, dst_mac, ETHERTYPE_ARP,
|
||||
&pkt, ARP_PACKET_SIZE);
|
||||
}
|
||||
|
||||
/* ================================================================
|
||||
* Public API
|
||||
* ================================================================ */
|
||||
|
||||
int arp_lookup(uint32_t ip, uint8_t *mac) {
|
||||
arp_entry_t *entry = arp_find(ip);
|
||||
if (entry && entry->state == ARP_STATE_RESOLVED) {
|
||||
memcpy(mac, entry->mac, 6);
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int arp_request(uint32_t iface_idx, uint32_t target_ip) {
|
||||
static const uint8_t zero_mac[6] = {0, 0, 0, 0, 0, 0};
|
||||
|
||||
/* Create an incomplete entry if we don't have one */
|
||||
arp_entry_t *entry = arp_find(target_ip);
|
||||
if (!entry) {
|
||||
entry = arp_alloc();
|
||||
memset(entry, 0, sizeof(arp_entry_t));
|
||||
entry->ip_addr = target_ip;
|
||||
entry->state = ARP_STATE_INCOMPLETE;
|
||||
entry->iface_idx = (uint8_t)iface_idx;
|
||||
entry->timestamp = 0; /* will be updated on reply */
|
||||
arp_count++;
|
||||
}
|
||||
|
||||
return arp_send_packet(iface_idx, ARP_OP_REQUEST, zero_mac, target_ip);
|
||||
}
|
||||
|
||||
int arp_resolve(uint32_t iface_idx, uint32_t ip, uint8_t *mac) {
|
||||
/* Broadcast address — no ARP needed */
|
||||
if (ip == 0xFFFFFFFF) {
|
||||
memset(mac, 0xFF, 6);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check cache */
|
||||
if (arp_lookup(ip, mac) == 0) return 0;
|
||||
|
||||
/* Send ARP request */
|
||||
arp_request(iface_idx, ip);
|
||||
return -1;
|
||||
}
|
||||
|
||||
void arp_receive(const void *data, uint32_t len, uint32_t iface_idx) {
|
||||
if (len < ARP_PACKET_SIZE) return;
|
||||
|
||||
const arp_packet_t *pkt = (const arp_packet_t *)data;
|
||||
|
||||
/* Validate: must be Ethernet/IPv4 */
|
||||
if (ntohs(pkt->hw_type) != ARP_HW_ETHER) return;
|
||||
if (ntohs(pkt->proto_type) != ETHERTYPE_IPV4) return;
|
||||
if (pkt->hw_len != 6 || pkt->proto_len != 4) return;
|
||||
|
||||
uint32_t sender_ip = ntohl(pkt->sender_ip);
|
||||
uint32_t target_ip = ntohl(pkt->target_ip);
|
||||
uint16_t operation = ntohs(pkt->operation);
|
||||
|
||||
/* Update or create ARP cache entry for sender */
|
||||
arp_entry_t *entry = arp_find(sender_ip);
|
||||
if (entry) {
|
||||
memcpy(entry->mac, pkt->sender_mac, 6);
|
||||
entry->state = ARP_STATE_RESOLVED;
|
||||
entry->iface_idx = (uint8_t)iface_idx;
|
||||
} else {
|
||||
entry = arp_alloc();
|
||||
entry->ip_addr = sender_ip;
|
||||
memcpy(entry->mac, pkt->sender_mac, 6);
|
||||
entry->state = ARP_STATE_RESOLVED;
|
||||
entry->iface_idx = (uint8_t)iface_idx;
|
||||
entry->timestamp = 0;
|
||||
arp_count++;
|
||||
}
|
||||
|
||||
/* Check if this ARP is targeted at us */
|
||||
eth_iface_t *iface = ethernet_get_iface(iface_idx);
|
||||
if (!iface || iface->ip_addr == 0) return;
|
||||
|
||||
if (target_ip == iface->ip_addr && operation == ARP_OP_REQUEST) {
|
||||
/* Send ARP reply */
|
||||
arp_send_packet(iface_idx, ARP_OP_REPLY,
|
||||
pkt->sender_mac, sender_ip);
|
||||
}
|
||||
}
|
||||
|
||||
int arp_add_static(uint32_t ip, const uint8_t *mac, uint32_t iface_idx) {
|
||||
arp_entry_t *entry = arp_find(ip);
|
||||
if (!entry) {
|
||||
entry = arp_alloc();
|
||||
if (!entry) return -1;
|
||||
arp_count++;
|
||||
}
|
||||
|
||||
entry->ip_addr = ip;
|
||||
memcpy(entry->mac, mac, 6);
|
||||
entry->state = ARP_STATE_RESOLVED;
|
||||
entry->iface_idx = (uint8_t)iface_idx;
|
||||
entry->timestamp = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
const arp_entry_t *arp_get_entry(uint32_t index) {
|
||||
uint32_t count = 0;
|
||||
for (uint32_t i = 0; i < ARP_TABLE_SIZE; i++) {
|
||||
if (arp_table[i].state == ARP_STATE_FREE) continue;
|
||||
if (count == index) return &arp_table[i];
|
||||
count++;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uint32_t arp_get_count(void) {
|
||||
return arp_count;
|
||||
}
|
||||
|
||||
/* ================================================================
|
||||
* Sysfs interface: /sys/arp
|
||||
*
|
||||
* Layout:
|
||||
* /sys/arp/
|
||||
* table - ARP table in human-readable format
|
||||
* ================================================================ */
|
||||
|
||||
/**
|
||||
* Format a MAC address as "XX:XX:XX:XX:XX:XX".
|
||||
*/
|
||||
static void mac_to_str(const uint8_t *mac, char *buf) {
|
||||
static const char hex[] = "0123456789ABCDEF";
|
||||
int pos = 0;
|
||||
for (int i = 0; i < 6; i++) {
|
||||
if (i > 0) buf[pos++] = ':';
|
||||
buf[pos++] = hex[(mac[i] >> 4) & 0xF];
|
||||
buf[pos++] = hex[mac[i] & 0xF];
|
||||
}
|
||||
buf[pos] = '\0';
|
||||
}
|
||||
|
||||
/**
|
||||
* Format an IPv4 address (host byte order) as dotted decimal.
|
||||
*/
|
||||
static int ip_to_str(uint32_t ip, char *buf, uint32_t size) {
|
||||
int pos = 0;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (i > 0 && pos < (int)size - 1) buf[pos++] = '.';
|
||||
uint8_t octet = (uint8_t)((ip >> (24 - i * 8)) & 0xFF);
|
||||
if (octet >= 100 && pos < (int)size - 3) {
|
||||
buf[pos++] = (char)('0' + octet / 100);
|
||||
buf[pos++] = (char)('0' + (octet % 100) / 10);
|
||||
buf[pos++] = (char)('0' + octet % 10);
|
||||
} else if (octet >= 10 && pos < (int)size - 2) {
|
||||
buf[pos++] = (char)('0' + octet / 10);
|
||||
buf[pos++] = (char)('0' + octet % 10);
|
||||
} else if (pos < (int)size - 1) {
|
||||
buf[pos++] = (char)('0' + octet);
|
||||
}
|
||||
}
|
||||
if (pos < (int)size) buf[pos] = '\0';
|
||||
return pos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Append a string to buf at position *pos.
|
||||
*/
|
||||
static void append_str(char *buf, uint32_t size, int *pos, const char *s) {
|
||||
while (*s && *pos < (int)size - 1) buf[(*pos)++] = *s++;
|
||||
}
|
||||
|
||||
static int arp_sysfs_list(void *ctx, const char *path, uint32_t idx,
|
||||
sysfs_entry_t *out) {
|
||||
(void)ctx;
|
||||
|
||||
if (path[0] == '\0') {
|
||||
if (idx == 0) {
|
||||
memset(out, 0, sizeof(sysfs_entry_t));
|
||||
strncpy(out->name, "table", SYSFS_MAX_NAME - 1);
|
||||
out->is_dir = 0;
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int arp_sysfs_read(void *ctx, const char *path, char *buf,
|
||||
uint32_t buf_size) {
|
||||
(void)ctx;
|
||||
|
||||
if (strcmp(path, "table") != 0) return -1;
|
||||
|
||||
int pos = 0;
|
||||
|
||||
/* Header */
|
||||
append_str(buf, buf_size, &pos, "IP Address MAC Address Iface State\n");
|
||||
|
||||
for (uint32_t i = 0; i < ARP_TABLE_SIZE; i++) {
|
||||
if (arp_table[i].state == ARP_STATE_FREE) continue;
|
||||
|
||||
/* IP address */
|
||||
char ip_buf[16];
|
||||
ip_to_str(arp_table[i].ip_addr, ip_buf, sizeof(ip_buf));
|
||||
append_str(buf, buf_size, &pos, ip_buf);
|
||||
|
||||
/* Pad to column 17 */
|
||||
int ip_len = (int)strlen(ip_buf);
|
||||
for (int p = ip_len; p < 17; p++) {
|
||||
if (pos < (int)buf_size - 1) buf[pos++] = ' ';
|
||||
}
|
||||
|
||||
/* MAC */
|
||||
char mac_buf[18];
|
||||
mac_to_str(arp_table[i].mac, mac_buf);
|
||||
append_str(buf, buf_size, &pos, mac_buf);
|
||||
if (pos < (int)buf_size - 1) buf[pos++] = ' ';
|
||||
if (pos < (int)buf_size - 1) buf[pos++] = ' ';
|
||||
|
||||
/* Interface */
|
||||
eth_iface_t *iface = ethernet_get_iface(arp_table[i].iface_idx);
|
||||
if (iface) {
|
||||
append_str(buf, buf_size, &pos, iface->name);
|
||||
} else {
|
||||
append_str(buf, buf_size, &pos, "?");
|
||||
}
|
||||
|
||||
/* Pad and state */
|
||||
int name_len = iface ? (int)strlen(iface->name) : 1;
|
||||
for (int p = name_len; p < 7; p++) {
|
||||
if (pos < (int)buf_size - 1) buf[pos++] = ' ';
|
||||
}
|
||||
|
||||
if (arp_table[i].state == ARP_STATE_RESOLVED) {
|
||||
append_str(buf, buf_size, &pos, "resolved");
|
||||
} else {
|
||||
append_str(buf, buf_size, &pos, "incomplete");
|
||||
}
|
||||
|
||||
if (pos < (int)buf_size - 1) buf[pos++] = '\n';
|
||||
}
|
||||
|
||||
buf[pos] = '\0';
|
||||
return pos;
|
||||
}
|
||||
|
||||
static int arp_sysfs_write(void *ctx, const char *path, const char *buf,
|
||||
uint32_t size) {
|
||||
(void)ctx;
|
||||
(void)path;
|
||||
(void)buf;
|
||||
(void)size;
|
||||
return -1; /* Read-only for now */
|
||||
}
|
||||
|
||||
static sysfs_ops_t arp_sysfs_ops = {
|
||||
.list = arp_sysfs_list,
|
||||
.read = arp_sysfs_read,
|
||||
.write = arp_sysfs_write,
|
||||
};
|
||||
|
||||
/* ================================================================
|
||||
* Initialization
|
||||
* ================================================================ */
|
||||
|
||||
void arp_init(void) {
|
||||
memset(arp_table, 0, sizeof(arp_table));
|
||||
arp_count = 0;
|
||||
|
||||
sysfs_register("arp", &arp_sysfs_ops, NULL);
|
||||
|
||||
offset_print(" ARP: initialized\n");
|
||||
}
|
||||
145
src/arp.h
Normal file
145
src/arp.h
Normal file
@@ -0,0 +1,145 @@
|
||||
/**
|
||||
* @file arp.h
|
||||
* @brief Address Resolution Protocol (ARP) subsystem.
|
||||
*
|
||||
* Implements ARP (RFC 826) for mapping IPv4 addresses to Ethernet
|
||||
* MAC addresses. Maintains an ARP cache and handles ARP requests
|
||||
* and replies.
|
||||
*
|
||||
* The ARP table is exposed via sysfs at /sys/arp for userspace tools.
|
||||
*/
|
||||
|
||||
#ifndef ARP_H
|
||||
#define ARP_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/** Maximum number of ARP cache entries. */
|
||||
#define ARP_TABLE_SIZE 32
|
||||
|
||||
/** ARP hardware type: Ethernet */
|
||||
#define ARP_HW_ETHER 1
|
||||
|
||||
/** ARP operation codes */
|
||||
#define ARP_OP_REQUEST 1
|
||||
#define ARP_OP_REPLY 2
|
||||
|
||||
/** ARP cache entry states */
|
||||
#define ARP_STATE_FREE 0 /**< Unused slot. */
|
||||
#define ARP_STATE_INCOMPLETE 1 /**< Request sent, awaiting reply. */
|
||||
#define ARP_STATE_RESOLVED 2 /**< MAC address known. */
|
||||
|
||||
/* ================================================================
|
||||
* ARP packet (28 bytes for IPv4-over-Ethernet)
|
||||
* ================================================================ */
|
||||
|
||||
/**
|
||||
* ARP packet structure for IPv4 over Ethernet.
|
||||
* All multi-byte fields are in network byte order.
|
||||
*/
|
||||
typedef struct __attribute__((packed)) arp_packet {
|
||||
uint16_t hw_type; /**< Hardware type (1 = Ethernet). */
|
||||
uint16_t proto_type; /**< Protocol type (0x0800 = IPv4). */
|
||||
uint8_t hw_len; /**< Hardware address length (6). */
|
||||
uint8_t proto_len; /**< Protocol address length (4). */
|
||||
uint16_t operation; /**< Operation (1=request, 2=reply). */
|
||||
uint8_t sender_mac[6]; /**< Sender hardware address. */
|
||||
uint32_t sender_ip; /**< Sender protocol address. */
|
||||
uint8_t target_mac[6]; /**< Target hardware address. */
|
||||
uint32_t target_ip; /**< Target protocol address. */
|
||||
} arp_packet_t;
|
||||
|
||||
/** ARP packet size. */
|
||||
#define ARP_PACKET_SIZE 28
|
||||
|
||||
/* ================================================================
|
||||
* ARP cache entry
|
||||
* ================================================================ */
|
||||
|
||||
/**
|
||||
* ARP cache entry.
|
||||
*/
|
||||
typedef struct arp_entry {
|
||||
uint32_t ip_addr; /**< IPv4 address (host byte order). */
|
||||
uint8_t mac[6]; /**< Resolved MAC address. */
|
||||
uint8_t state; /**< ARP_STATE_*. */
|
||||
uint8_t iface_idx; /**< Ethernet interface index. */
|
||||
uint32_t timestamp; /**< Time when entry was created (tick count). */
|
||||
} arp_entry_t;
|
||||
|
||||
/* ================================================================
|
||||
* Public API
|
||||
* ================================================================ */
|
||||
|
||||
/**
|
||||
* Initialize the ARP subsystem.
|
||||
* Registers sysfs namespace "arp".
|
||||
*/
|
||||
void arp_init(void);
|
||||
|
||||
/**
|
||||
* Look up an IP address in the ARP cache.
|
||||
*
|
||||
* @param ip IPv4 address (host byte order).
|
||||
* @param mac Output: 6-byte MAC address if found.
|
||||
* @return 0 if found and resolved, -1 if not in cache or incomplete.
|
||||
*/
|
||||
int arp_lookup(uint32_t ip, uint8_t *mac);
|
||||
|
||||
/**
|
||||
* Send an ARP request for the given IP address.
|
||||
*
|
||||
* @param iface_idx Ethernet interface to send on.
|
||||
* @param target_ip IP address to resolve (host byte order).
|
||||
* @return 0 on success, -1 on failure.
|
||||
*/
|
||||
int arp_request(uint32_t iface_idx, uint32_t target_ip);
|
||||
|
||||
/**
|
||||
* Resolve an IP address to a MAC address.
|
||||
*
|
||||
* Checks the ARP cache first. If not found, sends an ARP request
|
||||
* and returns -1 (caller should retry later).
|
||||
*
|
||||
* @param iface_idx Ethernet interface index.
|
||||
* @param ip IPv4 address (host byte order).
|
||||
* @param mac Output: 6-byte MAC address.
|
||||
* @return 0 if resolved, -1 if pending.
|
||||
*/
|
||||
int arp_resolve(uint32_t iface_idx, uint32_t ip, uint8_t *mac);
|
||||
|
||||
/**
|
||||
* Process an incoming ARP packet.
|
||||
*
|
||||
* Called by the Ethernet subsystem when an ARP frame is received.
|
||||
*
|
||||
* @param data Raw ARP packet.
|
||||
* @param len Packet length.
|
||||
* @param iface_idx Interface the packet arrived on.
|
||||
*/
|
||||
void arp_receive(const void *data, uint32_t len, uint32_t iface_idx);
|
||||
|
||||
/**
|
||||
* Add a static ARP entry.
|
||||
*
|
||||
* @param ip IPv4 address (host byte order).
|
||||
* @param mac 6-byte MAC address.
|
||||
* @param iface_idx Ethernet interface index.
|
||||
* @return 0 on success, -1 if table full.
|
||||
*/
|
||||
int arp_add_static(uint32_t ip, const uint8_t *mac, uint32_t iface_idx);
|
||||
|
||||
/**
|
||||
* Get an ARP table entry by index (for enumeration).
|
||||
*
|
||||
* @param index 0-based index.
|
||||
* @return Pointer to entry, or NULL if out of range.
|
||||
*/
|
||||
const arp_entry_t *arp_get_entry(uint32_t index);
|
||||
|
||||
/**
|
||||
* Get the number of active ARP entries.
|
||||
*/
|
||||
uint32_t arp_get_count(void);
|
||||
|
||||
#endif /* ARP_H */
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "keyboard.h"
|
||||
#include "ethernet.h"
|
||||
#include "ipv4.h"
|
||||
#include "arp.h"
|
||||
#include "framebuffer.h"
|
||||
|
||||
/* Global framebuffer info, parsed from multiboot2 tags. */
|
||||
@@ -423,6 +424,9 @@ void kernel_main(uint32_t magic, uint32_t addr) {
|
||||
ipv4_init();
|
||||
offset_print("IPv4 stack initialized\n");
|
||||
|
||||
arp_init();
|
||||
offset_print("ARP subsystem initialized\n");
|
||||
|
||||
init_drivers();
|
||||
EARLY_PRINT("DRV ");
|
||||
offset_print("Drivers initialized\n");
|
||||
|
||||
Reference in New Issue
Block a user