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