#!/bin/sh

#
# hotspot.sh
#
#   Tool to create/remove hotspots
#
# Copyright (C) 2013  Bayram Kurumahmut <bayram.kurumahmut@airties.com>
#
# Terminology:
#
#   v means virtual
#   p means port
#   m means manager
#   i means instance
#
#   hotspot_i: hotspot-x
#   parent_m: settings/mngr
#   parent_i: settings/inst
#   child_vm: settings/virtual/mngr
#   child_vi: settings/virtual/inst
#   child_pm: settings/port/mngr
#   child_pi: settings/port/inst
#
# TODO:
#   - If there is no hotspot manager, fail
#   - If there is no hotspot instance, fail
#

exe_name=`echo ${0##*/}`

. /usr/bin/debug.sh

debug_level=5
debug_owner=$exe_name
debug_logfile=/var/$debug_owner.log
debug_level_file=/var/$debug_owner.debug_level

[ -f $debug_level_file ] && {
	debug_level=`cat $debug_level_file`
	echo "new debug_level:$debug_level"
}

. /usr/bin/config.sh

resp_type="onlyresp"
try_val="try 5"
req_val=$exe_name

gw_assigned=1

usage()
{
	echo "
Usage: $exe_name -i INST_ID -c COMMAND [-s SLEEP_TIME] [-d DEBUG_LEVEL] [-f LOG_FILE] [-g GW_ASSIGNED]
  INST_ID    : must have 'hotspot-' prefix, ex. hotspot-0
  COMMAND    : [start|stop|delete]
  GW_ASSIGNED: 1, ON, 0, OFF.
  DEBUG_LEVEL: 1, ERROR. 2, WARN. 3, INFO. 4, TRACE. 5, CRAZY.
  LOG_FILE   : logs will be saved in this file, in addition to printing to STDOUT
               NOTE: Maximum line count is ${debug_logfile_linecount}.
"
}

do_exit()
{
	cli_cmd "cfgmgr-0:commit $hotspot_i"
	cli_cmd "cfgmgr-0:end_transaction $hotspot_i"
	exit $1
}

#
# Parse command line arguments
#

while [ "$1" != "" ]
do
    case "$1" in
	-h)
	    shift;
	    usage
	    exit;;
	-c)
	    shift;
	    command="$1";;
	-i)
	    shift;
	    hotspot_i="$1";;
	-g)
	    shift;
	    gw_assigned="$1";;
	-s)
	    shift;
	    sleep_time=$1;;
	-d)
	    shift;
	    debug_level=$1;;
	-f)
	    shift;
	    debug_logfile=$1;;
	*)
	    usage
	    exit;;
    esac
    shift
done

hotspot_m=`echo ${hotspot_i%%-*}`
[ "$hotspot_m" != "hotspot" ] && {
	debug_error "Not a hotspot instance: $hotspot_i"
	usage
	exit 1
}

#
# Update debug_logfile for each instance
#
debug_owner=${exe_name}-$hotspot_i
debug_logfile=/var/$debug_owner.log

[ `is_valid_inst $hotspot_i` = "0" ] && {
	debug_error "Invalid instance: $hotspot_i"
	usage
	exit 1
}

case "$command" in
    start)
        ;;

    stop)
        ;;

    delete)
        ;;

    update)
        ;;

	*)
		debug_error "Invalid command: $command"
		usage
        exit 1
		
esac

member_inst_list=

dhcpopt_inst="dhcpopt82-0"

do_job_check()
{
	[ "$2" != "$3" ] && {
		do_job=1
		debug_info "$1 is different, '$2' <= '$3'"
	}
}

#
# rem_xxx, add_xxx functions
#   xxx: l2tunnel, wireless_ap, bridge_vlan
#

rem_hotspot()
{
	cli_cmd "devmgr-0:stop_inst $hotspot_i"
	cli_cmd "devmgr-0:delete_inst $hotspot_i"
}

