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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [rc203soc/] [sw/] [uClinux/] [net/] [ax25/] [ax25_out.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1629 jcastillo
/*
2
 *      AX.25 release 035
3
 *
4
 *      This code REQUIRES 1.2.1 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
 *      Most of this code is based on the SDL diagrams published in the 7th
13
 *      ARRL Computer Networking Conference papers. The diagrams have mistakes
14
 *      in them, but are mostly correct. Before you modify the code could you
15
 *      read the SDL diagrams as the code is not obvious and probably very
16
 *      easy to break;
17
 *
18
 *      History
19
 *      AX.25 028a      Jonathan(G4KLX) New state machine based on SDL diagrams.
20
 *      AX.25 029       Alan(GW4PTS)    Switched to KA9Q constant names.
21
 *                      Jonathan(G4KLX) Only poll when window is full.
22
 *      AX.25 030       Jonathan(G4KLX) Added fragmentation to ax25_output.
23
 *                                      Added support for extended AX.25.
24
 *      AX.25 031       Joerg(DL1BKE)   Added DAMA support
25
 *                      Joerg(DL1BKE)   Modified fragmenter to fragment vanilla
26
 *                                      AX.25 I-Frames. Added PACLEN parameter.
27
 *                      Joerg(DL1BKE)   Fixed a problem with buffer allocation
28
 *                                      for fragments.
29
 */
30
 
31
#include <linux/config.h>
32
#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
33
#include <linux/errno.h>
34
#include <linux/types.h>
35
#include <linux/socket.h>
36
#include <linux/in.h>
37
#include <linux/kernel.h>
38
#include <linux/sched.h>
39
#include <linux/timer.h>
40
#include <linux/string.h>
41
#include <linux/sockios.h>
42
#include <linux/net.h>
43
#include <net/ax25.h>
44
#include <linux/inet.h>
45
#include <linux/netdevice.h>
46
#include <linux/skbuff.h>
47
#include <net/sock.h>
48
#include <asm/segment.h>
49
#include <asm/system.h>
50
#include <linux/fcntl.h>
51
#include <linux/mm.h>
52
#include <linux/interrupt.h>
53
 
54
/*
55
 *      All outgoing AX.25 I frames pass via this routine. Therefore this is
56
 *      where the fragmentation of frames takes place. If fragment is set to
57
 *      zero then we are not allowed to do fragmentation, even if the frame
58
 *      is too large.
59
 */
60
void ax25_output(ax25_cb *ax25, int paclen, struct sk_buff *skb)
61
{
62
        struct sk_buff *skbn;
63
        unsigned char *p;
64
        int frontlen, len, fragno, ka9qfrag, first = 1;
65
        long flags;
66
 
67
        if ((skb->len - 1) > paclen) {
68
                if (*skb->data == AX25_P_TEXT) {
69
                        skb_pull(skb, 1); /* skip PID */
70
                        ka9qfrag = 0;
71
                } else {
72
                        paclen -= 2;    /* Allow for fragment control info */
73
                        ka9qfrag = 1;
74
                }
75
 
76
                fragno = skb->len / paclen;
77
                if (skb->len % paclen == 0) fragno--;
78
 
79
                frontlen = skb_headroom(skb);   /* Address space + CTRL */
80
 
81
                while (skb->len > 0) {
82
                        save_flags(flags);
83
                        cli();
84
 
85
                        if ((skbn = alloc_skb(paclen + 2 + frontlen, GFP_ATOMIC)) == NULL) {
86
                                restore_flags(flags);
87
                                printk(KERN_DEBUG "ax25_output: alloc_skb returned NULL\n");
88
                                if (skb_device_locked(skb))
89
                                        skb_device_unlock(skb);
90
                                return;
91
                        }
92
 
93
                        skbn->sk   = skb->sk;
94
                        skbn->free = 1;
95
 
96
                        if (skbn->sk != NULL)
97
                                atomic_add(skbn->truesize, &skbn->sk->wmem_alloc);
98
 
99
                        restore_flags(flags);
100
 
101
                        len = (paclen > skb->len) ? skb->len : paclen;
102
 
103
                        if (ka9qfrag == 1) {
104
                                skb_reserve(skbn, frontlen + 2);
105
 
106
                                memcpy(skb_put(skbn, len), skb->data, len);
107
                                p = skb_push(skbn, 2);
108
 
109
                                *p++ = AX25_P_SEGMENT;
110
 
111
                                *p = fragno--;
112
                                if (first) {
113
                                        *p |= AX25_SEG_FIRST;
114
                                        first = 0;
115
                                }
116
                        } else {
117
                                skb_reserve(skbn, frontlen + 1);
118
                                memcpy(skb_put(skbn, len), skb->data, len);
119
                                p = skb_push(skbn, 1);
120
                                *p = AX25_P_TEXT;
121
                        }
122
 
123
                        skb_pull(skb, len);
124
                        skb_queue_tail(&ax25->write_queue, skbn); /* Throw it on the queue */
125
                }
126
 
127
                kfree_skb(skb, FREE_WRITE);
128
        } else {
129
                skb_queue_tail(&ax25->write_queue, skb);          /* Throw it on the queue */
130
        }
131
 
132
        if (ax25->state == AX25_STATE_3 || ax25->state == AX25_STATE_4) {
133
                if (!ax25->dama_slave)          /* bke 960114: we aren't allowed to transmit */
134
                        ax25_kick(ax25);        /* in DAMA mode unless we received a Poll */
135
        }
136
}
137
 
138
/*
139
 *  This procedure is passed a buffer descriptor for an iframe. It builds
140
 *  the rest of the control part of the frame and then writes it out.
141
 */
142
static void ax25_send_iframe(ax25_cb *ax25, struct sk_buff *skb, int poll_bit)
143
{
144
        unsigned char *frame;
145
 
146
        if (skb == NULL)
147
                return;
148
 
149
        if (ax25->modulus == AX25_MODULUS) {
150
                frame = skb_push(skb, 1);
151
 
152
                *frame = AX25_I;
153
                *frame |= (poll_bit) ? AX25_PF : 0;
154
                *frame |= (ax25->vr << 5);
155
                *frame |= (ax25->vs << 1);
156
        } else {
157
                frame = skb_push(skb, 2);
158
 
159
                frame[0] = AX25_I;
160
                frame[0] |= (ax25->vs << 1);
161
                frame[1] = (poll_bit) ? AX25_EPF : 0;
162
                frame[1] |= (ax25->vr << 1);
163
        }
164
 
165
        ax25->idletimer = ax25->idle;
166
 
167
        ax25_transmit_buffer(ax25, skb, AX25_COMMAND);
168
}
169
 
170
void ax25_kick(ax25_cb *ax25)
171
{
172
        struct sk_buff *skb, *skbn;
173
        int last = 1;
174
        unsigned short start, end, next;
175
 
176
        del_timer(&ax25->timer);
177
 
178
        start = (skb_peek(&ax25->ack_queue) == NULL) ? ax25->va : ax25->vs;
179
        end   = (ax25->va + ax25->window) % ax25->modulus;
180
 
181
        if (!(ax25->condition & AX25_COND_PEER_RX_BUSY) &&
182
            start != end                                &&
183
            skb_peek(&ax25->write_queue) != NULL) {
184
 
185
                ax25->vs = start;
186
 
187
                /*
188
                 * Transmit data until either we're out of data to send or
189
                 * the window is full. Send a poll on the final I frame if
190
                 * the window is filled.
191
                 */
192
 
193
                /*
194
                 * Dequeue the frame and copy it.
195
                 */
196
                skb  = skb_dequeue(&ax25->write_queue);
197
 
198
                do {
199
                        if ((skbn = skb_clone(skb, GFP_ATOMIC)) == NULL) {
200
                                skb_queue_head(&ax25->write_queue, skb);
201
                                break;
202
                        }
203
 
204
                        skbn->sk = skb->sk;
205
 
206
                        if (skbn->sk != NULL)
207
                                atomic_add(skbn->truesize, &skbn->sk->wmem_alloc);
208
 
209
                        next = (ax25->vs + 1) % ax25->modulus;
210
                        last = (next == end);
211
 
212
                        /*
213
                         * Transmit the frame copy.
214
                         * bke 960114: do not set the Poll bit on the last frame
215
                         * in DAMA mode.
216
                         */
217
                        ax25_send_iframe(ax25, skbn, (last && !ax25->dama_slave) ? AX25_POLLON : AX25_POLLOFF);
218
 
219
                        ax25->vs = next;
220
 
221
                        /*
222
                         * Requeue the original data frame.
223
                         */
224
                        skb_queue_tail(&ax25->ack_queue, skb);
225
 
226
                } while (!last && (skb = skb_dequeue(&ax25->write_queue)) != NULL);
227
 
228
                ax25->condition &= ~AX25_COND_ACK_PENDING;
229
 
230
                if (ax25->t1timer == 0) {
231
                        ax25->t3timer = 0;
232
                        ax25->t1timer = ax25->t1 = ax25_calculate_t1(ax25);
233
                }
234
        }
235
 
236
        ax25_set_timer(ax25);
237
}
238
 
239
void ax25_transmit_buffer(ax25_cb *ax25, struct sk_buff *skb, int type)
240
{
241
        unsigned char *ptr;
242
 
243
        if (ax25->device == NULL) {
244
                ax25_disconnect(ax25, ENETUNREACH);
245
                return;
246
        }
247
 
248
        if (skb_headroom(skb) < size_ax25_addr(ax25->digipeat)) {
249
                printk(KERN_CRIT "ax25_transmit_buffer: not enough room for digi-peaters\n");
250
                skb->free = 1;
251
                kfree_skb(skb, FREE_WRITE);
252
                return;
253
        }
254
 
255
        ptr = skb_push(skb, size_ax25_addr(ax25->digipeat));
256
        build_ax25_addr(ptr, &ax25->source_addr, &ax25->dest_addr, ax25->digipeat, type, ax25->modulus);
257
 
258
        ax25_queue_xmit(skb, ax25->device, SOPRI_NORMAL);
259
}
260
 
261
/*
262
 * The following routines are taken from page 170 of the 7th ARRL Computer
263
 * Networking Conference paper, as is the whole state machine.
264
 */
265
 
266
void ax25_nr_error_recovery(ax25_cb *ax25)
267
{
268
        ax25_establish_data_link(ax25);
269
}
270
 
271
void ax25_establish_data_link(ax25_cb *ax25)
272
{
273
        ax25->condition = 0x00;
274
        ax25->n2count   = 0;
275
 
276
        if (ax25->modulus == AX25_MODULUS)
277
                ax25_send_control(ax25, AX25_SABM, AX25_POLLON, AX25_COMMAND);
278
        else
279
                ax25_send_control(ax25, AX25_SABME, AX25_POLLON, AX25_COMMAND);
280
 
281
        ax25->t3timer = 0;
282
        ax25->t2timer = 0;
283
        ax25->t1timer = ax25->t1 = ax25_calculate_t1(ax25);
284
}
285
 
286
void ax25_transmit_enquiry(ax25_cb *ax25)
287
{
288
        if (ax25->condition & AX25_COND_OWN_RX_BUSY)
289
                ax25_send_control(ax25, AX25_RNR, AX25_POLLON, AX25_COMMAND);
290
        else
291
                ax25_send_control(ax25, AX25_RR, AX25_POLLON, AX25_COMMAND);
292
 
293
        ax25->condition &= ~AX25_COND_ACK_PENDING;
294
 
295
        ax25->t1timer = ax25->t1 = ax25_calculate_t1(ax25);
296
}
297
 
298
void ax25_enquiry_response(ax25_cb *ax25)
299
{
300
        if (ax25->condition & AX25_COND_OWN_RX_BUSY)
301
                ax25_send_control(ax25, AX25_RNR, AX25_POLLON, AX25_RESPONSE);
302
        else
303
                ax25_send_control(ax25, AX25_RR, AX25_POLLON, AX25_RESPONSE);
304
 
305
        ax25->condition &= ~AX25_COND_ACK_PENDING;
306
}
307
 
308
void ax25_timeout_response(ax25_cb *ax25)
309
{
310
        if (ax25->condition & AX25_COND_OWN_RX_BUSY)
311
                ax25_send_control(ax25, AX25_RNR, AX25_POLLOFF, AX25_RESPONSE);
312
        else
313
                ax25_send_control(ax25, AX25_RR, AX25_POLLOFF, AX25_RESPONSE);
314
 
315
        ax25->condition &= ~AX25_COND_ACK_PENDING;
316
}
317
 
318
void ax25_check_iframes_acked(ax25_cb *ax25, unsigned short nr)
319
{
320
        if (ax25->vs == nr) {
321
                ax25_frames_acked(ax25, nr);
322
                ax25_calculate_rtt(ax25);
323
                ax25->t1timer = 0;
324
                ax25->t3timer = ax25->t3;
325
        } else {
326
                if (ax25->va != nr) {
327
                        ax25_frames_acked(ax25, nr);
328
                        ax25->t1timer = ax25->t1 = ax25_calculate_t1(ax25);
329
                }
330
        }
331
}
332
 
333
/*
334
 *      dl1bke 960114: transmit I frames on DAMA poll
335
 */
336
void dama_enquiry_response(ax25_cb *ax25)
337
{
338
        ax25_cb *ax25o;
339
 
340
        if (!(ax25->condition & AX25_COND_PEER_RX_BUSY)) {
341
                ax25_requeue_frames(ax25);
342
                ax25_kick(ax25);
343
        }
344
 
345
        if (ax25->state == AX25_STATE_1 || ax25->state == AX25_STATE_2 || skb_peek(&ax25->ack_queue) != NULL)
346
                ax25_t1_timeout(ax25);
347
        else
348
                ax25->n2count = 0;
349
 
350
        ax25->t3timer = ax25->t3;
351
 
352
        /* The FLEXNET DAMA master implementation refuses to send us ANY */
353
        /* I frame for this connection if we send a REJ here, probably   */
354
        /* due to its frame collector scheme? A simple RR or  RNR will   */
355
        /* invoke the retransmission, and in fact REJs are superfluous   */
356
        /* in DAMA mode anyway...                                        */
357
 
358
#if 0
359
        if (ax25->condition & AX25_COND_REJECT)
360
                ax25_send_control(ax25, AX25_REJ, AX25_POLLOFF, AX25_RESPONSE);
361
        else
362
#endif
363
                ax25_enquiry_response(ax25);
364
 
365
        /* Note that above response to the poll could be sent behind the  */
366
        /* transmissions of the other channels as well... This version    */
367
        /* gives better performance on FLEXNET nodes. (Why, Gunter?)      */
368
 
369
        for (ax25o = ax25_list; ax25o != NULL; ax25o = ax25o->next) {
370
                if (ax25o == ax25)
371
                        continue;
372
 
373
                if (ax25o->device != ax25->device)
374
                        continue;
375
 
376
                if (ax25o->state == AX25_STATE_1 || ax25o->state == AX25_STATE_2) {
377
                        ax25_t1_timeout(ax25o);
378
                        continue;
379
                }
380
 
381
                if (!ax25o->dama_slave)
382
                        continue;
383
 
384
                if (!(ax25o->condition & AX25_COND_PEER_RX_BUSY) &&
385
                    (ax25o->state == AX25_STATE_3 ||
386
                    (ax25o->state == AX25_STATE_4 && ax25o->t1timer == 0))) {
387
                        ax25_requeue_frames(ax25o);
388
                        ax25_kick(ax25o);
389
                }
390
 
391
                if (ax25o->state == AX25_STATE_1 || ax25o->state == AX25_STATE_2 || skb_peek(&ax25o->ack_queue) != NULL)
392
                        ax25_t1_timeout(ax25o);
393
 
394
                ax25o->t3timer = ax25o->t3;
395
        }
396
}
397
 
398
void dama_establish_data_link(ax25_cb *ax25)
399
{
400
        ax25->condition = 0x00;
401
        ax25->n2count   = 0;
402
 
403
        ax25->t3timer = ax25->t3;
404
        ax25->t2timer = 0;
405
        ax25->t1timer = ax25->t1 = ax25_calculate_t1(ax25);
406
}
407
 
408
#endif

powered by: WebSVN 2.1.0

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