LCOV - code coverage report
Current view: top level - mptcp/syncookies.c (source / functions) Coverage Total Hit
Test: export-net Lines: 90.7 % 54 49
Test Date: 2024-10-18 11:14:13 Functions: 100.0 % 4 4
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 83.3 % 12 10

             Branch data     Line data    Source code
       1                 :             : // SPDX-License-Identifier: GPL-2.0
       2                 :             : #include <linux/skbuff.h>
       3                 :             : 
       4                 :             : #include "protocol.h"
       5                 :             : 
       6                 :             : /* Syncookies do not work for JOIN requests.
       7                 :             :  *
       8                 :             :  * Unlike MP_CAPABLE, where the ACK cookie contains the needed MPTCP
       9                 :             :  * options to reconstruct the initial syn state, MP_JOIN does not contain
      10                 :             :  * the token to obtain the mptcp socket nor the server-generated nonce
      11                 :             :  * that was used in the cookie SYN/ACK response.
      12                 :             :  *
      13                 :             :  * Keep a small best effort state table to store the syn/synack data,
      14                 :             :  * indexed by skb hash.
      15                 :             :  *
      16                 :             :  * A MP_JOIN SYN packet handled by syn cookies is only stored if the 32bit
      17                 :             :  * token matches a known mptcp connection that can still accept more subflows.
      18                 :             :  *
      19                 :             :  * There is no timeout handling -- state is only re-constructed
      20                 :             :  * when the TCP ACK passed the cookie validation check.
      21                 :             :  */
      22                 :             : 
      23                 :             : struct join_entry {
      24                 :             :         u32 token;
      25                 :             :         u32 remote_nonce;
      26                 :             :         u32 local_nonce;
      27                 :             :         u8 join_id;
      28                 :             :         u8 local_id;
      29                 :             :         u8 backup;
      30                 :             :         u8 valid;
      31                 :             : };
      32                 :             : 
      33                 :             : #define COOKIE_JOIN_SLOTS       1024
      34                 :             : 
      35                 :             : static struct join_entry join_entries[COOKIE_JOIN_SLOTS] __cacheline_aligned_in_smp;
      36                 :             : static spinlock_t join_entry_locks[COOKIE_JOIN_SLOTS] __cacheline_aligned_in_smp;
      37                 :             : 
      38                 :          40 : static u32 mptcp_join_entry_hash(struct sk_buff *skb, struct net *net)
      39                 :             : {
      40                 :          40 :         static u32 mptcp_join_hash_secret __read_mostly;
      41                 :          40 :         struct tcphdr *th = tcp_hdr(skb);
      42                 :          40 :         u32 seq, i;
      43                 :             : 
      44   [ +  +  +  + ]:          40 :         net_get_random_once(&mptcp_join_hash_secret,
      45                 :             :                             sizeof(mptcp_join_hash_secret));
      46                 :             : 
      47         [ +  + ]:          40 :         if (th->syn)
      48                 :          20 :                 seq = TCP_SKB_CB(skb)->seq;
      49                 :             :         else
      50                 :          20 :                 seq = TCP_SKB_CB(skb)->seq - 1;
      51                 :             : 
      52                 :          40 :         i = jhash_3words(seq, net_hash_mix(net),
      53                 :          40 :                          (__force __u32)th->source << 16 | (__force __u32)th->dest,
      54                 :             :                          mptcp_join_hash_secret);
      55                 :             : 
      56                 :          40 :         return i % ARRAY_SIZE(join_entries);
      57                 :             : }
      58                 :             : 
      59                 :           0 : static void mptcp_join_store_state(struct join_entry *entry,
      60                 :             :                                    const struct mptcp_subflow_request_sock *subflow_req)
      61                 :             : {
      62                 :          20 :         entry->token = subflow_req->token;
      63                 :          20 :         entry->remote_nonce = subflow_req->remote_nonce;
      64                 :          20 :         entry->local_nonce = subflow_req->local_nonce;
      65                 :          20 :         entry->backup = subflow_req->backup;
      66                 :          20 :         entry->join_id = subflow_req->remote_id;
      67                 :          20 :         entry->local_id = subflow_req->local_id;
      68                 :          20 :         entry->valid = 1;
      69                 :             : }
      70                 :             : 
      71                 :          20 : void subflow_init_req_cookie_join_save(const struct mptcp_subflow_request_sock *subflow_req,
      72                 :             :                                        struct sk_buff *skb)
      73                 :             : {
      74                 :          20 :         struct net *net = read_pnet(&subflow_req->sk.req.ireq_net);
      75                 :          20 :         u32 i = mptcp_join_entry_hash(skb, net);
      76                 :             : 
      77                 :             :         /* No use in waiting if other cpu is already using this slot --
      78                 :             :          * would overwrite the data that got stored.
      79                 :             :          */
      80                 :          20 :         spin_lock_bh(&join_entry_locks[i]);
      81                 :          20 :         mptcp_join_store_state(&join_entries[i], subflow_req);
      82                 :          20 :         spin_unlock_bh(&join_entry_locks[i]);
      83                 :          20 : }
      84                 :             : 
      85                 :             : /* Called for a cookie-ack with MP_JOIN option present.
      86                 :             :  * Look up the saved state based on skb hash & check token matches msk
      87                 :             :  * in same netns.
      88                 :             :  *
      89                 :             :  * Caller will check msk can still accept another subflow.  The hmac
      90                 :             :  * present in the cookie ACK mptcp option space will be checked later.
      91                 :             :  */
      92                 :          20 : bool mptcp_token_join_cookie_init_state(struct mptcp_subflow_request_sock *subflow_req,
      93                 :             :                                         struct sk_buff *skb)
      94                 :             : {
      95                 :          20 :         struct net *net = read_pnet(&subflow_req->sk.req.ireq_net);
      96                 :          20 :         u32 i = mptcp_join_entry_hash(skb, net);
      97                 :          20 :         struct mptcp_sock *msk;
      98                 :          20 :         struct join_entry *e;
      99                 :             : 
     100                 :          20 :         e = &join_entries[i];
     101                 :             : 
     102                 :          20 :         spin_lock_bh(&join_entry_locks[i]);
     103                 :             : 
     104         [ -  + ]:          20 :         if (e->valid == 0) {
     105                 :           0 :                 spin_unlock_bh(&join_entry_locks[i]);
     106                 :           0 :                 return false;
     107                 :             :         }
     108                 :             : 
     109                 :          20 :         e->valid = 0;
     110                 :             : 
     111                 :          20 :         msk = mptcp_token_get_sock(net, e->token);
     112         [ -  + ]:          20 :         if (!msk) {
     113                 :           0 :                 spin_unlock_bh(&join_entry_locks[i]);
     114                 :           0 :                 return false;
     115                 :             :         }
     116                 :             : 
     117                 :          20 :         subflow_req->remote_nonce = e->remote_nonce;
     118                 :          20 :         subflow_req->local_nonce = e->local_nonce;
     119                 :          20 :         subflow_req->backup = e->backup;
     120                 :          20 :         subflow_req->remote_id = e->join_id;
     121                 :          20 :         subflow_req->token = e->token;
     122                 :          20 :         subflow_req->msk = msk;
     123                 :          20 :         spin_unlock_bh(&join_entry_locks[i]);
     124                 :          20 :         return true;
     125                 :             : }
     126                 :             : 
     127                 :           4 : void __init mptcp_join_cookie_init(void)
     128                 :             : {
     129                 :           4 :         int i;
     130                 :             : 
     131         [ +  + ]:        4100 :         for (i = 0; i < COOKIE_JOIN_SLOTS; i++)
     132                 :        4096 :                 spin_lock_init(&join_entry_locks[i]);
     133                 :           4 : }
        

Generated by: LCOV version 2.0-1