rem_l2tunnel()
{
	child_vi=`get_cfg_only $hotspot_i settings/virtual/inst`
	[ `is_valid_inst $child_vi` != "1" ] && {
		debug_warn "$child_vi is not a valid instance"
		return
	}

	debug_trace "Check if $child_vi is used by another hotspot"
	hotspot_inst_list=`cli query onlyresp devmgr-0:inst_list hotspot`
	for rl_ci in `echo $hotspot_inst_list`
	do
		[ "$rl_ci" = "$hotspot_i" ] && {
			continue
		}
		vhotspot_type=`get_cfg $rl_ci settings/type`
		[ "$vhotspot_type" = "FON" ] && { 
			debug_trace "$child_vi is used by $rl_ci, will not delete $child_vi"
			set_cfg_only "$hotspot_i" "settings/virtual/inst" ""
			return
		}
	done
	cli_cmd "devmgr-0:stop_inst $child_vi"
	cli_cmd "devmgr-0:delete_inst $child_vi"

	set_cfg_only "$hotspot_i" "settings/virtual/inst" ""
}

add_l2tunnel()
{
	child_vi=`get_cfg_only $hotspot_i settings/virtual/inst`
	[ `is_valid_inst $child_vi` = "0" ] && {
		debug_warn "$child_vi (settings/virtual/inst) is not a valid instance"
		child_vi=
	}
	[ ! -n "$child_vi" ] && {
		debug_trace "Searching 'l2tunnel' virtual port"
		l2tunnel_inst_list=`cli query onlyresp devmgr-0:inst_list l2tunnel`
		for al_ci in `echo $l2tunnel_inst_list`
		do
			vhotspot_type=`get_cfg $al_ci settings/hotspot_type`
			[ "$vhotspot_type" = "FON" ] && { 
				child_vi=$al_ci
				debug_trace "Selected '$child_vi' virtual port"
				set_cfg_only "$hotspot_i" "settings/virtual/inst" "$child_vi"
				return
			}
		done

		[ ! -n "$child_vi" ] && {
			debug_trace "Creating 'l2tunnel' virtual port"
			child_vi=`cli command onlyresp devmgr-0:create_inst l2tunnel`
			[ ! -n "$child_vi" ] && {
				debug_error "Failed to create virtual instance"
				do_exit 10
			}
			cli_cmd "cfgmgr-0:commit $child_vi"
#			cli_cmd "cfgmgr-0:save"
			cli_cmd "devmgr-0:start_inst $child_vi"
			new_inst=1
		}
	}

	debug_trace "Using child_vi:$child_vi"

	set_cfg_only "$hotspot_i" "settings/virtual/inst" "$child_vi"

	enabled_val=`get_cfg_only $hotspot_i settings/virtual/enabled`
	type=`get_cfg_only $hotspot_i settings/virtual/type`
	header_type=`get_cfg_only $hotspot_i settings/virtual/header_type`
	remote_ip=`get_cfg_only $hotspot_i settings/virtual/remote_ip`
	local_inst=`get_cfg_only $hotspot_i settings/virtual/local_inst`
	mtu=`get_cfg_only $hotspot_i settings/virtual/mtu`

	cli_cmd "cfgmgr-0:begin_transaction $child_vi"

	do_job=1
	[ "$new_inst" != "1" ] && {
		debug_trace "Compare $child_vi values"

		do_job=0

		lenabled=`get_cfg_only $child_vi settings/enabled`
		ltype=`get_cfg_only $child_vi settings/type`
		lheader_type=`get_cfg_only $child_vi settings/header_type`
		lremote_ip=`get_cfg_only $child_vi settings/remote_ip`
		llocal_inst=`get_cfg_only $child_vi settings/local_inst`
		lmtu=`get_cfg_only $child_vi settings/mtu`
		lhotspot_type=`get_cfg_only $child_vi settings/hotspot_type`

		do_job_check "enabled" "$enabled_val" "$lenabled"
		do_job_check "type" "$type" "$ltype"
		do_job_check "header_type" "$header_type" "$lheader_type"
		do_job_check "remote_ip" "$remote_ip" "$lremote_ip"
		do_job_check "local_inst" "$local_inst" "$llocal_inst"
		do_job_check "mtu" "$mtu" "$lmtu"
		do_job_check "hotspot_type" "$hotspot_type" "$lhotspot_type"
	}

	[ "$do_job" = "1" ] && {
		debug_trace "Set $child_vi values"

		cli_set "$child_vi:settings/enabled $enabled_val"
		cli_set "$child_vi:settings/type $type"
		cli_set "$child_vi:settings/hotspot_type $hotspot_type"
		cli_set "$child_vi:settings/header_type $header_type"
		cli_set "$child_vi:settings/remote_ip $remote_ip"
		cli_set "$child_vi:settings/local_inst $local_inst"
		cli_set "$child_vi:settings/mtu $mtu"

		apply_inst_list="$apply_inst_list $child_vi"
	}

	cli_cmd "cfgmgr-0:commit $child_vi"
	cli_cmd "cfgmgr-0:end_transaction $child_vi"

	set_cfg "port_vlan-0" "addPort" "$child_vi"
#	cli_cmd "cfgmgr-0:save"

	set_cfg "port_vlan-0" "private_port ${child_vi}/1"
#	cli_cmd "cfgmgr-0:save"
}

