ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / net / x25 / x25_timer.c
1 /*
2  *      X.25 Packet Layer release 002
3  *
4  *      This is ALPHA test software. This code may break your machine,
5  *      randomly fail to work with new releases, misbehave and/or generally
6  *      screw up. It might even work. 
7  *
8  *      This code REQUIRES 2.1.15 or higher
9  *
10  *      This module:
11  *              This module is free software; you can redistribute it and/or
12  *              modify it under the terms of the GNU General Public License
13  *              as published by the Free Software Foundation; either version
14  *              2 of the License, or (at your option) any later version.
15  *
16  *      History
17  *      X.25 001        Jonathan Naylor Started coding.
18  *      X.25 002        Jonathan Naylor New timer architecture.
19  *                                      Centralised disconnection processing.
20  */
21
22 #include <linux/errno.h>
23 #include <linux/types.h>
24 #include <linux/socket.h>
25 #include <linux/in.h>
26 #include <linux/kernel.h>
27 #include <linux/jiffies.h>
28 #include <linux/timer.h>
29 #include <linux/string.h>
30 #include <linux/sockios.h>
31 #include <linux/net.h>
32 #include <linux/inet.h>
33 #include <linux/netdevice.h>
34 #include <linux/skbuff.h>
35 #include <net/sock.h>
36 #include <net/tcp.h>
37 #include <asm/system.h>
38 #include <linux/fcntl.h>
39 #include <linux/mm.h>
40 #include <linux/interrupt.h>
41 #include <net/x25.h>
42
43 static void x25_heartbeat_expiry(unsigned long);
44 static void x25_timer_expiry(unsigned long);
45
46 void x25_init_timers(struct sock *sk)
47 {
48         struct x25_opt *x25 = x25_sk(sk);
49
50         init_timer(&x25->timer);
51         x25->timer.data     = (unsigned long)sk;
52         x25->timer.function = &x25_timer_expiry;
53
54         /* initialized by sock_init_data */
55         sk->sk_timer.data     = (unsigned long)sk;
56         sk->sk_timer.function = &x25_heartbeat_expiry;
57 }
58
59 void x25_start_heartbeat(struct sock *sk)
60 {
61         mod_timer(&sk->sk_timer, jiffies + 5 * HZ);
62 }
63
64 void x25_stop_heartbeat(struct sock *sk)
65 {
66         del_timer(&sk->sk_timer);
67 }
68
69 void x25_start_t2timer(struct sock *sk)
70 {
71         struct x25_opt *x25 = x25_sk(sk);
72
73         mod_timer(&x25->timer, jiffies + x25->t2);
74 }
75
76 void x25_start_t21timer(struct sock *sk)
77 {
78         struct x25_opt *x25 = x25_sk(sk);
79
80         mod_timer(&x25->timer, jiffies + x25->t21);
81 }
82
83 void x25_start_t22timer(struct sock *sk)
84 {
85         struct x25_opt *x25 = x25_sk(sk);
86
87         mod_timer(&x25->timer, jiffies + x25->t22);
88 }
89
90 void x25_start_t23timer(struct sock *sk)
91 {
92         struct x25_opt *x25 = x25_sk(sk);
93
94         mod_timer(&x25->timer, jiffies + x25->t23);
95 }
96
97 void x25_stop_timer(struct sock *sk)
98 {
99         del_timer(&x25_sk(sk)->timer);
100 }
101
102 unsigned long x25_display_timer(struct sock *sk)
103 {
104         struct x25_opt *x25 = x25_sk(sk);
105
106         if (!timer_pending(&x25->timer))
107                 return 0;
108
109         return x25->timer.expires - jiffies;
110 }
111
112 static void x25_heartbeat_expiry(unsigned long param)
113 {
114         struct sock *sk = (struct sock *)param;
115
116         bh_lock_sock(sk);
117         if (sock_owned_by_user(sk)) /* can currently only occur in state 3 */ 
118                 goto restart_heartbeat;
119
120         switch (x25_sk(sk)->state) {
121
122                 case X25_STATE_0:
123                         /*
124                          * Magic here: If we listen() and a new link dies
125                          * before it is accepted() it isn't 'dead' so doesn't
126                          * get removed.
127                          */
128                         if (sock_flag(sk, SOCK_DESTROY) ||
129                             (sk->sk_state == TCP_LISTEN &&
130                              sock_flag(sk, SOCK_DEAD))) {
131                                 x25_destroy_socket(sk);
132                                 goto unlock;
133                         }
134                         break;
135
136                 case X25_STATE_3:
137                         /*
138                          * Check for the state of the receive buffer.
139                          */
140                         x25_check_rbuf(sk);
141                         break;
142         }
143 restart_heartbeat:
144         x25_start_heartbeat(sk);
145 unlock:
146         bh_unlock_sock(sk);
147 }
148
149 /*
150  *      Timer has expired, it may have been T2, T21, T22, or T23. We can tell
151  *      by the state machine state.
152  */
153 static inline void x25_do_timer_expiry(struct sock * sk)
154 {
155         struct x25_opt *x25 = x25_sk(sk);
156
157         switch (x25->state) {
158
159                 case X25_STATE_3:       /* T2 */
160                         if (x25->condition & X25_COND_ACK_PENDING) {
161                                 x25->condition &= ~X25_COND_ACK_PENDING;
162                                 x25_enquiry_response(sk);
163                         }
164                         break;
165
166                 case X25_STATE_1:       /* T21 */
167                 case X25_STATE_4:       /* T22 */
168                         x25_write_internal(sk, X25_CLEAR_REQUEST);
169                         x25->state = X25_STATE_2;
170                         x25_start_t23timer(sk);
171                         break;
172
173                 case X25_STATE_2:       /* T23 */
174                         x25_disconnect(sk, ETIMEDOUT, 0, 0);
175                         break;
176         }
177 }
178
179 static void x25_timer_expiry(unsigned long param)
180 {
181         struct sock *sk = (struct sock *)param;
182
183         bh_lock_sock(sk);
184         if (sock_owned_by_user(sk)) { /* can currently only occur in state 3 */
185                 if (x25_sk(sk)->state == X25_STATE_3)
186                         x25_start_t2timer(sk);
187         } else
188                 x25_do_timer_expiry(sk);
189         bh_unlock_sock(sk);
190 }