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

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [net/] [llc/] [llc_station.c] - Blame information for rev 62

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/*
2
 * llc_station.c - station component of LLC
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
#include <linux/init.h>
15
#include <linux/module.h>
16
#include <net/llc.h>
17
#include <net/llc_sap.h>
18
#include <net/llc_conn.h>
19
#include <net/llc_c_ac.h>
20
#include <net/llc_s_ac.h>
21
#include <net/llc_c_ev.h>
22
#include <net/llc_c_st.h>
23
#include <net/llc_s_ev.h>
24
#include <net/llc_s_st.h>
25
#include <net/llc_pdu.h>
26
 
27
/**
28
 * struct llc_station - LLC station component
29
 *
30
 * SAP and connection resource manager, one per adapter.
31
 *
32
 * @state - state of station
33
 * @xid_r_count - XID response PDU counter
34
 * @mac_sa - MAC source address
35
 * @sap_list - list of related SAPs
36
 * @ev_q - events entering state mach.
37
 * @mac_pdu_q - PDUs ready to send to MAC
38
 */
39
struct llc_station {
40
        u8                          state;
41
        u8                          xid_r_count;
42
        struct timer_list           ack_timer;
43
        u8                          retry_count;
44
        u8                          maximum_retry;
45
        struct {
46
                struct sk_buff_head list;
47
                spinlock_t          lock;
48
        } ev_q;
49
        struct sk_buff_head         mac_pdu_q;
50
};
51
 
52
#define LLC_STATION_ACK_TIME (3 * HZ)
53
 
54
int sysctl_llc_station_ack_timeout = LLC_STATION_ACK_TIME;
55
 
56
/* Types of events (possible values in 'ev->type') */
57
#define LLC_STATION_EV_TYPE_SIMPLE      1
58
#define LLC_STATION_EV_TYPE_CONDITION   2
59
#define LLC_STATION_EV_TYPE_PRIM        3
60
#define LLC_STATION_EV_TYPE_PDU         4       /* command/response PDU */
61
#define LLC_STATION_EV_TYPE_ACK_TMR     5
62
#define LLC_STATION_EV_TYPE_RPT_STATUS  6
63
 
64
/* Events */
65
#define LLC_STATION_EV_ENABLE_WITH_DUP_ADDR_CHECK               1
66
#define LLC_STATION_EV_ENABLE_WITHOUT_DUP_ADDR_CHECK            2
67
#define LLC_STATION_EV_ACK_TMR_EXP_LT_RETRY_CNT_MAX_RETRY       3
68
#define LLC_STATION_EV_ACK_TMR_EXP_EQ_RETRY_CNT_MAX_RETRY       4
69
#define LLC_STATION_EV_RX_NULL_DSAP_XID_C                       5
70
#define LLC_STATION_EV_RX_NULL_DSAP_0_XID_R_XID_R_CNT_EQ        6
71
#define LLC_STATION_EV_RX_NULL_DSAP_1_XID_R_XID_R_CNT_EQ        7
72
#define LLC_STATION_EV_RX_NULL_DSAP_TEST_C                      8
73
#define LLC_STATION_EV_DISABLE_REQ                              9
74
 
75
struct llc_station_state_ev {
76
        u8               type;
77
        u8               prim;
78
        u8               prim_type;
79
        u8               reason;
80
        struct list_head node; /* node in station->ev_q.list */
81
};
82
 
83
static __inline__ struct llc_station_state_ev *
84
                                        llc_station_ev(struct sk_buff *skb)
85
{
86
        return (struct llc_station_state_ev *)skb->cb;
87
}
88
 
89
typedef int (*llc_station_ev_t)(struct sk_buff *skb);
90
 
91
#define LLC_STATION_STATE_DOWN          1       /* initial state */
92
#define LLC_STATION_STATE_DUP_ADDR_CHK  2
93
#define LLC_STATION_STATE_UP            3
94
 
95
#define LLC_NBR_STATION_STATES          3       /* size of state table */
96
 
