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