OpenCores
URL https://opencores.org/ocsvn/test_project/test_project/trunk

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [net/] [rxrpc/] [ar-connection.c] - Blame information for rev 62

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/* RxRPC virtual connection handler
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/crypto.h>
16
#include <net/sock.h>
17
#include <net/af_rxrpc.h>
18
#include "ar-internal.h"
19
 
20
static void rxrpc_connection_reaper(struct work_struct *work);
21
 
22
LIST_HEAD(rxrpc_connections);
23
DEFINE_RWLOCK(rxrpc_connection_lock);
24
static unsigned long rxrpc_connection_timeout = 10 * 60;
25
static DECLARE_DELAYED_WORK(rxrpc_connection_reap, rxrpc_connection_reaper);
26
 
27
/*
28
 * allocate a new client connection bundle
29
 */
30
static struct rxrpc_conn_bundle *rxrpc_alloc_bundle(gfp_t gfp)
31
{
32
        struct rxrpc_conn_bundle *bundle;
33
 
34
        _enter("");
35
 
36
        bundle = kzalloc(sizeof(struct rxrpc_conn_bundle), gfp);
37
        if (bundle) {
38
                INIT_LIST_HEAD(&bundle->unused_conns);
39
                INIT_LIST_HEAD(&bundle->avail_conns);
40
                INIT_LIST_HEAD(&bundle->busy_conns);
41
                init_waitqueue_head(&bundle->chanwait);
42
                atomic_set(&bundle->usage, 1);
43
        }
44
 
45
        _leave(" = %p", bundle);
46
        return bundle;
47
}
48
 
49
/*
50
 * compare bundle parameters with what we're looking for
51
 * - return -ve, 0 or +ve
52
 */
53
static inline
54
int rxrpc_cmp_bundle(const struct rxrpc_conn_bundle *bundle,
55
                     struct key *key, __be16 service_id)
56
{
57
        return (bundle->service_id - service_id) ?:
58
                ((unsigned long) bundle->key - (unsigned long) key);
59
}
60
 
61
/*
62
 * get bundle of client connections that a client socket can make use of
63
 */
64
struct rxrpc_conn_bundle *rxrpc_get_bundle(struct rxrpc_sock *rx,
65
                                           struct rxrpc_transport *trans,
66
                                           struct key *key,
67
                                           __be16 service_id,
68
                                           gfp_t gfp)