97
typedef int (*llc_station_action_t)(struct sk_buff *skb);
98
 
99
/* Station component state table structure */
100
struct llc_station_state_trans {
101
        llc_station_ev_t ev;
102
        u8 next_state;
103
        llc_station_action_t *ev_actions;
104
};
105
 
106
struct llc_station_state {
107
        u8 curr_state;
108
        struct llc_station_state_trans **transitions;
109
};
110
 
111
static struct llc_station llc_main_station;
112
 
113
static int llc_stat_ev_enable_with_dup_addr_check(struct sk_buff *skb)
114
{
115
        struct llc_station_state_ev *ev = llc_station_ev(skb);
116
 
117
        return ev->type == LLC_STATION_EV_TYPE_SIMPLE &&
118
               ev->prim_type ==
119
                              LLC_STATION_EV_ENABLE_WITH_DUP_ADDR_CHECK ? 0 : 1;
120
}
121
 
122
static int llc_stat_ev_enable_without_dup_addr_check(struct sk_buff *skb)
123
{
124
        struct llc_station_state_ev *ev = llc_station_ev(skb);
125
 
126
        return ev->type == LLC_STATION_EV_TYPE_SIMPLE &&
127
               ev->prim_type ==
128
                        LLC_STATION_EV_ENABLE_WITHOUT_DUP_ADDR_CHECK ? 0 : 1;
129
}
130
 
131
static int llc_stat_ev_ack_tmr_exp_lt_retry_cnt_max_retry(struct sk_buff *skb)
132
{
133
        struct llc_station_state_ev *ev = llc_station_ev(skb);
134
 
135
        return ev->type == LLC_STATION_EV_TYPE_ACK_TMR &&
136
                llc_main_station.retry_count <
137
                llc_main_station.maximum_retry ? 0 : 1;
138
}
139
 
140
static int llc_stat_ev_ack_tmr_exp_eq_retry_cnt_max_retry(struct sk_buff *skb)
141
{
142
        struct llc_station_state_ev *ev = llc_station_ev(skb);
143
 
144
        return ev->type == LLC_STATION_EV_TYPE_ACK_TMR &&
145
                llc_main_station.retry_count ==
146
                llc_main_station.maximum_retry ? 0 : 1;
147
}
148
 
149
static int llc_stat_ev_rx_null_dsap_xid_c(struct sk_buff *skb)
150
{
151
        struct llc_station_state_ev *ev = llc_station_ev(skb);
152
        struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
153
 
154
        return ev->type == LLC_STATION_EV_TYPE_PDU &&
155
               LLC_PDU_IS_CMD(pdu) &&                   /* command PDU */
156
               LLC_PDU_TYPE_IS_U(pdu) &&                /* U type PDU */
157
               LLC_U_PDU_CMD(pdu) == LLC_1_PDU_CMD_XID &&
158
               !pdu->dsap ? 0 : 1;                       /* NULL DSAP value */
159
}
160
 
161
static int llc_stat_ev_rx_null_dsap_0_xid_r_xid_r_cnt_eq(struct sk_buff *skb)
162
{
163
        struct llc_station_state_ev *ev = llc_station_ev(skb);
164
        struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
165
 
166
        return ev->type == LLC_STATION_EV_TYPE_PDU &&
167
               LLC_PDU_IS_RSP(pdu) &&                   /* response PDU */
168
               LLC_PDU_TYPE_IS_U(pdu) &&                /* U type PDU */
169
               LLC_U_PDU_RSP(pdu) == LLC_1_PDU_CMD_XID &&
170
               !pdu->dsap &&                            /* NULL DSAP value */
171
               !llc_main_station.xid_r_count ? 0 : 1;
172
}
173
 
