440 lines
		
	
	
		
			7.8 KiB
		
	
	
	
		
			Bash
		
	
	
	
	
	
			
		
		
	
	
			440 lines
		
	
	
		
			7.8 KiB
		
	
	
	
		
			Bash
		
	
	
	
	
	
NETIFD_MAIN_DIR="${NETIFD_MAIN_DIR:-/lib/netifd}"
 | 
						|
 | 
						|
. /usr/share/libubox/jshn.sh
 | 
						|
. $NETIFD_MAIN_DIR/utils.sh
 | 
						|
 | 
						|
CMD_UP=0
 | 
						|
CMD_SET_DATA=1
 | 
						|
CMD_PROCESS_ADD=2
 | 
						|
CMD_PROCESS_KILL_ALL=3
 | 
						|
CMD_SET_RETRY=4
 | 
						|
 | 
						|
add_driver() {
 | 
						|
	return
 | 
						|
}
 | 
						|
 | 
						|
wireless_setup_vif_failed() {
 | 
						|
	local error="$1"
 | 
						|
	echo "Interface $_w_iface setup failed: $error"
 | 
						|
}
 | 
						|
 | 
						|
wireless_setup_failed() {
 | 
						|
	local error="$1"
 | 
						|
 | 
						|
	echo "Device setup failed: $error"
 | 
						|
	wireless_set_retry 0
 | 
						|
}
 | 
						|
 | 
						|
prepare_key_wep() {
 | 
						|
	local key="$1"
 | 
						|
	local hex=1
 | 
						|
 | 
						|
	echo -n "$key" | grep -qE "[^a-fA-F0-9]" && hex=0
 | 
						|
	[ "${#key}" -eq 10 -a $hex -eq 1 ] || \
 | 
						|
	[ "${#key}" -eq 26 -a $hex -eq 1 ] || {
 | 
						|
		[ "${key:0:2}" = "s:" ] && key="${key#s:}"
 | 
						|
		key="$(echo -n "$key" | hexdump -ve '1/1 "%02x" ""')"
 | 
						|
	}
 | 
						|
	echo "$key"
 | 
						|
}
 | 
						|
 | 
						|
_wdev_prepare_channel() {
 | 
						|
	json_get_vars channel band hwmode
 | 
						|
 | 
						|
	auto_channel=0
 | 
						|
	enable_ht=0
 | 
						|
	htmode=
 | 
						|
	hwmode="${hwmode##11}"
 | 
						|
 | 
						|
	case "$channel" in
 | 
						|
		""|0|auto)
 | 
						|
			channel=0
 | 
						|
			auto_channel=1
 | 
						|
		;;
 | 
						|
		[0-9]*) ;;
 | 
						|
		*)
 | 
						|
			wireless_setup_failed "INVALID_CHANNEL"
 | 
						|
		;;
 | 
						|
	esac
 | 
						|
 | 
						|
	case "$hwmode" in
 | 
						|
		a|b|g|ad) ;;
 | 
						|
		*)
 | 
						|
			if [ "$channel" -gt 14 ]; then
 | 
						|
				hwmode=a
 | 
						|
			else
 | 
						|
				hwmode=g
 | 
						|
			fi
 | 
						|
		;;
 | 
						|
	esac
 | 
						|
 | 
						|
	case "$band" in
 | 
						|
		2g) hwmode=g;;
 | 
						|
		5g|6g) hwmode=a;;
 | 
						|
		60g) hwmode=ad;;
 | 
						|
		*)
 | 
						|
			case "$hwmode" in
 | 
						|
				*a) band=5g;;
 | 
						|
				*ad) band=60g;;
 | 
						|
				*b|*g) band=2g;;
 | 
						|
			esac
 | 
						|
		;;
 | 
						|
	esac
 | 
						|
}
 | 
						|
 | 
						|
_wdev_handler() {
 | 
						|
	json_load "$data"
 | 
						|
 | 
						|
	json_select config
 | 
						|
	_wdev_prepare_channel
 | 
						|
	json_select ..
 | 
						|
 | 
						|
	eval "drv_$1_$2 \"$interface\""
 | 
						|
}
 | 
						|
 | 
						|
_wdev_msg_call() {
 | 
						|
	local old_cb
 | 
						|
 | 
						|
	json_set_namespace wdev old_cb
 | 
						|
	"$@"
 | 
						|
	json_set_namespace $old_cb
 | 
						|
}
 | 
						|
 | 
						|
_wdev_wrapper() {
 | 
						|
	while [ -n "$1" ]; do
 | 
						|
		eval "$1() { _wdev_msg_call _$1 \"\$@\"; }"
 | 
						|
		shift
 | 
						|
	done
 | 
						|
}
 | 
						|
 | 
						|
