import of ftp.dlink.com/GPL/DSMG-600_reB/ppclinux.tar.gz
[linux-2.4.21-pre4.git] / net / rose / rose_out.c
1 /*
2  *      ROSE release 003
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  *      History
13  *      ROSE 001        Jonathan(G4KLX) Cloned from nr_out.c
14  *      ROSE 003        Jonathan(G4KLX) New timer architecture.
15  *                                      Removed M bit processing.
16  */
17
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 <net/rose.h>
39
40 /* 
41  *      This procedure is passed a buffer descriptor for an iframe. It builds
42  *      the rest of the control part of the frame and then writes it out.
43  */
44 static void rose_send_iframe(struct sock *sk, struct sk_buff *skb)
45 {
46         if (skb == NULL)
47                 return;
48
49         skb->data[2] |= (sk->protinfo.rose->vr << 5) & 0xE0;
50         skb->data[2] |= (sk->protinfo.rose->vs << 1) & 0x0E;
51
52         rose_start_idletimer(sk);
53
54         rose_transmit_link(skb, sk->protinfo.rose->neighbour);  
55 }
56
57 void rose_kick(struct sock *sk)
58 {
59         struct sk_buff *skb, *skbn;
60         unsigned short start, end;
61
62         if (sk->protinfo.rose->state != ROSE_STATE_3)
63                 return;
64
65         if (sk->protinfo.rose->condition & ROSE_COND_PEER_RX_BUSY)
66                 return;
67
68         if (skb_peek(&sk->write_queue) == NULL)
69                 return;
70
71         start = (skb_peek(&sk->protinfo.rose->ack_queue) == NULL) ? sk->protinfo.rose->va : sk->protinfo.rose->vs;
72         end   = (sk->protinfo.rose->va + sysctl_rose_window_size) % ROSE_MODULUS;
73
74         if (start == end)
75                 return;
76
77         sk->protinfo.rose->vs = start;
78
79         /*
80          * Transmit data until either we're out of data to send or
81          * the window is full.
82          */
83
84         skb  = skb_dequeue(&sk->write_queue);
85
86         do {
87                 if ((skbn = skb_clone(skb, GFP_ATOMIC)) == NULL) {
88                         skb_queue_head(&sk->write_queue, skb);
89                         break;
90                 }
91
92                 skb_set_owner_w(skbn, sk);
93
94                 /*
95                  * Transmit the frame copy.
96                  */
97                 rose_send_iframe(sk, skbn);
98
99                 sk->protinfo.rose->vs = (sk->protinfo.rose->vs + 1) % ROSE_MODULUS;
100
101                 /*
102                  * Requeue the original data frame.
103                  */
104                 skb_queue_tail(&sk->protinfo.rose->ack_queue, skb);
105
106         } while (sk->protinfo.rose->vs != end && (skb = skb_dequeue(&sk->write_queue)) != NULL);
107
108         sk->protinfo.rose->vl         = sk->protinfo.rose->vr;
109         sk->protinfo.rose->condition &= ~ROSE_COND_ACK_PENDING;
110
111         rose_stop_timer(sk);
112 }
113
114 /*
115  * The following routines are taken from page 170 of the 7th ARRL Computer
116  * Networking Conference paper, as is the whole state machine.
117  */
118
119 void rose_enquiry_response(struct sock *sk)
120 {
121         if (sk->protinfo.rose->condition & ROSE_COND_OWN_RX_BUSY)
122                 rose_write_internal(sk, ROSE_RNR);
123         else
124                 rose_write_internal(sk, ROSE_RR);
125
126         sk->protinfo.rose->vl         = sk->protinfo.rose->vr;
127         sk->protinfo.rose->condition &= ~ROSE_COND_ACK_PENDING;
128
129         rose_stop_timer(sk);
130 }