1 /* AF_RXRPC local endpoint management
3 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
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.
12 #include <linux/module.h>
13 #include <linux/net.h>
14 #include <linux/skbuff.h>
15 #include <linux/slab.h>
17 #include <net/af_rxrpc.h>
18 #include "ar-internal.h"
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
);
25 static void rxrpc_destroy_local(struct work_struct
*work
);
28 * allocate a new local
31 struct rxrpc_local
*rxrpc_alloc_local(struct sockaddr_rxrpc
*srx
)
33 struct rxrpc_local
*local
;
35 local
= kzalloc(sizeof(struct rxrpc_local
), GFP_KERNEL
);
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
));
52 _leave(" = %p", local
);
57 * create the local socket
58 * - must be called with rxrpc_local_sem writelocked
60 static int rxrpc_create_local(struct rxrpc_local
*local
)
65 _enter("%p{%d}", local
, local
->srx
.transport_type
);
67 /* create a socket to represent the local endpoint */
68 ret
= sock_create_kern(PF_INET
, local
->srx
.transport_type
, IPPROTO_UDP
,
71 _leave(" = %d [socket]", ret
);
75 /* if a local address was supplied then bind it */
76 if (local
->srx
.transport_len
> sizeof(sa_family_t
)) {
78 ret
= kernel_bind(local
->socket
,
79 (struct sockaddr
*) &local
->srx
.transport
,
80 local
->srx
.transport_len
);
82 _debug("bind failed");
87 /* we want to receive ICMP errors */
89 ret
= kernel_setsockopt(local
->socket
, SOL_IP
, IP_RECVERR
,
90 (char *) &opt
, sizeof(opt
));
92 _debug("setsockopt failed");
96 /* we want to set the don't fragment bit */
98 ret
= kernel_setsockopt(local
->socket
, SOL_IP
, IP_MTU_DISCOVER
,
99 (char *) &opt
, sizeof(opt
));
101 _debug("setsockopt failed");
105 write_lock_bh(&rxrpc_local_lock
);
106 list_add(&local
->link
, &rxrpc_locals
);
107 write_unlock_bh(&rxrpc_local_lock
);
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
;
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
;
123 _leave(" = %d", ret
);
128 * create a new local endpoint using the specified UDP address
130 struct rxrpc_local
*rxrpc_lookup_local(struct sockaddr_rxrpc
*srx
)
132 struct rxrpc_local
*local
;
135 _enter("{%d,%u,%pI4+%hu}",
137 srx
->transport
.family
,
138 &srx
->transport
.sin
.sin_addr
,
139 ntohs(srx
->transport
.sin
.sin_port
));
141 down_write(&rxrpc_local_sem
);
143 /* see if we have a suitable local local endpoint already */
144 read_lock_bh(&rxrpc_local_lock
);
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
));
153 if (local
->srx
.transport_type
!= srx
->transport_type
||
154 local
->srx
.transport
.family
!= srx
->transport
.family
)
157 switch (srx
->transport
.family
) {
159 if (local
->srx
.transport
.sin
.sin_port
!=
160 srx
->transport
.sin
.sin_port
)
162 if (memcmp(&local
->srx
.transport
.sin
.sin_addr
,
163 &srx
->transport
.sin
.sin_addr
,
164 sizeof(struct in_addr
)) != 0)
173 read_unlock_bh(&rxrpc_local_lock
);
175 /* we didn't find one, so we need to create one */
176 local
= rxrpc_alloc_local(srx
);
178 up_write(&rxrpc_local_sem
);
179 return ERR_PTR(-ENOMEM
);
182 ret
= rxrpc_create_local(local
);
184 up_write(&rxrpc_local_sem
);
186 _leave(" = %d", ret
);
190 up_write(&rxrpc_local_sem
);
192 _net("LOCAL new %d {%d,%u,%pI4+%hu}",
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
));
199 _leave(" = %p [new]", local
);
203 rxrpc_get_local(local
);
204 read_unlock_bh(&rxrpc_local_lock
);
205 up_write(&rxrpc_local_sem
);
207 _net("LOCAL old %d {%d,%u,%pI4+%hu}",
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
));
214 _leave(" = %p [reuse]", local
);
219 * release a local endpoint
221 void rxrpc_put_local(struct rxrpc_local
*local
)
223 _enter("%p{u=%d}", local
, atomic_read(&local
->usage
));
225 ASSERTCMP(atomic_read(&local
->usage
), >, 0);
227 /* to prevent a race, the decrement and the dequeue must be effectively
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
);
234 write_unlock_bh(&rxrpc_local_lock
);
239 * destroy a local endpoint
241 static void rxrpc_destroy_local(struct work_struct
*work
)
243 struct rxrpc_local
*local
=
244 container_of(work
, struct rxrpc_local
, destroyer
);
246 _enter("%p{%d}", local
, atomic_read(&local
->usage
));
248 down_write(&rxrpc_local_sem
);
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]");
258 list_del(&local
->link
);
259 local
->socket
->sk
->sk_user_data
= NULL
;
260 write_unlock_bh(&rxrpc_local_lock
);
262 downgrade_write(&rxrpc_local_sem
);
264 ASSERT(list_empty(&local
->services
));
265 ASSERT(!work_pending(&local
->acceptor
));
266 ASSERT(!work_pending(&local
->rejecter
));
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
);
274 up_read(&rxrpc_local_sem
);
276 _net("DESTROY LOCAL %d", local
->debug_id
);
279 if (list_empty(&rxrpc_locals
))
280 wake_up_all(&rxrpc_local_wq
);
286 * preemptively destroy all local local endpoint rather than waiting for
287 * them to be destroyed
289 void __exit
rxrpc_destroy_all_locals(void)
291 DECLARE_WAITQUEUE(myself
,current
);
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
);
300 while (!list_empty(&rxrpc_locals
)) {
302 set_current_state(TASK_UNINTERRUPTIBLE
);
305 remove_wait_queue(&rxrpc_local_wq
, &myself
);
306 set_current_state(TASK_RUNNING
);