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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [net/] [802/] [llc_sendpdu.c] - 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
 *              llc_sendpdu(), llc_sendipdu(), resend() + queue handling code
7
 *
8
 *              Written by Tim Alpaerts, Tim_Alpaerts@toyota-motor-europe.com
9
 *
10
 *              This program is free software; you can redistribute it and/or
11
 *              modify it under the terms of the GNU General Public License
12
 *              as published by the Free Software Foundation; either version
13
 *              2 of the License, or (at your option) any later version.
14
 *
15
 *      Changes
16
 *              Alan Cox        :       Chainsawed into Linux format, style
17
 *                                      Added llc_ to function names
18
 */
19
 
20
#include <linux/types.h>
21
#include <linux/kernel.h>
22
#include <linux/slab.h>
23
#include <linux/netdevice.h>
24
#include <linux/skbuff.h>
25
#include <net/p8022.h>
26
#include <linux/stat.h>
27
#include <asm/byteorder.h>
28
#include <net/llc_frame.h>
29
#include <net/llc.h>
30
 
31
static unsigned char cntl_byte_encode[] =
32
{
33
        0x00,   /* I_CMD */
34
        0x01,   /* RR_CMD */
35
        0x05,   /* RNR_CMD */
36
        0x09,   /* REJ_CMD */
37
        0x43,   /* DISC_CMD */
38
        0x7F,   /* SABME_CMD */
39
        0x00,   /* I_RSP */
40
        0x01,   /* RR_RSP */
41
        0x05,   /* RNR_RSP */
42
        0x09,   /* REJ_RSP */
43
        0x63,   /* UA_RSP */
44
        0x0F,   /* DM_RSP */
45
        0x87,   /* FRMR_RSP */
46
        0xFF,   /* BAD_FRAME */
47
        0x03,   /* UI_CMD */
48
        0xBF,   /* XID_CMD */
49
        0xE3,   /* TEST_CMD */
50
        0xBF,   /* XID_RSP */
51
        0xE3    /* TEST_RSP */
52
};
53
 
54
static unsigned char fr_length_encode[] =
55
{
56
        0x04,   /* I_CMD */
57
        0x04,   /* RR_CMD */
58
        0x04,   /* RNR_CMD */
59
        0x04,   /* REJ_CMD */
60
        0x03,   /* DISC_CMD */
61
        0x03,   /* SABME_CMD */
62
        0x04,   /* I_RSP */
63
        0x04,   /* RR_RSP */
64
        0x04,   /* RNR_RSP */
65
        0x04,   /* REJ_RSP */
66
        0x03,   /* UA_RSP */
67
        0x03,   /* DM_RSP */
68
        0x03,   /* FRMR_RSP */
69
        0x00,   /* BAD_FRAME */
70
        0x03,   /* UI_CMD */
71
        0x03,   /* XID_CMD */
72
        0x03,   /* TEST_CMD */
73
        0x03,   /* XID_RSP */
74
        0x03    /* TEST_RSP */
75
};
76
 
77
static unsigned char cr_bit_encode[] = {
78
        0x00,   /* I_CMD */
79
        0x00,   /* RR_CMD */
80
        0x00,   /* RNR_CMD */
81
        0x00,   /* REJ_CMD */
82
        0x00,   /* DISC_CMD */
83
        0x00,   /* SABME_CMD */
84
        0x01,   /* I_RSP */
85
        0x01,   /* RR_RSP */
86
        0x01,   /* RNR_RSP */
87
        0x01,   /* REJ_RSP */
88
        0x01,   /* UA_RSP */
89
        0x01,   /* DM_RSP */
90
        0x01,   /* FRMR_RSP */
91
        0x00,   /* BAD_FRAME */
92
        0x00,   /* UI_CMD */
93
        0x00,   /* XID_CMD */
94
        0x00,   /* TEST_CMD */
95
        0x01,   /* XID_RSP */
96
        0x01    /* TEST_RSP */
97
};
98
 
99
/*
100
 *      Sendpdu() constructs an output frame in a new skb and
101
 *      gives it to the MAC layer for transmission.
102
 *      This function is not used to send I pdus.
103
 *      No queues are updated here, nothing is saved for retransmission.
104
 *
105
 *      Parameter pf controls both the poll/final bit and dsap
106
 *      fields in the output pdu.
107
 *      The dsap trick was needed to implement XID_CMD send with
108
 *      zero dsap field as described in doc 6.6 item 1 of enum.
109
 */
110
 