69
{
70
        struct rxrpc_conn_bundle *bundle, *candidate;
71
        struct rb_node *p, *parent, **pp;
72
 
73
        _enter("%p{%x},%x,%hx,",
74
               rx, key_serial(key), trans->debug_id, ntohs(service_id));
75
 
76
        if (rx->trans == trans && rx->bundle) {
77
                atomic_inc(&rx->bundle->usage);
78
                return rx->bundle;
79
        }
80
 
81
        /* search the extant bundles first for one that matches the specified
82
         * user ID */
83
        spin_lock(&trans->client_lock);
84
 
85
        p = trans->bundles.rb_node;
86
        while (p) {
87
                bundle = rb_entry(p, struct rxrpc_conn_bundle, node);
88
 
89
                if (rxrpc_cmp_bundle(bundle, key, service_id) < 0)
90
                        p = p->rb_left;
91
                else if (rxrpc_cmp_bundle(bundle, key, service_id) > 0)
92
                        p = p->rb_right;
93
                else
94
                        goto found_extant_bundle;
95
        }
96
 
97
        spin_unlock(&trans->client_lock);
98
 
99
        /* not yet present - create a candidate for a new record and then
100
         * redo the search */
101
        candidate = rxrpc_alloc_bundle(gfp);
102
        if (!candidate) {
103
                _leave(" = -ENOMEM");
104
                return ERR_PTR(-ENOMEM);
105
        }
106
 
107
        candidate->key = key_get(key);
108
        candidate->service_id = service_id;
109
 
110
        spin_lock(&trans->client_lock);
111
 
112
        pp = &trans->bundles.rb_node;
113
        parent = NULL;
114
        while (*pp) {
115
                parent = *pp;
116
                bundle = rb_entry(parent, struct rxrpc_conn_bundle, node);
117
 
118
                if (rxrpc_cmp_bundle(bundle, key, service_id) < 0)
119
                        pp = &(*pp)->rb_left;
120
                else if (rxrpc_cmp_bundle(bundle, key, service_id) > 0)
121
                        pp = &(*pp)->rb_right;
122
                else
123
                        goto found_extant_second;
124
        }
125
 
126
        /* second search also failed; add the new bundle */
127
        bundle = candidate;
128
        candidate = NULL;
129
 
130
        rb_link_node(&bundle->node, parent, pp);
131
        rb_insert_color(&bundle->node, &trans->bundles);
132
        spin_unlock(&trans->client_lock);
133
        _net("BUNDLE new on trans %d", trans->debug_id);
134
        if (!rx->bundle && rx->sk.sk_state == RXRPC_CLIENT_CONNECTED) {
135
                atomic_inc(&bundle->usage);
136
                rx->bundle = bundle;
137
        }
138
        _leave(" = %p [new]", bundle);
139
        return bundle;
140
 
141
        /* we found the bundle in the list immediately */
142
found_extant_bundle:
143
        atomic_inc(&bundle->usage);
144
        spin_unlock(&trans->client_lock);
145
        _net("BUNDLE old on trans %d", trans->debug_id);
146
        if (!rx->bundle && rx->sk.sk_state == RXRPC_CLIENT_CONNECTED) {
147
                atomic_inc(&bundle->usage);
148
                rx->bundle = bundle;
149
        }
150
        _leave(" = %p [extant %d]", bundle, atomic_read(&bundle->usage));
151
        return bundle;
152
 
153
        /* we found the bundle on the second time through the list */
154
found_extant_second:
155
        atomic_inc(&bundle->usage);
156
        spin_unlock(&trans->client_lock);
157
        kfree(candidate);
158
        _net("BUNDLE old2 on trans %d", trans->debug_id);
159
        if (!rx->bundle && rx->sk.sk_state == RXRPC_CLIENT_CONNECTED) {
160
                atomic_inc(&bundle->usage);
161
                rx->bundle = bundle;
162
        }
163
        _leave(" = %p [second %d]", bundle, atomic_read(&bundle->usage));
164
        return bundle;
165
}
166
 
167
/*
168
 * release a bundle
169
 */
170
void rxrpc_put_bundle(struct rxrpc_transport *trans,
171
                      struct rxrpc_conn_bundle *bundle)
172
{
173
        _enter("%p,%p{%d}",trans, bundle, atomic_read(&bundle->usage));
174
 
175
        if (atomic_dec_and_lock(&bundle->usage, &trans->client_lock)) {
176
                _debug("Destroy bundle");
177
                rb_erase(&bundle->node, &trans->bundles);
178
                spin_unlock(&trans->client_lock);
179
                ASSERT(list_empty(&bundle->unused_conns));
180
                ASSERT(list_empty(&bundle->avail_conns));
181
                ASSERT(list_empty(&bundle->busy_conns));
182
                ASSERTCMP(bundle->num_conns, ==, 0);
183
                key_put(bundle->key);
184
                kfree(bundle);
185
        }
186
 
187
        _leave("");
188
}
189
 
190
/*
191
 * allocate a new connection
192
 */
193
static struct rxrpc_connection *rxrpc_alloc_connection(gfp_t gfp)
194
{
195
        struct rxrpc_connection *conn;
196
 
197
        _enter("");
198
 
199
        conn = kzalloc(sizeof(struct rxrpc_connection), gfp);
200
        if (conn) {
201
                INIT_WORK(&conn->processor, &rxrpc_process_connection);
202
                INIT_LIST_HEAD(&conn->bundle_link);
203
                conn->calls = RB_ROOT;
204
                skb_queue_head_init(&conn->rx_queue);
205
                rwlock_init(&conn->lock);
206
                spin_lock_init(&conn->state_lock);
207
                atomic_set(&conn->usage, 1);
208
                conn->debug_id = atomic_inc_return(&rxrpc_debug_id);
209
                conn->avail_calls = RXRPC_MAXCALLS;
210
                conn->size_align = 4;
211
                conn->header_size = sizeof(struct rxrpc_header);
212
        }
213
 
214
        _leave(" = %p{%d}", conn, conn ? conn->debug_id : 0);
215
        return conn;
216
}
217
 
218
/*
219
 * assign a connection ID to a connection and add it to the transport's
220
 * connection lookup tree
221
 * - called with transport client lock held
222
 */
