File: /usr/src/linux/net/decnet/dn_timer.c

1     /*
2      * DECnet       An implementation of the DECnet protocol suite for the LINUX
3      *              operating system.  DECnet is implemented using the  BSD Socket
4      *              interface as the means of communication with the user level.
5      *
6      *              DECnet Socket Timer Functions
7      *
8      * Author:      Steve Whitehouse <SteveW@ACM.org>
9      *
10      *
11      * Changes:
12      *       Steve Whitehouse      : Made keepalive timer part of the same
13      *                               timer idea.
14      *       Steve Whitehouse      : Added checks for sk->sock_readers
15      *       David S. Miller       : New socket locking
16      *       Steve Whitehouse      : Timer grabs socket ref.
17      */
18     #include <linux/net.h>
19     #include <linux/socket.h>
20     #include <linux/skbuff.h>
21     #include <linux/netdevice.h>
22     #include <linux/timer.h>
23     #include <linux/spinlock.h>
24     #include <net/sock.h>
25     #include <asm/atomic.h>
26     #include <net/dn.h>
27     
28     /*
29      * Fast timer is for delayed acks (200mS max)
30      * Slow timer is for everything else (n * 500mS)
31      */
32     
33     #define FAST_INTERVAL (HZ/5)
34     #define SLOW_INTERVAL (HZ/2)
35     
36     static void dn_slow_timer(unsigned long arg);
37     
38     void dn_start_slow_timer(struct sock *sk)
39     {
40     	sk->timer.expires = jiffies + SLOW_INTERVAL;
41     	sk->timer.function = dn_slow_timer;
42     	sk->timer.data = (unsigned long)sk;
43     
44     	add_timer(&sk->timer);
45     }
46     
47     void dn_stop_slow_timer(struct sock *sk)
48     {
49     	del_timer(&sk->timer);
50     }
51     
52     static void dn_slow_timer(unsigned long arg)
53     {
54     	struct sock *sk = (struct sock *)arg;
55     	struct dn_scp *scp = DN_SK(sk);
56     
57     	sock_hold(sk);
58     	bh_lock_sock(sk);
59     
60     	if (sk->lock.users != 0) {
61     		sk->timer.expires = jiffies + HZ / 10;
62     		add_timer(&sk->timer);
63     		goto out;
64     	}
65     
66     	/*
67     	 * The persist timer is the standard slow timer used for retransmits
68     	 * in both connection establishment and disconnection as well as
69     	 * in the RUN state. The different states are catered for by changing
70     	 * the function pointer in the socket. Setting the timer to a value
71     	 * of zero turns it off. We allow the persist_fxn to turn the
72     	 * timer off in a permant way by returning non-zero, so that
73     	 * timer based routines may remove sockets. This is why we have a
74     	 * sock_hold()/sock_put() around the timer to prevent the socket
75     	 * going away in the middle.
76     	 */
77     	if (scp->persist && scp->persist_fxn) {
78     		if (scp->persist <= SLOW_INTERVAL) {
79     			scp->persist = 0;
80     
81     			if (scp->persist_fxn(sk))
82     				goto out;
83     		} else {
84     			scp->persist -= SLOW_INTERVAL;
85     		}
86     	}
87     
88     	/*
89     	 * Check for keepalive timeout. After the other timer 'cos if
90     	 * the previous timer caused a retransmit, we don't need to
91     	 * do this. scp->stamp is the last time that we sent a packet.
92     	 * The keepalive function sends a link service packet to the
93     	 * other end. If it remains unacknowledged, the standard
94     	 * socket timers will eventually shut the socket down. Each
95     	 * time we do this, scp->stamp will be updated, thus
96     	 * we won't try and send another until scp->keepalive has passed
97     	 * since the last successful transmission.
98     	 */
99     	if (scp->keepalive && scp->keepalive_fxn && (scp->state == DN_RUN)) {
100     		if ((jiffies - scp->stamp) >= scp->keepalive)
101     			scp->keepalive_fxn(sk);
102     	}
103     
104     	sk->timer.expires = jiffies + SLOW_INTERVAL;
105     
106     	add_timer(&sk->timer);
107     out:
108     	bh_unlock_sock(sk);
109     	sock_put(sk);
110     }
111     
112     static void dn_fast_timer(unsigned long arg)
113     {
114     	struct sock *sk = (struct sock *)arg;
115     	struct dn_scp *scp = DN_SK(sk);
116     
117     	bh_lock_sock(sk);
118     	if (sk->lock.users != 0) {
119     		scp->delack_timer.expires = jiffies + HZ / 20;
120     		add_timer(&scp->delack_timer);
121     		goto out;
122     	}
123     
124     	scp->delack_pending = 0;
125     
126     	if (scp->delack_fxn)
127     		scp->delack_fxn(sk);
128     out:
129     	bh_unlock_sock(sk);
130     }
131     
132     void dn_start_fast_timer(struct sock *sk)
133     {
134     	struct dn_scp *scp = DN_SK(sk);
135     
136     	if (!scp->delack_pending) {
137     		scp->delack_pending = 1;
138     		init_timer(&scp->delack_timer);
139     		scp->delack_timer.expires = jiffies + FAST_INTERVAL;
140     		scp->delack_timer.data = (unsigned long)sk;
141     		scp->delack_timer.function = dn_fast_timer;
142     		add_timer(&scp->delack_timer);
143     	}
144     }
145     
146     void dn_stop_fast_timer(struct sock *sk)
147     {
148     	struct dn_scp *scp = DN_SK(sk);
149     
150     	if (scp->delack_pending) {
151     		scp->delack_pending = 0;
152     		del_timer(&scp->delack_timer);
153     	}
154     }
155     
156