more changes on original files
[linux-2.4.git] / net / rose / rose_timer.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_timer.c
14  *      ROSE 003        Jonathan(G4KLX) New timer architecture.
15  *                                      Implemented idle timer.
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 static void rose_heartbeat_expiry(unsigned long);
41 static void rose_timer_expiry(unsigned long);
42 static void rose_idletimer_expiry(unsigned long);
43
44 void rose_start_heartbeat(struct sock *sk)
45 {
46         del_timer(&sk->timer);
47
48         sk->timer.data     = (unsigned long)sk;
49         sk->timer.function = &rose_heartbeat_expiry;
50         sk->timer.expires  = jiffies + 5 * HZ;
51
52         add_timer(&sk->timer);
53 }
54
55 void rose_start_t1timer(struct sock *sk)
56 {
57         del_timer(&sk->protinfo.rose->timer);
58
59         sk->protinfo.rose->timer.data     = (unsigned long)sk;
60         sk->protinfo.rose->timer.function = &rose_timer_expiry;
61         sk->protinfo.rose->timer.expires  = jiffies + sk->protinfo.rose->t1;
62
63         add_timer(&sk->protinfo.rose->timer);
64 }
65
66 void rose_start_t2timer(struct sock *sk)
67 {
68         del_timer(&sk->protinfo.rose->timer);
69
70         sk->protinfo.rose->timer.data     = (unsigned long)sk;
71         sk->protinfo.rose->timer.function = &rose_timer_expiry;
72         sk->protinfo.rose->timer.expires  = jiffies + sk->protinfo.rose->t2;
73
74         add_timer(&sk->protinfo.rose->timer);
75 }
76
77 void rose_start_t3timer(struct sock *sk)
78 {
79         del_timer(&sk->protinfo.rose->timer);
80
81         sk->protinfo.rose->timer.data     = (unsigned long)sk;
82         sk->protinfo.rose->timer.function = &rose_timer_expiry;
83         sk->protinfo.rose->timer.expires  = jiffies + sk->protinfo.rose->t3;
84
85         add_timer(&sk->protinfo.rose->timer);
86 }
87
88 void rose_start_hbtimer(struct sock *sk)
89 {
90         del_timer(&sk->protinfo.rose->timer);
91
92         sk->protinfo.rose->timer.data     = (unsigned long)sk;
93         sk->protinfo.rose->timer.function = &rose_timer_expiry;
94         sk->protinfo.rose->timer.expires  = jiffies + sk->protinfo.rose->hb;
95
96         add_timer(&sk->protinfo.rose->timer);
97 }
98
99 void rose_start_idletimer(struct sock *sk)
100 {
101         del_timer(&sk->protinfo.rose->idletimer);
102
103         if (sk->protinfo.rose->idle > 0) {
104                 sk->protinfo.rose->idletimer.data     = (unsigned long)sk;
105                 sk->protinfo.rose->idletimer.function = &rose_idletimer_expiry;
106                 sk->protinfo.rose->idletimer.expires  = jiffies + sk->protinfo.rose->idle;
107
108                 add_timer(&sk->protinfo.rose->idletimer);
109         }
110 }
111
112 void rose_stop_heartbeat(struct sock *sk)
113 {
114         del_timer(&sk->timer);
115 }
116
117 void rose_stop_timer(struct sock *sk)
118 {
119         del_timer(&sk->protinfo.rose->timer);
120 }
121
122 void rose_stop_idletimer(struct sock *sk)
123 {
124         del_timer(&sk->protinfo.rose->idletimer);
125 }
126
127 static void rose_heartbeat_expiry(unsigned long param)
128 {
129         struct sock *sk = (struct sock *)param;
130
131         switch (sk->protinfo.rose->state) {
132
133                 case ROSE_STATE_0:
134                         /* Magic here: If we listen() and a new link dies before it
135                            is accepted() it isn't 'dead' so doesn't get removed. */
136                         if (sk->destroy || (sk->state == TCP_LISTEN && sk->dead)) {
137                                 rose_destroy_socket(sk);
138                                 return;
139                         }
140                         break;
141
142                 case ROSE_STATE_3:
143                         /*
144                          * Check for the state of the receive buffer.
145                          */
146                         if (atomic_read(&sk->rmem_alloc) < (sk->rcvbuf / 2) &&
147                             (sk->protinfo.rose->condition & ROSE_COND_OWN_RX_BUSY)) {
148                                 sk->protinfo.rose->condition &= ~ROSE_COND_OWN_RX_BUSY;
149                                 sk->protinfo.rose->condition &= ~ROSE_COND_ACK_PENDING;
150                                 sk->protinfo.rose->vl         = sk->protinfo.rose->vr;
151                                 rose_write_internal(sk, ROSE_RR);
152                                 rose_stop_timer(sk);    /* HB */
153                                 break;
154                         }
155                         break;
156         }
157
158         rose_start_heartbeat(sk);
159 }
160
161 static void rose_timer_expiry(unsigned long param)
162 {
163         struct sock *sk = (struct sock *)param;
164
165         switch (sk->protinfo.rose->state) {
166
167                 case ROSE_STATE_1:      /* T1 */
168                 case ROSE_STATE_4:      /* T2 */
169                         rose_write_internal(sk, ROSE_CLEAR_REQUEST);
170                         sk->protinfo.rose->state = ROSE_STATE_2;
171                         rose_start_t3timer(sk);
172                         break;
173
174                 case ROSE_STATE_2:      /* T3 */
175                         sk->protinfo.rose->neighbour->use--;
176                         rose_disconnect(sk, ETIMEDOUT, -1, -1);
177                         break;
178
179                 case ROSE_STATE_3:      /* HB */
180                         if (sk->protinfo.rose->condition & ROSE_COND_ACK_PENDING) {
181                                 sk->protinfo.rose->condition &= ~ROSE_COND_ACK_PENDING;
182                                 rose_enquiry_response(sk);
183                         }
184                         break;
185         }
186 }
187
188 static void rose_idletimer_expiry(unsigned long param)
189 {
190         struct sock *sk = (struct sock *)param;
191
192         rose_clear_queues(sk);
193
194         rose_write_internal(sk, ROSE_CLEAR_REQUEST);
195         sk->protinfo.rose->state = ROSE_STATE_2;
196
197         rose_start_t3timer(sk);
198
199         sk->state     = TCP_CLOSE;
200         sk->err       = 0;
201         sk->shutdown |= SEND_SHUTDOWN;  
202
203         if (!sk->dead)
204                 sk->state_change(sk);
205
206         sk->dead = 1;
207 }