174
static int llc_stat_ev_rx_null_dsap_1_xid_r_xid_r_cnt_eq(struct sk_buff *skb)
175
{
176
        struct llc_station_state_ev *ev = llc_station_ev(skb);
177
        struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
178
 
179
        return ev->type == LLC_STATION_EV_TYPE_PDU &&
180
               LLC_PDU_IS_RSP(pdu) &&                   /* response PDU */
181
               LLC_PDU_TYPE_IS_U(pdu) &&                /* U type PDU */
182
               LLC_U_PDU_RSP(pdu) == LLC_1_PDU_CMD_XID &&
183
               !pdu->dsap &&                            /* NULL DSAP value */
184
               llc_main_station.xid_r_count == 1 ? 0 : 1;
185
}
186
 
187
static int llc_stat_ev_rx_null_dsap_test_c(struct sk_buff *skb)
188
{
189
        struct llc_station_state_ev *ev = llc_station_ev(skb);
190
        struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
191
 
192
        return ev->type == LLC_STATION_EV_TYPE_PDU &&
193
               LLC_PDU_IS_CMD(pdu) &&                   /* command PDU */
194
               LLC_PDU_TYPE_IS_U(pdu) &&                /* U type PDU */
195
               LLC_U_PDU_CMD(pdu) == LLC_1_PDU_CMD_TEST &&
196
               !pdu->dsap ? 0 : 1;                       /* NULL DSAP */
197
}
198
 
199
static int llc_stat_ev_disable_req(struct sk_buff *skb)
200
{
201
        struct llc_station_state_ev *ev = llc_station_ev(skb);
202
 
203
        return ev->type == LLC_STATION_EV_TYPE_PRIM &&
204
               ev->prim == LLC_DISABLE_PRIM &&
205
               ev->prim_type == LLC_PRIM_TYPE_REQ ? 0 : 1;
206
}
207
 
208
/**
209
 *      llc_station_send_pdu - queues PDU to send
210
 *      @skb: Address of the PDU
211
 *
212
 *      Queues a PDU to send to the MAC layer.
213
 */
214
static void llc_station_send_pdu(struct sk_buff *skb)
215
{
216
        skb_queue_tail(&llc_main_station.mac_pdu_q, skb);
217
        while ((skb = skb_dequeue(&llc_main_station.mac_pdu_q)) != NULL)
218
                if (dev_queue_xmit(skb))
219
                        break;
220
}
221
 
222
static int llc_station_ac_start_ack_timer(struct sk_buff *skb)
223
{
224
        mod_timer(&llc_main_station.ack_timer,
225
                  jiffies + sysctl_llc_station_ack_timeout);
226
        return 0;
227
}
228
 
229
static int llc_station_ac_set_retry_cnt_0(struct sk_buff *skb)
230
{
231
        llc_main_station.retry_count = 0;
232
        return 0;
233
}
234
 
235
static int llc_station_ac_inc_retry_cnt_by_1(struct sk_buff *skb)
236
{
237
        llc_main_station.retry_count++;
238
        return 0;
239
}
240
 
241
static int llc_station_ac_set_xid_r_cnt_0(struct sk_buff *skb)
242
{
243
        llc_main_station.xid_r_count = 0;
244
        return 0;
245
}
246
 
247
static int llc_station_ac_inc_xid_r_cnt_by_1(struct sk_buff *skb)
248
{
249
        llc_main_station.xid_r_count++;
250
        return 0;
251
}
252
 
253
static int llc_station_ac_send_null_dsap_xid_c(struct sk_buff *skb)
254
{
255
        int rc = 1;
256
        struct sk_buff *nskb = llc_alloc_frame(NULL, skb->dev);
257
 
258
        if (!nskb)
259
                goto out;
260
        llc_pdu_header_init(nskb, LLC_PDU_TYPE_U, 0, 0, LLC_PDU_CMD);
261
        llc_pdu_init_as_xid_cmd(nskb, LLC_XID_NULL_CLASS_2, 127);
262
        rc = llc_mac_hdr_init(nskb, llc_station_mac_sa, llc_station_mac_sa);
263
        if (unlikely(rc))
264
                goto free;
265
        llc_station_send_pdu(nskb);
266
out:
267
        return rc;
268
free:
269
        kfree_skb(skb);
270
        goto out;
271
}
272
 
