Commit d98c8210 authored by David S. Miller's avatar David S. Miller

Merge branch 'mptcp-fixes'

Mat Martineau says:

====================
mptcp: Bug fixes

Here are two bug fixes for the net tree:

Patch 1 fixes a memory leak that could be encountered when clearing the
list of advertised MPTCP addresses.

Patch 2 fixes a protocol issue early in an MPTCP connection, to ensure
both peers correctly understand that the full MPTCP connection handshake
has completed even when the server side quickly sends an ADD_ADDR
option.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents fb4b1373 67b12f79
...@@ -885,20 +885,16 @@ static bool check_fully_established(struct mptcp_sock *msk, struct sock *ssk, ...@@ -885,20 +885,16 @@ static bool check_fully_established(struct mptcp_sock *msk, struct sock *ssk,
return subflow->mp_capable; return subflow->mp_capable;
} }
if (mp_opt->dss && mp_opt->use_ack) { if ((mp_opt->dss && mp_opt->use_ack) ||
(mp_opt->add_addr && !mp_opt->echo)) {
/* subflows are fully established as soon as we get any /* subflows are fully established as soon as we get any
* additional ack. * additional ack, including ADD_ADDR.
*/ */
subflow->fully_established = 1; subflow->fully_established = 1;
WRITE_ONCE(msk->fully_established, true); WRITE_ONCE(msk->fully_established, true);
goto fully_established; goto fully_established;
} }
if (mp_opt->add_addr) {
WRITE_ONCE(msk->fully_established, true);
return true;
}
/* If the first established packet does not contain MP_CAPABLE + data /* If the first established packet does not contain MP_CAPABLE + data
* then fallback to TCP. Fallback scenarios requires a reset for * then fallback to TCP. Fallback scenarios requires a reset for
* MP_JOIN subflows. * MP_JOIN subflows.
......
...@@ -1135,36 +1135,12 @@ static int mptcp_nl_remove_subflow_and_signal_addr(struct net *net, ...@@ -1135,36 +1135,12 @@ static int mptcp_nl_remove_subflow_and_signal_addr(struct net *net,
return 0; return 0;
} }
struct addr_entry_release_work { /* caller must ensure the RCU grace period is already elapsed */
struct rcu_work rwork; static void __mptcp_pm_release_addr_entry(struct mptcp_pm_addr_entry *entry)
struct mptcp_pm_addr_entry *entry;
};
static void mptcp_pm_release_addr_entry(struct work_struct *work)
{ {
struct addr_entry_release_work *w; if (entry->lsk)
struct mptcp_pm_addr_entry *entry; sock_release(entry->lsk);
kfree(entry);
w = container_of(to_rcu_work(work), struct addr_entry_release_work, rwork);
entry = w->entry;
if (entry) {
if (entry->lsk)
sock_release(entry->lsk);
kfree(entry);
}
kfree(w);
}
static void mptcp_pm_free_addr_entry(struct mptcp_pm_addr_entry *entry)
{
struct addr_entry_release_work *w;
w = kmalloc(sizeof(*w), GFP_ATOMIC);
if (w) {
INIT_RCU_WORK(&w->rwork, mptcp_pm_release_addr_entry);
w->entry = entry;
queue_rcu_work(system_wq, &w->rwork);
}
} }
static int mptcp_nl_remove_id_zero_address(struct net *net, static int mptcp_nl_remove_id_zero_address(struct net *net,
...@@ -1244,7 +1220,8 @@ static int mptcp_nl_cmd_del_addr(struct sk_buff *skb, struct genl_info *info) ...@@ -1244,7 +1220,8 @@ static int mptcp_nl_cmd_del_addr(struct sk_buff *skb, struct genl_info *info)
spin_unlock_bh(&pernet->lock); spin_unlock_bh(&pernet->lock);
mptcp_nl_remove_subflow_and_signal_addr(sock_net(skb->sk), &entry->addr); mptcp_nl_remove_subflow_and_signal_addr(sock_net(skb->sk), &entry->addr);
mptcp_pm_free_addr_entry(entry); synchronize_rcu();
__mptcp_pm_release_addr_entry(entry);
return ret; return ret;
} }
...@@ -1297,6 +1274,7 @@ static void mptcp_nl_remove_addrs_list(struct net *net, ...@@ -1297,6 +1274,7 @@ static void mptcp_nl_remove_addrs_list(struct net *net,
} }
} }
/* caller must ensure the RCU grace period is already elapsed */
static void __flush_addrs(struct list_head *list) static void __flush_addrs(struct list_head *list)
{ {
while (!list_empty(list)) { while (!list_empty(list)) {
...@@ -1305,7 +1283,7 @@ static void __flush_addrs(struct list_head *list) ...@@ -1305,7 +1283,7 @@ static void __flush_addrs(struct list_head *list)
cur = list_entry(list->next, cur = list_entry(list->next,
struct mptcp_pm_addr_entry, list); struct mptcp_pm_addr_entry, list);
list_del_rcu(&cur->list); list_del_rcu(&cur->list);
mptcp_pm_free_addr_entry(cur); __mptcp_pm_release_addr_entry(cur);
} }
} }
...@@ -1329,6 +1307,7 @@ static int mptcp_nl_cmd_flush_addrs(struct sk_buff *skb, struct genl_info *info) ...@@ -1329,6 +1307,7 @@ static int mptcp_nl_cmd_flush_addrs(struct sk_buff *skb, struct genl_info *info)
bitmap_zero(pernet->id_bitmap, MAX_ADDR_ID + 1); bitmap_zero(pernet->id_bitmap, MAX_ADDR_ID + 1);
spin_unlock_bh(&pernet->lock); spin_unlock_bh(&pernet->lock);
mptcp_nl_remove_addrs_list(sock_net(skb->sk), &free_list); mptcp_nl_remove_addrs_list(sock_net(skb->sk), &free_list);
synchronize_rcu();
__flush_addrs(&free_list); __flush_addrs(&free_list);
return 0; return 0;
} }
...@@ -1939,7 +1918,8 @@ static void __net_exit pm_nl_exit_net(struct list_head *net_list) ...@@ -1939,7 +1918,8 @@ static void __net_exit pm_nl_exit_net(struct list_head *net_list)
struct pm_nl_pernet *pernet = net_generic(net, pm_nl_pernet_id); struct pm_nl_pernet *pernet = net_generic(net, pm_nl_pernet_id);
/* net is removed from namespace list, can't race with /* net is removed from namespace list, can't race with
* other modifiers * other modifiers, also netns core already waited for a
* RCU grace period.
*/ */
__flush_addrs(&pernet->local_addr_list); __flush_addrs(&pernet->local_addr_list);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment