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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [net/] [802/] [cl2llc.pre] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
 * NET          An implementation of the IEEE 802.2 LLC protocol for the
3
 *              LINUX operating system.  LLC is implemented as a set of
4
 *              state machines and callbacks for higher networking layers.
5
 *
6
 *              Class 2 llc algorithm.
7
 *              Pseudocode interpreter, transition table lookup,
8
 *                      data_request & indicate primitives...
9
 *
10
 *              Code for initialization, termination, registration and
11
 *              MAC layer glue.
12
 *
13
 *              Copyright Tim Alpaerts,
14
 *                      
15
 *
16
 *              This program is free software; you can redistribute it and/or
17
 *              modify it under the terms of the GNU General Public License
18
 *              as published by the Free Software Foundation; either version
19
 *              2 of the License, or (at your option) any later version.
20
 *
21
 *      Changes
22
 *              Alan Cox        :       Chainsawed into Linux format
23
 *                                      Modified to use llc_ names
24
 *                                      Changed callbacks
25
 *
26
 *      This file must be processed by sed before it can be compiled.
27
 */
28
 
29
#include 
30
#include 
31
#include 
32
#include 
33
#include 
34
#include 
35
#include 
36
#include 
37
#include 
38
 
39
#include "pseudo/pseudocode.h"
40
#include "transit/pdutr.h"
41
#include "transit/timertr.h"
42
#include 
43
#include 
44
 
45
/*
46
 *      Data_request() is called by the client to present a data unit
47
 *      to the llc for transmission.
48
 *      In the future this function should also check if the transmit window
49
 *      allows the sending of another pdu, and if not put the skb on the atq
50
 *      for deferred sending.
51
 */
52
 
53
int llc_data_request(llcptr lp, struct sk_buff *skb)
54
{
55
        if (skb_headroom(skb) < (lp->dev->hard_header_len +4)){
56
                printk("cl2llc: data_request() not enough headroom in skb\n");
57
                return -1;
58
        };
59
 
60
        skb_push(skb, 4);
61
 
62
        if ((lp->state != NORMAL) && (lp->state != BUSY) && (lp->state != REJECT))
63
        {
64
                printk("cl2llc: data_request() while no llc connection\n");
65
                return -1;
66
        }
67
 
68
        if (lp->remote_busy)
69
        {     /* if the remote llc is BUSY, */
70
                ADD_TO_ATQ(skb);      /* save skb in the await transmit queue */
71
                return 0;
72
        }
73
        else
74
        {
75
                /*
76
                 *      Else proceed with xmit
77
                 */
78
 
79
                switch(lp->state)
80
                {
81
                        case NORMAL:
82
                                if(lp->p_flag)
83
                                        llc_interpret_pseudo_code(lp, NORMAL2, skb, NO_FRAME);
84
                                else
85
                                        llc_interpret_pseudo_code(lp, NORMAL1, skb, NO_FRAME);
86
                                break;
87
                        case BUSY:
88
                                if (lp->p_flag)
89
                                        llc_interpret_pseudo_code(lp, BUSY2, skb, NO_FRAME);
90
                                else
91
                                        llc_interpret_pseudo_code(lp, BUSY1, skb, NO_FRAME);
92
                                break;
93
                        case REJECT:
94
                                if (lp->p_flag)
95
                                        llc_interpret_pseudo_code(lp, REJECT2, skb, NO_FRAME);
96
                                else
97
                                        llc_interpret_pseudo_code(lp, REJECT1, skb, NO_FRAME);
98
                                break;
99
                        default:;
100
                }
101
                if(lp->llc_callbacks)
102
                {
103
                        lp->llc_event(lp);
104
                        lp->llc_callbacks=0;
105
                }
106
                return 0;
107
        }
108
}
109
 
110
 
111
 
112
/*
113
 *      Disconnect_request() requests that the llc to terminate a connection
114
 */
115
 
116
void disconnect_request(llcptr lp)
117
{
118
        if ((lp->state == NORMAL) ||
119
                (lp->state == BUSY) ||
120
                (lp->state == REJECT) ||
121
                (lp->state == AWAIT) ||
122
                (lp->state == AWAIT_BUSY) ||
123
                (lp->state == AWAIT_REJECT))
124
        {
125
                lp->state = D_CONN;
126
                llc_interpret_pseudo_code(lp, SH1, NULL, NO_FRAME);
127
                if(lp->llc_callbacks)
128
                {
129
                        lp->llc_event(lp);
130
                        lp->llc_callbacks=0;
131
                }
132
                /*
133
                 *      lp may be invalid after the callback
134
                 */
135
        }
136
}
137
 
138
 
139
/*
140
 *      Connect_request() requests that the llc to start a connection
141
 */
142
 
143
void connect_request(llcptr lp)
144
{
145
        if (lp->state == ADM)
146
        {
147
                lp->state = SETUP;
148
                llc_interpret_pseudo_code(lp, ADM1, NULL, NO_FRAME);
149
                if(lp->llc_callbacks)
150
                {
151
                        lp->llc_event(lp);
152
                        lp->llc_callbacks=0;
153
                }
154
                /*
155
                 *      lp may be invalid after the callback
156
                 */
157
        }
158
}
159
 
160
 
161
/*
162
 *      Interpret_pseudo_code() executes the actions in the connection component
163
 *      state transition table. Table 4 in document on p88.
164
 *
165
 *      If this function is called to handle an incoming pdu, skb will point
166
 *      to the buffer with the pdu and type will contain the decoded pdu type.
167
 *
168
 *      If called by data_request skb points to an skb that was skb_alloc-ed by
169
 *      the llc client to hold the information unit to be transmitted, there is
170
 *      no valid type in this case.
171
 *
172
 *      If called because a timer expired no skb is passed, and there is no
173
 *      type.
174
 */
175
 
176
void llc_interpret_pseudo_code(llcptr lp, int pc_label, struct sk_buff *skb,
177
                char type)
