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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [net/] [x25/] [x25_link.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   New timer architecture.
18
 *      mar/20/00       Daniela Squassoni Disabling/enabling of facilities
19
 *                                        negotiation.
20
 *      2000-09-04      Henner Eisen      dev_hold() / dev_put() for x25_neigh.
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 <asm/uaccess.h>
40
#include <linux/fcntl.h>
41
#include <linux/mm.h>
42
#include <linux/interrupt.h>
43
#include <linux/init.h>
44
#include <net/x25.h>
45
 
46
static struct x25_neigh *x25_neigh_list /* = NULL initially */;
47
 
48
static void x25_t20timer_expiry(unsigned long);
49
 
50
/*
51
 *      Linux set/reset timer routines
52
 */
53
static void x25_start_t20timer(struct x25_neigh *neigh)
54
{
55
        del_timer(&neigh->t20timer);
56
 
57
        neigh->t20timer.data     = (unsigned long)neigh;
58
        neigh->t20timer.function = &x25_t20timer_expiry;
59
        neigh->t20timer.expires  = jiffies + neigh->t20;
60
 
61
        add_timer(&neigh->t20timer);
62
}
63
 
64
static void x25_t20timer_expiry(unsigned long param)
65
{
66
        struct x25_neigh *neigh = (struct x25_neigh *)param;
67
 
68
        x25_transmit_restart_request(neigh);
69
 
70
        x25_start_t20timer(neigh);
71
}
72
 
73
static void x25_stop_t20timer(struct x25_neigh *neigh)
74
{
75
        del_timer(&neigh->t20timer);
76
}
77
 
78
static int x25_t20timer_pending(struct x25_neigh *neigh)
79
{
80
        return timer_pending(&neigh->t20timer);
81
}
82
 
83
/*
84
 *      This handles all restart and diagnostic frames.
85
 */
86
void x25_link_control(struct sk_buff *skb, struct x25_neigh *neigh, unsigned short frametype)
87
{
88
        struct sk_buff *skbn;
89
        int confirm;
90
 
91
        switch (frametype) {
92
                case X25_RESTART_REQUEST:
93
                        confirm = !x25_t20timer_pending(neigh);
94
                        x25_stop_t20timer(neigh);
95
                        neigh->state = X25_LINK_STATE_3;
96
                        if (confirm) x25_transmit_restart_confirmation(neigh);
97
                        break;
98
 
99
                case X25_RESTART_CONFIRMATION:
100
                        x25_stop_t20timer(neigh);
101
                        neigh->state = X25_LINK_STATE_3;
102
                        break;
103
 
104
                case X25_DIAGNOSTIC:
105
                        printk(KERN_WARNING "x25: diagnostic #%d - %02X %02X %02X\n", skb->data[3], skb->data[4], skb->data[5], skb->data[6]);
106
                        break;
107
 
108
                default:
109
                        printk(KERN_WARNING "x25: received unknown %02X with LCI 000\n", frametype);
110
                        break;
111
        }
112
 
113
        if (neigh->state == X25_LINK_STATE_3) {
114
                while ((skbn = skb_dequeue(&neigh->queue)) != NULL)
115
                        x25_send_frame(skbn, neigh);
116
        }
117
}
118
 
119
/*
120
 *      This routine is called when a Restart Request is needed
121
 */
122
void x25_transmit_restart_request(struct x25_neigh *neigh)
123
{
124
        struct sk_buff *skb;
125
        unsigned char *dptr;
126
        int len;
127
 
128
        len = X25_MAX_L2_LEN + X25_STD_MIN_LEN + 2;
129
 
130
        if ((skb = alloc_skb(len, GFP_ATOMIC)) == NULL)
131
                return;
132
 
133
        skb_reserve(skb, X25_MAX_L2_LEN);
134
 
135
        dptr = skb_put(skb, X25_STD_MIN_LEN + 2);
136
 
137
        *dptr++ = (neigh->extended) ? X25_GFI_EXTSEQ : X25_GFI_STDSEQ;
138
        *dptr++ = 0x00;
139
        *dptr++ = X25_RESTART_REQUEST;
140
        *dptr++ = 0x00;
141
        *dptr++ = 0;
142
 
143
        skb->sk = NULL;
144
 
145
        x25_send_frame(skb, neigh);
146
}
147
 
148
/*
149
 * This routine is called when a Restart Confirmation is needed
150
 */
151
void x25_transmit_restart_confirmation(struct x25_neigh *neigh)
152
{
153
        struct sk_buff *skb;
154
        unsigned char *dptr;
155
        int len;
156
 
157
        len = X25_MAX_L2_LEN + X25_STD_MIN_LEN;
158
 
159
        if ((skb = alloc_skb(len, GFP_ATOMIC)) == NULL)
160
                return;
161
 
162
        skb_reserve(skb, X25_MAX_L2_LEN);
163
 
164
        dptr = skb_put(skb, X25_STD_MIN_LEN);
165
 
166
        *dptr++ = (neigh->extended) ? X25_GFI_EXTSEQ : X25_GFI_STDSEQ;
167
        *dptr++ = 0x00;
168
        *dptr++ = X25_RESTART_CONFIRMATION;
169
 
170
        skb->sk = NULL;
171
 
172
        x25_send_frame(skb, neigh);
173
}
174
 
175
/*
176
 * This routine is called when a Diagnostic is required.
177
 */
178
void x25_transmit_diagnostic(struct x25_neigh *neigh, unsigned char diag)
179
{
180
        struct sk_buff *skb;
181
        unsigned char *dptr;
182
        int len;
183
 
184
        len = X25_MAX_L2_LEN + X25_STD_MIN_LEN + 1;
185
 
186
        if ((skb = alloc_skb(len, GFP_ATOMIC)) == NULL)
187
                return;
188
 
189
        skb_reserve(skb, X25_MAX_L2_LEN);
190
 
191
        dptr = skb_put(skb, X25_STD_MIN_LEN + 1);
192
 
193
        *dptr++ = (neigh->extended) ? X25_GFI_EXTSEQ : X25_GFI_STDSEQ;
194
        *dptr++ = 0x00;
195
        *dptr++ = X25_DIAGNOSTIC;
196
        *dptr++ = diag;
197
 
198
        skb->sk = NULL;
199
 
200
        x25_send_frame(skb, neigh);
201
}
202
 
203
/*
204
 *      This routine is called when a Clear Request is needed outside of the context
205
 *      of a connected socket.
206
 */
207
void x25_transmit_clear_request(struct x25_neigh *neigh, unsigned int lci, unsigned char cause)
208
{
209
        struct sk_buff *skb;
210
        unsigned char *dptr;
211
        int len;
212
 
213
        len = X25_MAX_L2_LEN + X25_STD_MIN_LEN + 2;
214
 
215
        if ((skb = alloc_skb(len, GFP_ATOMIC)) == NULL)
216
                return;
217
 
218
        skb_reserve(skb, X25_MAX_L2_LEN);
219
 
220
        dptr = skb_put(skb, X25_STD_MIN_LEN + 2);
221
 
222
        *dptr++ = ((lci >> 8) & 0x0F) | (neigh->extended ? X25_GFI_EXTSEQ : X25_GFI_STDSEQ);
223
        *dptr++ = ((lci >> 0) & 0xFF);
224
        *dptr++ = X25_CLEAR_REQUEST;
225
        *dptr++ = cause;
226
        *dptr++ = 0x00;
227
 
228
        skb->sk = NULL;
229
 
230
        x25_send_frame(skb, neigh);
231
}
232
 
233
void x25_transmit_link(struct sk_buff *skb, struct x25_neigh *neigh)
234
{
235
        switch (neigh->state) {
236
                case X25_LINK_STATE_0:
237
                        skb_queue_tail(&neigh->queue, skb);
238
                        neigh->state = X25_LINK_STATE_1;
239
                        x25_establish_link(neigh);
240
                        break;
241
                case X25_LINK_STATE_1:
242
                case X25_LINK_STATE_2:
243
                        skb_queue_tail(&neigh->queue, skb);
244
                        break;
245
                case X25_LINK_STATE_3:
246
                        x25_send_frame(skb, neigh);
247
                        break;
248
        }
249
}
250
 
251
/*
252
 *      Called when the link layer has become established.
253
 */
254
void x25_link_established(struct x25_neigh *neigh)
255
{
256
        switch (neigh->state) {
257
                case X25_LINK_STATE_0:
258
                        neigh->state = X25_LINK_STATE_2;
259
                        break;
260
                case X25_LINK_STATE_1:
261
                        x25_transmit_restart_request(neigh);
262
                        neigh->state = X25_LINK_STATE_2;
263
                        x25_start_t20timer(neigh);
264
                        break;
265
        }
266
}
267
 
268
/*
269
 *      Called when the link layer has terminated, or an establishment
270
 *      request has failed.
271
 */
272
 
273
void x25_link_terminated(struct x25_neigh *neigh)
274
{
275
        neigh->state = X25_LINK_STATE_0;
276
        /* Out of order: clear existing virtual calls (X.25 03/93 4.6.3) */
277
        x25_kill_by_neigh(neigh);
278
}
279
 
280
/*
281
 *      Add a new device.
282
 */
283
void x25_link_device_up(struct net_device *dev)
284
{
285
        struct x25_neigh *x25_neigh;
286
        unsigned long flags;
287
 
288
        if ((x25_neigh = kmalloc(sizeof(*x25_neigh), GFP_ATOMIC)) == NULL)
289
                return;
290
 
291
        skb_queue_head_init(&x25_neigh->queue);
292
 
293
        init_timer(&x25_neigh->t20timer);
294
 
295
        dev_hold(dev);
296
        x25_neigh->dev      = dev;
297
        x25_neigh->state    = X25_LINK_STATE_0;
298
        x25_neigh->extended = 0;
299
        x25_neigh->global_facil_mask = (X25_MASK_REVERSE | X25_MASK_THROUGHPUT | X25_MASK_PACKET_SIZE | X25_MASK_WINDOW_SIZE); /* enables negotiation */
300
        x25_neigh->t20      = sysctl_x25_restart_request_timeout;
301
 
302
        save_flags(flags); cli();
303
        x25_neigh->next = x25_neigh_list;
304
        x25_neigh_list  = x25_neigh;
305
        restore_flags(flags);
306
}
307
 
308
static void x25_remove_neigh(struct x25_neigh *x25_neigh)
309
{
310
        struct x25_neigh *s;
311
        unsigned long flags;
312
 
313
        skb_queue_purge(&x25_neigh->queue);
314
 
315
        x25_stop_t20timer(x25_neigh);
316
 
317
        save_flags(flags); cli();
318
 
319
        if ((s = x25_neigh_list) == x25_neigh) {
320
                x25_neigh_list = x25_neigh->next;
321
                restore_flags(flags);
322
                kfree(x25_neigh);
323
                return;
324
        }
325
 
326
        while (s != NULL && s->next != NULL) {
327
                if (s->next == x25_neigh) {
328
                        s->next = x25_neigh->next;
329
                        restore_flags(flags);
330
                        kfree(x25_neigh);
331
                        return;
332
                }
333
 
334
                s = s->next;
335
        }
336
 
337
        restore_flags(flags);
338
}
339
 
340
/*
341
 *      A device has been removed, remove its links.
342
 */
343
void x25_link_device_down(struct net_device *dev)
344
{
345
        struct x25_neigh *neigh, *x25_neigh = x25_neigh_list;
346
 
347
        while (x25_neigh != NULL) {
348
                neigh     = x25_neigh;
349
                x25_neigh = x25_neigh->next;
350
 
351
                if (neigh->dev == dev){
352
                        x25_remove_neigh(neigh);
353
                        dev_put(dev);
354
                }
355
        }
356
}
357
 
358
/*
359
 *      Given a device, return the neighbour address.
360
 */
361
struct x25_neigh *x25_get_neigh(struct net_device *dev)
362
{
363
        struct x25_neigh *x25_neigh;
364
 
365
        for (x25_neigh = x25_neigh_list; x25_neigh != NULL; x25_neigh = x25_neigh->next)
366
                if (x25_neigh->dev == dev)
367
                        return x25_neigh;
368
 
369
        return NULL;
370
}
371
 
372
/*
373
 *      Handle the ioctls that control the subscription functions.
374
 */
375
int x25_subscr_ioctl(unsigned int cmd, void *arg)
376
{
377
        struct x25_subscrip_struct x25_subscr;
378
        struct x25_neigh *x25_neigh;
379
        struct net_device *dev;
380
 
381
        switch (cmd) {
382
 
383
                case SIOCX25GSUBSCRIP:
384
                        if (copy_from_user(&x25_subscr, arg, sizeof(struct x25_subscrip_struct)))
385
                                return -EFAULT;
386
                        if ((dev = x25_dev_get(x25_subscr.device)) == NULL)
387
                                return -EINVAL;
388
                        if ((x25_neigh = x25_get_neigh(dev)) == NULL) {
389
                                dev_put(dev);
390
                                return -EINVAL;
391
                        }
392
                        dev_put(dev);
393
                        x25_subscr.extended = x25_neigh->extended;
394
                        x25_subscr.global_facil_mask = x25_neigh->global_facil_mask;
395
                        if (copy_to_user(arg, &x25_subscr, sizeof(struct x25_subscrip_struct)))
396
                                return -EFAULT;
397
                        break;
398
 
399
                case SIOCX25SSUBSCRIP:
400
                        if (copy_from_user(&x25_subscr, arg, sizeof(struct x25_subscrip_struct)))
401
                                return -EFAULT;
402
                        if ((dev = x25_dev_get(x25_subscr.device)) == NULL)
403
                                return -EINVAL;
404
                        if ((x25_neigh = x25_get_neigh(dev)) == NULL) {
405
                                dev_put(dev);
406
                                return -EINVAL;
407
                        }
408
                        dev_put(dev);
409
                        if (x25_subscr.extended != 0 && x25_subscr.extended != 1)
410
                                return -EINVAL;
411
                        x25_neigh->extended = x25_subscr.extended;
412
                        x25_neigh->global_facil_mask = x25_subscr.global_facil_mask;
413
                        break;
414
 
415
                default:
416
                        return -EINVAL;
417
        }
418
 
419
        return 0;
420
}
421
 
422
 
423
/*
424
 *      Release all memory associated with X.25 neighbour structures.
425
 */
426
void __exit x25_link_free(void)
427
{
428
        struct x25_neigh *neigh, *x25_neigh = x25_neigh_list;
429
 
430
        while (x25_neigh != NULL) {
431
                neigh     = x25_neigh;
432
                x25_neigh = x25_neigh->next;
433
 
434
                x25_remove_neigh(neigh);
435
        }
436
}

powered by: WebSVN 2.1.0

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