hostapd: add ucode support, use ucode for the main ubus object

This implements vastly improved dynamic configuration reload support.
It can handle configuration changes on individual wifi interfaces, as well
as adding/removing interfaces.

Signed-off-by: Felix Fietkau <nbd@nbd.name>
This commit is contained in:
Felix Fietkau 2023-05-26 10:23:59 +02:00
parent 33e4ad767e
commit e56c5f7b27
24 changed files with 2360 additions and 705 deletions

View File

@ -15,12 +15,9 @@ MP_CONFIG_INT="mesh_retry_timeout mesh_confirm_timeout mesh_holding_timeout mesh
MP_CONFIG_BOOL="mesh_auto_open_plinks mesh_fwding"
MP_CONFIG_STRING="mesh_power_mode"
NEWAPLIST=
OLDAPLIST=
NEWSPLIST=
OLDSPLIST=
NEWUMLIST=
OLDUMLIST=
wdev_tool() {
ucode /usr/share/hostap/wdev.uc "$@"
}
drv_mac80211_init_device_config() {
hostapd_common_add_device_config
@ -661,74 +658,6 @@ mac80211_check_ap() {
has_ap=1
}
mac80211_iw_interface_add() {
local phy="$1"
local ifname="$2"
local type="$3"
local wdsflag="$4"
local rc
local oldifname
iw phy "$phy" interface add "$ifname" type "$type" $wdsflag >/dev/null 2>&1
rc="$?"
[ "$rc" = 233 ] && {
# Device might have just been deleted, give the kernel some time to finish cleaning it up
sleep 1
iw phy "$phy" interface add "$ifname" type "$type" $wdsflag >/dev/null 2>&1
rc="$?"
}
[ "$rc" = 233 ] && {
# Keep matching pre-existing interface
[ -d "/sys/class/ieee80211/${phy}/device/net/${ifname}" ] && \
case "$(iw dev $ifname info | grep "^\ttype" | cut -d' ' -f2- 2>/dev/null)" in
"AP")
[ "$type" = "__ap" ] && rc=0
;;
"IBSS")
[ "$type" = "adhoc" ] && rc=0
;;
"managed")
[ "$type" = "managed" ] && rc=0
;;
"mesh point")
[ "$type" = "mp" ] && rc=0
;;
"monitor")
[ "$type" = "monitor" ] && rc=0
;;
esac
}
[ "$rc" = 233 ] && {
iw dev "$ifname" del >/dev/null 2>&1
[ "$?" = 0 ] && {
sleep 1
iw phy "$phy" interface add "$ifname" type "$type" $wdsflag >/dev/null 2>&1
rc="$?"
}
}
[ "$rc" != 0 ] && {
# Device might not support virtual interfaces, so the interface never got deleted in the first place.
# Check if the interface already exists, and avoid failing in this case.
[ -d "/sys/class/ieee80211/${phy}/device/net/${ifname}" ] && rc=0
}
[ "$rc" != 0 ] && {
# Device doesn't support virtual interfaces and may have existing interface other than ifname.
oldifname="$(basename "/sys/class/ieee80211/${phy}/device/net"/* 2>/dev/null)"
[ "$oldifname" ] && ip link set "$oldifname" name "$ifname" 1>/dev/null 2>&1
rc="$?"
}
[ "$rc" != 0 ] && echo "Failed to create interface $ifname"
return $rc
}
mac80211_set_ifname() {
local phy="$1"
local prefix="$2"
@ -752,10 +681,10 @@ mac80211_prepare_vif() {
mac80211_set_ifname "$phy" "$prefix"
}
append active_ifnames "$ifname"
set_default wds 0
set_default powersave 0
json_select ..
json_add_string _ifname "$ifname"
if [ -z "$macaddr" ]; then
macaddr="$(mac80211_generate_mac $phy)"
@ -763,10 +692,9 @@ mac80211_prepare_vif() {
elif [ "$macaddr" = 'random' ]; then
macaddr="$(macaddr_random)"
fi
json_add_string _macaddr "$macaddr"
json_select ..
json_add_object data
json_add_string ifname "$ifname"
json_close_object
[ "$mode" == "ap" ] && {
[ -z "$wpa_psk_file" ] && hostapd_set_psk "$ifname"
@ -777,9 +705,6 @@ mac80211_prepare_vif() {
# It is far easier to delete and create the desired interface
case "$mode" in
adhoc)
mac80211_iw_interface_add "$phy" "$ifname" adhoc || return
;;
ap)
# Hostapd will handle recreating the interface and
# subsequent virtual APs belonging to the same PHY
@ -791,114 +716,16 @@ mac80211_prepare_vif() {
mac80211_hostapd_setup_bss "$phy" "$ifname" "$macaddr" "$type" || return
NEWAPLIST="${NEWAPLIST}$ifname "
[ -n "$hostapd_ctrl" ] || {
ap_ifname="${ifname}"
hostapd_ctrl="${hostapd_ctrl:-/var/run/hostapd/$ifname}"
}
;;
mesh)
mac80211_iw_interface_add "$phy" "$ifname" mp || return
;;
monitor)
mac80211_iw_interface_add "$phy" "$ifname" monitor || return
;;
sta)
local wdsflag=
[ "$enable" = 0 ] || staidx="$(($staidx + 1))"
[ "$wds" -gt 0 ] && wdsflag="4addr on"
mac80211_iw_interface_add "$phy" "$ifname" managed "$wdsflag" || return
if [ "$wds" -gt 0 ]; then
iw "$ifname" set 4addr on
else
iw "$ifname" set 4addr off
fi
[ "$powersave" -gt 0 ] && powersave="on" || powersave="off"
iw "$ifname" set power_save "$powersave"
;;
esac
case "$mode" in
monitor|mesh)
[ "$auto_channel" -gt 0 ] || iw dev "$ifname" set channel "$channel" $iw_htmode
;;
esac
if [ "$mode" != "ap" ]; then
# ALL ap functionality will be passed to hostapd
# All interfaces must have unique mac addresses
# which can either be explicitly set in the device
# section, or automatically generated
ip link set dev "$ifname" address "$macaddr"
fi
json_select ..
}
mac80211_setup_supplicant() {
local enable=$1
local add_sp=0
local spobj="$(ubus -S list | grep wpa_supplicant.${ifname})"
[ "$enable" = 0 ] && {
ubus call wpa_supplicant.${phy} config_remove "{\"iface\":\"$ifname\"}"
ip link set dev "$ifname" down
iw dev "$ifname" del
return 0
}
wpa_supplicant_prepare_interface "$ifname" nl80211 || {
iw dev "$ifname" del
return 1
}
if [ "$mode" = "sta" ]; then
wpa_supplicant_add_network "$ifname"
else
wpa_supplicant_add_network "$ifname" "$freq" "$htmode" "$noscan"
fi
NEWSPLIST="${NEWSPLIST}$ifname "
if [ "${NEWAPLIST%% *}" != "${OLDAPLIST%% *}" ]; then
[ "$spobj" ] && ubus call wpa_supplicant config_remove "{\"iface\":\"$ifname\"}"
add_sp=1
fi
[ -z "$spobj" ] && add_sp=1
NEW_MD5_SP=$(test -e "${_config}" && md5sum ${_config})
OLD_MD5_SP=$(uci -q -P /var/state get wireless._${phy}.md5_${ifname})
if [ "$add_sp" = "1" ]; then
wpa_supplicant_run "$ifname" "$hostapd_ctrl"
else
[ "${NEW_MD5_SP}" == "${OLD_MD5_SP}" ] || ubus call $spobj reload
fi
uci -q -P /var/state set wireless._${phy}.md5_${ifname}="${NEW_MD5_SP}"
return 0
}
mac80211_setup_supplicant_noctl() {
local enable=$1
local spobj="$(ubus -S list | grep wpa_supplicant.${ifname})"
wpa_supplicant_prepare_interface "$ifname" nl80211 || {
iw dev "$ifname" del
return 1
}
wpa_supplicant_add_network "$ifname" "$freq" "$htmode" "$noscan"
NEWSPLIST="${NEWSPLIST}$ifname "
[ "$enable" = 0 ] && {
ubus call wpa_supplicant config_remove "{\"iface\":\"$ifname\"}"
ip link set dev "$ifname" down
return 0
}
if [ -z "$spobj" ]; then
wpa_supplicant_run "$ifname"
else
ubus call $spobj reload
fi
}
mac80211_prepare_iw_htmode() {
case "$htmode" in
VHT20|HT20|HE20) iw_htmode=HT20;;
@ -936,6 +763,13 @@ mac80211_prepare_iw_htmode() {
esac
}
mac80211_add_mesh_params() {
for var in $MP_CONFIG_INT $MP_CONFIG_BOOL $MP_CONFIG_STRING; do
eval "mp_val=\"\$var\""
[ -n "$mp_val" ] && json_add_string "$var" "$mp_val"
done
}
mac80211_setup_adhoc() {
local enable=$1
json_get_vars bssid ssid key mcast_rate
@ -977,82 +811,216 @@ mac80211_setup_adhoc() {
mcval=
[ -n "$mcast_rate" ] && wpa_supplicant_add_rate mcval "$mcast_rate"
iw dev "$ifname" set type ibss
iw dev "$ifname" ibss join "$ssid" $freq $iw_htmode fixed-freq $bssid \
beacon-interval $beacon_int \
${brstr:+basic-rates $brstr} \
${mcval:+mcast-rate $mcval} \
${keyspec:+keys $keyspec}
local prev
json_set_namespace wdev_uc prev
json_add_object "$ifname"
json_add_string mode adhoc
json_add_string macaddr "$macaddr"
json_add_string ssid "$ssid"
json_add_string freq "$freq"
json_add_string htmode "$iw_htmode"
[ -n "$bssid" ] && json_add_string bssid "$bssid"
json_add_int beacon-interval "$beacon_int"
[ -n "$brstr" ] && json_add_string basic-rates "$brstr"
[ -n "$mcval" ] && json_add_string mcast-rate "$mcval"
[ -n "$keyspec" ] && json_add_string keys "$keyspec"
json_close_object
json_set_namespace "$prev"
}
mac80211_setup_mesh() {
local enable=$1
json_get_vars ssid mesh_id mcast_rate
NEWUMLIST="${NEWUMLIST}$ifname "
[ "$enable" = 0 ] && {
ip link set dev "$ifname" down
return 0
}
mcval=
[ -n "$mcast_rate" ] && wpa_supplicant_add_rate mcval "$mcast_rate"
[ -n "$mesh_id" ] && ssid="$mesh_id"
iw dev "$ifname" mesh join "$ssid" freq $freq $iw_htmode \
${mcval:+mcast-rate $mcval} \
beacon-interval $beacon_int
local prev
json_set_namespace wdev_uc prev
json_add_object "$ifname"
json_add_string mode mesh
json_add_string macaddr "$macaddr"
json_add_string ssid "$ssid"
json_add_string freq "$freq"
json_add_string htmode "$iw_htmode"
[ -n "$mcval" ] && json_add_string mcast-rate "$mcval"
json_add_int beacon-interval "$beacon_int"
mac80211_add_mesh_params
json_close_object
json_set_namespace "$prev"
}
mac80211_setup_monitor() {
local prev
json_set_namespace wdev_uc prev
json_add_object "$ifname"
json_add_string mode monitor
[ -n "$freq" ] && json_add_string freq "$freq"
json_add_string htmode "$iw_htmode"
json_close_object
json_set_namespace "$prev"
}
mac80211_set_vif_txpower() {
local name="$1"
json_select config
json_get_var ifname _ifname
json_get_vars vif_txpower
json_select ..
[ -z "$vif_txpower" ] || iw dev "$ifname" set txpower fixed "${vif_txpower%%.*}00"
}
wpa_supplicant_init_config() {
json_set_namespace wpa_supp prev
json_init
json_add_array config
json_set_namespace "$prev"
}
wpa_supplicant_add_interface() {
local ifname="$1"
local mode="$2"
local hostapd_ctrl="$3"
local prev
_wpa_supplicant_common "$ifname"
json_set_namespace wpa_supp prev
json_add_object
json_add_string ctrl "$_rpath"
json_add_string iface "$ifname"
json_add_string mode "$mode"
json_add_string config "$_config"
json_add_string macaddr "$macaddr"
[ -n "$network_bridge" ] && json_add_string bridge "$network_bridge"
[ -n "$hostapd_ctrl" ] && json_add_string hostapd_ctrl "$hostapd_ctrl"
[ -n "$wds" ] && json_add_boolean 4addr "$wds"
json_add_boolean powersave "$powersave"
[ "$mode" = "mesh" ] && mac80211_add_mesh_params
json_close_object
json_set_namespace "$prev"
wpa_supp_init=1
}
wpa_supplicant_set_config() {
local phy="$1"
local prev
json_set_namespace wpa_supp prev
json_close_array
json_add_string phy "$phy"
json_add_boolean defer 1
local data="$(json_dump)"
json_cleanup
json_set_namespace "$prev"
ubus -S -t 0 wait_for wpa_supplicant || {
[ -n "$wpa_supp_init" ] || return 0
ubus wait_for wpa_supplicant
}
local supplicant_res="$(ubus call wpa_supplicant config_set "$data")"
ret="$?"
[ "$ret" != 0 -o -z "$supplicant_res" ] && wireless_setup_vif_failed WPA_SUPPLICANT_FAILED
wireless_add_process "$(jsonfilter -s "$supplicant_res" -l 1 -e @.pid)" "/usr/sbin/wpa_supplicant" 1 1
}
hostapd_set_config() {
[ -n "$hostapd_ctrl" ] || {
ubus call hostapd config_set '{ "phy": "'"$phy"'", "config": "", "prev_config": "'"${hostapd_conf_file}.prev"'" }' > /dev/null
return 0;
}
ubus wait_for hostapd
local hostapd_res="$(ubus call hostapd config_set "{ \"phy\": \"$phy\", \"config\":\"${hostapd_conf_file}\", \"prev_config\": \"${hostapd_conf_file}.prev\"}")"
ret="$?"
[ "$ret" != 0 -o -z "$hostapd_res" ] && {
wireless_setup_failed HOSTAPD_START_FAILED
return
}
wireless_add_process "$(jsonfilter -s "$hostapd_res" -l 1 -e @.pid)" "/usr/sbin/hostapd" 1 1
}
wpa_supplicant_start() {
local phy="$1"
[ -n "$wpa_supp_init" ] || return 0
ubus call wpa_supplicant config_set '{ "phy": "'"$phy"'" }' > /dev/null
}
mac80211_setup_supplicant() {
local enable=$1
local add_sp=0
wpa_supplicant_prepare_interface "$ifname" nl80211 || return 1
if [ "$mode" = "sta" ]; then
wpa_supplicant_add_network "$ifname"
else
wpa_supplicant_add_network "$ifname" "$freq" "$htmode" "$noscan"
fi
wpa_supplicant_add_interface "$ifname" "$mode" "$hostapd_ctrl"
return 0
}
mac80211_setup_vif() {
local name="$1"
local failed
local action=up
json_select data
json_get_vars ifname
json_select ..
json_select config
json_get_vars mode
json_get_var vif_txpower
json_get_var vif_enable enable 1
json_get_var ifname _ifname
json_get_var macaddr _macaddr
json_get_vars mode wds powersave
[ "$vif_enable" = 1 ] || action=down
if [ "$mode" != "ap" ] || [ "$ifname" = "$ap_ifname" ]; then
ip link set dev "$ifname" "$action" || {
wireless_setup_vif_failed IFUP_ERROR
json_select ..
return
}
[ -z "$vif_txpower" ] || iw dev "$ifname" set txpower fixed "${vif_txpower%%.*}00"
fi
set_default powersave 0
set_default wds 0
case "$mode" in
mesh)
json_get_vars $MP_CONFIG_INT $MP_CONFIG_BOOL $MP_CONFIG_STRING
wireless_vif_parse_encryption
[ -z "$htmode" ] && htmode="NOHT";
if wpa_supplicant -vmesh || [ "$wpa" -gt 0 -o "$auto_channel" -gt 0 ] || chan_is_dfs "$phy" "$channel"; then
mac80211_setup_supplicant $vif_enable || failed=1
if wpa_supplicant -vmesh; then
mac80211_setup_supplicant || failed=1
else
mac80211_setup_mesh $vif_enable
mac80211_setup_mesh
fi
for var in $MP_CONFIG_INT $MP_CONFIG_BOOL $MP_CONFIG_STRING; do
json_get_var mp_val "$var"
[ -n "$mp_val" ] && iw dev "$ifname" set mesh_param "$var" "$mp_val"
done
;;
adhoc)
wireless_vif_parse_encryption
if [ "$wpa" -gt 0 -o "$auto_channel" -gt 0 ]; then
mac80211_setup_supplicant_noctl $vif_enable || failed=1
mac80211_setup_supplicant || failed=1
else
mac80211_setup_adhoc $vif_enable
mac80211_setup_adhoc
fi
;;
sta)
mac80211_setup_supplicant $vif_enable || failed=1
mac80211_setup_supplicant || failed=1
;;
monitor)
mac80211_setup_monitor
;;
esac
@ -1085,7 +1053,6 @@ band_match && $3 == "MHz" && $4 == channel {
'
}
chan_is_dfs() {
local phy="$1"
local chan="$2"
@ -1093,27 +1060,6 @@ chan_is_dfs() {
return $!
}
mac80211_vap_cleanup() {
local service="$1"
local vaps="$2"
for wdev in $vaps; do
[ "$service" != "none" ] && ubus call ${service} config_remove "{\"iface\":\"$wdev\"}"
ip link set dev "$wdev" down 2>/dev/null
iw dev "$wdev" del
done
}
mac80211_interface_cleanup() {
local phy="$1"
local primary_ap=$(uci -q -P /var/state get wireless._${phy}.aplist)
primary_ap=${primary_ap%% *}
mac80211_vap_cleanup hostapd "${primary_ap}"
mac80211_vap_cleanup wpa_supplicant "$(uci -q -P /var/state get wireless._${phy}.splist)"
mac80211_vap_cleanup none "$(uci -q -P /var/state get wireless._${phy}.umlist)"
}
mac80211_set_noscan() {
hostapd_noscan=1
}
@ -1122,6 +1068,15 @@ drv_mac80211_cleanup() {
hostapd_common_cleanup
}
mac80211_reset_config() {
local phy="$1"
hostapd_conf_file="/var/run/hostapd-$phy.conf"
ubus call hostapd config_set '{ "phy": "'"$phy"'", "config": "", "prev_config": "'"$hostapd_conf_file"'" }' > /dev/null
ubus call wpa_supplicant config_set '{ "phy": "'"$phy"'", "config": [] }' > /dev/null
wdev_tool "$phy" '{}'
}
drv_mac80211_setup() {
json_select config
json_get_vars \
@ -1141,30 +1096,11 @@ drv_mac80211_setup() {
}
wireless_set_data phy="$phy"
[ -z "$(uci -q -P /var/state show wireless._${phy})" ] && uci -q -P /var/state set wireless._${phy}=phy
OLDAPLIST=$(uci -q -P /var/state get wireless._${phy}.aplist)
OLDSPLIST=$(uci -q -P /var/state get wireless._${phy}.splist)
OLDUMLIST=$(uci -q -P /var/state get wireless._${phy}.umlist)
local wdev
local cwdev
local found
for wdev in $(list_phy_interfaces "$phy"); do
found=0
for cwdev in $OLDAPLIST $OLDSPLIST $OLDUMLIST; do
if [ "$wdev" = "$cwdev" ]; then
found=1
break
fi
done
if [ "$found" = "0" ]; then
ip link set dev "$wdev" down
iw dev "$wdev" del
fi
done
# convert channel to frequency
[ "$auto_channel" -gt 0 ] || freq="$(get_freq "$phy" "$channel" "$band")"
@ -1177,7 +1113,6 @@ drv_mac80211_setup() {
hostapd_conf_file="/var/run/hostapd-$phy.conf"
no_ap=1
macidx=0
staidx=0
@ -1212,78 +1147,36 @@ drv_mac80211_setup() {
hostapd_ctrl=
ap_ifname=
hostapd_noscan=
wpa_supp_init=
for_each_interface "ap" mac80211_check_ap
rm -f "$hostapd_conf_file"
[ -f "$hostapd_conf_file" ] && mv "$hostapd_conf_file" "$hostapd_conf_file.prev"
for_each_interface "sta adhoc mesh" mac80211_set_noscan
[ -n "$has_ap" ] && mac80211_hostapd_setup_base "$phy"
local prev
json_set_namespace wdev_uc prev
json_init
json_set_namespace "$prev"
wpa_supplicant_init_config
mac80211_prepare_iw_htmode
for_each_interface "sta adhoc mesh monitor" mac80211_prepare_vif
NEWAPLIST=
for_each_interface "ap" mac80211_prepare_vif
NEW_MD5=$(test -e "${hostapd_conf_file}" && md5sum ${hostapd_conf_file})
OLD_MD5=$(uci -q -P /var/state get wireless._${phy}.md5)
if [ "${NEWAPLIST}" != "${OLDAPLIST}" ]; then
mac80211_vap_cleanup hostapd "${OLDAPLIST}"
fi
[ -n "${NEWAPLIST}" ] && mac80211_iw_interface_add "$phy" "${NEWAPLIST%% *}" __ap
local add_ap=0
local primary_ap=${NEWAPLIST%% *}
[ -n "$hostapd_ctrl" ] && {
local no_reload=1
if [ -n "$(ubus list | grep hostapd.$primary_ap)" ]; then
no_reload=0
[ "${NEW_MD5}" = "${OLD_MD5}" ] || {
ubus call hostapd.$primary_ap reload
no_reload=$?
if [ "$no_reload" != "0" ]; then
mac80211_vap_cleanup hostapd "${OLDAPLIST}"
mac80211_vap_cleanup wpa_supplicant "$(uci -q -P /var/state get wireless._${phy}.splist)"
mac80211_vap_cleanup none "$(uci -q -P /var/state get wireless._${phy}.umlist)"
sleep 2
mac80211_iw_interface_add "$phy" "${NEWAPLIST%% *}" __ap
for_each_interface "sta adhoc mesh monitor" mac80211_prepare_vif
fi
}
fi
if [ "$no_reload" != "0" ]; then
add_ap=1
ubus wait_for hostapd
local hostapd_res="$(ubus call hostapd config_add "{\"iface\":\"$primary_ap\", \"config\":\"${hostapd_conf_file}\"}")"
ret="$?"
[ "$ret" != 0 -o -z "$hostapd_res" ] && {
wireless_setup_failed HOSTAPD_START_FAILED
return
}
wireless_add_process "$(jsonfilter -s "$hostapd_res" -l 1 -e @.pid)" "/usr/sbin/hostapd" 1 1
fi
}
uci -q -P /var/state set wireless._${phy}.aplist="${NEWAPLIST}"
uci -q -P /var/state set wireless._${phy}.md5="${NEW_MD5}"
active_ifnames=
for_each_interface "ap sta adhoc mesh monitor" mac80211_prepare_vif
for_each_interface "ap sta adhoc mesh monitor" mac80211_setup_vif
[ "${add_ap}" = 1 ] && sleep 1
for_each_interface "ap" mac80211_setup_vif
[ -x /usr/sbin/wpa_supplicant ] && wpa_supplicant_set_config "$phy"
[ -x /usr/sbin/hostapd ] && hostapd_set_config "$phy"
NEWSPLIST=
NEWUMLIST=
[ -x /usr/sbin/wpa_supplicant ] && wpa_supplicant_start "$phy"
for_each_interface "sta adhoc mesh monitor" mac80211_setup_vif
json_set_namespace wdev_uc prev
wdev_tool "$phy" "$(json_dump)" $active_ifnames
json_set_namespace "$prev"
uci -q -P /var/state set wireless._${phy}.splist="${NEWSPLIST}"
uci -q -P /var/state set wireless._${phy}.umlist="${NEWUMLIST}"
local foundvap
local dropvap=""
for oldvap in $OLDSPLIST; do
foundvap=0
for newvap in $NEWSPLIST; do
[ "$oldvap" = "$newvap" ] && foundvap=1
done
[ "$foundvap" = "0" ] && dropvap="$dropvap $oldvap"
done
[ -n "$dropvap" ] && mac80211_vap_cleanup wpa_supplicant "$dropvap"
for_each_interface "ap sta adhoc mesh monitor" mac80211_set_vif_txpower
wireless_set_up
}
@ -1314,8 +1207,12 @@ drv_mac80211_teardown() {
return 1
}
mac80211_interface_cleanup "$phy"
uci -q -P /var/state revert wireless._${phy}
mac80211_reset_config "$phy"
for wdev in $(list_phy_interfaces "$phy"); do
ip link set dev "$wdev" down
iw dev "$wdev" del
done
}
add_driver mac80211

View File

@ -81,12 +81,15 @@ ifneq ($(CONFIG_DRIVER_11AX_SUPPORT),)
HOSTAPD_IEEE80211AX:=y
endif
CORE_DEPENDS = +ucode +libubus +libucode +ucode-mod-fs +ucode-mod-nl80211 +ucode-mod-rtnl +ucode-mod-ubus +ucode-mod-uloop +libblobmsg-json
DRIVER_MAKEOPTS= \
CONFIG_ACS=$(CONFIG_PACKAGE_kmod-cfg80211) \
CONFIG_DRIVER_NL80211=$(CONFIG_PACKAGE_kmod-cfg80211) \
CONFIG_IEEE80211AC=$(HOSTAPD_IEEE80211AC) \
CONFIG_IEEE80211AX=$(HOSTAPD_IEEE80211AX) \
CONFIG_MBO=$(CONFIG_WPA_MBO_SUPPORT)
CONFIG_MBO=$(CONFIG_WPA_MBO_SUPPORT) \
CONFIG_UCODE=y
ifeq ($(SSL_VARIANT),openssl)
DRIVER_MAKEOPTS += CONFIG_TLS=openssl CONFIG_SAE=y
@ -148,7 +151,7 @@ define Package/hostapd/Default
SUBMENU:=WirelessAPD
TITLE:=IEEE 802.1x Authenticator
URL:=http://hostap.epitest.fi/
DEPENDS:=$(DRV_DEPENDS) +hostapd-common +libubus +libblobmsg-json
DEPENDS:=$(DRV_DEPENDS) +hostapd-common $(CORE_DEPENDS)
EXTRA_DEPENDS:=hostapd-common (=$(PKG_VERSION)-$(PKG_RELEASE))
USERID:=network=101:network=101
PROVIDES:=hostapd
@ -253,7 +256,7 @@ define Package/wpad/Default
CATEGORY:=Network
SUBMENU:=WirelessAPD
TITLE:=IEEE 802.1x Auth/Supplicant
DEPENDS:=$(DRV_DEPENDS) +hostapd-common +libubus +libblobmsg-json
DEPENDS:=$(DRV_DEPENDS) +hostapd-common $(CORE_DEPENDS)
EXTRA_DEPENDS:=hostapd-common (=$(PKG_VERSION)-$(PKG_RELEASE))
USERID:=network=101:network=101
URL:=http://hostap.epitest.fi/
@ -398,7 +401,7 @@ define Package/wpa-supplicant/Default
SUBMENU:=WirelessAPD
TITLE:=WPA Supplicant
URL:=http://hostap.epitest.fi/wpa_supplicant/
DEPENDS:=$(DRV_DEPENDS) +hostapd-common +libubus +libblobmsg-json
DEPENDS:=$(DRV_DEPENDS) +hostapd-common $(CORE_DEPENDS)
EXTRA_DEPENDS:=hostapd-common (=$(PKG_VERSION)-$(PKG_RELEASE))
USERID:=network=101:network=101
PROVIDES:=wpa-supplicant
@ -520,7 +523,7 @@ define Package/eapol-test/Default
SECTION:=net
SUBMENU:=WirelessAPD
CATEGORY:=Network
DEPENDS:=$(DRV_DEPENDS) +libubus +libblobmsg-json
DEPENDS:=$(DRV_DEPENDS) $(CORE_DEPENDS)
endef
define Package/eapol-test
@ -585,7 +588,7 @@ TARGET_CPPFLAGS := \
-D_GNU_SOURCE \
$(if $(CONFIG_WPA_MSG_MIN_PRIORITY),-DCONFIG_MSG_MIN_PRIORITY=$(CONFIG_WPA_MSG_MIN_PRIORITY))
TARGET_LDFLAGS += -lubox -lubus -lblobmsg_json
TARGET_LDFLAGS += -lubox -lubus -lblobmsg_json -lucode
ifdef CONFIG_PACKAGE_kmod-cfg80211
TARGET_LDFLAGS += -lm -lnl-tiny
@ -703,22 +706,26 @@ Package/hostapd-mbedtls/conffiles = $(Package/hostapd-full/conffiles)
endif
define Install/hostapd
$(INSTALL_DIR) $(1)/usr/sbin
$(INSTALL_DIR) $(1)/usr/sbin $(1)/usr/share/hostap
$(INSTALL_DATA) ./files/hostapd.uc $(1)/usr/share/hostap/
$(if $(findstring full,$(CONFIG_VARIANT)),$(Install/hostapd/full))
endef
define Install/supplicant
$(INSTALL_DIR) $(1)/usr/sbin
$(INSTALL_DIR) $(1)/usr/sbin $(1)/usr/share/hostap
$(INSTALL_DATA) ./files/wpa_supplicant.uc $(1)/usr/share/hostap/
endef
define Package/hostapd-common/install
$(INSTALL_DIR) $(1)/etc/capabilities $(1)/etc/rc.button $(1)/etc/hotplug.d/ieee80211 $(1)/etc/init.d $(1)/lib/netifd $(1)/usr/share/acl.d
$(INSTALL_DIR) $(1)/etc/capabilities $(1)/etc/rc.button $(1)/etc/hotplug.d/ieee80211 $(1)/etc/init.d $(1)/lib/netifd $(1)/usr/share/acl.d $(1)/usr/share/hostap
$(INSTALL_BIN) ./files/dhcp-get-server.sh $(1)/lib/netifd/dhcp-get-server.sh
$(INSTALL_DATA) ./files/hostapd.sh $(1)/lib/netifd/hostapd.sh
$(INSTALL_BIN) ./files/wpad.init $(1)/etc/init.d/wpad
$(INSTALL_BIN) ./files/wps-hotplug.sh $(1)/etc/rc.button/wps
$(INSTALL_DATA) ./files/wpad_acl.json $(1)/usr/share/acl.d
$(INSTALL_DATA) ./files/wpad.json $(1)/etc/capabilities
$(INSTALL_DATA) ./files/common.uc $(1)/usr/share/hostap/
$(INSTALL_DATA) ./files/wdev.uc $(1)/usr/share/hostap/
endef
define Package/hostapd/install

View File

@ -0,0 +1,168 @@
import * as nl80211 from "nl80211";
import * as rtnl from "rtnl";
import { readfile } from "fs";
const iftypes = {
ap: nl80211.const.NL80211_IFTYPE_AP,
mesh: nl80211.const.NL80211_IFTYPE_MESH_POINT,
sta: nl80211.const.NL80211_IFTYPE_STATION,
adhoc: nl80211.const.NL80211_IFTYPE_ADHOC,
monitor: nl80211.const.NL80211_IFTYPE_MONITOR,
};
function wdev_remove(name)
{
nl80211.request(nl80211.const.NL80211_CMD_DEL_INTERFACE, 0, { dev: name });
}
function __phy_is_fullmac(phyidx)
{
let data = nl80211.request(nl80211.const.NL80211_CMD_GET_WIPHY, 0, { wiphy: phyidx });
return !data.software_iftypes.ap_vlan;
}
function phy_is_fullmac(phy)
{
let phyidx = int(trim(readfile(`/sys/class/ieee80211/${phy}/index`)));
return __phy_is_fullmac(phyidx);
}
function find_reusable_wdev(phyidx)
{
if (!__phy_is_fullmac(phyidx))
return null;
data = nl80211.request(
nl80211.const.NL80211_CMD_GET_INTERFACE,
nl80211.const.NLM_F_DUMP,
{ wiphy: phyidx });
for (let res in data)
if (trim(readfile(`/sys/class/net/${res.ifname}/operstate`)) == "down")
return res.ifname;
return null;
}
function wdev_create(phy, name, data)
{
let phyidx = int(readfile(`/sys/class/ieee80211/${phy}/index`));
wdev_remove(name);
if (!iftypes[data.mode])
return `Invalid mode: ${data.mode}`;
let req = {
wiphy: phyidx,
ifname: name,
iftype: iftypes[data.mode],
};
if (data["4addr"])
req["4addr"] = data["4addr"];
if (data.macaddr)
req.mac = data.macaddr;
nl80211.error();
let reuse_ifname = find_reusable_wdev(phyidx);
if (reuse_ifname &&
(reuse_ifname == name ||
rtnl.request(rtnl.const.RTM_SETLINK, 0, { dev: reuse_ifname, ifname: name}) != false))
nl80211.request(
nl80211.const.NL80211_CMD_SET_INTERFACE, 0, {
wiphy: phyidx,
dev: name,
iftype: iftypes[data.mode],
});
else
nl80211.request(
nl80211.const.NL80211_CMD_NEW_INTERFACE,
nl80211.const.NLM_F_CREATE,
req);
let error = nl80211.error();
if (error)
return error;
if (data.powersave != null) {
nl80211.request(nl80211.const.NL80211_CMD_SET_POWER_SAVE, 0,
{ dev: name, ps_state: data.powersave ? 1 : 0});
}
return null;
}
const vlist_proto = {
update: function(values, arg) {
let data = this.data;
let cb = this.cb;
let seq = { };
let new_data = {};
let old_data = {};
this.data = new_data;
if (type(values) == "object") {
for (let key in values) {
old_data[key] = data[key];
new_data[key] = values[key];
delete data[key];
}
} else {
for (let val in values) {
let cur_key = val[0];
let cur_obj = val[1];
old_data[cur_key] = data[cur_key];
new_data[cur_key] = val[1];
delete data[cur_key];
}
}
for (let key in data) {
cb(null, data[key], arg);
delete data[key];
}
for (let key in new_data)
cb(new_data[key], old_data[key], arg);
}
};
function is_equal(val1, val2) {
let t1 = type(val1);
if (t1 != type(val2))
return false;
if (t1 == "array") {
if (length(val1) != length(val2))
return false;
for (let i = 0; i < length(val1); i++)
if (!is_equal(val1[i], val2[i]))
return false;
return true;
} else if (t1 == "object") {
for (let key in val1)
if (!is_equal(val1[key], val2[key]))
return false;
for (let key in val2)
if (!val1[key])
return false;
return true;
} else {
return val1 == val2;
}
}
function vlist_new(cb) {
return proto({
cb: cb,
data: {}
}, vlist_proto);
}
export { wdev_remove, wdev_create, is_equal, vlist_new, phy_is_fullmac };

View File

@ -1591,29 +1591,6 @@ EOF
return 0
}
wpa_supplicant_run() {
local ifname="$1"
local hostapd_ctrl="$2"
_wpa_supplicant_common "$ifname"
ubus wait_for wpa_supplicant
local supplicant_res="$(ubus call wpa_supplicant config_add "{ \
\"driver\": \"${_w_driver:-wext}\", \"ctrl\": \"$_rpath\", \
\"iface\": \"$ifname\", \"config\": \"$_config\" \
${network_bridge:+, \"bridge\": \"$network_bridge\"} \
${hostapd_ctrl:+, \"hostapd_ctrl\": \"$hostapd_ctrl\"} \
}")"
ret="$?"
[ "$ret" != 0 -o -z "$supplicant_res" ] && wireless_setup_vif_failed WPA_SUPPLICANT_FAILED
wireless_add_process "$(jsonfilter -s "$supplicant_res" -l 1 -e @.pid)" "/usr/sbin/wpa_supplicant" 1 1
return $ret
}
hostapd_common_cleanup() {
killall meshd-nl80211
}

View File

@ -0,0 +1,399 @@
let libubus = require("ubus");
import { open, readfile } from "fs";
import { wdev_create, wdev_remove, is_equal, vlist_new, phy_is_fullmac } from "common";
let ubus = libubus.connect();
hostapd.data.config = {};
hostapd.data.file_fields = {
vlan_file: true,
wpa_psk_file: true,
accept_mac_file: true,
deny_mac_file: true,
eap_user_file: true,
ca_cert: true,
server_cert: true,
server_cert2: true,
private_key: true,
private_key2: true,
dh_file: true,
eap_sim_db: true,
};
function iface_remove(cfg)
{
if (!cfg || !cfg.bss || !cfg.bss[0] || !cfg.bss[0].ifname)
return;
hostapd.remove_iface(cfg.bss[0].ifname);
for (let bss in cfg.bss)
wdev_remove(bss.ifname);
}
function iface_gen_config(phy, config)
{
let str = `data:
${join("\n", config.radio.data)}
channel=${config.radio.channel}
`;
for (let i = 0; i < length(config.bss); i++) {
let bss = config.bss[i];
let type = i > 0 ? "bss" : "interface";
str += `
${type}=${bss.ifname}
${join("\n", bss.data)}
`;
}
return str;
}
function iface_restart(phy, config, old_config)
{
iface_remove(old_config);
iface_remove(config);
if (!config.bss || !config.bss[0]) {
hostapd.printf(`No bss for phy ${phy}`);
return;
}
let bss = config.bss[0];
let err = wdev_create(phy, bss.ifname, { mode: "ap" });
if (err)
hostapd.printf(`Failed to create ${bss.ifname} on phy ${phy}: ${err}`);
let config_inline = iface_gen_config(phy, config);
if (hostapd.add_iface(`bss_config=${bss.ifname}:${config_inline}`) < 0) {
hostapd.printf(`hostapd.add_iface failed for phy ${phy} ifname=${bss.ifname}`);
return;
}
}
function array_to_obj(arr, key, start)
{
let obj = {};
start ??= 0;
for (let i = start; i < length(arr); i++) {
let cur = arr[i];
obj[cur[key]] = cur;
}
return obj;
}
function find_array_idx(arr, key, val)
{
for (let i = 0; i < length(arr); i++)
if (arr[i][key] == val)
return i;
return -1;
}
function bss_reload_psk(bss, config, old_config)
{
if (is_equal(old_config.hash.wpa_psk_file, config.hash.wpa_psk_file))
return;
old_config.hash.wpa_psk_file = config.hash.wpa_psk_file;
if (!is_equal(old_config, config))
return;
let ret = bss.ctrl("RELOAD_WPA_PSK");
ret ??= "failed";
hostapd.printf(`Reload WPA PSK file for bss ${config.ifname}: ${ret}`);
}
function iface_reload_config(phy, config, old_config)
{
if (!old_config || !is_equal(old_config.radio, config.radio))
return false;
if (is_equal(old_config.bss, config.bss))
return true;
if (config.bss[0].ifname != old_config.bss[0].ifname)
return false;
let iface = hostapd.interfaces[config.bss[0].ifname];
if (!iface)
return false;
let config_inline = iface_gen_config(phy, config);
bss_reload_psk(iface.bss[0], config.bss[0], old_config.bss[0]);
if (!is_equal(config.bss[0], old_config.bss[0])) {
if (phy_is_fullmac(phy))
return false;
hostapd.printf(`Reload config for bss '${config.bss[0].ifname}' on phy '${phy}'`);
if (iface.bss[0].set_config(config_inline, 0) < 0) {
hostapd.printf(`Failed to set config`);
return false;
}
}
let bss_list = array_to_obj(iface.bss, "name", 1);
let new_cfg = array_to_obj(config.bss, "ifname", 1);
let old_cfg = array_to_obj(old_config.bss, "ifname", 1);
for (let name in old_cfg) {
let bss = bss_list[name];
if (!bss) {
hostapd.printf(`bss '${name}' not found`);
return false;
}
if (!new_cfg[name]) {
hostapd.printf(`Remove bss '${name}' on phy '${phy}'`);
bss.delete();
wdev_remove(name);
continue;
}
let new_cfg_data = new_cfg[name];
delete new_cfg[name];
if (is_equal(old_cfg[name], new_cfg_data))
continue;
hostapd.printf(`Reload config for bss '${name}' on phy '${phy}'`);
let idx = find_array_idx(config.bss, "ifname", name);
if (idx < 0) {
hostapd.printf(`bss index not found`);
return false;
}
if (bss.set_config(config_inline, idx) < 0) {
hostapd.printf(`Failed to set config`);
return false;
}
}
for (let name in new_cfg) {
hostapd.printf(`Add bss '${name}' on phy '${phy}'`);
let idx = find_array_idx(config.bss, "ifname", name);
if (idx < 0) {
hostapd.printf(`bss index not found`);
return false;
}
if (iface.add_bss(config_inline, idx) < 0) {
hostapd.printf(`Failed to add bss`);
return false;
}
}
return true;
}
function iface_set_config(phy, config)
{
let old_config = hostapd.data.config[phy];
hostapd.data.config[phy] = config;
if (!config)
return iface_remove(old_config);
let ret = iface_reload_config(phy, config, old_config);
if (ret) {
hostapd.printf(`Reloaded settings for phy ${phy}`);
return 0;
}
hostapd.printf(`Restart interface for phy ${phy}`);
return iface_restart(phy, config, old_config);
}
function config_add_bss(config, name)
{
let bss = {
ifname: name,
data: [],
hash: {}
};
push(config.bss, bss);
return bss;
}
function iface_load_config(filename)
{
let f = open(filename, "r");
if (!f)
return null;
let config = {
radio: {
data: []
},
bss: [],
orig_file: filename,
};
let bss;
let line;
while ((line = trim(f.read("line"))) != null) {
let val = split(line, "=", 2);
if (!val[0])
continue;
if (val[0] == "interface") {
bss = config_add_bss(config, val[1]);
break;
}
if (val[0] == "channel") {
config.radio.channel = val[1];
continue;
}
push(config.radio.data, line);
}
while ((line = trim(f.read("line"))) != null) {
let val = split(line, "=", 2);
if (!val[0])
continue;
if (val[0] == "bss") {
bss = config_add_bss(config, val[1]);
continue;
}
if (hostapd.data.file_fields[val[0]])
bss.hash[val[0]] = hostapd.sha1(readfile(val[1]));
push(bss.data, line);
}
f.close();
return config;
}
let main_obj = {
reload: {
args: {
phy: "",
},
call: function(req) {
try {
let phy_list = req.args.phy ? [ req.args.phy ] : keys(hostapd.data.config);
for (let phy_name in phy_list) {
let phy = hostapd.data.config[phy_name];
let config = iface_load_config(phy.orig_file);
iface_set_config(phy_name, config);
}
} catch(e) {
hostapd.printf(`Error reloading config: ${e}\n${e.stacktrace[0].context}`);
return libubus.STATUS_INVALID_ARGUMENT;
}
return 0;
}
},
config_set: {
args: {
phy: "",
config: "",
prev_config: "",
},
call: function(req) {
let phy = req.args.phy;
let file = req.args.config;
let prev_file = req.args.prev_config;
if (!phy)
return libubus.STATUS_INVALID_ARGUMENT;
try {
if (prev_file && !hostapd.data.config[phy]) {
let config = iface_load_config(prev_file);
if (config)
config.radio.data = [];
hostapd.data.config[phy] = config;
}
let config = iface_load_config(file);
hostapd.printf(`Set new config for phy ${phy}: ${file}`);
iface_set_config(phy, config);
} catch(e) {
hostapd.printf(`Error loading config: ${e}\n${e.stacktrace[0].context}`);
return libubus.STATUS_INVALID_ARGUMENT;
}
return {
pid: hostapd.getpid()
};
}
},
config_add: {
args: {
iface: "",
config: "",
},
call: function(req) {
if (!req.args.iface || !req.args.config)
return libubus.STATUS_INVALID_ARGUMENT;
if (hostapd.add_iface(`bss_config=${req.args.iface}:${req.args.config}`) < 0)
return libubus.STATUS_INVALID_ARGUMENT;
return {
pid: hostapd.getpid()
};
}
},
config_remove: {
args: {
iface: ""
},
call: function(req) {
if (!req.args.iface)
return libubus.STATUS_INVALID_ARGUMENT;
hostapd.remove_iface(req.args.iface);
return 0;
}
},
};
hostapd.data.ubus = ubus;
hostapd.data.obj = ubus.publish("hostapd", main_obj);
function bss_event(type, name, data) {
let ubus = hostapd.data.ubus;
data ??= {};
data.name = name;
hostapd.data.obj.notify(`bss.${type}`, data, null, null, null, -1);
ubus.call("service", "event", { type: `hostapd.${name}.${type}`, data: {} });
}
return {
shutdown: function() {
for (let phy in hostapd.data.config)
iface_set_config(phy, null);
hostapd.ubus.disconnect();
},
bss_add: function(name, obj) {
bss_event("add", name);
},
bss_reload: function(name, obj, reconf) {
bss_event("reload", name, { reconf: reconf != 0 });
},
bss_remove: function(name, obj) {
bss_event("remove", name);
}
};

View File

@ -0,0 +1,153 @@
#!/usr/bin/env ucode
'use strict';
import { vlist_new, is_equal, wdev_create, wdev_remove } from "/usr/share/hostap/common.uc";
import { readfile, writefile, basename, glob } from "fs";
let keep_devices = {};
let phy = shift(ARGV);
let new_config = shift(ARGV);
const mesh_params = [
"mesh_retry_timeout", "mesh_confirm_timeout", "mesh_holding_timeout", "mesh_max_peer_links",
"mesh_max_retries", "mesh_ttl", "mesh_element_ttl", "mesh_hwmp_max_preq_retries",
"mesh_path_refresh_time", "mesh_min_discovery_timeout", "mesh_hwmp_active_path_timeout",
"mesh_hwmp_preq_min_interval", "mesh_hwmp_net_diameter_traversal_time", "mesh_hwmp_rootmode",
"mesh_hwmp_rann_interval", "mesh_gate_announcements", "mesh_sync_offset_max_neighor",
"mesh_rssi_threshold", "mesh_hwmp_active_path_to_root_timeout", "mesh_hwmp_root_interval",
"mesh_hwmp_confirmation_interval", "mesh_awake_window", "mesh_plink_timeout",
"mesh_auto_open_plinks", "mesh_fwding", "mesh_power_mode"
];
function iface_stop(wdev)
{
if (keep_devices[wdev.ifname])
return;
wdev_remove(wdev.ifname);
}
function iface_start(wdev)
{
let ifname = wdev.ifname;
if (readfile(`/sys/class/net/${ifname}/ifindex`)) {
system([ "ip", "link", "set", "dev", ifname, "down" ]);
wdev_remove(ifname);
}
wdev_create(phy, ifname, wdev);
system([ "ip", "link", "set", "dev", ifname, "up" ]);
if (wdev.freq)
system(`iw dev ${ifname} set freq ${wdev.freq} ${wdev.htmode}`);
if (wdev.mode == "adhoc") {
let cmd = ["iw", "dev", ifname, "ibss", "join", wdev.ssid, wdev.freq, wdev.htmode, "fixed-freq" ];
if (wdev.bssid)
push(cmd, wdev.bssid);
for (let key in [ "beacon-interval", "basic-rates", "mcast-rate", "keys" ])
if (wdev[key])
push(cmd, key, wdev[key]);
system(cmd);
} else if (wdev.mode == "mesh") {
let cmd = [ "iw", "dev", ifname, "mesh", "join", ssid, "freq", wdev.freq, wdev.htmode ];
for (let key in [ "beacon-interval", "mcast-rate" ])
if (wdev[key])
push(cmd, key, wdev[key]);
system(cmd);
cmd = ["iw", "dev", ifname, "set", "mesh_param" ];
let len = length(cmd);
for (let param in mesh_params)
if (wdev[param])
push(cmd, param, wdev[param]);
if (len == length(cmd))
return;
system(cmd);
}
}
function iface_cb(new_if, old_if)
{
if (old_if && new_if && is_equal(old_if, new_if))
return;
if (old_if)
iface_stop(old_if);
if (new_if)
iface_start(new_if);
}
function drop_inactive(config)
{
for (let key in config) {
if (!readfile(`/sys/class/net/${key}/ifindex`))
delete config[key];
}
}
function add_ifname(config)
{
for (let key in config)
config[key].ifname = key;
}
function delete_ifname(config)
{
for (let key in config)
delete config[key].ifname;
}
function add_existing(phy, config)
{
let wdevs = glob(`/sys/class/ieee80211/${phy}/device/net/*`);
wdevs = map(wdevs, (arg) => basename(arg));
for (let wdev in wdevs) {
if (config[wdev])
continue;
if (trim(readfile(`/sys/class/net/${wdev}/operstate`)) == "down")
config[wdev] = {};
}
}
let statefile = `/var/run/wdev-${phy}.json`;
for (let dev in ARGV)
keep_devices[dev] = true;
if (!phy || !new_config) {
warn(`Usage: ${basename(sourcepath())} <phy> <config> [<device]...]\n`);
exit(1);
}
if (!readfile(`/sys/class/ieee80211/${phy}/index`)) {
warn(`PHY ${phy} does not exist\n`);
exit(1);
}
new_config = json(new_config);
if (!new_config) {
warn("Invalid configuration\n");
exit(1);
}
let old_config = readfile(statefile);
if (old_config)
old_config = json(old_config);
let config = vlist_new(iface_cb);
if (type(old_config) == "object")
config.data = old_config;
add_existing(phy, config.data);
add_ifname(config.data);
drop_inactive(config.data);
add_ifname(new_config);
config.update(new_config);
drop_inactive(config.data);
delete_ifname(config.data);
writefile(statefile, sprintf("%J", config.data));

View File

@ -0,0 +1,161 @@
let libubus = require("ubus");
import { open, readfile } from "fs";
import { wdev_create, wdev_remove, is_equal, vlist_new } from "common";
let ubus = libubus.connect();
wpas.data.config = {};
function iface_stop(iface)
{
let ifname = iface.config.iface;
wpas.remove_iface(ifname);
wdev_remove(ifname);
iface.running = false;
}
function iface_start(phy, iface)
{
if (iface.running)
return;
let ifname = iface.config.iface;
wdev_remove(ifname);
let ret = wdev_create(phy, ifname, iface.config);
if (ret)
wpas.printf(`Failed to create device ${ifname}: ${ret}`);
wpas.add_iface(iface.config);
iface.running = true;
}
function iface_cb(new_if, old_if)
{
if (old_if && new_if && is_equal(old_if.config, new_if.config)) {
new_if.running = old_if.running;
return;
}
if (old_if && old_if.running)
iface_stop(old_if);
}
function prepare_config(config)
{
config.config_data = readfile(config.config);
return { config: config };
}
function set_config(phy_name, config_list)
{
let phy = wpas.data.config[phy_name];
if (!phy) {
phy = vlist_new(iface_cb, false);
wpas.data.config[phy_name] = phy;
}
let values = [];
for (let config in config_list)
push(values, [ config.iface, prepare_config(config) ]);
phy.update(values);
}
function start_pending(phy_name)
{
let phy = wpas.data.config[phy_name];
for (let ifname in phy.data)
iface_start(phy_name, phy.data[ifname]);
}
let main_obj = {
config_set: {
args: {
phy: "",
config: [],
defer: true,
},
call: function(req) {
if (!req.args.phy)
return libubus.STATUS_INVALID_ARGUMENT;
try {
if (req.args.config)
set_config(req.args.phy, req.args.config);
if (!req.args.defer)
start_pending(req.args.phy);
} catch (e) {
wpas.printf(`Error loading config: ${e}\n${e.stacktrace[0].context}`);
return libubus.STATUS_INVALID_ARGUMENT;
}
return {
pid: wpas.getpid()
};
}
},
config_add: {
args: {
driver: "",
iface: "",
bridge: "",
hostapd_ctrl: "",
ctrl: "",
config: "",
},
call: function(req) {
if (!req.args.iface || !req.args.config)
return libubus.STATUS_INVALID_ARGUMENT;
if (wpas.add_iface(req.args) < 0)
return libubus.STATUS_INVALID_ARGUMENT;
return {
pid: wpas.getpid()
};
}
},
config_remove: {
args: {
iface: ""
},
call: function(req) {
if (!req.args.iface)
return libubus.STATUS_INVALID_ARGUMENT;
wpas.remove_iface(req.args.iface);
return 0;
}
},
};
wpas.data.ubus = ubus;
wpas.data.obj = ubus.publish("wpa_supplicant", main_obj);
function iface_event(type, name, data) {
let ubus = wpas.data.ubus;
data ??= {};
data.name = name;
wpas.data.obj.notify(`iface.${type}`, data, null, null, null, -1);
ubus.call("service", "event", { type: `wpa_supplicant.${name}.${type}`, data: {} });
}
return {
shutdown: function() {
for (let phy in wpas.data.config)
set_config(phy, []);
wpas.ubus.disconnect();
},
iface_add: function(name, obj) {
iface_event("add", name);
},
iface_remove: function(name, obj) {
iface_event("remove", name);
}
};

View File

@ -23,15 +23,6 @@
#define OCE_STA_CFON_ENABLED(hapd) \
((hapd->conf->oce & OCE_STA_CFON) && \
@@ -92,7 +93,7 @@ struct hapd_interfaces {
#ifdef CONFIG_CTRL_IFACE_UDP
unsigned char ctrl_iface_cookie[CTRL_IFACE_COOKIE_LEN];
#endif /* CONFIG_CTRL_IFACE_UDP */
-
+ struct ubus_object ubus;
};
enum hostapd_chan_status {
@@ -184,6 +185,7 @@ struct hostapd_data {
struct hostapd_iface *iface;
struct hostapd_config *iconf;
@ -434,24 +425,6 @@
if (wpa_s->conf->wps_cred_processing == 1)
return 0;
--- a/hostapd/main.c
+++ b/hostapd/main.c
@@ -991,6 +991,7 @@ int main(int argc, char *argv[])
}
hostapd_global_ctrl_iface_init(&interfaces);
+ hostapd_ubus_add(&interfaces);
if (hostapd_global_run(&interfaces, daemonize, pid_file)) {
wpa_printf(MSG_ERROR, "Failed to start eloop");
@@ -1000,6 +1001,7 @@ int main(int argc, char *argv[])
ret = 0;
out:
+ hostapd_ubus_free(&interfaces);
hostapd_global_ctrl_iface_deinit(&interfaces);
/* Deinitialize all interfaces */
for (i = 0; i < interfaces.count; i++) {
--- a/wpa_supplicant/main.c
+++ b/wpa_supplicant/main.c
@@ -204,7 +204,7 @@ int main(int argc, char *argv[])

View File

@ -0,0 +1,224 @@
--- a/hostapd/Makefile
+++ b/hostapd/Makefile
@@ -168,9 +168,21 @@ OBJS += ../src/eapol_auth/eapol_auth_sm.
ifdef CONFIG_UBUS
CFLAGS += -DUBUS_SUPPORT
-OBJS += ../src/utils/uloop.o
OBJS += ../src/ap/ubus.o
-LIBS += -lubox -lubus
+LIBS += -lubus
+NEED_ULOOP:=y
+endif
+
+ifdef CONFIG_UCODE
+CFLAGS += -DUCODE_SUPPORT
+OBJS += ../src/utils/ucode.o
+OBJS += ../src/ap/ucode.o
+NEED_ULOOP:=y
+endif
+
+ifdef NEED_ULOOP
+OBJS += ../src/utils/uloop.o
+LIBS += -lubox
endif
ifdef CONFIG_CODE_COVERAGE
--- a/hostapd/main.c
+++ b/hostapd/main.c
@@ -991,6 +991,7 @@ int main(int argc, char *argv[])
}
hostapd_global_ctrl_iface_init(&interfaces);
+ hostapd_ucode_init(&interfaces);
if (hostapd_global_run(&interfaces, daemonize, pid_file)) {
wpa_printf(MSG_ERROR, "Failed to start eloop");
@@ -1000,6 +1001,7 @@ int main(int argc, char *argv[])
ret = 0;
out:
+ hostapd_ucode_free();
hostapd_global_ctrl_iface_deinit(&interfaces);
/* Deinitialize all interfaces */
for (i = 0; i < interfaces.count; i++) {
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -19,6 +19,7 @@
#include "ap_config.h"
#include "drivers/driver.h"
#include "ubus.h"
+#include "ucode.h"
#define OCE_STA_CFON_ENABLED(hapd) \
((hapd->conf->oce & OCE_STA_CFON) && \
@@ -51,6 +52,10 @@ struct hapd_interfaces {
struct hostapd_config * (*config_read_cb)(const char *config_fname);
int (*ctrl_iface_init)(struct hostapd_data *hapd);
void (*ctrl_iface_deinit)(struct hostapd_data *hapd);
+ int (*ctrl_iface_recv)(struct hostapd_data *hapd,
+ char *buf, char *reply, int reply_size,
+ struct sockaddr_storage *from,
+ socklen_t fromlen);
int (*for_each_interface)(struct hapd_interfaces *interfaces,
int (*cb)(struct hostapd_iface *iface,
void *ctx), void *ctx);
@@ -186,6 +191,7 @@ struct hostapd_data {
struct hostapd_config *iconf;
struct hostapd_bss_config *conf;
struct hostapd_ubus_bss ubus;
+ struct hostapd_ucode_bss ucode;
int interface_added; /* virtual interface added for this BSS */
unsigned int started:1;
unsigned int disabled:1;
@@ -506,6 +512,7 @@ struct hostapd_sta_info {
*/
struct hostapd_iface {
struct hapd_interfaces *interfaces;
+ struct hostapd_ucode_iface ucode;
void *owner;
char *config_fname;
struct hostapd_config *conf;
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -276,6 +276,8 @@ int hostapd_reload_config(struct hostapd
size_t j;
int i;
+ hostapd_ucode_reload_bss(hapd, reconf);
+
if (iface->config_fname == NULL) {
/* Only in-memory config in use - assume it has been updated */
hostapd_clear_old(iface);
@@ -455,6 +457,7 @@ void hostapd_free_hapd_data(struct hosta
hapd->beacon_set_done = 0;
wpa_printf(MSG_DEBUG, "%s(%s)", __func__, hapd->conf->iface);
+ hostapd_ucode_free_bss(hapd);
hostapd_ubus_free_bss(hapd);
accounting_deinit(hapd);
hostapd_deinit_wpa(hapd);
@@ -619,6 +622,7 @@ void hostapd_cleanup_iface_partial(struc
static void hostapd_cleanup_iface(struct hostapd_iface *iface)
{
wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface);
+ hostapd_ucode_free_iface(iface);
eloop_cancel_timeout(channel_list_update_timeout, iface, NULL);
eloop_cancel_timeout(hostapd_interface_setup_failure_handler, iface,
NULL);
@@ -1209,6 +1213,7 @@ static int hostapd_start_beacon(struct h
hapd->driver->set_operstate(hapd->drv_priv, 1);
hostapd_ubus_add_bss(hapd);
+ hostapd_ucode_add_bss(hapd);
return 0;
}
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
@@ -197,8 +197,20 @@ endif
ifdef CONFIG_UBUS
CFLAGS += -DUBUS_SUPPORT
OBJS += ubus.o
+LIBS += -lubus
+NEED_ULOOP:=y
+endif
+
+ifdef CONFIG_UCODE
+CFLAGS += -DUCODE_SUPPORT
+OBJS += ../src/utils/ucode.o
+OBJS += ucode.o
+NEED_ULOOP:=y
+endif
+
+ifdef NEED_ULOOP
OBJS += ../src/utils/uloop.o
-LIBS += -lubox -lubus
+LIBS += -lubox
endif
ifdef CONFIG_CODE_COVERAGE
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -7636,6 +7636,7 @@ struct wpa_supplicant * wpa_supplicant_a
#endif /* CONFIG_P2P */
wpas_ubus_add_bss(wpa_s);
+ wpas_ucode_add_bss(wpa_s);
return wpa_s;
}
@@ -7663,6 +7664,7 @@ int wpa_supplicant_remove_iface(struct w
struct wpa_supplicant *parent = wpa_s->parent;
#endif /* CONFIG_MESH */
+ wpas_ucode_free_bss(wpa_s);
wpas_ubus_free_bss(wpa_s);
/* Remove interface from the global list of interfaces */
@@ -7973,6 +7975,7 @@ struct wpa_global * wpa_supplicant_init(
eloop_register_timeout(WPA_SUPPLICANT_CLEANUP_INTERVAL, 0,
wpas_periodic, global, NULL);
+ wpas_ucode_init(global);
return global;
}
@@ -8011,12 +8014,8 @@ int wpa_supplicant_run(struct wpa_global
eloop_register_signal_terminate(wpa_supplicant_terminate, global);
eloop_register_signal_reconfig(wpa_supplicant_reconfig, global);
- wpas_ubus_add(global);
-
eloop_run();
- wpas_ubus_free(global);
-
return 0;
}
@@ -8049,6 +8048,8 @@ void wpa_supplicant_deinit(struct wpa_gl
wpas_notify_supplicant_deinitialized(global);
+ wpas_ucode_free();
+
eap_peer_unregister_methods();
#ifdef CONFIG_AP
eap_server_unregister_methods();
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -22,6 +22,7 @@
#include "wmm_ac.h"
#include "pasn/pasn_common.h"
#include "ubus.h"
+#include "ucode.h"
extern const char *const wpa_supplicant_version;
extern const char *const wpa_supplicant_license;
@@ -659,6 +660,7 @@ struct wpa_supplicant {
unsigned char perm_addr[ETH_ALEN];
char ifname[100];
struct wpas_ubus_bss ubus;
+ struct wpas_ucode_bss ucode;
#ifdef CONFIG_MATCH_IFACE
int matched;
#endif /* CONFIG_MATCH_IFACE */
--- a/hostapd/ctrl_iface.c
+++ b/hostapd/ctrl_iface.c
@@ -4921,6 +4921,7 @@ try_again:
return -1;
}
+ interface->ctrl_iface_recv = hostapd_ctrl_iface_receive_process;
wpa_msg_register_cb(hostapd_ctrl_iface_msg_cb);
return 0;
@@ -5022,6 +5023,7 @@ fail:
os_free(fname);
interface->global_ctrl_sock = s;
+ interface->ctrl_iface_recv = hostapd_ctrl_iface_receive_process;
eloop_register_read_sock(s, hostapd_global_ctrl_iface_receive,
interface, NULL);

View File

@ -40,6 +40,15 @@
int rts_threshold;
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -127,7 +127,7 @@ void hostapd_reconfig_encryption(struct
}
-static void hostapd_reload_bss(struct hostapd_data *hapd)
+void hostapd_reload_bss(struct hostapd_data *hapd)
{
struct hostapd_ssid *ssid;
@@ -255,6 +255,10 @@ static int hostapd_iface_conf_changed(st
{
size_t i;
@ -60,7 +69,7 @@
{
struct hapd_interfaces *interfaces = iface->interfaces;
struct hostapd_data *hapd = iface->bss[0];
@@ -296,6 +300,9 @@ int hostapd_reload_config(struct hostapd
@@ -298,6 +302,9 @@ int hostapd_reload_config(struct hostapd
char *fname;
int res;
@ -70,7 +79,7 @@
hostapd_clear_old(iface);
wpa_printf(MSG_DEBUG,
@@ -322,6 +329,24 @@ int hostapd_reload_config(struct hostapd
@@ -324,6 +331,24 @@ int hostapd_reload_config(struct hostapd
wpa_printf(MSG_ERROR,
"Failed to enable interface on config reload");
return res;
@ -95,7 +104,7 @@
}
iface->conf = newconf;
@@ -338,6 +363,12 @@ int hostapd_reload_config(struct hostapd
@@ -340,6 +365,12 @@ int hostapd_reload_config(struct hostapd
for (j = 0; j < iface->num_bss; j++) {
hapd = iface->bss[j];
@ -108,7 +117,17 @@
if (!hapd->conf->config_id || !newconf->bss[j]->config_id ||
os_strcmp(hapd->conf->config_id,
newconf->bss[j]->config_id) != 0)
@@ -2700,6 +2731,10 @@ hostapd_alloc_bss_data(struct hostapd_if
@@ -1236,8 +1267,7 @@ static int hostapd_start_beacon(struct h
* initialized. Most of the modules that are initialized here will be
* deinitialized in hostapd_cleanup().
*/
-static int hostapd_setup_bss(struct hostapd_data *hapd, int first,
- bool start_beacon)
+int hostapd_setup_bss(struct hostapd_data *hapd, int first, bool start_beacon)
{
struct hostapd_bss_config *conf = hapd->conf;
u8 ssid[SSID_MAX_LEN + 1];
@@ -2705,6 +2735,10 @@ hostapd_alloc_bss_data(struct hostapd_if
hapd->iconf = conf;
hapd->conf = bss;
hapd->iface = hapd_iface;
@ -119,9 +138,18 @@
if (conf)
hapd->driver = conf->driver;
hapd->ctrl_sock = -1;
@@ -2723,7 +2757,7 @@ hostapd_alloc_bss_data(struct hostapd_if
}
-static void hostapd_bss_deinit(struct hostapd_data *hapd)
+void hostapd_bss_deinit(struct hostapd_data *hapd)
{
if (!hapd)
return;
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -47,7 +47,7 @@ struct mesh_conf;
@@ -48,7 +48,7 @@ struct mesh_conf;
struct hostapd_iface;
struct hapd_interfaces {
@ -130,23 +158,33 @@
struct hostapd_config * (*config_read_cb)(const char *config_fname);
int (*ctrl_iface_init)(struct hostapd_data *hapd);
void (*ctrl_iface_deinit)(struct hostapd_data *hapd);
@@ -186,6 +186,7 @@ struct hostapd_data {
struct hostapd_config *iconf;
@@ -192,6 +192,7 @@ struct hostapd_data {
struct hostapd_bss_config *conf;
struct hostapd_ubus_bss ubus;
struct hostapd_ucode_bss ucode;
+ char *config_id;
int interface_added; /* virtual interface added for this BSS */
unsigned int started:1;
unsigned int disabled:1;
@@ -689,7 +690,7 @@ struct hostapd_iface {
@@ -696,7 +697,9 @@ struct hostapd_iface {
int hostapd_for_each_interface(struct hapd_interfaces *interfaces,
int (*cb)(struct hostapd_iface *iface,
void *ctx), void *ctx);
-int hostapd_reload_config(struct hostapd_iface *iface);
+int hostapd_reload_config(struct hostapd_iface *iface, int reconf);
+void hostapd_reload_bss(struct hostapd_data *hapd);
+void hostapd_bss_deinit(struct hostapd_data *hapd);
void hostapd_reconfig_encryption(struct hostapd_data *hapd);
struct hostapd_data *
hostapd_alloc_bss_data(struct hostapd_iface *hapd_iface,
@@ -713,6 +716,7 @@ struct hostapd_iface * hostapd_init(stru
struct hostapd_iface *
hostapd_interface_init_bss(struct hapd_interfaces *interfaces, const char *phy,
const char *config_fname, int debug);
+int hostapd_setup_bss(struct hostapd_data *hapd, int first, bool start_beacon);
void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta,
int reassoc);
void hostapd_interface_deinit_free(struct hostapd_iface *iface);
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -5322,6 +5322,9 @@ static int wpa_driver_nl80211_set_ap(voi

View File

@ -0,0 +1,33 @@
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -4814,7 +4814,12 @@ struct hostapd_config * hostapd_config_r
int errors = 0;
size_t i;
- f = fopen(fname, "r");
+ if (!strncmp(fname, "data:", 5)) {
+ f = fmemopen((void *)(fname + 5), strlen(fname + 5), "r");
+ fname = "<inline>";
+ } else {
+ f = fopen(fname, "r");
+ }
if (f == NULL) {
wpa_printf(MSG_ERROR, "Could not open configuration file '%s' "
"for reading.", fname);
--- a/wpa_supplicant/config_file.c
+++ b/wpa_supplicant/config_file.c
@@ -326,8 +326,13 @@ struct wpa_config * wpa_config_read(cons
while (cred_tail && cred_tail->next)
cred_tail = cred_tail->next;
+ if (!strncmp(name, "data:", 5)) {
+ f = fmemopen((void *)(name + 5), strlen(name + 5), "r");
+ name = "<inline>";
+ } else {
+ f = fopen(name, "r");
+ }
wpa_printf(MSG_DEBUG, "Reading configuration file '%s'", name);
- f = fopen(name, "r");
if (f == NULL) {
wpa_printf(MSG_ERROR, "Failed to open config file '%s', "
"error: %s", name, strerror(errno));

View File

@ -17,7 +17,7 @@
} else if (os_strcmp(buf, "extended_key_id") == 0) {
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -734,6 +734,7 @@ void hostapd_cleanup_cs_params(struct ho
@@ -744,6 +744,7 @@ void hostapd_cleanup_cs_params(struct ho
void hostapd_periodic_iface(struct hostapd_iface *iface);
int hostapd_owe_trans_get_info(struct hostapd_data *hapd);
void hostapd_ocv_check_csa_sa_query(void *eloop_ctx, void *timeout_ctx);

View File

@ -32,7 +32,7 @@
os_free(bss->dump_msk_file);
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -1534,6 +1534,7 @@ static int hostapd_setup_bss(struct host
@@ -1538,6 +1538,7 @@ int hostapd_setup_bss(struct hostapd_dat
wpa_printf(MSG_ERROR, "GAS server initialization failed");
return -1;
}
@ -40,7 +40,7 @@
if (conf->qos_map_set_len &&
hostapd_drv_set_qos_map(hapd, conf->qos_map_set,
@@ -1541,7 +1542,6 @@ static int hostapd_setup_bss(struct host
@@ -1545,7 +1546,6 @@ int hostapd_setup_bss(struct hostapd_dat
wpa_printf(MSG_ERROR, "Failed to initialize QoS Map");
return -1;
}

View File

@ -10,7 +10,7 @@
unsigned int time_window;
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -1471,6 +1471,7 @@ static int hostapd_setup_bss(struct host
@@ -1475,6 +1475,7 @@ int hostapd_setup_bss(struct hostapd_dat
os_memset(&das_conf, 0, sizeof(das_conf));
das_conf.port = conf->radius_das_port;

View File

@ -21,7 +21,7 @@
#ifndef CONFIG_NO_HOSTAPD_LOGGER
static void hostapd_logger_cb(void *ctx, const u8 *addr, unsigned int module,
@@ -665,6 +666,11 @@ int main(int argc, char *argv[])
@@ -755,6 +756,11 @@ int main(int argc, char *argv[])
if (os_program_init())
return -1;

View File

@ -29,11 +29,6 @@ static struct ubus_context *ctx;
static struct blob_buf b;
static int ctx_ref;
static inline struct hapd_interfaces *get_hapd_interfaces_from_object(struct ubus_object *obj)
{
return container_of(obj, struct hapd_interfaces, ubus);
}
static inline struct hostapd_data *get_hapd_from_object(struct ubus_object *obj)
{
return container_of(obj, struct hostapd_data, ubus.obj);
@ -123,38 +118,6 @@ static void hostapd_notify_ubus(struct ubus_object *obj, char *bssname, char *ev
free(event_type);
}
static void hostapd_send_procd_event(char *bssname, char *event)
{
char *name, *s;
uint32_t id;
void *v;
if (!ctx || ubus_lookup_id(ctx, "service", &id))
return;
if (asprintf(&name, "hostapd.%s.%s", bssname, event) < 0)
return;
blob_buf_init(&b, 0);
s = blobmsg_alloc_string_buffer(&b, "type", strlen(name) + 1);
sprintf(s, "%s", name);
blobmsg_add_string_buffer(&b);
v = blobmsg_open_table(&b, "data");
blobmsg_close_table(&b, v);
ubus_invoke(ctx, id, "event", b.head, NULL, NULL, 1000);
free(name);
}
static void hostapd_send_shared_event(struct ubus_object *obj, char *bssname, char *event)
{
hostapd_send_procd_event(bssname, event);
hostapd_notify_ubus(obj, bssname, event);
}
static void
hostapd_bss_del_ban(void *eloop_data, void *user_ctx)
{
@ -199,10 +162,8 @@ hostapd_bss_reload(struct ubus_context *ctx, struct ubus_object *obj,
struct blob_attr *msg)
{
struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj);
int ret = hostapd_reload_config(hapd->iface, 1);
hostapd_send_shared_event(&hapd->iface->interfaces->ubus, hapd->conf->iface, "reload");
return ret;
return hostapd_reload_config(hapd->iface, 1);
}
@ -683,68 +644,6 @@ enum {
__CONFIG_MAX
};
static const struct blobmsg_policy config_add_policy[__CONFIG_MAX] = {
[CONFIG_IFACE] = { "iface", BLOBMSG_TYPE_STRING },
[CONFIG_FILE] = { "config", BLOBMSG_TYPE_STRING },
};
static int
hostapd_config_add(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method,
struct blob_attr *msg)
{
struct blob_attr *tb[__CONFIG_MAX];
struct hapd_interfaces *interfaces = get_hapd_interfaces_from_object(obj);
char buf[128];
blobmsg_parse(config_add_policy, __CONFIG_MAX, tb, blob_data(msg), blob_len(msg));
if (!tb[CONFIG_FILE] || !tb[CONFIG_IFACE])
return UBUS_STATUS_INVALID_ARGUMENT;
snprintf(buf, sizeof(buf), "bss_config=%s:%s",
blobmsg_get_string(tb[CONFIG_IFACE]),
blobmsg_get_string(tb[CONFIG_FILE]));
if (hostapd_add_iface(interfaces, buf))
return UBUS_STATUS_INVALID_ARGUMENT;
blob_buf_init(&b, 0);
blobmsg_add_u32(&b, "pid", getpid());
ubus_send_reply(ctx, req, b.head);
return UBUS_STATUS_OK;
}
enum {
CONFIG_REM_IFACE,
__CONFIG_REM_MAX
};
static const struct blobmsg_policy config_remove_policy[__CONFIG_REM_MAX] = {
[CONFIG_REM_IFACE] = { "iface", BLOBMSG_TYPE_STRING },
};
static int
hostapd_config_remove(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method,
struct blob_attr *msg)
{
struct blob_attr *tb[__CONFIG_REM_MAX];
struct hapd_interfaces *interfaces = get_hapd_interfaces_from_object(obj);
char buf[128];
blobmsg_parse(config_remove_policy, __CONFIG_REM_MAX, tb, blob_data(msg), blob_len(msg));
if (!tb[CONFIG_REM_IFACE])
return UBUS_STATUS_INVALID_ARGUMENT;
if (hostapd_remove_iface(interfaces, blobmsg_get_string(tb[CONFIG_REM_IFACE])))
return UBUS_STATUS_INVALID_ARGUMENT;
return UBUS_STATUS_OK;
}
enum {
CSA_FREQ,
CSA_BCN_COUNT,
@ -1781,8 +1680,6 @@ void hostapd_ubus_add_bss(struct hostapd_data *hapd)
obj->n_methods = bss_object_type.n_methods;
ret = ubus_add_object(ctx, obj);
hostapd_ubus_ref_inc();
hostapd_send_shared_event(&hapd->iface->interfaces->ubus, hapd->conf->iface, "add");
}
void hostapd_ubus_free_bss(struct hostapd_data *hapd)
@ -1798,8 +1695,6 @@ void hostapd_ubus_free_bss(struct hostapd_data *hapd)
if (!ctx)
return;
hostapd_send_shared_event(&hapd->iface->interfaces->ubus, hapd->conf->iface, "remove");
if (obj->id) {
ubus_remove_object(ctx, obj);
hostapd_ubus_ref_dec();
@ -1845,47 +1740,6 @@ void hostapd_ubus_remove_vlan(struct hostapd_data *hapd, struct hostapd_vlan *vl
hostapd_ubus_vlan_action(hapd, vlan, "vlan_remove");
}
static const struct ubus_method daemon_methods[] = {
UBUS_METHOD("config_add", hostapd_config_add, config_add_policy),
UBUS_METHOD("config_remove", hostapd_config_remove, config_remove_policy),
};
static struct ubus_object_type daemon_object_type =
UBUS_OBJECT_TYPE("hostapd", daemon_methods);
void hostapd_ubus_add(struct hapd_interfaces *interfaces)
{
struct ubus_object *obj = &interfaces->ubus;
int ret;
if (!hostapd_ubus_init())
return;
obj->name = strdup("hostapd");
obj->type = &daemon_object_type;
obj->methods = daemon_object_type.methods;
obj->n_methods = daemon_object_type.n_methods;
ret = ubus_add_object(ctx, obj);
hostapd_ubus_ref_inc();
}
void hostapd_ubus_free(struct hapd_interfaces *interfaces)
{
struct ubus_object *obj = &interfaces->ubus;
char *name = (char *) obj->name;
if (!ctx)
return;
if (obj->id) {
ubus_remove_object(ctx, obj);
hostapd_ubus_ref_dec();
}
free(name);
}
struct ubus_event_req {
struct ubus_notify_request nreq;
int resp;

View File

@ -0,0 +1,394 @@
#include <sys/un.h>
#include "utils/includes.h"
#include "utils/common.h"
#include "utils/ucode.h"
#include "hostapd.h"
#include "ap_drv_ops.h"
#include <libubox/uloop.h>
static uc_resource_type_t *global_type, *bss_type, *iface_type;
static struct hapd_interfaces *interfaces;
static uc_value_t *global, *bss_registry, *iface_registry;
static uc_vm_t *vm;
static uc_value_t *
hostapd_ucode_bss_get_uval(struct hostapd_data *hapd)
{
uc_value_t *val;
if (hapd->ucode.idx)
return wpa_ucode_registry_get(bss_registry, hapd->ucode.idx);
val = uc_resource_new(bss_type, hapd);
wpa_ucode_registry_add(bss_registry, val, &hapd->ucode.idx);
return val;
}
static uc_value_t *
hostapd_ucode_iface_get_uval(struct hostapd_iface *hapd)
{
uc_value_t *val;
if (hapd->ucode.idx)
return wpa_ucode_registry_get(iface_registry, hapd->ucode.idx);
val = uc_resource_new(iface_type, hapd);
wpa_ucode_registry_add(iface_registry, val, &hapd->ucode.idx);
return val;
}
static void
hostapd_ucode_update_bss_list(struct hostapd_iface *iface)
{
uc_value_t *ifval, *list;
int i;
list = ucv_array_new(vm);
for (i = 0; i < iface->num_bss; i++) {
struct hostapd_data *hapd = iface->bss[i];
uc_value_t *val = hostapd_ucode_bss_get_uval(hapd);
uc_value_t *proto = ucv_prototype_get(val);
ucv_object_add(proto, "name", ucv_get(ucv_string_new(hapd->conf->iface)));
ucv_object_add(proto, "index", ucv_int64_new(i));
ucv_array_set(list, i, ucv_get(val));
}
ifval = hostapd_ucode_iface_get_uval(iface);
ucv_object_add(ucv_prototype_get(ifval), "bss", ucv_get(list));
}
static void
hostapd_ucode_update_interfaces(void)
{
uc_value_t *ifs = ucv_object_new(vm);
int i;
for (i = 0; i < interfaces->count; i++) {
struct hostapd_iface *iface = interfaces->iface[i];
ucv_object_add(ifs, iface->phy, ucv_get(hostapd_ucode_iface_get_uval(iface)));
hostapd_ucode_update_bss_list(iface);
}
ucv_object_add(ucv_prototype_get(global), "interfaces", ucv_get(ifs));
ucv_gc(vm);
}
static uc_value_t *
uc_hostapd_add_iface(uc_vm_t *vm, size_t nargs)
{
uc_value_t *iface = uc_fn_arg(0);
int ret;
if (ucv_type(iface) != UC_STRING)
return ucv_int64_new(-1);
ret = hostapd_add_iface(interfaces, ucv_string_get(iface));
hostapd_ucode_update_interfaces();
return ucv_int64_new(ret);
}
static uc_value_t *
uc_hostapd_remove_iface(uc_vm_t *vm, size_t nargs)
{
uc_value_t *iface = uc_fn_arg(0);
if (ucv_type(iface) != UC_STRING)
return NULL;
hostapd_remove_iface(interfaces, ucv_string_get(iface));
hostapd_ucode_update_interfaces();
return NULL;
}
static uc_value_t *
uc_hostapd_bss_set_config(uc_vm_t *vm, size_t nargs)
{
struct hostapd_data *hapd = uc_fn_thisval("hostapd.bss");
struct hostapd_bss_config *old_bss;
struct hostapd_iface *iface;
struct hostapd_config *conf;
uc_value_t *file = uc_fn_arg(0);
uc_value_t *index = uc_fn_arg(1);
unsigned int i, idx = 0;
int ret = -1;
if (!hapd || ucv_type(file) != UC_STRING)
goto out;
if (ucv_type(index) == UC_INTEGER)
idx = ucv_int64_get(index);
iface = hapd->iface;
conf = interfaces->config_read_cb(ucv_string_get(file));
if (!conf || idx > conf->num_bss || !conf->bss[idx])
goto out;
hostapd_bss_deinit_no_free(hapd);
hostapd_drv_stop_ap(hapd);
hostapd_free_hapd_data(hapd);
old_bss = hapd->conf;
for (i = 0; i < iface->conf->num_bss; i++)
if (iface->conf->bss[i] == hapd->conf)
iface->conf->bss[i] = conf->bss[idx];
hapd->conf = conf->bss[idx];
conf->bss[idx] = old_bss;
hostapd_config_free(conf);
hostapd_setup_bss(hapd, hapd == iface->bss[0], !iface->conf->mbssid);
ret = 0;
out:
return ucv_int64_new(ret);
}
static void
hostapd_remove_iface_bss_conf(struct hostapd_config *iconf,
struct hostapd_bss_config *conf)
{
int i;
for (i = 0; i < iconf->num_bss; i++)
if (iconf->bss[i] == conf)
break;
if (i == iconf->num_bss)
return;
for (i++; i < iconf->num_bss; i++)
iconf->bss[i - 1] = iconf->bss[i];
iconf->num_bss--;
}
static uc_value_t *
uc_hostapd_bss_delete(uc_vm_t *vm, size_t nargs)
{
struct hostapd_data *hapd = uc_fn_thisval("hostapd.bss");
struct hostapd_iface *iface;
int i, idx;
if (!hapd || hapd == hapd->iface->bss[0])
return NULL;
iface = hapd->iface;
for (idx = 0; idx < iface->num_bss; idx++)
if (iface->bss[idx] == hapd)
break;
if (idx == iface->num_bss)
return NULL;
for (i = idx + 1; i < iface->num_bss; i++)
iface->bss[i - 1] = iface->bss[i];
iface->num_bss--;
hostapd_drv_stop_ap(hapd);
hostapd_bss_deinit(hapd);
hostapd_remove_iface_bss_conf(iface->conf, hapd->conf);
hostapd_config_free_bss(hapd->conf);
os_free(hapd);
hostapd_ucode_update_bss_list(iface);
ucv_gc(vm);
return NULL;
}
static uc_value_t *
uc_hostapd_iface_add_bss(uc_vm_t *vm, size_t nargs)
{
struct hostapd_iface *iface = uc_fn_thisval("hostapd.iface");
struct hostapd_bss_config *bss;
struct hostapd_config *conf;
struct hostapd_data *hapd;
uc_value_t *file = uc_fn_arg(0);
uc_value_t *index = uc_fn_arg(1);
unsigned int idx = 0;
uc_value_t *ret = NULL;
if (!iface || ucv_type(file) != UC_STRING)
goto out;
if (ucv_type(index) == UC_INTEGER)
idx = ucv_int64_get(index);
conf = interfaces->config_read_cb(ucv_string_get(file));
if (!conf || idx > conf->num_bss || !conf->bss[idx])
goto out;
bss = conf->bss[idx];
hapd = hostapd_alloc_bss_data(iface, iface->conf, bss);
if (!hapd)
goto out;
hapd->driver = iface->bss[0]->driver;
hapd->drv_priv = iface->bss[0]->drv_priv;
if (interfaces->ctrl_iface_init &&
interfaces->ctrl_iface_init(hapd) < 0)
goto free_hapd;
if (iface->state == HAPD_IFACE_ENABLED &&
hostapd_setup_bss(hapd, -1, true))
goto deinit_ctrl;
iface->bss = os_realloc_array(iface->bss, iface->num_bss + 1,
sizeof(*iface->bss));
iface->bss[iface->num_bss++] = hapd;
iface->conf->bss = os_realloc_array(iface->conf->bss,
iface->conf->num_bss + 1,
sizeof(*iface->conf->bss));
iface->conf->bss[iface->conf->num_bss] = bss;
conf->bss[idx] = NULL;
ret = hostapd_ucode_bss_get_uval(hapd);
hostapd_ucode_update_bss_list(iface);
goto out;
deinit_ctrl:
if (interfaces->ctrl_iface_deinit)
interfaces->ctrl_iface_deinit(hapd);
free_hapd:
hostapd_free_hapd_data(hapd);
os_free(hapd);
out:
hostapd_config_free(conf);
return ret;
}
static uc_value_t *
uc_hostapd_bss_ctrl(uc_vm_t *vm, size_t nargs)
{
struct hostapd_data *hapd = uc_fn_thisval("hostapd.bss");
uc_value_t *arg = uc_fn_arg(0);
struct sockaddr_storage from = {};
static char reply[4096];
int reply_len;
if (!hapd || !interfaces->ctrl_iface_recv ||
ucv_type(arg) != UC_STRING)
return NULL;
reply_len = interfaces->ctrl_iface_recv(hapd, ucv_string_get(arg),
reply, sizeof(reply),
&from, sizeof(from));
if (reply_len < 0)
return NULL;
if (reply_len && reply[reply_len - 1] == '\n')
reply_len--;
return ucv_string_new_length(reply, reply_len);
}
int hostapd_ucode_init(struct hapd_interfaces *ifaces)
{
static const uc_function_list_t global_fns[] = {
{ "printf", uc_wpa_printf },
{ "getpid", uc_wpa_getpid },
{ "sha1", uc_wpa_sha1 },
{ "add_iface", uc_hostapd_add_iface },
{ "remove_iface", uc_hostapd_remove_iface },
};
static const uc_function_list_t bss_fns[] = {
{ "ctrl", uc_hostapd_bss_ctrl },
{ "set_config", uc_hostapd_bss_set_config },
{ "delete", uc_hostapd_bss_delete },
};
static const uc_function_list_t iface_fns[] = {
{ "add_bss", uc_hostapd_iface_add_bss }
};
uc_value_t *data, *proto;
interfaces = ifaces;
vm = wpa_ucode_create_vm();
global_type = uc_type_declare(vm, "hostapd.global", global_fns, NULL);
bss_type = uc_type_declare(vm, "hostapd.bss", bss_fns, NULL);
iface_type = uc_type_declare(vm, "hostapd.iface", iface_fns, NULL);
bss_registry = ucv_array_new(vm);
uc_vm_registry_set(vm, "hostap.bss_registry", bss_registry);
iface_registry = ucv_array_new(vm);
uc_vm_registry_set(vm, "hostap.iface_registry", iface_registry);
global = wpa_ucode_global_init("hostapd", global_type);
if (wpa_ucode_run(HOSTAPD_UC_PATH "hostapd.uc"))
goto free_vm;
ucv_gc(vm);
return 0;
free_vm:
wpa_ucode_free_vm();
return -1;
}
void hostapd_ucode_free(void)
{
if (wpa_ucode_call_prepare("shutdown") == 0)
ucv_put(wpa_ucode_call(0));
wpa_ucode_free_vm();
}
void hostapd_ucode_free_iface(struct hostapd_iface *iface)
{
wpa_ucode_registry_remove(iface_registry, iface->ucode.idx);
}
void hostapd_ucode_add_bss(struct hostapd_data *hapd)
{
uc_value_t *val;
if (wpa_ucode_call_prepare("bss_add"))
return;
val = hostapd_ucode_bss_get_uval(hapd);
uc_value_push(ucv_get(ucv_string_new(hapd->conf->iface)));
uc_value_push(ucv_get(val));
ucv_put(wpa_ucode_call(2));
ucv_gc(vm);
}
void hostapd_ucode_reload_bss(struct hostapd_data *hapd, int reconf)
{
uc_value_t *val;
if (wpa_ucode_call_prepare("bss_reload"))
return;
val = hostapd_ucode_bss_get_uval(hapd);
uc_value_push(ucv_get(ucv_string_new(hapd->conf->iface)));
uc_value_push(ucv_get(val));
uc_value_push(ucv_int64_new(reconf));
ucv_put(wpa_ucode_call(3));
ucv_gc(vm);
}
void hostapd_ucode_free_bss(struct hostapd_data *hapd)
{
uc_value_t *val;
val = wpa_ucode_registry_remove(bss_registry, hapd->ucode.idx);
if (!val)
return;
hapd->ucode.idx = 0;
if (wpa_ucode_call_prepare("bss_remove"))
return;
uc_value_push(ucv_string_new(hapd->conf->iface));
uc_value_push(ucv_get(val));
ucv_put(wpa_ucode_call(2));
ucv_gc(vm);
}

View File

@ -0,0 +1,54 @@
#ifndef __HOSTAPD_AP_UCODE_H
#define __HOSTAPD_AP_UCODE_H
#include "utils/ucode.h"
struct hostapd_data;
struct hostapd_ucode_bss {
#ifdef UCODE_SUPPORT
int idx;
#endif
};
struct hostapd_ucode_iface {
#ifdef UCODE_SUPPORT
int idx;
#endif
};
#ifdef UCODE_SUPPORT
int hostapd_ucode_init(struct hapd_interfaces *ifaces);
void hostapd_ucode_free(void);
void hostapd_ucode_free_iface(struct hostapd_iface *iface);
void hostapd_ucode_add_bss(struct hostapd_data *hapd);
void hostapd_ucode_free_bss(struct hostapd_data *hapd);
void hostapd_ucode_reload_bss(struct hostapd_data *hapd, int reconf);
#else
static inline int hostapd_ucode_init(struct hapd_interfaces *ifaces)
{
return -EINVAL;
}
static inline void hostapd_ucode_free(void)
{
}
static inline void hostapd_ucode_free_iface(struct hostapd_iface *iface)
{
}
static inline void hostapd_ucode_reload_bss(struct hostapd_data *hapd, int reconf)
{
}
static inline void hostapd_ucode_add_bss(struct hostapd_data *hapd)
{
}
static inline void hostapd_ucode_free_bss(struct hostapd_data *hapd)
{
}
#endif
#endif

View File

@ -0,0 +1,237 @@
#include <unistd.h>
#include "ucode.h"
#include "utils/eloop.h"
#include "crypto/crypto.h"
#include "crypto/sha1.h"
#include <libubox/uloop.h>
#include <ucode/compiler.h>
static uc_value_t *registry;
static uc_vm_t vm;
static struct uloop_timeout gc_timer;
static void uc_gc_timer(struct uloop_timeout *timeout)
{
ucv_gc(&vm);
}
uc_value_t *uc_wpa_printf(uc_vm_t *vm, size_t nargs)
{
uc_value_t *level = uc_fn_arg(0);
uc_value_t *ret, **args;
uc_cfn_ptr_t _sprintf;
int l = MSG_INFO;
int i, start = 0;
_sprintf = uc_stdlib_function("sprintf");
if (!sprintf)
return NULL;
if (ucv_type(level) == UC_INTEGER) {
l = ucv_int64_get(level);
start++;
}
if (nargs <= start)
return NULL;
ret = _sprintf(vm, nargs - start);
if (ucv_type(ret) != UC_STRING)
return NULL;
wpa_printf(l, "%s", ucv_string_get(ret));
ucv_put(ret);
return NULL;
}
uc_value_t *uc_wpa_getpid(uc_vm_t *vm, size_t nargs)
{
return ucv_int64_new(getpid());
}
uc_value_t *uc_wpa_sha1(uc_vm_t *vm, size_t nargs)
{
u8 hash[SHA1_MAC_LEN];
char hash_hex[2 * ARRAY_SIZE(hash) + 1];
uc_value_t *val;
size_t *lens;
const u8 **args;
int i;
if (!nargs)
return NULL;
args = alloca(nargs * sizeof(*args));
lens = alloca(nargs * sizeof(*lens));
for (i = 0; i < nargs; i++) {
val = uc_fn_arg(i);
if (ucv_type(val) != UC_STRING)
return NULL;
args[i] = ucv_string_get(val);
lens[i] = ucv_string_length(val);
}
if (sha1_vector(nargs, args, lens, hash))
return NULL;
for (i = 0; i < ARRAY_SIZE(hash); i++)
sprintf(hash_hex + 2 * i, "%02x", hash[i]);
return ucv_string_new_length(hash_hex, 2 * ARRAY_SIZE(hash));
}
uc_vm_t *wpa_ucode_create_vm(void)
{
static uc_parse_config_t config = {
.strict_declarations = true,
.lstrip_blocks = true,
.trim_blocks = true,
.raw_mode = true
};
uc_search_path_init(&config.module_search_path);
uc_search_path_add(&config.module_search_path, HOSTAPD_UC_PATH "*.so");
uc_search_path_add(&config.module_search_path, HOSTAPD_UC_PATH "*.uc");
uc_vm_init(&vm, &config);
uc_stdlib_load(uc_vm_scope_get(&vm));
eloop_add_uloop();
gc_timer.cb = uc_gc_timer;
return &vm;
}
int wpa_ucode_run(const char *script)
{
uc_source_t *source;
uc_program_t *prog;
uc_value_t *ops;
char *err;
int ret;
source = uc_source_new_file(script);
if (!source)
return -1;
prog = uc_compile(vm.config, source, &err);
uc_source_put(source);
if (!prog) {
wpa_printf(MSG_ERROR, "Error loading ucode: %s\n", err);
return -1;
}
ret = uc_vm_execute(&vm, prog, &ops);
uc_program_put(prog);
if (ret || !ops)
return -1;
registry = ucv_array_new(&vm);
uc_vm_registry_set(&vm, "hostap.registry", registry);
ucv_array_set(registry, 0, ucv_get(ops));
return 0;
}
int wpa_ucode_call_prepare(const char *fname)
{
uc_value_t *obj, *func;
if (!registry)
return -1;
obj = ucv_array_get(registry, 0);
if (!obj)
return -1;
func = ucv_object_get(obj, fname, NULL);
if (!ucv_is_callable(func))
return -1;
uc_vm_stack_push(&vm, ucv_get(obj));
uc_vm_stack_push(&vm, ucv_get(func));
return 0;
}
uc_value_t *wpa_ucode_global_init(const char *name, uc_resource_type_t *global_type)
{
uc_value_t *global = uc_resource_new(global_type, NULL);
uc_value_t *proto;
uc_vm_registry_set(&vm, "hostap.global", global);
proto = ucv_prototype_get(global);
ucv_object_add(proto, "data", ucv_get(ucv_object_new(&vm)));
#define ADD_CONST(x) ucv_object_add(proto, #x, ucv_int64_new(x))
ADD_CONST(MSG_EXCESSIVE);
ADD_CONST(MSG_MSGDUMP);
ADD_CONST(MSG_DEBUG);
ADD_CONST(MSG_INFO);
ADD_CONST(MSG_WARNING);
ADD_CONST(MSG_ERROR);
#undef ADD_CONST
ucv_object_add(uc_vm_scope_get(&vm), name, ucv_get(global));
return global;
}
void wpa_ucode_registry_add(uc_value_t *reg, uc_value_t *val, int *idx)
{
uc_value_t *data;
int i = 0;
while (ucv_array_get(reg, i))
i++;
ucv_array_set(reg, i, ucv_get(val));
data = ucv_object_new(&vm);
ucv_object_add(ucv_prototype_get(val), "data", ucv_get(data));
*idx = i + 1;
}
uc_value_t *wpa_ucode_registry_get(uc_value_t *reg, int idx)
{
if (!idx)
return NULL;
return ucv_array_get(reg, idx - 1);
}
uc_value_t *wpa_ucode_registry_remove(uc_value_t *reg, int idx)
{
uc_value_t *val = wpa_ucode_registry_get(reg, idx);
if (val)
ucv_array_set(reg, idx - 1, NULL);
return val;
}
uc_value_t *wpa_ucode_call(size_t nargs)
{
if (uc_vm_call(&vm, true, nargs) != EXCEPTION_NONE)
return NULL;
if (!gc_timer.pending)
uloop_timeout_set(&gc_timer, 10);
return uc_vm_stack_pop(&vm);
}
void wpa_ucode_free_vm(void)
{
if (!vm.config)
return;
uc_search_path_free(&vm.config->module_search_path);
uc_vm_free(&vm);
registry = NULL;
vm = (uc_vm_t){};
}

View File

@ -0,0 +1,28 @@
#ifndef __HOSTAPD_UTILS_UCODE_H
#define __HOSTAPD_UTILS_UCODE_H
#include "utils/includes.h"
#include "utils/common.h"
#include <ucode/lib.h>
#include <ucode/vm.h>
#define HOSTAPD_UC_PATH "/usr/share/hostap/"
extern uc_value_t *uc_registry;
uc_vm_t *wpa_ucode_create_vm(void);
int wpa_ucode_run(const char *script);
int wpa_ucode_call_prepare(const char *fname);
uc_value_t *wpa_ucode_call(size_t nargs);
void wpa_ucode_free_vm(void);
uc_value_t *wpa_ucode_global_init(const char *name, uc_resource_type_t *global_type);
void wpa_ucode_registry_add(uc_value_t *reg, uc_value_t *val, int *idx);
uc_value_t *wpa_ucode_registry_get(uc_value_t *reg, int idx);
uc_value_t *wpa_ucode_registry_remove(uc_value_t *reg, int idx);
uc_value_t *uc_wpa_printf(uc_vm_t *vm, size_t nargs);
uc_value_t *uc_wpa_getpid(uc_vm_t *vm, size_t nargs);
uc_value_t *uc_wpa_sha1(uc_vm_t *vm, size_t nargs);
#endif

View File

@ -207,152 +207,6 @@ void wpas_ubus_free_bss(struct wpa_supplicant *wpa_s)
free(name);
}
enum {
WPAS_CONFIG_DRIVER,
WPAS_CONFIG_IFACE,
WPAS_CONFIG_BRIDGE,
WPAS_CONFIG_HOSTAPD_CTRL,
WPAS_CONFIG_CTRL,
WPAS_CONFIG_FILE,
__WPAS_CONFIG_MAX
};
static const struct blobmsg_policy wpas_config_add_policy[__WPAS_CONFIG_MAX] = {
[WPAS_CONFIG_DRIVER] = { "driver", BLOBMSG_TYPE_STRING },
[WPAS_CONFIG_IFACE] = { "iface", BLOBMSG_TYPE_STRING },
[WPAS_CONFIG_BRIDGE] = { "bridge", BLOBMSG_TYPE_STRING },
[WPAS_CONFIG_HOSTAPD_CTRL] = { "hostapd_ctrl", BLOBMSG_TYPE_STRING },
[WPAS_CONFIG_CTRL] = { "ctrl", BLOBMSG_TYPE_STRING },
[WPAS_CONFIG_FILE] = { "config", BLOBMSG_TYPE_STRING },
};
static int
wpas_config_add(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method,
struct blob_attr *msg)
{
struct blob_attr *tb[__WPAS_CONFIG_MAX];
struct wpa_global *global = get_wpa_global_from_object(obj);
struct wpa_interface *iface;
blobmsg_parse(wpas_config_add_policy, __WPAS_CONFIG_MAX, tb, blob_data(msg), blob_len(msg));
if (!tb[WPAS_CONFIG_FILE] || !tb[WPAS_CONFIG_IFACE] || !tb[WPAS_CONFIG_DRIVER])
return UBUS_STATUS_INVALID_ARGUMENT;
iface = os_zalloc(sizeof(struct wpa_interface));
if (iface == NULL)
return UBUS_STATUS_UNKNOWN_ERROR;
iface->driver = blobmsg_get_string(tb[WPAS_CONFIG_DRIVER]);
iface->ifname = blobmsg_get_string(tb[WPAS_CONFIG_IFACE]);
iface->confname = blobmsg_get_string(tb[WPAS_CONFIG_FILE]);
if (tb[WPAS_CONFIG_BRIDGE])
iface->bridge_ifname = blobmsg_get_string(tb[WPAS_CONFIG_BRIDGE]);
if (tb[WPAS_CONFIG_CTRL])
iface->ctrl_interface = blobmsg_get_string(tb[WPAS_CONFIG_CTRL]);
if (tb[WPAS_CONFIG_HOSTAPD_CTRL])
iface->hostapd_ctrl = blobmsg_get_string(tb[WPAS_CONFIG_HOSTAPD_CTRL]);
if (!wpa_supplicant_add_iface(global, iface, NULL))
return UBUS_STATUS_INVALID_ARGUMENT;
blob_buf_init(&b, 0);
blobmsg_add_u32(&b, "pid", getpid());
ubus_send_reply(ctx, req, b.head);
return UBUS_STATUS_OK;
}
enum {
WPAS_CONFIG_REM_IFACE,
__WPAS_CONFIG_REM_MAX
};
static const struct blobmsg_policy wpas_config_remove_policy[__WPAS_CONFIG_REM_MAX] = {
[WPAS_CONFIG_REM_IFACE] = { "iface", BLOBMSG_TYPE_STRING },
};
static int
wpas_config_remove(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method,
struct blob_attr *msg)
{
struct blob_attr *tb[__WPAS_CONFIG_REM_MAX];
struct wpa_global *global = get_wpa_global_from_object(obj);
struct wpa_supplicant *wpa_s = NULL;
unsigned int found = 0;
blobmsg_parse(wpas_config_remove_policy, __WPAS_CONFIG_REM_MAX, tb, blob_data(msg), blob_len(msg));
if (!tb[WPAS_CONFIG_REM_IFACE])
return UBUS_STATUS_INVALID_ARGUMENT;
/* find wpa_s object for to-be-removed interface */
for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
if (!strncmp(wpa_s->ifname,
blobmsg_get_string(tb[WPAS_CONFIG_REM_IFACE]),
sizeof(wpa_s->ifname)))
{
found = 1;
break;
}
}
if (!found)
return UBUS_STATUS_INVALID_ARGUMENT;
if (wpa_supplicant_remove_iface(global, wpa_s, 0))
return UBUS_STATUS_INVALID_ARGUMENT;
return UBUS_STATUS_OK;
}
static const struct ubus_method wpas_daemon_methods[] = {
UBUS_METHOD("config_add", wpas_config_add, wpas_config_add_policy),
UBUS_METHOD("config_remove", wpas_config_remove, wpas_config_remove_policy),
};
static struct ubus_object_type wpas_daemon_object_type =
UBUS_OBJECT_TYPE("wpa_supplicant", wpas_daemon_methods);
void wpas_ubus_add(struct wpa_global *global)
{
struct ubus_object *obj = &global->ubus_global;
int ret;
if (!wpas_ubus_init())
return;
obj->name = strdup("wpa_supplicant");
obj->type = &wpas_daemon_object_type;
obj->methods = wpas_daemon_object_type.methods;
obj->n_methods = wpas_daemon_object_type.n_methods;
ret = ubus_add_object(ctx, obj);
wpas_ubus_ref_inc();
}
void wpas_ubus_free(struct wpa_global *global)
{
struct ubus_object *obj = &global->ubus_global;
char *name = (char *) obj->name;
if (!ctx)
return;
if (obj->id) {
ubus_remove_object(ctx, obj);
wpas_ubus_ref_dec();
}
free(name);
}
#ifdef CONFIG_WPS
void wpas_ubus_notify(struct wpa_supplicant *wpa_s, const struct wps_credential *cred)
{

View File

@ -24,9 +24,6 @@ struct wpas_ubus_bss {
void wpas_ubus_add_bss(struct wpa_supplicant *wpa_s);
void wpas_ubus_free_bss(struct wpa_supplicant *wpa_s);
void wpas_ubus_add(struct wpa_global *global);
void wpas_ubus_free(struct wpa_global *global);
#ifdef CONFIG_WPS
void wpas_ubus_notify(struct wpa_supplicant *wpa_s, const struct wps_credential *cred);
#endif
@ -34,14 +31,6 @@ void wpas_ubus_notify(struct wpa_supplicant *wpa_s, const struct wps_credential
#else
struct wpas_ubus_bss {};
static inline void wpas_ubus_add_iface(struct wpa_supplicant *wpa_s)
{
}
static inline void wpas_ubus_free_iface(struct wpa_supplicant *wpa_s)
{
}
static inline void wpas_ubus_add_bss(struct wpa_supplicant *wpa_s)
{
}

View File

@ -0,0 +1,177 @@
#include "utils/includes.h"
#include "utils/common.h"
#include "utils/ucode.h"
#include "wpa_supplicant_i.h"
#include "wps_supplicant.h"
#include "ucode.h"
static struct wpa_global *wpa_global;
static uc_resource_type_t *global_type, *iface_type;
static uc_value_t *global, *iface_registry;
static uc_vm_t *vm;
static uc_value_t *
wpas_ucode_iface_get_uval(struct wpa_supplicant *wpa_s)
{
uc_value_t *val;
if (wpa_s->ucode.idx)
return wpa_ucode_registry_get(iface_registry, wpa_s->ucode.idx);
val = uc_resource_new(iface_type, wpa_s);
wpa_ucode_registry_add(iface_registry, val, &wpa_s->ucode.idx);
return val;
}
static void
wpas_ucode_update_interfaces(void)
{
uc_value_t *ifs = ucv_object_new(vm);
struct wpa_supplicant *wpa_s;
int i;
for (wpa_s = wpa_global->ifaces; wpa_s; wpa_s = wpa_s->next)
ucv_object_add(ifs, wpa_s->ifname, ucv_get(wpas_ucode_iface_get_uval(wpa_s)));
ucv_object_add(ucv_prototype_get(global), "interfaces", ucv_get(ifs));
ucv_gc(vm);
}
void wpas_ucode_add_bss(struct wpa_supplicant *wpa_s)
{
uc_value_t *val;
if (wpa_ucode_call_prepare("iface_add"))
return;
uc_value_push(ucv_get(ucv_string_new(wpa_s->ifname)));
uc_value_push(ucv_get(wpas_ucode_iface_get_uval(wpa_s)));
ucv_put(wpa_ucode_call(2));
ucv_gc(vm);
}
void wpas_ucode_free_bss(struct wpa_supplicant *wpa_s)
{
uc_value_t *val;
val = wpa_ucode_registry_remove(iface_registry, wpa_s->ucode.idx);
if (!val)
return;
wpa_s->ucode.idx = 0;
if (wpa_ucode_call_prepare("iface_remove"))
return;
uc_value_push(ucv_string_new(wpa_s->ifname));
uc_value_push(ucv_get(val));
ucv_put(wpa_ucode_call(2));
ucv_gc(vm);
}
static const char *obj_stringval(uc_value_t *obj, const char *name)
{
uc_value_t *val = ucv_object_get(obj, name, NULL);
return ucv_string_get(val);
}
static uc_value_t *
uc_wpas_add_iface(uc_vm_t *vm, size_t nargs)
{
uc_value_t *info = uc_fn_arg(0);
uc_value_t *ifname = ucv_object_get(info, "iface", NULL);
uc_value_t *bridge = ucv_object_get(info, "bridge", NULL);
uc_value_t *config = ucv_object_get(info, "config", NULL);
uc_value_t *ctrl = ucv_object_get(info, "ctrl", NULL);
uc_value_t *hapd_ctrl = ucv_object_get(info, "hostapd_ctrl", NULL);
struct wpa_interface iface;
int ret = -1;
if (ucv_type(info) != UC_OBJECT)
goto out;
iface = (struct wpa_interface){
.driver = "nl80211",
.ifname = ucv_string_get(ifname),
.bridge_ifname = ucv_string_get(bridge),
.confname = ucv_string_get(config),
.ctrl_interface = ucv_string_get(ctrl),
.hostapd_ctrl = ucv_string_get(hapd_ctrl),
};
if (!iface.ifname || !iface.confname)
goto out;
ret = wpa_supplicant_add_iface(wpa_global, &iface, 0) ? 0 : -1;
wpas_ucode_update_interfaces();
out:
return ucv_int64_new(ret);
}
static uc_value_t *
uc_wpas_remove_iface(uc_vm_t *vm, size_t nargs)
{
struct wpa_supplicant *wpa_s = NULL;
uc_value_t *ifname_arg = uc_fn_arg(0);
const char *ifname = ucv_string_get(ifname_arg);
int ret = -1;
if (!ifname)
goto out;
for (wpa_s = wpa_global->ifaces; wpa_s; wpa_s = wpa_s->next)
if (!strcmp(wpa_s->ifname, ifname))
break;
if (!wpa_s)
goto out;
ret = wpa_supplicant_remove_iface(wpa_global, wpa_s, 0);
wpas_ucode_update_interfaces();
out:
return ucv_int64_new(ret);
}
int wpas_ucode_init(struct wpa_global *gl)
{
static const uc_function_list_t global_fns[] = {
{ "printf", uc_wpa_printf },
{ "getpid", uc_wpa_getpid },
{ "add_iface", uc_wpas_add_iface },
{ "remove_iface", uc_wpas_remove_iface },
};
static const uc_function_list_t iface_fns[] = {
};
uc_value_t *data, *proto;
wpa_global = gl;
vm = wpa_ucode_create_vm();
global_type = uc_type_declare(vm, "wpas.global", global_fns, NULL);
iface_type = uc_type_declare(vm, "hostapd.iface", iface_fns, NULL);
iface_registry = ucv_array_new(vm);
uc_vm_registry_set(vm, "hostap.iface_registry", iface_registry);
global = wpa_ucode_global_init("wpas", global_type);
if (wpa_ucode_run(HOSTAPD_UC_PATH "wpa_supplicant.uc"))
goto free_vm;
ucv_gc(vm);
return 0;
free_vm:
wpa_ucode_free_vm();
return -1;
}
void wpas_ucode_free(void)
{
if (wpa_ucode_call_prepare("shutdown") == 0)
ucv_put(wpa_ucode_call(0));
wpa_ucode_free_vm();
}

View File

@ -0,0 +1,38 @@
#ifndef __WPAS_UCODE_H
#define __WPAS_UCODE_H
#include "utils/ucode.h"
struct wpa_global;
struct wpa_supplicant;
struct wpas_ucode_bss {
#ifdef UCODE_SUPPORT
unsigned int idx;
#endif
};
#ifdef UCODE_SUPPORT
int wpas_ucode_init(struct wpa_global *gl);
void wpas_ucode_free(void);
void wpas_ucode_add_bss(struct wpa_supplicant *wpa_s);
void wpas_ucode_free_bss(struct wpa_supplicant *wpa_s);
#else
static inline int wpas_ucode_init(struct wpa_global *gl)
{
return -EINVAL;
}
static inline void wpas_ucode_free(void)
{
}
static inline void wpas_ucode_add_bss(struct wpa_supplicant *wpa_s)
{
}
static inline void wpas_ucode_free_bss(struct wpa_supplicant *wpa_s)
{
}
#endif
#endif