18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/* Multipath TCP
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Copyright (c) 2019, Intel Corporation.
58c2ecf20Sopenharmony_ci */
68c2ecf20Sopenharmony_ci#define pr_fmt(fmt) "MPTCP: " fmt
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include <linux/kernel.h>
98c2ecf20Sopenharmony_ci#include <net/tcp.h>
108c2ecf20Sopenharmony_ci#include <net/mptcp.h>
118c2ecf20Sopenharmony_ci#include "protocol.h"
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci/* path manager command handlers */
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ciint mptcp_pm_announce_addr(struct mptcp_sock *msk,
168c2ecf20Sopenharmony_ci			   const struct mptcp_addr_info *addr,
178c2ecf20Sopenharmony_ci			   bool echo)
188c2ecf20Sopenharmony_ci{
198c2ecf20Sopenharmony_ci	pr_debug("msk=%p, local_id=%d", msk, addr->id);
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci	msk->pm.local = *addr;
228c2ecf20Sopenharmony_ci	WRITE_ONCE(msk->pm.add_addr_echo, echo);
238c2ecf20Sopenharmony_ci	WRITE_ONCE(msk->pm.add_addr_signal, true);
248c2ecf20Sopenharmony_ci	return 0;
258c2ecf20Sopenharmony_ci}
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ciint mptcp_pm_remove_addr(struct mptcp_sock *msk, u8 local_id)
288c2ecf20Sopenharmony_ci{
298c2ecf20Sopenharmony_ci	pr_debug("msk=%p, local_id=%d", msk, local_id);
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci	msk->pm.rm_id = local_id;
328c2ecf20Sopenharmony_ci	WRITE_ONCE(msk->pm.rm_addr_signal, true);
338c2ecf20Sopenharmony_ci	return 0;
348c2ecf20Sopenharmony_ci}
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ciint mptcp_pm_remove_subflow(struct mptcp_sock *msk, u8 local_id)
378c2ecf20Sopenharmony_ci{
388c2ecf20Sopenharmony_ci	pr_debug("msk=%p, local_id=%d", msk, local_id);
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci	spin_lock_bh(&msk->pm.lock);
418c2ecf20Sopenharmony_ci	mptcp_pm_nl_rm_subflow_received(msk, local_id);
428c2ecf20Sopenharmony_ci	spin_unlock_bh(&msk->pm.lock);
438c2ecf20Sopenharmony_ci	return 0;
448c2ecf20Sopenharmony_ci}
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci/* path manager event handlers */
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_civoid mptcp_pm_new_connection(struct mptcp_sock *msk, int server_side)
498c2ecf20Sopenharmony_ci{
508c2ecf20Sopenharmony_ci	struct mptcp_pm_data *pm = &msk->pm;
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci	pr_debug("msk=%p, token=%u side=%d", msk, msk->token, server_side);
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci	WRITE_ONCE(pm->server_side, server_side);
558c2ecf20Sopenharmony_ci}
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_cibool mptcp_pm_allow_new_subflow(struct mptcp_sock *msk)
588c2ecf20Sopenharmony_ci{
598c2ecf20Sopenharmony_ci	struct mptcp_pm_data *pm = &msk->pm;
608c2ecf20Sopenharmony_ci	int ret = 0;
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci	pr_debug("msk=%p subflows=%d max=%d allow=%d", msk, pm->subflows,
638c2ecf20Sopenharmony_ci		 pm->subflows_max, READ_ONCE(pm->accept_subflow));
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci	/* try to avoid acquiring the lock below */
668c2ecf20Sopenharmony_ci	if (!READ_ONCE(pm->accept_subflow))
678c2ecf20Sopenharmony_ci		return false;
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci	spin_lock_bh(&pm->lock);
708c2ecf20Sopenharmony_ci	if (READ_ONCE(pm->accept_subflow)) {
718c2ecf20Sopenharmony_ci		ret = pm->subflows < pm->subflows_max;
728c2ecf20Sopenharmony_ci		if (ret && ++pm->subflows == pm->subflows_max)
738c2ecf20Sopenharmony_ci			WRITE_ONCE(pm->accept_subflow, false);
748c2ecf20Sopenharmony_ci	}
758c2ecf20Sopenharmony_ci	spin_unlock_bh(&pm->lock);
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci	return ret;
788c2ecf20Sopenharmony_ci}
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci/* return true if the new status bit is currently cleared, that is, this event
818c2ecf20Sopenharmony_ci * can be server, eventually by an already scheduled work
828c2ecf20Sopenharmony_ci */
838c2ecf20Sopenharmony_cistatic bool mptcp_pm_schedule_work(struct mptcp_sock *msk,
848c2ecf20Sopenharmony_ci				   enum mptcp_pm_status new_status)
858c2ecf20Sopenharmony_ci{
868c2ecf20Sopenharmony_ci	pr_debug("msk=%p status=%x new=%lx", msk, msk->pm.status,
878c2ecf20Sopenharmony_ci		 BIT(new_status));
888c2ecf20Sopenharmony_ci	if (msk->pm.status & BIT(new_status))
898c2ecf20Sopenharmony_ci		return false;
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci	msk->pm.status |= BIT(new_status);
928c2ecf20Sopenharmony_ci	if (schedule_work(&msk->work))
938c2ecf20Sopenharmony_ci		sock_hold((struct sock *)msk);
948c2ecf20Sopenharmony_ci	return true;
958c2ecf20Sopenharmony_ci}
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_civoid mptcp_pm_fully_established(struct mptcp_sock *msk)
988c2ecf20Sopenharmony_ci{
998c2ecf20Sopenharmony_ci	struct mptcp_pm_data *pm = &msk->pm;
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci	pr_debug("msk=%p", msk);
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci	/* try to avoid acquiring the lock below */
1048c2ecf20Sopenharmony_ci	if (!READ_ONCE(pm->work_pending))
1058c2ecf20Sopenharmony_ci		return;
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci	spin_lock_bh(&pm->lock);
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	if (READ_ONCE(pm->work_pending))
1108c2ecf20Sopenharmony_ci		mptcp_pm_schedule_work(msk, MPTCP_PM_ESTABLISHED);
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci	spin_unlock_bh(&pm->lock);
1138c2ecf20Sopenharmony_ci}
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_civoid mptcp_pm_connection_closed(struct mptcp_sock *msk)
1168c2ecf20Sopenharmony_ci{
1178c2ecf20Sopenharmony_ci	pr_debug("msk=%p", msk);
1188c2ecf20Sopenharmony_ci}
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_civoid mptcp_pm_subflow_established(struct mptcp_sock *msk,
1218c2ecf20Sopenharmony_ci				  struct mptcp_subflow_context *subflow)
1228c2ecf20Sopenharmony_ci{
1238c2ecf20Sopenharmony_ci	struct mptcp_pm_data *pm = &msk->pm;
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci	pr_debug("msk=%p", msk);
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci	if (!READ_ONCE(pm->work_pending))
1288c2ecf20Sopenharmony_ci		return;
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	spin_lock_bh(&pm->lock);
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci	if (READ_ONCE(pm->work_pending))
1338c2ecf20Sopenharmony_ci		mptcp_pm_schedule_work(msk, MPTCP_PM_SUBFLOW_ESTABLISHED);
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	spin_unlock_bh(&pm->lock);
1368c2ecf20Sopenharmony_ci}
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_civoid mptcp_pm_subflow_closed(struct mptcp_sock *msk, u8 id)
1398c2ecf20Sopenharmony_ci{
1408c2ecf20Sopenharmony_ci	pr_debug("msk=%p", msk);
1418c2ecf20Sopenharmony_ci}
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_civoid mptcp_pm_add_addr_received(struct mptcp_sock *msk,
1448c2ecf20Sopenharmony_ci				const struct mptcp_addr_info *addr)
1458c2ecf20Sopenharmony_ci{
1468c2ecf20Sopenharmony_ci	struct mptcp_pm_data *pm = &msk->pm;
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci	pr_debug("msk=%p remote_id=%d accept=%d", msk, addr->id,
1498c2ecf20Sopenharmony_ci		 READ_ONCE(pm->accept_addr));
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci	spin_lock_bh(&pm->lock);
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci	if (!READ_ONCE(pm->accept_addr))
1548c2ecf20Sopenharmony_ci		mptcp_pm_announce_addr(msk, addr, true);
1558c2ecf20Sopenharmony_ci	else if (mptcp_pm_schedule_work(msk, MPTCP_PM_ADD_ADDR_RECEIVED))
1568c2ecf20Sopenharmony_ci		pm->remote = *addr;
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci	spin_unlock_bh(&pm->lock);
1598c2ecf20Sopenharmony_ci}
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_civoid mptcp_pm_rm_addr_received(struct mptcp_sock *msk, u8 rm_id)
1628c2ecf20Sopenharmony_ci{
1638c2ecf20Sopenharmony_ci	struct mptcp_pm_data *pm = &msk->pm;
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci	pr_debug("msk=%p remote_id=%d", msk, rm_id);
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_ci	spin_lock_bh(&pm->lock);
1688c2ecf20Sopenharmony_ci	mptcp_pm_schedule_work(msk, MPTCP_PM_RM_ADDR_RECEIVED);
1698c2ecf20Sopenharmony_ci	pm->rm_id = rm_id;
1708c2ecf20Sopenharmony_ci	spin_unlock_bh(&pm->lock);
1718c2ecf20Sopenharmony_ci}
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci/* path manager helpers */
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_cibool mptcp_pm_add_addr_signal(struct mptcp_sock *msk, unsigned int remaining,
1768c2ecf20Sopenharmony_ci			      struct mptcp_addr_info *saddr, bool *echo)
1778c2ecf20Sopenharmony_ci{
1788c2ecf20Sopenharmony_ci	int ret = false;
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci	spin_lock_bh(&msk->pm.lock);
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci	/* double check after the lock is acquired */
1838c2ecf20Sopenharmony_ci	if (!mptcp_pm_should_add_signal(msk))
1848c2ecf20Sopenharmony_ci		goto out_unlock;
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci	*echo = READ_ONCE(msk->pm.add_addr_echo);
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci	if (remaining < mptcp_add_addr_len(msk->pm.local.family, *echo))
1898c2ecf20Sopenharmony_ci		goto out_unlock;
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci	*saddr = msk->pm.local;
1928c2ecf20Sopenharmony_ci	WRITE_ONCE(msk->pm.add_addr_signal, false);
1938c2ecf20Sopenharmony_ci	ret = true;
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ciout_unlock:
1968c2ecf20Sopenharmony_ci	spin_unlock_bh(&msk->pm.lock);
1978c2ecf20Sopenharmony_ci	return ret;
1988c2ecf20Sopenharmony_ci}
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_cibool mptcp_pm_rm_addr_signal(struct mptcp_sock *msk, unsigned int remaining,
2018c2ecf20Sopenharmony_ci			     u8 *rm_id)
2028c2ecf20Sopenharmony_ci{
2038c2ecf20Sopenharmony_ci	int ret = false;
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci	spin_lock_bh(&msk->pm.lock);
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci	/* double check after the lock is acquired */
2088c2ecf20Sopenharmony_ci	if (!mptcp_pm_should_rm_signal(msk))
2098c2ecf20Sopenharmony_ci		goto out_unlock;
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci	if (remaining < TCPOLEN_MPTCP_RM_ADDR_BASE)
2128c2ecf20Sopenharmony_ci		goto out_unlock;
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci	*rm_id = msk->pm.rm_id;
2158c2ecf20Sopenharmony_ci	WRITE_ONCE(msk->pm.rm_addr_signal, false);
2168c2ecf20Sopenharmony_ci	ret = true;
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ciout_unlock:
2198c2ecf20Sopenharmony_ci	spin_unlock_bh(&msk->pm.lock);
2208c2ecf20Sopenharmony_ci	return ret;
2218c2ecf20Sopenharmony_ci}
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ciint mptcp_pm_get_local_id(struct mptcp_sock *msk, struct sock_common *skc)
2248c2ecf20Sopenharmony_ci{
2258c2ecf20Sopenharmony_ci	return mptcp_pm_nl_get_local_id(msk, skc);
2268c2ecf20Sopenharmony_ci}
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_civoid mptcp_pm_data_init(struct mptcp_sock *msk)
2298c2ecf20Sopenharmony_ci{
2308c2ecf20Sopenharmony_ci	msk->pm.add_addr_signaled = 0;
2318c2ecf20Sopenharmony_ci	msk->pm.add_addr_accepted = 0;
2328c2ecf20Sopenharmony_ci	msk->pm.local_addr_used = 0;
2338c2ecf20Sopenharmony_ci	msk->pm.subflows = 0;
2348c2ecf20Sopenharmony_ci	msk->pm.rm_id = 0;
2358c2ecf20Sopenharmony_ci	WRITE_ONCE(msk->pm.work_pending, false);
2368c2ecf20Sopenharmony_ci	WRITE_ONCE(msk->pm.add_addr_signal, false);
2378c2ecf20Sopenharmony_ci	WRITE_ONCE(msk->pm.rm_addr_signal, false);
2388c2ecf20Sopenharmony_ci	WRITE_ONCE(msk->pm.accept_addr, false);
2398c2ecf20Sopenharmony_ci	WRITE_ONCE(msk->pm.accept_subflow, false);
2408c2ecf20Sopenharmony_ci	WRITE_ONCE(msk->pm.add_addr_echo, false);
2418c2ecf20Sopenharmony_ci	msk->pm.status = 0;
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ci	spin_lock_init(&msk->pm.lock);
2448c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&msk->pm.anno_list);
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci	mptcp_pm_nl_data_init(msk);
2478c2ecf20Sopenharmony_ci}
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_civoid __init mptcp_pm_init(void)
2508c2ecf20Sopenharmony_ci{
2518c2ecf20Sopenharmony_ci	mptcp_pm_nl_init();
2528c2ecf20Sopenharmony_ci}
253