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

Subversion Repositories or1k

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

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
 *      AX.25 release 037
3
 *
4
 *      This code REQUIRES 2.1.15 or higher/ NET3.038
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
 *      AX.25 037       Jonathan(G4KLX) New timer architecture.
30
 *                      Joerg(DL1BKE)   Fixed DAMA Slave mode: will work
31
 *                                      on non-DAMA interfaces like AX25L2V2
32
 *                                      again (this behaviour is _required_).
33
 *                      Joerg(DL1BKE)   ax25_check_iframes_acked() returns a
34
 *                                      value now (for DAMA n2count handling)
35
 */
36
 
37
#include <linux/config.h>
38
#include <linux/errno.h>
39
#include <linux/types.h>
40
#include <linux/socket.h>
41
#include <linux/in.h>
42
#include <linux/kernel.h>
43
#include <linux/sched.h>
44
#include <linux/timer.h>
45
#include <linux/string.h>
46
#include <linux/sockios.h>
47
#include <linux/net.h>
48
#include <net/ax25.h>
49
#include <linux/inet.h>
50
#include <linux/netdevice.h>
51
#include <linux/skbuff.h>
52
#include <linux/netfilter.h>
53
#include <net/sock.h>
54
#include <asm/uaccess.h>
55
#include <asm/system.h>
56
#include <linux/fcntl.h>
57
#include <linux/mm.h>
58
#include <linux/interrupt.h>
59
 
60
ax25_cb *ax25_send_frame(struct sk_buff *skb, int paclen, ax25_address *src, ax25_address *dest, ax25_digi *digi, struct net_device *dev)
61
{
62
        ax25_dev *ax25_dev;
63
        ax25_cb *ax25;
64
 
65
        /*
66
         * Take the default packet length for the device if zero is
67
         * specified.
68
         */
69
        if (paclen == 0) {
70
                if ((ax25_dev = ax25_dev_ax25dev(dev)) == NULL)
71
                        return NULL;
72
 
73
                paclen = ax25_dev->values[AX25_VALUES_PACLEN];
74
        }
75
 
76
        /*
77
         * Look for an existing connection.
78
         */
79
        if ((ax25 = ax25_find_cb(src, dest, digi, dev)) != NULL) {
80
                ax25_output(ax25, paclen, skb);
81
                return ax25;            /* It already existed */
82
        }
83
 
84
        if ((ax25_dev = ax25_dev_ax25dev(dev)) == NULL)
85
                return NULL;
86
 
87
        if ((ax25 = ax25_create_cb()) == NULL)
88
                return NULL;
89
 
90
        ax25_fillin_cb(ax25, ax25_dev);
91
 
92
        ax25->source_addr = *src;
93
        ax25->dest_addr   = *dest;
94
 
95
        if (digi != NULL) {
96
                if ((ax25->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) {
97
                        ax25_free_cb(ax25);
98
                        return NULL;
99
                }
100
                memcpy(ax25->digipeat, digi, sizeof(ax25_digi));
101
        }
102
 
103
        switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) {
104
                case AX25_PROTO_STD_SIMPLEX:
105
                case AX25_PROTO_STD_DUPLEX:
106
                        ax25_std_establish_data_link(ax25);
107
                        break;
108
 
109
#ifdef CONFIG_AX25_DAMA_SLAVE
110
                case AX25_PROTO_DAMA_SLAVE:
111
                        if (ax25_dev->dama.slave)
112
                                ax25_ds_establish_data_link(ax25);
113
                        else
114
                                ax25_std_establish_data_link(ax25);
115
                        break;
116
#endif
117
        }
118
 
119
        ax25_insert_socket(ax25);
120
 
121
        ax25->state = AX25_STATE_1;
122
 
123
        ax25_start_heartbeat(ax25);
124
 
125
        ax25_output(ax25, paclen, skb);
126
 
127
        return ax25;                    /* We had to create it */
128
}
129
 
130
/*
131
 *      All outgoing AX.25 I frames pass via this routine. Therefore this is
132
 *      where the fragmentation of frames takes place. If fragment is set to
133
 *      zero then we are not allowed to do fragmentation, even if the frame
134
 *      is too large.
135
 */