273
static int llc_station_ac_send_xid_r(struct sk_buff *skb)
274
{
275
        u8 mac_da[ETH_ALEN], dsap;
276
        int rc = 1;
277
        struct sk_buff* nskb = llc_alloc_frame(NULL, skb->dev);
278
 
279
        if (!nskb)
280
                goto out;
281
        rc = 0;
282
        llc_pdu_decode_sa(skb, mac_da);
283
        llc_pdu_decode_ssap(skb, &dsap);
284
        llc_pdu_header_init(nskb, LLC_PDU_TYPE_U, 0, dsap, LLC_PDU_RSP);
285
        llc_pdu_init_as_xid_rsp(nskb, LLC_XID_NULL_CLASS_2, 127);
286
        rc = llc_mac_hdr_init(nskb, llc_station_mac_sa, mac_da);
287
        if (unlikely(rc))
288
                goto free;
289
        llc_station_send_pdu(nskb);
290
out:
291
        return rc;
292
free:
293
        kfree_skb(skb);
294
        goto out;
295
}
296
 
297
static int llc_station_ac_send_test_r(struct sk_buff *skb)
298
{
299
        u8 mac_da[ETH_ALEN], dsap;
300
        int rc = 1;
301
        struct sk_buff *nskb = llc_alloc_frame(NULL, skb->dev);
302
 
303
        if (!nskb)
304
                goto out;
305
        rc = 0;
306
        llc_pdu_decode_sa(skb, mac_da);
307
        llc_pdu_decode_ssap(skb, &dsap);
308
        llc_pdu_header_init(nskb, LLC_PDU_TYPE_U, 0, dsap, LLC_PDU_RSP);
309
        llc_pdu_init_as_test_rsp(nskb, skb);
310
        rc = llc_mac_hdr_init(nskb, llc_station_mac_sa, mac_da);
311
        if (unlikely(rc))
312
                goto free;
313
        llc_station_send_pdu(nskb);
314
out:
315
        return rc;
316
free:
317
        kfree_skb(skb);
318
        goto out;
319
}
320
 
321
static int llc_station_ac_report_status(struct sk_buff *skb)
322
{
323
        return 0;
324
}
325
 
326
/* COMMON STATION STATE transitions */
327
 
328
/* dummy last-transition indicator; common to all state transition groups
329
 * last entry for this state
330
 * all members are zeros, .bss zeroes it
331
 */
332
static struct llc_station_state_trans llc_stat_state_trans_end;
333
 
334
/* DOWN STATE transitions */
335
 
336
/* state transition for LLC_STATION_EV_ENABLE_WITH_DUP_ADDR_CHECK event */
337
static llc_station_action_t llc_stat_down_state_actions_1[] = {
338
        [0] = llc_station_ac_start_ack_timer,
339
        [1] = llc_station_ac_set_retry_cnt_0,
340
        [2] = llc_station_ac_set_xid_r_cnt_0,
341
        [3] = llc_station_ac_send_null_dsap_xid_c,
342
        [4] = NULL,
343
};
344
 
345
static struct llc_station_state_trans llc_stat_down_state_trans_1 = {
346
        .ev         = llc_stat_ev_enable_with_dup_addr_check,
347
        .next_state = LLC_STATION_STATE_DUP_ADDR_CHK,
348
        .ev_actions = llc_stat_down_state_actions_1,
349
};
350
 
351
/* state transition for LLC_STATION_EV_ENABLE_WITHOUT_DUP_ADDR_CHECK event */
352
static llc_station_action_t llc_stat_down_state_actions_2[] = {
353
        [0] = llc_station_ac_report_status,      /* STATION UP */
354
        [1] = NULL,
355
};
356
 
357
static struct llc_station_state_trans llc_stat_down_state_trans_2 = {
358
        .ev         = llc_stat_ev_enable_without_dup_addr_check,
359
        .next_state = LLC_STATION_STATE_UP,
360
        .ev_actions = llc_stat_down_state_actions_2,
361
};
362
 