rem_wireless_ap()
{
	child_pi=`get_cfg_only $hotspot_i settings/port/inst`
	[ `is_valid_inst $child_pi` != "1" ] && {
		debug_trace "$child_pi is not a valid instance"
		return
	}

	cli_cmd "cfgmgr-0:begin_transaction $child_pi"
	cli_set "$child_pi:enabled 0"
	cli_cmd "cfgmgr-0:commit $child_pi"
	cli_cmd "cfgmgr-0:end_transaction $child_pi"
	apply_inst_list="$apply_inst_list wireless_core-0"

	# restore old wireless_ap values
	oenabled=`get_cfg_only $hotspot_i settings/port/old_values/enabled`
	owpa_auth_type=`get_cfg_only $hotspot_i settings/port/old_values/wpa_auth_type`
	ossid_val=`get_cfg_only $hotspot_i settings/port/old_values/ssid`
	osec_mode=`get_cfg_only $hotspot_i settings/port/old_values/sec_mode`
	orekey_interval=`get_cfg_only $hotspot_i settings/port/old_values/rekey_interval`
	oradius_addr=`get_cfg_only $hotspot_i settings/port/old_values/radius_addr`
	oradius_port=`get_cfg_only $hotspot_i settings/port/old_values/radius_port`
	oradius_key=`get_cfg_only $hotspot_i settings/port/old_values/radius_key`
	oradius_eap_period=`get_cfg_only $hotspot_i settings/port/old_values/radius_eap_period`

	cli_cmd "cfgmgr-0:begin_transaction $child_pi"

	cli_set "$child_pi:enabled $oenabled"
	cli_set "$child_pi:wpa_auth_type $owpa_auth_type"
	cli_set "$child_pi:ssid $ossid_val"
	cli_set "$child_pi:sec_mode $osec_mode"
	cli_set "$child_pi:wpa_rekey_interval $orekey_interval"
	cli_set "$child_pi:wpa_radius_addr $oradius_addr"
	cli_set "$child_pi:wpa_radius_port $oradius_port"
	cli_set "$child_pi:wpa_radius_key $oradius_key"
	cli_set "$child_pi:wpa_radius_eap_reauth_period $oradius_eap_period"
	cli_set "$child_pi:wpa2_rsn_preauth"

	cli_set "$child_pi:private_inst 0"

	cli_cmd "cfgmgr-0:commit $child_pi"
	cli_cmd "cfgmgr-0:end_transaction $child_pi"

	cli_set "$hotspot_i:settings/port/old_values/enabled "
	cli_set "$hotspot_i:settings/port/old_values/wpa_auth_type "
	cli_set "$hotspot_i:settings/port/old_values/ssid "
	cli_set "$hotspot_i:settings/port/old_values/sec_mode "
	cli_set "$hotspot_i:settings/port/old_values/rekey_interval "
	cli_set "$hotspot_i:settings/port/old_values/radius_addr "
	cli_set "$hotspot_i:settings/port/old_values/radius_port "
	cli_set "$hotspot_i:settings/port/old_values/radius_key "
	cli_set "$hotspot_i:settings/port/old_values/radius_eap_period "

	[ "$hotspot_type" != "FON" ] && {
		set_cfg_only "$hotspot_i" "settings/port/inst" ""
	}

	set_cfg "port_vlan-0" "private_port ${child_pi}/0"
}