223
static void rxrpc_assign_connection_id(struct rxrpc_connection *conn)
224
{
225
        struct rxrpc_connection *xconn;
226
        struct rb_node *parent, **p;
227
        __be32 epoch;
228
        u32 real_conn_id;
229
 
230
        _enter("");
231
 
232
        epoch = conn->epoch;
233
 
234
        write_lock_bh(&conn->trans->conn_lock);
235
 
236
        conn->trans->conn_idcounter += RXRPC_CID_INC;
237
        if (conn->trans->conn_idcounter < RXRPC_CID_INC)
238
                conn->trans->conn_idcounter = RXRPC_CID_INC;
239
        real_conn_id = conn->trans->conn_idcounter;
240
 
241
attempt_insertion:
242
        parent = NULL;
243
        p = &conn->trans->client_conns.rb_node;
244
 
245
        while (*p) {
246
                parent = *p;
247
                xconn = rb_entry(parent, struct rxrpc_connection, node);
248
 
249
                if (epoch < xconn->epoch)
250
                        p = &(*p)->rb_left;
251
                else if (epoch > xconn->epoch)
252
                        p = &(*p)->rb_right;
253
                else if (real_conn_id < xconn->real_conn_id)
254
                        p = &(*p)->rb_left;
255
                else if (real_conn_id > xconn->real_conn_id)
256
                        p = &(*p)->rb_right;
257
                else
258
                        goto id_exists;
259
        }
260
 
261
        /* we've found a suitable hole - arrange for this connection to occupy
262
         * it */
263
        rb_link_node(&conn->node, parent, p);
264
        rb_insert_color(&conn->node, &conn->trans->client_conns);
265
 
266
        conn->real_conn_id = real_conn_id;
267
        conn->cid = htonl(real_conn_id);
268
        write_unlock_bh(&conn->trans->conn_lock);
269
        _leave(" [CONNID %x CID %x]", real_conn_id, ntohl(conn->cid));
270
        return;
271
 
272
        /* we found a connection with the proposed ID - walk the tree from that
273
         * point looking for the next unused ID */
274
id_exists:
275
        for (;;) {
276
                real_conn_id += RXRPC_CID_INC;
277
                if (real_conn_id < RXRPC_CID_INC) {
278
                        real_conn_id = RXRPC_CID_INC;
279
                        conn->trans->conn_idcounter = real_conn_id;
280
                        goto attempt_insertion;
281
                }
282
 
283
                parent = rb_next(parent);
284
                if (!parent)
285
                        goto attempt_insertion;
286
 
287
                xconn = rb_entry(parent, struct rxrpc_connection, node);
288
                if (epoch < xconn->epoch ||
289
                    real_conn_id < xconn->real_conn_id)
290
                        goto attempt_insertion;
291
        }
292
}
293
 
294
/*
295
 * add a call to a connection's call-by-ID tree
296
 */
297
static void rxrpc_add_call_ID_to_conn(struct rxrpc_connection *conn,
298
                                      struct rxrpc_call *call)
299
{
300
        struct rxrpc_call *xcall;
301
        struct rb_node *parent, **p;
302
        __be32 call_id;
303
 
304
        write_lock_bh(&conn->lock);
305
 
306
        call_id = call->call_id;
307
        p = &conn->calls.rb_node;
308
        parent = NULL;
309
        while (*p) {
310
                parent = *p;
311
                xcall = rb_entry(parent, struct rxrpc_call, conn_node);
312
 
313
                if (call_id < xcall->call_id)
314
                        p = &(*p)->rb_left;
315
                else if (call_id > xcall->call_id)
316
                        p = &(*p)->rb_right;
317
                else
318
                        BUG();
319
        }
320
 
321
        rb_link_node(&call->conn_node, parent, p);
322
        rb_insert_color(&call->conn_node, &conn->calls);
323
 
324
        write_unlock_bh(&conn->lock);
325
}
326
 
327
/*
328
 * connect a call on an exclusive connection
329
 */
330
static int rxrpc_connect_exclusive(struct rxrpc_sock *rx,
331
                                   struct rxrpc_transport *trans,
332
                                   __be16 service_id,
333
                                   struct rxrpc_call *call,
334
                                   gfp_t gfp)
