feat: intel wi-fi (AX211) driver with network scanning

This commit is contained in:
2026-08-06 08:36:10 +02:00
parent 75d92d560c
commit a01e63c717
21 changed files with 5649 additions and 4 deletions
+387
View File
@@ -0,0 +1,387 @@
/*
* main.cpp
* wifi - Wi-Fi scanning and adapter diagnostics.
*
* Usage:
* wifi scan and list nearby networks
* wifi scan [seconds] scan for a specific duration (default 5, max 20)
* wifi info adapter, firmware and radio status
* wifi debug info plus raw counters, repeated scan detail
* wifi connect <ssid> bring up the firmware contexts for an open network
* wifi disconnect tear those contexts back down
*
* Copyright (c) 2026 Daniel Hammer
*/
#include <montauk/syscall.h>
#include <montauk/string.h>
using namespace montauk;
// ---------------------------------------------------------------------------
// Formatting helpers (freestanding; no libc printf here)
// ---------------------------------------------------------------------------
static void put_u64(uint64_t n) {
char buf[24];
int i = 0;
if (n == 0) { putchar('0'); return; }
while (n) { buf[i++] = (char)('0' + (n % 10)); n /= 10; }
while (i) putchar(buf[--i]);
}
static void put_i64(int64_t n) {
if (n < 0) { putchar('-'); n = -n; }
put_u64((uint64_t)n);
}
// Right-align an unsigned value in a field of `width` characters.
static void put_u64_pad(uint64_t n, int width) {
int digits = 1;
for (uint64_t t = n; t >= 10; t /= 10) digits++;
for (int i = digits; i < width; i++) putchar(' ');
put_u64(n);
}
static void put_hex2(uint8_t v) {
const char* hex = "0123456789abcdef";
putchar(hex[(v >> 4) & 0xF]);
putchar(hex[v & 0xF]);
}
static void put_mac(const uint8_t* m) {
for (int i = 0; i < 6; i++) {
if (i) putchar(':');
put_hex2(m[i]);
}
}
static void put_padded_str(const char* s, int width) {
int n = 0;
while (s[n] && n < width) { putchar(s[n]); n++; }
for (; n < width; n++) putchar(' ');
}
static const char* security_name(uint8_t sec) {
switch (sec) {
case abi::WIFI_SEC_OPEN: return "open";
case abi::WIFI_SEC_WEP: return "WEP";
case abi::WIFI_SEC_WPA: return "WPA";
case abi::WIFI_SEC_WPA2: return "WPA2";
case abi::WIFI_SEC_WPA3: return "WPA3";
default: return "?";
}
}
static const char* state_name(uint8_t state) {
switch (state) {
case abi::WIFI_STATE_ABSENT: return "no adapter";
case abi::WIFI_STATE_DETECTED: return "detected (firmware not loaded yet)";
case abi::WIFI_STATE_BOOTING: return "loading firmware";
case abi::WIFI_STATE_RUNNING: return "ready";
case abi::WIFI_STATE_ERROR: return "error";
case abi::WIFI_STATE_RFKILL: return "radio disabled (RF-kill)";
default: return "unknown";
}
}
// A rough signal-quality bar from the RSSI: -50 dBm and up is excellent,
// -90 dBm and below is unusable.
static void put_signal_bar(int8_t rssi) {
int bars = 0;
if (rssi >= -55) bars = 4;
else if (rssi >= -67) bars = 3;
else if (rssi >= -78) bars = 2;
else if (rssi >= -88) bars = 1;
putchar('[');
for (int i = 0; i < 4; i++) putchar(i < bars ? '#' : '.');
putchar(']');
}
// ---------------------------------------------------------------------------
// Argument helpers
// ---------------------------------------------------------------------------
static uint64_t parse_u64(const char* s) {
uint64_t v = 0;
while (*s >= '0' && *s <= '9') { v = v * 10 + (uint64_t)(*s - '0'); s++; }
return v;
}
static bool next_token(const char** rest, char* tok, int cap) {
const char* s = skip_spaces(*rest);
if (*s == '\0') { *rest = s; return false; }
int i = 0;
while (*s && *s != ' ' && i < cap - 1) tok[i++] = *s++;
tok[i] = '\0';
*rest = s;
return true;
}
// ---------------------------------------------------------------------------
// Commands
// ---------------------------------------------------------------------------
static abi::WifiNetwork g_nets[64];
static bool require_adapter(abi::WifiInfo& info) {
if (wifi_info(&info) != 0 || !info.present) {
print("wifi: no supported Wi-Fi adapter found.\n");
print(" Only Intel AX210-family devices with an RF type of GF "
"(AX211) are supported.\n");
return false;
}
if (info.state != abi::WIFI_STATE_RUNNING) {
print("wifi: adapter is not ready ("); print(state_name(info.state));
print(").\n");
if (info.state == abi::WIFI_STATE_DETECTED)
print(" Firmware loads shortly after boot; try again in a moment.\n");
else if (info.state == abi::WIFI_STATE_ERROR)
print(" Check the kernel log (klog) for firmware errors.\n");
return false;
}
return true;
}
static void print_info(const abi::WifiInfo& info, bool verbose) {
print("Wi-Fi adapter\n");
print(" status : "); print(state_name(info.state)); print("\n");
print(" MAC : "); put_mac(info.mac); print("\n");
print(" firmware : ");
print(info.fwVersion[0] ? info.fwVersion : "(not loaded)");
print("\n");
print(" bands : ");
if (info.bands & 1) print("2.4GHz ");
if (info.bands & 2) print("5GHz");
if (!info.bands) print("(unknown)");
print("\n");
print(" channels : "); put_u64(info.channels);
print(" usable after regulatory filtering\n");
print(" scanning : "); print(info.scanning ? "yes" : "no"); print("\n");
if (verbose) {
print(" rx packets : "); put_u64(info.rxPackets); print("\n");
print(" fw errors : "); put_u64(info.fwErrors); print("\n");
print(" conn state : "); put_u64(info.connState);
print(" (0 = idle)\n");
}
}
static int cmd_scan(uint32_t seconds, bool verbose) {
abi::WifiInfo info;
if (!require_adapter(info)) return 1;
uint32_t timeoutMs = seconds * 1000;
if (timeoutMs < 1000) timeoutMs = 5000;
if (timeoutMs > 20000) timeoutMs = 20000;
print("Scanning for up to ");
put_u64(timeoutMs / 1000);
print(" seconds...\n");
int n = wifi_scan(g_nets, 64, timeoutMs);
if (n < 0) {
print("wifi: scan failed.\n");
return 1;
}
if (n == 0) {
print("No networks found.\n");
return 0;
}
// Strongest signal first (small n, so a simple selection sort is fine).
for (int i = 0; i < n - 1; i++) {
int best = i;
for (int j = i + 1; j < n; j++)
if (g_nets[j].rssi > g_nets[best].rssi) best = j;
if (best != i) {
abi::WifiNetwork tmp = g_nets[i];
g_nets[i] = g_nets[best];
g_nets[best] = tmp;
}
}
print("\n");
print("SSID SIGNAL RSSI CH BAND SECURITY\n");
print("-------------------------------------------------------------------\n");
for (int i = 0; i < n; i++) {
const abi::WifiNetwork& w = g_nets[i];
put_padded_str(w.ssid[0] ? w.ssid : "(hidden)", 32);
putchar(' ');
put_signal_bar(w.rssi);
print(" ");
put_i64(w.rssi);
print(w.rssi > -100 ? " " : " ");
put_u64_pad(w.channel, 3);
print(" ");
print(w.band ? "5GHz " : "2.4GHz");
print(" ");
print(security_name(w.security));
print("\n");
if (verbose) {
print(" bssid "); put_mac(w.bssid);
print(" beacon interval "); put_u64(w.beaconInterval);
print(" TU\n");
}
}
print("\n");
put_u64((uint64_t)n);
print(n == 1 ? " network found.\n" : " networks found.\n");
return 0;
}
static int cmd_info(bool verbose) {
abi::WifiInfo info;
if (wifi_info(&info) != 0 && !info.present) {
print("wifi: no supported Wi-Fi adapter found.\n");
return 1;
}
print_info(info, verbose);
return 0;
}
static int cmd_debug() {
abi::WifiInfo info;
if (wifi_info(&info) != 0 && !info.present) {
print("wifi: no supported Wi-Fi adapter found.\n");
return 1;
}
print("=== Wi-Fi diagnostics ===\n\n");
print_info(info, true);
if (info.state != abi::WIFI_STATE_RUNNING) {
print("\nAdapter is not ready; skipping the scan test.\n");
print("Kernel-side detail is in the klog (look for the WiFi/WiFi-FW tags).\n");
return 0;
}
print("\nRunning a 5 second scan and reporting per-BSS detail...\n");
int n = wifi_scan(g_nets, 64, 5000);
if (n < 0) {
print("scan failed\n");
return 1;
}
int open = 0, wpa2 = 0, wpa3 = 0, other = 0, band24 = 0, band5 = 0;
for (int i = 0; i < n; i++) {
switch (g_nets[i].security) {
case abi::WIFI_SEC_OPEN: open++; break;
case abi::WIFI_SEC_WPA2: wpa2++; break;
case abi::WIFI_SEC_WPA3: wpa3++; break;
default: other++; break;
}
if (g_nets[i].band) band5++; else band24++;
}
print("\nBSS count : "); put_u64((uint64_t)n); print("\n");
print(" 2.4 GHz : "); put_u64((uint64_t)band24); print("\n");
print(" 5 GHz : "); put_u64((uint64_t)band5); print("\n");
print(" open : "); put_u64((uint64_t)open); print("\n");
print(" WPA2 : "); put_u64((uint64_t)wpa2); print("\n");
print(" WPA3 : "); put_u64((uint64_t)wpa3); print("\n");
print(" other : "); put_u64((uint64_t)other); print("\n");
if (n > 0) {
print("\nPer-BSS detail:\n");
for (int i = 0; i < n; i++) {
const abi::WifiNetwork& w = g_nets[i];
print(" "); put_mac(w.bssid);
print(" ch "); put_u64_pad(w.channel, 3);
print(" "); put_i64(w.rssi); print(" dBm ");
print(security_name(w.security));
print(" ");
print(w.ssid[0] ? w.ssid : "(hidden)");
print("\n");
}
}
// Re-read the counters so the caller can see whether frames actually moved.
abi::WifiInfo after;
if (wifi_info(&after) == 0) {
print("\nRX packets: "); put_u64(info.rxPackets);
print(" -> "); put_u64(after.rxPackets);
print(" firmware errors: "); put_u64(after.fwErrors);
print("\n");
}
return 0;
}
static int cmd_connect(const char* ssid, const char* password) {
abi::WifiInfo info;
if (!require_adapter(info)) return 1;
print("Connecting to \""); print(ssid); print("\"...\n");
int rc = wifi_connect(ssid, password);
if (rc == 0) {
print("Firmware contexts are up.\n");
print("NOTE: the 802.11 authentication exchange is not implemented yet,\n");
print(" so this does not establish a usable link.\n");
return 0;
}
if (rc == -2) {
print("wifi: \""); print(ssid); print("\" is encrypted (WPA2/WPA3).\n");
print(" Only open networks can be joined so far - the key exchange\n");
print(" is not implemented yet. Scanning is unaffected.\n");
return 1;
}
print("wifi: \""); print(ssid); print("\" was not found in the last scan.\n");
print(" Run \"wifi scan\" first, and check the SSID spelling.\n");
return 1;
}
static void usage() {
print("usage: wifi [command]\n\n");
print(" scan [seconds] scan and list nearby networks (default 5)\n");
print(" info adapter, firmware and radio status\n");
print(" debug diagnostics plus per-BSS scan detail\n");
print(" connect <ssid> bring up firmware contexts (open networks)\n");
print(" disconnect tear those contexts down\n\n");
print("With no command, runs a 5 second scan.\n");
}
extern "C" void _start() {
char args[192];
int alen = getargs(args, sizeof(args));
const char* rest = (alen > 0) ? args : "";
char cmd[32];
if (!next_token(&rest, cmd, sizeof(cmd))) {
exit(cmd_scan(5, false));
}
if (streq(cmd, "scan")) {
char tok[16];
uint32_t secs = 5;
if (next_token(&rest, tok, sizeof(tok))) secs = (uint32_t)parse_u64(tok);
exit(cmd_scan(secs, false));
} else if (streq(cmd, "info")) {
exit(cmd_info(false));
} else if (streq(cmd, "debug")) {
exit(cmd_debug());
} else if (streq(cmd, "connect")) {
char ssid[40], pass[80];
if (!next_token(&rest, ssid, sizeof(ssid))) {
print("wifi: connect needs an SSID\n");
exit(1);
}
pass[0] = '\0';
next_token(&rest, pass, sizeof(pass));
exit(cmd_connect(ssid, pass));
} else if (streq(cmd, "disconnect")) {
wifi_disconnect();
print("Disconnected.\n");
exit(0);
} else if (streq(cmd, "help") || streq(cmd, "-h") || streq(cmd, "--help")) {
usage();
exit(0);
}
print("wifi: unknown command \""); print(cmd); print("\"\n\n");
usage();
exit(1);
}