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

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [net/] [llc/] [llc_conn.c] - Blame information for rev 79

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/*
2
 * llc_conn.c - Driver routines for connection component.
3
 *
4
 * Copyright (c) 1997 by Procom Technology, Inc.
5
 *               2001-2003 by Arnaldo Carvalho de Melo <acme@conectiva.com.br>
6
 *
7
 * This program can be redistributed or modified under the terms of the
8
 * GNU General Public License as published by the Free Software Foundation.
9
 * This program is distributed without any warranty or implied warranty
10
 * of merchantability or fitness for a particular purpose.
11
 *
12
 * See the GNU General Public License for more details.
13
 */
14
 
15
#include <linux/init.h>
16
#include <net/llc_sap.h>
17
#include <net/llc_conn.h>
18
#include <net/sock.h>
19
#include <net/tcp_states.h>
20
#include <net/llc_c_ev.h>
21
#include <net/llc_c_ac.h>
22
#include <net/llc_c_st.h>
23
#include <net/llc_pdu.h>
24
 
25
#if 0
26
#define dprintk(args...) printk(KERN_DEBUG args)
27
#else
28
#define dprintk(args...)
29
#endif
30
 
31
static int llc_find_offset(int state, int ev_type);
32
static void llc_conn_send_pdus(struct sock *sk);
33
static int llc_conn_service(struct sock *sk, struct sk_buff *skb);
34
static int llc_exec_conn_trans_actions(struct sock *sk,
35
                                       struct llc_conn_state_trans *trans,
36
                                       struct sk_buff *ev);
37
static struct llc_conn_state_trans *llc_qualify_conn_ev(struct sock *sk,
38
                                                        struct sk_buff *skb);
39
 
40
/* Offset table on connection states transition diagram */
41
static int llc_offset_table[NBR_CONN_STATES][NBR_CONN_EV];
42
 
43
int sysctl_llc2_ack_timeout = LLC2_ACK_TIME * HZ;
44
int sysctl_llc2_p_timeout = LLC2_P_TIME * HZ;
45
int sysctl_llc2_rej_timeout = LLC2_REJ_TIME * HZ;
46
int sysctl_llc2_busy_timeout = LLC2_BUSY_TIME * HZ;
47
 
48
/**
49
 *      llc_conn_state_process - sends event to connection state machine
50
 *      @sk: connection
51
 *      @skb: occurred event
52
 *
53
 *      Sends an event to connection state machine. After processing event
54
 *      (executing it's actions and changing state), upper layer will be
55
 *      indicated or confirmed, if needed. Returns 0 for success, 1 for
56
 *      failure. The socket lock has to be held before calling this function.
57
 */
