Blame view

net/ipv4/tcp_ulp.c 3.37 KB
457c89965   Thomas Gleixner   treewide: Add SPD...
1
  // SPDX-License-Identifier: GPL-2.0-only
734942cc4   Dave Watson   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   Daniel Borkmann   tcp, ulp: remove ...
9
  #include <linux/module.h>
734942cc4   Dave Watson   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   Amol Grover   tcp, ulp: Pass lo...
23
24
  	list_for_each_entry_rcu(e, &tcp_ulp_list, list,
  				lockdep_is_held(&tcp_ulp_list_lock)) {
734942cc4   Dave Watson   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   Daniel Borkmann   tcp, ulp: add ali...
42
  		request_module("tcp-ulp-%s", name);
734942cc4   Dave Watson   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   John Fastabend   net: add a UID to...
62
  	if (tcp_ulp_find(ulp->name))
734942cc4   Dave Watson   tcp: ULP infrastr...
63
  		ret = -EEXIST;
b11a632c4   John Fastabend   net: add a UID to...
64
  	else
734942cc4   Dave Watson   tcp: ULP infrastr...
65
  		list_add_tail_rcu(&ulp->list, &tcp_ulp_list);
734942cc4   Dave Watson   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   Jakub Kicinski   tcp: fix out-of-b...
87
  	*buf = '\0';
734942cc4   Dave Watson   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   Hangbin Liu   tcp: warn if offs...
93
94
95
  
  		if (WARN_ON_ONCE(offs >= maxlen))
  			break;
734942cc4   Dave Watson   tcp: ULP infrastr...
96
97
98
  	}
  	rcu_read_unlock();
  }
33bfe20dd   John Fastabend   bpf: Sockmap/tls,...
99
100
  void tcp_update_ulp(struct sock *sk, struct proto *proto,
  		    void (*write_space)(struct sock *sk))
95fa14547   John Fastabend   bpf: sockmap/tls,...
101
102
  {
  	struct inet_connection_sock *icsk = inet_csk(sk);
95fa14547   John Fastabend   bpf: sockmap/tls,...
103
  	if (icsk->icsk_ulp_ops->update)
33bfe20dd   John Fastabend   bpf: Sockmap/tls,...
104
  		icsk->icsk_ulp_ops->update(sk, proto, write_space);
95fa14547   John Fastabend   bpf: sockmap/tls,...
105
  }
734942cc4   Dave Watson   tcp: ULP infrastr...
106
107
108
  void tcp_cleanup_ulp(struct sock *sk)
  {
  	struct inet_connection_sock *icsk = inet_csk(sk);
aadd43559   Daniel Borkmann   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   Dave Watson   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   Daniel Borkmann   tcp, ulp: fix lef...
119
120
  
  	icsk->icsk_ulp_ops = NULL;
734942cc4   Dave Watson   tcp: ULP infrastr...
121
  }
1243a51f6   Daniel Borkmann   tcp, ulp: remove ...
122
  static int __tcp_set_ulp(struct sock *sk, const struct tcp_ulp_ops *ulp_ops)
734942cc4   Dave Watson   tcp: ULP infrastr...
123
124
  {
  	struct inet_connection_sock *icsk = inet_csk(sk);
1243a51f6   Daniel Borkmann   tcp, ulp: remove ...
125
  	int err;
734942cc4   Dave Watson   tcp: ULP infrastr...
126

1243a51f6   Daniel Borkmann   tcp, ulp: remove ...
127
  	err = -EEXIST;
734942cc4   Dave Watson   tcp: ULP infrastr...
128
  	if (icsk->icsk_ulp_ops)
1243a51f6   Daniel Borkmann   tcp, ulp: remove ...
129
  		goto out_err;
b11a632c4   John Fastabend   net: add a UID to...
130
131
  
  	err = ulp_ops->init(sk);
1243a51f6   Daniel Borkmann   tcp, ulp: remove ...
132
133
  	if (err)
  		goto out_err;
b11a632c4   John Fastabend   net: add a UID to...
134
135
136
  
  	icsk->icsk_ulp_ops = ulp_ops;
  	return 0;
1243a51f6   Daniel Borkmann   tcp, ulp: remove ...
137
138
139
  out_err:
  	module_put(ulp_ops->owner);
  	return err;
b11a632c4   John Fastabend   net: add a UID to...
140
  }
1243a51f6   Daniel Borkmann   tcp, ulp: remove ...
141
  int tcp_set_ulp(struct sock *sk, const char *name)
b11a632c4   John Fastabend   net: add a UID to...
142
  {
b11a632c4   John Fastabend   net: add a UID to...
143
  	const struct tcp_ulp_ops *ulp_ops;
b11a632c4   John Fastabend   net: add a UID to...
144

8b9088f80   Daniel Borkmann   tcp, ulp: enforce...
145
  	sock_owned_by_me(sk);
b11a632c4   John Fastabend   net: add a UID to...
146

1243a51f6   Daniel Borkmann   tcp, ulp: remove ...
147
  	ulp_ops = __tcp_ulp_find_autoload(name);
b11a632c4   John Fastabend   net: add a UID to...
148
149
  	if (!ulp_ops)
  		return -ENOENT;
1243a51f6   Daniel Borkmann   tcp, ulp: remove ...
150
  	return __tcp_set_ulp(sk, ulp_ops);
734942cc4   Dave Watson   tcp: ULP infrastr...
151
  }