feat: intel wi-fi (AX211) driver with network scanning
This commit is contained in:
Binary file not shown.
Binary file not shown.
@@ -219,6 +219,12 @@ namespace montauk::abi {
|
||||
static constexpr uint64_t SYS_DISPLAYSETMODE = 156;
|
||||
static constexpr uint64_t SYS_DISPLAYBRIGHTNESS = 157;
|
||||
|
||||
// Wi-Fi adapter control
|
||||
static constexpr uint64_t SYS_WIFI_SCAN = 158; // (WifiNetwork*, maxCount, timeoutMs) -> count
|
||||
static constexpr uint64_t SYS_WIFI_INFO = 159; // (WifiInfo*) -> 0, -1 if absent
|
||||
static constexpr uint64_t SYS_WIFI_CONNECT = 160; // (ssid, password) -> 0, <0 on error
|
||||
static constexpr uint64_t SYS_WIFI_DISCONNECT = 161; // () -> 0
|
||||
|
||||
// Tunable parameters (for SYS_SDR_SETPARAM / SYS_SDR_GETPARAM).
|
||||
static constexpr int SDR_PARAM_FREQ = 0; // center frequency, Hz
|
||||
static constexpr int SDR_PARAM_SAMPLE_RATE = 1; // sample rate, Hz
|
||||
@@ -564,6 +570,46 @@ namespace montauk::abi {
|
||||
uint32_t _pad2;
|
||||
};
|
||||
|
||||
// Wi-Fi security suites reported in WifiNetwork.security.
|
||||
static constexpr uint8_t WIFI_SEC_OPEN = 0;
|
||||
static constexpr uint8_t WIFI_SEC_WEP = 1;
|
||||
static constexpr uint8_t WIFI_SEC_WPA = 2;
|
||||
static constexpr uint8_t WIFI_SEC_WPA2 = 3;
|
||||
static constexpr uint8_t WIFI_SEC_WPA3 = 4;
|
||||
|
||||
// Adapter states reported in WifiInfo.state.
|
||||
static constexpr uint8_t WIFI_STATE_ABSENT = 0; // no device
|
||||
static constexpr uint8_t WIFI_STATE_DETECTED = 1; // waiting for firmware load
|
||||
static constexpr uint8_t WIFI_STATE_BOOTING = 2;
|
||||
static constexpr uint8_t WIFI_STATE_RUNNING = 3;
|
||||
static constexpr uint8_t WIFI_STATE_ERROR = 4;
|
||||
static constexpr uint8_t WIFI_STATE_RFKILL = 5; // radio disabled in hardware
|
||||
|
||||
// One scanned network (returned by SYS_WIFI_SCAN).
|
||||
struct WifiNetwork {
|
||||
char ssid[36]; // NUL-terminated; empty for hidden networks
|
||||
uint8_t bssid[6];
|
||||
uint8_t channel;
|
||||
int8_t rssi; // dBm
|
||||
uint8_t band; // 0 = 2.4 GHz, 1 = 5 GHz
|
||||
uint8_t security; // WIFI_SEC_*
|
||||
uint16_t beaconInterval; // TU
|
||||
};
|
||||
|
||||
// Adapter status (returned by SYS_WIFI_INFO).
|
||||
struct WifiInfo {
|
||||
uint8_t mac[6];
|
||||
uint8_t present; // 1 if a supported device was found
|
||||
uint8_t state; // WIFI_STATE_*
|
||||
uint8_t scanning;
|
||||
uint8_t bands; // bit0 = 2.4 GHz, bit1 = 5 GHz
|
||||
uint16_t channels; // usable channels after regulatory filtering
|
||||
char fwVersion[32];
|
||||
uint64_t rxPackets;
|
||||
uint32_t fwErrors;
|
||||
uint32_t connState; // 0 idle, >0 connection setup in progress
|
||||
};
|
||||
|
||||
struct ThermalInfo {
|
||||
char name[32]; // short zone name (e.g. "THRM", "TZ00")
|
||||
int32_t temperature; // tenths of degrees Celsius, or -1 if unavailable
|
||||
|
||||
@@ -181,6 +181,10 @@ extern "C" {
|
||||
#define MTK_SYS_DISPLAYMODES 155
|
||||
#define MTK_SYS_DISPLAYSETMODE 156
|
||||
#define MTK_SYS_DISPLAYBRIGHTNESS 157
|
||||
#define MTK_SYS_WIFI_SCAN 158
|
||||
#define MTK_SYS_WIFI_INFO 159
|
||||
#define MTK_SYS_WIFI_CONNECT 160
|
||||
#define MTK_SYS_WIFI_DISCONNECT 161
|
||||
/* @SYSCALLS-END */
|
||||
|
||||
#define MTK_SOCK_TCP 1
|
||||
|
||||
@@ -596,6 +596,27 @@ namespace montauk {
|
||||
return (int)syscall1(montauk::abi::SYS_BTINFO, (uint64_t)buf);
|
||||
}
|
||||
|
||||
// Wi-Fi. scan() runs a full channel sweep and blocks until it finishes or
|
||||
// timeoutMs elapses, then fills buf with the networks seen; it returns the
|
||||
// number of entries written, or -1 when no adapter is ready.
|
||||
inline int wifi_scan(montauk::abi::WifiNetwork* buf, int maxCount,
|
||||
uint32_t timeoutMs) {
|
||||
return (int)syscall3(montauk::abi::SYS_WIFI_SCAN, (uint64_t)buf,
|
||||
(uint64_t)maxCount, (uint64_t)timeoutMs);
|
||||
}
|
||||
inline int wifi_info(montauk::abi::WifiInfo* out) {
|
||||
return (int)syscall1(montauk::abi::SYS_WIFI_INFO, (uint64_t)out);
|
||||
}
|
||||
// Association is groundwork only: open networks bring the firmware
|
||||
// contexts up, encrypted ones are rejected with -2.
|
||||
inline int wifi_connect(const char* ssid, const char* password) {
|
||||
return (int)syscall2(montauk::abi::SYS_WIFI_CONNECT, (uint64_t)ssid,
|
||||
(uint64_t)password);
|
||||
}
|
||||
inline int wifi_disconnect() {
|
||||
return (int)syscall0(montauk::abi::SYS_WIFI_DISCONNECT);
|
||||
}
|
||||
|
||||
// Software-defined radio (Rx). Receivers are identified by index [0, count);
|
||||
// open() returns a handle used by the rest of the calls. Samples are read
|
||||
// as interleaved 8-bit unsigned I/Q (CU8) from the device's ring buffer.
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
.TH WIFI 1
|
||||
.SH NAME
|
||||
wifi - scan for wireless networks and inspect the Wi-Fi adapter
|
||||
|
||||
.SH SYNOPSIS
|
||||
wifi [scan [seconds]]
|
||||
wifi info
|
||||
wifi debug
|
||||
wifi connect <ssid> [passphrase]
|
||||
wifi disconnect
|
||||
|
||||
.SH DESCRIPTION
|
||||
Drives the Intel Wi-Fi adapter. With no arguments, runs a five
|
||||
second scan and lists the networks found, strongest signal first.
|
||||
|
||||
The driver supports Intel AX210-family devices whose RF type is
|
||||
GF (marketed as AX211), which is what the bundled firmware image
|
||||
covers. Other Intel wireless parts are left unclaimed.
|
||||
|
||||
.SH COMMANDS
|
||||
scan [seconds]
|
||||
Sweep every regulatory-permitted channel and report the
|
||||
networks seen. The duration is clamped to 1-20 seconds and
|
||||
defaults to 5.
|
||||
|
||||
info
|
||||
Adapter status: MAC address, firmware version, supported
|
||||
bands, usable channel count and whether a scan is running.
|
||||
|
||||
debug
|
||||
Everything info prints, plus RX/error counters, a scan with
|
||||
per-BSS detail (BSSID, channel, RSSI, security) and band and
|
||||
security tallies. Use this when a scan finds nothing.
|
||||
|
||||
connect <ssid> [passphrase]
|
||||
Brings the firmware contexts (PHY, MAC, binding, station) up
|
||||
for a network from the last scan. The 802.11 authentication
|
||||
and association exchange is not implemented, so this does not
|
||||
produce a usable link; encrypted networks are refused outright.
|
||||
|
||||
disconnect
|
||||
Tears those contexts back down.
|
||||
|
||||
.SH OUTPUT
|
||||
SSID SIGNAL RSSI CH BAND SECURITY
|
||||
-------------------------------------------------------------------
|
||||
homenet [####] -42 6 2.4GHz WPA2
|
||||
homenet-5g [###.] -61 44 5GHz WPA3
|
||||
guest [##..] -74 11 2.4GHz open
|
||||
|
||||
.SH FIRMWARE
|
||||
The adapter needs firmware from the ramdisk:
|
||||
|
||||
0:/os/firmware/intel/iwlwifi-so-a0-gf-a0-<api>.ucode
|
||||
0:/os/firmware/intel/iwlwifi-so-a0-gf-a0.pnvm
|
||||
|
||||
Loading happens shortly after boot, off the boot-critical path,
|
||||
so "wifi info" may briefly report "detected (firmware not loaded
|
||||
yet)". The PNVM file carries regulatory data; without it the
|
||||
firmware falls back to conservative built-in limits.
|
||||
|
||||
.SH DIAGNOSTICS
|
||||
no supported Wi-Fi adapter found
|
||||
No matching device, or its RF type is not GF.
|
||||
|
||||
radio disabled (RF-kill)
|
||||
The hardware kill switch is off. No scanning is possible.
|
||||
|
||||
error
|
||||
Firmware load or configuration failed; klog(1) has the
|
||||
detail under the WiFi and WiFi-FW tags.
|
||||
|
||||
.SH SEE ALSO
|
||||
ifconfig(1), klog(1), dhcp(1), syscalls(2)
|
||||
@@ -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);
|
||||
}
|
||||
Reference in New Issue
Block a user