Linux kernel & device driver programming

Cross-Referenced Linux and Device Driver Code

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