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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [uclinux/] [uClinux-2.0.x/] [net/] [rose/] [rose_link.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 199 simons
/*
2
 *      ROSE release 003
3
 *
4
 *      This code REQUIRES 2.1.0 or higher/ NET3.029
5
 *
6
 *      This module:
7
 *              This module is free software; you can redistribute it and/or
8
 *              modify it under the terms of the GNU General Public License
9
 *              as published by the Free Software Foundation; either version
10
 *              2 of the License, or (at your option) any later version.
11
 *
12
 *      History
13
 *      ROSE 001        Jonathan(G4KLX) Cloned from rose_timer.c
14
 */
15
 
16
#include <linux/config.h>
17
#if defined(CONFIG_ROSE) || defined(CONFIG_ROSE_MODULE)
18
#include <linux/errno.h>
19
#include <linux/types.h>
20
#include <linux/socket.h>
21
#include <linux/in.h>
22
#include <linux/kernel.h>
23
#include <linux/sched.h>
24
#include <linux/timer.h>
25
#include <linux/string.h>
26
#include <linux/sockios.h>
27
#include <linux/net.h>
28
#include <net/ax25.h>
29
#include <linux/inet.h>
30
#include <linux/netdevice.h>
31
#include <linux/skbuff.h>
32
#include <net/sock.h>
33
#include <asm/segment.h>
34
#include <asm/system.h>
35
#include <linux/fcntl.h>
36
#include <linux/mm.h>
37
#include <linux/interrupt.h>
38
#include <linux/firewall.h>
39
#include <net/rose.h>
40
 
41
static void rose_link_timer(unsigned long);
42
 
43
/*
44
 *      Linux set timer
45
 */
46
void rose_link_set_timer(struct rose_neigh *neigh)
47
{
48
        unsigned long flags;
49
 
50
        save_flags(flags); cli();
51
        del_timer(&neigh->timer);
52
        restore_flags(flags);
53
 
54
        neigh->timer.data     = (unsigned long)neigh;
55
        neigh->timer.function = &rose_link_timer;
56
        neigh->timer.expires  = jiffies + 10;
57
 
58
        add_timer(&neigh->timer);
59
}
60
 
61
/*
62
 *      ROSE Link Timer
63
 *
64
 *      This routine is called every 100ms. Decrement timer by this
65
 *      amount - if expired then process the event.
66
 */
67
static void rose_link_timer(unsigned long param)
68
{
69
        struct rose_neigh *neigh = (struct rose_neigh *)param;
70
 
71
        if (neigh->ftimer > 0)
72
                neigh->ftimer--;
73
 
74
        if (neigh->t0timer > 0) {
75
                neigh->t0timer--;
76
 
77
                if (neigh->t0timer == 0) {
78
                        rose_transmit_restart_request(neigh);
79
                        neigh->dce_mode = 0;
80
                        neigh->t0timer  = sysctl_rose_restart_request_timeout;
81
                }
82
        }
83
 
84
        if (neigh->ftimer > 0 || neigh->t0timer > 0)
85
                rose_link_set_timer(neigh);
86
        else
87
                del_timer(&neigh->timer);
88
}
89
 
90
/*
91
 *      Interface to ax25_send_frame. Changes my level 2 callsign depending
92
 *      on whether we have a global ROSE callsign or use the default port
93
 *      callsign.
94
 */
95
static int rose_send_frame(struct sk_buff *skb, struct rose_neigh *neigh)
96
{
97
        ax25_address *rose_call;
98
 
99
        if (ax25cmp(&rose_callsign, &null_ax25_address) == 0)
100
                rose_call = (ax25_address *)neigh->dev->dev_addr;
101
        else
102
                rose_call = &rose_callsign;
103
 
104
        neigh->ax25 = ax25_send_frame(skb, 260, rose_call, &neigh->callsign, neigh->digipeat, neigh->dev);
105
 
106
        return (neigh->ax25 != NULL);
107
}
108
 
109
/*
110
 *      Interface to ax25_link_up. Changes my level 2 callsign depending
111
 *      on whether we have a global ROSE callsign or use the default port
112
 *      callsign.
113
 */
114
static int rose_link_up(struct rose_neigh *neigh)
115
{
116
        ax25_address *rose_call;
117
 
118
        if (ax25cmp(&rose_callsign, &null_ax25_address) == 0)
119
                rose_call = (ax25_address *)neigh->dev->dev_addr;
120
        else
121
                rose_call = &rose_callsign;
122
 
123
        neigh->ax25 = ax25_find_cb(rose_call, &neigh->callsign, neigh->digipeat, neigh->dev);
124
 
125
        return (neigh->ax25 != NULL);
126
}
127
 
128
/*
129
 *      This handles all restart and diagnostic frames.
130
 */
131
void rose_link_rx_restart(struct sk_buff *skb, struct rose_neigh *neigh, unsigned short frametype)
132
{
133
        struct sk_buff *skbn;
134
 
135
        switch (frametype) {
136
                case ROSE_RESTART_REQUEST:
137
                        /* Stop all existing routes on this link - F6FBB */
138
                        rose_clean_neighbour(neigh);
139
                        neigh->t0timer   = 0;
140
                        neigh->restarted = 1;
141
                        neigh->dce_mode  = (skb->data[3] == ROSE_DTE_ORIGINATED);
142
                        del_timer(&neigh->timer);
143
                        rose_transmit_restart_confirmation(neigh);
144
                        break;
145
 
146
                case ROSE_RESTART_CONFIRMATION:
147
                        neigh->t0timer   = 0;
148
                        neigh->restarted = 1;
149
                        del_timer(&neigh->timer);
150
                        break;
151
 
152
                case ROSE_DIAGNOSTIC:
153
                        printk(KERN_WARNING "rose: diagnostic #%d - %02X %02X %02X\n", skb->data[3], skb->data[4], skb->data[5], skb->data[6]);
154
                        break;
155
 
156
                default:
157
                        printk(KERN_WARNING "rose: received unknown %02X with LCI 000\n", frametype);
158
                        break;
159
        }
160
 
161
        if (neigh->restarted) {
162
                while ((skbn = skb_dequeue(&neigh->queue)) != NULL)
163
                        if (!rose_send_frame(skbn, neigh))
164
                                kfree_skb(skbn, FREE_WRITE);
165
        }
166
}
167
 
168
/*
169
 *      This routine is called when a Restart Request is needed
170
 */
171
void rose_transmit_restart_request(struct rose_neigh *neigh)
172
{
173
        struct sk_buff *skb;
174
        unsigned char *dptr;
175
        int len;
176
 
177
        len = AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + ROSE_MIN_LEN + 3;
178
 
179
        if ((skb = alloc_skb(len, GFP_ATOMIC)) == NULL)
180
                return;
181
 
182
        skb->free = 1;
183
 
184
        skb_reserve(skb, AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN);
185
 
186
        dptr = skb_put(skb, ROSE_MIN_LEN + 3);
187
 
188
        *dptr++ = AX25_P_ROSE;
189
        *dptr++ = ROSE_GFI;
190
        *dptr++ = 0x00;
191
        *dptr++ = ROSE_RESTART_REQUEST;
192
        *dptr++ = ROSE_DTE_ORIGINATED;
193
        *dptr++ = 0;
194
 
195
        if (!rose_send_frame(skb, neigh))
196
                kfree_skb(skb, FREE_WRITE);
197
}
198
 
199
/*
200
 * This routine is called when a Restart Confirmation is needed
201
 */
202
void rose_transmit_restart_confirmation(struct rose_neigh *neigh)
203
{
204
        struct sk_buff *skb;
205
        unsigned char *dptr;
206
        int len;
207
 
208
        len = AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + ROSE_MIN_LEN + 1;
209
 
210
        if ((skb = alloc_skb(len, GFP_ATOMIC)) == NULL)
211
                return;
212
 
213
        skb->free = 1;
214
 
215
        skb_reserve(skb, AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN);
216
 
217
        dptr = skb_put(skb, ROSE_MIN_LEN + 1);
218
 
219
        *dptr++ = AX25_P_ROSE;
220
        *dptr++ = ROSE_GFI;
221
        *dptr++ = 0x00;
222
        *dptr++ = ROSE_RESTART_CONFIRMATION;
223
 
224
        if (!rose_send_frame(skb, neigh))
225
                kfree_skb(skb, FREE_WRITE);
226
}
227
 
228
/*
229
 * This routine is called when a Diagnostic is required.
230
 */
231
void rose_transmit_diagnostic(struct rose_neigh *neigh, unsigned char diag)
232
{
233
        struct sk_buff *skb;
234
        unsigned char *dptr;
235
        int len;
236
 
237
        len = AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + ROSE_MIN_LEN + 2;
238
 
239
        if ((skb = alloc_skb(len, GFP_ATOMIC)) == NULL)
240
                return;
241
 
242
        skb->free = 1;
243
 
244
        skb_reserve(skb, AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN);
245
 
246
        dptr = skb_put(skb, ROSE_MIN_LEN + 2);
247
 
248
        *dptr++ = AX25_P_ROSE;
249
        *dptr++ = ROSE_GFI;
250
        *dptr++ = 0x00;
251
        *dptr++ = ROSE_DIAGNOSTIC;
252
        *dptr++ = diag;
253
 
254
        if (!rose_send_frame(skb, neigh))
255
                kfree_skb(skb, FREE_WRITE);
256
}
257
 
258
/*
259
 * This routine is called when a Clear Request is needed outside of the context
260
 * of a connected socket.
261
 */
262
void rose_transmit_clear_request(struct rose_neigh *neigh, unsigned int lci, unsigned char cause, unsigned char diagnostic)
263
{
264
        struct sk_buff *skb;
265
        unsigned char *dptr;
266
        struct device *first;
267
        int len;
268
 
269
        len = AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + ROSE_MIN_LEN + 3;
270
 
271
        first = rose_dev_first();
272
        if (first) {
273
                /* F6FBB - Adding facilities */
274
                len += 6 + AX25_ADDR_LEN + 3 + ROSE_ADDR_LEN;
275
        }
276
 
277
        if ((skb = alloc_skb(len, GFP_ATOMIC)) == NULL)
278
                return;
279
 
280
        skb->free = 1;
281
 
282
        skb_reserve(skb, AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN);
283
 
284
        dptr = skb_put(skb, skb_tailroom(skb));
285
 
286
        *dptr++ = AX25_P_ROSE;
287
        *dptr++ = ((lci >> 8) & 0x0F) | ROSE_GFI;
288
        *dptr++ = ((lci >> 0) & 0xFF);
289
        *dptr++ = ROSE_CLEAR_REQUEST;
290
        *dptr++ = cause;
291
        *dptr++ = diagnostic;
292
 
293
        if (first) {
294
                /* F6FBB - Adding facilities */
295
                *dptr++ = 0x00;         /* Address length */
296
                *dptr++ = 4 + AX25_ADDR_LEN + 3 + ROSE_ADDR_LEN; /* Facilities length */
297
                *dptr++ = 0;
298
                *dptr++ = FAC_NATIONAL;
299
                *dptr++ = FAC_NATIONAL_FAIL_CALL;
300
                *dptr++ = AX25_ADDR_LEN;
301
                memcpy(dptr, &rose_callsign, AX25_ADDR_LEN);
302
                dptr += AX25_ADDR_LEN;
303
                *dptr++ = FAC_NATIONAL_FAIL_ADD;
304
                *dptr++ = ROSE_ADDR_LEN + 1;
305
                *dptr++ = ROSE_ADDR_LEN * 2;
306
                memcpy(dptr, first->dev_addr, ROSE_ADDR_LEN);
307
        }
308
 
309
        if (!rose_send_frame(skb, neigh))
310
                kfree_skb(skb, FREE_WRITE);
311
}
312
 
313
void rose_transmit_link(struct sk_buff *skb, struct rose_neigh *neigh)
314
{
315
        rose_address *dest_addr;
316
        unsigned char *dptr;
317
 
318
#ifdef CONFIG_FIREWALL
319
        if (call_fw_firewall(PF_ROSE, skb->dev, skb->data, NULL) != FW_ACCEPT)
320
                return;
321
#endif
322
 
323
        /*
324
         * Check to see if its for us, if it is put it onto the loopback
325
         * queue.
326
         */
327
        dest_addr = (rose_address *)(skb->data + 4);
328
 
329
        if ((neigh->dce_mode == -1) || (rose_dev_get(dest_addr) != NULL)) {
330
                neigh->dce_mode = -1;
331
                rose_loopback_queue(skb, neigh);
332
                return;
333
        }
334
 
335
        if (!rose_link_up(neigh))
336
                neigh->restarted = 0;
337
 
338
        dptr = skb_push(skb, 1);
339
        *dptr++ = AX25_P_ROSE;
340
 
341
        if (neigh->restarted) {
342
                if (!rose_send_frame(skb, neigh))
343
                        kfree_skb(skb, FREE_WRITE);
344
        } else {
345
                skb_queue_tail(&neigh->queue, skb);
346
 
347
                if (neigh->t0timer == 0) {
348
                        rose_transmit_restart_request(neigh);
349
                        neigh->dce_mode = 0;
350
                        neigh->t0timer  = sysctl_rose_restart_request_timeout;
351
                        rose_link_set_timer(neigh);
352
                }
353
        }
354
}
355
 
356
#endif

powered by: WebSVN 2.1.0

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