363
/* array of pointers; one to each transition */
364
static struct llc_station_state_trans *llc_stat_dwn_state_trans[] = {
365
        [0] = &llc_stat_down_state_trans_1,
366
        [1] = &llc_stat_down_state_trans_2,
367
        [2] = &llc_stat_state_trans_end,
368
};
369
 
370
/* UP STATE transitions */
371
/* state transition for LLC_STATION_EV_DISABLE_REQ event */
372
static llc_station_action_t llc_stat_up_state_actions_1[] = {
373
        [0] = llc_station_ac_report_status,      /* STATION DOWN */
374
        [1] = NULL,
375
};
376
 
377
static struct llc_station_state_trans llc_stat_up_state_trans_1 = {
378
        .ev         = llc_stat_ev_disable_req,
379
        .next_state = LLC_STATION_STATE_DOWN,
380
        .ev_actions = llc_stat_up_state_actions_1,
381
};
382
 
383
/* state transition for LLC_STATION_EV_RX_NULL_DSAP_XID_C event */
384
static llc_station_action_t llc_stat_up_state_actions_2[] = {
385
        [0] = llc_station_ac_send_xid_r,
386
        [1] = NULL,
387
};
388
 
389
static struct llc_station_state_trans llc_stat_up_state_trans_2 = {
390
        .ev         = llc_stat_ev_rx_null_dsap_xid_c,
391
        .next_state = LLC_STATION_STATE_UP,
392
        .ev_actions = llc_stat_up_state_actions_2,
393
};
394
 
395
/* state transition for LLC_STATION_EV_RX_NULL_DSAP_TEST_C event */
396
static llc_station_action_t llc_stat_up_state_actions_3[] = {
397
        [0] = llc_station_ac_send_test_r,
398
        [1] = NULL,
399
};
400
 
401
static struct llc_station_state_trans llc_stat_up_state_trans_3 = {
402
        .ev         = llc_stat_ev_rx_null_dsap_test_c,
403
        .next_state = LLC_STATION_STATE_UP,
404
        .ev_actions = llc_stat_up_state_actions_3,
405
};
406
 
407
/* array of pointers; one to each transition */
408
static struct llc_station_state_trans *llc_stat_up_state_trans [] = {
409
        [0] = &llc_stat_up_state_trans_1,
410
        [1] = &llc_stat_up_state_trans_2,
411
        [2] = &llc_stat_up_state_trans_3,
412
        [3] = &llc_stat_state_trans_end,
413
};
414
 
415
/* DUP ADDR CHK STATE transitions */
416
/* state transition for LLC_STATION_EV_RX_NULL_DSAP_0_XID_R_XID_R_CNT_EQ
417
 * event
418
 */
419
static llc_station_action_t llc_stat_dupaddr_state_actions_1[] = {
420
        [0] = llc_station_ac_inc_xid_r_cnt_by_1,
421
        [1] = NULL,
422
};
423
 
424
static struct llc_station_state_trans llc_stat_dupaddr_state_trans_1 = {
425
        .ev         = llc_stat_ev_rx_null_dsap_0_xid_r_xid_r_cnt_eq,
426
        .next_state = LLC_STATION_STATE_DUP_ADDR_CHK,
427
        .ev_actions = llc_stat_dupaddr_state_actions_1,
428
};
429
 
430
/* state transition for LLC_STATION_EV_RX_NULL_DSAP_1_XID_R_XID_R_CNT_EQ
431
 * event
432
 */
433
static llc_station_action_t llc_stat_dupaddr_state_actions_2[] = {
434
        [0] = llc_station_ac_report_status,      /* DUPLICATE ADDRESS FOUND */
435
        [1] = NULL,
436
};
437
 
438
static struct llc_station_state_trans llc_stat_dupaddr_state_trans_2 = {
439
        .ev         = llc_stat_ev_rx_null_dsap_1_xid_r_xid_r_cnt_eq,
440
        .next_state = LLC_STATION_STATE_DOWN,
441
        .ev_actions = llc_stat_dupaddr_state_actions_2,
442
};
443
 
