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 
dn_start_slow_timer(struct sock * sk)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 
dn_stop_slow_timer(struct sock * sk)47 void dn_stop_slow_timer(struct sock *sk)
48 {
49 	del_timer(&sk->timer);
50 }
51 
dn_slow_timer(unsigned long arg)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 
dn_fast_timer(unsigned long arg)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 
dn_start_fast_timer(struct sock * sk)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 
dn_stop_fast_timer(struct sock * sk)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