#!/bin/sh
# Upstream (6.x) MPTCP exposes the scheduler list; the out-of-tree v0.9x
# stack (blest/roundrobin/redundant/ecf) does not. Pick a default the running
# kernel accepts: 'blest' on 6.x is rejected by the sysctl and /etc/init.d/mptcp
# then falls back to 'default' on every reload while logging about it.
if [ -f /proc/sys/net/mptcp/available_schedulers ]; then
	_omr_default_sched='default'
else
	_omr_default_sched='blest'
fi
# Same for the path manager: mainline registers its path managers by name
# and advertises the list, and the out-of-tree v0.9x names
# (default/fullmesh/ndiffports/binder/netlink) exist nowhere there --
# 'kernel' is the in-kernel netlink path manager, the one that actually
# creates the extra subflows. Sending a v0 name to the VPS leaves a
# 'net.mptcp.path_manager=fullmesh' line there that fails at every boot.
if [ -f /proc/sys/net/mptcp/available_path_managers ]; then
	_omr_default_pm='kernel'
else
	_omr_default_pm='fullmesh'
fi
if [ "$(uci -q get network.globals.mptcp_path_manager)" = "" ]; then
	uci -q batch <<-EOF >/dev/null
	set network.globals.multipath='enable'
	set network.globals.mptcp_path_manager='${_omr_default_pm}'
	set network.globals.mptcp_scheduler='${_omr_default_sched}'
	set network.globals.congestion='bbr2'
	set network.globals.mptcp_checksum=0
	set network.globals.mptcp_debug=0
	set network.globals.mptcp_syn_retries=4
	set network.globals.mptcp_subflows=8
	set network.globals.mptcp_add_addr_accepted=1
	set network.globals.mptcp_add_addr_timeout=120
	set network.globals.mptcp_pm_type=0
	set network.globals.mptcp_disable_initial_config=0
	set network.globals.mptcp_force_multipath=1
	set network.globals.mptcpd_enable='disable'
	set network.globals.mptcp_close_timeout=60
	set network.globals.mptcp_blackhole_timeout=0
	set network.globals.mptcp_syn_retrans_before_tcp_fallback=2
	commit network
	EOF
fi
# mptcpd_enable is "enable"/"disable" (mptcpd's init only starts on
# "enable", the LuCI field only knows those two), but this file used to
# write 0, which the form could not show and dropped on save.
case "$(uci -q get network.globals.mptcpd_enable)" in
	0) uci -q set network.globals.mptcpd_enable='disable'; uci -q commit network ;;
	1) uci -q set network.globals.mptcpd_enable='enable'; uci -q commit network ;;
esac
# Legacy v0.9x scheduler names carried over to a 6.x kernel: only the names
# that never exist upstream are migrated (BPF schedulers are not listed in
# available_schedulers until their object is registered, so they must not be
# touched here). BLEST and ECF have a BPF port: when its object is
# installed, the choice is kept on it instead of going back to 'default'.
if [ -f /proc/sys/net/mptcp/available_schedulers ]; then
	case "$(uci -q get network.globals.mptcp_scheduler)" in
		blest|ecf)
			_sched="bpf_$(uci -q get network.globals.mptcp_scheduler)"
			[ -f "/usr/share/bpf/scheduler/mptcp_${_sched}.o" ] || _sched='default'
			uci -q batch <<-EOF >/dev/null
			set network.globals.mptcp_scheduler='${_sched}'
			commit network
			EOF
			;;
		roundrobin|redundant)
			uci -q batch <<-EOF >/dev/null
			set network.globals.mptcp_scheduler='default'
			commit network
			EOF
			;;
	esac
fi
# Legacy v0.9x path manager names carried over to a 6.x kernel. Only the
# names that never exist upstream are migrated, and every one of them is an
# in-kernel path manager, so they all map onto 'kernel'; a name this kernel
# does register ('userspace', a BPF path manager) is left alone.
if [ -f /proc/sys/net/mptcp/available_path_managers ]; then
	case "$(uci -q get network.globals.mptcp_path_manager)" in
		default|fullmesh|ndiffports|binder|netlink)
			uci -q batch <<-EOF >/dev/null
			set network.globals.mptcp_path_manager='kernel'
			commit network
			EOF
			;;
	esac