_wdev_notify_init() {
 | 
						|
	local command="$1"; shift;
 | 
						|
 | 
						|
	json_init
 | 
						|
	json_add_int "command" "$command"
 | 
						|
	json_add_string "device" "$__netifd_device"
 | 
						|
	while [ -n "$1" ]; do
 | 
						|
		local name="$1"; shift
 | 
						|
		local value="$1"; shift
 | 
						|
		json_add_string "$name" "$value"
 | 
						|
	done
 | 
						|
	json_add_object "data"
 | 
						|
}
 | 
						|
 | 
						|
_wdev_notify() {
 | 
						|
	local options="$1"
 | 
						|
 | 
						|
	json_close_object
 | 
						|
	ubus $options call network.wireless notify "$(json_dump)"
 | 
						|
}
 | 
						|
 | 
						|
_wdev_add_variables() {
 | 
						|
	while [ -n "$1" ]; do
 | 
						|
		local var="${1%%=*}"
 | 
						|
		local val="$1"
 | 
						|
		shift
 | 
						|
		[[ "$var" = "$val" ]] && continue
 | 
						|
		val="${val#*=}"
 | 
						|
		json_add_string "$var" "$val"
 | 
						|
	done
 | 
						|
}
 | 
						|
 | 
						|
_wireless_add_vif() {
 | 
						|
	local name="$1"; shift
 | 
						|
	local ifname="$1"; shift
 | 
						|
 | 
						|
	_wdev_notify_init $CMD_SET_DATA "interface" "$name"
 | 
						|
	json_add_string "ifname" "$ifname"
 | 
						|
	_wdev_add_variables "$@"
 | 
						|
	_wdev_notify
 | 
						|
}
 | 
						|
 | 
						|
_wireless_add_vlan() {
 | 
						|
	local name="$1"; shift
 | 
						|
	local ifname="$1"; shift
 | 
						|
 | 
						|
	_wdev_notify_init $CMD_SET_DATA interface "$__cur_interface" "vlan" "$name"
 | 
						|
	json_add_string "ifname" "$ifname"
 | 
						|
	_wdev_add_variables "$@"
 | 
						|
	_wdev_notify
 | 
						|
}
 | 
						|
 | 
						|
_wireless_set_up() {
 | 
						|
	_wdev_notify_init $CMD_UP
 | 
						|
	_wdev_notify
 | 
						|
}
 | 
						|
 | 
						|
_wireless_set_data() {
 | 
						|
	_wdev_notify_init $CMD_SET_DATA
 | 
						|
	_wdev_add_variables "$@"
 | 
						|
	_wdev_notify
 | 
						|
}
 | 
						|
 | 
						|
_wireless_add_process() {
 | 
						|
	_wdev_notify_init $CMD_PROCESS_ADD
 | 
						|
	local exe="$2"
 | 
						|
	[ -L "$exe" ] && exe="$(readlink -f "$exe")"
 | 
						|
	json_add_int pid "$1"
 | 
						|
	json_add_string exe "$exe"
 | 
						|
	[ -n "$3" ] && json_add_boolean required 1
 | 
						|
	[ -n "$4" ] && json_add_boolean keep 1
 | 
						|
	exe2="$(readlink -f /proc/$1/exe)"
 | 
						|
	[ "$exe" != "$exe2" ] && echo "WARNING (wireless_add_process): executable path $exe does not match process $1 path ($exe2)"
 | 
						|
	_wdev_notify
 | 
						|
}
 | 
						|
 | 
						|
_wireless_process_kill_all() {
 | 
						|
	_wdev_notify_init $CMD_PROCESS_KILL_ALL
 | 
						|
	[ -n "$1" ] && json_add_int signal "$1"
 | 
						|
	_wdev_notify
 | 
						|
}
 | 
						|
 | 
						|
_wireless_set_retry() {
 | 
						|
	_wdev_notify_init $CMD_SET_RETRY
 | 
						|
	json_add_int retry "$1"
 | 
						|
	_wdev_notify
 | 
						|
}
 | 
						|
 | 
						|
_wdev_wrapper \
 | 
						|
	wireless_add_vif \
 | 
						|
	wireless_add_vlan \
 | 
						|
	wireless_set_up \
 | 
						|
	wireless_set_data \
 | 
						|
	wireless_add_process \
 | 
						|
	wireless_process_kill_all \
 | 
						|
	wireless_set_retry \
 | 
						|
 | 
						|