58
int llc_conn_state_process(struct sock *sk, struct sk_buff *skb)
59
{
60
        int rc;
61
        struct llc_sock *llc = llc_sk(skb->sk);
62
        struct llc_conn_state_ev *ev = llc_conn_ev(skb);
63
 
64
        /*
65
         * We have to hold the skb, because llc_conn_service will kfree it in
66
         * the sending path and we need to look at the skb->cb, where we encode
67
         * llc_conn_state_ev.
68
         */
69
        skb_get(skb);
70
        ev->ind_prim = ev->cfm_prim = 0;
71
        /*
72
         * Send event to state machine
73
         */
74
        rc = llc_conn_service(skb->sk, skb);
75
        if (unlikely(rc != 0)) {
76
                printk(KERN_ERR "%s: llc_conn_service failed\n", __FUNCTION__);
77
                goto out_kfree_skb;
78
        }
79
 
80
        if (unlikely(!ev->ind_prim && !ev->cfm_prim)) {
81
                /* indicate or confirm not required */
82
                /* XXX this is not very pretty, perhaps we should store
83
                 * XXX indicate/confirm-needed state in the llc_conn_state_ev
84
                 * XXX control block of the SKB instead? -DaveM
85
                 */
86
                if (!skb->next)
87
                        goto out_kfree_skb;
88
                goto out_skb_put;
89
        }
90
 
91
        if (unlikely(ev->ind_prim && ev->cfm_prim)) /* Paranoia */
92
                skb_get(skb);
93
 
94
        switch (ev->ind_prim) {
95
        case LLC_DATA_PRIM:
96
                llc_save_primitive(sk, skb, LLC_DATA_PRIM);
97
                if (unlikely(sock_queue_rcv_skb(sk, skb))) {
98
                        /*
99
                         * shouldn't happen
100
                         */
101
                        printk(KERN_ERR "%s: sock_queue_rcv_skb failed!\n",
102
                               __FUNCTION__);
103
                        kfree_skb(skb);
104
                }
105
                break;
106
        case LLC_CONN_PRIM:
107
                /*
108
                 * Can't be sock_queue_rcv_skb, because we have to leave the
109
                 * skb->sk pointing to the newly created struct sock in
110
                 * llc_conn_handler. -acme
111
                 */
112
                skb_queue_tail(&sk->sk_receive_queue, skb);
113
                sk->sk_state_change(sk);
114
                break;
115
        case LLC_DISC_PRIM:
116
                sock_hold(sk);
117
                if (sk->sk_type == SOCK_STREAM &&
118
                    sk->sk_state == TCP_ESTABLISHED) {
119
                        sk->sk_shutdown       = SHUTDOWN_MASK;
120
                        sk->sk_socket->state  = SS_UNCONNECTED;
121
                        sk->sk_state          = TCP_CLOSE;
122
                        if (!sock_flag(sk, SOCK_DEAD)) {
123
                                sock_set_flag(sk, SOCK_DEAD);
124
                                sk->sk_state_change(sk);
125
                        }
126
                }
127
                kfree_skb(skb);
128
                sock_put(sk);
129
                break;
130
        case LLC_RESET_PRIM:
131
                /*
132
                 * FIXME:
133
                 * RESET is not being notified to upper layers for now
134
                 */
135
                printk(KERN_INFO "%s: received a reset ind!\n", __FUNCTION__);
136
                kfree_skb(skb);
137
                break;
138
        default:
139
                if (ev->ind_prim) {
140
                        printk(KERN_INFO "%s: received unknown %d prim!\n",
141
                                __FUNCTION__, ev->ind_prim);
142
                        kfree_skb(skb);
143
                }
144
                /* No indication */
145
                break;
146
        }
147
 
148
        switch (ev->cfm_prim) {
149
        case LLC_DATA_PRIM:
150
                if (!llc_data_accept_state(llc->state))
151
                        sk->sk_write_space(sk);
152
                else
153
                        rc = llc->failed_data_req = 1;
154
                break;
155
        case LLC_CONN_PRIM:
156
                if (sk->sk_type == SOCK_STREAM &&
157
                    sk->sk_state == TCP_SYN_SENT) {
158
                        if (ev->status) {
159
                                sk->sk_socket->state = SS_UNCONNECTED;
160
                                sk->sk_state         = TCP_CLOSE;
161
                        } else {
162
                                sk->sk_socket->state = SS_CONNECTED;
163
                                sk->sk_state         = TCP_ESTABLISHED;
164
                        }
165
                        sk->sk_state_change(sk);
166
                }
167
                break;
168
        case LLC_DISC_PRIM:
169
                sock_hold(sk);
170
                if (sk->sk_type == SOCK_STREAM && sk->sk_state == TCP_CLOSING) {
171
                        sk->sk_socket->state = SS_UNCONNECTED;
172
                        sk->sk_state         = TCP_CLOSE;
173
                        sk->sk_state_change(sk);
174
                }
175
                sock_put(sk);
176
                break;
177
        case LLC_RESET_PRIM:
178
                /*
179
                 * FIXME:
180
                 * RESET is not being notified to upper layers for now
181
                 */
182
                printk(KERN_INFO "%s: received a reset conf!\n", __FUNCTION__);
183
                break;
184
        default:
185
                if (ev->cfm_prim) {
186
                        printk(KERN_INFO "%s: received unknown %d prim!\n",
187
                                        __FUNCTION__, ev->cfm_prim);
188
                        break;
189
                }
190
                goto out_skb_put; /* No confirmation */
191
        }
192
out_kfree_skb:
193
        kfree_skb(skb);
194
out_skb_put:
195
        kfree_skb(skb);
196
        return rc;
197
}
198
 
199
void llc_conn_send_pdu(struct sock *sk, struct sk_buff *skb)
200
{
201
        /* queue PDU to send to MAC layer */
202
        skb_queue_tail(&sk->sk_write_queue, skb);
203
        llc_conn_send_pdus(sk);
204
}
205
 
206
/**
207
 *      llc_conn_rtn_pdu - sends received data pdu to upper layer
208
 *      @sk: Active connection
209
 *      @skb: Received data frame
210
 *
211
 *      Sends received data pdu to upper layer (by using indicate function).
212
 *      Prepares service parameters (prim and prim_data). calling indication
213
 *      function will be done in llc_conn_state_process.
214
 */
215
void llc_conn_rtn_pdu(struct sock *sk, struct sk_buff *skb)
216
{
217
        struct llc_conn_state_ev *ev = llc_conn_ev(skb);
218
 
219
        ev->ind_prim = LLC_DATA_PRIM;
220
}
221
 
222
/**
223
 *      llc_conn_resend_i_pdu_as_cmd - resend all all unacknowledged I PDUs
224
 *      @sk: active connection
225
 *      @nr: NR
226
 *      @first_p_bit: p_bit value of first pdu
227
 *
228
 *      Resend all unacknowledged I PDUs, starting with the NR; send first as
229
 *      command PDU with P bit equal first_p_bit; if more than one send
230
 *      subsequent as command PDUs with P bit equal zero (0).
231
 */