335
{
336
        struct rxrpc_connection *conn;
337
        int chan, ret;
338
 
339
        _enter("");
340
 
341
        conn = rx->conn;
342
        if (!conn) {
343
                /* not yet present - create a candidate for a new connection
344
                 * and then redo the check */
345
                conn = rxrpc_alloc_connection(gfp);
346
                if (IS_ERR(conn)) {
347
                        _leave(" = %ld", PTR_ERR(conn));
348
                        return PTR_ERR(conn);
349
                }
350
 
351
                conn->trans = trans;
352
                conn->bundle = NULL;
353
                conn->service_id = service_id;
354
                conn->epoch = rxrpc_epoch;
355
                conn->in_clientflag = 0;
356
                conn->out_clientflag = RXRPC_CLIENT_INITIATED;
357
                conn->cid = 0;
358
                conn->state = RXRPC_CONN_CLIENT;
359
                conn->avail_calls = RXRPC_MAXCALLS - 1;
360
                conn->security_level = rx->min_sec_level;
361
                conn->key = key_get(rx->key);
362
 
363
                ret = rxrpc_init_client_conn_security(conn);
364
                if (ret < 0) {
365
                        key_put(conn->key);
366
                        kfree(conn);
367
                        _leave(" = %d [key]", ret);
368
                        return ret;
369
                }
370
 
371
                write_lock_bh(&rxrpc_connection_lock);
372
                list_add_tail(&conn->link, &rxrpc_connections);
373
                write_unlock_bh(&rxrpc_connection_lock);
374
 
375
                spin_lock(&trans->client_lock);
376
                atomic_inc(&trans->usage);
377
 
378
                _net("CONNECT EXCL new %d on TRANS %d",
379
                     conn->debug_id, conn->trans->debug_id);
380
 
381
                rxrpc_assign_connection_id(conn);
382
                rx->conn = conn;
383
        }
384
 
385
        /* we've got a connection with a free channel and we can now attach the
386
         * call to it
387
         * - we're holding the transport's client lock
388
         * - we're holding a reference on the connection
389
         */
390
        for (chan = 0; chan < RXRPC_MAXCALLS; chan++)
391
                if (!conn->channels[chan])
392
                        goto found_channel;
393
        goto no_free_channels;
394
 
395
found_channel:
396
        atomic_inc(&conn->usage);
397
        conn->channels[chan] = call;
398
        call->conn = conn;
399
        call->channel = chan;
400
        call->cid = conn->cid | htonl(chan);
401
        call->call_id = htonl(++conn->call_counter);
402
 
403
        _net("CONNECT client on conn %d chan %d as call %x",
404
             conn->debug_id, chan, ntohl(call->call_id));
405
 
406
        spin_unlock(&trans->client_lock);
407
 
408
        rxrpc_add_call_ID_to_conn(conn, call);
409
        _leave(" = 0");
410
        return 0;
411
 
412
no_free_channels:
413
        spin_unlock(&trans->client_lock);
414
        _leave(" = -ENOSR");
415
        return -ENOSR;
416
}
417
 
418
/*
419
 * find a connection for a call
420
 * - called in process context with IRQs enabled
421
 */
422
int rxrpc_connect_call(struct rxrpc_sock *rx,
423
                       struct rxrpc_transport *trans,
424
                       struct rxrpc_conn_bundle *bundle,
425
                       struct rxrpc_call *call,
426
                       gfp_t gfp)
