Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
ar-local.c
Go to the documentation of this file.
1 /* AF_RXRPC local endpoint management
2  *
3  * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
4  * Written by David Howells ([email protected])
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);
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);
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;
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;
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;
114  _leave(" = 0");
115  return 0;
116 
117 error:
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  */
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 */
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 
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);
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 */
230  if (unlikely(atomic_dec_and_test(&local->usage))) {
231  _debug("destroy local");
232  rxrpc_queue_work(&local->destroyer);
233  }
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);
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  */
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)) {
298  add_wait_queue(&rxrpc_local_wq, &myself);
299 
300  while (!list_empty(&rxrpc_locals)) {
301  schedule();
303  }
304 
305  remove_wait_queue(&rxrpc_local_wq, &myself);
307  }
308 
309  _leave("");
310 }