136
void ax25_output(ax25_cb *ax25, int paclen, struct sk_buff *skb)
137
{
138
        struct sk_buff *skbn;
139
        unsigned char *p;
140
        int frontlen, len, fragno, ka9qfrag, first = 1;
141
        unsigned long flags;
142
 
143
        if ((skb->len - 1) > paclen) {
144
                if (*skb->data == AX25_P_TEXT) {
145
                        skb_pull(skb, 1); /* skip PID */
146
                        ka9qfrag = 0;
147
                } else {
148
                        paclen -= 2;    /* Allow for fragment control info */
149
                        ka9qfrag = 1;
150
                }
151
 
152
                fragno = skb->len / paclen;
153
                if (skb->len % paclen == 0) fragno--;
154
 
155
                frontlen = skb_headroom(skb);   /* Address space + CTRL */
156
 
157
                while (skb->len > 0) {
158
                        save_flags(flags);
159
                        cli();
160
 
161
                        if ((skbn = alloc_skb(paclen + 2 + frontlen, GFP_ATOMIC)) == NULL) {
162
                                restore_flags(flags);
163
                                printk(KERN_CRIT "AX.25: ax25_output - out of memory\n");
164
                                return;
165
                        }
166
 
167
                        if (skb->sk != NULL)
168
                                skb_set_owner_w(skbn, skb->sk);
169
 
170
                        restore_flags(flags);
171
 
172
                        len = (paclen > skb->len) ? skb->len : paclen;
173
 
174
                        if (ka9qfrag == 1) {
175
                                skb_reserve(skbn, frontlen + 2);
176
                                skbn->nh.raw = skbn->data + (skb->nh.raw - skb->data);
177
                                memcpy(skb_put(skbn, len), skb->data, len);
178
                                p = skb_push(skbn, 2);
179
 
180
                                *p++ = AX25_P_SEGMENT;
181
 
182
                                *p = fragno--;
183
                                if (first) {
184
                                        *p |= AX25_SEG_FIRST;
185
                                        first = 0;
186
                                }
187
                        } else {
188
                                skb_reserve(skbn, frontlen + 1);
189
                                skbn->nh.raw = skbn->data + (skb->nh.raw - skb->data);
190
                                memcpy(skb_put(skbn, len), skb->data, len);
191
                                p = skb_push(skbn, 1);
192
                                *p = AX25_P_TEXT;
193
                        }
194
 
195
                        skb_pull(skb, len);
196
                        skb_queue_tail(&ax25->write_queue, skbn); /* Throw it on the queue */
197
                }
198
 
199
                kfree_skb(skb);
200
        } else {
201
                skb_queue_tail(&ax25->write_queue, skb);          /* Throw it on the queue */
202
        }
203
 
204
        switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) {
205
                case AX25_PROTO_STD_SIMPLEX:
206
                case AX25_PROTO_STD_DUPLEX:
207
                        ax25_kick(ax25);
208
                        break;
209
 
210
#ifdef CONFIG_AX25_DAMA_SLAVE
211
                /*
212
                 * A DAMA slave is _required_ to work as normal AX.25L2V2
213
                 * if no DAMA master is available.
214
                 */
215
                case AX25_PROTO_DAMA_SLAVE:
216
                        if (!ax25->ax25_dev->dama.slave) ax25_kick(ax25);
217
                        break;
218
#endif
219
        }
220
}
221
 
222
/*
223
 *  This procedure is passed a buffer descriptor for an iframe. It builds
224
 *  the rest of the control part of the frame and then writes it out.
225
 */
226
static void ax25_send_iframe(ax25_cb *ax25, struct sk_buff *skb, int poll_bit)
227
{
228
        unsigned char *frame;
229
 
230
        if (skb == NULL)
231
                return;
232
 
233
        skb->nh.raw = skb->data;
234
 
235
        if (ax25->modulus == AX25_MODULUS) {
236
                frame = skb_push(skb, 1);
237
 
238
                *frame = AX25_I;
239
                *frame |= (poll_bit) ? AX25_PF : 0;
240
                *frame |= (ax25->vr << 5);
241
                *frame |= (ax25->vs << 1);
242
        } else {
243
                frame = skb_push(skb, 2);
244
 
245
                frame[0] = AX25_I;
246
                frame[0] |= (ax25->vs << 1);
247
                frame[1] = (poll_bit) ? AX25_EPF : 0;
248
                frame[1] |= (ax25->vr << 1);
249
        }
250
 
251
        ax25_start_idletimer(ax25);
252
 
253
        ax25_transmit_buffer(ax25, skb, AX25_COMMAND);
254
}
255
 