232
void llc_conn_resend_i_pdu_as_cmd(struct sock *sk, u8 nr, u8 first_p_bit)
233
{
234
        struct sk_buff *skb;
235
        struct llc_pdu_sn *pdu;
236
        u16 nbr_unack_pdus;
237
        struct llc_sock *llc;
238
        u8 howmany_resend = 0;
239
 
240
        llc_conn_remove_acked_pdus(sk, nr, &nbr_unack_pdus);
241
        if (!nbr_unack_pdus)
242
                goto out;
243
        /*
244
         * Process unack PDUs only if unack queue is not empty; remove
245
         * appropriate PDUs, fix them up, and put them on mac_pdu_q.
246
         */
247
        llc = llc_sk(sk);
248
 
249
        while ((skb = skb_dequeue(&llc->pdu_unack_q)) != NULL) {
250
                pdu = llc_pdu_sn_hdr(skb);
251
                llc_pdu_set_cmd_rsp(skb, LLC_PDU_CMD);
252
                llc_pdu_set_pf_bit(skb, first_p_bit);
253
                skb_queue_tail(&sk->sk_write_queue, skb);
254
                first_p_bit = 0;
255
                llc->vS = LLC_I_GET_NS(pdu);
256
                howmany_resend++;
257
        }
258
        if (howmany_resend > 0)
259
                llc->vS = (llc->vS + 1) % LLC_2_SEQ_NBR_MODULO;
260
        /* any PDUs to re-send are queued up; start sending to MAC */
261
        llc_conn_send_pdus(sk);
262
out:;
263
}
264
 
265
/**
266
 *      llc_conn_resend_i_pdu_as_rsp - Resend all unacknowledged I PDUs
267
 *      @sk: active connection.
268
 *      @nr: NR
269
 *      @first_f_bit: f_bit value of first pdu.
270
 *
271
 *      Resend all unacknowledged I PDUs, starting with the NR; send first as
272
 *      response PDU with F bit equal first_f_bit; if more than one send
273
 *      subsequent as response PDUs with F bit equal zero (0).
274
 */
275
void llc_conn_resend_i_pdu_as_rsp(struct sock *sk, u8 nr, u8 first_f_bit)
276
{
277
        struct sk_buff *skb;
278
        u16 nbr_unack_pdus;
279
        struct llc_sock *llc = llc_sk(sk);
280
        u8 howmany_resend = 0;
281
 
282
        llc_conn_remove_acked_pdus(sk, nr, &nbr_unack_pdus);
283
        if (!nbr_unack_pdus)
284
                goto out;
285
        /*
286
         * Process unack PDUs only if unack queue is not empty; remove
287
         * appropriate PDUs, fix them up, and put them on mac_pdu_q
288
         */
289
        while ((skb = skb_dequeue(&llc->pdu_unack_q)) != NULL) {
290
                struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
291
 
292
                llc_pdu_set_cmd_rsp(skb, LLC_PDU_RSP);
293
                llc_pdu_set_pf_bit(skb, first_f_bit);
294
                skb_queue_tail(&sk->sk_write_queue, skb);
295
                first_f_bit = 0;
296
                llc->vS = LLC_I_GET_NS(pdu);
297
                howmany_resend++;
298
        }
299
        if (howmany_resend > 0)
300
                llc->vS = (llc->vS + 1) % LLC_2_SEQ_NBR_MODULO;
301
        /* any PDUs to re-send are queued up; start sending to MAC */
302
        llc_conn_send_pdus(sk);
303
out:;
304
}
305
 
306
/**
307
 *      llc_conn_remove_acked_pdus - Removes acknowledged pdus from tx queue
308
 *      @sk: active connection
309
 *      nr: NR
310
 *      how_many_unacked: size of pdu_unack_q after removing acked pdus
311
 *
312
 *      Removes acknowledged pdus from transmit queue (pdu_unack_q). Returns
313
 *      the number of pdus that removed from queue.
314
 */
315
int llc_conn_remove_acked_pdus(struct sock *sk, u8 nr, u16 *how_many_unacked)
316
{
317
        int pdu_pos, i;
318
        struct sk_buff *skb;
319
        struct llc_pdu_sn *pdu;
320
        int nbr_acked = 0;
321
        struct llc_sock *llc = llc_sk(sk);
322
        int q_len = skb_queue_len(&llc->pdu_unack_q);
323
 
324
        if (!q_len)
325
                goto out;
326
        skb = skb_peek(&llc->pdu_unack_q);
327
        pdu = llc_pdu_sn_hdr(skb);
328
 
329
        /* finding position of last acked pdu in queue */
330
        pdu_pos = ((int)LLC_2_SEQ_NBR_MODULO + (int)nr -
331
                        (int)LLC_I_GET_NS(pdu)) % LLC_2_SEQ_NBR_MODULO;
332
 
333
        for (i = 0; i < pdu_pos && i < q_len; i++) {
334
                skb = skb_dequeue(&llc->pdu_unack_q);
335
                if (skb)
336
                        kfree_skb(skb);
337
                nbr_acked++;
338
        }
339
out:
340
        *how_many_unacked = skb_queue_len(&llc->pdu_unack_q);
341
        return nbr_acked;
342
}
343
 
