Implement IPv4 stack and ip app (AI)
- Created src/ipv4.h: IPv4 header struct, protocol numbers, checksum, address conversion (ipv4_aton/ntoa), send/receive/routing API, protocol handler registration - Created src/ipv4.c: packet construction with header checksum, simple routing (direct subnet + gateway), incoming packet validation and dispatch to registered protocol handlers - Created apps/ip/ip.c: displays network interface config from /sys/net (MAC, link, IP, netmask, gateway); supports 'ip set' to configure interface via sysfs writes - Added ipv4.c to kernel build, kernel calls ipv4_init() at boot - Tested: clean boot, IPv4 initialized, ip app in CPIO
This commit is contained in:
202
apps/ip/ip.c
Normal file
202
apps/ip/ip.c
Normal file
@@ -0,0 +1,202 @@
|
||||
/**
|
||||
* @file ip.c
|
||||
* @brief Display and configure IPv4 network configuration.
|
||||
*
|
||||
* Reads network interface information from /sys/net and displays
|
||||
* the current IPv4 configuration for all interfaces.
|
||||
*
|
||||
* Usage:
|
||||
* ip - Show all interfaces
|
||||
* ip set <iface> <ip> <netmask> <gateway> - Configure an interface
|
||||
*
|
||||
* Examples:
|
||||
* ip
|
||||
* ip set eth1 192.168.1.100 255.255.255.0 192.168.1.1
|
||||
*/
|
||||
|
||||
#include "syscalls.h"
|
||||
|
||||
/**
|
||||
* Read the contents of a sysfs file into buf.
|
||||
* Returns number of bytes read, or -1 on failure.
|
||||
*/
|
||||
static int32_t read_sysfs(const char *path, char *buf, uint32_t size) {
|
||||
int32_t fd = open(path, 0);
|
||||
if (fd < 0) return -1;
|
||||
|
||||
int32_t n = read(fd, buf, size - 1);
|
||||
close(fd);
|
||||
|
||||
if (n > 0) {
|
||||
buf[n] = '\0';
|
||||
/* Strip trailing newline */
|
||||
for (int32_t i = n - 1; i >= 0; i--) {
|
||||
if (buf[i] == '\n' || buf[i] == '\r') buf[i] = '\0';
|
||||
else break;
|
||||
}
|
||||
} else {
|
||||
buf[0] = '\0';
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a sysfs path: /sys/net/<iface>/<file>
|
||||
*/
|
||||
static void build_path(char *out, uint32_t out_size,
|
||||
const char *iface, const char *file) {
|
||||
/* Manual string concatenation */
|
||||
uint32_t pos = 0;
|
||||
const char *prefix = "/sys/net/";
|
||||
while (*prefix && pos < out_size - 1) out[pos++] = *prefix++;
|
||||
while (*iface && pos < out_size - 1) out[pos++] = *iface++;
|
||||
if (pos < out_size - 1) out[pos++] = '/';
|
||||
while (*file && pos < out_size - 1) out[pos++] = *file++;
|
||||
out[pos] = '\0';
|
||||
}
|
||||
|
||||
/**
|
||||
* Show info for one interface.
|
||||
*/
|
||||
static void show_iface(const char *name) {
|
||||
char path[128];
|
||||
char val[64];
|
||||
|
||||
puts(name);
|
||||
puts(":\n");
|
||||
|
||||
/* MAC address */
|
||||
build_path(path, sizeof(path), name, "mac");
|
||||
if (read_sysfs(path, val, sizeof(val)) > 0) {
|
||||
puts(" MAC: ");
|
||||
puts(val);
|
||||
puts("\n");
|
||||
}
|
||||
|
||||
/* Link status */
|
||||
build_path(path, sizeof(path), name, "link");
|
||||
if (read_sysfs(path, val, sizeof(val)) > 0) {
|
||||
puts(" Link: ");
|
||||
puts(val);
|
||||
puts("\n");
|
||||
}
|
||||
|
||||
/* IP address */
|
||||
build_path(path, sizeof(path), name, "ip");
|
||||
if (read_sysfs(path, val, sizeof(val)) > 0) {
|
||||
puts(" IP: ");
|
||||
puts(val);
|
||||
puts("\n");
|
||||
}
|
||||
|
||||
/* Netmask */
|
||||
build_path(path, sizeof(path), name, "netmask");
|
||||
if (read_sysfs(path, val, sizeof(val)) > 0) {
|
||||
puts(" Netmask: ");
|
||||
puts(val);
|
||||
puts("\n");
|
||||
}
|
||||
|
||||
/* Gateway */
|
||||
build_path(path, sizeof(path), name, "gateway");
|
||||
if (read_sysfs(path, val, sizeof(val)) > 0) {
|
||||
puts(" Gateway: ");
|
||||
puts(val);
|
||||
puts("\n");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a value to a sysfs file.
|
||||
*/
|
||||
static int32_t write_sysfs(const char *path, const char *value) {
|
||||
int32_t fd = open(path, 0);
|
||||
if (fd < 0) return -1;
|
||||
|
||||
int32_t n = write(fd, value, strlen(value));
|
||||
close(fd);
|
||||
return n;
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
char arg1[64];
|
||||
|
||||
/* Check if we have a subcommand */
|
||||
if (getenv("ARG1", arg1, sizeof(arg1)) < 0 || arg1[0] == '\0') {
|
||||
/* No arguments — show all interfaces */
|
||||
char name[128];
|
||||
uint32_t idx = 0;
|
||||
int found = 0;
|
||||
|
||||
while (readdir("/sys/net", idx, name) >= 0) {
|
||||
show_iface(name);
|
||||
found = 1;
|
||||
idx++;
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
puts("No network interfaces found.\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check for "set" subcommand */
|
||||
if (strcmp(arg1, "set") == 0) {
|
||||
char iface_name[32], ip[32], netmask[32], gateway[32];
|
||||
char path[128];
|
||||
|
||||
if (getenv("ARG2", iface_name, sizeof(iface_name)) < 0) {
|
||||
puts("Usage: ip set <iface> <ip> <netmask> <gateway>\n");
|
||||
return 1;
|
||||
}
|
||||
if (getenv("ARG3", ip, sizeof(ip)) < 0) {
|
||||
puts("Usage: ip set <iface> <ip> <netmask> <gateway>\n");
|
||||
return 1;
|
||||
}
|
||||
if (getenv("ARG4", netmask, sizeof(netmask)) < 0) {
|
||||
puts("Usage: ip set <iface> <ip> <netmask> <gateway>\n");
|
||||
return 1;
|
||||
}
|
||||
if (getenv("ARG5", gateway, sizeof(gateway)) < 0) {
|
||||
puts("Usage: ip set <iface> <ip> <netmask> <gateway>\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Write IP */
|
||||
build_path(path, sizeof(path), iface_name, "ip");
|
||||
if (write_sysfs(path, ip) < 0) {
|
||||
puts("Failed to set IP address\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Write netmask */
|
||||
build_path(path, sizeof(path), iface_name, "netmask");
|
||||
if (write_sysfs(path, netmask) < 0) {
|
||||
puts("Failed to set netmask\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Write gateway */
|
||||
build_path(path, sizeof(path), iface_name, "gateway");
|
||||
if (write_sysfs(path, gateway) < 0) {
|
||||
puts("Failed to set gateway\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
puts("Configured ");
|
||||
puts(iface_name);
|
||||
puts(": ");
|
||||
puts(ip);
|
||||
puts(" / ");
|
||||
puts(netmask);
|
||||
puts(" gw ");
|
||||
puts(gateway);
|
||||
puts("\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
puts("Unknown command: ");
|
||||
puts(arg1);
|
||||
puts("\nUsage: ip [set <iface> <ip> <netmask> <gateway>]\n");
|
||||
return 1;
|
||||
}
|
||||
Reference in New Issue
Block a user