#!/bin/sh
. /lib/netifd/netifd-wireless.sh

init_wireless_driver "$@"
maclist=""
force_channel=""

drv_ralink_init_device_config() {
	config_add_string country region variant log_level short_preamble
	config_add_boolean noscan
	config_add_int channel
}

drv_ralink_init_iface_config() {
	config_add_string 'auth_server:host'
	config_add_string auth_secret
	config_add_int 'auth_port:port'

	config_add_string ifname apname mode bssid ssid encryption key key1 key2 key3 key4 wps_pushbutton macfilter led
        config_add_boolean hidden sta_isolate
        config_add_array 'maclist:list(macaddr)'
}

drv_ralink_cleanup() {
	logger drv_ralink_cleanup
}

ralink_setup_ap(){
	local name="$1"
	local eap=0

	json_select config
	json_get_vars mode ifname ssid encryption key key1 key2 key3 key4 wps_pushbutton server port hidden sta_isolate macfilter
	json_get_values maclist maclist

	ifconfig $ifname up

	[ -z "$force_channel" ] || iwpriv $ifname set Channel=$force_channel
	[ "$sta_isolate" = 1 ] || sta_isolate=0
	iwpriv $ifname set NoForwarding=$sta_isolate
	iwpriv $ifname set NoForwardingBTNBSSID=$sta_isolate
	iwpriv $ifname set NoForwardingMBCast=$sta_isolate

	[ "$hidden" = 1 ] || hidden=0
	iwpriv $ifname set HideSSID=$hidden

	wsc_methods=0
	wsc_mode=0
	case "$encryption" in
		psk*|mixed*)
			local enc="WPA2PSK"
			case "$encryption" in
				psk | psk+*) enc=WPAPSK;;
				psk2 | psk2*) enc=WPA2PSK;;
				mixed*) enc=WPAPSKWPA2PSK;;
				wpa | wpa+*) eap=1; enc=WPA;;
				wpa2*) eap=1; enc=WPA2;;
			esac
			local crypto="AES"
			case "$encryption" in
				*tkip+aes*) crypto=TKIPAES;;
				*tkip*) crypto=TKIP;;
			esac
			[ "$eap" = "1" ] && {
				iwpriv $ifname set RADIUS_Server=$server
				iwpriv $ifname set RADIUS_Port=$port
				iwpriv $ifname set RADIUS_Key=$key
				iwpriv $ifname set own_ip_addr=192.168.1.1
				iwpriv $ifname set IEEE8021X=0
				iwpriv $ifname set EAPifname=eth0.2
				iwpriv $ifname set PreAuthIfname=br-lan
			}
			iwpriv $ifname set AuthMode=$enc
			iwpriv $ifname set EncrypType=$crypto
			iwpriv $ifname set IEEE8021X=0
			iwpriv $ifname set "SSID=${ssid}"
			[ "$eap" = "1" ] || iwpriv $ifname set "WPAPSK=${key}"
			iwpriv $ifname set DefaultKeyID=2
			iwpriv $ifname set "SSID=${ssid}"
			if [ "$wps_pushbutton" == "1" ]; then
				wsc_methods=128
				wsc_mode=7
			fi
			;;
		wep)
			iwpriv $ifname set AuthMode=WEPAUTO
			iwpriv $ifname set EncrypType=WEP
			iwpriv $ifname set IEEE8021X=0
			for idx in 1 2 3 4; do
				json_get_var keyn key${idx}
				[ -n "$keyn" ] && iwpriv $ifname set "Key${idx}=${keyn}"
			done
			iwpriv $ifname set DefaultKeyID=${key}
			iwpriv $ifname set "SSID=${ssid}"
			;;
		none)
			iwpriv $ifname set "SSID=${ssid}"
			;;
	esac

	iwpriv $ifname set WscConfMode=$wsc_mode
	iwpriv $ifname set WscConfStatus=2
	iwpriv $ifname set WscMode=2
	iwpriv $ifname set ACLClearAll=1
	[ -n "$maclist" ] && {
		for m in ${maclist}; do
			logger iwpriv $ifname set ACLAddEntry="$m"
			iwpriv $ifname set ACLAddEntry="$m"
		done
	}
	case "$macfilter" in
		allow)
			iwpriv $ifname set AccessPolicy=1
			;;
		deny)
			iwpriv $ifname set AccessPolicy=2
			;;
		*)
			iwpriv $ifname set AccessPolicy=0
			;;
	esac
	json_select ..


	wireless_add_vif "$name" "$ifname"
}

createWifiConfigList () {
	local option="$1"
	local count=0
	local resp=""
	# check that wifi-config section exists
	local exists=$(uci -q get wireless.@wifi-config[$count])

	while [ "$exists" != "" ]; do
		val=$(uci -q get wireless.@wifi-config[$count].$option)
		if [ "$val" == "" ]; then
			resp="$resp /"
		else
			resp="$resp$val/"
		fi

		count=$(($count+1))
		exists=$(uci -q get wireless.@wifi-config[$count])
	done

	echo "$resp"
}

# read a UCI option, specify a default option to return if it doesn't exist
#		arg1 - UCI option
#		arg2 - default value
uciGetDefaultVal () {
	local opt="$1"
	local def="$2"

	local val=$(uci -q get $opt)
	if [ "$val" == "" ]; then
		val="$def"
	fi

	echo "$val"
}