427
{
428
        struct rxrpc_connection *conn, *candidate;
429
        int chan, ret;
430
 
431
        DECLARE_WAITQUEUE(myself, current);
432
 
433
        _enter("%p,%lx,", rx, call->user_call_ID);
434
 
435
        if (test_bit(RXRPC_SOCK_EXCLUSIVE_CONN, &rx->flags))
436
                return rxrpc_connect_exclusive(rx, trans, bundle->service_id,
437
                                               call, gfp);
438
 
439
        spin_lock(&trans->client_lock);
440
        for (;;) {
441
                /* see if the bundle has a call slot available */
442
                if (!list_empty(&bundle->avail_conns)) {
443
                        _debug("avail");
444
                        conn = list_entry(bundle->avail_conns.next,
445
                                          struct rxrpc_connection,
446
                                          bundle_link);
447
                        if (--conn->avail_calls == 0)
448
                                list_move(&conn->bundle_link,
449
                                          &bundle->busy_conns);
450
                        ASSERTCMP(conn->avail_calls, <, RXRPC_MAXCALLS);
451
                        ASSERT(conn->channels[0] == NULL ||
452
                               conn->channels[1] == NULL ||
453
                               conn->channels[2] == NULL ||
454
                               conn->channels[3] == NULL);
455
                        atomic_inc(&conn->usage);
456
                        break;
457
                }
458
 
459
                if (!list_empty(&bundle->unused_conns)) {
460
                        _debug("unused");
461
                        conn = list_entry(bundle->unused_conns.next,
462
                                          struct rxrpc_connection,
463
                                          bundle_link);
464
                        ASSERTCMP(conn->avail_calls, ==, RXRPC_MAXCALLS);
465
                        conn->avail_calls = RXRPC_MAXCALLS - 1;
466
                        ASSERT(conn->channels[0] == NULL &&
467
                               conn->channels[1] == NULL &&
468
                               conn->channels[2] == NULL &&
469
                               conn->channels[3] == NULL);
470
                        atomic_inc(&conn->usage);
471
                        list_move(&conn->bundle_link, &bundle->avail_conns);
472
                        break;
473
                }
474
 
475
                /* need to allocate a new connection */
476
                _debug("get new conn [%d]", bundle->num_conns);
477
 
478
                spin_unlock(&trans->client_lock);
479
 
480
                if (signal_pending(current))
481
                        goto interrupted;
482
 
483
                if (bundle->num_conns >= 20) {
484
                        _debug("too many conns");
485
 
486
                        if (!(gfp & __GFP_WAIT)) {
487
                                _leave(" = -EAGAIN");
488
                                return -EAGAIN;
489
                        }
490
 
491
                        add_wait_queue(&bundle->chanwait, &myself);
492
                        for (;;) {
493
                                set_current_state(TASK_INTERRUPTIBLE);
494
                                if (bundle->num_conns < 20 ||
495
                                    !list_empty(&bundle->unused_conns) ||
496
                                    !list_empty(&bundle->avail_conns))
497
                                        break;
498
                                if (signal_pending(current))
499
                                        goto interrupted_dequeue;
500
                                schedule();
501
                        }
502
                        remove_wait_queue(&bundle->chanwait, &myself);
503
                        __set_current_state(TASK_RUNNING);
504
                        spin_lock(&trans->client_lock);
505
                        continue;
506
                }
507
 
508
                /* not yet present - create a candidate for a new connection and then
509
                 * redo the check */
510
                candidate = rxrpc_alloc_connection(gfp);
511
                if (IS_ERR(candidate)) {
512
                        _leave(" = %ld", PTR_ERR(candidate));
513
                        return PTR_ERR(candidate);
514
                }
515
 
516
                candidate->trans = trans;
517
                candidate->bundle = bundle;
518
                candidate->service_id = bundle->service_id;
519
                candidate->epoch = rxrpc_epoch;
520
                candidate->in_clientflag = 0;
521
                candidate->out_clientflag = RXRPC_CLIENT_INITIATED;
522
                candidate->cid = 0;
523
                candidate->state = RXRPC_CONN_CLIENT;
524
                candidate->avail_calls = RXRPC_MAXCALLS;
525
                candidate->security_level = rx->min_sec_level;
526
                candidate->key = key_get(bundle->key);
527
 
528
                ret = rxrpc_init_client_conn_security(candidate);
529
                if (ret < 0) {
530
                        key_put(candidate->key);
531
                        kfree(candidate);
532
                        _leave(" = %d [key]", ret);
533
                        return ret;
534
                }
535
 
536
                write_lock_bh(&rxrpc_connection_lock);
537
                list_add_tail(&candidate->link, &rxrpc_connections);
538
                write_unlock_bh(&rxrpc_connection_lock);
539
 
540
                spin_lock(&trans->client_lock);
541
 
542
                list_add(&candidate->bundle_link, &bundle->unused_conns);
543
                bundle->num_conns++;
544
                atomic_inc(&bundle->usage);
545
                atomic_inc(&trans->usage);
546
 
547
                _net("CONNECT new %d on TRANS %d",
548
                     candidate->debug_id, candidate->trans->debug_id);
549
 
550
                rxrpc_assign_connection_id(candidate);
551
                if (candidate->security)
552
                        candidate->security->prime_packet_security(candidate);
553
 
554
                /* leave the candidate lurking in zombie mode attached to the
555
                 * bundle until we're ready for it */
556
                rxrpc_put_connection(candidate);
557
                candidate = NULL;
558
        }
559
 
560
        /* we've got a connection with a free channel and we can now attach the
561
         * call to it
562
         * - we're holding the transport's client lock
563
         * - we're holding a reference on the connection
564
         * - we're holding a reference on the bundle
565
         */
566
        for (chan = 0; chan < RXRPC_MAXCALLS; chan++)
567
                if (!conn->channels[chan])
568
                        goto found_channel;
569
        ASSERT(conn->channels[0] == NULL ||
570
               conn->channels[1] == NULL ||
571
               conn->channels[2] == NULL ||
572
               conn->channels[3] == NULL);
573
        BUG();
574
 
575
found_channel:
576
        conn->channels[chan] = call;
577
        call->conn = conn;
578
        call->channel = chan;
579
        call->cid = conn->cid | htonl(chan);
580
        call->call_id = htonl(++conn->call_counter);
581
 
582
        _net("CONNECT client on conn %d chan %d as call %x",
583
             conn->debug_id, chan, ntohl(call->call_id));
584
 
585
        ASSERTCMP(conn->avail_calls, <, RXRPC_MAXCALLS);
586
        spin_unlock(&trans->client_lock);
587
 
588
        rxrpc_add_call_ID_to_conn(conn, call);
589
 
590
        _leave(" = 0");
591
        return 0;
592
 
593
interrupted_dequeue:
594
        remove_wait_queue(&bundle->chanwait, &myself);
595
        __set_current_state(TASK_RUNNING);
596
interrupted:
597
        _leave(" = -ERESTARTSYS");
598
        return -ERESTARTSYS;
599
}
600
 
