| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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/flow.h> | 
|  | 27 | #include <net/dn.h> | 
|  | 28 |  | 
|  | 29 | /* | 
|  | 30 | * Slow timer is for everything else (n * 500mS) | 
|  | 31 | */ | 
|  | 32 |  | 
|  | 33 | #define SLOW_INTERVAL (HZ/2) | 
|  | 34 |  | 
|  | 35 | static void dn_slow_timer(unsigned long arg); | 
|  | 36 |  | 
|  | 37 | void dn_start_slow_timer(struct sock *sk) | 
|  | 38 | { | 
|  | 39 | sk->sk_timer.expires	= jiffies + SLOW_INTERVAL; | 
|  | 40 | sk->sk_timer.function	= dn_slow_timer; | 
|  | 41 | sk->sk_timer.data	= (unsigned long)sk; | 
|  | 42 |  | 
|  | 43 | add_timer(&sk->sk_timer); | 
|  | 44 | } | 
|  | 45 |  | 
|  | 46 | void dn_stop_slow_timer(struct sock *sk) | 
|  | 47 | { | 
|  | 48 | del_timer(&sk->sk_timer); | 
|  | 49 | } | 
|  | 50 |  | 
|  | 51 | static void dn_slow_timer(unsigned long arg) | 
|  | 52 | { | 
|  | 53 | struct sock *sk = (struct sock *)arg; | 
|  | 54 | struct dn_scp *scp = DN_SK(sk); | 
|  | 55 |  | 
|  | 56 | sock_hold(sk); | 
|  | 57 | bh_lock_sock(sk); | 
|  | 58 |  | 
|  | 59 | if (sock_owned_by_user(sk)) { | 
|  | 60 | sk->sk_timer.expires = jiffies + HZ / 10; | 
|  | 61 | add_timer(&sk->sk_timer); | 
|  | 62 | goto out; | 
|  | 63 | } | 
|  | 64 |  | 
|  | 65 | /* | 
|  | 66 | * The persist timer is the standard slow timer used for retransmits | 
|  | 67 | * in both connection establishment and disconnection as well as | 
|  | 68 | * in the RUN state. The different states are catered for by changing | 
|  | 69 | * the function pointer in the socket. Setting the timer to a value | 
|  | 70 | * of zero turns it off. We allow the persist_fxn to turn the | 
|  | 71 | * timer off in a permant way by returning non-zero, so that | 
|  | 72 | * timer based routines may remove sockets. This is why we have a | 
|  | 73 | * sock_hold()/sock_put() around the timer to prevent the socket | 
|  | 74 | * going away in the middle. | 
|  | 75 | */ | 
|  | 76 | if (scp->persist && scp->persist_fxn) { | 
|  | 77 | if (scp->persist <= SLOW_INTERVAL) { | 
|  | 78 | scp->persist = 0; | 
|  | 79 |  | 
|  | 80 | if (scp->persist_fxn(sk)) | 
|  | 81 | goto out; | 
|  | 82 | } else { | 
|  | 83 | scp->persist -= SLOW_INTERVAL; | 
|  | 84 | } | 
|  | 85 | } | 
|  | 86 |  | 
|  | 87 | /* | 
|  | 88 | * Check for keepalive timeout. After the other timer 'cos if | 
|  | 89 | * the previous timer caused a retransmit, we don't need to | 
|  | 90 | * do this. scp->stamp is the last time that we sent a packet. | 
|  | 91 | * The keepalive function sends a link service packet to the | 
|  | 92 | * other end. If it remains unacknowledged, the standard | 
|  | 93 | * socket timers will eventually shut the socket down. Each | 
|  | 94 | * time we do this, scp->stamp will be updated, thus | 
|  | 95 | * we won't try and send another until scp->keepalive has passed | 
|  | 96 | * since the last successful transmission. | 
|  | 97 | */ | 
|  | 98 | if (scp->keepalive && scp->keepalive_fxn && (scp->state == DN_RUN)) { | 
|  | 99 | if ((jiffies - scp->stamp) >= scp->keepalive) | 
|  | 100 | scp->keepalive_fxn(sk); | 
|  | 101 | } | 
|  | 102 |  | 
|  | 103 | sk->sk_timer.expires = jiffies + SLOW_INTERVAL; | 
|  | 104 |  | 
|  | 105 | add_timer(&sk->sk_timer); | 
|  | 106 | out: | 
|  | 107 | bh_unlock_sock(sk); | 
|  | 108 | sock_put(sk); | 
|  | 109 | } |