add_wireless_ap()
{
	child_pi=`get_cfg_only $hotspot_i settings/port/inst`
	[ `is_valid_inst $child_pi` = "0" ] && {
		debug_warn "$child_pi (settings/port/inst) is not a valid instance"
		child_pi=
	}
	[ ! -n "$child_pi" ] && {
		debug_trace "Selecting a 'wireless_ap' port"
		for ava_ci in `echo 'wireless_ap-3 wireless_ap-2 wireless_ap-1'`
		do
			debug_crazy "ci:$ava_ci"
			[ `get_cfg $ava_ci enabled` = "0" ] && {
				child_pi=$ava_ci
				debug_trace "Selected ci:$ava_ci"
				new_inst=1
				break
			}
		done
	}

	[ ! -n "$child_pi" ] && {
		debug_error "No available instance to select as a 'wireless_ap' port"
		do_exit 20
	}

	debug_trace "Using child_pi:$child_pi"

	set_cfg_only "$hotspot_i" "settings/port/inst" "$child_pi"

	[ "$gw_assigned" = "1" ] && {
		enabled_val=`get_cfg_only $hotspot_i settings/port/enabled`
	} || {
		enabled_val="0"
	}
	ssid_val=`get_cfg_only $hotspot_i settings/port/ssid`
	sec_mode=`get_cfg_only $hotspot_i settings/port/sec_mode`
	rekey_interval=`get_cfg_only $hotspot_i settings/port/rekey_interval`
	radius_addr=`get_cfg_only $hotspot_i settings/port/radius_addr`
	radius_port=`get_cfg_only $hotspot_i settings/port/radius_port`
	radius_key=`get_cfg_only $hotspot_i settings/port/radius_key`
	radius_eap_period=`get_cfg_only $hotspot_i settings/port/radius_eap_period`
	# wps_enabled=`get_cfg_only $hotspot_i settings/port/wps_enabled`
	# wps_role=`get_cfg_only $hotspot_i settings/port/wps_role`

	cli_cmd "cfgmgr-0:begin_transaction $child_pi"

	wenabled_val=`get_cfg_only $child_pi enabled`
	wwpa_auth_type=`get_cfg_only $child_pi wpa_auth_type`
	wssid_val=`get_cfg_only $child_pi ssid`
	wsec_mode=`get_cfg_only $child_pi sec_mode`
	wrekey_interval=`get_cfg_only $child_pi wpa_rekey_interval`
	wradius_addr=`get_cfg_only $child_pi wpa_radius_addr`
	wradius_port=`get_cfg_only $child_pi wpa_radius_port`
	wradius_key=`get_cfg_only $child_pi wpa_radius_key`
	wradius_eap_period=`get_cfg_only $child_pi wpa_radius_eap_reauth_period`

	do_job=1
	[ "$new_inst" != "1" ] && {
		debug_trace "Compare $child_pi values"

		do_job=0

		do_job_check "enabled" "$enabled_val" "$wenabled_val"
		do_job_check "ssid" "$ssid_val" "$wssid_val"
		do_job_check "sec_mode" "$sec_mode" "$wsec_mode"

		[ "$sec_mode" != "off" ] && {
			do_job_check "rekey_interval" "$rekey_interval" "$wrekey_interval"
			do_job_check "radius_addr" "$radius_addr" "$wradius_addr"
			do_job_check "radius_port" "$radius_port" "$wradius_port"
			do_job_check "radius_key" "$radius_key" "$wradius_key"
			do_job_check "radius_eap_period" "$radius_eap_period" "$wradius_eap_period"
		}
	}

	[ "$do_job" = "1" ] && {
		debug_trace "Set $child_pi values"

		cli_set "$hotspot_i:settings/port/old_values/enabled $wenabled_val"
		cli_set "$hotspot_i:settings/port/old_values/wpa_auth_type $wwpa_auth_type"
		set_cfg_only "$hotspot_i" "settings/port/old_values/ssid" "$wssid_val"
		cli_set "$hotspot_i:settings/port/old_values/sec_mode $wsec_mode"

		[ "$sec_mode" != "off" ] && {
			cli_set "$hotspot_i:settings/port/old_values/rekey_interval $wrekey_interval"
			cli_set "$hotspot_i:settings/port/old_values/radius_addr $wradius_addr"
			cli_set "$hotspot_i:settings/port/old_values/radius_port $wradius_port"
			cli_set "$hotspot_i:settings/port/old_values/radius_key $wradius_key"
			cli_set "$hotspot_i:settings/port/old_values/radius_eap_period $wradius_eap_period"
		}

		cli_set "$child_pi:enabled $enabled_val"
		cli_set "$child_pi:wpa_auth_type 1"
		set_cfg_only "$child_pi" "ssid" "$ssid_val"
		cli_set "$child_pi:sec_mode $sec_mode"
		cli_set "$child_pi:isolation 1"

		[ "$sec_mode" != "off" ] && {
			cli_set "$child_pi:wpa_rekey_interval $rekey_interval"
			cli_set "$child_pi:wpa_radius_addr $radius_addr"
			cli_set "$child_pi:wpa_radius_port $radius_port"
			cli_set "$child_pi:wpa_radius_key $radius_key"
			cli_set "$child_pi:wpa_radius_eap_reauth_period $radius_eap_period"
		}

		cli_set "$child_pi:wpa2_rsn_preauth"

		cli_set "$child_pi:private_inst 1"

		[ "$enabled_val" = "0" -a "$wenabled_val" = "0" ] && {
			debug_trace "No wireless_ap apply required"
		} || {
			apply_inst_list="$apply_inst_list wireless_core-0"
		}
	}

	cli_cmd "cfgmgr-0:commit $child_pi"
	cli_cmd "cfgmgr-0:end_transaction $child_pi"

	set_cfg "port_vlan-0" "addPort" "$child_pi"
#	cli_cmd "cfgmgr-0:save"

	set_cfg "port_vlan-0" "private_port ${child_pi}/1"
}