178
{
179
        short int pc;   /* program counter in pseudo code array */
180
        char p_flag_received;
181
        frameptr fr;
182
        int resend_count;   /* number of pdus resend by llc_resend_ipdu() */
183
        int ack_count;      /* number of pdus acknowledged */
184
        struct sk_buff *skb2;
185
 
186
        if (skb != NULL)
187
        {
188
                fr = (frameptr) skb->data;
189
        }
190
        else
191
                fr = NULL;
192
 
193
        pc = pseudo_code_idx[pc_label];
194
        while(pseudo_code[pc])
195
        {
196
                switch(pseudo_code[pc])
197
                {
198
                        case IF_F=1_CLEAR_REMOTE_BUSY:
199
                                if ((type != I_CMD) || (fr->i_hdr.i_pflag == 0))
200
                                        break;
201
                        case CLEAR_REMOTE_BUSY:
202
                                lp->remote_busy = 0;
203
                                llc_stop_timer(lp, BUSY_TIMER);
204
                                if ((lp->state == NORMAL) ||
205
                                        (lp->state == REJECT) ||
206
                                        (lp->state == BUSY))
207
                                {
208
                                        skb2 = llc_pull_from_atq(lp);
209
                                        if (skb2 != NULL)
210
                                                llc_start_timer(lp, ACK_TIMER);
211
                                        while (skb2 != NULL)
212
                                        {
213
                                                llc_sendipdu( lp, I_CMD, 0, skb2);
214
                                                skb2 = llc_pull_from_atq(lp);
215
                                        }
216
                                }
217
                                break;
218
                        case CONNECT_INDICATION:
219
                                lp->state = NORMAL;  /* needed to eliminate connect_response() */
220
                                lp->llc_mode = MODE_ABM;
221
                                lp->llc_callbacks|=LLC_CONN_INDICATION;
222
                                break;
223
                        case CONNECT_CONFIRM:
224
                                lp->llc_mode = MODE_ABM;
225
                                lp->llc_callbacks|=LLC_CONN_CONFIRM;
226
                                break;
227
                        case DATA_INDICATION:
228
                                skb_pull(skb, 4);
229
                                lp->inc_skb=skb;
230
                                lp->llc_callbacks|=LLC_DATA_INDIC;
231
                                break;
232
                        case DISCONNECT_INDICATION:
233
                                lp->llc_mode = MODE_ADM;
234
                                lp->llc_callbacks|=LLC_DISC_INDICATION;
235
                                break;
236
                        case RESET_INDICATION(LOCAL):
237
                                lp->llc_callbacks|=LLC_RESET_INDIC_LOC;
238
                                break;
239
                        case RESET_INDICATION(REMOTE):
240
                                lp->llc_callbacks|=LLC_RESET_INDIC_REM;
241
                                break;
242
                        case RESET_CONFIRM:
243
                                lp->llc_callbacks|=LLC_RST_CONFIRM;
244
                                break;
245
                        case REPORT_STATUS(FRMR_RECEIVED):
246
                                lp->llc_callbacks|=LLC_FRMR_RECV;
247
                                break;
248
                        case REPORT_STATUS(FRMR_SENT):
249
                                lp->llc_callbacks|=LLC_FRMR_SENT;
250
                                break;
251
                        case REPORT_STATUS(REMOTE_BUSY):
252
                                lp->llc_callbacks|=LLC_REMOTE_BUSY;
253
                                break;
254
                        case REPORT_STATUS(REMOTE_NOT_BUSY):
255
                                lp->llc_callbacks|=LLC_REMOTE_NOTBUSY;
256
                                break;
257
                        case SEND_DISC_CMD(P=X):
258
                                llc_sendpdu(lp, DISC_CMD, lp->f_flag, 0, NULL);
259
                                break;
260
                        case SEND_DM_RSP(F=X):
261
                                llc_sendpdu(lp, DM_RSP, 0, 0, NULL);
262
                                break;
263
                        case SEND_FRMR_RSP(F=X):
264
                                lp->frmr_info_fld.cntl1 = fr->pdu_cntl.byte1;
265
                                lp->frmr_info_fld.cntl2 = fr->pdu_cntl.byte2;
266
                                lp->frmr_info_fld.vs = lp->vs;
267
                                lp->frmr_info_fld.vr_cr = lp->vr;
268
                                llc_sendpdu(lp, FRMR_RSP, 0, 5, (char *) &lp->frmr_info_fld);
269
                                break;
270
                        case RE-SEND_FRMR_RSP(F=0):
271
                                llc_sendpdu(lp, FRMR_RSP, 0, 5, (char *) &lp->frmr_info_fld);
272
                                break;
273
                        case RE-SEND_FRMR_RSP(F=P):
274
                                llc_sendpdu(lp, FRMR_RSP, lp->p_flag,
275
                                        5, (char *) &lp->frmr_info_fld);
276
                                break;
277
                        case SEND_I_CMD(P=1):
278
                                llc_sendipdu(lp, I_CMD, 1, skb);
279
                                break;
280
                        case RE-SEND_I_CMD(P=1):
281
                                resend_count = llc_resend_ipdu(lp, fr->i_hdr.nr, I_CMD, 1);
282
                                break;
283
                        case RE-SEND_I_CMD(P=1)_OR_SEND_RR:
284
                                resend_count = llc_resend_ipdu(lp, fr->i_hdr.nr, I_CMD, 1);
285
                                if (resend_count == 0)
286
                                {
287
                                        llc_sendpdu(lp, RR_CMD, 1, 0, NULL);
288
                                }
289
                                break;
290
                        case SEND_I_XXX(X=0):
291
                                llc_sendipdu(lp, I_CMD, 0, skb);
292
                                break;
293
                        case RE-SEND_I_XXX(X=0):
294
                                resend_count = llc_resend_ipdu(lp, fr->i_hdr.nr, I_CMD, 0);
295
                                break;
296
                        case RE-SEND_I_XXX(X=0)_OR_SEND_RR:
297
                                resend_count = llc_resend_ipdu(lp, fr->i_hdr.nr, I_CMD, 0);
298
                                if (resend_count == 0)
299
                                {
300
                                        llc_sendpdu(lp, RR_CMD, 0, 0, NULL);
301
                                }
302
                                break;
303
                        case RE-SEND_I_RSP(F=1):
304
                                resend_count = llc_resend_ipdu(lp, fr->i_hdr.nr, I_RSP, 1);
305
                                break;
306
                        case SEND_REJ_CMD(P=1):
307
                                llc_sendpdu(lp, REJ_CMD, 1, 0, NULL);
308
                                break;
309
                        case SEND_REJ_RSP(F=1):
310
                                llc_sendpdu(lp, REJ_RSP, 1, 0, NULL);
311
                                break;
312
                        case SEND_REJ_XXX(X=0):
313
                                if (IS_RSP(fr))
314
                                        llc_sendpdu(lp, REJ_CMD, 0, 0, NULL);
315
                                else
316
                                        llc_sendpdu(lp, REJ_RSP, 0, 0, NULL);
317
                                break;
318
                        case SEND_RNR_CMD(F=1):
319
                                llc_sendpdu(lp, RNR_CMD, 1, 0, NULL);
320
                                break;
321
                        case SEND_RNR_RSP(F=1):
322
                                llc_sendpdu(lp, RNR_RSP, 1, 0, NULL);
323
                                break;
324
                        case SEND_RNR_XXX(X=0):
325
                                if (IS_RSP(fr))
326
                                        llc_sendpdu(lp, RNR_CMD, 0, 0, NULL);
327
                                else
328
                                        llc_sendpdu(lp, RNR_RSP, 0, 0, NULL);
329
                                break;
330
                        case SET_REMOTE_BUSY:
331
                                if (lp->remote_busy == 0)
332
                                {
333
                                        lp->remote_busy = 1;
334
                                        llc_start_timer(lp, BUSY_TIMER);
335
                                        lp->llc_callbacks|=LLC_REMOTE_BUSY;
336
                                }
337
                                else if (lp->timer_state[BUSY_TIMER] == TIMER_IDLE)
338
                                {
339
                                        llc_start_timer(lp, BUSY_TIMER);
340
                                }
341
                                break;
342
                        case OPTIONAL_SEND_RNR_XXX(X=0):
343
                                if (IS_RSP(fr))
344
                                        llc_sendpdu(lp, RNR_CMD, 0, 0, NULL);
345
                                else
346
                                        llc_sendpdu(lp, RNR_RSP, 0, 0, NULL);
347
                                break;
348
                        case SEND_RR_CMD(P=1):
349
                                llc_sendpdu(lp, RR_CMD, 1, 0, NULL);
350
                                break;
351
                        case SEND_ACKNOWLEDGE_CMD(P=1):
352
                                llc_sendpdu(lp, RR_CMD, 1, 0, NULL);
353
                                break;
354
                        case SEND_RR_RSP(F=1):
355
                                llc_sendpdu(lp, RR_RSP, 1, 0, NULL);
356
                                break;
357
                        case SEND_ACKNOWLEDGE_RSP(F=1):
358
                                llc_sendpdu(lp, RR_RSP, 1, 0, NULL);
359
                                break;
360
                        case SEND_RR_XXX(X=0):
361
                                llc_sendpdu(lp, RR_RSP, 0, 0, NULL);
362
                                break;
363
                        case SEND_ACKNOWLEDGE_XXX(X=0):
364
                                if (IS_RSP(fr))
365
                                        llc_sendpdu(lp, RR_CMD, 0, 0, NULL);
366
                                else
367
                                        llc_sendpdu(lp, RR_RSP, 0, 0, NULL);
368
                                break;
369
                        case SEND_SABME_CMD(P=X):
370
                                llc_sendpdu(lp, SABME_CMD, 0, 0, NULL);
371
                                lp->f_flag = 0;
372
                                break;
373
                        case SEND_UA_RSP(F=X):
374
                                llc_sendpdu(lp, UA_RSP, lp->f_flag, 0, NULL);
375
                                break;
376
                        case S_FLAG:=0:
377
                                lp->s_flag = 0;
378
                                break;
379
                        case S_FLAG:=1:
380
                                lp->s_flag = 1;
381
                                break;
382
                        case START_P_TIMER:
383
                                if(lp->timer_state[P_TIMER] == TIMER_RUNNING)
384
                                        llc_stop_timer(lp, P_TIMER);
385
                                llc_start_timer(lp, P_TIMER);
386
                                if (lp->p_flag == 0)
387
                                {
388
                                        lp->retry_count = 0;
389
                                        lp->p_flag = 1;
390
                                }
391
                                break;
392
                        case START_ACK_TIMER_IF_NOT_RUNNING:
393
                                if (lp->timer_state[ACK_TIMER] == TIMER_IDLE)
394
                                        llc_start_timer(lp, ACK_TIMER);
395
                                break;
396
                        case START_ACK_TIMER:
397
                                llc_start_timer(lp, ACK_TIMER);
398
                                break;
399
                        case START_REJ_TIMER:
400
                                llc_start_timer(lp, REJ_TIMER);
401
                                break;
402
                        case STOP_ACK_TIMER:
403
                                llc_stop_timer(lp, ACK_TIMER);
404
                                break;
405
                        case STOP_P_TIMER:
406
                                llc_stop_timer(lp, ACK_TIMER);
407
                                lp->p_flag = 0;
408
                                break;
409
                        case IF_DATA_FLAG=2_STOP_REJ_TIMER:
410
                                if (lp->data_flag == 2)
411
                                        llc_stop_timer(lp, REJ_TIMER);
412
                                break;
413
                        case STOP_REJ_TIMER:
414
                                llc_stop_timer(lp, REJ_TIMER);
415
                                break;
416
                        case STOP_ALL_TIMERS:
417
                                llc_stop_timer(lp, ACK_TIMER);
418
                                llc_stop_timer(lp, P_TIMER);
419
                                llc_stop_timer(lp, REJ_TIMER);
420
                                llc_stop_timer(lp, BUSY_TIMER);
421
                                break;
422
                        case STOP_OTHER_TIMERS:
423
                                llc_stop_timer(lp, P_TIMER);
424
                                llc_stop_timer(lp, REJ_TIMER);
425
                                llc_stop_timer(lp, BUSY_TIMER);
426
                                break;
427
                        case UPDATE_N(R)_RECEIVED:
428
                                ack_count = llc_free_acknowledged_skbs(lp,
429
                                        (unsigned char) fr->s_hdr.nr);
430
                                if (ack_count > 0)
431
                                {
432
                                        lp->retry_count = 0;
433
                                        llc_stop_timer(lp, ACK_TIMER);
434
                                        if (skb_peek(&lp->rtq) != NULL)
435
                                        {
436
                                                /*
437
                                                 *      Re-transmit queue not empty
438
                                                 */
439
                                                llc_start_timer(lp, ACK_TIMER);
440
                                        }
441
                                }
442
                                break;
443
                        case UPDATE_P_FLAG:
444
                                if (IS_UFRAME(fr))
445
                                        p_flag_received = fr->u_hdr.u_pflag;
446
                                else
447
                                        p_flag_received = fr->i_hdr.i_pflag;
448
                                if ((fr->pdu_hdr.ssap & 0x01) && (p_flag_received))
449
                                {
450
                                        lp->p_flag = 0;
451
                                        llc_stop_timer(lp, P_TIMER);
452
                                }
453
                                break;
454
                        case DATA_FLAG:=2:
455
                                lp->data_flag = 2;
456
                                break;
457
                        case DATA_FLAG:=0:
458
                                lp->data_flag = 0;
459
                                break;
460
                        case DATA_FLAG:=1:
461
                                lp->data_flag = 1;
462
                                break;
463
                        case IF_DATA_FLAG_=0_THEN_DATA_FLAG:=1:
464
                                if (lp->data_flag == 0)
465
                                        lp->data_flag = 1;
466
                                break;
467
                        case P_FLAG:=0:
468
                                lp->p_flag = 0;
469
                                break;
470
                        case P_FLAG:=P:
471
                                lp->p_flag = lp->f_flag;
472
                                break;
473
                        case REMOTE_BUSY:=0:
474
                                lp->remote_busy = 0;
475
                                break;
476
                        case RETRY_COUNT:=0:
477
                                lp->retry_count = 0;
478
                                break;
479
                        case RETRY_COUNT:=RETRY_COUNT+1:
480
                                lp->retry_count++;
481
                                break;
482
                        case V(R):=0:
483
                                lp->vr = 0;
484
                                break;
485
                        case V(R):=V(R)+1:
486
                                lp->vr++;
487
                                break;
488
                        case V(S):=0:
489
                                lp->vs = 0;
490
                                break;
491
                        case V(S):=N(R):
492
                                lp->vs = fr->i_hdr.nr;
493
                                break;
494
                        case F_FLAG:=P:
495
                                if (IS_UFRAME(fr))
496
                                        lp->f_flag = fr->u_hdr.u_pflag;
497
                                else
498
                                        lp->f_flag = fr->i_hdr.i_pflag;
499
                                break;
500
                        default:;
501
                }
502
                pc++;
503
        }
504
}
505
 