fi
# BBRv2 is replaced by BBRv3
if [ "$(uci -q get network.globals.congestion)" = "bbr2" ] && [ -z "$(uname -a | grep 5.4)" ]; then
	uci -q batch <<-EOF >/dev/null
	set network.globals.congestion='bbr'
	commit network
	EOF
fi
# The old defaults (syn_retries 1, add_addr_accepted 1) are moved once:
# this script runs again on every sysupgrade, and a 1 the user chose
# afterwards was reset each time, as were the checksum and the debug level.
# mptcp_defaults_version records which of these migrations already ran.
if [ "$(uci -q get network.globals.mptcp_defaults_version)" != "1" ]; then
	if [ "$(uci -q get network.globals.mptcp_syn_retries)" = "1" ]; then
		uci -q set network.globals.mptcp_syn_retries=4
	fi
	if [ "$(uci -q get network.globals.mptcp_add_addr_accepted)" = "1" ]; then
		uci -q set network.globals.mptcp_add_addr_accepted=8
	fi
	uci -q batch <<-EOF >/dev/null
	set network.globals.mptcp_defaults_version=1
	commit network
	EOF
fi
# enable/disable were written by an older release: the sysctl takes 1/0
case "$(uci -q get network.globals.mptcp_checksum)" in
	enable) uci -q set network.globals.mptcp_checksum=1; uci -q commit network ;;
	disable) uci -q set network.globals.mptcp_checksum=0; uci -q commit network ;;
esac

if [ "$(uci -q show network.globals | grep mptcp_fullmesh)" = "" ]; then
	uci -q batch <<-EOF >/dev/null
	set network.globals.mptcp_fullmesh_num_subflows=1
	set network.globals.mptcp_fullmesh_create_on_err=1
	set network.globals.mptcp_ndiffports_num_subflows=1
	commit network
	EOF
fi
if [ "$(uci -q get network.globals.mptcp_subflows)" = "" ]; then
	uci -q batch <<-EOF >/dev/null
	set network.globals.mptcp_subflows=8
	set network.globals.mptcp_add_addr_accepted=8
	set network.globals.mptcp_add_addr_timeout=120
	commit network
	EOF
fi
# A multipath_weight out of 1-256 (0, 300, set by hand or by an older
# release) failed the datatype of the MPTCP pages and blocked every save
# there. Stored as 040-multipath-weight reads it: not a number is unset
# (100), leading zeros dropped, 0 is 1, over 256 is 256.
_weight_changed=""
for _sec in $(uci -q show network | sed -n "s/^network\.\([^.]*\)\.multipath_weight=.*/\1/p"); do
	_weight="$(uci -q get "network.${_sec}.multipath_weight")"
	case "$_weight" in
		''|*[!0-9]*) _new_weight="" ;;
		*)
			_new_weight="${_weight#"${_weight%%[!0]*}"}"
			if [ -z "$_new_weight" ]; then
				_new_weight=1
			elif [ "${#_new_weight}" -gt 3 ] || [ "$_new_weight" -gt 256 ]; then
				_new_weight=256
			fi
			;;
	esac
	[ "$_new_weight" = "$_weight" ] && continue
	if [ -z "$_new_weight" ]; then
		uci -q delete "network.${_sec}.multipath_weight"
	else
		uci -q set "network.${_sec}.multipath_weight=${_new_weight}"
	fi
	_weight_changed=1
done
[ -n "$_weight_changed" ] && uci -q commit network

# The pre-procd config-change registration was dropped from here: OMR images
# ship no /etc/config/ucitrack, so it failed silently anyway, and the init
# declares procd_add_reload_trigger "network", which is what actually reloads
# mptcp when the network config changes.
if [ "$(uci -q get network.globals.mptcp_close_timeout)" = "" ]; then
	uci -q batch <<-EOF >/dev/null
	set network.globals.mptcp_close_timeout=60
	set network.globals.mptcp_blackhole_timeout=0
	set network.globals.mptcp_syn_retrans_before_tcp_fallback=2
	commit network
	EOF
fi
exit 0