111
void llc_sendpdu(llcptr lp, char type, char pf, int data_len, char *pdu_data)
112
{
113
        frameptr fr;                /* ptr to output pdu buffer */
114
        unsigned short int fl;      /* frame length == 802.3 "length" value */
115
        struct sk_buff *skb;
116
 
117
        fl = data_len + fr_length_encode[(int)type];
118
        skb = alloc_skb(16 + fl, GFP_ATOMIC);
119
        if (skb != NULL)
120
        {
121
                skb->dev = lp->dev;
122
                skb_reserve(skb, 16);
123
                fr = (frameptr) skb_put(skb, fl);
124
                memset(fr, 0, fl);
125
                /*
126
                 *      Construct 802.2 header
127
                 */
128
                if (pf & 0x02)
129
                        fr->pdu_hdr.dsap = 0;
130
                else
131
                        fr->pdu_hdr.dsap = lp->remote_sap;
132
                fr->pdu_hdr.ssap = lp->local_sap + cr_bit_encode[(int)type];
133
                fr->pdu_cntl.byte1 = cntl_byte_encode[(int)type];
134
                /*
135
                 *      Fill in pflag and seq nbrs:
136
                 */
137
                if (IS_SFRAME(fr))
138
                {
139
                        /* case S-frames */
140
                        if (pf & 0x01)
141
                                fr->i_hdr.i_pflag = 1;
142
                        fr->i_hdr.nr = lp->vr;
143
                }
144
                else
145
                {
146
                        /* case U frames */
147
                        if (pf & 0x01)
148
                                fr->u_hdr.u_pflag = 1;
149
                }
150
 
151
                if (data_len > 0)
152
                {                       /* append data if any  */
153
                        if (IS_UFRAME(fr))
154
                        {
155
                                memcpy(fr->u_hdr.u_info, pdu_data, data_len);
156
                        }
157
                        else
158
                        {
159
                                memcpy(fr->i_hdr.is_info, pdu_data, data_len);
160
                        }
161
                }
162
                lp->dev->hard_header(skb, lp->dev, ETH_P_802_3,
163
                         lp->remote_mac, NULL, fl);
164
                skb->dev=lp->dev;
165
                dev_queue_xmit(skb);
166
        }
167
        else
168
                printk(KERN_DEBUG "cl2llc: skb_alloc() in llc_sendpdu() failed\n");
169
}
170
 
171
void llc_xid_request(llcptr lp, char opt, int ll, char * data)
172
{
173
        llc_sendpdu(lp, XID_CMD, opt, ll, data);
174
}
175
 
176
void llc_test_request(llcptr lp, int ll, char * data)
177
{
178
        llc_sendpdu(lp, TEST_CMD, 0, ll, data);
179
}
180
 
181
void llc_unit_data_request(llcptr lp, int ll, char * data)
182
{
183
        llc_sendpdu(lp, UI_CMD, 0, ll, data);
184
}
185
 
186
 
187
/*
188
 *      llc_sendipdu() Completes an I pdu in an existing skb and gives it
189
 *      to the MAC layer for transmission.
190
 *      Parameter "type" must be either I_CMD or I_RSP.
191
 *      The skb is not freed after xmit, it is kept in case a retransmission
192
 *      is requested. If needed it can be picked up again from the rtq.
193
 */
194
 
195
void llc_sendipdu(llcptr lp, char type, char pf, struct sk_buff *skb)
196
{
197
        frameptr fr;                /* ptr to output pdu buffer */
198
        struct sk_buff *tmp;
199
 
200
        fr = (frameptr) skb->data;
201
 
202
        fr->pdu_hdr.dsap = lp->remote_sap;
203
        fr->pdu_hdr.ssap = lp->local_sap + cr_bit_encode[(int)type];
204
        fr->pdu_cntl.byte1 = cntl_byte_encode[(int)type];
205
 
206
        if (pf)
207
                fr->i_hdr.i_pflag = 1; /* p/f and seq numbers */
208
        fr->i_hdr.nr = lp->vr;
209
        fr->i_hdr.ns = lp->vs;
210
        lp->vs++;
211
        if (lp->vs > 127)
212
                lp->vs = 0;
213
        lp->dev->hard_header(skb, lp->dev, ETH_P_802_3,
214
                lp->remote_mac, NULL, skb->len);
215
        ADD_TO_RTQ(skb);                /* add skb to the retransmit queue */
216
        tmp=skb_clone(skb, GFP_ATOMIC);
217
        if(tmp!=NULL)
218
        {
219
                tmp->dev=lp->dev;
220
                dev_queue_xmit(tmp);
221
        }
222
}
223
 
