Skip to content

Commit 1027374

Browse files
authored
Merge pull request #1366 from kernelkit/misc
2 parents 0432d7f + 0a77880 commit 1027374

6 files changed

Lines changed: 383 additions & 446 deletions

File tree

board/common/rootfs/usr/libexec/infix/iw.py

Lines changed: 144 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,73 @@ def parse_interface_info(ifname):
286286
return result
287287

288288

289+
def parse_stations(ifname):
290+
"""
291+
Parse 'iw dev <name> station dump' output
292+
Returns: list of connected stations with stats
293+
"""
294+
output = run_iw('dev', ifname, 'station', 'dump')
295+
if not output:
296+
return []
297+
298+
stations = []
299+
current = None
300+
301+
for line in output.splitlines():
302+
stripped = line.strip()
303+
304+
# New station entry: "Station aa:bb:cc:dd:ee:ff (on wifiX)"
305+
if stripped.startswith('Station '):
306+
if current:
307+
stations.append(current)
308+
parts = stripped.split()
309+
if len(parts) >= 2:
310+
current = {'mac-address': parts[1].lower()}
311+
else:
312+
current = None
313+
continue
314+
315+
if not current or ':' not in stripped:
316+
continue
317+
318+
key, _, value = stripped.partition(':')
319+
key = key.strip()
320+
value = value.strip()
321+
322+
try:
323+
if key == 'signal':
324+
# Format: "-42 dBm" or "-42 [-44, -45] dBm"
325+
current['rssi'] = int(value.split()[0])
326+
elif key == 'connected time':
327+
# Format: "123 seconds"
328+
current['connected-time'] = int(value.split()[0])
329+
elif key == 'rx bytes':
330+
current['rx-bytes'] = value # counter64: string-encoded
331+
elif key == 'tx bytes':
332+
current['tx-bytes'] = value # counter64: string-encoded
333+
elif key == 'rx packets':
334+
current['rx-packets'] = value # counter64: string-encoded
335+
elif key == 'tx packets':
336+
current['tx-packets'] = value # counter64: string-encoded
337+
elif key == 'tx bitrate':
338+
# Format: "866.7 MBit/s ..." - convert to 100kbit/s units
339+
speed_mbps = float(value.split()[0])
340+
current['tx-speed'] = int(speed_mbps * 10)
341+
elif key == 'rx bitrate':
342+
speed_mbps = float(value.split()[0])
343+
current['rx-speed'] = int(speed_mbps * 10)
344+
elif key == 'inactive time':
345+
# Format: "1234 ms"
346+
current['inactive-time'] = int(value.split()[0])
347+
except (ValueError, IndexError):
348+
continue
349+
350+
if current:
351+
stations.append(current)
352+
353+
return stations
354+
355+
289356
def parse_survey(ifname):
290357
"""
291358
Parse 'iw dev <name> survey dump' output
@@ -396,6 +463,66 @@ def parse_dev():
396463
return result
397464

398465

466+
def parse_link(ifname):
467+
"""
468+
Parse 'iw dev <name> link' output for station mode
469+
Returns: {connected, bssid, ssid, frequency, signal, tx_bitrate, rx_bitrate}
470+
"""
471+
output = run_iw('dev', ifname, 'link')
472+
if not output:
473+
return {'connected': False}
474+
475+
if 'Not connected' in output:
476+
return {'connected': False}
477+
478+
result = {'connected': True}
479+
480+
for line in output.splitlines():
481+
stripped = line.strip()
482+
483+
# Connected to aa:bb:cc:dd:ee:ff
484+
if stripped.startswith('Connected to '):
485+
parts = stripped.split()
486+
if len(parts) >= 3:
487+
result['bssid'] = parts[2].lower()
488+
489+
# SSID: NetworkName
490+
elif stripped.startswith('SSID: '):
491+
result['ssid'] = stripped[6:]
492+
493+
# freq: 5180
494+
elif stripped.startswith('freq: '):
495+
try:
496+
result['frequency'] = int(stripped[6:])
497+
except ValueError:
498+
pass
499+
500+
# signal: -42 dBm
501+
elif stripped.startswith('signal: '):
502+
try:
503+
result['rssi'] = int(stripped.split()[1])
504+
except (ValueError, IndexError):
505+
pass
506+
507+
# tx bitrate: 866.7 MBit/s ...
508+
elif stripped.startswith('tx bitrate: '):
509+
try:
510+
speed = float(stripped.split()[2])
511+
result['tx-speed'] = int(speed * 10) # 100kbit/s units
512+
except (ValueError, IndexError):
513+
pass
514+
515+
# rx bitrate: 780.0 MBit/s ...
516+
elif stripped.startswith('rx bitrate: '):
517+
try:
518+
speed = float(stripped.split()[2])
519+
result['rx-speed'] = int(speed * 10)
520+
except (ValueError, IndexError):
521+
pass
522+
523+
return result
524+
525+
399526
def main():
400527
if len(sys.argv) < 2:
401528
print(json.dumps({
@@ -404,14 +531,17 @@ def main():
404531
'list': 'List all PHY devices',
405532
'dev': 'List all interfaces grouped by PHY',
406533
'info': 'Get PHY or interface information (requires device)',
407-
'survey': 'Get channel survey data (requires interface name)'
534+
'survey': 'Get channel survey data (requires interface)',
535+
'station': 'Get connected stations in AP mode (requires interface)',
536+
'link': 'Get link info in station mode (requires interface)'
408537
},
409538
'examples': [
410539
'iw.py list',
411540
'iw.py dev',
412541
'iw.py info radio0',
413-
'iw.py info phy4',
414542
'iw.py info wlan0',
543+
'iw.py station wifi0',
544+
'iw.py link wlan0',
415545
'iw.py survey wlan0'
416546
]
417547
}, indent=2))
@@ -434,12 +564,21 @@ def main():
434564
data = parse_phy_info(device)
435565
else:
436566
data = parse_interface_info(device)
567+
elif command == 'station':
568+
if len(sys.argv) < 3:
569+
data = {'error': 'station command requires interface argument'}
570+
else:
571+
data = parse_stations(sys.argv[2])
572+
elif command == 'link':
573+
if len(sys.argv) < 3:
574+
data = {'error': 'link command requires interface argument'}
575+
else:
576+
data = parse_link(sys.argv[2])
437577
elif command == 'survey':
438578
if len(sys.argv) < 3:
439-
data = {'error': 'survey command requires device argument'}
579+
data = {'error': 'survey command requires interface argument'}
440580
else:
441-
device = sys.argv[2]
442-
data = parse_survey(device)
581+
data = parse_survey(sys.argv[2])
443582
else:
444583
data = {'error': f'Unknown command: {command}'}
445584

doc/wifi.md

Lines changed: 5 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -84,46 +84,27 @@ admin@example:/config/hardware/component/radio0/wifi-radio/> leave
8484

8585
**Key radio parameters:**
8686
- `country-code`: Two-letter ISO 3166-1 code - determines allowed channels and maximum power. Examples: US, DE, GB, SE, FR, JP. **Must match your physical location for legal compliance.**
87-
- `band`: 2.4GHz, 5GHz, or 6GHz (required for AP mode). Band selection automatically enables appropriate WiFi standards (2.4GHz: 802.11n, 5GHz: 802.11n/ac, 6GHz: 802.11n/ac/ax)
87+
- `band`: 2.4GHz, 5GHz, or 6GHz (required for AP mode). Automatically enables appropriate WiFi standards (2.4GHz: 802.11n/ax, 5GHz: 802.11n/ac/ax, 6GHz: 802.11ax)
8888
- `channel`: Channel number (1-196) or "auto" (required for AP mode). When set to "auto", defaults to channel 6 for 2.4GHz, channel 36 for 5GHz, or channel 109 for 6GHz
89-
- `enable-80211ax`: Boolean (default: false). Opt-in to enable 802.11ax (WiFi 6) on 2.4GHz and 5GHz bands. The 6GHz band always uses 802.11ax regardless of this setting
9089

9190
> [!NOTE]
9291
> TX power and channel width are automatically determined by the driver based on regulatory constraints, PHY mode, and hardware capabilities.
9392
9493
### WiFi 6 (802.11ax) Support
9594

96-
WiFi 6 (802.11ax) provides improved performance in congested environments through
97-
features like OFDMA, Target Wake Time, and BSS Coloring. By default, WiFi 6 is
98-
only enabled on the 6GHz band (WiFi 6E requirement).
95+
WiFi 6 (802.11ax) is always enabled in AP mode on all bands, providing improved
96+
performance through features like OFDMA, BSS Coloring, and beamforming.
9997

100-
To enable WiFi 6 on 2.4GHz or 5GHz bands:
101-
102-
```
103-
admin@example:/> configure
104-
admin@example:/config/> edit hardware component radio0 wifi-radio
105-
admin@example:/config/hardware/component/radio0/wifi-radio/> set country-code DE
106-
admin@example:/config/hardware/component/radio0/wifi-radio/> set band 5GHz
107-
admin@example:/config/hardware/component/radio0/wifi-radio/> set channel 36
108-
admin@example:/config/hardware/component/radio0/wifi-radio/> set enable-80211ax true
109-
admin@example:/config/hardware/component/radio0/wifi-radio/> leave
110-
```
111-
112-
**WiFi 6 Benefits:**
98+
**WiFi 6 Features (always enabled):**
11399
- **OFDMA**: Better multi-user efficiency in dense environments
114-
- **Target Wake Time**: Improved battery life for client devices
115-
- **1024-QAM**: Higher throughput with strong signal conditions
116100
- **BSS Coloring**: Reduced interference from neighboring networks
101+
- **Beamforming**: Improved signal quality and range
117102

118103
**Requirements:**
119104
- Hardware must support 802.11ax
120105
- Client devices must support WiFi 6 for full benefits
121106
- Older WiFi 5/4 clients can still connect but won't use WiFi 6 features
122107

123-
> [!NOTE]
124-
> The 6GHz band always uses WiFi 6 (802.11ax) regardless of the `enable-80211ax`
125-
> setting, as WiFi 6E requires 802.11ax support.
126-
127108
## Discovering Available Networks (Scanning)
128109

129110
Before connecting to a WiFi network, you need to discover which networks

src/bin/copy.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -580,7 +580,7 @@ static int resolve_dst(const char **dst, const struct infix_ds **ds, char **path
580580
static int copy(const char *src, const char *dst)
581581
{
582582
char *srcpath = NULL, *dstpath = NULL;
583-
const struct infix_ds *srcds, *dstds;
583+
const struct infix_ds *srcds = NULL, *dstds = NULL;
584584
bool rmsrc = false;
585585
mode_t oldmask;
586586
int err = 1;

0 commit comments

Comments
 (0)