506
 
507
/*
508
 *      Process_otype2_frame will handle incoming frames
509
 *      for 802.2 Type 2 Procedure.
510
 */
511
 
512
void llc_process_otype2_frame(llcptr lp, struct sk_buff *skb, char type)
513
{
514
        int idx;                /*      index in transition table */
515
        int pc_label;           /*      action to perform, from tr tbl */
516
        int validation;         /*      result of validate_seq_nos */
517
        int p_flag_received;    /*      p_flag in received frame */
518
        frameptr fr;
519
 
520
        fr = (frameptr) skb->data;
521
 
522
        if (IS_UFRAME(fr))
523
                p_flag_received = fr->u_hdr.u_pflag;
524
        else
525
                p_flag_received = fr->i_hdr.i_pflag;
526
 
527
        switch(lp->state)
528
        {
529
                /*      Compute index in transition table: */
530
                case ADM:
531
                        idx = type;
532
                        idx = (idx << 1) + p_flag_received;
533
                        break;
534
                case CONN:
535
                case RESET_WAIT:
536
                case RESET_CHECK:
537
                case ERROR:
538
                        idx = type;
539
                        break;
540
                case SETUP:
541
                case RESET:
542
                case D_CONN:
543
                        idx = type;
544
                        idx = (idx << 1) + lp->p_flag;
545
                        break;
546
                case NORMAL:
547
                case BUSY:
548
                case REJECT:
549
                case AWAIT:
550
                case AWAIT_BUSY:
551
                case AWAIT_REJECT:
552
                        validation = llc_validate_seq_nos(lp, fr);
553
                        if (validation > 3)
554
                                type = BAD_FRAME;
555
                        idx = type;
556
                        idx = (idx << 1);
557
                        if (validation & 1)
558
                                idx = idx +1;
559
                        idx = (idx << 1) + p_flag_received;
560
                        idx = (idx << 1) + lp->p_flag;
561
                default:
562
                        printk("llc_proc: bad state\n");
563
                        return;
564
        }
565
        idx = (idx << 1) + pdutr_offset[lp->state];
566
        lp->state = pdutr_entry[idx +1];
567
        pc_label = pdutr_entry[idx];
568
        if (pc_label != NOP)
569
        {
570
                llc_interpret_pseudo_code(lp, pc_label, skb, type);
571
                if(lp->llc_callbacks)
572
                {
573
                        lp->llc_event(lp);
574
                        lp->llc_callbacks=0;
575
                }
576
                /*
577
                 *      lp may no longer be valid after this point. Be
578
                 *      careful what is added!
579
                 */
580
        }
581
}
582
 
