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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [net/] [x25/] [x25_subr.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
 *      X.25 Packet Layer release 002
3
 *
4
 *      This is ALPHA test software. This code may break your machine, randomly fail to work with new
5
 *      releases, misbehave and/or generally screw up. It might even work.
6
 *
7
 *      This code REQUIRES 2.1.15 or higher
8
 *
9
 *      This module:
10
 *              This module 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
 *      History
16
 *      X.25 001        Jonathan Naylor   Started coding.
17
 *      X.25 002        Jonathan Naylor   Centralised disconnection processing.
18
 *      mar/20/00       Daniela Squassoni Disabling/enabling of facilities
19
 *                                        negotiation.
20
 *      jun/24/01       Arnaldo C. Melo   use skb_queue_purge, cleanups
21
 */
22
 
23
#include <linux/errno.h>
24
#include <linux/types.h>
25
#include <linux/socket.h>
26
#include <linux/in.h>
27
#include <linux/kernel.h>
28
#include <linux/sched.h>
29
#include <linux/timer.h>
30
#include <linux/string.h>
31
#include <linux/sockios.h>
32
#include <linux/net.h>
33
#include <linux/inet.h>
34
#include <linux/netdevice.h>
35
#include <linux/skbuff.h>
36
#include <net/sock.h>
37
#include <asm/segment.h>
38
#include <asm/system.h>
39
#include <linux/fcntl.h>
40
#include <linux/mm.h>
41
#include <linux/interrupt.h>
42
#include <net/x25.h>
43
 
44
/*
45
 *      This routine purges all of the queues of frames.
46
 */
47
void x25_clear_queues(struct sock *sk)
48
{
49
        skb_queue_purge(&sk->write_queue);
50
        skb_queue_purge(&sk->protinfo.x25->ack_queue);
51
        skb_queue_purge(&sk->protinfo.x25->interrupt_in_queue);
52
        skb_queue_purge(&sk->protinfo.x25->interrupt_out_queue);
53
        skb_queue_purge(&sk->protinfo.x25->fragment_queue);
54
}
55
 
56
 
57
/*
58
 * This routine purges the input queue of those frames that have been
59
 * acknowledged. This replaces the boxes labelled "V(a) <- N(r)" on the
60
 * SDL diagram.
61
*/
62
void x25_frames_acked(struct sock *sk, unsigned short nr)
63
{
64
        struct sk_buff *skb;
65
        int modulus = sk->protinfo.x25->neighbour->extended ? X25_EMODULUS :
66
                                                              X25_SMODULUS;
67
 
68
        /*
69
         * Remove all the ack-ed frames from the ack queue.
70
         */
71
        if (sk->protinfo.x25->va != nr)
72
                while (skb_peek(&sk->protinfo.x25->ack_queue) != NULL &&
73
                       sk->protinfo.x25->va != nr) {
74
                        skb = skb_dequeue(&sk->protinfo.x25->ack_queue);
75
                        kfree_skb(skb);
76
                        sk->protinfo.x25->va = (sk->protinfo.x25->va + 1) %
77
                                                modulus;
78
                }
79
}
80
 
81
void x25_requeue_frames(struct sock *sk)
82
{
83
        struct sk_buff *skb, *skb_prev = NULL;
84
 
85
        /*
86
         * Requeue all the un-ack-ed frames on the output queue to be picked
87
         * up by x25_kick. This arrangement handles the possibility of an empty
88
         * output queue.
89
         */
90
        while ((skb = skb_dequeue(&sk->protinfo.x25->ack_queue)) != NULL) {
91
                if (skb_prev == NULL)
92
                        skb_queue_head(&sk->write_queue, skb);
93
                else
94
                        skb_append(skb_prev, skb);
95
                skb_prev = skb;
96
        }
97
}
98
 
99
/*
100
 *      Validate that the value of nr is between va and vs. Return true or
101
 *      false for testing.
102
 */
103
int x25_validate_nr(struct sock *sk, unsigned short nr)
104
{
105
        unsigned short vc = sk->protinfo.x25->va;
106
        int modulus = sk->protinfo.x25->neighbour->extended ? X25_EMODULUS :
107
                                                              X25_SMODULUS;
108
 
109
        while (vc != sk->protinfo.x25->vs) {
110
                if (nr == vc) return 1;
111
                vc = (vc + 1) % modulus;
112
        }
113
 
114
        return nr == sk->protinfo.x25->vs ? 1 : 0;
115
}
116
 
117
/*
118
 *  This routine is called when the packet layer internally generates a
119
 *  control frame.
120
 */
121
void x25_write_internal(struct sock *sk, int frametype)
122
{
123
        struct sk_buff *skb;
124
        unsigned char  *dptr;
125
        unsigned char  facilities[X25_MAX_FAC_LEN];
126
        unsigned char  addresses[1 + X25_ADDR_LEN];
127
        unsigned char  lci1, lci2;
128
        int len;
129
 
130
        /*
131
         *      Default safe frame size.
132
         */
133
        len = X25_MAX_L2_LEN + X25_EXT_MIN_LEN;
134
 
135
        /*
136
         *      Adjust frame size.
137
         */
138
        switch (frametype) {
139
                case X25_CALL_REQUEST:
140
                        len += 1 + X25_ADDR_LEN + X25_MAX_FAC_LEN +
141
                               X25_MAX_CUD_LEN;
142
                        break;
143
                case X25_CALL_ACCEPTED:
144
                        len += 1 + X25_MAX_FAC_LEN + X25_MAX_CUD_LEN;
145
                        break;
146
                case X25_CLEAR_REQUEST:
147
                case X25_RESET_REQUEST:
148
                        len += 2;
149
                        break;
150
                case X25_RR:
151
                case X25_RNR:
152
                case X25_REJ:
153
                case X25_CLEAR_CONFIRMATION:
154
                case X25_INTERRUPT_CONFIRMATION:
155
                case X25_RESET_CONFIRMATION:
156
                        break;
157
                default:
158
                        printk(KERN_ERR "X.25: invalid frame type %02X\n",
159
                               frametype);
160
                        return;
161
        }
162
 
163
        if ((skb = alloc_skb(len, GFP_ATOMIC)) == NULL)
164
                return;
165
 
166
        /*
167
         *      Space for Ethernet and 802.2 LLC headers.
168
         */
169
        skb_reserve(skb, X25_MAX_L2_LEN);
170
 
171
        /*
172
         *      Make space for the GFI and LCI, and fill them in.
173
         */
174
        dptr = skb_put(skb, 2);
175
 
176
        lci1 = (sk->protinfo.x25->lci >> 8) & 0x0F;
177
        lci2 = (sk->protinfo.x25->lci >> 0) & 0xFF;
178
 
179
        if (sk->protinfo.x25->neighbour->extended) {
180
                *dptr++ = lci1 | X25_GFI_EXTSEQ;
181
                *dptr++ = lci2;
182
        } else {
183
                *dptr++ = lci1 | X25_GFI_STDSEQ;
184
                *dptr++ = lci2;
185
        }
186
 
187
        /*
188
         *      Now fill in the frame type specific information.
189
         */
190
        switch (frametype) {
191
 
192
                case X25_CALL_REQUEST:
193
                        dptr    = skb_put(skb, 1);
194
                        *dptr++ = X25_CALL_REQUEST;
195
                        len     = x25_addr_aton(addresses, &sk->protinfo.x25->dest_addr, &sk->protinfo.x25->source_addr);
196
                        dptr    = skb_put(skb, len);
197
                        memcpy(dptr, addresses, len);
198
                        len     = x25_create_facilities(facilities, &sk->protinfo.x25->facilities, sk->protinfo.x25->neighbour->global_facil_mask);
199
                        dptr    = skb_put(skb, len);
200
                        memcpy(dptr, facilities, len);
201
                        dptr = skb_put(skb, sk->protinfo.x25->calluserdata.cudlength);
202
                        memcpy(dptr, sk->protinfo.x25->calluserdata.cuddata, sk->protinfo.x25->calluserdata.cudlength);
203
                        sk->protinfo.x25->calluserdata.cudlength = 0;
204
                        break;
205
 
206
                case X25_CALL_ACCEPTED:
207
                        dptr    = skb_put(skb, 2);
208
                        *dptr++ = X25_CALL_ACCEPTED;
209
                        *dptr++ = 0x00;         /* Address lengths */
210
                        len     = x25_create_facilities(facilities, &sk->protinfo.x25->facilities, sk->protinfo.x25->vc_facil_mask);
211
                        dptr    = skb_put(skb, len);
212
                        memcpy(dptr, facilities, len);
213
                        dptr = skb_put(skb, sk->protinfo.x25->calluserdata.cudlength);
214
                        memcpy(dptr, sk->protinfo.x25->calluserdata.cuddata, sk->protinfo.x25->calluserdata.cudlength);
215
                        sk->protinfo.x25->calluserdata.cudlength = 0;
216
                        break;
217
 
218
                case X25_CLEAR_REQUEST:
219
                case X25_RESET_REQUEST:
220
                        dptr    = skb_put(skb, 3);
221
                        *dptr++ = frametype;
222
                        *dptr++ = 0x00;         /* XXX */
223
                        *dptr++ = 0x00;         /* XXX */
224
                        break;
225
 
226
                case X25_RR:
227
                case X25_RNR:
228
                case X25_REJ:
229
                        if (sk->protinfo.x25->neighbour->extended) {
230
                                dptr     = skb_put(skb, 2);
231
                                *dptr++  = frametype;
232
                                *dptr++  = (sk->protinfo.x25->vr << 1) & 0xFE;
233
                        } else {
234
                                dptr     = skb_put(skb, 1);
235
                                *dptr    = frametype;
236
                                *dptr++ |= (sk->protinfo.x25->vr << 5) & 0xE0;
237
                        }
238
                        break;
239
 
240
                case X25_CLEAR_CONFIRMATION:
241
                case X25_INTERRUPT_CONFIRMATION:
242
                case X25_RESET_CONFIRMATION:
243
                        dptr  = skb_put(skb, 1);
244
                        *dptr = frametype;
245
                        break;
246
        }
247
 
248
        x25_transmit_link(skb, sk->protinfo.x25->neighbour);
249
}
250
 
251
/*
252
 *      Unpick the contents of the passed X.25 Packet Layer frame.
253
 */
254
int x25_decode(struct sock *sk, struct sk_buff *skb, int *ns, int *nr, int *q,
255
               int *d, int *m)
256
{
257
        unsigned char *frame = skb->data;
258
 
259
        *ns = *nr = *q = *d = *m = 0;
260
 
261
        switch (frame[2]) {
262
                case X25_CALL_REQUEST:
263
                case X25_CALL_ACCEPTED:
264
                case X25_CLEAR_REQUEST:
265
                case X25_CLEAR_CONFIRMATION:
266
                case X25_INTERRUPT:
267
                case X25_INTERRUPT_CONFIRMATION:
268
                case X25_RESET_REQUEST:
269
                case X25_RESET_CONFIRMATION:
270
                case X25_RESTART_REQUEST:
271
                case X25_RESTART_CONFIRMATION:
272
                case X25_REGISTRATION_REQUEST:
273
                case X25_REGISTRATION_CONFIRMATION:
274
                case X25_DIAGNOSTIC:
275
                        return frame[2];
276
        }
277
 
278
        if (sk->protinfo.x25->neighbour->extended) {
279
                if (frame[2] == X25_RR  ||
280
                    frame[2] == X25_RNR ||
281
                    frame[2] == X25_REJ) {
282
                        *nr = (frame[3] >> 1) & 0x7F;
283
                        return frame[2];
284
                }
285
        } else {
286
                if ((frame[2] & 0x1F) == X25_RR  ||
287
                    (frame[2] & 0x1F) == X25_RNR ||
288
                    (frame[2] & 0x1F) == X25_REJ) {
289
                        *nr = (frame[2] >> 5) & 0x07;
290
                        return frame[2] & 0x1F;
291
                }
292
        }
293
 
294
        if (sk->protinfo.x25->neighbour->extended) {
295
                if ((frame[2] & 0x01) == X25_DATA) {
296
                        *q  = (frame[0] & X25_Q_BIT) == X25_Q_BIT;
297
                        *d  = (frame[0] & X25_D_BIT) == X25_D_BIT;
298
                        *m  = (frame[3] & X25_EXT_M_BIT) == X25_EXT_M_BIT;
299
                        *nr = (frame[3] >> 1) & 0x7F;
300
                        *ns = (frame[2] >> 1) & 0x7F;
301
                        return X25_DATA;
302
                }
303
        } else {
304
                if ((frame[2] & 0x01) == X25_DATA) {
305
                        *q  = (frame[0] & X25_Q_BIT) == X25_Q_BIT;
306
                        *d  = (frame[0] & X25_D_BIT) == X25_D_BIT;
307
                        *m  = (frame[2] & X25_STD_M_BIT) == X25_STD_M_BIT;
308
                        *nr = (frame[2] >> 5) & 0x07;
309
                        *ns = (frame[2] >> 1) & 0x07;
310
                        return X25_DATA;
311
                }
312
        }
313
 
314
        printk(KERN_DEBUG "X.25: invalid PLP frame %02X %02X %02X\n",
315
               frame[0], frame[1], frame[2]);
316
 
317
        return X25_ILLEGAL;
318
}
319
 
320
void x25_disconnect(struct sock *sk, int reason, unsigned char cause,
321
                    unsigned char diagnostic)
322
{
323
        x25_clear_queues(sk);
324
        x25_stop_timer(sk);
325
 
326
        sk->protinfo.x25->lci   = 0;
327
        sk->protinfo.x25->state = X25_STATE_0;
328
 
329
        sk->protinfo.x25->causediag.cause      = cause;
330
        sk->protinfo.x25->causediag.diagnostic = diagnostic;
331
 
332
        sk->state     = TCP_CLOSE;
333
        sk->err       = reason;
334
        sk->shutdown |= SEND_SHUTDOWN;
335
 
336
        if (!sk->dead)
337
                sk->state_change(sk);
338
 
339
        sk->dead = 1;
340
}
341
 
342
/*
343
 * Clear an own-rx-busy condition and tell the peer about this, provided
344
 * that there is a significant amount of free receive buffer space available.
345
 */
346
void x25_check_rbuf(struct sock *sk)
347
{
348
        if (atomic_read(&sk->rmem_alloc) < (sk->rcvbuf / 2) &&
349
            (sk->protinfo.x25->condition & X25_COND_OWN_RX_BUSY)) {
350
                sk->protinfo.x25->condition &= ~X25_COND_OWN_RX_BUSY;
351
                sk->protinfo.x25->condition &= ~X25_COND_ACK_PENDING;
352
                sk->protinfo.x25->vl         = sk->protinfo.x25->vr;
353
                x25_write_internal(sk, X25_RR);
354
                x25_stop_timer(sk);
355
        }
356
}

powered by: WebSVN 2.1.0

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