]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blame - net/rxrpc/local_object.c
rxrpc: Separate local endpoint event handling out into its own file
[mirror_ubuntu-bionic-kernel.git] / net / rxrpc / local_object.c
CommitLineData
87563616 1/* Local endpoint object management
17926a79
DH
2 *
3 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 *
6 * This program is free software; you can redistribute it and/or
87563616 7 * modify it under the terms of the GNU General Public Licence
17926a79 8 * as published by the Free Software Foundation; either version
87563616 9 * 2 of the Licence, or (at your option) any later version.
17926a79
DH
10 */
11
9b6d5398
JP
12#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
13
17926a79
DH
14#include <linux/module.h>
15#include <linux/net.h>
16#include <linux/skbuff.h>
5a0e3ad6 17#include <linux/slab.h>
44ba0698
DH
18#include <linux/udp.h>
19#include <linux/ip.h>
17926a79
DH
20#include <net/sock.h>
21#include <net/af_rxrpc.h>
22#include "ar-internal.h"
23
24static LIST_HEAD(rxrpc_locals);
25DEFINE_RWLOCK(rxrpc_local_lock);
26static DECLARE_RWSEM(rxrpc_local_sem);
27static DECLARE_WAIT_QUEUE_HEAD(rxrpc_local_wq);
28
29static void rxrpc_destroy_local(struct work_struct *work);
30
31/*
32 * allocate a new local
33 */
34static
35struct rxrpc_local *rxrpc_alloc_local(struct sockaddr_rxrpc *srx)
36{
37 struct rxrpc_local *local;
38
39 local = kzalloc(sizeof(struct rxrpc_local), GFP_KERNEL);
40 if (local) {
41 INIT_WORK(&local->destroyer, &rxrpc_destroy_local);
42 INIT_WORK(&local->acceptor, &rxrpc_accept_incoming_calls);
43 INIT_WORK(&local->rejecter, &rxrpc_reject_packets);
44ba0698 44 INIT_WORK(&local->event_processor, &rxrpc_process_local_events);
17926a79
DH
45 INIT_LIST_HEAD(&local->services);
46 INIT_LIST_HEAD(&local->link);
47 init_rwsem(&local->defrag_sem);
48 skb_queue_head_init(&local->accept_queue);
49 skb_queue_head_init(&local->reject_queue);
44ba0698 50 skb_queue_head_init(&local->event_queue);
17926a79
DH
51 spin_lock_init(&local->lock);
52 rwlock_init(&local->services_lock);
53 atomic_set(&local->usage, 1);
54 local->debug_id = atomic_inc_return(&rxrpc_debug_id);
55 memcpy(&local->srx, srx, sizeof(*srx));
56 }
57
58 _leave(" = %p", local);
59 return local;
60}
61
62/*
63 * create the local socket
64 * - must be called with rxrpc_local_sem writelocked
65 */
66static int rxrpc_create_local(struct rxrpc_local *local)
67{
68 struct sock *sock;
69 int ret, opt;
70
71 _enter("%p{%d}", local, local->srx.transport_type);
72
73 /* create a socket to represent the local endpoint */
eeb1bd5c
EB
74 ret = sock_create_kern(&init_net, PF_INET, local->srx.transport_type,
75 IPPROTO_UDP, &local->socket);
17926a79
DH
76 if (ret < 0) {
77 _leave(" = %d [socket]", ret);
78 return ret;
79 }
80
81 /* if a local address was supplied then bind it */
82 if (local->srx.transport_len > sizeof(sa_family_t)) {
83 _debug("bind");
84 ret = kernel_bind(local->socket,
85 (struct sockaddr *) &local->srx.transport,
86 local->srx.transport_len);
87 if (ret < 0) {
88 _debug("bind failed");
89 goto error;
90 }
91 }
92
93 /* we want to receive ICMP errors */
94 opt = 1;
95 ret = kernel_setsockopt(local->socket, SOL_IP, IP_RECVERR,
96 (char *) &opt, sizeof(opt));
97 if (ret < 0) {
98 _debug("setsockopt failed");
99 goto error;
100 }
101
102 /* we want to set the don't fragment bit */
103 opt = IP_PMTUDISC_DO;
104 ret = kernel_setsockopt(local->socket, SOL_IP, IP_MTU_DISCOVER,
105 (char *) &opt, sizeof(opt));
106 if (ret < 0) {
107 _debug("setsockopt failed");
108 goto error;
109 }
110
111 write_lock_bh(&rxrpc_local_lock);
112 list_add(&local->link, &rxrpc_locals);
113 write_unlock_bh(&rxrpc_local_lock);
114
115 /* set the socket up */
116 sock = local->socket->sk;
117 sock->sk_user_data = local;
118 sock->sk_data_ready = rxrpc_data_ready;
abe89ef0 119 sock->sk_error_report = rxrpc_error_report;
17926a79
DH
120 _leave(" = 0");
121 return 0;
122
123error:
91cf45f0 124 kernel_sock_shutdown(local->socket, SHUT_RDWR);
17926a79
DH
125 local->socket->sk->sk_user_data = NULL;
126 sock_release(local->socket);
127 local->socket = NULL;
128
129 _leave(" = %d", ret);
130 return ret;
131}
132
133/*
134 * create a new local endpoint using the specified UDP address
135 */
136struct rxrpc_local *rxrpc_lookup_local(struct sockaddr_rxrpc *srx)
137{
138 struct rxrpc_local *local;
139 int ret;
140
21454aaa 141 _enter("{%d,%u,%pI4+%hu}",
17926a79
DH
142 srx->transport_type,
143 srx->transport.family,
21454aaa 144 &srx->transport.sin.sin_addr,
17926a79
DH
145 ntohs(srx->transport.sin.sin_port));
146
147 down_write(&rxrpc_local_sem);
148
149 /* see if we have a suitable local local endpoint already */
150 read_lock_bh(&rxrpc_local_lock);
151
152 list_for_each_entry(local, &rxrpc_locals, link) {
21454aaa 153 _debug("CMP {%d,%u,%pI4+%hu}",
17926a79
DH
154 local->srx.transport_type,
155 local->srx.transport.family,
21454aaa 156 &local->srx.transport.sin.sin_addr,
17926a79
DH
157 ntohs(local->srx.transport.sin.sin_port));
158
159 if (local->srx.transport_type != srx->transport_type ||
160 local->srx.transport.family != srx->transport.family)
161 continue;
162
163 switch (srx->transport.family) {
164 case AF_INET:
165 if (local->srx.transport.sin.sin_port !=
166 srx->transport.sin.sin_port)
167 continue;
168 if (memcmp(&local->srx.transport.sin.sin_addr,
169 &srx->transport.sin.sin_addr,
170 sizeof(struct in_addr)) != 0)
171 continue;
172 goto found_local;
173
174 default:
175 BUG();
176 }
177 }
178
179 read_unlock_bh(&rxrpc_local_lock);
180
181 /* we didn't find one, so we need to create one */
182 local = rxrpc_alloc_local(srx);
183 if (!local) {
184 up_write(&rxrpc_local_sem);
185 return ERR_PTR(-ENOMEM);
186 }
187
188 ret = rxrpc_create_local(local);
189 if (ret < 0) {
190 up_write(&rxrpc_local_sem);
191 kfree(local);
192 _leave(" = %d", ret);
193 return ERR_PTR(ret);
194 }
195
196 up_write(&rxrpc_local_sem);
197
21454aaa 198 _net("LOCAL new %d {%d,%u,%pI4+%hu}",
17926a79
DH
199 local->debug_id,
200 local->srx.transport_type,
201 local->srx.transport.family,
21454aaa 202 &local->srx.transport.sin.sin_addr,
17926a79
DH
203 ntohs(local->srx.transport.sin.sin_port));
204
205 _leave(" = %p [new]", local);
206 return local;
207
208found_local:
209 rxrpc_get_local(local);
210 read_unlock_bh(&rxrpc_local_lock);
211 up_write(&rxrpc_local_sem);
212
21454aaa 213 _net("LOCAL old %d {%d,%u,%pI4+%hu}",
17926a79
DH
214 local->debug_id,
215 local->srx.transport_type,
216 local->srx.transport.family,
21454aaa 217 &local->srx.transport.sin.sin_addr,
17926a79
DH
218 ntohs(local->srx.transport.sin.sin_port));
219
220 _leave(" = %p [reuse]", local);
221 return local;
222}
223
224/*
225 * release a local endpoint
226 */
227void rxrpc_put_local(struct rxrpc_local *local)
228{
229 _enter("%p{u=%d}", local, atomic_read(&local->usage));
230
231 ASSERTCMP(atomic_read(&local->usage), >, 0);
232
233 /* to prevent a race, the decrement and the dequeue must be effectively
234 * atomic */
235 write_lock_bh(&rxrpc_local_lock);
236 if (unlikely(atomic_dec_and_test(&local->usage))) {
237 _debug("destroy local");
651350d1 238 rxrpc_queue_work(&local->destroyer);
17926a79
DH
239 }
240 write_unlock_bh(&rxrpc_local_lock);
241 _leave("");
242}
243
244/*
245 * destroy a local endpoint
246 */
247static void rxrpc_destroy_local(struct work_struct *work)
248{
249 struct rxrpc_local *local =
250 container_of(work, struct rxrpc_local, destroyer);
251
252 _enter("%p{%d}", local, atomic_read(&local->usage));
253
254 down_write(&rxrpc_local_sem);
255
256 write_lock_bh(&rxrpc_local_lock);
257 if (atomic_read(&local->usage) > 0) {
258 write_unlock_bh(&rxrpc_local_lock);
259 up_read(&rxrpc_local_sem);
260 _leave(" [resurrected]");
261 return;
262 }
263
264 list_del(&local->link);
265 local->socket->sk->sk_user_data = NULL;
266 write_unlock_bh(&rxrpc_local_lock);
267
268 downgrade_write(&rxrpc_local_sem);
269
270 ASSERT(list_empty(&local->services));
271 ASSERT(!work_pending(&local->acceptor));
272 ASSERT(!work_pending(&local->rejecter));
44ba0698 273 ASSERT(!work_pending(&local->event_processor));
17926a79
DH
274
275 /* finish cleaning up the local descriptor */
276 rxrpc_purge_queue(&local->accept_queue);
277 rxrpc_purge_queue(&local->reject_queue);
44ba0698 278 rxrpc_purge_queue(&local->event_queue);
91cf45f0 279 kernel_sock_shutdown(local->socket, SHUT_RDWR);
17926a79
DH
280 sock_release(local->socket);
281
282 up_read(&rxrpc_local_sem);
283
284 _net("DESTROY LOCAL %d", local->debug_id);
285 kfree(local);
286
287 if (list_empty(&rxrpc_locals))
288 wake_up_all(&rxrpc_local_wq);
289
290 _leave("");
291}
292
293/*
294 * preemptively destroy all local local endpoint rather than waiting for
295 * them to be destroyed
296 */
297void __exit rxrpc_destroy_all_locals(void)
298{
299 DECLARE_WAITQUEUE(myself,current);
300
301 _enter("");
302
303 /* we simply have to wait for them to go away */
304 if (!list_empty(&rxrpc_locals)) {
305 set_current_state(TASK_UNINTERRUPTIBLE);
306 add_wait_queue(&rxrpc_local_wq, &myself);
307
308 while (!list_empty(&rxrpc_locals)) {
309 schedule();
310 set_current_state(TASK_UNINTERRUPTIBLE);
311 }
312
313 remove_wait_queue(&rxrpc_local_wq, &myself);
314 set_current_state(TASK_RUNNING);
315 }
316
317 _leave("");
318}