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