root/net/ipv4/tcp_ulp.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. tcp_ulp_find
  2. __tcp_ulp_find_autoload
  3. tcp_register_ulp
  4. tcp_unregister_ulp
  5. tcp_get_available_ulp
  6. tcp_update_ulp
  7. tcp_cleanup_ulp
  8. __tcp_set_ulp
  9. tcp_set_ulp

   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 static struct tcp_ulp_ops *tcp_ulp_find(const char *name)
  22 {
  23         struct tcp_ulp_ops *e;
  24 
  25         list_for_each_entry_rcu(e, &tcp_ulp_list, list) {
  26                 if (strcmp(e->name, name) == 0)
  27                         return e;
  28         }
  29 
  30         return NULL;
  31 }
  32 
  33 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         ulp = tcp_ulp_find(name);
  39 
  40 #ifdef CONFIG_MODULES
  41         if (!ulp && capable(CAP_NET_ADMIN)) {
  42                 rcu_read_unlock();
  43                 request_module("tcp-ulp-%s", name);
  44                 rcu_read_lock();
  45                 ulp = tcp_ulp_find(name);
  46         }
  47 #endif
  48         if (!ulp || !try_module_get(ulp->owner))
  49                 ulp = NULL;
  50 
  51         rcu_read_unlock();
  52         return ulp;
  53 }
  54 
  55 /* Attach new upper layer protocol to the list
  56  * of available protocols.
  57  */
  58 int tcp_register_ulp(struct tcp_ulp_ops *ulp)
  59 {
  60         int ret = 0;
  61 
  62         spin_lock(&tcp_ulp_list_lock);
  63         if (tcp_ulp_find(ulp->name))
  64                 ret = -EEXIST;
  65         else
  66                 list_add_tail_rcu(&ulp->list, &tcp_ulp_list);
  67         spin_unlock(&tcp_ulp_list_lock);
  68 
  69         return ret;
  70 }
  71 EXPORT_SYMBOL_GPL(tcp_register_ulp);
  72 
  73 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         synchronize_rcu();
  80 }
  81 EXPORT_SYMBOL_GPL(tcp_unregister_ulp);
  82 
  83 /* Build string with list of available upper layer protocl values */
  84 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         *buf = '\0';
  90         rcu_read_lock();
  91         list_for_each_entry_rcu(ulp_ops, &tcp_ulp_list, list) {
  92                 offs += snprintf(buf + offs, maxlen - offs,
  93                                  "%s%s",
  94                                  offs == 0 ? "" : " ", ulp_ops->name);
  95         }
  96         rcu_read_unlock();
  97 }
  98 
  99 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         if (!icsk->icsk_ulp_ops) {
 105                 sk->sk_write_space = write_space;
 106                 sk->sk_prot = proto;
 107                 return;
 108         }
 109 
 110         if (icsk->icsk_ulp_ops->update)
 111                 icsk->icsk_ulp_ops->update(sk, proto, write_space);
 112 }
 113 
 114 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         if (!icsk->icsk_ulp_ops)
 123                 return;
 124 
 125         if (icsk->icsk_ulp_ops->release)
 126                 icsk->icsk_ulp_ops->release(sk);
 127         module_put(icsk->icsk_ulp_ops->owner);
 128 
 129         icsk->icsk_ulp_ops = NULL;
 130 }
 131 
 132 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         if (icsk->icsk_ulp_ops)
 139                 goto out_err;
 140 
 141         err = ulp_ops->init(sk);
 142         if (err)
 143                 goto out_err;
 144 
 145         icsk->icsk_ulp_ops = ulp_ops;
 146         return 0;
 147 out_err:
 148         module_put(ulp_ops->owner);
 149         return err;
 150 }
 151 
 152 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         ulp_ops = __tcp_ulp_find_autoload(name);
 159         if (!ulp_ops)
 160                 return -ENOENT;
 161 
 162         return __tcp_set_ulp(sk, ulp_ops);
 163 }

/* [<][>][^][v][top][bottom][index][help] */