~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/net/rxrpc/ar-local.c

Version: ~ [ linux-5.3-rc5 ] ~ [ linux-5.2.9 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.67 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.139 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.189 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.189 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.72 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-3.9.11 ] ~ [ linux-3.8.13 ] ~ [ linux-3.7.10 ] ~ [ linux-3.6.11 ] ~ [ linux-3.5.7 ] ~ [ linux-3.4.113 ] ~ [ linux-3.3.8 ] ~ [ linux-3.2.102 ] ~ [ linux-3.1.10 ] ~ [ linux-3.0.101 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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
 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  */
 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  */
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  */
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  */
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  */
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 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp