11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * DECnet       An implementation of the DECnet protocol suite for the LINUX
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *              operating system.  DECnet is implemented using the  BSD Socket
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *              interface as the means of communication with the user level.
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *              DECnet Socket Timer Functions
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Author:      Steve Whitehouse <SteveW@ACM.org>
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Changes:
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *       Steve Whitehouse      : Made keepalive timer part of the same
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *                               timer idea.
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *       Steve Whitehouse      : Added checks for sk->sock_readers
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *       David S. Miller       : New socket locking
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *       Steve Whitehouse      : Timer grabs socket ref.
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/net.h>
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/socket.h>
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/skbuff.h>
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/netdevice.h>
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/timer.h>
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/spinlock.h>
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/sock.h>
2560063497a95e716c9a689af3be2687d261f115b4Arun Sharma#include <linux/atomic.h>
268b1b1eb521004cec2518307c22dba8f4bff1c2bfHimangi Saraogi#include <linux/jiffies.h>
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/flow.h>
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/dn.h>
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Slow timer is for everything else (n * 500mS)
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SLOW_INTERVAL (HZ/2)
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void dn_slow_timer(unsigned long arg);
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid dn_start_slow_timer(struct sock *sk)
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
408a6e77d5209e459a9ec5c268c39800c06cd1dc86Eric Dumazet	setup_timer(&sk->sk_timer, dn_slow_timer, (unsigned long)sk);
418a6e77d5209e459a9ec5c268c39800c06cd1dc86Eric Dumazet	sk_reset_timer(sk, &sk->sk_timer, jiffies + SLOW_INTERVAL);
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid dn_stop_slow_timer(struct sock *sk)
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
468a6e77d5209e459a9ec5c268c39800c06cd1dc86Eric Dumazet	sk_stop_timer(sk, &sk->sk_timer);
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void dn_slow_timer(unsigned long arg)
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sock *sk = (struct sock *)arg;
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dn_scp *scp = DN_SK(sk);
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bh_lock_sock(sk);
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (sock_owned_by_user(sk)) {
578a6e77d5209e459a9ec5c268c39800c06cd1dc86Eric Dumazet		sk_reset_timer(sk, &sk->sk_timer, jiffies + HZ / 10);
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * The persist timer is the standard slow timer used for retransmits
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * in both connection establishment and disconnection as well as
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * in the RUN state. The different states are catered for by changing
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * the function pointer in the socket. Setting the timer to a value
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * of zero turns it off. We allow the persist_fxn to turn the
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * timer off in a permant way by returning non-zero, so that
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * timer based routines may remove sockets. This is why we have a
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * sock_hold()/sock_put() around the timer to prevent the socket
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * going away in the middle.
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (scp->persist && scp->persist_fxn) {
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (scp->persist <= SLOW_INTERVAL) {
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			scp->persist = 0;
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (scp->persist_fxn(sk))
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto out;
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			scp->persist -= SLOW_INTERVAL;
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Check for keepalive timeout. After the other timer 'cos if
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * the previous timer caused a retransmit, we don't need to
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * do this. scp->stamp is the last time that we sent a packet.
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * The keepalive function sends a link service packet to the
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * other end. If it remains unacknowledged, the standard
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * socket timers will eventually shut the socket down. Each
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * time we do this, scp->stamp will be updated, thus
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * we won't try and send another until scp->keepalive has passed
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * since the last successful transmission.
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (scp->keepalive && scp->keepalive_fxn && (scp->state == DN_RUN)) {
958b1b1eb521004cec2518307c22dba8f4bff1c2bfHimangi Saraogi		if (time_after_eq(jiffies, scp->stamp + scp->keepalive))
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			scp->keepalive_fxn(sk);
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
998a6e77d5209e459a9ec5c268c39800c06cd1dc86Eric Dumazet	sk_reset_timer(sk, &sk->sk_timer, jiffies + SLOW_INTERVAL);
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout:
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bh_unlock_sock(sk);
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sock_put(sk);
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
104