rem_bridge_vlan()
{
	bridge_inst=`get_cfg_only $hotspot_i settings/inst`
	[ `is_valid_inst $bridge_inst` != "1" ] && {
		debug_trace "$bridge_inst is not a valid instance"
		return
	}

	debug_trace "Check if $bridge_inst is used by another hotspot"
	hotspot_inst_list=`cli query onlyresp devmgr-0:inst_list hotspot`
	for rbv_ci in `echo $hotspot_inst_list`
	do
		[ "$rbv_ci" = "$hotspot_i" ] && {
			continue
		}
		vhotspot_inst=`get_cfg $rbv_ci settings/inst`
		[ "$vhotspot_inst" = "$bridge_inst" ] && { 
			debug_trace "$bridge_inst is used by $rbv_ci, will not delete $bridge_inst"
			set_cfg_only "$hotspot_i" "settings/inst" ""
			return
		}
	done

	cli_cmd "devmgr-0:stop_inst $bridge_inst"
	cli_cmd "devmgr-0:delete_inst $bridge_inst"

	set_cfg_only "$hotspot_i" "settings/inst" ""
}

tagness_bridge_vlan()
{
	[ "$1" != "0" -a "$2" = "0" ] && {
		debug_trace "Check if there is a hotspot without tagging enabled"
		hotspot_inst_list=`cli query onlyresp devmgr-0:inst_list hotspot`
		for tbv_ci in `echo $hotspot_inst_list`
		do
			[ "$tbv_ci" = "$hotspot_i" ] && {
				continue
			}
			vhotspot_type=`get_cfg $tbv_ci settings/type`
			[ "$vhotspot_type" != "FON" ] && {
				continue
			}
			vhotspot_enabled=`get_cfg $tbv_ci settings/enabled`
			[ "$vhotspot_enabled" != "1" ] && {
				continue
			}
			vhotspot_vlan_id=`get_cfg $tbv_ci settings/vlan_id`
			[ "$vhotspot_vlan_id" != "0" ] && {
				continue
			}
			rem_bridge_vlan		# removing old bridge_vlan
			vhotspot_inst=`get_cfg $tbv_ci settings/inst`
			bridge_inst="$vhotspot_inst"
			debug_trace "Use untagged $bridge_inst together with $tbv_ci"
			return
		done
	}
	[ "$1" = "0" -a "$2" != "0" ] && {
		will_remove_bridge=0
		hotspot_inst_list=`cli query onlyresp devmgr-0:inst_list hotspot`
		for tbv_ci in `echo $hotspot_inst_list`
		do
			[ "$tbv_ci" = "$hotspot_i" ] && {
				continue
			}
			vhotspot_type=`get_cfg $tbv_ci settings/type`
			[ "$vhotspot_type" != "FON" ] && {
				continue
			}
			vhotspot_enabled=`get_cfg $tbv_ci settings/enabled`
			[ "$vhotspot_enabled" != "1" ] && {
				continue
			}
			vhotspot_inst=`get_cfg $tbv_ci settings/inst`
			[ "$vhotspot_inst" != "$bridge_inst" ] && {
				will_remove_bridge=1
				break
			}
		done
		[ "$will_remove_bridge" = "1" ] && {
			debug_trace "Remove $bridge_inst, there is no user"
			rem_bridge_vlan
		}
		bridge_inst=
	}
	[ "$2" = 0 ] && {
		set_cfg "port_vlan-0" "port_tagging ${child_vi}/0"
	} || {
		set_cfg "port_vlan-0" "port_tagging ${child_vi}/1"
	}
}