601
/*
602
 * get a record of an incoming connection
603
 */
604
struct rxrpc_connection *
605
rxrpc_incoming_connection(struct rxrpc_transport *trans,
606
                          struct rxrpc_header *hdr,
607
                          gfp_t gfp)
608
{
609
        struct rxrpc_connection *conn, *candidate = NULL;
610
        struct rb_node *p, **pp;
611
        const char *new = "old";
612
        __be32 epoch;
613
        u32 conn_id;
614
 
615
        _enter("");
616
 
617
        ASSERT(hdr->flags & RXRPC_CLIENT_INITIATED);
618
 
619
        epoch = hdr->epoch;
620
        conn_id = ntohl(hdr->cid) & RXRPC_CIDMASK;
621
 
622
        /* search the connection list first */
623
        read_lock_bh(&trans->conn_lock);
624
 
625
        p = trans->server_conns.rb_node;
626
        while (p) {
627
                conn = rb_entry(p, struct rxrpc_connection, node);
628
 
629
                _debug("maybe %x", conn->real_conn_id);
630
 
631
                if (epoch < conn->epoch)
632
                        p = p->rb_left;
633
                else if (epoch > conn->epoch)
634
                        p = p->rb_right;
635
                else if (conn_id < conn->real_conn_id)
636
                        p = p->rb_left;
637
                else if (conn_id > conn->real_conn_id)
638
                        p = p->rb_right;
639
                else
640
                        goto found_extant_connection;
641
        }
642
        read_unlock_bh(&trans->conn_lock);
643
 
644
        /* not yet present - create a candidate for a new record and then
645
         * redo the search */
646
        candidate = rxrpc_alloc_connection(gfp);
647
        if (!candidate) {
648
                _leave(" = -ENOMEM");
649
                return ERR_PTR(-ENOMEM);
650
        }
651
 
652
        candidate->trans = trans;
653
        candidate->epoch = hdr->epoch;
654
        candidate->cid = hdr->cid & __constant_cpu_to_be32(RXRPC_CIDMASK);
655
        candidate->service_id = hdr->serviceId;
656
        candidate->security_ix = hdr->securityIndex;
657
        candidate->in_clientflag = RXRPC_CLIENT_INITIATED;
658
        candidate->out_clientflag = 0;
659
        candidate->real_conn_id = conn_id;
660
        candidate->state = RXRPC_CONN_SERVER;
661
        if (candidate->service_id)
662
                candidate->state = RXRPC_CONN_SERVER_UNSECURED;
663
 
664
        write_lock_bh(&trans->conn_lock);
665
 
666
        pp = &trans->server_conns.rb_node;
667
        p = NULL;
668
        while (*pp) {
669
                p = *pp;
670
                conn = rb_entry(p, struct rxrpc_connection, node);
671
 
672
                if (epoch < conn->epoch)
673
                        pp = &(*pp)->rb_left;
674
                else if (epoch > conn->epoch)
675
                        pp = &(*pp)->rb_right;
676
                else if (conn_id < conn->real_conn_id)
677
                        pp = &(*pp)->rb_left;
678
                else if (conn_id > conn->real_conn_id)
679
                        pp = &(*pp)->rb_right;
680
                else
681
                        goto found_extant_second;
682
        }
683
 
684
        /* we can now add the new candidate to the list */
685
        conn = candidate;
686
        candidate = NULL;
687
        rb_link_node(&conn->node, p, pp);
688
        rb_insert_color(&conn->node, &trans->server_conns);
689
        atomic_inc(&conn->trans->usage);
690
 
691
        write_unlock_bh(&trans->conn_lock);
692
 
693
        write_lock_bh(&rxrpc_connection_lock);
694
        list_add_tail(&conn->link, &rxrpc_connections);
695
        write_unlock_bh(&rxrpc_connection_lock);
696
 
697
        new = "new";
698
 
699
success:
700
        _net("CONNECTION %s %d {%x}", new, conn->debug_id, conn->real_conn_id);
701
 
702
        _leave(" = %p {u=%d}", conn, atomic_read(&conn->usage));
703
        return conn;
704
 
705
        /* we found the connection in the list immediately */
706
found_extant_connection:
707
        if (hdr->securityIndex != conn->security_ix) {
708
                read_unlock_bh(&trans->conn_lock);
709
                goto security_mismatch;
710
        }
711
        atomic_inc(&conn->usage);
712
        read_unlock_bh(&trans->conn_lock);
713
        goto success;
714
 
715
        /* we found the connection on the second time through the list */
716
found_extant_second:
717
        if (hdr->securityIndex != conn->security_ix) {
718
                write_unlock_bh(&trans->conn_lock);
719
                goto security_mismatch;
720
        }
721
        atomic_inc(&conn->usage);
722
        write_unlock_bh(&trans->conn_lock);
723
        kfree(candidate);
724
        goto success;
725
 
726
security_mismatch:
727
        kfree(candidate);
728
        _leave(" = -EKEYREJECTED");
729
        return ERR_PTR(-EKEYREJECTED);
730
}
731
 
