Merge branch 'openwrt:master' into master

This commit is contained in:
Hayzam Sherif 2023-08-01 15:44:23 +05:30 committed by GitHub
commit e0757aba35
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
31 changed files with 3547 additions and 735 deletions

View file

@ -8,9 +8,9 @@
include $(TOPDIR)/rules.mk include $(TOPDIR)/rules.mk
PKG_NAME:=ath11k-firmware PKG_NAME:=ath11k-firmware
PKG_SOURCE_DATE:=2023-07-06 PKG_SOURCE_DATE:=2023-07-28
PKG_SOURCE_VERSION:=69f6b7346b64784188dba791a9cfb614eefa441f PKG_SOURCE_VERSION:=006a4e2a23a6cf9e7a28d8349025a4418e39cb1d
PKG_MIRROR_HASH:=0f0203f755cb6713f6a1f41397dcd0f1a24e5cdbe75258af961343b927ebb3e9 PKG_MIRROR_HASH:=1043b8c01d28cad2a34e4586e4e6a3949bd1aed9f9afd5b71f527b6b23835e81
PKG_RELEASE:=1 PKG_RELEASE:=1
PKG_SOURCE_PROTO:=git PKG_SOURCE_PROTO:=git
@ -60,14 +60,14 @@ $(eval $(call Download,qcn9074-board))
define Package/ath11k-firmware-ipq8074/install define Package/ath11k-firmware-ipq8074/install
$(INSTALL_DIR) $(1)/lib/firmware/IPQ8074 $(INSTALL_DIR) $(1)/lib/firmware/IPQ8074
$(INSTALL_DATA) \ $(INSTALL_DATA) \
$(PKG_BUILD_DIR)/ath11k-firmware/IPQ8074/hw2.0/2.9.0.1/WLAN.HK.2.9.0.1-01837-QCAHKSWPL_SILICONZ-1/* \ $(PKG_BUILD_DIR)/ath11k-firmware/IPQ8074/hw2.0/2.9.0.1/WLAN.HK.2.9.0.1-01862-QCAHKSWPL_SILICONZ-1/* \
$(1)/lib/firmware/IPQ8074/ $(1)/lib/firmware/IPQ8074/
endef endef
define Package/ath11k-firmware-qcn9074/install define Package/ath11k-firmware-qcn9074/install
$(INSTALL_DIR) $(1)/lib/firmware/ath11k/QCN9074/hw1.0 $(INSTALL_DIR) $(1)/lib/firmware/ath11k/QCN9074/hw1.0
$(INSTALL_DATA) \ $(INSTALL_DATA) \
$(PKG_BUILD_DIR)/ath11k-firmware/QCN9074/hw1.0/2.9.0.1/WLAN.HK.2.9.0.1-01837-QCAHKSWPL_SILICONZ-1/* \ $(PKG_BUILD_DIR)/ath11k-firmware/QCN9074/hw1.0/2.9.0.1/WLAN.HK.2.9.0.1-01862-QCAHKSWPL_SILICONZ-1/* \
$(1)/lib/firmware/ath11k/QCN9074/hw1.0/ $(1)/lib/firmware/ath11k/QCN9074/hw1.0/
$(INSTALL_BIN) \ $(INSTALL_BIN) \
$(DL_DIR)/$(QCN9074_BOARD_FILE) $(1)/lib/firmware/ath11k/QCN9074/hw1.0/board-2.bin $(DL_DIR)/$(QCN9074_BOARD_FILE) $(1)/lib/firmware/ath11k/QCN9074/hw1.0/board-2.bin

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_BOOL="mesh_auto_open_plinks mesh_fwding"
MP_CONFIG_STRING="mesh_power_mode" MP_CONFIG_STRING="mesh_power_mode"
NEWAPLIST= wdev_tool() {
OLDAPLIST= ucode /usr/share/hostap/wdev.uc "$@"
NEWSPLIST= }
OLDSPLIST=
NEWUMLIST=
OLDUMLIST=
drv_mac80211_init_device_config() { drv_mac80211_init_device_config() {
hostapd_common_add_device_config hostapd_common_add_device_config
@ -661,74 +658,6 @@ mac80211_check_ap() {
has_ap=1 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() { mac80211_set_ifname() {
local phy="$1" local phy="$1"
local prefix="$2" local prefix="$2"
@ -752,10 +681,10 @@ mac80211_prepare_vif() {
mac80211_set_ifname "$phy" "$prefix" mac80211_set_ifname "$phy" "$prefix"
} }
append active_ifnames "$ifname"
set_default wds 0 set_default wds 0
set_default powersave 0 set_default powersave 0
json_add_string _ifname "$ifname"
json_select ..
if [ -z "$macaddr" ]; then if [ -z "$macaddr" ]; then
macaddr="$(mac80211_generate_mac $phy)" macaddr="$(mac80211_generate_mac $phy)"
@ -763,10 +692,9 @@ mac80211_prepare_vif() {
elif [ "$macaddr" = 'random' ]; then elif [ "$macaddr" = 'random' ]; then
macaddr="$(macaddr_random)" macaddr="$(macaddr_random)"
fi fi
json_add_string _macaddr "$macaddr"
json_select ..
json_add_object data
json_add_string ifname "$ifname"
json_close_object
[ "$mode" == "ap" ] && { [ "$mode" == "ap" ] && {
[ -z "$wpa_psk_file" ] && hostapd_set_psk "$ifname" [ -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 # It is far easier to delete and create the desired interface
case "$mode" in case "$mode" in
adhoc)
mac80211_iw_interface_add "$phy" "$ifname" adhoc || return
;;
ap) ap)
# Hostapd will handle recreating the interface and # Hostapd will handle recreating the interface and
# subsequent virtual APs belonging to the same PHY # subsequent virtual APs belonging to the same PHY
@ -791,114 +716,16 @@ mac80211_prepare_vif() {
mac80211_hostapd_setup_bss "$phy" "$ifname" "$macaddr" "$type" || return mac80211_hostapd_setup_bss "$phy" "$ifname" "$macaddr" "$type" || return
NEWAPLIST="${NEWAPLIST}$ifname "
[ -n "$hostapd_ctrl" ] || { [ -n "$hostapd_ctrl" ] || {
ap_ifname="${ifname}" ap_ifname="${ifname}"
hostapd_ctrl="${hostapd_ctrl:-/var/run/hostapd/$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 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 .. 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() { mac80211_prepare_iw_htmode() {
case "$htmode" in case "$htmode" in
VHT20|HT20|HE20) iw_htmode=HT20;; VHT20|HT20|HE20) iw_htmode=HT20;;
@ -936,6 +763,13 @@ mac80211_prepare_iw_htmode() {
esac 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() { mac80211_setup_adhoc() {
local enable=$1 local enable=$1
json_get_vars bssid ssid key mcast_rate json_get_vars bssid ssid key mcast_rate
@ -977,82 +811,216 @@ mac80211_setup_adhoc() {
mcval= mcval=
[ -n "$mcast_rate" ] && wpa_supplicant_add_rate mcval "$mcast_rate" [ -n "$mcast_rate" ] && wpa_supplicant_add_rate mcval "$mcast_rate"
iw dev "$ifname" set type ibss local prev
iw dev "$ifname" ibss join "$ssid" $freq $iw_htmode fixed-freq $bssid \ json_set_namespace wdev_uc prev
beacon-interval $beacon_int \
${brstr:+basic-rates $brstr} \ json_add_object "$ifname"
${mcval:+mcast-rate $mcval} \ json_add_string mode adhoc
${keyspec:+keys $keyspec} 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() { mac80211_setup_mesh() {
local enable=$1
json_get_vars ssid mesh_id mcast_rate json_get_vars ssid mesh_id mcast_rate
NEWUMLIST="${NEWUMLIST}$ifname "
[ "$enable" = 0 ] && {
ip link set dev "$ifname" down
return 0
}
mcval= mcval=
[ -n "$mcast_rate" ] && wpa_supplicant_add_rate mcval "$mcast_rate" [ -n "$mcast_rate" ] && wpa_supplicant_add_rate mcval "$mcast_rate"
[ -n "$mesh_id" ] && ssid="$mesh_id" [ -n "$mesh_id" ] && ssid="$mesh_id"
iw dev "$ifname" mesh join "$ssid" freq $freq $iw_htmode \ local prev
${mcval:+mcast-rate $mcval} \ json_set_namespace wdev_uc prev
beacon-interval $beacon_int
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() { mac80211_setup_vif() {
local name="$1" local name="$1"
local failed local failed
local action=up
json_select data
json_get_vars ifname
json_select ..
json_select config json_select config
json_get_vars mode json_get_var ifname _ifname
json_get_var vif_txpower json_get_var macaddr _macaddr
json_get_var vif_enable enable 1 json_get_vars mode wds powersave
[ "$vif_enable" = 1 ] || action=down set_default powersave 0
if [ "$mode" != "ap" ] || [ "$ifname" = "$ap_ifname" ]; then set_default wds 0
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
case "$mode" in case "$mode" in
mesh) mesh)
json_get_vars $MP_CONFIG_INT $MP_CONFIG_BOOL $MP_CONFIG_STRING
wireless_vif_parse_encryption wireless_vif_parse_encryption
[ -z "$htmode" ] && htmode="NOHT"; [ -z "$htmode" ] && htmode="NOHT";
if wpa_supplicant -vmesh || [ "$wpa" -gt 0 -o "$auto_channel" -gt 0 ] || chan_is_dfs "$phy" "$channel"; then if wpa_supplicant -vmesh; then
mac80211_setup_supplicant $vif_enable || failed=1 mac80211_setup_supplicant || failed=1
else else
mac80211_setup_mesh $vif_enable mac80211_setup_mesh
fi 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) adhoc)
wireless_vif_parse_encryption wireless_vif_parse_encryption
if [ "$wpa" -gt 0 -o "$auto_channel" -gt 0 ]; then if [ "$wpa" -gt 0 -o "$auto_channel" -gt 0 ]; then
mac80211_setup_supplicant_noctl $vif_enable || failed=1 mac80211_setup_supplicant || failed=1
else else
mac80211_setup_adhoc $vif_enable mac80211_setup_adhoc
fi fi
;; ;;
sta) sta)
mac80211_setup_supplicant $vif_enable || failed=1 mac80211_setup_supplicant || failed=1
;;
monitor)
mac80211_setup_monitor
;; ;;
esac esac
@ -1085,7 +1053,6 @@ band_match && $3 == "MHz" && $4 == channel {
' '
} }
chan_is_dfs() { chan_is_dfs() {
local phy="$1" local phy="$1"
local chan="$2" local chan="$2"
@ -1093,27 +1060,6 @@ chan_is_dfs() {
return $! 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() { mac80211_set_noscan() {
hostapd_noscan=1 hostapd_noscan=1
} }
@ -1122,6 +1068,15 @@ drv_mac80211_cleanup() {
hostapd_common_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() { drv_mac80211_setup() {
json_select config json_select config
json_get_vars \ json_get_vars \
@ -1141,30 +1096,11 @@ drv_mac80211_setup() {
} }
wireless_set_data phy="$phy" 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 wdev
local cwdev local cwdev
local found 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 # convert channel to frequency
[ "$auto_channel" -gt 0 ] || freq="$(get_freq "$phy" "$channel" "$band")" [ "$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" hostapd_conf_file="/var/run/hostapd-$phy.conf"
no_ap=1
macidx=0 macidx=0
staidx=0 staidx=0
@ -1212,78 +1147,36 @@ drv_mac80211_setup() {
hostapd_ctrl= hostapd_ctrl=
ap_ifname= ap_ifname=
hostapd_noscan= hostapd_noscan=
wpa_supp_init=
for_each_interface "ap" mac80211_check_ap 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 for_each_interface "sta adhoc mesh" mac80211_set_noscan
[ -n "$has_ap" ] && mac80211_hostapd_setup_base "$phy" [ -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 mac80211_prepare_iw_htmode
for_each_interface "sta adhoc mesh monitor" mac80211_prepare_vif active_ifnames=
NEWAPLIST= for_each_interface "ap sta adhoc mesh monitor" mac80211_prepare_vif
for_each_interface "ap" mac80211_prepare_vif for_each_interface "ap sta adhoc mesh monitor" mac80211_setup_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}"
[ "${add_ap}" = 1 ] && sleep 1 [ -x /usr/sbin/wpa_supplicant ] && wpa_supplicant_set_config "$phy"
for_each_interface "ap" mac80211_setup_vif [ -x /usr/sbin/hostapd ] && hostapd_set_config "$phy"
NEWSPLIST= [ -x /usr/sbin/wpa_supplicant ] && wpa_supplicant_start "$phy"
NEWUMLIST=
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}" for_each_interface "ap sta adhoc mesh monitor" mac80211_set_vif_txpower
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"
wireless_set_up wireless_set_up
} }
@ -1314,8 +1207,12 @@ drv_mac80211_teardown() {
return 1 return 1
} }
mac80211_interface_cleanup "$phy" mac80211_reset_config "$phy"
uci -q -P /var/state revert wireless._${phy}
for wdev in $(list_phy_interfaces "$phy"); do
ip link set dev "$wdev" down
iw dev "$wdev" del
done
} }
add_driver mac80211 add_driver mac80211

View file

@ -5,9 +5,9 @@ PKG_RELEASE:=1
PKG_SOURCE_PROTO:=git PKG_SOURCE_PROTO:=git
PKG_SOURCE_URL=$(PROJECT_GIT)/project/netifd.git PKG_SOURCE_URL=$(PROJECT_GIT)/project/netifd.git
PKG_SOURCE_DATE:=2023-07-03 PKG_SOURCE_DATE:=2023-07-17
PKG_SOURCE_VERSION:=e94f7a81a03992805aa443156b73721228e6e2d1 PKG_SOURCE_VERSION:=0ff22a6a68ce942d4c9e7d58355d128dd3793b06
PKG_MIRROR_HASH:=4cf3199c2ebb96bcee183a2c9a750541afca16a16942008e865b4313c14a01bd PKG_MIRROR_HASH:=4cc81829fa6eb571d67f6879c78d2f514b757a34cc963b7627d55a7a8deffb75
PKG_MAINTAINER:=Felix Fietkau <nbd@nbd.name> PKG_MAINTAINER:=Felix Fietkau <nbd@nbd.name>
PKG_LICENSE:=GPL-2.0 PKG_LICENSE:=GPL-2.0

View file

@ -81,12 +81,15 @@ ifneq ($(CONFIG_DRIVER_11AX_SUPPORT),)
HOSTAPD_IEEE80211AX:=y HOSTAPD_IEEE80211AX:=y
endif 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= \ DRIVER_MAKEOPTS= \
CONFIG_ACS=$(CONFIG_PACKAGE_kmod-cfg80211) \ CONFIG_ACS=$(CONFIG_PACKAGE_kmod-cfg80211) \
CONFIG_DRIVER_NL80211=$(CONFIG_PACKAGE_kmod-cfg80211) \ CONFIG_DRIVER_NL80211=$(CONFIG_PACKAGE_kmod-cfg80211) \
CONFIG_IEEE80211AC=$(HOSTAPD_IEEE80211AC) \ CONFIG_IEEE80211AC=$(HOSTAPD_IEEE80211AC) \
CONFIG_IEEE80211AX=$(HOSTAPD_IEEE80211AX) \ CONFIG_IEEE80211AX=$(HOSTAPD_IEEE80211AX) \
CONFIG_MBO=$(CONFIG_WPA_MBO_SUPPORT) CONFIG_MBO=$(CONFIG_WPA_MBO_SUPPORT) \
CONFIG_UCODE=y
ifeq ($(SSL_VARIANT),openssl) ifeq ($(SSL_VARIANT),openssl)
DRIVER_MAKEOPTS += CONFIG_TLS=openssl CONFIG_SAE=y DRIVER_MAKEOPTS += CONFIG_TLS=openssl CONFIG_SAE=y
@ -148,7 +151,7 @@ define Package/hostapd/Default
SUBMENU:=WirelessAPD SUBMENU:=WirelessAPD
TITLE:=IEEE 802.1x Authenticator TITLE:=IEEE 802.1x Authenticator
URL:=http://hostap.epitest.fi/ URL:=http://hostap.epitest.fi/
DEPENDS:=$(DRV_DEPENDS) +hostapd-common +libubus DEPENDS:=$(DRV_DEPENDS) +hostapd-common $(CORE_DEPENDS)
EXTRA_DEPENDS:=hostapd-common (=$(PKG_VERSION)-$(PKG_RELEASE)) EXTRA_DEPENDS:=hostapd-common (=$(PKG_VERSION)-$(PKG_RELEASE))
USERID:=network=101:network=101 USERID:=network=101:network=101
PROVIDES:=hostapd PROVIDES:=hostapd
@ -253,7 +256,7 @@ define Package/wpad/Default
CATEGORY:=Network CATEGORY:=Network
SUBMENU:=WirelessAPD SUBMENU:=WirelessAPD
TITLE:=IEEE 802.1x Auth/Supplicant TITLE:=IEEE 802.1x Auth/Supplicant
DEPENDS:=$(DRV_DEPENDS) +hostapd-common +libubus DEPENDS:=$(DRV_DEPENDS) +hostapd-common $(CORE_DEPENDS)
EXTRA_DEPENDS:=hostapd-common (=$(PKG_VERSION)-$(PKG_RELEASE)) EXTRA_DEPENDS:=hostapd-common (=$(PKG_VERSION)-$(PKG_RELEASE))
USERID:=network=101:network=101 USERID:=network=101:network=101
URL:=http://hostap.epitest.fi/ URL:=http://hostap.epitest.fi/
@ -398,7 +401,7 @@ define Package/wpa-supplicant/Default
SUBMENU:=WirelessAPD SUBMENU:=WirelessAPD
TITLE:=WPA Supplicant TITLE:=WPA Supplicant
URL:=http://hostap.epitest.fi/wpa_supplicant/ URL:=http://hostap.epitest.fi/wpa_supplicant/
DEPENDS:=$(DRV_DEPENDS) +hostapd-common +libubus DEPENDS:=$(DRV_DEPENDS) +hostapd-common $(CORE_DEPENDS)
EXTRA_DEPENDS:=hostapd-common (=$(PKG_VERSION)-$(PKG_RELEASE)) EXTRA_DEPENDS:=hostapd-common (=$(PKG_VERSION)-$(PKG_RELEASE))
USERID:=network=101:network=101 USERID:=network=101:network=101
PROVIDES:=wpa-supplicant PROVIDES:=wpa-supplicant
@ -520,7 +523,7 @@ define Package/eapol-test/Default
SECTION:=net SECTION:=net
SUBMENU:=WirelessAPD SUBMENU:=WirelessAPD
CATEGORY:=Network CATEGORY:=Network
DEPENDS:=$(DRV_DEPENDS) +libubus DEPENDS:=$(DRV_DEPENDS) $(CORE_DEPENDS)
endef endef
define Package/eapol-test define Package/eapol-test
@ -585,7 +588,7 @@ TARGET_CPPFLAGS := \
-D_GNU_SOURCE \ -D_GNU_SOURCE \
$(if $(CONFIG_WPA_MSG_MIN_PRIORITY),-DCONFIG_MSG_MIN_PRIORITY=$(CONFIG_WPA_MSG_MIN_PRIORITY)) $(if $(CONFIG_WPA_MSG_MIN_PRIORITY),-DCONFIG_MSG_MIN_PRIORITY=$(CONFIG_WPA_MSG_MIN_PRIORITY))
TARGET_LDFLAGS += -lubox -lubus TARGET_LDFLAGS += -lubox -lubus -lblobmsg_json -lucode
ifdef CONFIG_PACKAGE_kmod-cfg80211 ifdef CONFIG_PACKAGE_kmod-cfg80211
TARGET_LDFLAGS += -lm -lnl-tiny TARGET_LDFLAGS += -lm -lnl-tiny
@ -674,22 +677,55 @@ define Build/Compile
$(Build/Compile/$(BUILD_VARIANT)) $(Build/Compile/$(BUILD_VARIANT))
endef endef
define Install/hostapd/full
$(INSTALL_DIR) $(1)/etc/init.d $(1)/etc/config $(1)/etc/radius
ln -sf hostapd $(1)/usr/sbin/hostapd-radius
$(INSTALL_BIN) ./files/radius.init $(1)/etc/init.d/radius
$(INSTALL_DATA) ./files/radius.config $(1)/etc/config/radius
$(INSTALL_DATA) ./files/radius.clients $(1)/etc/radius/clients
$(INSTALL_DATA) ./files/radius.users $(1)/etc/radius/users
endef
define Package/hostapd-full/conffiles
/etc/config/radius
/etc/radius
endef
ifeq ($(CONFIG_VARIANT),full)
Package/wpad-mesh-openssl/conffiles = $(Package/hostapd-full/conffiles)
Package/wpad-mesh-wolfssl/conffiles = $(Package/hostapd-full/conffiles)
Package/wpad-mesh-mbedtls/conffiles = $(Package/hostapd-full/conffiles)
Package/wpad/conffiles = $(Package/hostapd-full/conffiles)
Package/wpad-openssl/conffiles = $(Package/hostapd-full/conffiles)
Package/wpad-wolfssl/conffiles = $(Package/hostapd-full/conffiles)
Package/wpad-mbedtls/conffiles = $(Package/hostapd-full/conffiles)
Package/hostapd/conffiles = $(Package/hostapd-full/conffiles)
Package/hostapd-openssl/conffiles = $(Package/hostapd-full/conffiles)
Package/hostapd-wolfssl/conffiles = $(Package/hostapd-full/conffiles)
Package/hostapd-mbedtls/conffiles = $(Package/hostapd-full/conffiles)
endif
define Install/hostapd 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 endef
define Install/supplicant 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 endef
define Package/hostapd-common/install 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_BIN) ./files/dhcp-get-server.sh $(1)/lib/netifd/dhcp-get-server.sh
$(INSTALL_DATA) ./files/hostapd.sh $(1)/lib/netifd/hostapd.sh $(INSTALL_DATA) ./files/hostapd.sh $(1)/lib/netifd/hostapd.sh
$(INSTALL_BIN) ./files/wpad.init $(1)/etc/init.d/wpad $(INSTALL_BIN) ./files/wpad.init $(1)/etc/init.d/wpad
$(INSTALL_BIN) ./files/wps-hotplug.sh $(1)/etc/rc.button/wps $(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_acl.json $(1)/usr/share/acl.d
$(INSTALL_DATA) ./files/wpad.json $(1)/etc/capabilities $(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 endef
define Package/hostapd/install 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 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() { hostapd_common_cleanup() {
killall meshd-nl80211 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 @@
0.0.0.0/0 radius

View file

@ -0,0 +1,9 @@
config radius
option disabled '1'
option ca_cert '/etc/radius/ca.pem'
option cert '/etc/radius/cert.pem'
option key '/etc/radius/key.pem'
option users '/etc/radius/users'
option clients '/etc/radius/clients'
option auth_port '1812'
option acct_port '1813'

View file

@ -0,0 +1,42 @@
#!/bin/sh /etc/rc.common
START=30
USE_PROCD=1
NAME=radius
radius_start() {
local cfg="$1"
config_get_bool disabled "$cfg" disabled 0
[ "$disabled" -gt 0 ] && return
config_get ca "$cfg" ca_cert
config_get key "$cfg" key
config_get cert "$cfg" cert
config_get users "$cfg" users
config_get clients "$cfg" clients
config_get auth_port "$cfg" auth_port 1812
config_get acct_port "$cfg" acct_port 1813
config_get identity "$cfg" identity "$(cat /proc/sys/kernel/hostname)"
procd_open_instance $cfg
procd_set_param command /usr/sbin/hostapd-radius \
-C "$ca" \
-c "$cert" -k "$key" \
-s "$clients" -u "$users" \
-p "$auth_port" -P "$acct_port" \
-i "$identity"
procd_close_instance
}
start_service() {
config_load radius
config_foreach radius_start radius
}
service_triggers()
{
procd_add_reload_trigger "radius"
}

View file

@ -0,0 +1,14 @@
{
"phase1": {
"wildcard": [
{
"name": "*",
"methods": [ "PEAP" ]
}
]
},
"phase2": {
"users": {
}
}
}

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

@ -1,11 +1,12 @@
--- a/hostapd/Makefile --- a/hostapd/Makefile
+++ b/hostapd/Makefile +++ b/hostapd/Makefile
@@ -166,6 +166,11 @@ OBJS += ../src/common/hw_features_common @@ -166,6 +166,12 @@ OBJS += ../src/common/hw_features_common
OBJS += ../src/eapol_auth/eapol_auth_sm.o OBJS += ../src/eapol_auth/eapol_auth_sm.o
+ifdef CONFIG_UBUS +ifdef CONFIG_UBUS
+CFLAGS += -DUBUS_SUPPORT +CFLAGS += -DUBUS_SUPPORT
+OBJS += ../src/utils/uloop.o
+OBJS += ../src/ap/ubus.o +OBJS += ../src/ap/ubus.o
+LIBS += -lubox -lubus +LIBS += -lubox -lubus
+endif +endif
@ -22,15 +23,6 @@
#define OCE_STA_CFON_ENABLED(hapd) \ #define OCE_STA_CFON_ENABLED(hapd) \
((hapd->conf->oce & OCE_STA_CFON) && \ ((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 { @@ -184,6 +185,7 @@ struct hostapd_data {
struct hostapd_iface *iface; struct hostapd_iface *iface;
struct hostapd_config *iconf; struct hostapd_config *iconf;
@ -330,20 +322,21 @@
--- a/wpa_supplicant/Makefile --- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile +++ b/wpa_supplicant/Makefile
@@ -194,6 +194,12 @@ ifdef CONFIG_EAPOL_TEST @@ -194,6 +194,13 @@ ifdef CONFIG_EAPOL_TEST
CFLAGS += -Werror -DEAPOL_TEST CFLAGS += -Werror -DEAPOL_TEST
endif endif
+ifdef CONFIG_UBUS +ifdef CONFIG_UBUS
+CFLAGS += -DUBUS_SUPPORT +CFLAGS += -DUBUS_SUPPORT
+OBJS += ubus.o +OBJS += ubus.o
+OBJS += ../src/utils/uloop.o
+LIBS += -lubox -lubus +LIBS += -lubox -lubus
+endif +endif
+ +
ifdef CONFIG_CODE_COVERAGE ifdef CONFIG_CODE_COVERAGE
CFLAGS += -O0 -fprofile-arcs -ftest-coverage CFLAGS += -O0 -fprofile-arcs -ftest-coverage
LIBS += -lgcov LIBS += -lgcov
@@ -989,6 +995,9 @@ ifdef CONFIG_CTRL_IFACE_MIB @@ -989,6 +996,9 @@ ifdef CONFIG_CTRL_IFACE_MIB
CFLAGS += -DCONFIG_CTRL_IFACE_MIB CFLAGS += -DCONFIG_CTRL_IFACE_MIB
endif endif
OBJS += ../src/ap/ctrl_iface_ap.o OBJS += ../src/ap/ctrl_iface_ap.o
@ -432,24 +425,6 @@
if (wpa_s->conf->wps_cred_processing == 1) if (wpa_s->conf->wps_cred_processing == 1)
return 0; 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 --- a/wpa_supplicant/main.c
+++ b/wpa_supplicant/main.c +++ b/wpa_supplicant/main.c
@@ -204,7 +204,7 @@ int main(int argc, char *argv[]) @@ -204,7 +204,7 @@ int main(int argc, char *argv[])
@ -623,3 +598,151 @@
wpa_hexdump(MSG_DEBUG, "WNM: BSS Transition Candidate List Entries", wpa_hexdump(MSG_DEBUG, "WNM: BSS Transition Candidate List Entries",
pos, end - pos); pos, end - pos);
} }
--- a/src/utils/eloop.c
+++ b/src/utils/eloop.c
@@ -77,6 +77,9 @@ struct eloop_sock_table {
struct eloop_data {
int max_sock;
+ eloop_timeout_poll_handler timeout_poll_cb;
+ eloop_poll_handler poll_cb;
+
size_t count; /* sum of all table counts */
#ifdef CONFIG_ELOOP_POLL
size_t max_pollfd_map; /* number of pollfds_map currently allocated */
@@ -1121,6 +1124,12 @@ void eloop_run(void)
os_reltime_sub(&timeout->time, &now, &tv);
else
tv.sec = tv.usec = 0;
+ }
+
+ if (eloop.timeout_poll_cb && eloop.timeout_poll_cb(&tv, !!timeout))
+ timeout = (void *)1;
+
+ if (timeout) {
#if defined(CONFIG_ELOOP_POLL) || defined(CONFIG_ELOOP_EPOLL)
timeout_ms = tv.sec * 1000 + tv.usec / 1000;
#endif /* defined(CONFIG_ELOOP_POLL) || defined(CONFIG_ELOOP_EPOLL) */
@@ -1190,7 +1199,8 @@ void eloop_run(void)
eloop.exceptions.changed = 0;
eloop_process_pending_signals();
-
+ if (eloop.poll_cb)
+ eloop.poll_cb();
/* check if some registered timeouts have occurred */
timeout = dl_list_first(&eloop.timeout, struct eloop_timeout,
@@ -1252,6 +1262,14 @@ out:
return;
}
+int eloop_register_cb(eloop_poll_handler poll_cb,
+ eloop_timeout_poll_handler timeout_cb)
+{
+ eloop.poll_cb = poll_cb;
+ eloop.timeout_poll_cb = timeout_cb;
+
+ return 0;
+}
void eloop_terminate(void)
{
--- a/src/utils/eloop.h
+++ b/src/utils/eloop.h
@@ -65,6 +65,9 @@ typedef void (*eloop_timeout_handler)(vo
*/
typedef void (*eloop_signal_handler)(int sig, void *signal_ctx);
+typedef bool (*eloop_timeout_poll_handler)(struct os_reltime *tv, bool tv_set);
+typedef void (*eloop_poll_handler)(void);
+
/**
* eloop_init() - Initialize global event loop data
* Returns: 0 on success, -1 on failure
@@ -73,6 +76,9 @@ typedef void (*eloop_signal_handler)(int
*/
int eloop_init(void);
+int eloop_register_cb(eloop_poll_handler poll_cb,
+ eloop_timeout_poll_handler timeout_cb);
+
/**
* eloop_register_read_sock - Register handler for read events
* @sock: File descriptor number for the socket
@@ -320,6 +326,8 @@ int eloop_register_signal_reconfig(eloop
*/
int eloop_sock_requeue(void);
+void eloop_add_uloop(void);
+
/**
* eloop_run - Start the event loop
*
--- /dev/null
+++ b/src/utils/uloop.c
@@ -0,0 +1,64 @@
+#include <libubox/uloop.h>
+#include "includes.h"
+#include "common.h"
+#include "eloop.h"
+
+static void eloop_uloop_event_cb(int sock, void *eloop_ctx, void *sock_ctx)
+{
+}
+
+static void eloop_uloop_fd_cb(struct uloop_fd *fd, unsigned int events)
+{
+ unsigned int changed = events ^ fd->flags;
+
+ if (changed & ULOOP_READ) {
+ if (events & ULOOP_READ)
+ eloop_register_sock(fd->fd, EVENT_TYPE_READ, eloop_uloop_event_cb, fd, fd);
+ else
+ eloop_unregister_sock(fd->fd, EVENT_TYPE_READ);
+ }
+
+ if (changed & ULOOP_WRITE) {
+ if (events & ULOOP_WRITE)
+ eloop_register_sock(fd->fd, EVENT_TYPE_WRITE, eloop_uloop_event_cb, fd, fd);
+ else
+ eloop_unregister_sock(fd->fd, EVENT_TYPE_WRITE);
+ }
+}
+
+static bool uloop_timeout_poll_handler(struct os_reltime *tv, bool tv_set)
+{
+ struct os_reltime tv_uloop;
+ int timeout_ms = uloop_get_next_timeout();
+
+ if (timeout_ms < 0)
+ return false;
+
+ tv_uloop.sec = timeout_ms / 1000;
+ tv_uloop.usec = (timeout_ms % 1000) * 1000;
+
+ if (!tv_set || os_reltime_before(&tv_uloop, tv)) {
+ *tv = tv_uloop;
+ return true;
+ }
+
+ return false;
+}
+
+static void uloop_poll_handler(void)
+{
+ uloop_run_timeout(0);
+}
+
+void eloop_add_uloop(void)
+{
+ static bool init_done = false;
+
+ if (!init_done) {
+ uloop_init();
+ uloop_fd_set_cb = eloop_uloop_fd_cb;
+ init_done = true;
+ }
+
+ eloop_register_cb(uloop_poll_handler, uloop_timeout_poll_handler);
+}

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; int rts_threshold;
--- a/src/ap/hostapd.c --- a/src/ap/hostapd.c
+++ b/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 @@ -255,6 +255,10 @@ static int hostapd_iface_conf_changed(st
{ {
size_t i; size_t i;
@ -60,7 +69,7 @@
{ {
struct hapd_interfaces *interfaces = iface->interfaces; struct hapd_interfaces *interfaces = iface->interfaces;
struct hostapd_data *hapd = iface->bss[0]; 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; char *fname;
int res; int res;
@ -70,7 +79,7 @@
hostapd_clear_old(iface); hostapd_clear_old(iface);
wpa_printf(MSG_DEBUG, 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, wpa_printf(MSG_ERROR,
"Failed to enable interface on config reload"); "Failed to enable interface on config reload");
return res; return res;
@ -95,7 +104,7 @@
} }
iface->conf = newconf; 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++) { for (j = 0; j < iface->num_bss; j++) {
hapd = iface->bss[j]; hapd = iface->bss[j];
@ -108,7 +117,17 @@
if (!hapd->conf->config_id || !newconf->bss[j]->config_id || if (!hapd->conf->config_id || !newconf->bss[j]->config_id ||
os_strcmp(hapd->conf->config_id, os_strcmp(hapd->conf->config_id,
newconf->bss[j]->config_id) != 0) 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->iconf = conf;
hapd->conf = bss; hapd->conf = bss;
hapd->iface = hapd_iface; hapd->iface = hapd_iface;
@ -119,9 +138,18 @@
if (conf) if (conf)
hapd->driver = conf->driver; hapd->driver = conf->driver;
hapd->ctrl_sock = -1; 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 --- a/src/ap/hostapd.h
+++ b/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 hostapd_iface;
struct hapd_interfaces { struct hapd_interfaces {
@ -130,23 +158,33 @@
struct hostapd_config * (*config_read_cb)(const char *config_fname); struct hostapd_config * (*config_read_cb)(const char *config_fname);
int (*ctrl_iface_init)(struct hostapd_data *hapd); int (*ctrl_iface_init)(struct hostapd_data *hapd);
void (*ctrl_iface_deinit)(struct hostapd_data *hapd); void (*ctrl_iface_deinit)(struct hostapd_data *hapd);
@@ -186,6 +186,7 @@ struct hostapd_data { @@ -192,6 +192,7 @@ struct hostapd_data {
struct hostapd_config *iconf;
struct hostapd_bss_config *conf; struct hostapd_bss_config *conf;
struct hostapd_ubus_bss ubus; struct hostapd_ubus_bss ubus;
struct hostapd_ucode_bss ucode;
+ char *config_id; + char *config_id;
int interface_added; /* virtual interface added for this BSS */ int interface_added; /* virtual interface added for this BSS */
unsigned int started:1; unsigned int started:1;
unsigned int disabled: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 hostapd_for_each_interface(struct hapd_interfaces *interfaces,
int (*cb)(struct hostapd_iface *iface, int (*cb)(struct hostapd_iface *iface,
void *ctx), void *ctx); void *ctx), void *ctx);
-int hostapd_reload_config(struct hostapd_iface *iface); -int hostapd_reload_config(struct hostapd_iface *iface);
+int hostapd_reload_config(struct hostapd_iface *iface, int reconf); +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); void hostapd_reconfig_encryption(struct hostapd_data *hapd);
struct hostapd_data * struct hostapd_data *
hostapd_alloc_bss_data(struct hostapd_iface *hapd_iface, 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 --- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c
@@ -5322,6 +5322,9 @@ static int wpa_driver_nl80211_set_ap(voi @@ -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) { } else if (os_strcmp(buf, "extended_key_id") == 0) {
--- a/src/ap/hostapd.h --- a/src/ap/hostapd.h
+++ b/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); void hostapd_periodic_iface(struct hostapd_iface *iface);
int hostapd_owe_trans_get_info(struct hostapd_data *hapd); int hostapd_owe_trans_get_info(struct hostapd_data *hapd);
void hostapd_ocv_check_csa_sa_query(void *eloop_ctx, void *timeout_ctx); 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); os_free(bss->dump_msk_file);
--- a/src/ap/hostapd.c --- a/src/ap/hostapd.c
+++ b/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"); wpa_printf(MSG_ERROR, "GAS server initialization failed");
return -1; return -1;
} }
@ -40,7 +40,7 @@
if (conf->qos_map_set_len && if (conf->qos_map_set_len &&
hostapd_drv_set_qos_map(hapd, conf->qos_map_set, 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"); wpa_printf(MSG_ERROR, "Failed to initialize QoS Map");
return -1; return -1;
} }

View file

@ -10,7 +10,7 @@
unsigned int time_window; unsigned int time_window;
--- a/src/ap/hostapd.c --- a/src/ap/hostapd.c
+++ b/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)); os_memset(&das_conf, 0, sizeof(das_conf));
das_conf.port = conf->radius_das_port; das_conf.port = conf->radius_das_port;