ralink_setup_sta(){
	local name="$1"
	local hide=1
	json_select config
	json_get_vars mode apname ifname ssid bssid encryption key key1 key2 key3 key4 wps_pushbutton led

	device_mode="$(uci get wireless.radio0.device_mode)"
	[ "${device_mode}" == "ap" ] && return
	[ "${device_mode}" == "apsta" ] && hide=0

	key=
	case "$encryption" in
		psk*|mixed*) json_get_vars key;;
		wep) json_get_var key key1;;
	esac
	json_select ..

	ssid_list=$(createWifiConfigList "ssid")
	pass_list=$(createWifiConfigList "key")
	bssid_list=$(createWifiConfigList "bssid")

	op_mode="$(uci -q get wireless.radio0.op_mode)"
	if [ "$op_mode" == "" ]; then
		op_mode="preference"
	fi

	interval=$(uciGetDefaultVal "wireless.radio0.interval" "-1")
	scan_wait=$(uciGetDefaultVal "wireless.radio0.scan_wait" "-1")
	check_assoc_wait=$(uciGetDefaultVal "wireless.radio0.assoc_wait" "-1")
	check_assoc_num_checks=$(uciGetDefaultVal "wireless.radio0.assoc_num_checks" "-1")
	rssi_thresh=$(uciGetDefaultVal "wireless.radio0.rssi_threshold" "-1")
	low_sig_max_count=$(uciGetDefaultVal "wireless.radio0.low_signal_max_count" "-1")
	params="${interval},${scan_wait},${check_assoc_wait},${check_assoc_num_checks},${rssi_thresh},${low_sig_max_count}"

	killall ap_client
	#echo "/sbin/ap_client \"$op_mode\" \"ra0\" \"$ifname\" \"${params}\" \"${ssid_list}\" \"${pass_list}\" \"${bssid_list}\" \"${hide}\" \"${led}\"" > /tmp/ralink.out
	/sbin/ap_client "$op_mode" "ra0" "$ifname" "${params}" "${ssid_list}" "${pass_list}" "${bssid_list}" "${hide}" "${led}"
	sleep 1
	wireless_add_process "$(cat /tmp/apcli-${ifname}.pid)" /sbin/ap_client "$op_mode" "ra0" "$ifname" "${params}" "${ssid_list}" "${pass_list}" "${bssid_list}" "${hide}" "${led}"

	wireless_add_vif "$name" "$ifname"
}

drv_ralink_setup() {
	local ifname="$1"
	local bcn_active=0
	wmode=9
	VHT=0
	VHT_SGI=0
	HT=0
	EXTCHA=0

	device_mode="$(uci get wireless.radio0.device_mode)"
	[ "${device_mode}" != "sta" ] && bcn_active=1

	json_select config
	json_get_vars variant region country channel htmode log_level short_preamble noscan:0
	json_select ..

	[ -z "$region" ] && region=0

	[ "$short_preamble" = 1 ] || short_preamble=0

	case ${htmode:-none} in
		HT20)
			wmode=9
			HT=0
			;;
		HT40)
			wmode=9
			HT=1
			EXTCHA=1
			;;
		VHT20)
			wmode=15
			HT=0
			VHT=0
			VHT_SGI=1
			;;
		VHT40)
			wmode=15
			HT=1
			VHT=0
			VHT_SGI=1
			EXTCHA=1
			;;
		VHT80)
			wmode=15
			HT=1
			VHT=1
			VHT_SGI=1
			EXTCHA=1
			;;
		*)
			case $hwmode in
				a) wmode=2;;
				g) wmode=3;;
			esac
			;;
	esac

	if [ "$auto_channel" -gt 0 ]; then
		force_channel=""
		channel=0
		auto_channel=3
	else
		force_channel=$channel
		auto_channel=0
	fi

	coex=1
	[ "$noscan" -gt 0 ] && coex=0

	cat /etc/Wireless/${variant}_tpl.dat > /tmp/${variant}.dat
	cat >> /tmp/${variant}.dat<<EOF
Beacon=${bcn_active}
BssidNum=4
HT_BW=${HT:-0}
HT_EXTCHA=${EXTCHA:-0}
CountryRegion=${region}
CountryCode=${country}
WirelessMode=${wmode:-9}
Channel=${channel:-8}
AutoChannelSelect=$auto_channel
Debug=${log_level:-3}
SSID=${ssid:-OpenWrt}
HT_BSSCoexistence=$coex
WscConfMethods=680
EOF
	for_each_interface "ap" ralink_setup_ap
	for_each_interface "sta" ralink_setup_sta
	wireless_set_up
	LED="$(uci get wireless.sta.led)"
	device_mode="$(uci get wireless.radio0.device_mode)"
	[ "${device_mode}" = "ap" -a -n "${LED}" -a -f /sys/class/leds/${LED}/trigger ] && ap_client ${LED} set
}

ralink_teardown() {
	json_select config
	json_get_vars ifname
	json_select ..

	ifconfig $ifname down

	LED="$(uci get wireless.sta.led)"
	[ -n "${LED}" -a -f /sys/class/leds/${LED}/trigger ] && ap_client ${LED} clear
}

drv_ralink_teardown() {
	wireless_process_kill_all
	for_each_interface "ap sta" ralink_teardown
}

add_driver ralink
