feat: wi-fi - join WPA2/WPA3-PSK networks and carry traffic like ethernet
This commit is contained in:
+100
-17
@@ -7,8 +7,10 @@
|
||||
* 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
|
||||
* wifi connect <ssid> [passphrase]
|
||||
* join a network (WPA2/WPA3-PSK or open)
|
||||
* wifi status the network currently joined
|
||||
* wifi disconnect leave it
|
||||
*
|
||||
* Copyright (c) 2026 Daniel Hammer
|
||||
*/
|
||||
@@ -85,6 +87,21 @@ static const char* state_name(uint8_t state) {
|
||||
}
|
||||
}
|
||||
|
||||
static const char* conn_state_name(uint32_t s) {
|
||||
switch (s) {
|
||||
case abi::WIFI_CONN_IDLE: return "not connected";
|
||||
case abi::WIFI_CONN_CONTEXTS_UP: return "preparing radio";
|
||||
case abi::WIFI_CONN_AUTHENTICATING: return "authenticating";
|
||||
case abi::WIFI_CONN_AUTHENTICATED: return "authenticated";
|
||||
case abi::WIFI_CONN_ASSOCIATING: return "associating";
|
||||
case abi::WIFI_CONN_ASSOCIATED: return "associated";
|
||||
case abi::WIFI_CONN_HANDSHAKING: return "exchanging keys";
|
||||
case abi::WIFI_CONN_CONNECTED: return "connected";
|
||||
case abi::WIFI_CONN_FAILED: return "failed";
|
||||
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) {
|
||||
@@ -159,15 +176,50 @@ static void print_info(const abi::WifiInfo& info, bool verbose) {
|
||||
print(" channels : "); put_u64(info.channels);
|
||||
print(" usable after regulatory filtering\n");
|
||||
print(" scanning : "); print(info.scanning ? "yes" : "no"); print("\n");
|
||||
print(" network : ");
|
||||
if (info.ssid[0]) {
|
||||
print(info.ssid);
|
||||
print(" ("); print(conn_state_name(info.connState)); print(")");
|
||||
} else {
|
||||
print(conn_state_name(info.connState));
|
||||
}
|
||||
print("\n");
|
||||
if (info.ssid[0]) {
|
||||
print(" bssid : "); put_mac(info.bssid); print("\n");
|
||||
}
|
||||
|
||||
if (verbose) {
|
||||
print(" rx packets : "); put_u64(info.rxPackets); print("\n");
|
||||
print(" tx packets : "); put_u64(info.txPackets); print("\n");
|
||||
print(" fw errors : "); put_u64(info.fwErrors); print("\n");
|
||||
print(" conn state : "); put_u64(info.connState);
|
||||
print(" (0 = idle)\n");
|
||||
print(" ("); print(conn_state_name(info.connState)); print(")\n");
|
||||
}
|
||||
}
|
||||
|
||||
static int cmd_status() {
|
||||
abi::WifiInfo info;
|
||||
if (wifi_info(&info) != 0 && !info.present) {
|
||||
print("wifi: no supported Wi-Fi adapter found.\n");
|
||||
return 1;
|
||||
}
|
||||
if (!info.connected) {
|
||||
print("Not connected.");
|
||||
if (info.connState != abi::WIFI_CONN_IDLE) {
|
||||
print(" Currently "); print(conn_state_name(info.connState)); print(".");
|
||||
}
|
||||
print("\n");
|
||||
return 1;
|
||||
}
|
||||
print("Connected to \""); print(info.ssid); print("\"\n");
|
||||
print(" bssid : "); put_mac(info.bssid); print("\n");
|
||||
print(" interface : wlan0 ("); put_mac(info.mac); print(")\n");
|
||||
print(" rx / tx : "); put_u64(info.rxPackets);
|
||||
print(" / "); put_u64(info.txPackets); print(" packets\n");
|
||||
print("\nRun \"dhcp\" to pick up an address if you have not already.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cmd_scan(uint32_t seconds, bool verbose) {
|
||||
abi::WifiInfo info;
|
||||
if (!require_adapter(info)) return 1;
|
||||
@@ -317,20 +369,44 @@ static int cmd_connect(const char* ssid, const char* password) {
|
||||
|
||||
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");
|
||||
print("Connected.\n");
|
||||
print("Run \"dhcp\" to get an address, then the network is usable\n");
|
||||
print("just like a wired connection.\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;
|
||||
|
||||
switch (rc) {
|
||||
case abi::WIFI_ERR_NOT_FOUND:
|
||||
print("wifi: \""); print(ssid); print("\" was not found in the last scan.\n");
|
||||
print(" Run \"wifi scan\" first, and check the SSID spelling.\n");
|
||||
break;
|
||||
case abi::WIFI_ERR_NEED_KEY:
|
||||
print("wifi: \""); print(ssid); print("\" is encrypted and needs a passphrase.\n");
|
||||
print(" Usage: wifi connect "); print(ssid); print(" <passphrase>\n");
|
||||
break;
|
||||
case abi::WIFI_ERR_UNSUPPORTED:
|
||||
print("wifi: \""); print(ssid); print("\" uses security this driver cannot do.\n");
|
||||
print(" Supported: open, and WPA2/WPA3-PSK with CCMP or GCMP.\n");
|
||||
print(" Not supported: WEP, the original WPA (TKIP), WPA3 SAE-only\n");
|
||||
print(" networks, and 802.1X enterprise. Check klog for the detail.\n");
|
||||
break;
|
||||
case abi::WIFI_ERR_AUTH:
|
||||
print("wifi: the key exchange was rejected - the passphrase is\n");
|
||||
print(" probably wrong. Check it and try again.\n");
|
||||
break;
|
||||
case abi::WIFI_ERR_TIMEOUT:
|
||||
print("wifi: the access point did not respond in time.\n");
|
||||
print(" It may be out of range; \"wifi scan\" shows the signal.\n");
|
||||
break;
|
||||
case abi::WIFI_ERR_NO_ADAPTER:
|
||||
print("wifi: the adapter is not ready.\n");
|
||||
break;
|
||||
default:
|
||||
print("wifi: could not connect. See klog for the kernel-side detail.\n");
|
||||
break;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -339,8 +415,9 @@ static void usage() {
|
||||
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(" connect <ssid> [key] join a network (open or WPA2/WPA3-PSK)\n");
|
||||
print(" status show the network currently joined\n");
|
||||
print(" disconnect leave the current network\n\n");
|
||||
print("With no command, runs a 5 second scan.\n");
|
||||
}
|
||||
|
||||
@@ -363,14 +440,20 @@ extern "C" void _start() {
|
||||
exit(cmd_info(false));
|
||||
} else if (streq(cmd, "debug")) {
|
||||
exit(cmd_debug());
|
||||
} else if (streq(cmd, "status")) {
|
||||
exit(cmd_status());
|
||||
} 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));
|
||||
// Everything after the SSID is the passphrase, spaces and all.
|
||||
const char* p = skip_spaces(rest);
|
||||
int n = 0;
|
||||
while (p[n] && n < (int)sizeof(pass) - 1) { pass[n] = p[n]; n++; }
|
||||
while (n > 0 && pass[n - 1] == ' ') n--;
|
||||
pass[n] = '\0';
|
||||
exit(cmd_connect(ssid, pass));
|
||||
} else if (streq(cmd, "disconnect")) {
|
||||
wifi_disconnect();
|
||||
|
||||
Reference in New Issue
Block a user