444
/* state transition for LLC_STATION_EV_RX_NULL_DSAP_XID_C event */
445
static llc_station_action_t llc_stat_dupaddr_state_actions_3[] = {
446
        [0] = llc_station_ac_send_xid_r,
447
        [1] = NULL,
448
};
449
 
450
static struct llc_station_state_trans llc_stat_dupaddr_state_trans_3 = {
451
        .ev         = llc_stat_ev_rx_null_dsap_xid_c,
452
        .next_state = LLC_STATION_STATE_DUP_ADDR_CHK,
453
        .ev_actions = llc_stat_dupaddr_state_actions_3,
454
};
455
 
456
/* state transition for LLC_STATION_EV_ACK_TMR_EXP_LT_RETRY_CNT_MAX_RETRY
457
 * event
458
 */
459
static llc_station_action_t llc_stat_dupaddr_state_actions_4[] = {
460
        [0] = llc_station_ac_start_ack_timer,
461
        [1] = llc_station_ac_inc_retry_cnt_by_1,
462
        [2] = llc_station_ac_set_xid_r_cnt_0,
463
        [3] = llc_station_ac_send_null_dsap_xid_c,
464
        [4] = NULL,
465
};
466
 
467
static struct llc_station_state_trans llc_stat_dupaddr_state_trans_4 = {
468
        .ev         = llc_stat_ev_ack_tmr_exp_lt_retry_cnt_max_retry,
469
        .next_state = LLC_STATION_STATE_DUP_ADDR_CHK,
470
        .ev_actions = llc_stat_dupaddr_state_actions_4,
471
};
472
 
473
/* state transition for LLC_STATION_EV_ACK_TMR_EXP_EQ_RETRY_CNT_MAX_RETRY
474
 * event
475
 */
476
static llc_station_action_t llc_stat_dupaddr_state_actions_5[] = {
477
        [0] = llc_station_ac_report_status,      /* STATION UP */
478
        [1] = NULL,
479
};
480
 
481
static struct llc_station_state_trans llc_stat_dupaddr_state_trans_5 = {
482
        .ev         = llc_stat_ev_ack_tmr_exp_eq_retry_cnt_max_retry,
483
        .next_state = LLC_STATION_STATE_UP,
484
        .ev_actions = llc_stat_dupaddr_state_actions_5,
485
};
486
 
487
/* state transition for LLC_STATION_EV_DISABLE_REQ event */
488
static llc_station_action_t llc_stat_dupaddr_state_actions_6[] = {
489
        [0] = llc_station_ac_report_status,      /* STATION DOWN */
490
        [1] = NULL,
491
};
492
 
493
static struct llc_station_state_trans llc_stat_dupaddr_state_trans_6 = {
494
        .ev         = llc_stat_ev_disable_req,
495
        .next_state = LLC_STATION_STATE_DOWN,
496
        .ev_actions = llc_stat_dupaddr_state_actions_6,
497
};
498
 
499
/* array of pointers; one to each transition */
500
static struct llc_station_state_trans *llc_stat_dupaddr_state_trans[] = {
501
        [0] = &llc_stat_dupaddr_state_trans_6,   /* Request */
502
        [1] = &llc_stat_dupaddr_state_trans_4,  /* Timer */
503
        [2] = &llc_stat_dupaddr_state_trans_5,
504
        [3] = &llc_stat_dupaddr_state_trans_1,  /* Receive frame */
505
        [4] = &llc_stat_dupaddr_state_trans_2,
506
        [5] = &llc_stat_dupaddr_state_trans_3,
507
        [6] = &llc_stat_state_trans_end,
508
};
509
 