wireless_vif_parse_encryption() {
 | 
						|
	json_get_vars encryption
 | 
						|
	set_default encryption none
 | 
						|
 | 
						|
	auth_mode_open=1
 | 
						|
	auth_mode_shared=0
 | 
						|
	auth_type=none
 | 
						|
 | 
						|
	if [ "$hwmode" = "ad" ]; then
 | 
						|
		wpa_cipher="GCMP"
 | 
						|
	else
 | 
						|
		wpa_cipher="CCMP"
 | 
						|
	fi
 | 
						|
 | 
						|
	case "$encryption" in
 | 
						|
		*tkip+aes|*tkip+ccmp|*aes+tkip|*ccmp+tkip) wpa_cipher="CCMP TKIP";;
 | 
						|
		*ccmp256) wpa_cipher="CCMP-256";;
 | 
						|
		*aes|*ccmp) wpa_cipher="CCMP";;
 | 
						|
		*tkip) wpa_cipher="TKIP";;
 | 
						|
		*gcmp256) wpa_cipher="GCMP-256";;
 | 
						|
		*gcmp) wpa_cipher="GCMP";;
 | 
						|
		wpa3-192*) wpa_cipher="GCMP-256";;
 | 
						|
	esac
 | 
						|
 | 
						|
	# 802.11n requires CCMP for WPA
 | 
						|
	[ "$enable_ht:$wpa_cipher" = "1:TKIP" ] && wpa_cipher="CCMP TKIP"
 | 
						|
 | 
						|
	# Examples:
 | 
						|
	# psk-mixed/tkip    => WPA1+2 PSK, TKIP
 | 
						|
	# wpa-psk2/tkip+aes => WPA2 PSK, CCMP+TKIP
 | 
						|
	# wpa2/tkip+aes     => WPA2 RADIUS, CCMP+TKIP
 | 
						|
 | 
						|
	case "$encryption" in
 | 
						|
		wpa2*|wpa3*|*psk2*|psk3*|sae*|owe*)
 | 
						|
			wpa=2
 | 
						|
		;;
 | 
						|
		wpa*mixed*|*psk*mixed*)
 | 
						|
			wpa=3
 | 
						|
		;;
 | 
						|
		wpa*|*psk*)
 | 
						|
			wpa=1
 | 
						|
		;;
 | 
						|
		*)
 | 
						|
			wpa=0
 | 
						|
			wpa_cipher=
 | 
						|
		;;
 | 
						|
	esac
 | 
						|
	wpa_pairwise="$wpa_cipher"
 | 
						|
 | 
						|
	case "$encryption" in
 | 
						|
		owe*)
 | 
						|
			auth_type=owe
 | 
						|
		;;
 | 
						|
		wpa3-192*)
 | 
						|
			auth_type=eap192
 | 
						|
		;;
 | 
						|
		wpa3-mixed*)
 | 
						|
			auth_type=eap-eap2
 | 
						|
		;;
 | 
						|
		wpa3*)
 | 
						|
			auth_type=eap2
 | 
						|
		;;
 | 
						|
		psk3-mixed*|sae-mixed*)
 | 
						|
			auth_type=psk-sae
 | 
						|
		;;
 | 
						|
		psk3*|sae*)
 | 
						|
			auth_type=sae
 | 
						|
		;;
 | 
						|
		*psk*)
 | 
						|
			auth_type=psk
 | 
						|
		;;
 | 
						|
		*wpa*|*8021x*)
 | 
						|
			auth_type=eap
 | 
						|
		;;
 | 
						|
		*wep*)
 | 
						|
			auth_type=wep
 | 
						|
			case "$encryption" in
 | 
						|
				*shared*)
 | 
						|
					auth_mode_open=0
 | 
						|
					auth_mode_shared=1
 | 
						|
				;;
 | 
						|
				*mixed*)
 | 
						|
					auth_mode_shared=1
 | 
						|
				;;
 | 
						|
			esac
 | 
						|
		;;
 | 
						|
	esac
 | 
						|
 | 
						|
	case "$encryption" in
 | 
						|
		*osen*)
 | 
						|
			auth_osen=1
 | 
						|
		;;
 | 
						|
	esac
 | 
						|
}
 | 
						|
 | 
						|
_wireless_set_brsnoop_isolation() {
 | 
						|
	local multicast_to_unicast="$1"
 | 
						|
	local isolate
 | 
						|
 | 
						|
	json_get_vars isolate proxy_arp
 | 
						|
 | 
						|
	[ ${isolate:-0} -gt 0 -o -z "$network_bridge" ] && return
 | 
						|
	[ ${multicast_to_unicast:-1} -gt 0 -o ${proxy_arp:-0} -gt 0 ] && json_add_boolean isolate 1
 | 
						|
}
 | 
						|
 | 
						|
