Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Changed

- LongFred Soft-AP commissioning addresses are now `192.168.4.1` / source
`192.168.4.2` (ESP-IDF default, same as WiFred). This no longer overlaps
the BigFred hub LAN (`192.168.0.0/24`). Requires matching LongFred
firmware; older devices at `192.168.0.1` will not program.

## [v0.2] — 2026-08-22

Hub Soft-AP programming for LongFred (and WiFred) when the device AP shares the
Expand Down
4 changes: 2 additions & 2 deletions crates/wp-core/src/capabilities.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,11 @@ impl From<CommissioningKind> for CommissioningKindWire {
/// daemon keeps its historical defaults (`192.168.4.1` / `192.168.4.2/24`).
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct CommissioningNet {
/// Device Soft-AP address (e.g. `192.168.0.1`).
/// Device Soft-AP address (e.g. `192.168.4.1`).
pub host: Ipv4Addr,
/// HTTP port on the Soft-AP (typically 80).
pub port: u16,
/// Address the hub assigns on the wireless interface (e.g. `192.168.0.2`).
/// Address the hub assigns on the wireless interface (e.g. `192.168.4.2`).
pub source: Ipv4Addr,
/// Prefix length for the on-link route (typically 24).
pub prefix: u8,
Expand Down
4 changes: 2 additions & 2 deletions crates/wp-drivers/src/longfred/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ pub const WIFI_CONFIG_SSID_PREFIX: &str = "longfred_prog";
pub const CONFIG_AP_PORT: u16 = 80;

/// Config AP address (firmware static Soft-AP IP).
pub const CONFIG_HOST: Ipv4Addr = Ipv4Addr::new(192, 168, 0, 1);
pub const CONFIG_HOST: Ipv4Addr = Ipv4Addr::new(192, 168, 4, 1);

/// Source address the daemon assigns to the wireless interface.
pub const CONFIG_SOURCE: Ipv4Addr = Ipv4Addr::new(192, 168, 0, 2);
pub const CONFIG_SOURCE: Ipv4Addr = Ipv4Addr::new(192, 168, 4, 2);

/// On-link prefix length for the config AP subnet.
pub const CONFIG_PREFIX_LEN: u8 = 24;
Expand Down
2 changes: 1 addition & 1 deletion crates/wp-drivers/src/longfred/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
//!
//! Implements [`wp_core::DeviceDriver`] for LongFred throttles in programming
//! mode. The firmware raises an open Soft-AP named `longfred_prog_XXXXXX` with
//! a static address `192.168.0.1/24` and serves:
//! a static address `192.168.4.1/24` and serves:
//!
//! - `GET /api/v1/settings`
//! - `PUT /api/v1/settings`
Expand Down
7 changes: 4 additions & 3 deletions crates/wp-link/src/http.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
//!
//! Plain HTTP only — Soft-AP config pages serve on an on-link address with no
//! TLS. The client binds to a caller-supplied source address (e.g.
//! `192.168.4.2` or `192.168.0.2`) so requests leave the wireless interface,
//! `192.168.4.2`) so requests leave the wireless interface,
//! and enforces a deadline, a maximum response body size, and a bounded retry
//! count.

Expand Down Expand Up @@ -89,8 +89,9 @@ impl BoundedHttpClient {
/// Remember the wireless interface name for diagnostics and for
/// `SO_BINDTODEVICE` when the destination is **not** a local address.
///
/// When the Soft-AP IP is also assigned on another interface (LongFred
/// `192.168.0.1` vs hub LAN), `SO_BINDTODEVICE` must **not** be set:
/// When the Soft-AP IP is also assigned on another interface (e.g. a
/// device AP at `192.168.0.1` vs hub LAN), `SO_BINDTODEVICE` must **not**
/// be set:
/// the SYN-ACK's source is a local address, so the kernel may deliver
/// it with `skb->dev = lo`, and a socket bound to `wlan0` will not match
/// — Linux then generates RST (`Connection reset by peer`). Output is
Expand Down
9 changes: 6 additions & 3 deletions crates/wp-link/src/netcfg.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
//! Interface-scoped IPv4 settings needed when a device Soft-AP shares a
//! subnet with the hub's own LAN.
//!
//! The LongFred Soft-AP serves `192.168.0.1/24`, which is also the BigFred
//! hub's LAN address. Three kernel behaviours break the HTTP conversation:
//! Historically the LongFred Soft-AP served `192.168.0.1/24`, the same
//! address as the BigFred hub LAN. Current LongFred firmware uses
//! `192.168.4.1/24` (no overlap). The helpers below still apply whenever
//! `host` is a locally-owned address — three kernel behaviours then break
//! the HTTP conversation:
//!
//! 1. **Outbound SYN** — a route lookup for `192.168.0.1` hits the `local`
//! 1. **Outbound SYN** — a route lookup for the Soft-AP IP hits the `local`
//! table first (pref 0) and delivers to loopback. `SO_BINDTODEVICE` does
//! **not** override that: `from all lookup local` has no oif filter.
//! ICMP "success" with a local route is the hub answering its own address.
Expand Down
25 changes: 10 additions & 15 deletions docs/drivers/longfred.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,31 +7,26 @@ programming mode.

In programming mode the firmware raises an **open** WiFi AP named
`longfred_prog_XXXXXX` (6 hex characters derived from the MAC). The Soft-AP
uses a static address `192.168.0.1/24` (not the ESP-IDF Soft-AP default of
`192.168.4.1`) and a DHCP pool `192.168.0.50–200`. The wireless-programmer
uses a static address `192.168.4.1/24` (ESP-IDF Soft-AP default, same as
WiFred) and a DHCP pool `192.168.4.50–200`. The wireless-programmer
source address `.2` is **outside** that pool. The driver advertises this via
`capabilities.commissioningNet`:

| Field | Value |
|----------|----------------|
| `host` | `192.168.0.1` |
| `host` | `192.168.4.1` |
| `port` | `80` |
| `source` | `192.168.0.2` |
| `source` | `192.168.4.2` |
| `prefix` | `24` |

The daemon should associate to the open AP, assign `192.168.0.2/24` on the
The daemon should associate to the open AP, assign `192.168.4.2/24` on the
wireless interface (**no default route**), hand a sync `HttpClient` to the
driver, and release the radio on every exit path.

> **Address collision with hub LAN.** The BigFred hub serves its own LAN from
> `192.168.0.1/24`, so `192.168.0.1` is a local address on the hub's Ethernet.
> The daemon parks `lookup local` at pref 1 and installs
> `from 192.168.0.2 to 192.168.0.1 lookup 100` at pref 0, with
> `192.168.0.1/32 dev wlan0` in table 100. The HTTP client binds
> `192.168.0.2` but **does not** set `SO_BINDTODEVICE` for this destination
> (that made the kernel RST the SYN-ACK). Inbound still needs
> `accept_local=1` and `rp_filter=0` on `wlan0`. Restored on radio release;
> see `wp_link::netcfg`.
This subnet does **not** overlap the BigFred hub LAN (`192.168.0.0/24`), so
the `wp_link::netcfg` policy-route path for a locally-owned destination is
not needed for LongFred. The radio still installs the generic Soft-AP
sysctls; they are a no-op when `host` is not a local address.

Candidate identity: SSID prefix `longfred_prog`, stable key = BSSID.

Expand All @@ -45,7 +40,7 @@ Candidate identity: SSID prefix `longfred_prog`, stable key = BSSID.
| `supportsThrottleServer` | true (field accepted, unused) |
| `supportsFirmwareUpdate` | true |
| `commissioning` | `SoftAp` |
| `commissioningNet` | `192.168.0.1` / source `.2` /24 |
| `commissioningNet` | `192.168.4.1` / source `.2` /24 |

`identity` is written as `wifi.hostname`. BigFred authentication uses the
optional `bigfred.login` / `bigfred.pin` fields on `ProgramRequest` (not the
Expand Down
2 changes: 1 addition & 1 deletion docs/drivers/wifred.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ The HTTP client is bound to the wireless device (`SO_BINDTODEVICE`) and the
radio installs a policy route plus `accept_local` / `rp_filter` on that
device, so commissioning works even when the Soft-AP subnet collides with a
local interface. WiFred's `192.168.4.0/24` does not normally collide with the
hub LAN; see `docs/drivers/longfred.md` for the case where it does.
hub LAN; LongFred now uses the same `192.168.4.0/24` subnet.

## Capabilities

Expand Down
Loading