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