732
/*
733
 * find a connection based on transport and RxRPC connection ID for an incoming
734
 * packet
735
 */
736
struct rxrpc_connection *rxrpc_find_connection(struct rxrpc_transport *trans,
737
                                               struct rxrpc_header *hdr)
738
{
739
        struct rxrpc_connection *conn;
740
        struct rb_node *p;
741
        __be32 epoch;
742
        u32 conn_id;
743
 
744
        _enter(",{%x,%x}", ntohl(hdr->cid), hdr->flags);
745
 
746
        read_lock_bh(&trans->conn_lock);
747
 
748
        conn_id = ntohl(hdr->cid) & RXRPC_CIDMASK;
749
        epoch = hdr->epoch;
750
 
751
        if (hdr->flags & RXRPC_CLIENT_INITIATED)
752
                p = trans->server_conns.rb_node;
753
        else
754
                p = trans->client_conns.rb_node;
755
 
756
        while (p) {
757
                conn = rb_entry(p, struct rxrpc_connection, node);
758
 
759
                _debug("maybe %x", conn->real_conn_id);
760
 
761
                if (epoch < conn->epoch)
762
                        p = p->rb_left;
763
                else if (epoch > conn->epoch)
764
                        p = p->rb_right;
765
                else if (conn_id < conn->real_conn_id)
766
                        p = p->rb_left;
767
                else if (conn_id > conn->real_conn_id)
768
                        p = p->rb_right;
769
                else
770
                        goto found;
771
        }
772
 
773
        read_unlock_bh(&trans->conn_lock);
774
        _leave(" = NULL");
775
        return NULL;
776
 
777
found:
778
        atomic_inc(&conn->usage);
779
        read_unlock_bh(&trans->conn_lock);
780
        _leave(" = %p", conn);
781
        return conn;
782
}
783
 
784
/*
785
 * release a virtual connection
786
 */