510
static struct llc_station_state
511
                        llc_station_state_table[LLC_NBR_STATION_STATES] = {
512
        [LLC_STATION_STATE_DOWN - 1] = {
513
                .curr_state  = LLC_STATION_STATE_DOWN,
514
                .transitions = llc_stat_dwn_state_trans,
515
        },
516
        [LLC_STATION_STATE_DUP_ADDR_CHK - 1] = {
517
                .curr_state  = LLC_STATION_STATE_DUP_ADDR_CHK,
518
                .transitions = llc_stat_dupaddr_state_trans,
519
        },
520
        [LLC_STATION_STATE_UP - 1] = {
521
                .curr_state  = LLC_STATION_STATE_UP,
522
                .transitions = llc_stat_up_state_trans,
523
        },
524
};
525
 
526
/**
527
 *      llc_exec_station_trans_actions - executes actions for transition
528
 *      @trans: Address of the transition
529
 *      @skb: Address of the event that caused the transition
530
 *
531
 *      Executes actions of a transition of the station state machine. Returns
532
 *      0 if all actions complete successfully, nonzero otherwise.
533
 */
534
static u16 llc_exec_station_trans_actions(struct llc_station_state_trans *trans,
535
                                          struct sk_buff *skb)
536
{
537
        u16 rc = 0;
538
        llc_station_action_t *next_action = trans->ev_actions;
539
 
540
        for (; next_action && *next_action; next_action++)
541
                if ((*next_action)(skb))
542
                        rc = 1;
543
        return rc;
544
}
545
 
546
/**
547
 *      llc_find_station_trans - finds transition for this event
548
 *      @skb: Address of the event
549
 *
550
 *      Search thru events of the current state of the station until list
551
 *      exhausted or it's obvious that the event is not valid for the current
552
 *      state. Returns the address of the transition if cound, %NULL otherwise.
553
 */
554
static struct llc_station_state_trans *
555
                                llc_find_station_trans(struct sk_buff *skb)
556
{
557
        int i = 0;
558
        struct llc_station_state_trans *rc = NULL;
559
        struct llc_station_state_trans **next_trans;
560
        struct llc_station_state *curr_state =
561
                                &llc_station_state_table[llc_main_station.state - 1];
562
 
563
        for (next_trans = curr_state->transitions; next_trans[i]->ev; i++)
564
                if (!next_trans[i]->ev(skb)) {
565
                        rc = next_trans[i];
566
                        break;
567
                }
568
        return rc;
569
}
570
 
571
/**
572
 *      llc_station_free_ev - frees an event
573
 *      @skb: Address of the event
574
 *
575
 *      Frees an event.
576
 */
577
static void llc_station_free_ev(struct sk_buff *skb)
578
{
579
        struct llc_station_state_ev *ev = llc_station_ev(skb);
580
 
581
        if (ev->type == LLC_STATION_EV_TYPE_PDU)
582
                kfree_skb(skb);
583
}
584
 
585
/**
586
 *      llc_station_next_state - processes event and goes to the next state
587
 *      @skb: Address of the event
588
 *
589
 *      Processes an event, executes any transitions related to that event and
590
 *      updates the state of the station.
591
 */
592
static u16 llc_station_next_state(struct sk_buff *skb)
593
{
594
        u16 rc = 1;
595
        struct llc_station_state_trans *trans;
596
 
597
        if (llc_main_station.state > LLC_NBR_STATION_STATES)
598
                goto out;
599
        trans = llc_find_station_trans(skb);
600
        if (trans) {
601
                /* got the state to which we next transition; perform the
602
                 * actions associated with this transition before actually
603
                 * transitioning to the next state
604
                 */
605
                rc = llc_exec_station_trans_actions(trans, skb);
606
                if (!rc)
607
                        /* transition station to next state if all actions
608
                         * execute successfully; done; wait for next event
609
                         */
610
                        llc_main_station.state = trans->next_state;
611
        } else
612
                /* event not recognized in current state; re-queue it for
613
                 * processing again at a later time; return failure
614
                 */
615
                rc = 0;
616
out:
617
        llc_station_free_ev(skb);
618
        return rc;
619
}
620
 
