18617e85eSMatthieu Baerts (NGI0) // SPDX-License-Identifier: GPL-2.0 28617e85eSMatthieu Baerts (NGI0) /* Multipath TCP 38617e85eSMatthieu Baerts (NGI0) * 48617e85eSMatthieu Baerts (NGI0) * Copyright (c) 2025, Matthieu Baerts. 58617e85eSMatthieu Baerts (NGI0) */ 68617e85eSMatthieu Baerts (NGI0) 78617e85eSMatthieu Baerts (NGI0) #define pr_fmt(fmt) "MPTCP: " fmt 88617e85eSMatthieu Baerts (NGI0) 98617e85eSMatthieu Baerts (NGI0) #include <net/netns/generic.h> 108617e85eSMatthieu Baerts (NGI0) 118617e85eSMatthieu Baerts (NGI0) #include "protocol.h" 128617e85eSMatthieu Baerts (NGI0) #include "mib.h" 138617e85eSMatthieu Baerts (NGI0) #include "mptcp_pm_gen.h" 148617e85eSMatthieu Baerts (NGI0) 158617e85eSMatthieu Baerts (NGI0) static int pm_nl_pernet_id; 168617e85eSMatthieu Baerts (NGI0) 178617e85eSMatthieu Baerts (NGI0) struct pm_nl_pernet { 188617e85eSMatthieu Baerts (NGI0) /* protects pernet updates */ 198617e85eSMatthieu Baerts (NGI0) spinlock_t lock; 208617e85eSMatthieu Baerts (NGI0) struct list_head local_addr_list; 218617e85eSMatthieu Baerts (NGI0) unsigned int addrs; 228617e85eSMatthieu Baerts (NGI0) unsigned int stale_loss_cnt; 238617e85eSMatthieu Baerts (NGI0) unsigned int add_addr_signal_max; 248617e85eSMatthieu Baerts (NGI0) unsigned int add_addr_accept_max; 258617e85eSMatthieu Baerts (NGI0) unsigned int local_addr_max; 268617e85eSMatthieu Baerts (NGI0) unsigned int subflows_max; 278617e85eSMatthieu Baerts (NGI0) unsigned int next_id; 288617e85eSMatthieu Baerts (NGI0) DECLARE_BITMAP(id_bitmap, MPTCP_PM_MAX_ADDR_ID + 1); 298617e85eSMatthieu Baerts (NGI0) }; 308617e85eSMatthieu Baerts (NGI0) 318617e85eSMatthieu Baerts (NGI0) #define MPTCP_PM_ADDR_MAX 8 328617e85eSMatthieu Baerts (NGI0) 338617e85eSMatthieu Baerts (NGI0) static struct pm_nl_pernet *pm_nl_get_pernet(const struct net *net) 348617e85eSMatthieu Baerts (NGI0) { 358617e85eSMatthieu Baerts (NGI0) return net_generic(net, pm_nl_pernet_id); 368617e85eSMatthieu Baerts (NGI0) } 378617e85eSMatthieu Baerts (NGI0) 388617e85eSMatthieu Baerts (NGI0) static struct pm_nl_pernet * 398617e85eSMatthieu Baerts (NGI0) pm_nl_get_pernet_from_msk(const struct mptcp_sock *msk) 408617e85eSMatthieu Baerts (NGI0) { 418617e85eSMatthieu Baerts (NGI0) return pm_nl_get_pernet(sock_net((struct sock *)msk)); 428617e85eSMatthieu Baerts (NGI0) } 438617e85eSMatthieu Baerts (NGI0) 448617e85eSMatthieu Baerts (NGI0) static struct pm_nl_pernet *genl_info_pm_nl(struct genl_info *info) 458617e85eSMatthieu Baerts (NGI0) { 468617e85eSMatthieu Baerts (NGI0) return pm_nl_get_pernet(genl_info_net(info)); 478617e85eSMatthieu Baerts (NGI0) } 488617e85eSMatthieu Baerts (NGI0) 498617e85eSMatthieu Baerts (NGI0) unsigned int mptcp_pm_get_add_addr_signal_max(const struct mptcp_sock *msk) 508617e85eSMatthieu Baerts (NGI0) { 518617e85eSMatthieu Baerts (NGI0) const struct pm_nl_pernet *pernet = pm_nl_get_pernet_from_msk(msk); 528617e85eSMatthieu Baerts (NGI0) 538617e85eSMatthieu Baerts (NGI0) return READ_ONCE(pernet->add_addr_signal_max); 548617e85eSMatthieu Baerts (NGI0) } 558617e85eSMatthieu Baerts (NGI0) EXPORT_SYMBOL_GPL(mptcp_pm_get_add_addr_signal_max); 568617e85eSMatthieu Baerts (NGI0) 578617e85eSMatthieu Baerts (NGI0) unsigned int mptcp_pm_get_add_addr_accept_max(const struct mptcp_sock *msk) 588617e85eSMatthieu Baerts (NGI0) { 598617e85eSMatthieu Baerts (NGI0) struct pm_nl_pernet *pernet = pm_nl_get_pernet_from_msk(msk); 608617e85eSMatthieu Baerts (NGI0) 618617e85eSMatthieu Baerts (NGI0) return READ_ONCE(pernet->add_addr_accept_max); 628617e85eSMatthieu Baerts (NGI0) } 638617e85eSMatthieu Baerts (NGI0) EXPORT_SYMBOL_GPL(mptcp_pm_get_add_addr_accept_max); 648617e85eSMatthieu Baerts (NGI0) 658617e85eSMatthieu Baerts (NGI0) unsigned int mptcp_pm_get_subflows_max(const struct mptcp_sock *msk) 668617e85eSMatthieu Baerts (NGI0) { 678617e85eSMatthieu Baerts (NGI0) struct pm_nl_pernet *pernet = pm_nl_get_pernet_from_msk(msk); 688617e85eSMatthieu Baerts (NGI0) 698617e85eSMatthieu Baerts (NGI0) return READ_ONCE(pernet->subflows_max); 708617e85eSMatthieu Baerts (NGI0) } 718617e85eSMatthieu Baerts (NGI0) EXPORT_SYMBOL_GPL(mptcp_pm_get_subflows_max); 728617e85eSMatthieu Baerts (NGI0) 738617e85eSMatthieu Baerts (NGI0) unsigned int mptcp_pm_get_local_addr_max(const struct mptcp_sock *msk) 748617e85eSMatthieu Baerts (NGI0) { 758617e85eSMatthieu Baerts (NGI0) struct pm_nl_pernet *pernet = pm_nl_get_pernet_from_msk(msk); 768617e85eSMatthieu Baerts (NGI0) 778617e85eSMatthieu Baerts (NGI0) return READ_ONCE(pernet->local_addr_max); 788617e85eSMatthieu Baerts (NGI0) } 798617e85eSMatthieu Baerts (NGI0) EXPORT_SYMBOL_GPL(mptcp_pm_get_local_addr_max); 808617e85eSMatthieu Baerts (NGI0) 818617e85eSMatthieu Baerts (NGI0) static bool lookup_subflow_by_daddr(const struct list_head *list, 828617e85eSMatthieu Baerts (NGI0) const struct mptcp_addr_info *daddr) 838617e85eSMatthieu Baerts (NGI0) { 848617e85eSMatthieu Baerts (NGI0) struct mptcp_subflow_context *subflow; 858617e85eSMatthieu Baerts (NGI0) struct mptcp_addr_info cur; 868617e85eSMatthieu Baerts (NGI0) 878617e85eSMatthieu Baerts (NGI0) list_for_each_entry(subflow, list, node) { 888617e85eSMatthieu Baerts (NGI0) struct sock *ssk = mptcp_subflow_tcp_sock(subflow); 898617e85eSMatthieu Baerts (NGI0) 908617e85eSMatthieu Baerts (NGI0) if (!((1 << inet_sk_state_load(ssk)) & 918617e85eSMatthieu Baerts (NGI0) (TCPF_ESTABLISHED | TCPF_SYN_SENT | TCPF_SYN_RECV))) 928617e85eSMatthieu Baerts (NGI0) continue; 938617e85eSMatthieu Baerts (NGI0) 948617e85eSMatthieu Baerts (NGI0) mptcp_remote_address((struct sock_common *)ssk, &cur); 958617e85eSMatthieu Baerts (NGI0) if (mptcp_addresses_equal(&cur, daddr, daddr->port)) 968617e85eSMatthieu Baerts (NGI0) return true; 978617e85eSMatthieu Baerts (NGI0) } 988617e85eSMatthieu Baerts (NGI0) 998617e85eSMatthieu Baerts (NGI0) return false; 1008617e85eSMatthieu Baerts (NGI0) } 1018617e85eSMatthieu Baerts (NGI0) 1028617e85eSMatthieu Baerts (NGI0) static bool 1038617e85eSMatthieu Baerts (NGI0) select_local_address(const struct pm_nl_pernet *pernet, 1048617e85eSMatthieu Baerts (NGI0) const struct mptcp_sock *msk, 1058617e85eSMatthieu Baerts (NGI0) struct mptcp_pm_local *new_local) 1068617e85eSMatthieu Baerts (NGI0) { 1078617e85eSMatthieu Baerts (NGI0) struct mptcp_pm_addr_entry *entry; 1088617e85eSMatthieu Baerts (NGI0) bool found = false; 1098617e85eSMatthieu Baerts (NGI0) 1108617e85eSMatthieu Baerts (NGI0) msk_owned_by_me(msk); 1118617e85eSMatthieu Baerts (NGI0) 1128617e85eSMatthieu Baerts (NGI0) rcu_read_lock(); 1138617e85eSMatthieu Baerts (NGI0) list_for_each_entry_rcu(entry, &pernet->local_addr_list, list) { 1148617e85eSMatthieu Baerts (NGI0) if (!(entry->flags & MPTCP_PM_ADDR_FLAG_SUBFLOW)) 1158617e85eSMatthieu Baerts (NGI0) continue; 1168617e85eSMatthieu Baerts (NGI0) 1178617e85eSMatthieu Baerts (NGI0) if (!test_bit(entry->addr.id, msk->pm.id_avail_bitmap)) 1188617e85eSMatthieu Baerts (NGI0) continue; 1198617e85eSMatthieu Baerts (NGI0) 1208617e85eSMatthieu Baerts (NGI0) new_local->addr = entry->addr; 1218617e85eSMatthieu Baerts (NGI0) new_local->flags = entry->flags; 1228617e85eSMatthieu Baerts (NGI0) new_local->ifindex = entry->ifindex; 1238617e85eSMatthieu Baerts (NGI0) found = true; 1248617e85eSMatthieu Baerts (NGI0) break; 1258617e85eSMatthieu Baerts (NGI0) } 1268617e85eSMatthieu Baerts (NGI0) rcu_read_unlock(); 1278617e85eSMatthieu Baerts (NGI0) 1288617e85eSMatthieu Baerts (NGI0) return found; 1298617e85eSMatthieu Baerts (NGI0) } 1308617e85eSMatthieu Baerts (NGI0) 1318617e85eSMatthieu Baerts (NGI0) static bool 1328617e85eSMatthieu Baerts (NGI0) select_signal_address(struct pm_nl_pernet *pernet, const struct mptcp_sock *msk, 1338617e85eSMatthieu Baerts (NGI0) struct mptcp_pm_local *new_local) 1348617e85eSMatthieu Baerts (NGI0) { 1358617e85eSMatthieu Baerts (NGI0) struct mptcp_pm_addr_entry *entry; 1368617e85eSMatthieu Baerts (NGI0) bool found = false; 1378617e85eSMatthieu Baerts (NGI0) 1388617e85eSMatthieu Baerts (NGI0) rcu_read_lock(); 1398617e85eSMatthieu Baerts (NGI0) /* do not keep any additional per socket state, just signal 1408617e85eSMatthieu Baerts (NGI0) * the address list in order. 1418617e85eSMatthieu Baerts (NGI0) * Note: removal from the local address list during the msk life-cycle 1428617e85eSMatthieu Baerts (NGI0) * can lead to additional addresses not being announced. 1438617e85eSMatthieu Baerts (NGI0) */ 1448617e85eSMatthieu Baerts (NGI0) list_for_each_entry_rcu(entry, &pernet->local_addr_list, list) { 1458617e85eSMatthieu Baerts (NGI0) if (!test_bit(entry->addr.id, msk->pm.id_avail_bitmap)) 1468617e85eSMatthieu Baerts (NGI0) continue; 1478617e85eSMatthieu Baerts (NGI0) 1488617e85eSMatthieu Baerts (NGI0) if (!(entry->flags & MPTCP_PM_ADDR_FLAG_SIGNAL)) 1498617e85eSMatthieu Baerts (NGI0) continue; 1508617e85eSMatthieu Baerts (NGI0) 1518617e85eSMatthieu Baerts (NGI0) new_local->addr = entry->addr; 1528617e85eSMatthieu Baerts (NGI0) new_local->flags = entry->flags; 1538617e85eSMatthieu Baerts (NGI0) new_local->ifindex = entry->ifindex; 1548617e85eSMatthieu Baerts (NGI0) found = true; 1558617e85eSMatthieu Baerts (NGI0) break; 1568617e85eSMatthieu Baerts (NGI0) } 1578617e85eSMatthieu Baerts (NGI0) rcu_read_unlock(); 1588617e85eSMatthieu Baerts (NGI0) 1598617e85eSMatthieu Baerts (NGI0) return found; 1608617e85eSMatthieu Baerts (NGI0) } 1618617e85eSMatthieu Baerts (NGI0) 1628617e85eSMatthieu Baerts (NGI0) /* Fill all the remote addresses into the array addrs[], 1638617e85eSMatthieu Baerts (NGI0) * and return the array size. 1648617e85eSMatthieu Baerts (NGI0) */ 1658617e85eSMatthieu Baerts (NGI0) static unsigned int fill_remote_addresses_vec(struct mptcp_sock *msk, 1668617e85eSMatthieu Baerts (NGI0) struct mptcp_addr_info *local, 1678617e85eSMatthieu Baerts (NGI0) bool fullmesh, 1688617e85eSMatthieu Baerts (NGI0) struct mptcp_addr_info *addrs) 1698617e85eSMatthieu Baerts (NGI0) { 1708617e85eSMatthieu Baerts (NGI0) bool deny_id0 = READ_ONCE(msk->pm.remote_deny_join_id0); 1718617e85eSMatthieu Baerts (NGI0) struct sock *sk = (struct sock *)msk, *ssk; 1728617e85eSMatthieu Baerts (NGI0) struct mptcp_subflow_context *subflow; 1738617e85eSMatthieu Baerts (NGI0) struct mptcp_addr_info remote = { 0 }; 1748617e85eSMatthieu Baerts (NGI0) unsigned int subflows_max; 1758617e85eSMatthieu Baerts (NGI0) int i = 0; 1768617e85eSMatthieu Baerts (NGI0) 1778617e85eSMatthieu Baerts (NGI0) subflows_max = mptcp_pm_get_subflows_max(msk); 1788617e85eSMatthieu Baerts (NGI0) mptcp_remote_address((struct sock_common *)sk, &remote); 1798617e85eSMatthieu Baerts (NGI0) 1808617e85eSMatthieu Baerts (NGI0) /* Non-fullmesh endpoint, fill in the single entry 1818617e85eSMatthieu Baerts (NGI0) * corresponding to the primary MPC subflow remote address 1828617e85eSMatthieu Baerts (NGI0) */ 1838617e85eSMatthieu Baerts (NGI0) if (!fullmesh) { 1848617e85eSMatthieu Baerts (NGI0) if (deny_id0) 1858617e85eSMatthieu Baerts (NGI0) return 0; 1868617e85eSMatthieu Baerts (NGI0) 1878617e85eSMatthieu Baerts (NGI0) if (!mptcp_pm_addr_families_match(sk, local, &remote)) 1888617e85eSMatthieu Baerts (NGI0) return 0; 1898617e85eSMatthieu Baerts (NGI0) 1908617e85eSMatthieu Baerts (NGI0) msk->pm.subflows++; 1918617e85eSMatthieu Baerts (NGI0) addrs[i++] = remote; 1928617e85eSMatthieu Baerts (NGI0) } else { 1938617e85eSMatthieu Baerts (NGI0) DECLARE_BITMAP(unavail_id, MPTCP_PM_MAX_ADDR_ID + 1); 1948617e85eSMatthieu Baerts (NGI0) 1958617e85eSMatthieu Baerts (NGI0) /* Forbid creation of new subflows matching existing 1968617e85eSMatthieu Baerts (NGI0) * ones, possibly already created by incoming ADD_ADDR 1978617e85eSMatthieu Baerts (NGI0) */ 1988617e85eSMatthieu Baerts (NGI0) bitmap_zero(unavail_id, MPTCP_PM_MAX_ADDR_ID + 1); 1998617e85eSMatthieu Baerts (NGI0) mptcp_for_each_subflow(msk, subflow) 2008617e85eSMatthieu Baerts (NGI0) if (READ_ONCE(subflow->local_id) == local->id) 2018617e85eSMatthieu Baerts (NGI0) __set_bit(subflow->remote_id, unavail_id); 2028617e85eSMatthieu Baerts (NGI0) 2038617e85eSMatthieu Baerts (NGI0) mptcp_for_each_subflow(msk, subflow) { 2048617e85eSMatthieu Baerts (NGI0) ssk = mptcp_subflow_tcp_sock(subflow); 2058617e85eSMatthieu Baerts (NGI0) mptcp_remote_address((struct sock_common *)ssk, &addrs[i]); 2068617e85eSMatthieu Baerts (NGI0) addrs[i].id = READ_ONCE(subflow->remote_id); 2078617e85eSMatthieu Baerts (NGI0) if (deny_id0 && !addrs[i].id) 2088617e85eSMatthieu Baerts (NGI0) continue; 2098617e85eSMatthieu Baerts (NGI0) 2108617e85eSMatthieu Baerts (NGI0) if (test_bit(addrs[i].id, unavail_id)) 2118617e85eSMatthieu Baerts (NGI0) continue; 2128617e85eSMatthieu Baerts (NGI0) 2138617e85eSMatthieu Baerts (NGI0) if (!mptcp_pm_addr_families_match(sk, local, &addrs[i])) 2148617e85eSMatthieu Baerts (NGI0) continue; 2158617e85eSMatthieu Baerts (NGI0) 2168617e85eSMatthieu Baerts (NGI0) if (msk->pm.subflows < subflows_max) { 2178617e85eSMatthieu Baerts (NGI0) /* forbid creating multiple address towards 2188617e85eSMatthieu Baerts (NGI0) * this id 2198617e85eSMatthieu Baerts (NGI0) */ 2208617e85eSMatthieu Baerts (NGI0) __set_bit(addrs[i].id, unavail_id); 2218617e85eSMatthieu Baerts (NGI0) msk->pm.subflows++; 2228617e85eSMatthieu Baerts (NGI0) i++; 2238617e85eSMatthieu Baerts (NGI0) } 2248617e85eSMatthieu Baerts (NGI0) } 2258617e85eSMatthieu Baerts (NGI0) } 2268617e85eSMatthieu Baerts (NGI0) 2278617e85eSMatthieu Baerts (NGI0) return i; 2288617e85eSMatthieu Baerts (NGI0) } 2298617e85eSMatthieu Baerts (NGI0) 2308617e85eSMatthieu Baerts (NGI0) static struct mptcp_pm_addr_entry * 2318617e85eSMatthieu Baerts (NGI0) __lookup_addr_by_id(struct pm_nl_pernet *pernet, unsigned int id) 2328617e85eSMatthieu Baerts (NGI0) { 2338617e85eSMatthieu Baerts (NGI0) struct mptcp_pm_addr_entry *entry; 2348617e85eSMatthieu Baerts (NGI0) 2358617e85eSMatthieu Baerts (NGI0) list_for_each_entry_rcu(entry, &pernet->local_addr_list, list, 2368617e85eSMatthieu Baerts (NGI0) lockdep_is_held(&pernet->lock)) { 2378617e85eSMatthieu Baerts (NGI0) if (entry->addr.id == id) 2388617e85eSMatthieu Baerts (NGI0) return entry; 2398617e85eSMatthieu Baerts (NGI0) } 2408617e85eSMatthieu Baerts (NGI0) return NULL; 2418617e85eSMatthieu Baerts (NGI0) } 2428617e85eSMatthieu Baerts (NGI0) 2438617e85eSMatthieu Baerts (NGI0) static struct mptcp_pm_addr_entry * 2448617e85eSMatthieu Baerts (NGI0) __lookup_addr(struct pm_nl_pernet *pernet, const struct mptcp_addr_info *info) 2458617e85eSMatthieu Baerts (NGI0) { 2468617e85eSMatthieu Baerts (NGI0) struct mptcp_pm_addr_entry *entry; 2478617e85eSMatthieu Baerts (NGI0) 2488617e85eSMatthieu Baerts (NGI0) list_for_each_entry_rcu(entry, &pernet->local_addr_list, list, 2498617e85eSMatthieu Baerts (NGI0) lockdep_is_held(&pernet->lock)) { 2508617e85eSMatthieu Baerts (NGI0) if (mptcp_addresses_equal(&entry->addr, info, entry->addr.port)) 2518617e85eSMatthieu Baerts (NGI0) return entry; 2528617e85eSMatthieu Baerts (NGI0) } 2538617e85eSMatthieu Baerts (NGI0) return NULL; 2548617e85eSMatthieu Baerts (NGI0) } 2558617e85eSMatthieu Baerts (NGI0) 2568617e85eSMatthieu Baerts (NGI0) static void mptcp_pm_create_subflow_or_signal_addr(struct mptcp_sock *msk) 2578617e85eSMatthieu Baerts (NGI0) { 2588617e85eSMatthieu Baerts (NGI0) struct sock *sk = (struct sock *)msk; 2598617e85eSMatthieu Baerts (NGI0) unsigned int add_addr_signal_max; 2608617e85eSMatthieu Baerts (NGI0) bool signal_and_subflow = false; 2618617e85eSMatthieu Baerts (NGI0) unsigned int local_addr_max; 2628617e85eSMatthieu Baerts (NGI0) struct pm_nl_pernet *pernet; 2638617e85eSMatthieu Baerts (NGI0) struct mptcp_pm_local local; 2648617e85eSMatthieu Baerts (NGI0) unsigned int subflows_max; 2658617e85eSMatthieu Baerts (NGI0) 2668617e85eSMatthieu Baerts (NGI0) pernet = pm_nl_get_pernet(sock_net(sk)); 2678617e85eSMatthieu Baerts (NGI0) 2688617e85eSMatthieu Baerts (NGI0) add_addr_signal_max = mptcp_pm_get_add_addr_signal_max(msk); 2698617e85eSMatthieu Baerts (NGI0) local_addr_max = mptcp_pm_get_local_addr_max(msk); 2708617e85eSMatthieu Baerts (NGI0) subflows_max = mptcp_pm_get_subflows_max(msk); 2718617e85eSMatthieu Baerts (NGI0) 2728617e85eSMatthieu Baerts (NGI0) /* do lazy endpoint usage accounting for the MPC subflows */ 2738617e85eSMatthieu Baerts (NGI0) if (unlikely(!(msk->pm.status & BIT(MPTCP_PM_MPC_ENDPOINT_ACCOUNTED))) && msk->first) { 2748617e85eSMatthieu Baerts (NGI0) struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(msk->first); 2758617e85eSMatthieu Baerts (NGI0) struct mptcp_pm_addr_entry *entry; 2768617e85eSMatthieu Baerts (NGI0) struct mptcp_addr_info mpc_addr; 2778617e85eSMatthieu Baerts (NGI0) bool backup = false; 2788617e85eSMatthieu Baerts (NGI0) 2798617e85eSMatthieu Baerts (NGI0) mptcp_local_address((struct sock_common *)msk->first, &mpc_addr); 2808617e85eSMatthieu Baerts (NGI0) rcu_read_lock(); 2818617e85eSMatthieu Baerts (NGI0) entry = __lookup_addr(pernet, &mpc_addr); 2828617e85eSMatthieu Baerts (NGI0) if (entry) { 2838617e85eSMatthieu Baerts (NGI0) __clear_bit(entry->addr.id, msk->pm.id_avail_bitmap); 2848617e85eSMatthieu Baerts (NGI0) msk->mpc_endpoint_id = entry->addr.id; 2858617e85eSMatthieu Baerts (NGI0) backup = !!(entry->flags & MPTCP_PM_ADDR_FLAG_BACKUP); 2868617e85eSMatthieu Baerts (NGI0) } 2878617e85eSMatthieu Baerts (NGI0) rcu_read_unlock(); 2888617e85eSMatthieu Baerts (NGI0) 2898617e85eSMatthieu Baerts (NGI0) if (backup) 2908617e85eSMatthieu Baerts (NGI0) mptcp_pm_send_ack(msk, subflow, true, backup); 2918617e85eSMatthieu Baerts (NGI0) 2928617e85eSMatthieu Baerts (NGI0) msk->pm.status |= BIT(MPTCP_PM_MPC_ENDPOINT_ACCOUNTED); 2938617e85eSMatthieu Baerts (NGI0) } 2948617e85eSMatthieu Baerts (NGI0) 2958617e85eSMatthieu Baerts (NGI0) pr_debug("local %d:%d signal %d:%d subflows %d:%d\n", 2968617e85eSMatthieu Baerts (NGI0) msk->pm.local_addr_used, local_addr_max, 2978617e85eSMatthieu Baerts (NGI0) msk->pm.add_addr_signaled, add_addr_signal_max, 2988617e85eSMatthieu Baerts (NGI0) msk->pm.subflows, subflows_max); 2998617e85eSMatthieu Baerts (NGI0) 3008617e85eSMatthieu Baerts (NGI0) /* check first for announce */ 3018617e85eSMatthieu Baerts (NGI0) if (msk->pm.add_addr_signaled < add_addr_signal_max) { 3028617e85eSMatthieu Baerts (NGI0) /* due to racing events on both ends we can reach here while 3038617e85eSMatthieu Baerts (NGI0) * previous add address is still running: if we invoke now 3048617e85eSMatthieu Baerts (NGI0) * mptcp_pm_announce_addr(), that will fail and the 3058617e85eSMatthieu Baerts (NGI0) * corresponding id will be marked as used. 3068617e85eSMatthieu Baerts (NGI0) * Instead let the PM machinery reschedule us when the 3078617e85eSMatthieu Baerts (NGI0) * current address announce will be completed. 3088617e85eSMatthieu Baerts (NGI0) */ 3098617e85eSMatthieu Baerts (NGI0) if (msk->pm.addr_signal & BIT(MPTCP_ADD_ADDR_SIGNAL)) 3108617e85eSMatthieu Baerts (NGI0) return; 3118617e85eSMatthieu Baerts (NGI0) 3128617e85eSMatthieu Baerts (NGI0) if (!select_signal_address(pernet, msk, &local)) 3138617e85eSMatthieu Baerts (NGI0) goto subflow; 3148617e85eSMatthieu Baerts (NGI0) 3158617e85eSMatthieu Baerts (NGI0) /* If the alloc fails, we are on memory pressure, not worth 3168617e85eSMatthieu Baerts (NGI0) * continuing, and trying to create subflows. 3178617e85eSMatthieu Baerts (NGI0) */ 3188617e85eSMatthieu Baerts (NGI0) if (!mptcp_pm_alloc_anno_list(msk, &local.addr)) 3198617e85eSMatthieu Baerts (NGI0) return; 3208617e85eSMatthieu Baerts (NGI0) 3218617e85eSMatthieu Baerts (NGI0) __clear_bit(local.addr.id, msk->pm.id_avail_bitmap); 3228617e85eSMatthieu Baerts (NGI0) msk->pm.add_addr_signaled++; 3238617e85eSMatthieu Baerts (NGI0) 3248617e85eSMatthieu Baerts (NGI0) /* Special case for ID0: set the correct ID */ 3258617e85eSMatthieu Baerts (NGI0) if (local.addr.id == msk->mpc_endpoint_id) 3268617e85eSMatthieu Baerts (NGI0) local.addr.id = 0; 3278617e85eSMatthieu Baerts (NGI0) 3288617e85eSMatthieu Baerts (NGI0) mptcp_pm_announce_addr(msk, &local.addr, false); 3298617e85eSMatthieu Baerts (NGI0) mptcp_pm_addr_send_ack(msk); 3308617e85eSMatthieu Baerts (NGI0) 3318617e85eSMatthieu Baerts (NGI0) if (local.flags & MPTCP_PM_ADDR_FLAG_SUBFLOW) 3328617e85eSMatthieu Baerts (NGI0) signal_and_subflow = true; 3338617e85eSMatthieu Baerts (NGI0) } 3348617e85eSMatthieu Baerts (NGI0) 3358617e85eSMatthieu Baerts (NGI0) subflow: 3368617e85eSMatthieu Baerts (NGI0) /* check if should create a new subflow */ 3378617e85eSMatthieu Baerts (NGI0) while (msk->pm.local_addr_used < local_addr_max && 3388617e85eSMatthieu Baerts (NGI0) msk->pm.subflows < subflows_max) { 3398617e85eSMatthieu Baerts (NGI0) struct mptcp_addr_info addrs[MPTCP_PM_ADDR_MAX]; 3408617e85eSMatthieu Baerts (NGI0) bool fullmesh; 3418617e85eSMatthieu Baerts (NGI0) int i, nr; 3428617e85eSMatthieu Baerts (NGI0) 3438617e85eSMatthieu Baerts (NGI0) if (signal_and_subflow) 3448617e85eSMatthieu Baerts (NGI0) signal_and_subflow = false; 3458617e85eSMatthieu Baerts (NGI0) else if (!select_local_address(pernet, msk, &local)) 3468617e85eSMatthieu Baerts (NGI0) break; 3478617e85eSMatthieu Baerts (NGI0) 3488617e85eSMatthieu Baerts (NGI0) fullmesh = !!(local.flags & MPTCP_PM_ADDR_FLAG_FULLMESH); 3498617e85eSMatthieu Baerts (NGI0) 3508617e85eSMatthieu Baerts (NGI0) __clear_bit(local.addr.id, msk->pm.id_avail_bitmap); 3518617e85eSMatthieu Baerts (NGI0) 3528617e85eSMatthieu Baerts (NGI0) /* Special case for ID0: set the correct ID */ 3538617e85eSMatthieu Baerts (NGI0) if (local.addr.id == msk->mpc_endpoint_id) 3548617e85eSMatthieu Baerts (NGI0) local.addr.id = 0; 3558617e85eSMatthieu Baerts (NGI0) else /* local_addr_used is not decr for ID 0 */ 3568617e85eSMatthieu Baerts (NGI0) msk->pm.local_addr_used++; 3578617e85eSMatthieu Baerts (NGI0) 3588617e85eSMatthieu Baerts (NGI0) nr = fill_remote_addresses_vec(msk, &local.addr, fullmesh, addrs); 3598617e85eSMatthieu Baerts (NGI0) if (nr == 0) 3608617e85eSMatthieu Baerts (NGI0) continue; 3618617e85eSMatthieu Baerts (NGI0) 3628617e85eSMatthieu Baerts (NGI0) spin_unlock_bh(&msk->pm.lock); 3638617e85eSMatthieu Baerts (NGI0) for (i = 0; i < nr; i++) 3648617e85eSMatthieu Baerts (NGI0) __mptcp_subflow_connect(sk, &local, &addrs[i]); 3658617e85eSMatthieu Baerts (NGI0) spin_lock_bh(&msk->pm.lock); 3668617e85eSMatthieu Baerts (NGI0) } 3678617e85eSMatthieu Baerts (NGI0) mptcp_pm_nl_check_work_pending(msk); 3688617e85eSMatthieu Baerts (NGI0) } 3698617e85eSMatthieu Baerts (NGI0) 3708617e85eSMatthieu Baerts (NGI0) static void mptcp_pm_nl_fully_established(struct mptcp_sock *msk) 3718617e85eSMatthieu Baerts (NGI0) { 3728617e85eSMatthieu Baerts (NGI0) mptcp_pm_create_subflow_or_signal_addr(msk); 3738617e85eSMatthieu Baerts (NGI0) } 3748617e85eSMatthieu Baerts (NGI0) 3758617e85eSMatthieu Baerts (NGI0) static void mptcp_pm_nl_subflow_established(struct mptcp_sock *msk) 3768617e85eSMatthieu Baerts (NGI0) { 3778617e85eSMatthieu Baerts (NGI0) mptcp_pm_create_subflow_or_signal_addr(msk); 3788617e85eSMatthieu Baerts (NGI0) } 3798617e85eSMatthieu Baerts (NGI0) 3808617e85eSMatthieu Baerts (NGI0) /* Fill all the local addresses into the array addrs[], 3818617e85eSMatthieu Baerts (NGI0) * and return the array size. 3828617e85eSMatthieu Baerts (NGI0) */ 3838617e85eSMatthieu Baerts (NGI0) static unsigned int fill_local_addresses_vec(struct mptcp_sock *msk, 3848617e85eSMatthieu Baerts (NGI0) struct mptcp_addr_info *remote, 3858617e85eSMatthieu Baerts (NGI0) struct mptcp_pm_local *locals) 3868617e85eSMatthieu Baerts (NGI0) { 3878617e85eSMatthieu Baerts (NGI0) struct sock *sk = (struct sock *)msk; 3888617e85eSMatthieu Baerts (NGI0) struct mptcp_pm_addr_entry *entry; 3898617e85eSMatthieu Baerts (NGI0) struct mptcp_addr_info mpc_addr; 3908617e85eSMatthieu Baerts (NGI0) struct pm_nl_pernet *pernet; 3918617e85eSMatthieu Baerts (NGI0) unsigned int subflows_max; 3928617e85eSMatthieu Baerts (NGI0) int i = 0; 3938617e85eSMatthieu Baerts (NGI0) 3948617e85eSMatthieu Baerts (NGI0) pernet = pm_nl_get_pernet_from_msk(msk); 3958617e85eSMatthieu Baerts (NGI0) subflows_max = mptcp_pm_get_subflows_max(msk); 3968617e85eSMatthieu Baerts (NGI0) 3978617e85eSMatthieu Baerts (NGI0) mptcp_local_address((struct sock_common *)msk, &mpc_addr); 3988617e85eSMatthieu Baerts (NGI0) 3998617e85eSMatthieu Baerts (NGI0) rcu_read_lock(); 4008617e85eSMatthieu Baerts (NGI0) list_for_each_entry_rcu(entry, &pernet->local_addr_list, list) { 4018617e85eSMatthieu Baerts (NGI0) if (!(entry->flags & MPTCP_PM_ADDR_FLAG_FULLMESH)) 4028617e85eSMatthieu Baerts (NGI0) continue; 4038617e85eSMatthieu Baerts (NGI0) 4048617e85eSMatthieu Baerts (NGI0) if (!mptcp_pm_addr_families_match(sk, &entry->addr, remote)) 4058617e85eSMatthieu Baerts (NGI0) continue; 4068617e85eSMatthieu Baerts (NGI0) 4078617e85eSMatthieu Baerts (NGI0) if (msk->pm.subflows < subflows_max) { 4088617e85eSMatthieu Baerts (NGI0) locals[i].addr = entry->addr; 4098617e85eSMatthieu Baerts (NGI0) locals[i].flags = entry->flags; 4108617e85eSMatthieu Baerts (NGI0) locals[i].ifindex = entry->ifindex; 4118617e85eSMatthieu Baerts (NGI0) 4128617e85eSMatthieu Baerts (NGI0) /* Special case for ID0: set the correct ID */ 4138617e85eSMatthieu Baerts (NGI0) if (mptcp_addresses_equal(&locals[i].addr, &mpc_addr, locals[i].addr.port)) 4148617e85eSMatthieu Baerts (NGI0) locals[i].addr.id = 0; 4158617e85eSMatthieu Baerts (NGI0) 4168617e85eSMatthieu Baerts (NGI0) msk->pm.subflows++; 4178617e85eSMatthieu Baerts (NGI0) i++; 4188617e85eSMatthieu Baerts (NGI0) } 4198617e85eSMatthieu Baerts (NGI0) } 4208617e85eSMatthieu Baerts (NGI0) rcu_read_unlock(); 4218617e85eSMatthieu Baerts (NGI0) 4228617e85eSMatthieu Baerts (NGI0) /* If the array is empty, fill in the single 4238617e85eSMatthieu Baerts (NGI0) * 'IPADDRANY' local address 4248617e85eSMatthieu Baerts (NGI0) */ 4258617e85eSMatthieu Baerts (NGI0) if (!i) { 4268617e85eSMatthieu Baerts (NGI0) memset(&locals[i], 0, sizeof(locals[i])); 4278617e85eSMatthieu Baerts (NGI0) locals[i].addr.family = 4288617e85eSMatthieu Baerts (NGI0) #if IS_ENABLED(CONFIG_MPTCP_IPV6) 4298617e85eSMatthieu Baerts (NGI0) remote->family == AF_INET6 && 4308617e85eSMatthieu Baerts (NGI0) ipv6_addr_v4mapped(&remote->addr6) ? AF_INET : 4318617e85eSMatthieu Baerts (NGI0) #endif 4328617e85eSMatthieu Baerts (NGI0) remote->family; 4338617e85eSMatthieu Baerts (NGI0) 4348617e85eSMatthieu Baerts (NGI0) if (!mptcp_pm_addr_families_match(sk, &locals[i].addr, remote)) 4358617e85eSMatthieu Baerts (NGI0) return 0; 4368617e85eSMatthieu Baerts (NGI0) 4378617e85eSMatthieu Baerts (NGI0) msk->pm.subflows++; 4388617e85eSMatthieu Baerts (NGI0) i++; 4398617e85eSMatthieu Baerts (NGI0) } 4408617e85eSMatthieu Baerts (NGI0) 4418617e85eSMatthieu Baerts (NGI0) return i; 4428617e85eSMatthieu Baerts (NGI0) } 4438617e85eSMatthieu Baerts (NGI0) 4448617e85eSMatthieu Baerts (NGI0) static void mptcp_pm_nl_add_addr_received(struct mptcp_sock *msk) 4458617e85eSMatthieu Baerts (NGI0) { 4468617e85eSMatthieu Baerts (NGI0) struct mptcp_pm_local locals[MPTCP_PM_ADDR_MAX]; 4478617e85eSMatthieu Baerts (NGI0) struct sock *sk = (struct sock *)msk; 4488617e85eSMatthieu Baerts (NGI0) unsigned int add_addr_accept_max; 4498617e85eSMatthieu Baerts (NGI0) struct mptcp_addr_info remote; 4508617e85eSMatthieu Baerts (NGI0) unsigned int subflows_max; 4518617e85eSMatthieu Baerts (NGI0) bool sf_created = false; 4528617e85eSMatthieu Baerts (NGI0) int i, nr; 4538617e85eSMatthieu Baerts (NGI0) 4548617e85eSMatthieu Baerts (NGI0) add_addr_accept_max = mptcp_pm_get_add_addr_accept_max(msk); 4558617e85eSMatthieu Baerts (NGI0) subflows_max = mptcp_pm_get_subflows_max(msk); 4568617e85eSMatthieu Baerts (NGI0) 4578617e85eSMatthieu Baerts (NGI0) pr_debug("accepted %d:%d remote family %d\n", 4588617e85eSMatthieu Baerts (NGI0) msk->pm.add_addr_accepted, add_addr_accept_max, 4598617e85eSMatthieu Baerts (NGI0) msk->pm.remote.family); 4608617e85eSMatthieu Baerts (NGI0) 4618617e85eSMatthieu Baerts (NGI0) remote = msk->pm.remote; 4628617e85eSMatthieu Baerts (NGI0) mptcp_pm_announce_addr(msk, &remote, true); 4638617e85eSMatthieu Baerts (NGI0) mptcp_pm_addr_send_ack(msk); 4648617e85eSMatthieu Baerts (NGI0) 4658617e85eSMatthieu Baerts (NGI0) if (lookup_subflow_by_daddr(&msk->conn_list, &remote)) 4668617e85eSMatthieu Baerts (NGI0) return; 4678617e85eSMatthieu Baerts (NGI0) 4688617e85eSMatthieu Baerts (NGI0) /* pick id 0 port, if none is provided the remote address */ 4698617e85eSMatthieu Baerts (NGI0) if (!remote.port) 4708617e85eSMatthieu Baerts (NGI0) remote.port = sk->sk_dport; 4718617e85eSMatthieu Baerts (NGI0) 4728617e85eSMatthieu Baerts (NGI0) /* connect to the specified remote address, using whatever 4738617e85eSMatthieu Baerts (NGI0) * local address the routing configuration will pick. 4748617e85eSMatthieu Baerts (NGI0) */ 4758617e85eSMatthieu Baerts (NGI0) nr = fill_local_addresses_vec(msk, &remote, locals); 4768617e85eSMatthieu Baerts (NGI0) if (nr == 0) 4778617e85eSMatthieu Baerts (NGI0) return; 4788617e85eSMatthieu Baerts (NGI0) 4798617e85eSMatthieu Baerts (NGI0) spin_unlock_bh(&msk->pm.lock); 4808617e85eSMatthieu Baerts (NGI0) for (i = 0; i < nr; i++) 4818617e85eSMatthieu Baerts (NGI0) if (__mptcp_subflow_connect(sk, &locals[i], &remote) == 0) 4828617e85eSMatthieu Baerts (NGI0) sf_created = true; 4838617e85eSMatthieu Baerts (NGI0) spin_lock_bh(&msk->pm.lock); 4848617e85eSMatthieu Baerts (NGI0) 4858617e85eSMatthieu Baerts (NGI0) if (sf_created) { 4868617e85eSMatthieu Baerts (NGI0) /* add_addr_accepted is not decr for ID 0 */ 4878617e85eSMatthieu Baerts (NGI0) if (remote.id) 4888617e85eSMatthieu Baerts (NGI0) msk->pm.add_addr_accepted++; 4898617e85eSMatthieu Baerts (NGI0) if (msk->pm.add_addr_accepted >= add_addr_accept_max || 4908617e85eSMatthieu Baerts (NGI0) msk->pm.subflows >= subflows_max) 4918617e85eSMatthieu Baerts (NGI0) WRITE_ONCE(msk->pm.accept_addr, false); 4928617e85eSMatthieu Baerts (NGI0) } 4938617e85eSMatthieu Baerts (NGI0) } 4948617e85eSMatthieu Baerts (NGI0) 4958617e85eSMatthieu Baerts (NGI0) void mptcp_pm_nl_rm_addr(struct mptcp_sock *msk, u8 rm_id) 4968617e85eSMatthieu Baerts (NGI0) { 4978617e85eSMatthieu Baerts (NGI0) if (rm_id && WARN_ON_ONCE(msk->pm.add_addr_accepted == 0)) { 4988617e85eSMatthieu Baerts (NGI0) /* Note: if the subflow has been closed before, this 4998617e85eSMatthieu Baerts (NGI0) * add_addr_accepted counter will not be decremented. 5008617e85eSMatthieu Baerts (NGI0) */ 5018617e85eSMatthieu Baerts (NGI0) if (--msk->pm.add_addr_accepted < mptcp_pm_get_add_addr_accept_max(msk)) 5028617e85eSMatthieu Baerts (NGI0) WRITE_ONCE(msk->pm.accept_addr, true); 5038617e85eSMatthieu Baerts (NGI0) } 5048617e85eSMatthieu Baerts (NGI0) } 5058617e85eSMatthieu Baerts (NGI0) 5068617e85eSMatthieu Baerts (NGI0) static bool address_use_port(struct mptcp_pm_addr_entry *entry) 5078617e85eSMatthieu Baerts (NGI0) { 5088617e85eSMatthieu Baerts (NGI0) return (entry->flags & 5098617e85eSMatthieu Baerts (NGI0) (MPTCP_PM_ADDR_FLAG_SIGNAL | MPTCP_PM_ADDR_FLAG_SUBFLOW)) == 5108617e85eSMatthieu Baerts (NGI0) MPTCP_PM_ADDR_FLAG_SIGNAL; 5118617e85eSMatthieu Baerts (NGI0) } 5128617e85eSMatthieu Baerts (NGI0) 5138617e85eSMatthieu Baerts (NGI0) /* caller must ensure the RCU grace period is already elapsed */ 5148617e85eSMatthieu Baerts (NGI0) static void __mptcp_pm_release_addr_entry(struct mptcp_pm_addr_entry *entry) 5158617e85eSMatthieu Baerts (NGI0) { 5168617e85eSMatthieu Baerts (NGI0) if (entry->lsk) 5178617e85eSMatthieu Baerts (NGI0) sock_release(entry->lsk); 5188617e85eSMatthieu Baerts (NGI0) kfree(entry); 5198617e85eSMatthieu Baerts (NGI0) } 5208617e85eSMatthieu Baerts (NGI0) 5218617e85eSMatthieu Baerts (NGI0) static int mptcp_pm_nl_append_new_local_addr(struct pm_nl_pernet *pernet, 5228617e85eSMatthieu Baerts (NGI0) struct mptcp_pm_addr_entry *entry, 5238617e85eSMatthieu Baerts (NGI0) bool needs_id, bool replace) 5248617e85eSMatthieu Baerts (NGI0) { 5258617e85eSMatthieu Baerts (NGI0) struct mptcp_pm_addr_entry *cur, *del_entry = NULL; 5268617e85eSMatthieu Baerts (NGI0) unsigned int addr_max; 5278617e85eSMatthieu Baerts (NGI0) int ret = -EINVAL; 5288617e85eSMatthieu Baerts (NGI0) 5298617e85eSMatthieu Baerts (NGI0) spin_lock_bh(&pernet->lock); 5308617e85eSMatthieu Baerts (NGI0) /* to keep the code simple, don't do IDR-like allocation for address ID, 5318617e85eSMatthieu Baerts (NGI0) * just bail when we exceed limits 5328617e85eSMatthieu Baerts (NGI0) */ 5338617e85eSMatthieu Baerts (NGI0) if (pernet->next_id == MPTCP_PM_MAX_ADDR_ID) 5348617e85eSMatthieu Baerts (NGI0) pernet->next_id = 1; 5358617e85eSMatthieu Baerts (NGI0) if (pernet->addrs >= MPTCP_PM_ADDR_MAX) { 5368617e85eSMatthieu Baerts (NGI0) ret = -ERANGE; 5378617e85eSMatthieu Baerts (NGI0) goto out; 5388617e85eSMatthieu Baerts (NGI0) } 5398617e85eSMatthieu Baerts (NGI0) if (test_bit(entry->addr.id, pernet->id_bitmap)) { 5408617e85eSMatthieu Baerts (NGI0) ret = -EBUSY; 5418617e85eSMatthieu Baerts (NGI0) goto out; 5428617e85eSMatthieu Baerts (NGI0) } 5438617e85eSMatthieu Baerts (NGI0) 5448617e85eSMatthieu Baerts (NGI0) /* do not insert duplicate address, differentiate on port only 5458617e85eSMatthieu Baerts (NGI0) * singled addresses 5468617e85eSMatthieu Baerts (NGI0) */ 5478617e85eSMatthieu Baerts (NGI0) if (!address_use_port(entry)) 5488617e85eSMatthieu Baerts (NGI0) entry->addr.port = 0; 5498617e85eSMatthieu Baerts (NGI0) list_for_each_entry(cur, &pernet->local_addr_list, list) { 5508617e85eSMatthieu Baerts (NGI0) if (mptcp_addresses_equal(&cur->addr, &entry->addr, 5518617e85eSMatthieu Baerts (NGI0) cur->addr.port || entry->addr.port)) { 5528617e85eSMatthieu Baerts (NGI0) /* allow replacing the exiting endpoint only if such 5538617e85eSMatthieu Baerts (NGI0) * endpoint is an implicit one and the user-space 5548617e85eSMatthieu Baerts (NGI0) * did not provide an endpoint id 5558617e85eSMatthieu Baerts (NGI0) */ 5568617e85eSMatthieu Baerts (NGI0) if (!(cur->flags & MPTCP_PM_ADDR_FLAG_IMPLICIT)) { 5578617e85eSMatthieu Baerts (NGI0) ret = -EEXIST; 5588617e85eSMatthieu Baerts (NGI0) goto out; 5598617e85eSMatthieu Baerts (NGI0) } 5608617e85eSMatthieu Baerts (NGI0) if (entry->addr.id) 5618617e85eSMatthieu Baerts (NGI0) goto out; 5628617e85eSMatthieu Baerts (NGI0) 5638617e85eSMatthieu Baerts (NGI0) /* allow callers that only need to look up the local 5648617e85eSMatthieu Baerts (NGI0) * addr's id to skip replacement. This allows them to 5658617e85eSMatthieu Baerts (NGI0) * avoid calling synchronize_rcu in the packet recv 5668617e85eSMatthieu Baerts (NGI0) * path. 5678617e85eSMatthieu Baerts (NGI0) */ 5688617e85eSMatthieu Baerts (NGI0) if (!replace) { 5698617e85eSMatthieu Baerts (NGI0) kfree(entry); 5708617e85eSMatthieu Baerts (NGI0) ret = cur->addr.id; 5718617e85eSMatthieu Baerts (NGI0) goto out; 5728617e85eSMatthieu Baerts (NGI0) } 5738617e85eSMatthieu Baerts (NGI0) 5748617e85eSMatthieu Baerts (NGI0) pernet->addrs--; 5758617e85eSMatthieu Baerts (NGI0) entry->addr.id = cur->addr.id; 5768617e85eSMatthieu Baerts (NGI0) list_del_rcu(&cur->list); 5778617e85eSMatthieu Baerts (NGI0) del_entry = cur; 5788617e85eSMatthieu Baerts (NGI0) break; 5798617e85eSMatthieu Baerts (NGI0) } 5808617e85eSMatthieu Baerts (NGI0) } 5818617e85eSMatthieu Baerts (NGI0) 5828617e85eSMatthieu Baerts (NGI0) if (!entry->addr.id && needs_id) { 5838617e85eSMatthieu Baerts (NGI0) find_next: 5848617e85eSMatthieu Baerts (NGI0) entry->addr.id = find_next_zero_bit(pernet->id_bitmap, 5858617e85eSMatthieu Baerts (NGI0) MPTCP_PM_MAX_ADDR_ID + 1, 5868617e85eSMatthieu Baerts (NGI0) pernet->next_id); 5878617e85eSMatthieu Baerts (NGI0) if (!entry->addr.id && pernet->next_id != 1) { 5888617e85eSMatthieu Baerts (NGI0) pernet->next_id = 1; 5898617e85eSMatthieu Baerts (NGI0) goto find_next; 5908617e85eSMatthieu Baerts (NGI0) } 5918617e85eSMatthieu Baerts (NGI0) } 5928617e85eSMatthieu Baerts (NGI0) 5938617e85eSMatthieu Baerts (NGI0) if (!entry->addr.id && needs_id) 5948617e85eSMatthieu Baerts (NGI0) goto out; 5958617e85eSMatthieu Baerts (NGI0) 5968617e85eSMatthieu Baerts (NGI0) __set_bit(entry->addr.id, pernet->id_bitmap); 5978617e85eSMatthieu Baerts (NGI0) if (entry->addr.id > pernet->next_id) 5988617e85eSMatthieu Baerts (NGI0) pernet->next_id = entry->addr.id; 5998617e85eSMatthieu Baerts (NGI0) 6008617e85eSMatthieu Baerts (NGI0) if (entry->flags & MPTCP_PM_ADDR_FLAG_SIGNAL) { 6018617e85eSMatthieu Baerts (NGI0) addr_max = pernet->add_addr_signal_max; 6028617e85eSMatthieu Baerts (NGI0) WRITE_ONCE(pernet->add_addr_signal_max, addr_max + 1); 6038617e85eSMatthieu Baerts (NGI0) } 6048617e85eSMatthieu Baerts (NGI0) if (entry->flags & MPTCP_PM_ADDR_FLAG_SUBFLOW) { 6058617e85eSMatthieu Baerts (NGI0) addr_max = pernet->local_addr_max; 6068617e85eSMatthieu Baerts (NGI0) WRITE_ONCE(pernet->local_addr_max, addr_max + 1); 6078617e85eSMatthieu Baerts (NGI0) } 6088617e85eSMatthieu Baerts (NGI0) 6098617e85eSMatthieu Baerts (NGI0) pernet->addrs++; 6108617e85eSMatthieu Baerts (NGI0) if (!entry->addr.port) 6118617e85eSMatthieu Baerts (NGI0) list_add_tail_rcu(&entry->list, &pernet->local_addr_list); 6128617e85eSMatthieu Baerts (NGI0) else 6138617e85eSMatthieu Baerts (NGI0) list_add_rcu(&entry->list, &pernet->local_addr_list); 6148617e85eSMatthieu Baerts (NGI0) ret = entry->addr.id; 6158617e85eSMatthieu Baerts (NGI0) 6168617e85eSMatthieu Baerts (NGI0) out: 6178617e85eSMatthieu Baerts (NGI0) spin_unlock_bh(&pernet->lock); 6188617e85eSMatthieu Baerts (NGI0) 6198617e85eSMatthieu Baerts (NGI0) /* just replaced an existing entry, free it */ 6208617e85eSMatthieu Baerts (NGI0) if (del_entry) { 6218617e85eSMatthieu Baerts (NGI0) synchronize_rcu(); 6228617e85eSMatthieu Baerts (NGI0) __mptcp_pm_release_addr_entry(del_entry); 6238617e85eSMatthieu Baerts (NGI0) } 6248617e85eSMatthieu Baerts (NGI0) return ret; 6258617e85eSMatthieu Baerts (NGI0) } 6268617e85eSMatthieu Baerts (NGI0) 6278617e85eSMatthieu Baerts (NGI0) static struct lock_class_key mptcp_slock_keys[2]; 6288617e85eSMatthieu Baerts (NGI0) static struct lock_class_key mptcp_keys[2]; 6298617e85eSMatthieu Baerts (NGI0) 6308617e85eSMatthieu Baerts (NGI0) static int mptcp_pm_nl_create_listen_socket(struct sock *sk, 6318617e85eSMatthieu Baerts (NGI0) struct mptcp_pm_addr_entry *entry) 6328617e85eSMatthieu Baerts (NGI0) { 6338617e85eSMatthieu Baerts (NGI0) bool is_ipv6 = sk->sk_family == AF_INET6; 6348617e85eSMatthieu Baerts (NGI0) int addrlen = sizeof(struct sockaddr_in); 6358617e85eSMatthieu Baerts (NGI0) struct sockaddr_storage addr; 6368617e85eSMatthieu Baerts (NGI0) struct sock *newsk, *ssk; 6378617e85eSMatthieu Baerts (NGI0) int backlog = 1024; 6388617e85eSMatthieu Baerts (NGI0) int err; 6398617e85eSMatthieu Baerts (NGI0) 6408617e85eSMatthieu Baerts (NGI0) err = sock_create_kern(sock_net(sk), entry->addr.family, 6418617e85eSMatthieu Baerts (NGI0) SOCK_STREAM, IPPROTO_MPTCP, &entry->lsk); 6428617e85eSMatthieu Baerts (NGI0) if (err) 6438617e85eSMatthieu Baerts (NGI0) return err; 6448617e85eSMatthieu Baerts (NGI0) 6458617e85eSMatthieu Baerts (NGI0) newsk = entry->lsk->sk; 6468617e85eSMatthieu Baerts (NGI0) if (!newsk) 6478617e85eSMatthieu Baerts (NGI0) return -EINVAL; 6488617e85eSMatthieu Baerts (NGI0) 6498617e85eSMatthieu Baerts (NGI0) /* The subflow socket lock is acquired in a nested to the msk one 6508617e85eSMatthieu Baerts (NGI0) * in several places, even by the TCP stack, and this msk is a kernel 6518617e85eSMatthieu Baerts (NGI0) * socket: lockdep complains. Instead of propagating the _nested 6528617e85eSMatthieu Baerts (NGI0) * modifiers in several places, re-init the lock class for the msk 6538617e85eSMatthieu Baerts (NGI0) * socket to an mptcp specific one. 6548617e85eSMatthieu Baerts (NGI0) */ 6558617e85eSMatthieu Baerts (NGI0) sock_lock_init_class_and_name(newsk, 6568617e85eSMatthieu Baerts (NGI0) is_ipv6 ? "mlock-AF_INET6" : "mlock-AF_INET", 6578617e85eSMatthieu Baerts (NGI0) &mptcp_slock_keys[is_ipv6], 6588617e85eSMatthieu Baerts (NGI0) is_ipv6 ? "msk_lock-AF_INET6" : "msk_lock-AF_INET", 6598617e85eSMatthieu Baerts (NGI0) &mptcp_keys[is_ipv6]); 6608617e85eSMatthieu Baerts (NGI0) 6618617e85eSMatthieu Baerts (NGI0) lock_sock(newsk); 6628617e85eSMatthieu Baerts (NGI0) ssk = __mptcp_nmpc_sk(mptcp_sk(newsk)); 6638617e85eSMatthieu Baerts (NGI0) release_sock(newsk); 6648617e85eSMatthieu Baerts (NGI0) if (IS_ERR(ssk)) 6658617e85eSMatthieu Baerts (NGI0) return PTR_ERR(ssk); 6668617e85eSMatthieu Baerts (NGI0) 6678617e85eSMatthieu Baerts (NGI0) mptcp_info2sockaddr(&entry->addr, &addr, entry->addr.family); 6688617e85eSMatthieu Baerts (NGI0) #if IS_ENABLED(CONFIG_MPTCP_IPV6) 6698617e85eSMatthieu Baerts (NGI0) if (entry->addr.family == AF_INET6) 6708617e85eSMatthieu Baerts (NGI0) addrlen = sizeof(struct sockaddr_in6); 6718617e85eSMatthieu Baerts (NGI0) #endif 6728617e85eSMatthieu Baerts (NGI0) if (ssk->sk_family == AF_INET) 6738617e85eSMatthieu Baerts (NGI0) err = inet_bind_sk(ssk, (struct sockaddr *)&addr, addrlen); 6748617e85eSMatthieu Baerts (NGI0) #if IS_ENABLED(CONFIG_MPTCP_IPV6) 6758617e85eSMatthieu Baerts (NGI0) else if (ssk->sk_family == AF_INET6) 6768617e85eSMatthieu Baerts (NGI0) err = inet6_bind_sk(ssk, (struct sockaddr *)&addr, addrlen); 6778617e85eSMatthieu Baerts (NGI0) #endif 6788617e85eSMatthieu Baerts (NGI0) if (err) 6798617e85eSMatthieu Baerts (NGI0) return err; 6808617e85eSMatthieu Baerts (NGI0) 6818617e85eSMatthieu Baerts (NGI0) /* We don't use mptcp_set_state() here because it needs to be called 6828617e85eSMatthieu Baerts (NGI0) * under the msk socket lock. For the moment, that will not bring 6838617e85eSMatthieu Baerts (NGI0) * anything more than only calling inet_sk_state_store(), because the 6848617e85eSMatthieu Baerts (NGI0) * old status is known (TCP_CLOSE). 6858617e85eSMatthieu Baerts (NGI0) */ 6868617e85eSMatthieu Baerts (NGI0) inet_sk_state_store(newsk, TCP_LISTEN); 6878617e85eSMatthieu Baerts (NGI0) lock_sock(ssk); 6888617e85eSMatthieu Baerts (NGI0) WRITE_ONCE(mptcp_subflow_ctx(ssk)->pm_listener, true); 6898617e85eSMatthieu Baerts (NGI0) err = __inet_listen_sk(ssk, backlog); 6908617e85eSMatthieu Baerts (NGI0) if (!err) 6918617e85eSMatthieu Baerts (NGI0) mptcp_event_pm_listener(ssk, MPTCP_EVENT_LISTENER_CREATED); 6928617e85eSMatthieu Baerts (NGI0) release_sock(ssk); 6938617e85eSMatthieu Baerts (NGI0) return err; 6948617e85eSMatthieu Baerts (NGI0) } 6958617e85eSMatthieu Baerts (NGI0) 6968617e85eSMatthieu Baerts (NGI0) int mptcp_pm_nl_get_local_id(struct mptcp_sock *msk, 6978617e85eSMatthieu Baerts (NGI0) struct mptcp_pm_addr_entry *skc) 6988617e85eSMatthieu Baerts (NGI0) { 6998617e85eSMatthieu Baerts (NGI0) struct mptcp_pm_addr_entry *entry; 7008617e85eSMatthieu Baerts (NGI0) struct pm_nl_pernet *pernet; 7018617e85eSMatthieu Baerts (NGI0) int ret; 7028617e85eSMatthieu Baerts (NGI0) 7038617e85eSMatthieu Baerts (NGI0) pernet = pm_nl_get_pernet_from_msk(msk); 7048617e85eSMatthieu Baerts (NGI0) 7058617e85eSMatthieu Baerts (NGI0) rcu_read_lock(); 7068617e85eSMatthieu Baerts (NGI0) entry = __lookup_addr(pernet, &skc->addr); 7078617e85eSMatthieu Baerts (NGI0) ret = entry ? entry->addr.id : -1; 7088617e85eSMatthieu Baerts (NGI0) rcu_read_unlock(); 7098617e85eSMatthieu Baerts (NGI0) if (ret >= 0) 7108617e85eSMatthieu Baerts (NGI0) return ret; 7118617e85eSMatthieu Baerts (NGI0) 7128617e85eSMatthieu Baerts (NGI0) /* address not found, add to local list */ 713*fa123489SGeliang Tang entry = kmemdup(skc, sizeof(*skc), GFP_ATOMIC); 7148617e85eSMatthieu Baerts (NGI0) if (!entry) 7158617e85eSMatthieu Baerts (NGI0) return -ENOMEM; 7168617e85eSMatthieu Baerts (NGI0) 7178617e85eSMatthieu Baerts (NGI0) entry->addr.port = 0; 7188617e85eSMatthieu Baerts (NGI0) ret = mptcp_pm_nl_append_new_local_addr(pernet, entry, true, false); 7198617e85eSMatthieu Baerts (NGI0) if (ret < 0) 7208617e85eSMatthieu Baerts (NGI0) kfree(entry); 7218617e85eSMatthieu Baerts (NGI0) 7228617e85eSMatthieu Baerts (NGI0) return ret; 7238617e85eSMatthieu Baerts (NGI0) } 7248617e85eSMatthieu Baerts (NGI0) 7258617e85eSMatthieu Baerts (NGI0) bool mptcp_pm_nl_is_backup(struct mptcp_sock *msk, struct mptcp_addr_info *skc) 7268617e85eSMatthieu Baerts (NGI0) { 7278617e85eSMatthieu Baerts (NGI0) struct pm_nl_pernet *pernet = pm_nl_get_pernet_from_msk(msk); 7288617e85eSMatthieu Baerts (NGI0) struct mptcp_pm_addr_entry *entry; 7298617e85eSMatthieu Baerts (NGI0) bool backup; 7308617e85eSMatthieu Baerts (NGI0) 7318617e85eSMatthieu Baerts (NGI0) rcu_read_lock(); 7328617e85eSMatthieu Baerts (NGI0) entry = __lookup_addr(pernet, skc); 7338617e85eSMatthieu Baerts (NGI0) backup = entry && !!(entry->flags & MPTCP_PM_ADDR_FLAG_BACKUP); 7348617e85eSMatthieu Baerts (NGI0) rcu_read_unlock(); 7358617e85eSMatthieu Baerts (NGI0) 7368617e85eSMatthieu Baerts (NGI0) return backup; 7378617e85eSMatthieu Baerts (NGI0) } 7388617e85eSMatthieu Baerts (NGI0) 7398617e85eSMatthieu Baerts (NGI0) static int mptcp_nl_add_subflow_or_signal_addr(struct net *net, 7408617e85eSMatthieu Baerts (NGI0) struct mptcp_addr_info *addr) 7418617e85eSMatthieu Baerts (NGI0) { 7428617e85eSMatthieu Baerts (NGI0) struct mptcp_sock *msk; 7438617e85eSMatthieu Baerts (NGI0) long s_slot = 0, s_num = 0; 7448617e85eSMatthieu Baerts (NGI0) 7458617e85eSMatthieu Baerts (NGI0) while ((msk = mptcp_token_iter_next(net, &s_slot, &s_num)) != NULL) { 7468617e85eSMatthieu Baerts (NGI0) struct sock *sk = (struct sock *)msk; 7478617e85eSMatthieu Baerts (NGI0) struct mptcp_addr_info mpc_addr; 7488617e85eSMatthieu Baerts (NGI0) 7498617e85eSMatthieu Baerts (NGI0) if (!READ_ONCE(msk->fully_established) || 7508617e85eSMatthieu Baerts (NGI0) mptcp_pm_is_userspace(msk)) 7518617e85eSMatthieu Baerts (NGI0) goto next; 7528617e85eSMatthieu Baerts (NGI0) 7538617e85eSMatthieu Baerts (NGI0) /* if the endp linked to the init sf is re-added with a != ID */ 7548617e85eSMatthieu Baerts (NGI0) mptcp_local_address((struct sock_common *)msk, &mpc_addr); 7558617e85eSMatthieu Baerts (NGI0) 7568617e85eSMatthieu Baerts (NGI0) lock_sock(sk); 7578617e85eSMatthieu Baerts (NGI0) spin_lock_bh(&msk->pm.lock); 7588617e85eSMatthieu Baerts (NGI0) if (mptcp_addresses_equal(addr, &mpc_addr, addr->port)) 7598617e85eSMatthieu Baerts (NGI0) msk->mpc_endpoint_id = addr->id; 7608617e85eSMatthieu Baerts (NGI0) mptcp_pm_create_subflow_or_signal_addr(msk); 7618617e85eSMatthieu Baerts (NGI0) spin_unlock_bh(&msk->pm.lock); 7628617e85eSMatthieu Baerts (NGI0) release_sock(sk); 7638617e85eSMatthieu Baerts (NGI0) 7648617e85eSMatthieu Baerts (NGI0) next: 7658617e85eSMatthieu Baerts (NGI0) sock_put(sk); 7668617e85eSMatthieu Baerts (NGI0) cond_resched(); 7678617e85eSMatthieu Baerts (NGI0) } 7688617e85eSMatthieu Baerts (NGI0) 7698617e85eSMatthieu Baerts (NGI0) return 0; 7708617e85eSMatthieu Baerts (NGI0) } 7718617e85eSMatthieu Baerts (NGI0) 7728617e85eSMatthieu Baerts (NGI0) static bool mptcp_pm_has_addr_attr_id(const struct nlattr *attr, 7738617e85eSMatthieu Baerts (NGI0) struct genl_info *info) 7748617e85eSMatthieu Baerts (NGI0) { 7758617e85eSMatthieu Baerts (NGI0) struct nlattr *tb[MPTCP_PM_ADDR_ATTR_MAX + 1]; 7768617e85eSMatthieu Baerts (NGI0) 7778617e85eSMatthieu Baerts (NGI0) if (!nla_parse_nested_deprecated(tb, MPTCP_PM_ADDR_ATTR_MAX, attr, 7788617e85eSMatthieu Baerts (NGI0) mptcp_pm_address_nl_policy, info->extack) && 7798617e85eSMatthieu Baerts (NGI0) tb[MPTCP_PM_ADDR_ATTR_ID]) 7808617e85eSMatthieu Baerts (NGI0) return true; 7818617e85eSMatthieu Baerts (NGI0) return false; 7828617e85eSMatthieu Baerts (NGI0) } 7838617e85eSMatthieu Baerts (NGI0) 7848617e85eSMatthieu Baerts (NGI0) /* Add an MPTCP endpoint */ 7858617e85eSMatthieu Baerts (NGI0) int mptcp_pm_nl_add_addr_doit(struct sk_buff *skb, struct genl_info *info) 7868617e85eSMatthieu Baerts (NGI0) { 7878617e85eSMatthieu Baerts (NGI0) struct pm_nl_pernet *pernet = genl_info_pm_nl(info); 7888617e85eSMatthieu Baerts (NGI0) struct mptcp_pm_addr_entry addr, *entry; 7898617e85eSMatthieu Baerts (NGI0) struct nlattr *attr; 7908617e85eSMatthieu Baerts (NGI0) int ret; 7918617e85eSMatthieu Baerts (NGI0) 7928617e85eSMatthieu Baerts (NGI0) if (GENL_REQ_ATTR_CHECK(info, MPTCP_PM_ENDPOINT_ADDR)) 7938617e85eSMatthieu Baerts (NGI0) return -EINVAL; 7948617e85eSMatthieu Baerts (NGI0) 7958617e85eSMatthieu Baerts (NGI0) attr = info->attrs[MPTCP_PM_ENDPOINT_ADDR]; 7968617e85eSMatthieu Baerts (NGI0) ret = mptcp_pm_parse_entry(attr, info, true, &addr); 7978617e85eSMatthieu Baerts (NGI0) if (ret < 0) 7988617e85eSMatthieu Baerts (NGI0) return ret; 7998617e85eSMatthieu Baerts (NGI0) 8008617e85eSMatthieu Baerts (NGI0) if (addr.addr.port && !address_use_port(&addr)) { 8018617e85eSMatthieu Baerts (NGI0) NL_SET_ERR_MSG_ATTR(info->extack, attr, 8028617e85eSMatthieu Baerts (NGI0) "flags must have signal and not subflow when using port"); 8038617e85eSMatthieu Baerts (NGI0) return -EINVAL; 8048617e85eSMatthieu Baerts (NGI0) } 8058617e85eSMatthieu Baerts (NGI0) 8068617e85eSMatthieu Baerts (NGI0) if (addr.flags & MPTCP_PM_ADDR_FLAG_SIGNAL && 8078617e85eSMatthieu Baerts (NGI0) addr.flags & MPTCP_PM_ADDR_FLAG_FULLMESH) { 8088617e85eSMatthieu Baerts (NGI0) NL_SET_ERR_MSG_ATTR(info->extack, attr, 8098617e85eSMatthieu Baerts (NGI0) "flags mustn't have both signal and fullmesh"); 8108617e85eSMatthieu Baerts (NGI0) return -EINVAL; 8118617e85eSMatthieu Baerts (NGI0) } 8128617e85eSMatthieu Baerts (NGI0) 8138617e85eSMatthieu Baerts (NGI0) if (addr.flags & MPTCP_PM_ADDR_FLAG_IMPLICIT) { 8148617e85eSMatthieu Baerts (NGI0) NL_SET_ERR_MSG_ATTR(info->extack, attr, 8158617e85eSMatthieu Baerts (NGI0) "can't create IMPLICIT endpoint"); 8168617e85eSMatthieu Baerts (NGI0) return -EINVAL; 8178617e85eSMatthieu Baerts (NGI0) } 8188617e85eSMatthieu Baerts (NGI0) 819*fa123489SGeliang Tang entry = kmemdup(&addr, sizeof(addr), GFP_KERNEL_ACCOUNT); 8208617e85eSMatthieu Baerts (NGI0) if (!entry) { 8218617e85eSMatthieu Baerts (NGI0) GENL_SET_ERR_MSG(info, "can't allocate addr"); 8228617e85eSMatthieu Baerts (NGI0) return -ENOMEM; 8238617e85eSMatthieu Baerts (NGI0) } 8248617e85eSMatthieu Baerts (NGI0) 8258617e85eSMatthieu Baerts (NGI0) if (entry->addr.port) { 8268617e85eSMatthieu Baerts (NGI0) ret = mptcp_pm_nl_create_listen_socket(skb->sk, entry); 8278617e85eSMatthieu Baerts (NGI0) if (ret) { 8288617e85eSMatthieu Baerts (NGI0) GENL_SET_ERR_MSG_FMT(info, "create listen socket error: %d", ret); 8298617e85eSMatthieu Baerts (NGI0) goto out_free; 8308617e85eSMatthieu Baerts (NGI0) } 8318617e85eSMatthieu Baerts (NGI0) } 8328617e85eSMatthieu Baerts (NGI0) ret = mptcp_pm_nl_append_new_local_addr(pernet, entry, 8338617e85eSMatthieu Baerts (NGI0) !mptcp_pm_has_addr_attr_id(attr, info), 8348617e85eSMatthieu Baerts (NGI0) true); 8358617e85eSMatthieu Baerts (NGI0) if (ret < 0) { 8368617e85eSMatthieu Baerts (NGI0) GENL_SET_ERR_MSG_FMT(info, "too many addresses or duplicate one: %d", ret); 8378617e85eSMatthieu Baerts (NGI0) goto out_free; 8388617e85eSMatthieu Baerts (NGI0) } 8398617e85eSMatthieu Baerts (NGI0) 8408617e85eSMatthieu Baerts (NGI0) mptcp_nl_add_subflow_or_signal_addr(sock_net(skb->sk), &entry->addr); 8418617e85eSMatthieu Baerts (NGI0) return 0; 8428617e85eSMatthieu Baerts (NGI0) 8438617e85eSMatthieu Baerts (NGI0) out_free: 8448617e85eSMatthieu Baerts (NGI0) __mptcp_pm_release_addr_entry(entry); 8458617e85eSMatthieu Baerts (NGI0) return ret; 8468617e85eSMatthieu Baerts (NGI0) } 8478617e85eSMatthieu Baerts (NGI0) 8488617e85eSMatthieu Baerts (NGI0) static u8 mptcp_endp_get_local_id(struct mptcp_sock *msk, 8498617e85eSMatthieu Baerts (NGI0) const struct mptcp_addr_info *addr) 8508617e85eSMatthieu Baerts (NGI0) { 8518617e85eSMatthieu Baerts (NGI0) return msk->mpc_endpoint_id == addr->id ? 0 : addr->id; 8528617e85eSMatthieu Baerts (NGI0) } 8538617e85eSMatthieu Baerts (NGI0) 8548617e85eSMatthieu Baerts (NGI0) static bool mptcp_pm_remove_anno_addr(struct mptcp_sock *msk, 8558617e85eSMatthieu Baerts (NGI0) const struct mptcp_addr_info *addr, 8568617e85eSMatthieu Baerts (NGI0) bool force) 8578617e85eSMatthieu Baerts (NGI0) { 8588617e85eSMatthieu Baerts (NGI0) struct mptcp_rm_list list = { .nr = 0 }; 8598617e85eSMatthieu Baerts (NGI0) bool ret; 8608617e85eSMatthieu Baerts (NGI0) 8618617e85eSMatthieu Baerts (NGI0) list.ids[list.nr++] = mptcp_endp_get_local_id(msk, addr); 8628617e85eSMatthieu Baerts (NGI0) 8638617e85eSMatthieu Baerts (NGI0) ret = mptcp_remove_anno_list_by_saddr(msk, addr); 8648617e85eSMatthieu Baerts (NGI0) if (ret || force) { 8658617e85eSMatthieu Baerts (NGI0) spin_lock_bh(&msk->pm.lock); 8668617e85eSMatthieu Baerts (NGI0) if (ret) { 8678617e85eSMatthieu Baerts (NGI0) __set_bit(addr->id, msk->pm.id_avail_bitmap); 8688617e85eSMatthieu Baerts (NGI0) msk->pm.add_addr_signaled--; 8698617e85eSMatthieu Baerts (NGI0) } 8708617e85eSMatthieu Baerts (NGI0) mptcp_pm_remove_addr(msk, &list); 8718617e85eSMatthieu Baerts (NGI0) spin_unlock_bh(&msk->pm.lock); 8728617e85eSMatthieu Baerts (NGI0) } 8738617e85eSMatthieu Baerts (NGI0) return ret; 8748617e85eSMatthieu Baerts (NGI0) } 8758617e85eSMatthieu Baerts (NGI0) 8768617e85eSMatthieu Baerts (NGI0) static void __mark_subflow_endp_available(struct mptcp_sock *msk, u8 id) 8778617e85eSMatthieu Baerts (NGI0) { 8788617e85eSMatthieu Baerts (NGI0) /* If it was marked as used, and not ID 0, decrement local_addr_used */ 8798617e85eSMatthieu Baerts (NGI0) if (!__test_and_set_bit(id ? : msk->mpc_endpoint_id, msk->pm.id_avail_bitmap) && 8808617e85eSMatthieu Baerts (NGI0) id && !WARN_ON_ONCE(msk->pm.local_addr_used == 0)) 8818617e85eSMatthieu Baerts (NGI0) msk->pm.local_addr_used--; 8828617e85eSMatthieu Baerts (NGI0) } 8838617e85eSMatthieu Baerts (NGI0) 8848617e85eSMatthieu Baerts (NGI0) static int mptcp_nl_remove_subflow_and_signal_addr(struct net *net, 8858617e85eSMatthieu Baerts (NGI0) const struct mptcp_pm_addr_entry *entry) 8868617e85eSMatthieu Baerts (NGI0) { 8878617e85eSMatthieu Baerts (NGI0) const struct mptcp_addr_info *addr = &entry->addr; 8888617e85eSMatthieu Baerts (NGI0) struct mptcp_rm_list list = { .nr = 1 }; 8898617e85eSMatthieu Baerts (NGI0) long s_slot = 0, s_num = 0; 8908617e85eSMatthieu Baerts (NGI0) struct mptcp_sock *msk; 8918617e85eSMatthieu Baerts (NGI0) 8928617e85eSMatthieu Baerts (NGI0) pr_debug("remove_id=%d\n", addr->id); 8938617e85eSMatthieu Baerts (NGI0) 8948617e85eSMatthieu Baerts (NGI0) while ((msk = mptcp_token_iter_next(net, &s_slot, &s_num)) != NULL) { 8958617e85eSMatthieu Baerts (NGI0) struct sock *sk = (struct sock *)msk; 8968617e85eSMatthieu Baerts (NGI0) bool remove_subflow; 8978617e85eSMatthieu Baerts (NGI0) 8988617e85eSMatthieu Baerts (NGI0) if (mptcp_pm_is_userspace(msk)) 8998617e85eSMatthieu Baerts (NGI0) goto next; 9008617e85eSMatthieu Baerts (NGI0) 9018617e85eSMatthieu Baerts (NGI0) lock_sock(sk); 9028617e85eSMatthieu Baerts (NGI0) remove_subflow = mptcp_lookup_subflow_by_saddr(&msk->conn_list, addr); 9038617e85eSMatthieu Baerts (NGI0) mptcp_pm_remove_anno_addr(msk, addr, remove_subflow && 9048617e85eSMatthieu Baerts (NGI0) !(entry->flags & MPTCP_PM_ADDR_FLAG_IMPLICIT)); 9058617e85eSMatthieu Baerts (NGI0) 9068617e85eSMatthieu Baerts (NGI0) list.ids[0] = mptcp_endp_get_local_id(msk, addr); 9078617e85eSMatthieu Baerts (NGI0) if (remove_subflow) { 9088617e85eSMatthieu Baerts (NGI0) spin_lock_bh(&msk->pm.lock); 9098617e85eSMatthieu Baerts (NGI0) mptcp_pm_rm_subflow(msk, &list); 9108617e85eSMatthieu Baerts (NGI0) spin_unlock_bh(&msk->pm.lock); 9118617e85eSMatthieu Baerts (NGI0) } 9128617e85eSMatthieu Baerts (NGI0) 9138617e85eSMatthieu Baerts (NGI0) if (entry->flags & MPTCP_PM_ADDR_FLAG_SUBFLOW) { 9148617e85eSMatthieu Baerts (NGI0) spin_lock_bh(&msk->pm.lock); 9158617e85eSMatthieu Baerts (NGI0) __mark_subflow_endp_available(msk, list.ids[0]); 9168617e85eSMatthieu Baerts (NGI0) spin_unlock_bh(&msk->pm.lock); 9178617e85eSMatthieu Baerts (NGI0) } 9188617e85eSMatthieu Baerts (NGI0) 9198617e85eSMatthieu Baerts (NGI0) if (msk->mpc_endpoint_id == entry->addr.id) 9208617e85eSMatthieu Baerts (NGI0) msk->mpc_endpoint_id = 0; 9218617e85eSMatthieu Baerts (NGI0) release_sock(sk); 9228617e85eSMatthieu Baerts (NGI0) 9238617e85eSMatthieu Baerts (NGI0) next: 9248617e85eSMatthieu Baerts (NGI0) sock_put(sk); 9258617e85eSMatthieu Baerts (NGI0) cond_resched(); 9268617e85eSMatthieu Baerts (NGI0) } 9278617e85eSMatthieu Baerts (NGI0) 9288617e85eSMatthieu Baerts (NGI0) return 0; 9298617e85eSMatthieu Baerts (NGI0) } 9308617e85eSMatthieu Baerts (NGI0) 9318617e85eSMatthieu Baerts (NGI0) static int mptcp_nl_remove_id_zero_address(struct net *net, 9328617e85eSMatthieu Baerts (NGI0) struct mptcp_addr_info *addr) 9338617e85eSMatthieu Baerts (NGI0) { 9348617e85eSMatthieu Baerts (NGI0) struct mptcp_rm_list list = { .nr = 0 }; 9358617e85eSMatthieu Baerts (NGI0) long s_slot = 0, s_num = 0; 9368617e85eSMatthieu Baerts (NGI0) struct mptcp_sock *msk; 9378617e85eSMatthieu Baerts (NGI0) 9388617e85eSMatthieu Baerts (NGI0) list.ids[list.nr++] = 0; 9398617e85eSMatthieu Baerts (NGI0) 9408617e85eSMatthieu Baerts (NGI0) while ((msk = mptcp_token_iter_next(net, &s_slot, &s_num)) != NULL) { 9418617e85eSMatthieu Baerts (NGI0) struct sock *sk = (struct sock *)msk; 9428617e85eSMatthieu Baerts (NGI0) struct mptcp_addr_info msk_local; 9438617e85eSMatthieu Baerts (NGI0) 9448617e85eSMatthieu Baerts (NGI0) if (list_empty(&msk->conn_list) || mptcp_pm_is_userspace(msk)) 9458617e85eSMatthieu Baerts (NGI0) goto next; 9468617e85eSMatthieu Baerts (NGI0) 9478617e85eSMatthieu Baerts (NGI0) mptcp_local_address((struct sock_common *)msk, &msk_local); 9488617e85eSMatthieu Baerts (NGI0) if (!mptcp_addresses_equal(&msk_local, addr, addr->port)) 9498617e85eSMatthieu Baerts (NGI0) goto next; 9508617e85eSMatthieu Baerts (NGI0) 9518617e85eSMatthieu Baerts (NGI0) lock_sock(sk); 9528617e85eSMatthieu Baerts (NGI0) spin_lock_bh(&msk->pm.lock); 9538617e85eSMatthieu Baerts (NGI0) mptcp_pm_remove_addr(msk, &list); 9548617e85eSMatthieu Baerts (NGI0) mptcp_pm_rm_subflow(msk, &list); 9558617e85eSMatthieu Baerts (NGI0) __mark_subflow_endp_available(msk, 0); 9568617e85eSMatthieu Baerts (NGI0) spin_unlock_bh(&msk->pm.lock); 9578617e85eSMatthieu Baerts (NGI0) release_sock(sk); 9588617e85eSMatthieu Baerts (NGI0) 9598617e85eSMatthieu Baerts (NGI0) next: 9608617e85eSMatthieu Baerts (NGI0) sock_put(sk); 9618617e85eSMatthieu Baerts (NGI0) cond_resched(); 9628617e85eSMatthieu Baerts (NGI0) } 9638617e85eSMatthieu Baerts (NGI0) 9648617e85eSMatthieu Baerts (NGI0) return 0; 9658617e85eSMatthieu Baerts (NGI0) } 9668617e85eSMatthieu Baerts (NGI0) 9678617e85eSMatthieu Baerts (NGI0) /* Remove an MPTCP endpoint */ 9688617e85eSMatthieu Baerts (NGI0) int mptcp_pm_nl_del_addr_doit(struct sk_buff *skb, struct genl_info *info) 9698617e85eSMatthieu Baerts (NGI0) { 9708617e85eSMatthieu Baerts (NGI0) struct pm_nl_pernet *pernet = genl_info_pm_nl(info); 9718617e85eSMatthieu Baerts (NGI0) struct mptcp_pm_addr_entry addr, *entry; 9728617e85eSMatthieu Baerts (NGI0) unsigned int addr_max; 9738617e85eSMatthieu Baerts (NGI0) struct nlattr *attr; 9748617e85eSMatthieu Baerts (NGI0) int ret; 9758617e85eSMatthieu Baerts (NGI0) 9768617e85eSMatthieu Baerts (NGI0) if (GENL_REQ_ATTR_CHECK(info, MPTCP_PM_ENDPOINT_ADDR)) 9778617e85eSMatthieu Baerts (NGI0) return -EINVAL; 9788617e85eSMatthieu Baerts (NGI0) 9798617e85eSMatthieu Baerts (NGI0) attr = info->attrs[MPTCP_PM_ENDPOINT_ADDR]; 9808617e85eSMatthieu Baerts (NGI0) ret = mptcp_pm_parse_entry(attr, info, false, &addr); 9818617e85eSMatthieu Baerts (NGI0) if (ret < 0) 9828617e85eSMatthieu Baerts (NGI0) return ret; 9838617e85eSMatthieu Baerts (NGI0) 9848617e85eSMatthieu Baerts (NGI0) /* the zero id address is special: the first address used by the msk 9858617e85eSMatthieu Baerts (NGI0) * always gets such an id, so different subflows can have different zero 9868617e85eSMatthieu Baerts (NGI0) * id addresses. Additionally zero id is not accounted for in id_bitmap. 9878617e85eSMatthieu Baerts (NGI0) * Let's use an 'mptcp_rm_list' instead of the common remove code. 9888617e85eSMatthieu Baerts (NGI0) */ 9898617e85eSMatthieu Baerts (NGI0) if (addr.addr.id == 0) 9908617e85eSMatthieu Baerts (NGI0) return mptcp_nl_remove_id_zero_address(sock_net(skb->sk), &addr.addr); 9918617e85eSMatthieu Baerts (NGI0) 9928617e85eSMatthieu Baerts (NGI0) spin_lock_bh(&pernet->lock); 9938617e85eSMatthieu Baerts (NGI0) entry = __lookup_addr_by_id(pernet, addr.addr.id); 9948617e85eSMatthieu Baerts (NGI0) if (!entry) { 9958617e85eSMatthieu Baerts (NGI0) NL_SET_ERR_MSG_ATTR(info->extack, attr, "address not found"); 9968617e85eSMatthieu Baerts (NGI0) spin_unlock_bh(&pernet->lock); 9978617e85eSMatthieu Baerts (NGI0) return -EINVAL; 9988617e85eSMatthieu Baerts (NGI0) } 9998617e85eSMatthieu Baerts (NGI0) if (entry->flags & MPTCP_PM_ADDR_FLAG_SIGNAL) { 10008617e85eSMatthieu Baerts (NGI0) addr_max = pernet->add_addr_signal_max; 10018617e85eSMatthieu Baerts (NGI0) WRITE_ONCE(pernet->add_addr_signal_max, addr_max - 1); 10028617e85eSMatthieu Baerts (NGI0) } 10038617e85eSMatthieu Baerts (NGI0) if (entry->flags & MPTCP_PM_ADDR_FLAG_SUBFLOW) { 10048617e85eSMatthieu Baerts (NGI0) addr_max = pernet->local_addr_max; 10058617e85eSMatthieu Baerts (NGI0) WRITE_ONCE(pernet->local_addr_max, addr_max - 1); 10068617e85eSMatthieu Baerts (NGI0) } 10078617e85eSMatthieu Baerts (NGI0) 10088617e85eSMatthieu Baerts (NGI0) pernet->addrs--; 10098617e85eSMatthieu Baerts (NGI0) list_del_rcu(&entry->list); 10108617e85eSMatthieu Baerts (NGI0) __clear_bit(entry->addr.id, pernet->id_bitmap); 10118617e85eSMatthieu Baerts (NGI0) spin_unlock_bh(&pernet->lock); 10128617e85eSMatthieu Baerts (NGI0) 10138617e85eSMatthieu Baerts (NGI0) mptcp_nl_remove_subflow_and_signal_addr(sock_net(skb->sk), entry); 10148617e85eSMatthieu Baerts (NGI0) synchronize_rcu(); 10158617e85eSMatthieu Baerts (NGI0) __mptcp_pm_release_addr_entry(entry); 10168617e85eSMatthieu Baerts (NGI0) 10178617e85eSMatthieu Baerts (NGI0) return ret; 10188617e85eSMatthieu Baerts (NGI0) } 10198617e85eSMatthieu Baerts (NGI0) 10208617e85eSMatthieu Baerts (NGI0) static void mptcp_pm_flush_addrs_and_subflows(struct mptcp_sock *msk, 10218617e85eSMatthieu Baerts (NGI0) struct list_head *rm_list) 10228617e85eSMatthieu Baerts (NGI0) { 10238617e85eSMatthieu Baerts (NGI0) struct mptcp_rm_list alist = { .nr = 0 }, slist = { .nr = 0 }; 10248617e85eSMatthieu Baerts (NGI0) struct mptcp_pm_addr_entry *entry; 10258617e85eSMatthieu Baerts (NGI0) 10268617e85eSMatthieu Baerts (NGI0) list_for_each_entry(entry, rm_list, list) { 10278617e85eSMatthieu Baerts (NGI0) if (slist.nr < MPTCP_RM_IDS_MAX && 10288617e85eSMatthieu Baerts (NGI0) mptcp_lookup_subflow_by_saddr(&msk->conn_list, &entry->addr)) 10298617e85eSMatthieu Baerts (NGI0) slist.ids[slist.nr++] = mptcp_endp_get_local_id(msk, &entry->addr); 10308617e85eSMatthieu Baerts (NGI0) 10318617e85eSMatthieu Baerts (NGI0) if (alist.nr < MPTCP_RM_IDS_MAX && 10328617e85eSMatthieu Baerts (NGI0) mptcp_remove_anno_list_by_saddr(msk, &entry->addr)) 10338617e85eSMatthieu Baerts (NGI0) alist.ids[alist.nr++] = mptcp_endp_get_local_id(msk, &entry->addr); 10348617e85eSMatthieu Baerts (NGI0) } 10358617e85eSMatthieu Baerts (NGI0) 10368617e85eSMatthieu Baerts (NGI0) spin_lock_bh(&msk->pm.lock); 10378617e85eSMatthieu Baerts (NGI0) if (alist.nr) { 10388617e85eSMatthieu Baerts (NGI0) msk->pm.add_addr_signaled -= alist.nr; 10398617e85eSMatthieu Baerts (NGI0) mptcp_pm_remove_addr(msk, &alist); 10408617e85eSMatthieu Baerts (NGI0) } 10418617e85eSMatthieu Baerts (NGI0) if (slist.nr) 10428617e85eSMatthieu Baerts (NGI0) mptcp_pm_rm_subflow(msk, &slist); 10438617e85eSMatthieu Baerts (NGI0) /* Reset counters: maybe some subflows have been removed before */ 10448617e85eSMatthieu Baerts (NGI0) bitmap_fill(msk->pm.id_avail_bitmap, MPTCP_PM_MAX_ADDR_ID + 1); 10458617e85eSMatthieu Baerts (NGI0) msk->pm.local_addr_used = 0; 10468617e85eSMatthieu Baerts (NGI0) spin_unlock_bh(&msk->pm.lock); 10478617e85eSMatthieu Baerts (NGI0) } 10488617e85eSMatthieu Baerts (NGI0) 10498617e85eSMatthieu Baerts (NGI0) static void mptcp_nl_flush_addrs_list(struct net *net, 10508617e85eSMatthieu Baerts (NGI0) struct list_head *rm_list) 10518617e85eSMatthieu Baerts (NGI0) { 10528617e85eSMatthieu Baerts (NGI0) long s_slot = 0, s_num = 0; 10538617e85eSMatthieu Baerts (NGI0) struct mptcp_sock *msk; 10548617e85eSMatthieu Baerts (NGI0) 10558617e85eSMatthieu Baerts (NGI0) if (list_empty(rm_list)) 10568617e85eSMatthieu Baerts (NGI0) return; 10578617e85eSMatthieu Baerts (NGI0) 10588617e85eSMatthieu Baerts (NGI0) while ((msk = mptcp_token_iter_next(net, &s_slot, &s_num)) != NULL) { 10598617e85eSMatthieu Baerts (NGI0) struct sock *sk = (struct sock *)msk; 10608617e85eSMatthieu Baerts (NGI0) 10618617e85eSMatthieu Baerts (NGI0) if (!mptcp_pm_is_userspace(msk)) { 10628617e85eSMatthieu Baerts (NGI0) lock_sock(sk); 10638617e85eSMatthieu Baerts (NGI0) mptcp_pm_flush_addrs_and_subflows(msk, rm_list); 10648617e85eSMatthieu Baerts (NGI0) release_sock(sk); 10658617e85eSMatthieu Baerts (NGI0) } 10668617e85eSMatthieu Baerts (NGI0) 10678617e85eSMatthieu Baerts (NGI0) sock_put(sk); 10688617e85eSMatthieu Baerts (NGI0) cond_resched(); 10698617e85eSMatthieu Baerts (NGI0) } 10708617e85eSMatthieu Baerts (NGI0) } 10718617e85eSMatthieu Baerts (NGI0) 10728617e85eSMatthieu Baerts (NGI0) /* caller must ensure the RCU grace period is already elapsed */ 10738617e85eSMatthieu Baerts (NGI0) static void __flush_addrs(struct list_head *list) 10748617e85eSMatthieu Baerts (NGI0) { 10758617e85eSMatthieu Baerts (NGI0) while (!list_empty(list)) { 10768617e85eSMatthieu Baerts (NGI0) struct mptcp_pm_addr_entry *cur; 10778617e85eSMatthieu Baerts (NGI0) 10788617e85eSMatthieu Baerts (NGI0) cur = list_entry(list->next, 10798617e85eSMatthieu Baerts (NGI0) struct mptcp_pm_addr_entry, list); 10808617e85eSMatthieu Baerts (NGI0) list_del_rcu(&cur->list); 10818617e85eSMatthieu Baerts (NGI0) __mptcp_pm_release_addr_entry(cur); 10828617e85eSMatthieu Baerts (NGI0) } 10838617e85eSMatthieu Baerts (NGI0) } 10848617e85eSMatthieu Baerts (NGI0) 10858617e85eSMatthieu Baerts (NGI0) static void __reset_counters(struct pm_nl_pernet *pernet) 10868617e85eSMatthieu Baerts (NGI0) { 10878617e85eSMatthieu Baerts (NGI0) WRITE_ONCE(pernet->add_addr_signal_max, 0); 10888617e85eSMatthieu Baerts (NGI0) WRITE_ONCE(pernet->add_addr_accept_max, 0); 10898617e85eSMatthieu Baerts (NGI0) WRITE_ONCE(pernet->local_addr_max, 0); 10908617e85eSMatthieu Baerts (NGI0) pernet->addrs = 0; 10918617e85eSMatthieu Baerts (NGI0) } 10928617e85eSMatthieu Baerts (NGI0) 10938617e85eSMatthieu Baerts (NGI0) int mptcp_pm_nl_flush_addrs_doit(struct sk_buff *skb, struct genl_info *info) 10948617e85eSMatthieu Baerts (NGI0) { 10958617e85eSMatthieu Baerts (NGI0) struct pm_nl_pernet *pernet = genl_info_pm_nl(info); 10968617e85eSMatthieu Baerts (NGI0) LIST_HEAD(free_list); 10978617e85eSMatthieu Baerts (NGI0) 10988617e85eSMatthieu Baerts (NGI0) spin_lock_bh(&pernet->lock); 10998617e85eSMatthieu Baerts (NGI0) list_splice_init(&pernet->local_addr_list, &free_list); 11008617e85eSMatthieu Baerts (NGI0) __reset_counters(pernet); 11018617e85eSMatthieu Baerts (NGI0) pernet->next_id = 1; 11028617e85eSMatthieu Baerts (NGI0) bitmap_zero(pernet->id_bitmap, MPTCP_PM_MAX_ADDR_ID + 1); 11038617e85eSMatthieu Baerts (NGI0) spin_unlock_bh(&pernet->lock); 11048617e85eSMatthieu Baerts (NGI0) mptcp_nl_flush_addrs_list(sock_net(skb->sk), &free_list); 11058617e85eSMatthieu Baerts (NGI0) synchronize_rcu(); 11068617e85eSMatthieu Baerts (NGI0) __flush_addrs(&free_list); 11078617e85eSMatthieu Baerts (NGI0) return 0; 11088617e85eSMatthieu Baerts (NGI0) } 11098617e85eSMatthieu Baerts (NGI0) 11108617e85eSMatthieu Baerts (NGI0) int mptcp_pm_nl_get_addr(u8 id, struct mptcp_pm_addr_entry *addr, 11118617e85eSMatthieu Baerts (NGI0) struct genl_info *info) 11128617e85eSMatthieu Baerts (NGI0) { 11138617e85eSMatthieu Baerts (NGI0) struct pm_nl_pernet *pernet = genl_info_pm_nl(info); 11148617e85eSMatthieu Baerts (NGI0) struct mptcp_pm_addr_entry *entry; 11158617e85eSMatthieu Baerts (NGI0) int ret = -EINVAL; 11168617e85eSMatthieu Baerts (NGI0) 11178617e85eSMatthieu Baerts (NGI0) rcu_read_lock(); 11188617e85eSMatthieu Baerts (NGI0) entry = __lookup_addr_by_id(pernet, id); 11198617e85eSMatthieu Baerts (NGI0) if (entry) { 11208617e85eSMatthieu Baerts (NGI0) *addr = *entry; 11218617e85eSMatthieu Baerts (NGI0) ret = 0; 11228617e85eSMatthieu Baerts (NGI0) } 11238617e85eSMatthieu Baerts (NGI0) rcu_read_unlock(); 11248617e85eSMatthieu Baerts (NGI0) 11258617e85eSMatthieu Baerts (NGI0) return ret; 11268617e85eSMatthieu Baerts (NGI0) } 11278617e85eSMatthieu Baerts (NGI0) 11288617e85eSMatthieu Baerts (NGI0) int mptcp_pm_nl_dump_addr(struct sk_buff *msg, 11298617e85eSMatthieu Baerts (NGI0) struct netlink_callback *cb) 11308617e85eSMatthieu Baerts (NGI0) { 11318617e85eSMatthieu Baerts (NGI0) struct net *net = sock_net(msg->sk); 11328617e85eSMatthieu Baerts (NGI0) struct mptcp_pm_addr_entry *entry; 11338617e85eSMatthieu Baerts (NGI0) struct pm_nl_pernet *pernet; 11348617e85eSMatthieu Baerts (NGI0) int id = cb->args[0]; 11358617e85eSMatthieu Baerts (NGI0) int i; 11368617e85eSMatthieu Baerts (NGI0) 11378617e85eSMatthieu Baerts (NGI0) pernet = pm_nl_get_pernet(net); 11388617e85eSMatthieu Baerts (NGI0) 11398617e85eSMatthieu Baerts (NGI0) rcu_read_lock(); 11408617e85eSMatthieu Baerts (NGI0) for (i = id; i < MPTCP_PM_MAX_ADDR_ID + 1; i++) { 11418617e85eSMatthieu Baerts (NGI0) if (test_bit(i, pernet->id_bitmap)) { 11428617e85eSMatthieu Baerts (NGI0) entry = __lookup_addr_by_id(pernet, i); 11438617e85eSMatthieu Baerts (NGI0) if (!entry) 11448617e85eSMatthieu Baerts (NGI0) break; 11458617e85eSMatthieu Baerts (NGI0) 11468617e85eSMatthieu Baerts (NGI0) if (entry->addr.id <= id) 11478617e85eSMatthieu Baerts (NGI0) continue; 11488617e85eSMatthieu Baerts (NGI0) 11498617e85eSMatthieu Baerts (NGI0) if (mptcp_pm_genl_fill_addr(msg, cb, entry) < 0) 11508617e85eSMatthieu Baerts (NGI0) break; 11518617e85eSMatthieu Baerts (NGI0) 11528617e85eSMatthieu Baerts (NGI0) id = entry->addr.id; 11538617e85eSMatthieu Baerts (NGI0) } 11548617e85eSMatthieu Baerts (NGI0) } 11558617e85eSMatthieu Baerts (NGI0) rcu_read_unlock(); 11568617e85eSMatthieu Baerts (NGI0) 11578617e85eSMatthieu Baerts (NGI0) cb->args[0] = id; 11588617e85eSMatthieu Baerts (NGI0) return msg->len; 11598617e85eSMatthieu Baerts (NGI0) } 11608617e85eSMatthieu Baerts (NGI0) 11618617e85eSMatthieu Baerts (NGI0) static int parse_limit(struct genl_info *info, int id, unsigned int *limit) 11628617e85eSMatthieu Baerts (NGI0) { 11638617e85eSMatthieu Baerts (NGI0) struct nlattr *attr = info->attrs[id]; 11648617e85eSMatthieu Baerts (NGI0) 11658617e85eSMatthieu Baerts (NGI0) if (!attr) 11668617e85eSMatthieu Baerts (NGI0) return 0; 11678617e85eSMatthieu Baerts (NGI0) 11688617e85eSMatthieu Baerts (NGI0) *limit = nla_get_u32(attr); 11698617e85eSMatthieu Baerts (NGI0) if (*limit > MPTCP_PM_ADDR_MAX) { 11708617e85eSMatthieu Baerts (NGI0) NL_SET_ERR_MSG_ATTR_FMT(info->extack, attr, 11718617e85eSMatthieu Baerts (NGI0) "limit greater than maximum (%u)", 11728617e85eSMatthieu Baerts (NGI0) MPTCP_PM_ADDR_MAX); 11738617e85eSMatthieu Baerts (NGI0) return -EINVAL; 11748617e85eSMatthieu Baerts (NGI0) } 11758617e85eSMatthieu Baerts (NGI0) return 0; 11768617e85eSMatthieu Baerts (NGI0) } 11778617e85eSMatthieu Baerts (NGI0) 11788617e85eSMatthieu Baerts (NGI0) int mptcp_pm_nl_set_limits_doit(struct sk_buff *skb, struct genl_info *info) 11798617e85eSMatthieu Baerts (NGI0) { 11808617e85eSMatthieu Baerts (NGI0) struct pm_nl_pernet *pernet = genl_info_pm_nl(info); 11818617e85eSMatthieu Baerts (NGI0) unsigned int rcv_addrs, subflows; 11828617e85eSMatthieu Baerts (NGI0) int ret; 11838617e85eSMatthieu Baerts (NGI0) 11848617e85eSMatthieu Baerts (NGI0) spin_lock_bh(&pernet->lock); 11858617e85eSMatthieu Baerts (NGI0) rcv_addrs = pernet->add_addr_accept_max; 11868617e85eSMatthieu Baerts (NGI0) ret = parse_limit(info, MPTCP_PM_ATTR_RCV_ADD_ADDRS, &rcv_addrs); 11878617e85eSMatthieu Baerts (NGI0) if (ret) 11888617e85eSMatthieu Baerts (NGI0) goto unlock; 11898617e85eSMatthieu Baerts (NGI0) 11908617e85eSMatthieu Baerts (NGI0) subflows = pernet->subflows_max; 11918617e85eSMatthieu Baerts (NGI0) ret = parse_limit(info, MPTCP_PM_ATTR_SUBFLOWS, &subflows); 11928617e85eSMatthieu Baerts (NGI0) if (ret) 11938617e85eSMatthieu Baerts (NGI0) goto unlock; 11948617e85eSMatthieu Baerts (NGI0) 11958617e85eSMatthieu Baerts (NGI0) WRITE_ONCE(pernet->add_addr_accept_max, rcv_addrs); 11968617e85eSMatthieu Baerts (NGI0) WRITE_ONCE(pernet->subflows_max, subflows); 11978617e85eSMatthieu Baerts (NGI0) 11988617e85eSMatthieu Baerts (NGI0) unlock: 11998617e85eSMatthieu Baerts (NGI0) spin_unlock_bh(&pernet->lock); 12008617e85eSMatthieu Baerts (NGI0) return ret; 12018617e85eSMatthieu Baerts (NGI0) } 12028617e85eSMatthieu Baerts (NGI0) 12038617e85eSMatthieu Baerts (NGI0) int mptcp_pm_nl_get_limits_doit(struct sk_buff *skb, struct genl_info *info) 12048617e85eSMatthieu Baerts (NGI0) { 12058617e85eSMatthieu Baerts (NGI0) struct pm_nl_pernet *pernet = genl_info_pm_nl(info); 12068617e85eSMatthieu Baerts (NGI0) struct sk_buff *msg; 12078617e85eSMatthieu Baerts (NGI0) void *reply; 12088617e85eSMatthieu Baerts (NGI0) 12098617e85eSMatthieu Baerts (NGI0) msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 12108617e85eSMatthieu Baerts (NGI0) if (!msg) 12118617e85eSMatthieu Baerts (NGI0) return -ENOMEM; 12128617e85eSMatthieu Baerts (NGI0) 12138617e85eSMatthieu Baerts (NGI0) reply = genlmsg_put_reply(msg, info, &mptcp_genl_family, 0, 12148617e85eSMatthieu Baerts (NGI0) MPTCP_PM_CMD_GET_LIMITS); 12158617e85eSMatthieu Baerts (NGI0) if (!reply) 12168617e85eSMatthieu Baerts (NGI0) goto fail; 12178617e85eSMatthieu Baerts (NGI0) 12188617e85eSMatthieu Baerts (NGI0) if (nla_put_u32(msg, MPTCP_PM_ATTR_RCV_ADD_ADDRS, 12198617e85eSMatthieu Baerts (NGI0) READ_ONCE(pernet->add_addr_accept_max))) 12208617e85eSMatthieu Baerts (NGI0) goto fail; 12218617e85eSMatthieu Baerts (NGI0) 12228617e85eSMatthieu Baerts (NGI0) if (nla_put_u32(msg, MPTCP_PM_ATTR_SUBFLOWS, 12238617e85eSMatthieu Baerts (NGI0) READ_ONCE(pernet->subflows_max))) 12248617e85eSMatthieu Baerts (NGI0) goto fail; 12258617e85eSMatthieu Baerts (NGI0) 12268617e85eSMatthieu Baerts (NGI0) genlmsg_end(msg, reply); 12278617e85eSMatthieu Baerts (NGI0) return genlmsg_reply(msg, info); 12288617e85eSMatthieu Baerts (NGI0) 12298617e85eSMatthieu Baerts (NGI0) fail: 12308617e85eSMatthieu Baerts (NGI0) GENL_SET_ERR_MSG(info, "not enough space in Netlink message"); 12318617e85eSMatthieu Baerts (NGI0) nlmsg_free(msg); 12328617e85eSMatthieu Baerts (NGI0) return -EMSGSIZE; 12338617e85eSMatthieu Baerts (NGI0) } 12348617e85eSMatthieu Baerts (NGI0) 12358617e85eSMatthieu Baerts (NGI0) static void mptcp_pm_nl_fullmesh(struct mptcp_sock *msk, 12368617e85eSMatthieu Baerts (NGI0) struct mptcp_addr_info *addr) 12378617e85eSMatthieu Baerts (NGI0) { 12388617e85eSMatthieu Baerts (NGI0) struct mptcp_rm_list list = { .nr = 0 }; 12398617e85eSMatthieu Baerts (NGI0) 12408617e85eSMatthieu Baerts (NGI0) list.ids[list.nr++] = mptcp_endp_get_local_id(msk, addr); 12418617e85eSMatthieu Baerts (NGI0) 12428617e85eSMatthieu Baerts (NGI0) spin_lock_bh(&msk->pm.lock); 12438617e85eSMatthieu Baerts (NGI0) mptcp_pm_rm_subflow(msk, &list); 12448617e85eSMatthieu Baerts (NGI0) __mark_subflow_endp_available(msk, list.ids[0]); 12458617e85eSMatthieu Baerts (NGI0) mptcp_pm_create_subflow_or_signal_addr(msk); 12468617e85eSMatthieu Baerts (NGI0) spin_unlock_bh(&msk->pm.lock); 12478617e85eSMatthieu Baerts (NGI0) } 12488617e85eSMatthieu Baerts (NGI0) 12498617e85eSMatthieu Baerts (NGI0) static void mptcp_pm_nl_set_flags_all(struct net *net, 12508617e85eSMatthieu Baerts (NGI0) struct mptcp_pm_addr_entry *local, 12518617e85eSMatthieu Baerts (NGI0) u8 changed) 12528617e85eSMatthieu Baerts (NGI0) { 12538617e85eSMatthieu Baerts (NGI0) u8 is_subflow = !!(local->flags & MPTCP_PM_ADDR_FLAG_SUBFLOW); 12548617e85eSMatthieu Baerts (NGI0) u8 bkup = !!(local->flags & MPTCP_PM_ADDR_FLAG_BACKUP); 12558617e85eSMatthieu Baerts (NGI0) long s_slot = 0, s_num = 0; 12568617e85eSMatthieu Baerts (NGI0) struct mptcp_sock *msk; 12578617e85eSMatthieu Baerts (NGI0) 12588617e85eSMatthieu Baerts (NGI0) if (changed == MPTCP_PM_ADDR_FLAG_FULLMESH && !is_subflow) 12598617e85eSMatthieu Baerts (NGI0) return; 12608617e85eSMatthieu Baerts (NGI0) 12618617e85eSMatthieu Baerts (NGI0) while ((msk = mptcp_token_iter_next(net, &s_slot, &s_num)) != NULL) { 12628617e85eSMatthieu Baerts (NGI0) struct sock *sk = (struct sock *)msk; 12638617e85eSMatthieu Baerts (NGI0) 12648617e85eSMatthieu Baerts (NGI0) if (list_empty(&msk->conn_list) || mptcp_pm_is_userspace(msk)) 12658617e85eSMatthieu Baerts (NGI0) goto next; 12668617e85eSMatthieu Baerts (NGI0) 12678617e85eSMatthieu Baerts (NGI0) lock_sock(sk); 12688617e85eSMatthieu Baerts (NGI0) if (changed & MPTCP_PM_ADDR_FLAG_BACKUP) 12698617e85eSMatthieu Baerts (NGI0) mptcp_pm_mp_prio_send_ack(msk, &local->addr, NULL, bkup); 12708617e85eSMatthieu Baerts (NGI0) /* Subflows will only be recreated if the SUBFLOW flag is set */ 12718617e85eSMatthieu Baerts (NGI0) if (is_subflow && (changed & MPTCP_PM_ADDR_FLAG_FULLMESH)) 12728617e85eSMatthieu Baerts (NGI0) mptcp_pm_nl_fullmesh(msk, &local->addr); 12738617e85eSMatthieu Baerts (NGI0) release_sock(sk); 12748617e85eSMatthieu Baerts (NGI0) 12758617e85eSMatthieu Baerts (NGI0) next: 12768617e85eSMatthieu Baerts (NGI0) sock_put(sk); 12778617e85eSMatthieu Baerts (NGI0) cond_resched(); 12788617e85eSMatthieu Baerts (NGI0) } 12798617e85eSMatthieu Baerts (NGI0) } 12808617e85eSMatthieu Baerts (NGI0) 12818617e85eSMatthieu Baerts (NGI0) int mptcp_pm_nl_set_flags(struct mptcp_pm_addr_entry *local, 12828617e85eSMatthieu Baerts (NGI0) struct genl_info *info) 12838617e85eSMatthieu Baerts (NGI0) { 12848617e85eSMatthieu Baerts (NGI0) struct nlattr *attr = info->attrs[MPTCP_PM_ATTR_ADDR]; 12858617e85eSMatthieu Baerts (NGI0) u8 changed, mask = MPTCP_PM_ADDR_FLAG_BACKUP | 12868617e85eSMatthieu Baerts (NGI0) MPTCP_PM_ADDR_FLAG_FULLMESH; 12878617e85eSMatthieu Baerts (NGI0) struct net *net = genl_info_net(info); 12888617e85eSMatthieu Baerts (NGI0) struct mptcp_pm_addr_entry *entry; 12898617e85eSMatthieu Baerts (NGI0) struct pm_nl_pernet *pernet; 12908617e85eSMatthieu Baerts (NGI0) u8 lookup_by_id = 0; 12918617e85eSMatthieu Baerts (NGI0) 12928617e85eSMatthieu Baerts (NGI0) pernet = pm_nl_get_pernet(net); 12938617e85eSMatthieu Baerts (NGI0) 12948617e85eSMatthieu Baerts (NGI0) if (local->addr.family == AF_UNSPEC) { 12958617e85eSMatthieu Baerts (NGI0) lookup_by_id = 1; 12968617e85eSMatthieu Baerts (NGI0) if (!local->addr.id) { 12978617e85eSMatthieu Baerts (NGI0) NL_SET_ERR_MSG_ATTR(info->extack, attr, 12988617e85eSMatthieu Baerts (NGI0) "missing address ID"); 12998617e85eSMatthieu Baerts (NGI0) return -EOPNOTSUPP; 13008617e85eSMatthieu Baerts (NGI0) } 13018617e85eSMatthieu Baerts (NGI0) } 13028617e85eSMatthieu Baerts (NGI0) 13038617e85eSMatthieu Baerts (NGI0) spin_lock_bh(&pernet->lock); 13048617e85eSMatthieu Baerts (NGI0) entry = lookup_by_id ? __lookup_addr_by_id(pernet, local->addr.id) : 13058617e85eSMatthieu Baerts (NGI0) __lookup_addr(pernet, &local->addr); 13068617e85eSMatthieu Baerts (NGI0) if (!entry) { 13078617e85eSMatthieu Baerts (NGI0) spin_unlock_bh(&pernet->lock); 13088617e85eSMatthieu Baerts (NGI0) NL_SET_ERR_MSG_ATTR(info->extack, attr, "address not found"); 13098617e85eSMatthieu Baerts (NGI0) return -EINVAL; 13108617e85eSMatthieu Baerts (NGI0) } 13118617e85eSMatthieu Baerts (NGI0) if ((local->flags & MPTCP_PM_ADDR_FLAG_FULLMESH) && 13128617e85eSMatthieu Baerts (NGI0) (entry->flags & (MPTCP_PM_ADDR_FLAG_SIGNAL | 13138617e85eSMatthieu Baerts (NGI0) MPTCP_PM_ADDR_FLAG_IMPLICIT))) { 13148617e85eSMatthieu Baerts (NGI0) spin_unlock_bh(&pernet->lock); 13158617e85eSMatthieu Baerts (NGI0) NL_SET_ERR_MSG_ATTR(info->extack, attr, "invalid addr flags"); 13168617e85eSMatthieu Baerts (NGI0) return -EINVAL; 13178617e85eSMatthieu Baerts (NGI0) } 13188617e85eSMatthieu Baerts (NGI0) 13198617e85eSMatthieu Baerts (NGI0) changed = (local->flags ^ entry->flags) & mask; 13208617e85eSMatthieu Baerts (NGI0) entry->flags = (entry->flags & ~mask) | (local->flags & mask); 13218617e85eSMatthieu Baerts (NGI0) *local = *entry; 13228617e85eSMatthieu Baerts (NGI0) spin_unlock_bh(&pernet->lock); 13238617e85eSMatthieu Baerts (NGI0) 13248617e85eSMatthieu Baerts (NGI0) mptcp_pm_nl_set_flags_all(net, local, changed); 13258617e85eSMatthieu Baerts (NGI0) return 0; 13268617e85eSMatthieu Baerts (NGI0) } 13278617e85eSMatthieu Baerts (NGI0) 13288617e85eSMatthieu Baerts (NGI0) bool mptcp_pm_nl_check_work_pending(struct mptcp_sock *msk) 13298617e85eSMatthieu Baerts (NGI0) { 13308617e85eSMatthieu Baerts (NGI0) struct pm_nl_pernet *pernet = pm_nl_get_pernet_from_msk(msk); 13318617e85eSMatthieu Baerts (NGI0) 13328617e85eSMatthieu Baerts (NGI0) if (msk->pm.subflows == mptcp_pm_get_subflows_max(msk) || 13338617e85eSMatthieu Baerts (NGI0) (find_next_and_bit(pernet->id_bitmap, msk->pm.id_avail_bitmap, 13348617e85eSMatthieu Baerts (NGI0) MPTCP_PM_MAX_ADDR_ID + 1, 0) == MPTCP_PM_MAX_ADDR_ID + 1)) { 13358617e85eSMatthieu Baerts (NGI0) WRITE_ONCE(msk->pm.work_pending, false); 13368617e85eSMatthieu Baerts (NGI0) return false; 13378617e85eSMatthieu Baerts (NGI0) } 13388617e85eSMatthieu Baerts (NGI0) return true; 13398617e85eSMatthieu Baerts (NGI0) } 13408617e85eSMatthieu Baerts (NGI0) 13418617e85eSMatthieu Baerts (NGI0) /* Called under PM lock */ 13428617e85eSMatthieu Baerts (NGI0) void __mptcp_pm_kernel_worker(struct mptcp_sock *msk) 13438617e85eSMatthieu Baerts (NGI0) { 13448617e85eSMatthieu Baerts (NGI0) struct mptcp_pm_data *pm = &msk->pm; 13458617e85eSMatthieu Baerts (NGI0) 13468617e85eSMatthieu Baerts (NGI0) if (pm->status & BIT(MPTCP_PM_ADD_ADDR_RECEIVED)) { 13478617e85eSMatthieu Baerts (NGI0) pm->status &= ~BIT(MPTCP_PM_ADD_ADDR_RECEIVED); 13488617e85eSMatthieu Baerts (NGI0) mptcp_pm_nl_add_addr_received(msk); 13498617e85eSMatthieu Baerts (NGI0) } 13508617e85eSMatthieu Baerts (NGI0) if (pm->status & BIT(MPTCP_PM_ESTABLISHED)) { 13518617e85eSMatthieu Baerts (NGI0) pm->status &= ~BIT(MPTCP_PM_ESTABLISHED); 13528617e85eSMatthieu Baerts (NGI0) mptcp_pm_nl_fully_established(msk); 13538617e85eSMatthieu Baerts (NGI0) } 13548617e85eSMatthieu Baerts (NGI0) if (pm->status & BIT(MPTCP_PM_SUBFLOW_ESTABLISHED)) { 13558617e85eSMatthieu Baerts (NGI0) pm->status &= ~BIT(MPTCP_PM_SUBFLOW_ESTABLISHED); 13568617e85eSMatthieu Baerts (NGI0) mptcp_pm_nl_subflow_established(msk); 13578617e85eSMatthieu Baerts (NGI0) } 13588617e85eSMatthieu Baerts (NGI0) } 13598617e85eSMatthieu Baerts (NGI0) 13608617e85eSMatthieu Baerts (NGI0) static int __net_init pm_nl_init_net(struct net *net) 13618617e85eSMatthieu Baerts (NGI0) { 13628617e85eSMatthieu Baerts (NGI0) struct pm_nl_pernet *pernet = pm_nl_get_pernet(net); 13638617e85eSMatthieu Baerts (NGI0) 13648617e85eSMatthieu Baerts (NGI0) INIT_LIST_HEAD_RCU(&pernet->local_addr_list); 13658617e85eSMatthieu Baerts (NGI0) 13668617e85eSMatthieu Baerts (NGI0) /* Cit. 2 subflows ought to be enough for anybody. */ 13678617e85eSMatthieu Baerts (NGI0) pernet->subflows_max = 2; 13688617e85eSMatthieu Baerts (NGI0) pernet->next_id = 1; 13698617e85eSMatthieu Baerts (NGI0) pernet->stale_loss_cnt = 4; 13708617e85eSMatthieu Baerts (NGI0) spin_lock_init(&pernet->lock); 13718617e85eSMatthieu Baerts (NGI0) 13728617e85eSMatthieu Baerts (NGI0) /* No need to initialize other pernet fields, the struct is zeroed at 13738617e85eSMatthieu Baerts (NGI0) * allocation time. 13748617e85eSMatthieu Baerts (NGI0) */ 13758617e85eSMatthieu Baerts (NGI0) 13768617e85eSMatthieu Baerts (NGI0) return 0; 13778617e85eSMatthieu Baerts (NGI0) } 13788617e85eSMatthieu Baerts (NGI0) 13798617e85eSMatthieu Baerts (NGI0) static void __net_exit pm_nl_exit_net(struct list_head *net_list) 13808617e85eSMatthieu Baerts (NGI0) { 13818617e85eSMatthieu Baerts (NGI0) struct net *net; 13828617e85eSMatthieu Baerts (NGI0) 13838617e85eSMatthieu Baerts (NGI0) list_for_each_entry(net, net_list, exit_list) { 13848617e85eSMatthieu Baerts (NGI0) struct pm_nl_pernet *pernet = pm_nl_get_pernet(net); 13858617e85eSMatthieu Baerts (NGI0) 13868617e85eSMatthieu Baerts (NGI0) /* net is removed from namespace list, can't race with 13878617e85eSMatthieu Baerts (NGI0) * other modifiers, also netns core already waited for a 13888617e85eSMatthieu Baerts (NGI0) * RCU grace period. 13898617e85eSMatthieu Baerts (NGI0) */ 13908617e85eSMatthieu Baerts (NGI0) __flush_addrs(&pernet->local_addr_list); 13918617e85eSMatthieu Baerts (NGI0) } 13928617e85eSMatthieu Baerts (NGI0) } 13938617e85eSMatthieu Baerts (NGI0) 13948617e85eSMatthieu Baerts (NGI0) static struct pernet_operations mptcp_pm_pernet_ops = { 13958617e85eSMatthieu Baerts (NGI0) .init = pm_nl_init_net, 13968617e85eSMatthieu Baerts (NGI0) .exit_batch = pm_nl_exit_net, 13978617e85eSMatthieu Baerts (NGI0) .id = &pm_nl_pernet_id, 13988617e85eSMatthieu Baerts (NGI0) .size = sizeof(struct pm_nl_pernet), 13998617e85eSMatthieu Baerts (NGI0) }; 14008617e85eSMatthieu Baerts (NGI0) 1401b97d6b68SMatthieu Baerts (NGI0) void __init mptcp_pm_kernel_register(void) 14028617e85eSMatthieu Baerts (NGI0) { 14038617e85eSMatthieu Baerts (NGI0) if (register_pernet_subsys(&mptcp_pm_pernet_ops) < 0) 14048617e85eSMatthieu Baerts (NGI0) panic("Failed to register MPTCP PM pernet subsystem.\n"); 14058617e85eSMatthieu Baerts (NGI0) } 1406