use anyhow::{Context, Result}; use tracing::info; use crate::tollgate::TollGateConfig; use crate::Router; /// Create a dedicated pay-as-you-go WiFi interface for TollGate. /// /// Adds a new `wifi-iface` section on the first detected radio, sets the SSID, /// marks it as an open network, and ties it to a TollGate firewall zone. pub fn provision_ssid(router: &Router, cfg: &TollGateConfig) -> Result<()> { let radio = detect_radio(router).context("detect WiFi radio")?; info!("[{}] Using radio {} for TollGate SSID", router.host, radio); // Add a new wifi-iface section; uci add returns the section name (e.g. "cfg123456"). let section = router.uci_add("wireless", "wifi-iface")?; router.uci_apply( "wireless", &[ (&format!("wireless.{}.device", section), &radio), (&format!("wireless.{}.mode", section), "ap"), (&format!("wireless.{}.ssid", section), &cfg.ssid), (&format!("wireless.{}.encryption", section), "none"), (&format!("wireless.{}.network", section), "tollgate"), // Disable 802.11r/k/v — unnecessary for transient pay-as-you-go clients. (&format!("wireless.{}.ieee80211r", section), "0"), ], )?; provision_network(router)?; provision_firewall(router)?; Ok(()) } /// Add a `tollgate` network interface (isolated LAN for TollGate clients). fn provision_network(router: &Router) -> Result<()> { router.uci_apply( "network", &[ ("network.tollgate", "interface"), ("network.tollgate.proto", "static"), ("network.tollgate.ipaddr", "192.168.99.1"), ("network.tollgate.netmask", "255.255.255.0"), ], )?; // Enable DHCP for the tollgate interface. router.uci_apply( "dhcp", &[ ("dhcp.tollgate", "dhcp"), ("dhcp.tollgate.interface", "tollgate"), ("dhcp.tollgate.start", "100"), ("dhcp.tollgate.limit", "150"), ("dhcp.tollgate.leasetime", "5m"), ], )?; Ok(()) } /// Add firewall zone for the tollgate interface. /// /// TollGate itself gates forwarding via iptables; the firewall zone isolates /// tollgate clients from other LAN segments. fn provision_firewall(router: &Router) -> Result<()> { // Zone router.uci_apply( "firewall", &[ ("firewall.tollgate_zone", "zone"), ("firewall.tollgate_zone.name", "tollgate"), ("firewall.tollgate_zone.network", "tollgate"), ("firewall.tollgate_zone.input", "ACCEPT"), ("firewall.tollgate_zone.output", "ACCEPT"), ("firewall.tollgate_zone.forward", "REJECT"), ], )?; // Forwarding rule: tollgate → wan (TollGate manages which clients can forward) router.uci_apply( "firewall", &[ ("firewall.tollgate_fwd", "forwarding"), ("firewall.tollgate_fwd.src", "tollgate"), ("firewall.tollgate_fwd.dest", "wan"), ], )?; Ok(()) } /// Return the first available wireless radio device name (e.g. "radio0"). fn detect_radio(router: &Router) -> Result { let out = router.run_ok("uci show wireless | grep -o 'wireless\\.radio[0-9]*\\.type' | head -1")?; // Extract "radioN" from "wireless.radioN.type" let radio = out .trim() .split('.') .nth(1) .unwrap_or("radio0") .to_string(); Ok(radio) }