Skip to content
1 change: 1 addition & 0 deletions board/common/qemu/qemu.sh
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,7 @@ run_qemu()
$(serial_args) \
$(rw_args) \
$(usb_args) \
-device usb-host,vendorid=0x0bda,productid=0xc820 \
$(host_args) \
$(net_args) \
$(wdt_args) \
Expand Down
4 changes: 4 additions & 0 deletions board/common/rootfs/etc/finit.d/available/hostapd@.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
service <!> name:hostapd :%i \
[2345] hostapd -P/var/run/hostapd-%i.pid /etc/hostapd-%i.conf \
-- Hostapd (Wi-Fi AccessPoint, 802.1X) @%i

3 changes: 2 additions & 1 deletion board/common/rootfs/etc/udev/rules.d/70-rename-wifi.rules
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
SUBSYSTEM=="net", ACTION=="add", TEST=="/sys/class/net/$name/wireless", NAME="wifi%n"
# Only rename physical interfaces, skip virtual ones created by hostapd
SUBSYSTEM=="net", ACTION=="add", TEST=="/sys/class/net/$name/wireless", TEST=="/sys/class/net/$name/device", KERNEL!="*_*", NAME="wifi%n"
95 changes: 95 additions & 0 deletions board/common/rootfs/usr/libexec/infix/wifi-ap-stations
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
#!/usr/bin/env python3

import sys
import subprocess
import json
import re
import os

def check_interface_exists(interface):
"""Check if the network interface exists"""
try:
result = subprocess.run(['ip', 'link', 'show', interface],
capture_output=True, check=True)
return True
except subprocess.CalledProcessError:
return False

def parse_iw_station_dump(interface):
"""Parse iw station dump output and return JSON"""
try:
result = subprocess.run(['sudo', 'iw', 'dev', interface, 'station', 'dump'],
capture_output=True, text=True, check=True)
output = result.stdout
except subprocess.CalledProcessError as e:
print(f"Error running iw command: {e}", file=sys.stderr)
return []
except FileNotFoundError:
print("Error: 'iw' command not found", file=sys.stderr)
return []

stations = []
current_station = {}

for line in output.split('\n'):
line = line.strip()

if line.startswith('Station'):
if current_station:
stations.append(current_station)

mac_match = re.search(r'Station ([a-fA-F0-9:]{17})', line)
current_station = {
'mac-address': mac_match.group(1) if mac_match else 'unknown',
'tx-speed': 'unknown',
'rx-speed': 'unknown',
'rssi': 0,
'connected-time': 'unknown'
}

elif 'tx bitrate:' in line:
bitrate_match = re.search(r'tx bitrate:\s*(\d+\.?\d*)\s*(MBit/s|Gbit/s)', line)
if bitrate_match:
speed = bitrate_match.group(1)
unit = bitrate_match.group(2)
current_station['tx-speed'] = f"{speed} {unit.replace('Bit/s', 'bps')}"

elif 'rx bitrate:' in line:
bitrate_match = re.search(r'rx bitrate:\s*(\d+\.?\d*)\s*(MBit/s|Gbit/s)', line)
if bitrate_match:
speed = bitrate_match.group(1)
unit = bitrate_match.group(2)
current_station['rx-speed'] = f"{speed} {unit.replace('Bit/s', 'bps')}"

elif 'signal:' in line and 'avg' not in line:
signal_match = re.search(r'signal:\s*(-?\d+)', line)
if signal_match:
current_station['rssi'] = int(f"{signal_match.group(1)}")

elif 'connected time:' in line:
time_match = re.search(r'connected time:\s*(\d+\s+\w+)', line)
if time_match:
current_station['connected-time'] = time_match.group(1)

if current_station:
stations.append(current_station)

return stations

def main():
if len(sys.argv) != 2:
print("Usage: python3 wifi_station_parser.py <interface>")
print("Example: python3 wifi_station_parser.py wifi0_ap2")
sys.exit(1)

interface = sys.argv[1]

if not check_interface_exists(interface):
print(f"Error: Interface '{interface}' not found", file=sys.stderr)
sys.exit(1)

stations = parse_iw_station_dump(interface)
print(json.dumps(stations, indent=2))

if __name__ == "__main__":
main()
4 changes: 4 additions & 0 deletions package/feature-wifi/Config.in
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ config BR2_PACKAGE_FEATURE_WIFI
select BR2_PACKAGE_WPA_SUPPLICANT_AUTOSCAN
select BR2_PACKAGE_WPA_SUPPLICANT_CLI
select BR2_PACKAGE_WIRELESS_REGDB
select BR2_PACKAGE_HOSTAPD
select BR2_PACKAGE_HOSTAPD_DRIVER_NL80211
select BR2_PACKAGE_HOSTAPD_WPA3
select BR2_PACKAGE_HOSTAPD_WPS
select BR2_PACKAGE_IW
help
Enables WiFi in Infix. Enables all requried applications.
Expand Down
1 change: 0 additions & 1 deletion package/feature-wifi/feature-wifi.mk
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ define FEATURE_WIFI_LINUX_CONFIG_FIXUPS
$(call KCONFIG_ENABLE_OPT,CONFIG_RFKILL)
$(call KCONFIG_SET_OPT,CONFIG_MAC80211,m)
$(call KCONFIG_SET_OPT,CONFIG_CFG80211,m)