add_bridge_vlan()
{
	debug_trace "Create a bridge having '$member_inst_list'"

	vlan_id=`get_cfg_only $hotspot_i settings/vlan_id`

	# Check if inst is valid, if not create a new inst

	bridge_inst=`get_cfg_only $hotspot_i settings/inst`
	[ `is_valid_inst $bridge_inst` = "0" ] && {
		debug_warn "$bridge_inst (settings/inst) is not a valid instance"
		bridge_inst=
	} || {

		# Check if the inst already have the ports

		iface_list=`get_cfg $bridge_inst ifaces`
		do_job=0
		for abv_mi in `echo $member_inst_list`
		do
			have_inst=`echo $iface_list | grep -c $abv_mi`
			[ "$have_inst" = "0" ] && {
				do_job=1
				break
			}
		done

		[ "$do_job" = "0" ] && {

			debug_trace "Already have '$member_inst_list' in $bridge_inst"

			lvlan_id=`get_cfg $bridge_inst vlanid`

			cbridge_inst="$bridge_inst"

			tagness_bridge_vlan "$lvlan_id" "$vlan_id"

			[ "$cbridge_inst" = "$bridge_inst" ] && {

				do_job=0

				do_job_check "vlan_id" "$vlan_id" "$lvlan_id"

				cli_cmd "cfgmgr-0:begin_transaction $bridge_inst"

				[ "$do_job" = "1" ] && {
					debug_trace "Set $child_vi values"

					cli_set "$bridge_inst:vlanid $vlan_id"
					cli_set "$bridge_inst:name TTNET_FON_VLAN_$vlan_id"

					cli_cmd "cfgmgr-0:commit $bridge_inst"

					apply_inst_list="$apply_inst_list $bridge_inst"
				}

				cli_cmd "cfgmgr-0:end_transaction $bridge_inst"

				return
			}
		}
	}

	# Create new inst if required

	[ ! -n "$bridge_inst" ] && {

		tagness_bridge_vlan "x" "$vlan_id"

		[ ! -n "$bridge_inst" ] && {

			debug_trace "Creating 'bridge_vlan'"
			bridge_inst=`cli command onlyresp devmgr-0:create_inst $parent_m`
			[ ! -n "$bridge_inst" ] && {
				debug_error "Failed to create bridge instance"
				do_exit 30
			}
			cli_cmd "cfgmgr-0:commit $bridge_inst"
#			cli_cmd "cfgmgr-0:save"
			cli_cmd "devmgr-0:start_inst $bridge_inst"
		}
	}

	debug_trace "Using bridge_inst:$bridge_inst"

	set_cfg_only "$hotspot_i" "settings/inst" "$bridge_inst"

	# Remove port instance list from bridge_vlan they are attached

	vlan_inst_list=`cli query onlyresp devmgr-0:inst_list bridge_vlan`
	for abv_ci in `echo $vlan_inst_list`
	do
		[ "$abv_ci" = "bridge_inst" ] && {
			continue
		}
		iface_list=`get_cfg $abv_ci ifaces`
		cli_cmd "cfgmgr-0:begin_transaction $abv_ci"
		do_job=0
		for abv_mi in `echo $member_inst_list`
		do
			is_tagged=`get_cfg port_vlan-0 port_tagging $abv_mi`
			[ "$is_tagged" = "1" ] && {
				debug_trace "$abv_mi is tagged, skipping"
				continue
			}
			have_inst=`echo $iface_list | grep -c $abv_mi`
			[ "$have_inst" = "1" ] && {
				debug_trace "Removing $abv_mi from $abv_ci"
				cli_set "$abv_ci:delIface $abv_mi"
				do_job=1
			}
		done
		cli_cmd "cfgmgr-0:commit $abv_ci"
		cli_cmd "cfgmgr-0:end_transaction $abv_ci"
		[ "$do_job" = "1" ] && {
			apply_inst_list="$apply_inst_list $abv_ci"
		}
	done

	# Add port instance list to new bridge_vlan

	iface_list=`get_cfg $bridge_inst ifaces`

	cli_cmd "cfgmgr-0:begin_transaction $bridge_inst"

	cli_set "$bridge_inst:vlanid $vlan_id"
	cli_set "$bridge_inst:name TTNET_FON_VLAN_$vlan_id"

	for abv_mi in `echo $member_inst_list`
	do
		have_inst=`echo $iface_list | grep -c $abv_mi`
		[ "$have_inst" = "0" ] && {
			cli_set "$bridge_inst:addIface $abv_mi"
		}
	done

	cli_set "$bridge_inst:private_inst 1"

	cli_cmd "cfgmgr-0:commit $bridge_inst"
	cli_cmd "cfgmgr-0:end_transaction $bridge_inst"

	apply_inst_list="$apply_inst_list $bridge_inst"
}

