LCOV - code coverage report
Current view: top level - net/ipv4 - tcp_ulp.c (source / functions) Hit Total Coverage
Test: gcov_data_raspi2_qemu_modules_combined.info Lines: 3 50 6.0 %
Date: 2020-09-30 20:25:01 Functions: 1 9 11.1 %
Branches: 1 32 3.1 %

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: GPL-2.0-only
       2                 :            : /*
       3                 :            :  * Pluggable TCP upper layer protocol support.
       4                 :            :  *
       5                 :            :  * Copyright (c) 2016-2017, Mellanox Technologies. All rights reserved.
       6                 :            :  * Copyright (c) 2016-2017, Dave Watson <davejwatson@fb.com>. All rights reserved.
       7                 :            :  *
       8                 :            :  */
       9                 :            : 
      10                 :            : #include <linux/module.h>
      11                 :            : #include <linux/mm.h>
      12                 :            : #include <linux/types.h>
      13                 :            : #include <linux/list.h>
      14                 :            : #include <linux/gfp.h>
      15                 :            : #include <net/tcp.h>
      16                 :            : 
      17                 :            : static DEFINE_SPINLOCK(tcp_ulp_list_lock);
      18                 :            : static LIST_HEAD(tcp_ulp_list);
      19                 :            : 
      20                 :            : /* Simple linear search, don't expect many entries! */
      21                 :          0 : static struct tcp_ulp_ops *tcp_ulp_find(const char *name)
      22                 :            : {
      23                 :            :         struct tcp_ulp_ops *e;
      24                 :            : 
      25         [ #  # ]:          0 :         list_for_each_entry_rcu(e, &tcp_ulp_list, list) {
      26         [ #  # ]:          0 :                 if (strcmp(e->name, name) == 0)
      27                 :          0 :                         return e;
      28                 :            :         }
      29                 :            : 
      30                 :            :         return NULL;
      31                 :            : }
      32                 :            : 
      33                 :          0 : static const struct tcp_ulp_ops *__tcp_ulp_find_autoload(const char *name)
      34                 :            : {
      35                 :            :         const struct tcp_ulp_ops *ulp = NULL;
      36                 :            : 
      37                 :            :         rcu_read_lock();
      38                 :          0 :         ulp = tcp_ulp_find(name);
      39                 :            : 
      40                 :            : #ifdef CONFIG_MODULES
      41   [ #  #  #  # ]:          0 :         if (!ulp && capable(CAP_NET_ADMIN)) {
      42                 :            :                 rcu_read_unlock();
      43                 :          0 :                 request_module("tcp-ulp-%s", name);
      44                 :            :                 rcu_read_lock();
      45                 :          0 :                 ulp = tcp_ulp_find(name);
      46                 :            :         }
      47                 :            : #endif
      48   [ #  #  #  # ]:          0 :         if (!ulp || !try_module_get(ulp->owner))
      49                 :            :                 ulp = NULL;
      50                 :            : 
      51                 :            :         rcu_read_unlock();
      52                 :          0 :         return ulp;
      53                 :            : }
      54                 :            : 
      55                 :            : /* Attach new upper layer protocol to the list
      56                 :            :  * of available protocols.
      57                 :            :  */
      58                 :          0 : int tcp_register_ulp(struct tcp_ulp_ops *ulp)
      59                 :            : {
      60                 :            :         int ret = 0;
      61                 :            : 
      62                 :            :         spin_lock(&tcp_ulp_list_lock);
      63         [ #  # ]:          0 :         if (tcp_ulp_find(ulp->name))
      64                 :            :                 ret = -EEXIST;
      65                 :            :         else
      66                 :          0 :                 list_add_tail_rcu(&ulp->list, &tcp_ulp_list);
      67                 :            :         spin_unlock(&tcp_ulp_list_lock);
      68                 :            : 
      69                 :          0 :         return ret;
      70                 :            : }
      71                 :            : EXPORT_SYMBOL_GPL(tcp_register_ulp);
      72                 :            : 
      73                 :          0 : void tcp_unregister_ulp(struct tcp_ulp_ops *ulp)
      74                 :            : {
      75                 :            :         spin_lock(&tcp_ulp_list_lock);
      76                 :            :         list_del_rcu(&ulp->list);
      77                 :            :         spin_unlock(&tcp_ulp_list_lock);
      78                 :            : 
      79                 :          0 :         synchronize_rcu();
      80                 :          0 : }
      81                 :            : EXPORT_SYMBOL_GPL(tcp_unregister_ulp);
      82                 :            : 
      83                 :            : /* Build string with list of available upper layer protocl values */
      84                 :          0 : void tcp_get_available_ulp(char *buf, size_t maxlen)
      85                 :            : {
      86                 :            :         struct tcp_ulp_ops *ulp_ops;
      87                 :            :         size_t offs = 0;
      88                 :            : 
      89                 :          0 :         *buf = '\0';
      90                 :            :         rcu_read_lock();
      91         [ #  # ]:          0 :         list_for_each_entry_rcu(ulp_ops, &tcp_ulp_list, list) {
      92         [ #  # ]:          0 :                 offs += snprintf(buf + offs, maxlen - offs,
      93                 :            :                                  "%s%s",
      94                 :          0 :                                  offs == 0 ? "" : " ", ulp_ops->name);
      95                 :            :         }
      96                 :            :         rcu_read_unlock();
      97                 :          0 : }
      98                 :            : 
      99                 :          0 : void tcp_update_ulp(struct sock *sk, struct proto *proto,
     100                 :            :                     void (*write_space)(struct sock *sk))
     101                 :            : {
     102                 :            :         struct inet_connection_sock *icsk = inet_csk(sk);
     103                 :            : 
     104         [ #  # ]:          0 :         if (!icsk->icsk_ulp_ops) {
     105                 :          0 :                 sk->sk_write_space = write_space;
     106                 :          0 :                 sk->sk_prot = proto;
     107                 :          0 :                 return;
     108                 :            :         }
     109                 :            : 
     110         [ #  # ]:          0 :         if (icsk->icsk_ulp_ops->update)
     111                 :          0 :                 icsk->icsk_ulp_ops->update(sk, proto, write_space);
     112                 :            : }
     113                 :            : 
     114                 :         72 : void tcp_cleanup_ulp(struct sock *sk)
     115                 :            : {
     116                 :            :         struct inet_connection_sock *icsk = inet_csk(sk);
     117                 :            : 
     118                 :            :         /* No sock_owned_by_me() check here as at the time the
     119                 :            :          * stack calls this function, the socket is dead and
     120                 :            :          * about to be destroyed.
     121                 :            :          */
     122         [ -  + ]:         72 :         if (!icsk->icsk_ulp_ops)
     123                 :         72 :                 return;
     124                 :            : 
     125         [ #  # ]:          0 :         if (icsk->icsk_ulp_ops->release)
     126                 :          0 :                 icsk->icsk_ulp_ops->release(sk);
     127                 :          0 :         module_put(icsk->icsk_ulp_ops->owner);
     128                 :            : 
     129                 :          0 :         icsk->icsk_ulp_ops = NULL;
     130                 :            : }
     131                 :            : 
     132                 :          0 : static int __tcp_set_ulp(struct sock *sk, const struct tcp_ulp_ops *ulp_ops)
     133                 :            : {
     134                 :            :         struct inet_connection_sock *icsk = inet_csk(sk);
     135                 :            :         int err;
     136                 :            : 
     137                 :            :         err = -EEXIST;
     138         [ #  # ]:          0 :         if (icsk->icsk_ulp_ops)
     139                 :            :                 goto out_err;
     140                 :            : 
     141                 :          0 :         err = ulp_ops->init(sk);
     142         [ #  # ]:          0 :         if (err)
     143                 :            :                 goto out_err;
     144                 :            : 
     145                 :          0 :         icsk->icsk_ulp_ops = ulp_ops;
     146                 :          0 :         return 0;
     147                 :            : out_err:
     148                 :          0 :         module_put(ulp_ops->owner);
     149                 :          0 :         return err;
     150                 :            : }
     151                 :            : 
     152                 :          0 : int tcp_set_ulp(struct sock *sk, const char *name)
     153                 :            : {
     154                 :            :         const struct tcp_ulp_ops *ulp_ops;
     155                 :            : 
     156                 :            :         sock_owned_by_me(sk);
     157                 :            : 
     158                 :          0 :         ulp_ops = __tcp_ulp_find_autoload(name);
     159         [ #  # ]:          0 :         if (!ulp_ops)
     160                 :            :                 return -ENOENT;
     161                 :            : 
     162                 :          0 :         return __tcp_set_ulp(sk, ulp_ops);
     163                 :            : }

Generated by: LCOV version 1.14