$(if $(filter y,$(BR2_PACKAGE_FEATURE_WIFI_DONGLE_REALTEK)),
$(call KCONFIG_ENABLE_OPT,CONFIG_WLAN_VENDOR_REALTEK)
$(call KCONFIG_ENABLE_OPT,CONFIG_RTW88)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@
},
{
"name": "wifi0",
"type": "infix-if-type:wifi"
"type": "infix-if-type:wifi",
"infix-interfaces:wifi": {}
}
]
},
Expand Down
39 changes: 27 additions & 12 deletions src/confd/src/ietf-interfaces.c
Original file line number Diff line number Diff line change
Expand Up @@ -425,6 +425,8 @@ static int netdag_gen_afspec_add(sr_session_ctx_t *session, struct dagger *net,
return vxlan_gen(NULL, cif, ip);
case IFT_WIFI:
return wifi_gen(NULL, cif, net);
case IFT_WIFI_AP:
return wifi_ap_add_iface(cif, net) || wifi_gen(NULL, wifi_ap_get_radio(cif), net);
case IFT_ETH:
return netdag_gen_ethtool(net, cif, dif);
case IFT_LO:
Expand Down Expand Up @@ -455,6 +457,11 @@ static int netdag_gen_afspec_set(sr_session_ctx_t *session, struct dagger *net,
return netdag_gen_ethtool(net, cif, dif);
case IFT_WIFI:
return wifi_gen(dif, cif, net);
case IFT_WIFI_AP: {
struct lyd_node *radio_if = wifi_ap_get_radio(cif);
return wifi_gen(NULL, radio_if, net);
return 0;
}
case IFT_DUMMY:
case IFT_GRE:
case IFT_GRETAP:
Expand Down Expand Up @@ -483,6 +490,8 @@ static bool netdag_must_del(struct lyd_node *dif, struct lyd_node *cif)
case IFT_WIFI:
case IFT_ETH:
return lydx_get_child(dif, "custom-phys-address");
case IFT_WIFI_AP:
return lydx_get_child(dif, "custom-phys-address");

case IFT_GRE:
case IFT_GRETAP:
Expand Down Expand Up @@ -572,9 +581,13 @@ static int netdag_gen_iface_del(struct dagger *net, struct lyd_node *dif,
eth_gen_del(dif, ip);
wifi_gen_del(dif, net);
break;
case IFT_WIFI_AP:
wifi_ap_del_iface(dif, net);
break;
case IFT_VETH:
veth_gen_del(dif, ip);
break;

case IFT_BRIDGE:
case IFT_DUMMY:
case IFT_GRE:
Expand Down Expand Up @@ -615,7 +628,6 @@ static sr_error_t netdag_gen_iface(sr_session_ctx_t *session, struct dagger *net
int err = 0;
FILE *ip;


err = netdag_gen_iface_timeout(net, ifname, iftype);
if (err)
goto err;
Expand Down Expand Up @@ -744,6 +756,7 @@ static int netdag_init_iface(struct lyd_node *cif)
case IFT_DUMMY:
case IFT_ETH:
case IFT_WIFI:
case IFT_WIFI_AP:
case IFT_GRE:
case IFT_GRETAP:
case IFT_LO:
Expand Down Expand Up @@ -897,18 +910,20 @@ static int keystorecb(sr_session_ctx_t *session, uint32_t sub_id, const char *mo

LYX_LIST_FOR_EACH(interfaces, interface, "interface") {
const char *name;

if (iftype_from_iface(interface) != IFT_WIFI)
continue;

wifi = lydx_get_child(interface, "wifi");
if (!wifi)
continue;

name = lydx_get_cattr(wifi, "secret");
if (!name || strcmp(name, secret_name))
enum iftype itype = iftype_from_iface(interface);

if (itype == IFT_WIFI) {
wifi = lydx_get_child(interface, "wifi");
if (!wifi)
continue;

name = lydx_get_cattr(wifi, "secret");
if (!name || strcmp(name, secret_name))
continue;
wifi_station_gen(interface, &confd->netdag);
} else {
continue;
wifi_gen(NULL, interface, &confd->netdag);
}
}
}

Expand Down
10 changes: 9 additions & 1 deletion src/confd/src/ietf-interfaces.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
_map(IFT_DUMMY, "infix-if-type:dummy") \
_map(IFT_ETH, "infix-if-type:ethernet") \
_map(IFT_WIFI, "infix-if-type:wifi") \
_map(IFT_WIFI_AP, "infix-if-type:wifi-ap") \
_map(IFT_GRE, "infix-if-type:gre") \
_map(IFT_GRETAP, "infix-if-type:gretap") \
_map(IFT_LAG, "infix-if-type:lag") \
Expand Down Expand Up @@ -122,7 +123,14 @@ int bridge_port_gen(struct lyd_node *dif, struct lyd_node *cif, FILE *ip);

/* infix-if-wifi.c */
int wifi_gen(struct lyd_node *dif, struct lyd_node *cif, struct dagger *net);
int wifi_gen_del(struct lyd_node *dif, struct dagger *net);
int wifi_station_gen(struct lyd_node *cif, struct dagger *net);
int wifi_ap_add_iface(struct lyd_node *cif,struct dagger *net);
int wifi_ap_del_iface(struct lyd_node *cif,struct dagger *net);
int wifi_ap_gen(struct lyd_node *cif, struct dagger *net);
int wifi_gen_del(struct lyd_node *iface, struct dagger *net);
int wifi_is_accesspoint(struct lyd_node *cif);
bool wifi_ap_must_delete(struct lyd_node *dif);
struct lyd_node *wifi_ap_get_radio(struct lyd_node *cif);

/* infix-if-gre.c */
int gre_gen(struct lyd_node *dif, struct lyd_node *cif, FILE *ip);
Expand Down
Loading