344
/**
345
 *      llc_conn_send_pdus - Sends queued PDUs
346
 *      @sk: active connection
347
 *
348
 *      Sends queued pdus to MAC layer for transmission.
349
 */
350
static void llc_conn_send_pdus(struct sock *sk)
351
{
352
        struct sk_buff *skb;
353
 
354
        while ((skb = skb_dequeue(&sk->sk_write_queue)) != NULL) {
355
                struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
356
 
357
                if (LLC_PDU_TYPE_IS_I(pdu) &&
358
                    !(skb->dev->flags & IFF_LOOPBACK)) {
359
                        struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
360
 
361
                        skb_queue_tail(&llc_sk(sk)->pdu_unack_q, skb);
362
                        if (!skb2)
363
                                break;
364
                        skb = skb2;
365
                }
366
                dev_queue_xmit(skb);
367
        }
368
}
369
 
370
/**
371
 *      llc_conn_service - finds transition and changes state of connection
372
 *      @sk: connection
373
 *      @skb: happened event
374
 *
375
 *      This function finds transition that matches with happened event, then
376
 *      executes related actions and finally changes state of connection.
377
 *      Returns 0 for success, 1 for failure.
378
 */
379
static int llc_conn_service(struct sock *sk, struct sk_buff *skb)
380
{
381
        int rc = 1;
382
        struct llc_sock *llc = llc_sk(sk);
383
        struct llc_conn_state_trans *trans;
384
 
385
        if (llc->state > NBR_CONN_STATES)
386
                goto out;
387
        rc = 0;
388
        trans = llc_qualify_conn_ev(sk, skb);
389
        if (trans) {
390
                rc = llc_exec_conn_trans_actions(sk, trans, skb);
391
                if (!rc && trans->next_state != NO_STATE_CHANGE) {
392
                        llc->state = trans->next_state;
393
                        if (!llc_data_accept_state(llc->state))
394
                                sk->sk_state_change(sk);
395
                }
396
        }
397
out:
398
        return rc;
399
}
400
 
401
/**
402
 *      llc_qualify_conn_ev - finds transition for event
403
 *      @sk: connection
404
 *      @skb: happened event
405
 *
406
 *      This function finds transition that matches with happened event.
407
 *      Returns pointer to found transition on success, %NULL otherwise.
408
 */
409
static struct llc_conn_state_trans *llc_qualify_conn_ev(struct sock *sk,
410
                                                        struct sk_buff *skb)
411
{
412
        struct llc_conn_state_trans **next_trans;
413
        llc_conn_ev_qfyr_t *next_qualifier;
414
        struct llc_conn_state_ev *ev = llc_conn_ev(skb);
415
        struct llc_sock *llc = llc_sk(sk);
416
        struct llc_conn_state *curr_state =
417
                                        &llc_conn_state_table[llc->state - 1];
418
 
419
        /* search thru events for this state until
420
         * list exhausted or until no more
421
         */
422
        for (next_trans = curr_state->transitions +
423
                llc_find_offset(llc->state - 1, ev->type);
424
             (*next_trans)->ev; next_trans++) {
425
                if (!((*next_trans)->ev)(sk, skb)) {
426
                        /* got POSSIBLE event match; the event may require
427
                         * qualification based on the values of a number of
428
                         * state flags; if all qualifications are met (i.e.,
429
                         * if all qualifying functions return success, or 0,
430
                         * then this is THE event we're looking for
431
                         */
432
                        for (next_qualifier = (*next_trans)->ev_qualifiers;
433
                             next_qualifier && *next_qualifier &&
434
                             !(*next_qualifier)(sk, skb); next_qualifier++)
435
                                /* nothing */;
436
                        if (!next_qualifier || !*next_qualifier)
437
                                /* all qualifiers executed successfully; this is
438
                                 * our transition; return it so we can perform
439
                                 * the associated actions & change the state
440
                                 */
441
                                return *next_trans;
442
                }
443
        }
444
        return NULL;
445
}
446
 
447
/**
448
 *      llc_exec_conn_trans_actions - executes related actions
449
 *      @sk: connection
450
 *      @trans: transition that it's actions must be performed
451
 *      @skb: event
452
 *
453
 *      Executes actions that is related to happened event. Returns 0 for
454
 *      success, 1 to indicate failure of at least one action.
455
 */
456
static int llc_exec_conn_trans_actions(struct sock *sk,
457
                                       struct llc_conn_state_trans *trans,
458
                                       struct sk_buff *skb)
459
{
460
        int rc = 0;
461
        llc_conn_action_t *next_action;
462
 
463
        for (next_action = trans->ev_actions;
464
             next_action && *next_action; next_action++) {
465
                int rc2 = (*next_action)(sk, skb);
466
 
467
                if (rc2 == 2) {
468
                        rc = rc2;
469
                        break;
470
                } else if (rc2)
471
                        rc = 1;
472
        }
473
        return rc;
474
}
475
 