787
void rxrpc_put_connection(struct rxrpc_connection *conn)
788
{
789
        _enter("%p{u=%d,d=%d}",
790
               conn, atomic_read(&conn->usage), conn->debug_id);
791
 
792
        ASSERTCMP(atomic_read(&conn->usage), >, 0);
793
 
794
        conn->put_time = get_seconds();
795
        if (atomic_dec_and_test(&conn->usage)) {
796
                _debug("zombie");
797
                rxrpc_queue_delayed_work(&rxrpc_connection_reap, 0);
798
        }
799
 
800
        _leave("");
801
}
802
 
803
/*
804
 * destroy a virtual connection
805
 */
806
static void rxrpc_destroy_connection(struct rxrpc_connection *conn)
807
{
808
        _enter("%p{%d}", conn, atomic_read(&conn->usage));
809
 
810
        ASSERTCMP(atomic_read(&conn->usage), ==, 0);
811
 
812
        _net("DESTROY CONN %d", conn->debug_id);
813
 
814
        if (conn->bundle)
815
                rxrpc_put_bundle(conn->trans, conn->bundle);
816
 
817
        ASSERT(RB_EMPTY_ROOT(&conn->calls));
818
        rxrpc_purge_queue(&conn->rx_queue);
819
 
820
        rxrpc_clear_conn_security(conn);
821
        rxrpc_put_transport(conn->trans);
822
        kfree(conn);
823
        _leave("");
824
}
825
 
826
/*
827
 * reap dead connections
828
 */
829
void rxrpc_connection_reaper(struct work_struct *work)
830
{
831
        struct rxrpc_connection *conn, *_p;
832
        unsigned long now, earliest, reap_time;
833
 
834
        LIST_HEAD(graveyard);
835
 
836
        _enter("");
837
 
838
        now = get_seconds();
839
        earliest = ULONG_MAX;
840
 
841
        write_lock_bh(&rxrpc_connection_lock);
842
        list_for_each_entry_safe(conn, _p, &rxrpc_connections, link) {
843
                _debug("reap CONN %d { u=%d,t=%ld }",
844
                       conn->debug_id, atomic_read(&conn->usage),
845
                       (long) now - (long) conn->put_time);
846
 
847
                if (likely(atomic_read(&conn->usage) > 0))
848
                        continue;
849
 
850
                spin_lock(&conn->trans->client_lock);
851
                write_lock(&conn->trans->conn_lock);
852
                reap_time = conn->put_time + rxrpc_connection_timeout;
853
 
854
                if (atomic_read(&conn->usage) > 0) {
855
                        ;
856
                } else if (reap_time <= now) {
857
                        list_move_tail(&conn->link, &graveyard);
858
                        if (conn->out_clientflag)
859
                                rb_erase(&conn->node,
860
                                         &conn->trans->client_conns);
861
                        else
862
                                rb_erase(&conn->node,
863
                                         &conn->trans->server_conns);
864
                        if (conn->bundle) {
865
                                list_del_init(&conn->bundle_link);
866
                                conn->bundle->num_conns--;
867
                        }
868
 
869
                } else if (reap_time < earliest) {
870
                        earliest = reap_time;
871
                }
872
 
873
                write_unlock(&conn->trans->conn_lock);
874
                spin_unlock(&conn->trans->client_lock);
875
        }
876
        write_unlock_bh(&rxrpc_connection_lock);
877
 
878
        if (earliest != ULONG_MAX) {
879
                _debug("reschedule reaper %ld", (long) earliest - now);
880
                ASSERTCMP(earliest, >, now);
881
                rxrpc_queue_delayed_work(&rxrpc_connection_reap,
882
                                         (earliest - now) * HZ);
883
        }
884
 
885
        /* then destroy all those pulled out */
886
        while (!list_empty(&graveyard)) {
887
                conn = list_entry(graveyard.next, struct rxrpc_connection,
888
                                  link);
889
                list_del_init(&conn->link);
890
 
891
                ASSERTCMP(atomic_read(&conn->usage), ==, 0);
892
                rxrpc_destroy_connection(conn);
893
        }
894
 
895
        _leave("");
896
}
897
 
898
/*
899
 * preemptively destroy all the connection records rather than waiting for them
900
 * to time out
901
 */
902
void __exit rxrpc_destroy_all_connections(void)
903
{
904
        _enter("");
905
 
906
        rxrpc_connection_timeout = 0;
907
        cancel_delayed_work(&rxrpc_connection_reap);
908
        rxrpc_queue_delayed_work(&rxrpc_connection_reap, 0);
909
 
910
        _leave("");
911
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.