for_each_interface() {
 | 
						|
	local _w_types="$1"; shift
 | 
						|
	local _w_ifaces _w_iface
 | 
						|
	local _w_type
 | 
						|
	local _w_found
 | 
						|
 | 
						|
	local multicast_to_unicast
 | 
						|
 | 
						|
	json_get_keys _w_ifaces interfaces
 | 
						|
	json_select interfaces
 | 
						|
	for _w_iface in $_w_ifaces; do
 | 
						|
		json_select "$_w_iface"
 | 
						|
		if [ -n "$_w_types" ]; then
 | 
						|
			json_get_var network_bridge bridge
 | 
						|
			json_get_var network_ifname bridge-ifname
 | 
						|
			json_get_var multicast_to_unicast multicast_to_unicast
 | 
						|
			json_select config
 | 
						|
			_wireless_set_brsnoop_isolation "$multicast_to_unicast"
 | 
						|
			json_get_var _w_type mode
 | 
						|
			json_select ..
 | 
						|
			_w_types=" $_w_types "
 | 
						|
			[[ "${_w_types%$_w_type*}" = "$_w_types" ]] && {
 | 
						|
				json_select ..
 | 
						|
				continue
 | 
						|
			}
 | 
						|
		fi
 | 
						|
		__cur_interface="$_w_iface"
 | 
						|
		"$@" "$_w_iface"
 | 
						|
		json_select ..
 | 
						|
	done
 | 
						|
	json_select ..
 | 
						|
}
 | 
						|
 | 
						|
for_each_vlan() {
 | 
						|
	local _w_vlans _w_vlan
 | 
						|
 | 
						|
	json_get_keys _w_vlans vlans
 | 
						|
	json_select vlans
 | 
						|
	for _w_vlan in $_w_vlans; do
 | 
						|
		json_select "$_w_vlan"
 | 
						|
		json_select config
 | 
						|
		"$@" "$_w_vlan"
 | 
						|
		json_select ..
 | 
						|
		json_select ..
 | 
						|
	done
 | 
						|
	json_select ..
 | 
						|
}
 | 
						|
 | 
						|
for_each_station() {
 | 
						|
	local _w_stas _w_sta
 | 
						|
 | 
						|
	json_get_keys _w_stas stas
 | 
						|
	json_select stas
 | 
						|
	for _w_sta in $_w_stas; do
 | 
						|
		json_select "$_w_sta"
 | 
						|
		json_select config
 | 
						|
		"$@" "$_w_sta"
 | 
						|
		json_select ..
 | 
						|
		json_select ..
 | 
						|
	done
 | 
						|
	json_select ..
 | 
						|
}
 | 
						|
 | 
						|
_wdev_common_device_config() {
 | 
						|
	config_add_string channel hwmode band htmode noscan
 | 
						|
}
 | 
						|
 | 
						|
_wdev_common_iface_config() {
 | 
						|
	config_add_string mode ssid encryption 'key:wpakey'
 | 
						|
	config_add_boolean bridge_isolate
 | 
						|
}
 | 
						|
 | 
						|
_wdev_common_vlan_config() {
 | 
						|
	config_add_string name vid iface
 | 
						|
	config_add_boolean bridge_isolate
 | 
						|
}
 | 
						|
 | 
						|
_wdev_common_station_config() {
 | 
						|
	config_add_string mac key vid iface
 | 
						|
}
 | 
						|
 | 
						|
init_wireless_driver() {
 | 
						|
	name="$1"; shift
 | 
						|
	cmd="$1"; shift
 | 
						|
 | 
						|
	case "$cmd" in
 | 
						|
		dump)
 | 
						|
			add_driver() {
 | 
						|
				eval "drv_$1_cleanup"
 | 
						|
 | 
						|
				json_init
 | 
						|
				json_add_string name "$1"
 | 
						|
 | 
						|
				json_add_array device
 | 
						|
				_wdev_common_device_config
 | 
						|
				eval "drv_$1_init_device_config"
 | 
						|
				json_close_array
 | 
						|
 | 
						|
				json_add_array iface
 | 
						|
				_wdev_common_iface_config
 | 
						|
				eval "drv_$1_init_iface_config"
 | 
						|
				json_close_array
 | 
						|
 | 
						|
				json_add_array vlan
 | 
						|
				_wdev_common_vlan_config
 | 
						|
				eval "drv_$1_init_vlan_config"
 | 
						|
				json_close_array
 | 
						|
 | 
						|
				json_add_array station
 | 
						|
				_wdev_common_station_config
 | 
						|
				eval "drv_$1_init_station_config"
 | 
						|
				json_close_array
 | 
						|
 | 
						|
				json_dump
 | 
						|
			}
 | 
						|
		;;
 | 
						|
		setup|teardown)
 | 
						|
			interface="$1"; shift
 | 
						|
			data="$1"; shift
 | 
						|
			export __netifd_device="$interface"
 | 
						|
 | 
						|
			add_driver() {
 | 
						|
				[[ "$name" == "$1" ]] || return 0
 | 
						|
				_wdev_handler "$1" "$cmd"
 | 
						|
			}
 | 
						|
		;;
 | 
						|
	esac
 | 
						|
}
 |