476
/**
477
 *      __llc_lookup_established - Finds connection for the remote/local sap/mac
478
 *      @sap: SAP
479
 *      @daddr: address of remote LLC (MAC + SAP)
480
 *      @laddr: address of local LLC (MAC + SAP)
481
 *
482
 *      Search connection list of the SAP and finds connection using the remote
483
 *      mac, remote sap, local mac, and local sap. Returns pointer for
484
 *      connection found, %NULL otherwise.
485
 *      Caller has to make sure local_bh is disabled.
486
 */
487
static struct sock *__llc_lookup_established(struct llc_sap *sap,
488
                                             struct llc_addr *daddr,
489
                                             struct llc_addr *laddr)
490
{
491
        struct sock *rc;
492
        struct hlist_node *node;
493
 
494
        read_lock(&sap->sk_list.lock);
495
        sk_for_each(rc, node, &sap->sk_list.list) {
496
                struct llc_sock *llc = llc_sk(rc);
497
 
498
                if (llc->laddr.lsap == laddr->lsap &&
499
                    llc->daddr.lsap == daddr->lsap &&
500
                    llc_mac_match(llc->laddr.mac, laddr->mac) &&
501
                    llc_mac_match(llc->daddr.mac, daddr->mac)) {
502
                        sock_hold(rc);
503
                        goto found;
504
                }
505
        }
506
        rc = NULL;
507
found:
508
        read_unlock(&sap->sk_list.lock);
509
        return rc;
510
}
511
 
512
struct sock *llc_lookup_established(struct llc_sap *sap,
513
                                    struct llc_addr *daddr,
514
                                    struct llc_addr *laddr)
515
{
516
        struct sock *sk;
517
 
518
        local_bh_disable();
519
        sk = __llc_lookup_established(sap, daddr, laddr);
520
        local_bh_enable();
521
        return sk;
522
}
523
 
524
/**
525
 *      llc_lookup_listener - Finds listener for local MAC + SAP
526
 *      @sap: SAP
527
 *      @laddr: address of local LLC (MAC + SAP)
528
 *
529
 *      Search connection list of the SAP and finds connection listening on
530
 *      local mac, and local sap. Returns pointer for parent socket found,
531
 *      %NULL otherwise.
532
 *      Caller has to make sure local_bh is disabled.
533
 */
534
static struct sock *llc_lookup_listener(struct llc_sap *sap,
535
                                        struct llc_addr *laddr)
536
{
537
        struct sock *rc;
538
        struct hlist_node *node;
539
 
540
        read_lock(&sap->sk_list.lock);
541
        sk_for_each(rc, node, &sap->sk_list.list) {
542
                struct llc_sock *llc = llc_sk(rc);
543
 
544
                if (rc->sk_type == SOCK_STREAM && rc->sk_state == TCP_LISTEN &&
545
                    llc->laddr.lsap == laddr->lsap &&
546
                    (llc_mac_match(llc->laddr.mac, laddr->mac) ||
547
                     llc_mac_null(llc->laddr.mac))) {
548
                        sock_hold(rc);
549
                        goto found;
550
                }
551
        }
552
        rc = NULL;
553
found:
554
        read_unlock(&sap->sk_list.lock);
555
        return rc;
556
}
557
 
558
static struct sock *__llc_lookup(struct llc_sap *sap,
559
                                 struct llc_addr *daddr,
560
                                 struct llc_addr *laddr)
561
{
562
        struct sock *sk = __llc_lookup_established(sap, daddr, laddr);
563
 
564
        return sk ? : llc_lookup_listener(sap, laddr);
565
}
566
 
567
/**
568
 *      llc_data_accept_state - designates if in this state data can be sent.
569
 *      @state: state of connection.
570
 *
571
 *      Returns 0 if data can be sent, 1 otherwise.
572
 */
573
u8 llc_data_accept_state(u8 state)
574
{
575
        return state != LLC_CONN_STATE_NORMAL && state != LLC_CONN_STATE_BUSY &&
576
               state != LLC_CONN_STATE_REJ;
577
}
578
 
579
/**
580
 *      llc_find_next_offset - finds offset for next category of transitions
581
 *      @state: state table.
582
 *      @offset: start offset.
583
 *
584
 *      Finds offset of next category of transitions in transition table.
585
 *      Returns the start index of next category.
586
 */
587
static u16 __init llc_find_next_offset(struct llc_conn_state *state, u16 offset)
588
{
589
        u16 cnt = 0;
590
        struct llc_conn_state_trans **next_trans;
591
 
592
        for (next_trans = state->transitions + offset;
593
             (*next_trans)->ev; next_trans++)
594
                ++cnt;
595
        return cnt;
596
}
597
 
598
/**
599
 *      llc_build_offset_table - builds offset table of connection
600
 *
601
 *      Fills offset table of connection state transition table
602
 *      (llc_offset_table).
603
 */
