wdev.uc adopted every operstate-down netdev on the phy and then removed any
not in its new config. hostapd BSS netdevs are legitimately operstate-down
while stopped (co-located STA down, or start_disabled), so a reload deleted
them and hostapd, seeing an unchanged config, never recreated them. Drop the
adopt-existing step; the statefile already tracks the interfaces wdev.uc
owns.
Signed-off-by: Felix Fietkau <nbd@nbd.name>
The transition BSS is a copy of the main BSS with the MAC already set, so
iface.prepare() was a no-op and both BSSes emitted the same bssid; with a
fixed or random MAC the duplicate was never reassigned and the second
interface failed to come up. Clear the address (and stale flags) and
prepare a fresh one, plumbing the phy/num_global/macaddr_base through
iface_setup().
Signed-off-by: Felix Fietkau <nbd@nbd.name>
append() space-joins list options into one line, which breaks hostapd
options that are parsed one entry per line: anqp_elem, nai_realm,
venue_name, venue_url, hs20_conn_capab and the radius req_attr lists (a
parse error there fails the whole phy). Add append_list() to emit one line
per element and route those options through it. vendor_elements is instead
a single concatenated hex blob (join ''), and iface_interworking() no
longer overwrites domain_name with the 3GPP cell-net data (and uses ';').
Signed-off-by: Felix Fietkau <nbd@nbd.name>
validate() converts the country alias to country_code and deletes country
before setup_phy() runs, so the iw reg set branch tested a null
config.country and never ran, leaving wdev-only radios (adhoc/mesh/monitor)
on the world regdomain. Use config.country_code.
Signed-off-by: Felix Fietkau <nbd@nbd.name>
The generator emits a '# Setup interface: <ifname>' comment before each
interface, so the first one landed in config.radio.data and made the radio
comparison depend on the first BSS's ifname: renaming it forced a full
radio restart instead of the rename path. Skip comment lines when parsing
radio.data/bss.data.
Signed-off-by: Felix Fietkau <nbd@nbd.name>
The per-wiphy radio-mask loops iterated all MLDs without checking the phy,
so a stop/start or status query for one wiphy touched MLDs on another wiphy
with the same radio index (clearing present bits, tearing links down, or
reporting a foreign MLD). Skip MLDs that do not belong to the phy, matching
mld_update_phy().
Signed-off-by: Felix Fietkau <nbd@nbd.name>
dpp_connector was emitted unquoted, but wpa_supplicant parses it as a
string and hex-decodes an unquoted value; a base64url connector then failed
to parse and the network block was rejected. Emit it via the quoted-string
list. dpp_csign/dpp_netaccesskey stay raw, as they are hex.
Signed-off-by: Felix Fietkau <nbd@nbd.name>
hostapd_free_hapd_data() skips hostapd_ucode_free_bss()/hostapd_ubus_free_bss()
for a bss that never started, so bss.delete() on such a bss freed hapd while
the ucode registry entry and ubus object still referenced it. Call both
explicitly before os_free(); they are idempotent for the started case.
Signed-off-by: Felix Fietkau <nbd@nbd.name>
The early error path jumps to out: before conf is assigned, where
hostapd_config_free(conf) frees an indeterminate pointer. Initialise it to
NULL (hostapd_config_free tolerates NULL).
Signed-off-by: Felix Fietkau <nbd@nbd.name>
hostapd_ucode_free_bss() pushed only two arguments, but the bss_remove
handler (like bss_add/bss_reload) takes three (phy, name, obj), so name
received the bss resource: the DPP hook was never removed and the removal
event was malformed. Push the phy as well.
Signed-off-by: Felix Fietkau <nbd@nbd.name>
phydev.name is already radio-suffixed, and the hostapd handler re-applies
the suffix, so on multi-radio phys the lookup missed and the returned MAC
list was always empty, letting wdev.uc reuse a MAC hostapd had reserved for
an AP BSS. Pass the base phy and radio index.
Signed-off-by: Felix Fietkau <nbd@nbd.name>
setup_sta() called parse_encryption() without the device config, so the
sae-compat branch dereferenced a null dev_config.band and threw, aborting
the whole radio setup. Pass the device config through.
Signed-off-by: Felix Fietkau <nbd@nbd.name>
Only an exact GCMP cipher was mapped to the network block; other explicit
ciphers (CCMP-256, GCMP-256, TKIP variants) left pairwise unset, so
wpa_supplicant offered its default set and could not associate with an AP
restricted to the configured cipher. Pass wpa_pairwise through, keeping the
GCMP special case that also pins group.
Signed-off-by: Felix Fietkau <nbd@nbd.name>
The hotplug match /(.+)\.sta.+/ also matched VLAN subinterfaces of a WDS
station (e.g. wlan0.sta1.100 -> wlan0), so the tagged subinterface was added
into the vif base networks, breaking VLAN separation. Anchor the pattern to
the plain station suffix.
Signed-off-by: Felix Fietkau <nbd@nbd.name>
handle_link() passed the option as a ucode boolean, but the netifd
device_set binding reads it with prop_get_int (UC_INTEGER only) and ignored
a boolean, so the option was a no-op. Convert it to 0/1.
Signed-off-by: Felix Fietkau <nbd@nbd.name>
retry was only reset on config change/start, never on a successful setup,
so occasional transient setup failures accumulated over a device lifetime
and latched retry_setup_failed after three cumulative failures. Reset it
when the device comes up.
Signed-off-by: Felix Fietkau <nbd@nbd.name>
Service data VLANs were stored under vif_data.vlans, but every consumer
reads vif.vlan, so per-VLAN config from a procd service was silently
dropped. Use the singular key, matching the adjacent station handling.
Signed-off-by: Felix Fietkau <nbd@nbd.name>
wdev_add() dropped the wdev_create() result, so every caller's error check
was dead and an nl80211 NEW_INTERFACE failure was silently ignored (hostapd
and wpa_supplicant then proceeded on a missing netdev with stale MLD
bookkeeping). Return the result.
Signed-off-by: Felix Fietkau <nbd@nbd.name>
new_config was tested against the freshly emptied new_mld object, so it was
always false and the reload-all-interfaces block never ran. Test the
incoming config instead, so the first MLD config re-adds the spliced-out
MLD BSSes.
Signed-off-by: Felix Fietkau <nbd@nbd.name>
The guard meant to bail to a full restart read `!mac_idx < 0`, which parses
as `(!mac_idx) < 0` and is always false, so a static BSSID colliding with
the first (or a foreign-owned) BSS fell through and reassigned the wrong
BSS's address. Use `mac_idx <= 0`.
Signed-off-by: Felix Fietkau <nbd@nbd.name>
device_extended_features() used bitwise OR instead of AND, so every
extended-feature query returned true regardless of the driver bitmap:
ftm_responder and radar_background were always reported present.
Signed-off-by: Felix Fietkau <nbd@nbd.name>
A disabled wifi-device is intentionally still run through the setup path
(with no interfaces) to reliably tear down hostapd/wpa_supplicant and to
handle disabled/enabled flapping, so it reaches state "up" and status
reported up: true alongside disabled: true. Exclude disabled devices from
the up state in status instead.
Signed-off-by: Felix Fietkau <nbd@nbd.name>
On a radio shared with a STA every AP BSS is generated with
start_disabled=1. A smart reload that takes the full bss.set_config() path
restarts the BSS but never cleared start_disabled, so hostapd_start_beacon()
skipped beaconing and the AP went silently quiet until an unrelated
apsta_state event. Clear it when the BSS was already started, matching the
add_bss path.
Signed-off-by: Felix Fietkau <nbd@nbd.name>
A 64-character hex PSK was always quoted, but wpa_supplicant rejects a
quoted passphrase longer than 63 characters, so the network block failed
and the STA never associated while netifd still reported the radio up. Emit
the key unquoted when it is a 64-character raw PMK, matching the AP path.
The sae_password branch keeps quoting, as SAE passwords are arbitrary
strings.
Signed-off-by: Felix Fietkau <nbd@nbd.name>
stop() and destroy() set cancel_setup while a setup handler is running, but
nothing read it, so a device brought down (or removed) mid-setup still went
up and stayed up, holding its interface links. Check the flag (and
autostart/delete) in wdev_mark_up and tear the device down instead of
completing the up transition.
Signed-off-by: Felix Fietkau <nbd@nbd.name>
Two defects handling the psk array returned by an auth handler: strlen()
ran before the string was validated (strlen(NULL) on a non-string entry),
and the hex-PMK branch tested the array length instead of the entry length.
A 64-character passphrase therefore reached the passphrase branch and its
memcpy of str_len + 1 overflowed passphrase[MAX_PASSPHRASE_LEN + 1] by one
byte. Validate the type first and branch on the string length.
Signed-off-by: Felix Fietkau <nbd@nbd.name>
The wifi-device injection path used object shorthand `name` where no such
variable is in scope (the loop binds radio/config), so under the strict VM
config_init threw and the whole wireless configuration for that reload was
skipped. Use the radio key as the device name.
Signed-off-by: Felix Fietkau <nbd@nbd.name>
config_reset and shutdown call iface_set_config(name) with no config, but
the null-config guard was dropped in the MLO rework, so config.phy
dereferenced null and threw: config_reset reset nothing and shutdown left
hostapd-created interfaces behind. Restore the guard, removing the stale
config entry and tearing the interface down via iface_config_remove.
Signed-off-by: Felix Fietkau <nbd@nbd.name>
iface.switch_channel() only reports whether a CSA was started, not whether
it completed, so a config-driven channel switch that the driver never
finishes would leave the AP stuck without recovery. After issuing the CSA,
arm a timer and, if the switch has not completed by the deadline
(csa_in_progress still set), fall back to a full interface restart. The
timer is armed only on the config-initiated path, so ubus- and
apsta-triggered channel switches keep their own recovery.
Add an iface.csa_in_progress() ucode method wrapping hostapd_csa_in_progress().
Signed-off-by: Felix Fietkau <nbd@nbd.name>
A config change that only alters the channel or channel width previously
failed the radio comparison in iface_reload_config() and forced a full
interface restart, disconnecting every client. Classify the radio diff:
apply a channel/width-only change through iface.switch_channel() (CSA) so
clients stay associated, keep the full restart for any other radio change.
When a co-located STA on the same band owns the runtime channel
(#channel_owned_by_sta), the change is a no-op on the AP side, which keeps
following the STA via apsta_state. MLD APs and DFS targets fall back to a
full restart, as a single iface-level CSA cannot handle them.
Signed-off-by: Felix Fietkau <nbd@nbd.name>
Emit #frequency (the target channel frequency, already computed during phy
setup) and #channel_owned_by_sta (set when a co-located STA/mesh/adhoc on
the same band dictates the runtime channel) into the generated config.
The hostapd daemon uses these to decide whether a channel change can be
applied via CSA instead of a full restart.
Signed-off-by: Felix Fietkau <nbd@nbd.name>
Lift the #frequency and #channel_owned_by_sta markers (emitted by the
config generator) onto config.radio and keep them out of radio.data so
they do not perturb the radio comparison. These feed the config-driven
channel switch handling added next.
Signed-off-by: Felix Fietkau <nbd@nbd.name>
On 6 GHz there is no HT Operation IE, so a 0 secondary-channel offset made
freq_info() return without a segment centre frequency, leaving wide-channel
switches (80/160/320 MHz) on the stale centre. Pass a null offset for wide
6 GHz channels so the centre is auto-derived.
Signed-off-by: Felix Fietkau <nbd@nbd.name>
switch_channel computed the CSA bandwidth as 40 << oper_chwidth, which
mismaps oper_chwidth 3 (80+80, must be 80 MHz plus center_freq2) to 320
and 9 (320 MHz) to 20480. Map the operating channel width to the actual
MHz bandwidth explicitly.
Signed-off-by: Felix Fietkau <nbd@nbd.name>
With new PCS implementation, the pcs property needs to be updated to the
new name of 'pcs-handle' to correctly work with PCS fwnode
consumer/provider.
Fixes: 4d5f579a81 ("airoha: update PCS node in DTSI for new PCS implementation")
Signed-off-by: Robert Marko <robert.marko@sartura.hr>
i2c-an7581 (In reality its just i2c-mt7621) should depend on the airoha
target in general and not on an7581 as an7583 also uses it.
Signed-off-by: Robert Marko <robert.marko@sartura.hr>
AN7583 DTS currently uses a non existant compatible that only exists in the
Airoha SDK.
It should just be changed to the generic MT7621 compatible as AN7581 uses
as well.
Signed-off-by: Robert Marko <robert.marko@sartura.hr>
Use upstream solution for managing GPIO power for USB devices.
A small patch is needed to make the whole thing work as this is an older
USB driver that does not use the PHY framework.
Signed-off-by: Rosen Penev <rosenp@gmail.com>
Link: https://github.com/openwrt/openwrt/pull/16842
Signed-off-by: Jonas Jelonek <jelonek.jonas@gmail.com>
The u-boot-env0 partition on this board stores a redundant U-Boot
environment (4-byte CRC32 + 1-byte flag + data), with the flag byte
differing between the u-boot-env0/u-boot-env1 copies (0x00 vs 0x01).
The actual environment size used by U-Boot for the CRC calculation is
0x1000 bytes, not the full 0x10000 byte partition.
The DTS declared this as the plain, non-redundant "u-boot,env" layout
with no env-size, so the kernel's u-boot-env nvmem-layout driver
miscomputes the CRC and fails to probe:
u-boot-env-layout ...nvmem-layout: Invalid calculated CRC32: 0xbc490a68 (expected: 0xfae56b95)
u-boot-env-layout ...nvmem-layout: probe with driver u-boot-env-layout failed with error -22
Because the probe fails, the macaddr_uboot_ethaddr nvmem cell is never
created, so eth0's nvmem-cells reference never resolves and the
ag71xx-legacy platform device is stuck in "deferred probe pending"
forever - the device boots with no functioning Ethernet interface at
all.
Switch to "u-boot,env-redundant-count" (matching the redundant-env
layout already used on other boards from this vendor lineage, e.g.
qca9557_extreme-networks_ws-ap3805i.dts) and set env-size to the
verified 0x1000, which fixes CRC validation and lets eth0 probe
successfully.
Verified on real hardware: before the fix, eth0 never comes up
(confirmed against the official 25.12.5 release, matching CRC values
exactly); after the fix, eth0 links up normally and dmesg is free of
any CRC/nvmem-layout errors.
Signed-off-by: Zoltan Szalay <dealer@ddsweb.hu>
Signed-off-by: Zoltan Szalay <szazo@halycomp.hu>
Link: https://github.com/openwrt/openwrt/pull/24134
Signed-off-by: Jonas Jelonek <jelonek.jonas@gmail.com>
This bit was set unconditionally for any 10G-capable SerDes regardless
of hw_mode, including SGMII/1000BASEX/2500BASEX running on 10G-capable
silicon. The vendor SDK's dal_longan_construct_mac_default_10gmedia_fiber
gates it on the port's declared protocol class instead, applying it to
PHY-attached XSGMII/USXGMII as well as genuine fiber - the "medium to
fiber" naming doesn't match its actual condition.
Gate on speed == RTPCS_SDS_PLL_SPD_10000 instead, matching the real
10G-class protocol family, and actively clear it for 1G/2.5G modes so a
prior 10G-class configuration doesn't leave it stuck across a runtime
downshift. 0 also matches this register's confirmed hardware reset
default on an unconfigured SerDes.
Link: https://github.com/openwrt/openwrt/pull/24232
Signed-off-by: Jonas Jelonek <jelonek.jonas@gmail.com>
TX amp/pre-emphasis tuning depends on the SerDes' real baud rate class
rather than hw_mode, so key config_attachment's dispatch on that instead.
At 1G/2.5G, attachment doesn't change meaningful: even a non-adaptive
fiber receiver needs little compensation on a short trace, so
PHY-attached and fiber links already use the same config there. At 10G,
real channel loss is high enough that it matters: PHY-attached links
equalize on the PHY's own far-end receiver and need less amp drive,
while genuine fiber/DAC links, which have no adaptive receiver
downstream, need the full config. Real DAC-vs-fiber detection doesn't
exist yet, so both of those still share one config for now.
Make use of the PLL speed enum for now, though it is a bit blurry and
may not represent the real baud rate in some cases, e.g. QSGMII (1.25G
PLL with multiplier -> 5G).
Link: https://github.com/openwrt/openwrt/pull/24232
Signed-off-by: Jonas Jelonek <jelonek.jonas@gmail.com>
Replace the on-stack, hardcoded pre/main/post-amp locals with static
const rtpcs_sds_tx_config data, one struct per speed class (1g, 2g5,
10g), instead of duplicating the same literals inline on every call.
Move the decision logic about which values are applied to the
config_media function. The tx_config should only be about what is set,
decision logic is handled one layer above. This also prepares further
refactoring.
Link: https://github.com/openwrt/openwrt/pull/24232
Signed-off-by: Jonas Jelonek <jelonek.jonas@gmail.com>
sds->attachment was written right after selection, before
config_attachment() ran, so a failed config call would leave it
reflecting a value that was never actually applied to hardware. Move
the assignment after the call succeeds, matching how sds->hw_mode is
only committed after set_hw_mode() succeeds.
Link: https://github.com/openwrt/openwrt/pull/24232
Signed-off-by: Jonas Jelonek <jelonek.jonas@gmail.com>
"media" doesn't fit well once PHY sits alongside FIBER/DAC_SHORT/
DAC_LONG as a value: a PHY isn't a transmission medium, whereas what
actually matters here is what electrically terminates the SerDes lane
on the other end. Rename the enum, struct field, ops vtable member,
and both variants' config functions accordingly. Calling it 'attachment'
better fits what it actually is, doesn't confuse with the variants and
also fits to the PMA (Physical Medium Attachment) sublayer that lives
below PCS.
Link: https://github.com/openwrt/openwrt/pull/24232
Signed-off-by: Jonas Jelonek <jelonek.jonas@gmail.com>
Every SerDes lane runs over some PCB trace before reaching the port,
even fiber/DAC ones, so PCB doesn't describe what actually
distinguishes this case: the SerDes terminates directly into a PHY
chip rather than a fiber module or DAC cable.
Link: https://github.com/openwrt/openwrt/pull/24232
Signed-off-by: Jonas Jelonek <jelonek.jonas@gmail.com>
SGMII always terminates in a PHY, whether on-board or embedded in an
SFP copper module, so it belongs with QSGMII/XSGMII/USXGMII rather
than the direct fiber/DAC modes. The PHY equalizes on its own far-end
receiver in either case, so no media-dependent TX tuning is needed.
Link: https://github.com/openwrt/openwrt/pull/24232
Signed-off-by: Jonas Jelonek <jelonek.jonas@gmail.com>
So far, there was only a misleading and confusing gate to avoid applying
the TX config to SerDes which do not need it or where it even breaks
some modes. This is achieved by not applying any configuration for
QSGMII mode. While this fits the real-world cases we know so far where
QSGMII is only used on SerDes 0/1 but never on others, it implicates
that this is true too for QSGMII on 10G SerDes. Looking at the SDK, this
assumption doesn't hold.
To fix this, drop out of config_media in case a non-10G SerDes is
delivered. The SDK does the same in various ways, ending up with the
config just being applied for SerDes 2 - 9.
Link: https://github.com/openwrt/openwrt/pull/24232
Signed-off-by: Jonas Jelonek <jelonek.jonas@gmail.com>
Derive the CMU page from rtpcs_93xx_sds_get_cmu_page() instead of
hardcoding it per hw_mode case. Also change the function to return
int and propagate errors instead of silently doing nothing.
Link: https://github.com/openwrt/openwrt/pull/24232
Signed-off-by: Jonas Jelonek <jelonek.jonas@gmail.com>