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)38void 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)47void dn_stop_slow_timer(struct sock *sk) 48 { 49 del_timer(&sk->timer); 50 } 51 dn_slow_timer(unsigned long arg)52static 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)112static 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)132void 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)146void 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