604
void __init llc_build_offset_table(void)
605
{
606
        struct llc_conn_state *curr_state;
607
        int state, ev_type, next_offset;
608
 
609
        for (state = 0; state < NBR_CONN_STATES; state++) {
610
                curr_state = &llc_conn_state_table[state];
611
                next_offset = 0;
612
                for (ev_type = 0; ev_type < NBR_CONN_EV; ev_type++) {
613
                        llc_offset_table[state][ev_type] = next_offset;
614
                        next_offset += llc_find_next_offset(curr_state,
615
                                                            next_offset) + 1;
616
                }
617
        }
618
}
619
 
620
/**
621
 *      llc_find_offset - finds start offset of category of transitions
622
 *      @state: state of connection
623
 *      @ev_type: type of happened event
624
 *
625
 *      Finds start offset of desired category of transitions. Returns the
626
 *      desired start offset.
627
 */
628
static int llc_find_offset(int state, int ev_type)
629
{
630
        int rc = 0;
631
        /* at this stage, llc_offset_table[..][2] is not important. it is for
632
         * init_pf_cycle and I don't know what is it.
633
         */
634
        switch (ev_type) {
635
        case LLC_CONN_EV_TYPE_PRIM:
636
                rc = llc_offset_table[state][0]; break;
637
        case LLC_CONN_EV_TYPE_PDU:
638
                rc = llc_offset_table[state][4]; break;
639
        case LLC_CONN_EV_TYPE_SIMPLE:
640
                rc = llc_offset_table[state][1]; break;
641
        case LLC_CONN_EV_TYPE_P_TMR:
642
        case LLC_CONN_EV_TYPE_ACK_TMR:
643
        case LLC_CONN_EV_TYPE_REJ_TMR:
644
        case LLC_CONN_EV_TYPE_BUSY_TMR:
645
                rc = llc_offset_table[state][3]; break;
646
        }
647
        return rc;
648
}
649
 
650
/**
651
 *      llc_sap_add_socket - adds a socket to a SAP
652
 *      @sap: SAP
653
 *      @sk: socket
654
 *
655
 *      This function adds a socket to sk_list of a SAP.
656
 */
657
void llc_sap_add_socket(struct llc_sap *sap, struct sock *sk)
658
{
659
        llc_sap_hold(sap);
660
        write_lock_bh(&sap->sk_list.lock);
661
        llc_sk(sk)->sap = sap;
662
        sk_add_node(sk, &sap->sk_list.list);
663
        write_unlock_bh(&sap->sk_list.lock);
664
}
665
 
666
/**
667
 *      llc_sap_remove_socket - removes a socket from SAP
668
 *      @sap: SAP
669
 *      @sk: socket
670
 *
671
 *      This function removes a connection from sk_list.list of a SAP if
672
 *      the connection was in this list.
673
 */
674
void llc_sap_remove_socket(struct llc_sap *sap, struct sock *sk)
675
{
676
        write_lock_bh(&sap->sk_list.lock);
677
        sk_del_node_init(sk);
678
        write_unlock_bh(&sap->sk_list.lock);
679
        llc_sap_put(sap);
680
}
681
 
682
/**
683
 *      llc_conn_rcv - sends received pdus to the connection state machine
684
 *      @sk: current connection structure.
685
 *      @skb: received frame.
686
 *
687
 *      Sends received pdus to the connection state machine.
688
 */
689
static int llc_conn_rcv(struct sock* sk, struct sk_buff *skb)
690
{
691
        struct llc_conn_state_ev *ev = llc_conn_ev(skb);
692
 
693
        ev->type   = LLC_CONN_EV_TYPE_PDU;
694
        ev->reason = 0;
695
        return llc_conn_state_process(sk, skb);
696
}
697
 
698
static struct sock *llc_create_incoming_sock(struct sock *sk,
699
                                             struct net_device *dev,
700
                                             struct llc_addr *saddr,
701
                                             struct llc_addr *daddr)
702
{
703
        struct sock *newsk = llc_sk_alloc(sk->sk_net, sk->sk_family, GFP_ATOMIC,
704
                                          sk->sk_prot);
705
        struct llc_sock *newllc, *llc = llc_sk(sk);
706
 
707
        if (!newsk)
708
                goto out;
709
        newllc = llc_sk(newsk);
710
        memcpy(&newllc->laddr, daddr, sizeof(newllc->laddr));
711
        memcpy(&newllc->daddr, saddr, sizeof(newllc->daddr));
712
        newllc->dev = dev;
713
        dev_hold(dev);
714
        llc_sap_add_socket(llc->sap, newsk);
715
        llc_sap_hold(llc->sap);
716
out:
717
        return newsk;
718
}
719
 