583
 
584
void llc_timer_expired(llcptr lp, int t)
585
{
586
        int idx;                /* index in transition table    */
587
        int pc_label;           /* action to perform, from tr tbl */
588
 
589
        lp->timer_state[t] = TIMER_EXPIRED;
590
        idx = lp->state;            /* Compute index in transition table: */
591
        idx = (idx << 2) + t;
592
        idx = idx << 1;
593
        if (lp->retry_count >= lp->n2)
594
                idx = idx + 1;
595
        idx = (idx << 1) + lp->s_flag;
596
        idx = (idx << 1) + lp->p_flag;
597
        idx = idx << 1;             /* 2 bytes per entry: action & newstate */
598
 
599
        pc_label = timertr_entry[idx];
600
        if (pc_label != NOP)
601
        {
602
                llc_interpret_pseudo_code(lp, pc_label, NULL, NO_FRAME);
603
                lp->state = timertr_entry[idx +1];
604
        }
605
        lp->timer_state[t] = TIMER_IDLE;
606
        if(lp->llc_callbacks)
607
        {
608
                lp->llc_event(lp);
609
                lp->llc_callbacks=0;
610
        }
611
        /*
612
         *      And lp may have vanished in the event callback
613
         */
614
}
615
 

powered by: WebSVN 2.1.0

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