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)
pm_nl_get_pernet(const struct net * net)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 *
pm_nl_get_pernet_from_msk(const struct mptcp_sock * msk)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)
genl_info_pm_nl(struct genl_info * info)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)
mptcp_pm_get_add_addr_signal_max(const struct mptcp_sock * msk)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)
mptcp_pm_get_add_addr_accept_max(const struct mptcp_sock * msk)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)
mptcp_pm_get_subflows_max(const struct mptcp_sock * msk)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)
mptcp_pm_get_local_addr_max(const struct mptcp_sock * msk)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)
lookup_subflow_by_daddr(const struct list_head * list,const struct mptcp_addr_info * daddr)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
select_local_address(const struct pm_nl_pernet * pernet,const struct mptcp_sock * msk,struct mptcp_pm_local * new_local)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
select_signal_address(struct pm_nl_pernet * pernet,const struct mptcp_sock * msk,struct mptcp_pm_local * new_local)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) */
fill_remote_addresses_vec(struct mptcp_sock * msk,struct mptcp_addr_info * local,bool fullmesh,struct mptcp_addr_info * addrs)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 *
__lookup_addr_by_id(struct pm_nl_pernet * pernet,unsigned int id)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 *
__lookup_addr(struct pm_nl_pernet * pernet,const struct mptcp_addr_info * info)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)
mptcp_pm_create_subflow_or_signal_addr(struct mptcp_sock * msk)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)
mptcp_pm_nl_fully_established(struct mptcp_sock * msk)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)
mptcp_pm_nl_subflow_established(struct mptcp_sock * msk)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) */
fill_local_addresses_vec(struct mptcp_sock * msk,struct mptcp_addr_info * remote,struct mptcp_pm_local * locals)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)
mptcp_pm_nl_add_addr_received(struct mptcp_sock * msk)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)
mptcp_pm_nl_rm_addr(struct mptcp_sock * msk,u8 rm_id)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)
address_use_port(struct mptcp_pm_addr_entry * entry)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 */
__mptcp_pm_release_addr_entry(struct mptcp_pm_addr_entry * entry)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)
mptcp_pm_nl_append_new_local_addr(struct pm_nl_pernet * pernet,struct mptcp_pm_addr_entry * entry,bool needs_id,bool replace)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)
mptcp_pm_nl_create_listen_socket(struct sock * sk,struct mptcp_pm_addr_entry * entry)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)
mptcp_pm_nl_get_local_id(struct mptcp_sock * msk,struct mptcp_pm_addr_entry * skc)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 */
713fa123489SGeliang 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)
mptcp_pm_nl_is_backup(struct mptcp_sock * msk,struct mptcp_addr_info * skc)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)
mptcp_nl_add_subflow_or_signal_addr(struct net * net,struct mptcp_addr_info * addr)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)
mptcp_pm_has_addr_attr_id(const struct nlattr * attr,struct genl_info * info)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 */
mptcp_pm_nl_add_addr_doit(struct sk_buff * skb,struct genl_info * info)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)
819fa123489SGeliang 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)
mptcp_endp_get_local_id(struct mptcp_sock * msk,const struct mptcp_addr_info * addr)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)
mptcp_pm_remove_anno_addr(struct mptcp_sock * msk,const struct mptcp_addr_info * addr,bool force)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)
__mark_subflow_endp_available(struct mptcp_sock * msk,u8 id)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)
mptcp_nl_remove_subflow_and_signal_addr(struct net * net,const struct mptcp_pm_addr_entry * entry)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)
mptcp_nl_remove_id_zero_address(struct net * net,struct mptcp_addr_info * addr)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 */
mptcp_pm_nl_del_addr_doit(struct sk_buff * skb,struct genl_info * info)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)
mptcp_pm_flush_addrs_and_subflows(struct mptcp_sock * msk,struct list_head * rm_list)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)
mptcp_nl_flush_addrs_list(struct net * net,struct list_head * rm_list)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 */
__flush_addrs(struct list_head * list)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)
__reset_counters(struct pm_nl_pernet * pernet)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)
mptcp_pm_nl_flush_addrs_doit(struct sk_buff * skb,struct genl_info * info)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)
mptcp_pm_nl_get_addr(u8 id,struct mptcp_pm_addr_entry * addr,struct genl_info * info)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)
mptcp_pm_nl_dump_addr(struct sk_buff * msg,struct netlink_callback * cb)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)
parse_limit(struct genl_info * info,int id,unsigned int * limit)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)
mptcp_pm_nl_set_limits_doit(struct sk_buff * skb,struct genl_info * info)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)
mptcp_pm_nl_get_limits_doit(struct sk_buff * skb,struct genl_info * info)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)
mptcp_pm_nl_fullmesh(struct mptcp_sock * msk,struct mptcp_addr_info * addr)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)
mptcp_pm_nl_set_flags_all(struct net * net,struct mptcp_pm_addr_entry * local,u8 changed)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)
mptcp_pm_nl_set_flags(struct mptcp_pm_addr_entry * local,struct genl_info * info)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)
mptcp_pm_nl_check_work_pending(struct mptcp_sock * msk)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 */
__mptcp_pm_kernel_worker(struct mptcp_sock * msk)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)
pm_nl_init_net(struct net * net)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)
pm_nl_exit_net(struct list_head * net_list)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)
1401*770170b4SGeliang Tang struct mptcp_pm_ops mptcp_pm_kernel = {
1402*770170b4SGeliang Tang .name = "kernel",
1403*770170b4SGeliang Tang .owner = THIS_MODULE,
1404*770170b4SGeliang Tang };
1405*770170b4SGeliang Tang
mptcp_pm_kernel_register(void)1406b97d6b68SMatthieu Baerts (NGI0) void __init mptcp_pm_kernel_register(void)
14078617e85eSMatthieu Baerts (NGI0) {
14088617e85eSMatthieu Baerts (NGI0) if (register_pernet_subsys(&mptcp_pm_pernet_ops) < 0)
14098617e85eSMatthieu Baerts (NGI0) panic("Failed to register MPTCP PM pernet subsystem.\n");
1410*770170b4SGeliang Tang
1411*770170b4SGeliang Tang mptcp_pm_register(&mptcp_pm_kernel);
14128617e85eSMatthieu Baerts (NGI0) }
1413