View file

@ -0,0 +1,154 @@
--- a/hostapd/Makefile
+++ b/hostapd/Makefile
@@ -63,6 +63,10 @@ endif
OBJS += main.o
OBJS += config_file.o
+ifdef CONFIG_RADIUS_SERVER
+OBJS += radius.o
+endif
+
OBJS += ../src/ap/hostapd.o
OBJS += ../src/ap/wpa_auth_glue.o
OBJS += ../src/ap/drv_callbacks.o
--- a/hostapd/main.c
+++ b/hostapd/main.c
@@ -42,6 +42,7 @@ static struct hapd_global global;
static int daemonize = 0;
static char *pid_file = NULL;
+extern int radius_main(int argc, char **argv);
#ifndef CONFIG_NO_HOSTAPD_LOGGER
static void hostapd_logger_cb(void *ctx, const u8 *addr, unsigned int module,
@@ -755,6 +756,11 @@ int main(int argc, char *argv[])
if (os_program_init())
return -1;
+#ifdef RADIUS_SERVER
+ if (strstr(argv[0], "radius"))
+ return radius_main(argc, argv);
+#endif
+
os_memset(&interfaces, 0, sizeof(interfaces));
interfaces.reload_config = hostapd_reload_config;
interfaces.config_read_cb = hostapd_config_read;
--- a/src/radius/radius_server.c
+++ b/src/radius/radius_server.c
@@ -63,6 +63,12 @@ struct radius_server_counters {
u32 unknown_acct_types;
};
+struct radius_accept_attr {
+ u8 type;
+ u16 len;
+ void *data;
+};
+
/**
* struct radius_session - Internal RADIUS server data for a session
*/
@@ -90,7 +96,7 @@ struct radius_session {
unsigned int macacl:1;
unsigned int t_c_filtering:1;
- struct hostapd_radius_attr *accept_attr;
+ struct radius_accept_attr *accept_attr;
u32 t_c_timestamp; /* Last read T&C timestamp from user DB */
};
@@ -394,6 +400,7 @@ static void radius_server_session_free(s
radius_msg_free(sess->last_reply);
os_free(sess->username);
os_free(sess->nas_ip);
+ os_free(sess->accept_attr);
os_free(sess);
data->num_sess--;
}
@@ -554,6 +561,36 @@ radius_server_erp_find_key(struct radius
}
#endif /* CONFIG_ERP */
+static struct radius_accept_attr *
+radius_server_copy_attr(const struct hostapd_radius_attr *data)
+{
+ const struct hostapd_radius_attr *attr;
+ struct radius_accept_attr *attr_new;
+ size_t data_size = 0;
+ void *data_buf;
+ int n_attr = 1;
+
+ for (attr = data; attr; attr = attr->next) {
+ n_attr++;
+ data_size += wpabuf_len(attr->val);
+ }
+
+ attr_new = os_zalloc(n_attr * sizeof(*attr) + data_size);
+ if (!attr_new)
+ return NULL;
+
+ data_buf = &attr_new[n_attr];
+ for (n_attr = 0, attr = data; attr; attr = attr->next) {
+ struct radius_accept_attr *cur = &attr_new[n_attr++];
+
+ cur->type = attr->type;
+ cur->len = wpabuf_len(attr->val);
+ cur->data = memcpy(data_buf, wpabuf_head(attr->val), cur->len);
+ data_buf += cur->len;
+ }
+
+ return attr_new;
+}
static struct radius_session *
radius_server_get_new_session(struct radius_server_data *data,
@@ -607,7 +644,7 @@ radius_server_get_new_session(struct rad
eap_user_free(tmp);
return NULL;
}
- sess->accept_attr = tmp->accept_attr;
+ sess->accept_attr = radius_server_copy_attr(tmp->accept_attr);
sess->macacl = tmp->macacl;
eap_user_free(tmp);
@@ -1118,11 +1155,10 @@ radius_server_encapsulate_eap(struct rad
}
if (code == RADIUS_CODE_ACCESS_ACCEPT) {
- struct hostapd_radius_attr *attr;
- for (attr = sess->accept_attr; attr; attr = attr->next) {
- if (!radius_msg_add_attr(msg, attr->type,
- wpabuf_head(attr->val),
- wpabuf_len(attr->val))) {
+ struct radius_accept_attr *attr;
+ for (attr = sess->accept_attr; attr->data; attr++) {
+ if (!radius_msg_add_attr(msg, attr->type, attr->data,
+ attr->len)) {
wpa_printf(MSG_ERROR, "Could not add RADIUS attribute");
radius_msg_free(msg);
return NULL;
@@ -1211,11 +1247,10 @@ radius_server_macacl(struct radius_serve
}
if (code == RADIUS_CODE_ACCESS_ACCEPT) {
- struct hostapd_radius_attr *attr;
- for (attr = sess->accept_attr; attr; attr = attr->next) {
- if (!radius_msg_add_attr(msg, attr->type,
- wpabuf_head(attr->val),
- wpabuf_len(attr->val))) {
+ struct radius_accept_attr *attr;
+ for (attr = sess->accept_attr; attr->data; attr++) {
+ if (!radius_msg_add_attr(msg, attr->type, attr->data,
+ attr->len)) {
wpa_printf(MSG_ERROR, "Could not add RADIUS attribute");
radius_msg_free(msg);
return NULL;
@@ -2512,7 +2547,7 @@ static int radius_server_get_eap_user(vo
ret = data->get_eap_user(data->conf_ctx, identity, identity_len,
phase2, user);
if (ret == 0 && user) {
- sess->accept_attr = user->accept_attr;
+ sess->accept_attr = radius_server_copy_attr(user->accept_attr);
sess->remediation = user->remediation;
sess->macacl = user->macacl;
sess->t_c_timestamp = user->t_c_timestamp;

View file

@ -0,0 +1,715 @@
#include "utils/includes.h"
#include "utils/common.h"
#include "utils/eloop.h"
#include "crypto/crypto.h"
#include "crypto/tls.h"
#include "ap/ap_config.h"
#include "eap_server/eap.h"
#include "radius/radius.h"
#include "radius/radius_server.h"
#include "eap_register.h"
#include <libubox/blobmsg_json.h>
#include <libubox/blobmsg.h>
#include <libubox/avl.h>
#include <libubox/avl-cmp.h>
#include <libubox/kvlist.h>
#include <sys/stat.h>
#include <fnmatch.h>
#define VENDOR_ID_WISPR 14122
#define VENDOR_ATTR_SIZE 6
struct radius_parse_attr_data {
unsigned int vendor;
u8 type;
int size;
char format;
const char *data;
};
struct radius_parse_attr_state {
struct hostapd_radius_attr *prev;
struct hostapd_radius_attr *attr;
struct wpabuf *buf;
void *attrdata;
};
struct radius_user_state {
struct avl_node node;
struct eap_user data;
};
struct radius_user_data {
struct kvlist users;
struct avl_tree user_state;
struct blob_attr *wildcard;
};
struct radius_state {
struct radius_server_data *radius;
struct eap_config eap;
struct radius_user_data phase1, phase2;
const char *user_file;
time_t user_file_ts;
int n_attrs;
struct hostapd_radius_attr *attrs;
};
struct radius_config {
struct tls_connection_params tls;
struct radius_server_conf radius;
};
enum {
USER_ATTR_PASSWORD,
USER_ATTR_HASH,
USER_ATTR_SALT,
USER_ATTR_METHODS,
USER_ATTR_RADIUS,
USER_ATTR_VLAN,
USER_ATTR_MAX_RATE_UP,
USER_ATTR_MAX_RATE_DOWN,
__USER_ATTR_MAX
};
static void radius_tls_event(void *ctx, enum tls_event ev,
union tls_event_data *data)
{
switch (ev) {
case TLS_CERT_CHAIN_SUCCESS:
wpa_printf(MSG_DEBUG, "radius: remote certificate verification success");
break;
case TLS_CERT_CHAIN_FAILURE:
wpa_printf(MSG_INFO, "radius: certificate chain failure: reason=%d depth=%d subject='%s' err='%s'",
data->cert_fail.reason,
data->cert_fail.depth,
data->cert_fail.subject,
data->cert_fail.reason_txt);
break;
case TLS_PEER_CERTIFICATE:
wpa_printf(MSG_DEBUG, "radius: peer certificate: depth=%d serial_num=%s subject=%s",
data->peer_cert.depth,
data->peer_cert.serial_num ? data->peer_cert.serial_num : "N/A",
data->peer_cert.subject);
break;
case TLS_ALERT:
if (data->alert.is_local)
wpa_printf(MSG_DEBUG, "radius: local TLS alert: %s",
data->alert.description);
else
wpa_printf(MSG_DEBUG, "radius: remote TLS alert: %s",
data->alert.description);
break;
case TLS_UNSAFE_RENEGOTIATION_DISABLED:
/* Not applicable to TLS server */
break;
}
}
static void radius_userdata_init(struct radius_user_data *u)
{
kvlist_init(&u->users, kvlist_blob_len);
avl_init(&u->user_state, avl_strcmp, false, NULL);
}
static void radius_userdata_free(struct radius_user_data *u)
{
struct radius_user_state *s, *tmp;
kvlist_free(&u->users);
free(u->wildcard);
u->wildcard = NULL;
avl_remove_all_elements(&u->user_state, s, node, tmp)
free(s);
}
static void
radius_userdata_load(struct radius_user_data *u, struct blob_attr *data)
{
enum {
USERSTATE_USERS,
USERSTATE_WILDCARD,
__USERSTATE_MAX,
};
static const struct blobmsg_policy policy[__USERSTATE_MAX] = {
[USERSTATE_USERS] = { "users", BLOBMSG_TYPE_TABLE },
[USERSTATE_WILDCARD] = { "wildcard", BLOBMSG_TYPE_ARRAY },
};
struct blob_attr *tb[__USERSTATE_MAX], *cur;
int rem;
if (!data)
return;
blobmsg_parse(policy, __USERSTATE_MAX, tb, blobmsg_data(data), blobmsg_len(data));
blobmsg_for_each_attr(cur, tb[USERSTATE_USERS], rem)
kvlist_set(&u->users, blobmsg_name(cur), cur);
if (tb[USERSTATE_WILDCARD])
u->wildcard = blob_memdup(tb[USERSTATE_WILDCARD]);
}
static void
load_userfile(struct radius_state *s)
{
enum {
USERDATA_PHASE1,
USERDATA_PHASE2,
__USERDATA_MAX
};
static const struct blobmsg_policy policy[__USERDATA_MAX] = {
[USERDATA_PHASE1] = { "phase1", BLOBMSG_TYPE_TABLE },
[USERDATA_PHASE2] = { "phase2", BLOBMSG_TYPE_TABLE },
};
struct blob_attr *tb[__USERDATA_MAX], *cur;
static struct blob_buf b;
struct stat st;
int rem;
if (stat(s->user_file, &st))
return;
if (s->user_file_ts == st.st_mtime)
return;
s->user_file_ts = st.st_mtime;
radius_userdata_free(&s->phase1);
radius_userdata_free(&s->phase2);
blob_buf_init(&b, 0);
blobmsg_add_json_from_file(&b, s->user_file);
blobmsg_parse(policy, __USERDATA_MAX, tb, blob_data(b.head), blob_len(b.head));
radius_userdata_load(&s->phase1, tb[USERDATA_PHASE1]);
radius_userdata_load(&s->phase2, tb[USERDATA_PHASE2]);
blob_buf_free(&b);
}
static struct blob_attr *
radius_user_get(struct radius_user_data *s, const char *name)
{
struct blob_attr *cur;
int rem;
cur = kvlist_get(&s->users, name);
if (cur)
return cur;
blobmsg_for_each_attr(cur, s->wildcard, rem) {
static const struct blobmsg_policy policy = {
"name", BLOBMSG_TYPE_STRING
};
struct blob_attr *pattern;
if (blobmsg_type(cur) != BLOBMSG_TYPE_TABLE)
continue;
blobmsg_parse(&policy, 1, &pattern, blobmsg_data(cur), blobmsg_len(cur));
if (!name)
continue;
if (!fnmatch(blobmsg_get_string(pattern), name, 0))
return cur;
}
return NULL;
}
static struct radius_parse_attr_data *
radius_parse_attr(struct blob_attr *attr)
{
static const struct blobmsg_policy policy[4] = {
{ .type = BLOBMSG_TYPE_INT32 },
{ .type = BLOBMSG_TYPE_INT32 },
{ .type = BLOBMSG_TYPE_STRING },
{ .type = BLOBMSG_TYPE_STRING },
};
static struct radius_parse_attr_data data;
struct blob_attr *tb[4];
const char *format;
blobmsg_parse_array(policy, ARRAY_SIZE(policy), tb, blobmsg_data(attr), blobmsg_len(attr));
if (!tb[0] || !tb[1] || !tb[2] || !tb[3])
return NULL;
format = blobmsg_get_string(tb[2]);
if (strlen(format) != 1)
return NULL;
data.vendor = blobmsg_get_u32(tb[0]);
data.type = blobmsg_get_u32(tb[1]);
data.format = format[0];
data.data = blobmsg_get_string(tb[3]);
data.size = strlen(data.data);
switch (data.format) {
case 's':
break;
case 'x':
if (data.size & 1)
return NULL;
data.size /= 2;
break;
case 'd':
data.size = 4;
break;
default:
return NULL;
}
return &data;
}
static void
radius_count_attrs(struct blob_attr **tb, int *n_attr, size_t *attr_size)
{
struct blob_attr *data = tb[USER_ATTR_RADIUS];
struct blob_attr *cur;
int rem;
blobmsg_for_each_attr(cur, data, rem) {
struct radius_parse_attr_data *data;
size_t prev = *attr_size;
data = radius_parse_attr(cur);
if (!data)
continue;
*attr_size += data->size;
if (data->vendor)
*attr_size += VENDOR_ATTR_SIZE;
(*n_attr)++;
}
*n_attr += !!tb[USER_ATTR_VLAN] * 3 +
!!tb[USER_ATTR_MAX_RATE_UP] +
!!tb[USER_ATTR_MAX_RATE_DOWN];
*attr_size += !!tb[USER_ATTR_VLAN] * (4 + 4 + 5) +
!!tb[USER_ATTR_MAX_RATE_UP] * (4 + VENDOR_ATTR_SIZE) +
!!tb[USER_ATTR_MAX_RATE_DOWN] * (4 + VENDOR_ATTR_SIZE);
}
static void *
radius_add_attr(struct radius_parse_attr_state *state,
u32 vendor, u8 type, u8 len)
{
struct hostapd_radius_attr *attr;
struct wpabuf *buf;
void *val;
val = state->attrdata;
buf = state->buf++;
buf->buf = val;
attr = state->attr++;
attr->val = buf;
attr->type = type;
if (state->prev)
state->prev->next = attr;
state->prev = attr;
if (vendor) {
u8 *vendor_hdr = val + 4;
WPA_PUT_BE32(val, vendor);
vendor_hdr[0] = type;
vendor_hdr[1] = len + 2;
len += VENDOR_ATTR_SIZE;
val += VENDOR_ATTR_SIZE;
attr->type = RADIUS_ATTR_VENDOR_SPECIFIC;
}
buf->size = buf->used = len;
state->attrdata += len;
return val;
}
static void
radius_parse_attrs(struct blob_attr **tb, struct radius_parse_attr_state *state)
{
struct blob_attr *data = tb[USER_ATTR_RADIUS];
struct hostapd_radius_attr *prev = NULL;
struct blob_attr *cur;
int len, rem;
void *val;
if ((cur = tb[USER_ATTR_VLAN]) != NULL && blobmsg_get_u32(cur) < 4096) {
char buf[5];
val = radius_add_attr(state, 0, RADIUS_ATTR_TUNNEL_TYPE, 4);
WPA_PUT_BE32(val, RADIUS_TUNNEL_TYPE_VLAN);
val = radius_add_attr(state, 0, RADIUS_ATTR_TUNNEL_MEDIUM_TYPE, 4);
WPA_PUT_BE32(val, RADIUS_TUNNEL_MEDIUM_TYPE_802);
len = snprintf(buf, sizeof(buf), "%d", blobmsg_get_u32(cur));
val = radius_add_attr(state, 0, RADIUS_ATTR_TUNNEL_PRIVATE_GROUP_ID, len);
memcpy(val, buf, len);
}
if ((cur = tb[USER_ATTR_MAX_RATE_UP]) != NULL) {
val = radius_add_attr(state, VENDOR_ID_WISPR, 7, 4);
WPA_PUT_BE32(val, blobmsg_get_u32(cur));
}
if ((cur = tb[USER_ATTR_MAX_RATE_DOWN]) != NULL) {
val = radius_add_attr(state, VENDOR_ID_WISPR, 8, 4);
WPA_PUT_BE32(val, blobmsg_get_u32(cur));
}
blobmsg_for_each_attr(cur, data, rem) {
struct radius_parse_attr_data *data;
void *val;
int size;
data = radius_parse_attr(cur);
if (!data)
continue;
val = radius_add_attr(state, data->vendor, data->type, data->size);
switch (data->format) {
case 's':
memcpy(val, data->data, data->size);
break;
case 'x':
hexstr2bin(data->data, val, data->size);
break;
case 'd':
WPA_PUT_BE32(val, atoi(data->data));
break;
}
}
}
static void
radius_user_parse_methods(struct eap_user *eap, struct blob_attr *data)
{
struct blob_attr *cur;
int rem, n = 0;
if (!data)
return;
blobmsg_for_each_attr(cur, data, rem) {
const char *method;
if (blobmsg_type(cur) != BLOBMSG_TYPE_STRING)
continue;
if (n == EAP_MAX_METHODS)
break;
method = blobmsg_get_string(cur);
eap->methods[n].method = eap_server_get_type(method, &eap->methods[n].vendor);
if (eap->methods[n].vendor == EAP_VENDOR_IETF &&
eap->methods[n].method == EAP_TYPE_NONE) {
if (!strcmp(method, "TTLS-PAP")) {
eap->ttls_auth |= EAP_TTLS_AUTH_PAP;
continue;
}
if (!strcmp(method, "TTLS-CHAP")) {
eap->ttls_auth |= EAP_TTLS_AUTH_CHAP;
continue;
}
if (!strcmp(method, "TTLS-MSCHAP")) {
eap->ttls_auth |= EAP_TTLS_AUTH_MSCHAP;
continue;
}
if (!strcmp(method, "TTLS-MSCHAPV2")) {
eap->ttls_auth |= EAP_TTLS_AUTH_MSCHAPV2;
continue;
}
}
n++;
}
}
static struct eap_user *
radius_user_get_state(struct radius_user_data *u, struct blob_attr *data,
const char *id)
{
static const struct blobmsg_policy policy[__USER_ATTR_MAX] = {
[USER_ATTR_PASSWORD] = { "password", BLOBMSG_TYPE_STRING },
[USER_ATTR_HASH] = { "hash", BLOBMSG_TYPE_STRING },
[USER_ATTR_SALT] = { "salt", BLOBMSG_TYPE_STRING },
[USER_ATTR_METHODS] = { "methods", BLOBMSG_TYPE_ARRAY },
[USER_ATTR_RADIUS] = { "radius", BLOBMSG_TYPE_ARRAY },
[USER_ATTR_VLAN] = { "vlan-id", BLOBMSG_TYPE_INT32 },
[USER_ATTR_MAX_RATE_UP] = { "max-rate-up", BLOBMSG_TYPE_INT32 },
[USER_ATTR_MAX_RATE_DOWN] = { "max-rate-down", BLOBMSG_TYPE_INT32 },
};
struct blob_attr *tb[__USER_ATTR_MAX], *cur;
char *password_buf, *salt_buf, *name_buf;
struct radius_parse_attr_state astate = {};
struct hostapd_radius_attr *attr;
struct radius_user_state *state;
int pw_len = 0, salt_len = 0;
struct eap_user *eap;
struct wpabuf *val;
size_t attrsize = 0;
void *attrdata;
int n_attr = 0;
state = avl_find_element(&u->user_state, id, state, node);
if (state)
return &state->data;
blobmsg_parse(policy, __USER_ATTR_MAX, tb, blobmsg_data(data), blobmsg_len(data));
if ((cur = tb[USER_ATTR_SALT]) != NULL)
salt_len = strlen(blobmsg_get_string(cur)) / 2;
if ((cur = tb[USER_ATTR_HASH]) != NULL)
pw_len = strlen(blobmsg_get_string(cur)) / 2;
else if ((cur = tb[USER_ATTR_PASSWORD]) != NULL)
pw_len = blobmsg_len(cur) - 1;
radius_count_attrs(tb, &n_attr, &attrsize);
state = calloc_a(sizeof(*state), &name_buf, strlen(id) + 1,
&password_buf, pw_len,
&salt_buf, salt_len,
&astate.attr, n_attr * sizeof(*astate.attr),
&astate.buf, n_attr * sizeof(*astate.buf),
&astate.attrdata, attrsize);
eap = &state->data;
eap->salt = salt_len ? salt_buf : NULL;
eap->salt_len = salt_len;
eap->password = pw_len ? password_buf : NULL;
eap->password_len = pw_len;
eap->force_version = -1;
if ((cur = tb[USER_ATTR_SALT]) != NULL)
hexstr2bin(blobmsg_get_string(cur), salt_buf, salt_len);
if ((cur = tb[USER_ATTR_PASSWORD]) != NULL)
memcpy(password_buf, blobmsg_get_string(cur), pw_len);
else if ((cur = tb[USER_ATTR_HASH]) != NULL) {
hexstr2bin(blobmsg_get_string(cur), password_buf, pw_len);
eap->password_hash = 1;
}
radius_user_parse_methods(eap, tb[USER_ATTR_METHODS]);
if (n_attr > 0) {
cur = tb[USER_ATTR_RADIUS];
eap->accept_attr = astate.attr;
radius_parse_attrs(tb, &astate);
}
state->node.key = strcpy(name_buf, id);
avl_insert(&u->user_state, &state->node);
return &state->data;
free:
free(state);
return NULL;
}
static int radius_get_eap_user(void *ctx, const u8 *identity,
size_t identity_len, int phase2,
struct eap_user *user)
{
struct radius_state *s = ctx;
struct radius_user_data *u = phase2 ? &s->phase2 : &s->phase1;
struct blob_attr *entry;
struct eap_user *data;
char *id;
if (identity_len > 512)
return -1;
load_userfile(s);
id = alloca(identity_len + 1);
memcpy(id, identity, identity_len);
id[identity_len] = 0;
entry = radius_user_get(u, id);
if (!entry)
return -1;
if (!user)
return 0;
data = radius_user_get_state(u, entry, id);
if (!data)
return -1;
*user = *data;
if (user->password_len > 0)
user->password = os_memdup(user->password, user->password_len);
if (user->salt_len > 0)
user->salt = os_memdup(user->salt, user->salt_len);
user->phase2 = phase2;
return 0;
}
static int radius_setup(struct radius_state *s, struct radius_config *c)
{
struct eap_config *eap = &s->eap;
struct tls_config conf = {
.event_cb = radius_tls_event,
.tls_flags = TLS_CONN_DISABLE_TLSv1_3,
.cb_ctx = s,
};
eap->eap_server = 1;
eap->max_auth_rounds = 100;
eap->max_auth_rounds_short = 50;
eap->ssl_ctx = tls_init(&conf);
if (!eap->ssl_ctx) {
wpa_printf(MSG_INFO, "TLS init failed\n");
return 1;
}
if (tls_global_set_params(eap->ssl_ctx, &c->tls)) {
wpa_printf(MSG_INFO, "failed to set TLS parameters\n");
return 1;
}
c->radius.eap_cfg = eap;
c->radius.conf_ctx = s;
c->radius.get_eap_user = radius_get_eap_user;
s->radius = radius_server_init(&c->radius);
if (!s->radius) {
wpa_printf(MSG_INFO, "failed to initialize radius server\n");
return 1;
}
return 0;
}
static int radius_init(struct radius_state *s)
{
memset(s, 0, sizeof(*s));
radius_userdata_init(&s->phase1);
radius_userdata_init(&s->phase2);
}
static void radius_deinit(struct radius_state *s)
{
if (s->radius)
radius_server_deinit(s->radius);
if (s->eap.ssl_ctx)
tls_deinit(s->eap.ssl_ctx);
radius_userdata_free(&s->phase1);
radius_userdata_free(&s->phase2);
}
static int usage(const char *progname)
{
fprintf(stderr, "Usage: %s <options>\n",
progname);
}
int radius_main(int argc, char **argv)
{
static struct radius_state state = {};
static struct radius_config config = {};
const char *progname = argv[0];
int ret = 0;
int ch;
wpa_debug_setup_stdout();
wpa_debug_level = 0;
if (eloop_init()) {
wpa_printf(MSG_ERROR, "Failed to initialize event loop");
return 1;
}
eap_server_register_methods();
radius_init(&state);
while ((ch = getopt(argc, argv, "6C:c:d:i:k:K:p:P:s:u:")) != -1) {
switch (ch) {
case '6':
config.radius.ipv6 = 1;
break;
case 'C':
config.tls.ca_cert = optarg;
break;
case 'c':
if (config.tls.client_cert2)
return usage(progname);
if (config.tls.client_cert)
config.tls.client_cert2 = optarg;
else
config.tls.client_cert = optarg;
break;
case 'd':
config.tls.dh_file = optarg;
break;
case 'i':
state.eap.server_id = optarg;
state.eap.server_id_len = strlen(optarg);
break;
case 'k':
if (config.tls.private_key2)
return usage(progname);
if (config.tls.private_key)
config.tls.private_key2 = optarg;
else
config.tls.private_key = optarg;
break;
case 'K':
if (config.tls.private_key_passwd2)
return usage(progname);
if (config.tls.private_key_passwd)
config.tls.private_key_passwd2 = optarg;
else
config.tls.private_key_passwd = optarg;
break;
case 'p':
config.radius.auth_port = atoi(optarg);
break;
case 'P':
config.radius.acct_port = atoi(optarg);
break;
case 's':
config.radius.client_file = optarg;
break;
case 'u':
state.user_file = optarg;
break;
default:
return usage(progname);
}
}
if (!config.tls.client_cert || !config.tls.private_key ||
!config.radius.client_file || !state.eap.server_id ||
!state.user_file) {
wpa_printf(MSG_INFO, "missing options\n");
goto out;
}
ret = radius_setup(&state, &config);
if (ret)
goto out;
load_userfile(&state);
eloop_run();
out:
radius_deinit(&state);
os_program_deinit();
return ret;
}

View file

@ -29,11 +29,6 @@ static struct ubus_context *ctx;
static struct blob_buf b; static struct blob_buf b;
static int ctx_ref; 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) static inline struct hostapd_data *get_hapd_from_object(struct ubus_object *obj)
{ {
return container_of(obj, struct hostapd_data, ubus.obj); return container_of(obj, struct hostapd_data, ubus.obj);
@ -44,12 +39,6 @@ struct ubus_banned_client {
u8 addr[ETH_ALEN]; u8 addr[ETH_ALEN];
}; };
static void ubus_receive(int sock, void *eloop_ctx, void *sock_ctx)
{
struct ubus_context *ctx = eloop_ctx;
ubus_handle_event(ctx);
}
static void ubus_reconnect_timeout(void *eloop_data, void *user_ctx) static void ubus_reconnect_timeout(void *eloop_data, void *user_ctx)
{ {
if (ubus_reconnect(ctx, NULL)) { if (ubus_reconnect(ctx, NULL)) {
@ -57,12 +46,12 @@ static void ubus_reconnect_timeout(void *eloop_data, void *user_ctx)
return; return;
} }
eloop_register_read_sock(ctx->sock.fd, ubus_receive, ctx, NULL); ubus_add_uloop(ctx);
} }
static void hostapd_ubus_connection_lost(struct ubus_context *ctx) static void hostapd_ubus_connection_lost(struct ubus_context *ctx)
{ {
eloop_unregister_read_sock(ctx->sock.fd); uloop_fd_delete(&ctx->sock);
eloop_register_timeout(1, 0, ubus_reconnect_timeout, ctx, NULL); eloop_register_timeout(1, 0, ubus_reconnect_timeout, ctx, NULL);
} }
@ -71,12 +60,14 @@ static bool hostapd_ubus_init(void)
if (ctx) if (ctx)
return true; return true;
eloop_add_uloop();
ctx = ubus_connect(NULL); ctx = ubus_connect(NULL);
if (!ctx) if (!ctx)
return false; return false;
ctx->connection_lost = hostapd_ubus_connection_lost; ctx->connection_lost = hostapd_ubus_connection_lost;
eloop_register_read_sock(ctx->sock.fd, ubus_receive, ctx, NULL); ubus_add_uloop(ctx);
return true; return true;
} }
@ -94,7 +85,7 @@ static void hostapd_ubus_ref_dec(void)
if (ctx_ref) if (ctx_ref)
return; return;
eloop_unregister_read_sock(ctx->sock.fd); uloop_fd_delete(&ctx->sock);
ubus_free(ctx); ubus_free(ctx);
ctx = NULL; ctx = NULL;
} }
@ -127,38 +118,6 @@ static void hostapd_notify_ubus(struct ubus_object *obj, char *bssname, char *ev
free(event_type); 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 static void
hostapd_bss_del_ban(void *eloop_data, void *user_ctx) hostapd_bss_del_ban(void *eloop_data, void *user_ctx)
{ {
@ -203,10 +162,8 @@ hostapd_bss_reload(struct ubus_context *ctx, struct ubus_object *obj,
struct blob_attr *msg) struct blob_attr *msg)
{ {
struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj); 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 hostapd_reload_config(hapd->iface, 1);
return ret;
} }
@ -687,68 +644,6 @@ enum {
__CONFIG_MAX __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 { enum {
CSA_FREQ, CSA_FREQ,
CSA_BCN_COUNT, CSA_BCN_COUNT,
@ -1669,10 +1564,61 @@ hostapd_bss_update_airtime(struct ubus_context *ctx, struct ubus_object *obj,
} }
#endif #endif
#ifdef CONFIG_TAXONOMY
static const struct blobmsg_policy addr_policy[] = {
{ "address", BLOBMSG_TYPE_STRING }
};
static bool
hostapd_add_b64_data(const char *name, const struct wpabuf *buf)
{
char *str;
if (!buf)
return false;
str = blobmsg_alloc_string_buffer(&b, name, B64_ENCODE_LEN(wpabuf_len(buf)));
b64_encode(wpabuf_head(buf), wpabuf_len(buf), str, B64_ENCODE_LEN(wpabuf_len(buf)));
blobmsg_add_string_buffer(&b);
return true;
}
static int
hostapd_bss_get_sta_ies(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method,
struct blob_attr *msg)
{
struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj);
struct blob_attr *tb;
struct sta_info *sta;
u8 addr[ETH_ALEN];
blobmsg_parse(addr_policy, 1, &tb, blobmsg_data(msg), blobmsg_len(msg));
if (!tb || hwaddr_aton(blobmsg_data(tb), addr))
return UBUS_STATUS_INVALID_ARGUMENT;
sta = ap_get_sta(hapd, addr);
if (!sta || (!sta->probe_ie_taxonomy && !sta->assoc_ie_taxonomy))
return UBUS_STATUS_NOT_FOUND;
blob_buf_init(&b, 0);
hostapd_add_b64_data("probe_ie", sta->probe_ie_taxonomy);
hostapd_add_b64_data("assoc_ie", sta->assoc_ie_taxonomy);
ubus_send_reply(ctx, req, b.head);
return 0;
}
#endif
static const struct ubus_method bss_methods[] = { static const struct ubus_method bss_methods[] = {
UBUS_METHOD_NOARG("reload", hostapd_bss_reload), UBUS_METHOD_NOARG("reload", hostapd_bss_reload),
UBUS_METHOD_NOARG("get_clients", hostapd_bss_get_clients), UBUS_METHOD_NOARG("get_clients", hostapd_bss_get_clients),
#ifdef CONFIG_TAXONOMY
UBUS_METHOD("get_sta_ies", hostapd_bss_get_sta_ies, addr_policy),
#endif
UBUS_METHOD_NOARG("get_status", hostapd_bss_get_status), UBUS_METHOD_NOARG("get_status", hostapd_bss_get_status),
UBUS_METHOD("del_client", hostapd_bss_del_client, del_policy), UBUS_METHOD("del_client", hostapd_bss_del_client, del_policy),
#ifdef CONFIG_AIRTIME_POLICY #ifdef CONFIG_AIRTIME_POLICY
@ -1734,8 +1680,6 @@ void hostapd_ubus_add_bss(struct hostapd_data *hapd)
obj->n_methods = bss_object_type.n_methods; obj->n_methods = bss_object_type.n_methods;
ret = ubus_add_object(ctx, obj); ret = ubus_add_object(ctx, obj);
hostapd_ubus_ref_inc(); 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) void hostapd_ubus_free_bss(struct hostapd_data *hapd)
@ -1751,8 +1695,6 @@ void hostapd_ubus_free_bss(struct hostapd_data *hapd)
if (!ctx) if (!ctx)
return; return;
hostapd_send_shared_event(&hapd->iface->interfaces->ubus, hapd->conf->iface, "remove");
if (obj->id) { if (obj->id) {
ubus_remove_object(ctx, obj); ubus_remove_object(ctx, obj);
hostapd_ubus_ref_dec(); hostapd_ubus_ref_dec();
@ -1798,47 +1740,6 @@ void hostapd_ubus_remove_vlan(struct hostapd_data *hapd, struct hostapd_vlan *vl
hostapd_ubus_vlan_action(hapd, vlan, "vlan_remove"); 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_event_req {
struct ubus_notify_request nreq; struct ubus_notify_request nreq;
int resp; 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

@ -30,12 +30,6 @@ static inline struct wpa_supplicant *get_wpas_from_object(struct ubus_object *ob
return container_of(obj, struct wpa_supplicant, ubus.obj); return container_of(obj, struct wpa_supplicant, ubus.obj);
} }
static void ubus_receive(int sock, void *eloop_ctx, void *sock_ctx)
{
struct ubus_context *ctx = eloop_ctx;
ubus_handle_event(ctx);
}
static void ubus_reconnect_timeout(void *eloop_data, void *user_ctx) static void ubus_reconnect_timeout(void *eloop_data, void *user_ctx)
{ {
if (ubus_reconnect(ctx, NULL)) { if (ubus_reconnect(ctx, NULL)) {
@ -43,12 +37,12 @@ static void ubus_reconnect_timeout(void *eloop_data, void *user_ctx)
return; return;
} }
eloop_register_read_sock(ctx->sock.fd, ubus_receive, ctx, NULL); ubus_add_uloop(ctx);
} }
static void wpas_ubus_connection_lost(struct ubus_context *ctx) static void wpas_ubus_connection_lost(struct ubus_context *ctx)
{ {
eloop_unregister_read_sock(ctx->sock.fd); uloop_fd_delete(&ctx->sock);
eloop_register_timeout(1, 0, ubus_reconnect_timeout, ctx, NULL); eloop_register_timeout(1, 0, ubus_reconnect_timeout, ctx, NULL);
} }
@ -57,12 +51,14 @@ static bool wpas_ubus_init(void)
if (ctx) if (ctx)
return true; return true;
eloop_add_uloop();
ctx = ubus_connect(NULL); ctx = ubus_connect(NULL);
if (!ctx) if (!ctx)
return false; return false;
ctx->connection_lost = wpas_ubus_connection_lost; ctx->connection_lost = wpas_ubus_connection_lost;
eloop_register_read_sock(ctx->sock.fd, ubus_receive, ctx, NULL); ubus_add_uloop(ctx);
return true; return true;
} }
@ -80,7 +76,7 @@ static void wpas_ubus_ref_dec(void)
if (ctx_ref) if (ctx_ref)
return; return;
eloop_unregister_read_sock(ctx->sock.fd); uloop_fd_delete(&ctx->sock);
ubus_free(ctx); ubus_free(ctx);
ctx = NULL; ctx = NULL;
} }
@ -211,152 +207,6 @@ void wpas_ubus_free_bss(struct wpa_supplicant *wpa_s)
free(name); 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 #ifdef CONFIG_WPS
void wpas_ubus_notify(struct wpa_supplicant *wpa_s, const struct wps_credential *cred) 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_add_bss(struct wpa_supplicant *wpa_s);
void wpas_ubus_free_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 #ifdef CONFIG_WPS
void wpas_ubus_notify(struct wpa_supplicant *wpa_s, const struct wps_credential *cred); void wpas_ubus_notify(struct wpa_supplicant *wpa_s, const struct wps_credential *cred);
#endif #endif
@ -34,14 +31,6 @@ void wpas_ubus_notify(struct wpa_supplicant *wpa_s, const struct wps_credential
#else #else
struct wpas_ubus_bss {}; 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) 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