720
void llc_conn_handler(struct llc_sap *sap, struct sk_buff *skb)
721
{
722
        struct llc_addr saddr, daddr;
723
        struct sock *sk;
724
 
725
        llc_pdu_decode_sa(skb, saddr.mac);
726
        llc_pdu_decode_ssap(skb, &saddr.lsap);
727
        llc_pdu_decode_da(skb, daddr.mac);
728
        llc_pdu_decode_dsap(skb, &daddr.lsap);
729
 
730
        sk = __llc_lookup(sap, &saddr, &daddr);
731
        if (!sk)
732
                goto drop;
733
 
734
        bh_lock_sock(sk);
735
        /*
736
         * This has to be done here and not at the upper layer ->accept
737
         * method because of the way the PROCOM state machine works:
738
         * it needs to set several state variables (see, for instance,
739
         * llc_adm_actions_2 in net/llc/llc_c_st.c) and send a packet to
740
         * the originator of the new connection, and this state has to be
741
         * in the newly created struct sock private area. -acme
742
         */
743
        if (unlikely(sk->sk_state == TCP_LISTEN)) {
744
                struct sock *newsk = llc_create_incoming_sock(sk, skb->dev,
745
                                                              &saddr, &daddr);
746
                if (!newsk)
747
                        goto drop_unlock;
748
                skb_set_owner_r(skb, newsk);
749
        } else {
750
                /*
751
                 * Can't be skb_set_owner_r, this will be done at the
752
                 * llc_conn_state_process function, later on, when we will use
753
                 * skb_queue_rcv_skb to send it to upper layers, this is
754
                 * another trick required to cope with how the PROCOM state
755
                 * machine works. -acme
756
                 */
757
                skb->sk = sk;
758
        }
759
        if (!sock_owned_by_user(sk))
760
                llc_conn_rcv(sk, skb);
761
        else {
762
                dprintk("%s: adding to backlog...\n", __FUNCTION__);
763
                llc_set_backlog_type(skb, LLC_PACKET);
764
                sk_add_backlog(sk, skb);
765
        }
766
out:
767
        bh_unlock_sock(sk);
768
        sock_put(sk);
769
        return;
770
drop:
771
        kfree_skb(skb);
772
        return;
773
drop_unlock:
774
        kfree_skb(skb);
775
        goto out;
776
}
777
 
778
#undef LLC_REFCNT_DEBUG
779
#ifdef LLC_REFCNT_DEBUG
780
static atomic_t llc_sock_nr;
781
#endif
782
 
783
/**
784
 *      llc_backlog_rcv - Processes rx frames and expired timers.
785
 *      @sk: LLC sock (p8022 connection)
786
 *      @skb: queued rx frame or event
787
 *
788
 *      This function processes frames that has received and timers that has
789
 *      expired during sending an I pdu (refer to data_req_handler).  frames
790
 *      queue by llc_rcv function (llc_mac.c) and timers queue by timer
791
 *      callback functions(llc_c_ac.c).
792
 */
793
static int llc_backlog_rcv(struct sock *sk, struct sk_buff *skb)
794
{
795
        int rc = 0;
796
        struct llc_sock *llc = llc_sk(sk);
797
 
798
        if (likely(llc_backlog_type(skb) == LLC_PACKET)) {
799
                if (likely(llc->state > 1)) /* not closed */
800
                        rc = llc_conn_rcv(sk, skb);
801
                else
802
                        goto out_kfree_skb;
803
        } else if (llc_backlog_type(skb) == LLC_EVENT) {
804
                /* timer expiration event */
805
                if (likely(llc->state > 1))  /* not closed */
806
                        rc = llc_conn_state_process(sk, skb);
807
                else
808
                        goto out_kfree_skb;
809
        } else {
810
                printk(KERN_ERR "%s: invalid skb in backlog\n", __FUNCTION__);
811
                goto out_kfree_skb;
812
        }
813
out:
814
        return rc;
815
out_kfree_skb:
816
        kfree_skb(skb);
817
        goto out;
818
}
819
 
820
/**
821
 *     llc_sk_init - Initializes a socket with default llc values.
822
 *     @sk: socket to initialize.
823
 *
824
 *     Initializes a socket with default llc values.
825
 */
826
static void llc_sk_init(struct sock* sk)
827
{
828
        struct llc_sock *llc = llc_sk(sk);
829
 
830
        llc->state    = LLC_CONN_STATE_ADM;
831
        llc->inc_cntr = llc->dec_cntr = 2;
832
        llc->dec_step = llc->connect_step = 1;
833
 
834
        init_timer(&llc->ack_timer.timer);
835
        llc->ack_timer.expire         = sysctl_llc2_ack_timeout;
836
        llc->ack_timer.timer.data     = (unsigned long)sk;
837
        llc->ack_timer.timer.function = llc_conn_ack_tmr_cb;
838
 
839
        init_timer(&llc->pf_cycle_timer.timer);
840
        llc->pf_cycle_timer.expire         = sysctl_llc2_p_timeout;
841
        llc->pf_cycle_timer.timer.data     = (unsigned long)sk;
842
        llc->pf_cycle_timer.timer.function = llc_conn_pf_cycle_tmr_cb;
843
 
844
        init_timer(&llc->rej_sent_timer.timer);
845
        llc->rej_sent_timer.expire         = sysctl_llc2_rej_timeout;
846
        llc->rej_sent_timer.timer.data     = (unsigned long)sk;
847
        llc->rej_sent_timer.timer.function = llc_conn_rej_tmr_cb;
848
 
849
        init_timer(&llc->busy_state_timer.timer);
850
        llc->busy_state_timer.expire         = sysctl_llc2_busy_timeout;
851
        llc->busy_state_timer.timer.data     = (unsigned long)sk;
852
        llc->busy_state_timer.timer.function = llc_conn_busy_tmr_cb;
853
 
854
        llc->n2 = 2;   /* max retransmit */
855
        llc->k  = 2;   /* tx win size, will adjust dynam */
856
        llc->rw = 128; /* rx win size (opt and equal to
857
                        * tx_win of remote LLC) */
858
        skb_queue_head_init(&llc->pdu_unack_q);
859
        sk->sk_backlog_rcv = llc_backlog_rcv;
860
}
861
 