621
/**
622
 *      llc_station_service_events - service events in the queue
623
 *
624
 *      Get an event from the station event queue (if any); attempt to service
625
 *      the event; if event serviced, get the next event (if any) on the event
626
 *      queue; if event not service, re-queue the event on the event queue and
627
 *      attempt to service the next event; when serviced all events in queue,
628
 *      finished; if don't transition to different state, just service all
629
 *      events once; if transition to new state, service all events again.
630
 *      Caller must hold llc_main_station.ev_q.lock.
631
 */
632
static void llc_station_service_events(void)
633
{
634
        struct sk_buff *skb;
635
 
636
        while ((skb = skb_dequeue(&llc_main_station.ev_q.list)) != NULL)
637
                llc_station_next_state(skb);
638
}
639
 
640
/**
641
 *      llc_station_state_process: queue event and try to process queue.
642
 *      @skb: Address of the event
643
 *
644
 *      Queues an event (on the station event queue) for handling by the
645
 *      station state machine and attempts to process any queued-up events.
646
 */
647
static void llc_station_state_process(struct sk_buff *skb)
648
{
649
        spin_lock_bh(&llc_main_station.ev_q.lock);
650
        skb_queue_tail(&llc_main_station.ev_q.list, skb);
651
        llc_station_service_events();
652
        spin_unlock_bh(&llc_main_station.ev_q.lock);
653
}
654
 
655
static void llc_station_ack_tmr_cb(unsigned long timeout_data)
656
{
657
        struct sk_buff *skb = alloc_skb(0, GFP_ATOMIC);
658
 
659
        if (skb) {
660
                struct llc_station_state_ev *ev = llc_station_ev(skb);
661
 
662
                ev->type = LLC_STATION_EV_TYPE_ACK_TMR;
663
                llc_station_state_process(skb);
664
        }
665
}
666
 
667
/*
668
 *      llc_station_rcv - send received pdu to the station state machine
669
 *      @skb: received frame.
670
 *
671
 *      Sends data unit to station state machine.
672
 */
673
static void llc_station_rcv(struct sk_buff *skb)
674
{
675
        struct llc_station_state_ev *ev = llc_station_ev(skb);
676
 
677
        ev->type   = LLC_STATION_EV_TYPE_PDU;
678
        ev->reason = 0;
679
        llc_station_state_process(skb);
680
}
681
 
682
int __init llc_station_init(void)
683
{
684
        u16 rc = -ENOBUFS;
685
        struct sk_buff *skb;
686
        struct llc_station_state_ev *ev;
687
 
688
        skb_queue_head_init(&llc_main_station.mac_pdu_q);
689
        skb_queue_head_init(&llc_main_station.ev_q.list);
690
        spin_lock_init(&llc_main_station.ev_q.lock);
691
        init_timer(&llc_main_station.ack_timer);
692
        llc_main_station.ack_timer.data     = (unsigned long)&llc_main_station;
693
        llc_main_station.ack_timer.function = llc_station_ack_tmr_cb;
694
        llc_main_station.ack_timer.expires  = jiffies +
695
                                                sysctl_llc_station_ack_timeout;
696
        skb = alloc_skb(0, GFP_ATOMIC);
697
        if (!skb)
698
                goto out;
699
        rc = 0;
700
        llc_set_station_handler(llc_station_rcv);
701
        ev = llc_station_ev(skb);
702
        memset(ev, 0, sizeof(*ev));
703
        llc_main_station.maximum_retry  = 1;
704
        llc_main_station.state          = LLC_STATION_STATE_DOWN;
705
        ev->type        = LLC_STATION_EV_TYPE_SIMPLE;
706
        ev->prim_type   = LLC_STATION_EV_ENABLE_WITHOUT_DUP_ADDR_CHECK;
707
        rc = llc_station_next_state(skb);
708
out:
709
        return rc;
710
}
711
 
712
void __exit llc_station_exit(void)
713
{
714
        llc_set_station_handler(NULL);
715
}

powered by: WebSVN 2.1.0

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