add_all()
{
	[ "$child_vm" = "l2tunnel" ] && {
		add_l2tunnel
		member_inst_list="$member_inst_list $child_vi"
	}

	[ "$child_pm" = "wireless_ap" ] && {
		add_wireless_ap
		member_inst_list="$member_inst_list $child_pi"
	}

	[ "$parent_m" = "bridge_vlan" ] && {
		add_bridge_vlan
		set_cfg "$dhcpopt_inst" "addIface" "$bridge_inst"
		apply_inst_list="$apply_inst_list $dhcpopt_inst"
	}
}

rem_all()
{
	[ "$child_vm" = "l2tunnel" ] && {
		rem_l2tunnel
	}

	[ "$child_pm" = "wireless_ap" ] && {
		rem_wireless_ap
		set_cfg "port_vlan-0" "private_port ${child_pi}/0"
	}

	set_cfg "port_vlan-0" "port"

	[ "$parent_m" = "bridge_vlan" ] && {
		rem_bridge_vlan
		set_cfg "$dhcpopt_inst" "delIface" "$bridge_inst"
		apply_inst_list="$apply_inst_list $dhcpopt_inst"
	}
}

#
# upd_all (update all) means that instances are ready
#   Only update tag values if there is a change. If so apply them.
#   In other words, bridge_vlan already created before and includes instances.
#   Finally, in this state, we know that bridge_vlan is up but vlan_id may be changed.
#   If there is an update for l2tunnel or wireless_ap, they will be removed from
#     bridge_vlan, configured, then re-add by mngr w/o making bridge_vlan down.
#
upd_all()
{
	[ "$child_vm" = "l2tunnel" ] && {
		add_l2tunnel
		member_inst_list="$member_inst_list $child_vi"
	}

	[ "$child_pm" = "wireless_ap" ] && {
		add_wireless_ap
		set_cfg "port_vlan-0" "port"
#		cli_cmd "cfgmgr-0:save"
		member_inst_list="$member_inst_list $child_pi"
	}

	[ "$parent_m" = "bridge_vlan" ] && {
		add_bridge_vlan
	}
}

[ -n "$sleep_time" ] && {
	sleep $sleep_time
}

#
# Start working - get managers
#

debug_info "========================="
debug_info "====  Started to run ===="
debug_info "========================="

cli_cmd "cfgmgr-0:begin_transaction $hotspot_i"