862
/**
863
 *      llc_sk_alloc - Allocates LLC sock
864
 *      @family: upper layer protocol family
865
 *      @priority: for allocation (%GFP_KERNEL, %GFP_ATOMIC, etc)
866
 *
867
 *      Allocates a LLC sock and initializes it. Returns the new LLC sock
868
 *      or %NULL if there's no memory available for one
869
 */
870
struct sock *llc_sk_alloc(struct net *net, int family, gfp_t priority, struct proto *prot)
871
{
872
        struct sock *sk = sk_alloc(net, family, priority, prot);
873
 
874
        if (!sk)
875
                goto out;
876
        llc_sk_init(sk);
877
        sock_init_data(NULL, sk);
878
#ifdef LLC_REFCNT_DEBUG
879
        atomic_inc(&llc_sock_nr);
880
        printk(KERN_DEBUG "LLC socket %p created in %s, now we have %d alive\n", sk,
881
                __FUNCTION__, atomic_read(&llc_sock_nr));
882
#endif
883
out:
884
        return sk;
885
}
886
 
887
/**
888
 *      llc_sk_free - Frees a LLC socket
889
 *      @sk - socket to free
890
 *
891
 *      Frees a LLC socket
892
 */
893
void llc_sk_free(struct sock *sk)
894
{
895
        struct llc_sock *llc = llc_sk(sk);
896
 
897
        llc->state = LLC_CONN_OUT_OF_SVC;
898
        /* Stop all (possibly) running timers */
899
        llc_conn_ac_stop_all_timers(sk, NULL);
900
#ifdef DEBUG_LLC_CONN_ALLOC
901
        printk(KERN_INFO "%s: unackq=%d, txq=%d\n", __FUNCTION__,
902
                skb_queue_len(&llc->pdu_unack_q),
903
                skb_queue_len(&sk->sk_write_queue));
904
#endif
905
        skb_queue_purge(&sk->sk_receive_queue);
906
        skb_queue_purge(&sk->sk_write_queue);
907
        skb_queue_purge(&llc->pdu_unack_q);
908
#ifdef LLC_REFCNT_DEBUG
909
        if (atomic_read(&sk->sk_refcnt) != 1) {
910
                printk(KERN_DEBUG "Destruction of LLC sock %p delayed in %s, cnt=%d\n",
911
                        sk, __FUNCTION__, atomic_read(&sk->sk_refcnt));
912
                printk(KERN_DEBUG "%d LLC sockets are still alive\n",
913
                        atomic_read(&llc_sock_nr));
914
        } else {
915
                atomic_dec(&llc_sock_nr);
916
                printk(KERN_DEBUG "LLC socket %p released in %s, %d are still alive\n", sk,
917
                        __FUNCTION__, atomic_read(&llc_sock_nr));
918
        }
919
#endif
920
        sock_put(sk);
921
}
922
 
923
/**
924
 *      llc_sk_reset - resets a connection
925
 *      @sk: LLC socket to reset
926
 *
927
 *      Resets a connection to the out of service state. Stops its timers
928
 *      and frees any frames in the queues of the connection.
929
 */
930
void llc_sk_reset(struct sock *sk)
931
{
932
        struct llc_sock *llc = llc_sk(sk);
933
 
934
        llc_conn_ac_stop_all_timers(sk, NULL);
935
        skb_queue_purge(&sk->sk_write_queue);
936
        skb_queue_purge(&llc->pdu_unack_q);
937
        llc->remote_busy_flag   = 0;
938
        llc->cause_flag         = 0;
939
        llc->retry_count        = 0;
940
        llc_conn_set_p_flag(sk, 0);
941
        llc->f_flag             = 0;
942
        llc->s_flag             = 0;
943
        llc->ack_pf             = 0;
944
        llc->first_pdu_Ns       = 0;
945
        llc->ack_must_be_send   = 0;
946
        llc->dec_step           = 1;
947
        llc->inc_cntr           = 2;
948
        llc->dec_cntr           = 2;
949
        llc->X                  = 0;
950
        llc->failed_data_req    = 0 ;
951
        llc->last_nr            = 0;
952
}

powered by: WebSVN 2.1.0

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