224
 
225
/*
226
 *      Resend_ipdu() will resend the pdus in the retransmit queue (rtq)
227
 *      the return value is the number of pdus resend.
228
 *      ack_nr is N(R) of 1st pdu to resent.
229
 *      Type is I_CMD or I_RSP for 1st pdu resent.
230
 *      p is p/f flag 0 or 1 for 1st pdu resent.
231
 *      All subsequent pdus will be sent as I_CMDs with p/f set to 0
232
 */
233
 
234
int llc_resend_ipdu(llcptr lp, unsigned char ack_nr, unsigned char type, char p)
235
{
236
        struct sk_buff *skb,*tmp;
237
        int resend_count;
238
        frameptr fr;
239
        unsigned long flags;
240
 
241
 
242
        resend_count = 0;
243
 
244
        save_flags(flags);
245
        cli();
246
 
247
        skb = skb_peek(&lp->rtq);
248
 
249
        while(skb && skb != (struct sk_buff *)&lp->rtq)
250
        {
251
                fr = (frameptr) (skb->data + lp->dev->hard_header_len);
252
                if (resend_count == 0)
253
                {
254
                        /*
255
                         *      Resending 1st pdu:
256
                         */
257
 
258
                        if (p)
259
                                fr->i_hdr.i_pflag = 1;
260
                        else
261
                                fr->i_hdr.i_pflag = 0;
262
 
263
                        if (type == I_CMD)
264
                                fr->pdu_hdr.ssap = fr->pdu_hdr.ssap & 0xfe;
265
                        else
266
                                fr->pdu_hdr.ssap = fr->pdu_hdr.ssap | 0x01;
267
                }
268
                else
269
                {
270
                        /*
271
                         *      Resending pdu 2...n
272
                         */
273
 
274
                        fr->pdu_hdr.ssap = fr->pdu_hdr.ssap & 0xfe;
275
                        fr->i_hdr.i_pflag = 0;
276
                }
277
                fr->i_hdr.nr = lp->vr;
278
                fr->i_hdr.ns = lp->vs;
279
                lp->vs++;
280
                if (lp->vs > 127)
281
                        lp->vs = 0;
282
                tmp=skb_clone(skb, GFP_ATOMIC);
283
                if(tmp!=NULL)
284
                {
285
                        tmp->dev = lp->dev;
286
                        dev_queue_xmit(tmp);
287
                }
288
                resend_count++;
289
                skb = skb->next;
290
        }
291
        restore_flags(flags);
292
        return resend_count;
293
}
294
 
295
/* ************** internal queue management code ****************** */
296
 
297
 
298
/*
299
 *      Remove one skb from the front of the awaiting transmit queue
300
 *      (this is the skb longest on the queue) and return a pointer to
301
 *      that skb.
302
 */
303
 
304
struct sk_buff *llc_pull_from_atq(llcptr lp)
305
{
306
        return skb_dequeue(&lp->atq);
307
}
308
 
309
/*
310
 *      Free_acknowledged_skbs(), remove from retransmit queue (rtq)
311
 *      and free all skbs with an N(S) chronologicaly before 'pdu_ack'.
312
 *      The return value is the number of pdus acknowledged.
313
 */
314
 
315
int llc_free_acknowledged_skbs(llcptr lp, unsigned char pdu_ack)
316
{
317
        struct sk_buff *pp;
318
        frameptr fr;
319
        int ack_count;
320
        unsigned char ack;      /* N(S) of most recently ack'ed pdu */
321
        unsigned char ns_save;
322
        unsigned long flags;
323
 
324
        if (pdu_ack > 0)
325
                ack = pdu_ack -1;
326
        else
327
                ack = 127;
328
 
329
        ack_count = 0;
330
 
331
        save_flags(flags);
332
        cli();
333
 
334
        pp = skb_dequeue(&lp->rtq);
335
        while (pp != NULL)
336
        {
337
                /*
338
                 *      Locate skb with N(S) == ack
339
                 */
340
 
341
                /*
342
                 *      BUG: FIXME - use skb->h.*
343
                 */
344
                fr = (frameptr) (pp->data + lp->dev->hard_header_len);
345
                ns_save = fr->i_hdr.ns;
346
 
347
                kfree_skb(pp);
348
                ack_count++;
349
 
350
                if (ns_save == ack)
351
                        break;
352
                pp = skb_dequeue(&lp->rtq);
353
        }
354
        restore_flags(flags);
355
        return ack_count;
356
}
357
 

powered by: WebSVN 2.1.0

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