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>
16 #include <net/af_rxrpc.h>
17 #include "ar-internal.h"
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
);
24 static void rxrpc_destroy_local(struct work_struct
*work
);
27 * allocate a new local
30 struct rxrpc_local
*rxrpc_alloc_local(struct sockaddr_rxrpc
*srx
)
32 struct rxrpc_local
*local
;
34 local
= kzalloc(sizeof(struct rxrpc_local
), GFP_KERNEL
);
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
));
51 _leave(" = %p", local
);
56 * create the local socket
57 * - must be called with rxrpc_local_sem writelocked
59 static int rxrpc_create_local(struct rxrpc_local
*local
)
64 _enter("%p{%d}", local
, local
->srx
.transport_type
);
66 /* create a socket to represent the local endpoint */
67 ret
= sock_create_kern(PF_INET
, local
->srx
.transport_type
, IPPROTO_UDP
,
70 _leave(" = %d [socket]", ret
);
74 /* if a local address was supplied then bind it */
75 if (local
->srx
.transport_len
> sizeof(sa_family_t
)) {
77 ret
= kernel_bind(local
->socket
,
78 (struct sockaddr
*) &local
->srx
.transport
,
79 local
->srx
.transport_len
);
81 _debug("bind failed");
86 /* we want to receive ICMP errors */
88 ret
= kernel_setsockopt(local
->socket
, SOL_IP
, IP_RECVERR
,
89 (char *) &opt
, sizeof(opt
));
91 _debug("setsockopt failed");
95 /* we want to set the don't fragment bit */
97 ret
= kernel_setsockopt(local
->socket
, SOL_IP
, IP_MTU_DISCOVER
,
98 (char *) &opt
, sizeof(opt
));
100 _debug("setsockopt failed");
104 write_lock_bh(&rxrpc_local_lock
);
105 list_add(&local
->link
, &rxrpc_locals
);
106 write_unlock_bh(&rxrpc_local_lock
);
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
;
117 local
->socket
->ops
->shutdown(local
->socket
, 2);
118 local
->socket
->sk
->sk_user_data
= NULL
;
119 sock_release(local
->socket
);
120 local
->socket
= NULL
;
122 _leave(" = %d", ret
);
127 * create a new local endpoint using the specified UDP address
129 struct rxrpc_local
*rxrpc_lookup_local(struct sockaddr_rxrpc
*srx
)
131 struct rxrpc_local
*local
;
134 _enter("{%d,%u,%u.%u.%u.%u+%hu}",
136 srx
->transport
.family
,
137 NIPQUAD(srx
->transport
.sin
.sin_addr
),
138 ntohs(srx
->transport
.sin
.sin_port
));
140 down_write(&rxrpc_local_sem
);
142 /* see if we have a suitable local local endpoint already */
143 read_lock_bh(&rxrpc_local_lock
);
145 list_for_each_entry(local
, &rxrpc_locals
, link
) {
146 _debug("CMP {%d,%u,%u.%u.%u.%u+%hu}",
147 local
->srx
.transport_type
,
148 local
->srx
.transport
.family
,
149 NIPQUAD(local
->srx
.transport
.sin
.sin_addr
),
150 ntohs(local
->srx
.transport
.sin
.sin_port
));
152 if (local
->srx
.transport_type
!= srx
->transport_type
||
153 local
->srx
.transport
.family
!= srx
->transport
.family
)
156 switch (srx
->transport
.family
) {
158 if (local
->srx
.transport
.sin
.sin_port
!=
159 srx
->transport
.sin
.sin_port
)
161 if (memcmp(&local
->srx
.transport
.sin
.sin_addr
,
162 &srx
->transport
.sin
.sin_addr
,
163 sizeof(struct in_addr
)) != 0)
172 read_unlock_bh(&rxrpc_local_lock
);
174 /* we didn't find one, so we need to create one */
175 local
= rxrpc_alloc_local(srx
);
177 up_write(&rxrpc_local_sem
);
178 return ERR_PTR(-ENOMEM
);
181 ret
= rxrpc_create_local(local
);
183 up_write(&rxrpc_local_sem
);
185 _leave(" = %d", ret
);
189 up_write(&rxrpc_local_sem
);
191 _net("LOCAL new %d {%d,%u,%u.%u.%u.%u+%hu}",
193 local
->srx
.transport_type
,
194 local
->srx
.transport
.family
,
195 NIPQUAD(local
->srx
.transport
.sin
.sin_addr
),
196 ntohs(local
->srx
.transport
.sin
.sin_port
));
198 _leave(" = %p [new]", local
);
202 rxrpc_get_local(local
);
203 read_unlock_bh(&rxrpc_local_lock
);
204 up_write(&rxrpc_local_sem
);
206 _net("LOCAL old %d {%d,%u,%u.%u.%u.%u+%hu}",
208 local
->srx
.transport_type
,
209 local
->srx
.transport
.family
,
210 NIPQUAD(local
->srx
.transport
.sin
.sin_addr
),
211 ntohs(local
->srx
.transport
.sin
.sin_port
));
213 _leave(" = %p [reuse]", local
);
218 * release a local endpoint
220 void rxrpc_put_local(struct rxrpc_local
*local
)
222 _enter("%p{u=%d}", local
, atomic_read(&local
->usage
));
224 ASSERTCMP(atomic_read(&local
->usage
), >, 0);
226 /* to prevent a race, the decrement and the dequeue must be effectively
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
);
233 write_unlock_bh(&rxrpc_local_lock
);
238 * destroy a local endpoint
240 static void rxrpc_destroy_local(struct work_struct
*work
)
242 struct rxrpc_local
*local
=
243 container_of(work
, struct rxrpc_local
, destroyer
);
245 _enter("%p{%d}", local
, atomic_read(&local
->usage
));
247 down_write(&rxrpc_local_sem
);
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]");
257 list_del(&local
->link
);
258 local
->socket
->sk
->sk_user_data
= NULL
;
259 write_unlock_bh(&rxrpc_local_lock
);
261 downgrade_write(&rxrpc_local_sem
);
263 ASSERT(list_empty(&local
->services
));
264 ASSERT(!work_pending(&local
->acceptor
));
265 ASSERT(!work_pending(&local
->rejecter
));
267 /* finish cleaning up the local descriptor */
268 rxrpc_purge_queue(&local
->accept_queue
);
269 rxrpc_purge_queue(&local
->reject_queue
);
270 local
->socket
->ops
->shutdown(local
->socket
, 2);
271 sock_release(local
->socket
);
273 up_read(&rxrpc_local_sem
);
275 _net("DESTROY LOCAL %d", local
->debug_id
);
278 if (list_empty(&rxrpc_locals
))
279 wake_up_all(&rxrpc_local_wq
);
285 * preemptively destroy all local local endpoint rather than waiting for
286 * them to be destroyed
288 void __exit
rxrpc_destroy_all_locals(void)
290 DECLARE_WAITQUEUE(myself
,current
);
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
);
299 while (!list_empty(&rxrpc_locals
)) {
301 set_current_state(TASK_UNINTERRUPTIBLE
);
304 remove_wait_queue(&rxrpc_local_wq
, &myself
);
305 set_current_state(TASK_RUNNING
);