#
# Try 3 times reading - it sometimes fails
#
hotspot_type=`get_cfg_only $hotspot_i settings/type`
[ `echo $hotspot_type | grep -c error` != 0 ] && {
	sleep 1
	debug_crazy "2nd try to get settings/type"
	hotspot_type=`get_cfg_only $hotspot_i settings/type`
	[ `echo $hotspot_type | grep -c error` != 0 ] && {
		sleep 1
		debug_crazy "3rd try to get settings/type"
		hotspot_type=`get_cfg_only $hotspot_i settings/type`
		[ `echo $hotspot_type | grep -c error` != 0 ] && {
			debug_error "Failed to extract type"
			do_exit 39
		}
	}
}

child_vm=`get_cfg_only $hotspot_i settings/virtual/mngr`
[ ! -n "$child_vm" ] && {
	sleep 1
	debug_crazy "2nd try to get settings/virtual/mngr"
	child_vm=`get_cfg_only $hotspot_i settings/virtual/mngr`
	[ ! -n "$child_vm" ] && {		
		sleep 1
		debug_crazy "3rd try to get settings/virtual/mngr"
		child_vm=`get_cfg_only $hotspot_i settings/virtual/mngr`
		[ ! -n "$child_vm" ] && {
			debug_error "Failed to extract virtual manager"
			do_exit 40
		}
	}
}

debug_crazy "child_vm=$child_vm"

child_pm=`get_cfg_only $hotspot_i settings/port/mngr`
[ ! -n "$child_pm" ] && {
	sleep 1
	debug_crazy "2nd try to get settings/port/mngr"
	child_pm=`get_cfg_only $hotspot_i settings/port/mngr`
	[ ! -n "$child_pm" ] && {
		sleep 1
		debug_crazy "3rd try to get settings/port/mngr"
		child_pm=`get_cfg_only $hotspot_i settings/port/mngr`
		[ ! -n "$child_pm" ] && {
			debug_error "Failed to extract port manager"
			do_exit 41
		}
	}
}

debug_crazy "child_pm=$child_pm"

parent_m=`get_cfg_only $hotspot_i settings/mngr`
[ ! -n "$parent_m" ] && {
	sleep 1
	debug_crazy "2nd try to get settings/mngr"
	parent_m=`get_cfg_only $hotspot_i settings/mngr`
	[ ! -n "$parent_m" ] && {
		sleep 1
		debug_crazy "3rd try to get settings/mngr"
		parent_m=`get_cfg_only $hotspot_i settings/mngr`
		[ ! -n "$parent_m" ] && {
			debug_error "Failed to extract manager"
			do_exit 42
		}
	}
}

debug_crazy "parent_m=$parent_m"

#
# wireless_core-0
#
# cfgmgr-0:begin_transaction wireless_core-0

# wireless_core-0:wps_enabled 0
# wireless_core-0:wps_config_uuid_update
# wireless_core-0:wps_role registrar

# cfgmgr-0:commit wireless_core-0
# cfgmgr-0:end_transaction wireless_core-0

#cli_cmd "wireless_core-0:apply"

#
# Start hotspot
#   Combine virtual and ports under bridge_vlan
#
[ "$command" = "start" ] && {
	add_all
	set_cfg_only "$hotspot_i" "settings/enabled" "1"
}

#
# Stop (close) hotspot
#  Delete l2tunnel-x and bridge_vlan-x
#  Disable wireless_ap-x
#
[ "$command" = "stop" ] && {
	rem_all
	set_cfg_only "$hotspot_i" "settings/enabled" "0"
}

#
# Update hotspot
#
[ "$command" = "update" ] && {
	upd_all
}

#
# Delete hotspot
#  Delete hotspot-x, l2tunnel-x, and bridge_vlan-x
#  Disable wireless_ap-x
#
[ "$command" = "delete" ] && {
	rem_all
	rem_hotspot
}

debug_info "Will apply: $apply_inst_list"

for apply_inst in `echo $apply_inst_list`
do
	echo "$apply_inst" >> $apply_list_file
done

cli_cmd "cfgmgr-0:commit $hotspot_i"
cli_cmd "cfgmgr-0:end_transaction $hotspot_i"

#
# Finalize
#   Save config and send apply commands
#
cli_cmd "cfgmgr-0:save"

debug_info "========================="
debug_info "======  Completed ======="
debug_info "========================="