256
void ax25_kick(ax25_cb *ax25)
257
{
258
        struct sk_buff *skb, *skbn;
259
        int last = 1;
260
        unsigned short start, end, next;
261
 
262
        if (ax25->state != AX25_STATE_3 && ax25->state != AX25_STATE_4)
263
                return;
264
 
265
        if (ax25->condition & AX25_COND_PEER_RX_BUSY)
266
                return;
267
 
268
        if (skb_peek(&ax25->write_queue) == NULL)
269
                return;
270
 
271
        start = (skb_peek(&ax25->ack_queue) == NULL) ? ax25->va : ax25->vs;
272
        end   = (ax25->va + ax25->window) % ax25->modulus;
273
 
274
        if (start == end)
275
                return;
276
 
277
        ax25->vs = start;
278
 
279
        /*
280
         * Transmit data until either we're out of data to send or
281
         * the window is full. Send a poll on the final I frame if
282
         * the window is filled.
283
         */
284
 
285
        /*
286
         * Dequeue the frame and copy it.
287
         */
288
        skb  = skb_dequeue(&ax25->write_queue);
289
 
290
        do {
291
                if ((skbn = skb_clone(skb, GFP_ATOMIC)) == NULL) {
292
                        skb_queue_head(&ax25->write_queue, skb);
293
                        break;
294
                }
295
 
296
                if (skb->sk != NULL)
297
                        skb_set_owner_w(skbn, skb->sk);
298
 
299
                next = (ax25->vs + 1) % ax25->modulus;
300
                last = (next == end);
301
 
302
                /*
303
                 * Transmit the frame copy.
304
                 * bke 960114: do not set the Poll bit on the last frame
305
                 * in DAMA mode.
306
                 */
307
                switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) {
308
                        case AX25_PROTO_STD_SIMPLEX:
309
                        case AX25_PROTO_STD_DUPLEX:
310
                                ax25_send_iframe(ax25, skbn, (last) ? AX25_POLLON : AX25_POLLOFF);
311
                                break;
312
 
313
#ifdef CONFIG_AX25_DAMA_SLAVE
314
                        case AX25_PROTO_DAMA_SLAVE:
315
                                ax25_send_iframe(ax25, skbn, AX25_POLLOFF);
316
                                break;
317
#endif
318
                }
319
 
320
                ax25->vs = next;
321
 
322
                /*
323
                 * Requeue the original data frame.
324
                 */
325
                skb_queue_tail(&ax25->ack_queue, skb);
326
 
327
        } while (!last && (skb = skb_dequeue(&ax25->write_queue)) != NULL);
328
 
329
        ax25->condition &= ~AX25_COND_ACK_PENDING;
330
 
331
        if (!ax25_t1timer_running(ax25)) {
332
                ax25_stop_t3timer(ax25);
333
                ax25_calculate_t1(ax25);
334
                ax25_start_t1timer(ax25);
335
        }
336
}
337
 
338
void ax25_transmit_buffer(ax25_cb *ax25, struct sk_buff *skb, int type)
339
{
340
        struct sk_buff *skbn;
341
        unsigned char *ptr;
342
        int headroom;
343
 
344
        if (ax25->ax25_dev == NULL) {
345
                ax25_disconnect(ax25, ENETUNREACH);
346
                return;
347
        }
348
 
349
        headroom = ax25_addr_size(ax25->digipeat);
350
 
351
        if (skb_headroom(skb) < headroom) {
352
                if ((skbn = skb_realloc_headroom(skb, headroom)) == NULL) {
353
                        printk(KERN_CRIT "AX.25: ax25_transmit_buffer - out of memory\n");
354
                        kfree_skb(skb);
355
                        return;
356
                }
357
 
358
                if (skb->sk != NULL)
359
                        skb_set_owner_w(skbn, skb->sk);
360
 
361
                kfree_skb(skb);
362
                skb = skbn;
363
        }
364
 
365
        ptr = skb_push(skb, headroom);
366
 
367
        ax25_addr_build(ptr, &ax25->source_addr, &ax25->dest_addr, ax25->digipeat, type, ax25->modulus);
368
 
369
        skb->dev = ax25->ax25_dev->dev;
370
 
371
        ax25_queue_xmit(skb);
372
}
373
 
374
/*
375
 *      A small shim to dev_queue_xmit to add the KISS control byte, and do
376
 *      any packet forwarding in operation.
377
 */
378
void ax25_queue_xmit(struct sk_buff *skb)
379
{
380
        unsigned char *ptr;
381
 
382
        skb->protocol = htons(ETH_P_AX25);
383
        skb->dev      = ax25_fwd_dev(skb->dev);
384
 
385
        ptr  = skb_push(skb, 1);
386
        *ptr = 0x00;                    /* KISS */
387
 
388
        dev_queue_xmit(skb);
389
}
390
 
391
int ax25_check_iframes_acked(ax25_cb *ax25, unsigned short nr)
392
{
393
        if (ax25->vs == nr) {
394
                ax25_frames_acked(ax25, nr);
395
                ax25_calculate_rtt(ax25);
396
                ax25_stop_t1timer(ax25);
397
                ax25_start_t3timer(ax25);
398
                return 1;
399
        } else {
400
                if (ax25->va != nr) {
401
                        ax25_frames_acked(ax25, nr);
402
                        ax25_calculate_t1(ax25);
403
                        ax25_start_t1timer(ax25);
404
                        return 1;
405
                }
406
        }
407
        return 0;
408
}
409
 

powered by: WebSVN 2.1.0

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