summaryrefslogtreecommitdiffstats
path: root/net/rose/rose_timer.c
blob: 572975e5d3149187648dece2462e2b5ce1688672 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
/*
 *	ROSE release 002
 *
 *	This code REQUIRES 2.1.15 or higher/ NET3.038
 *
 *	This module:
 *		This module is free software; you can redistribute it and/or
 *		modify it under the terms of the GNU General Public License
 *		as published by the Free Software Foundation; either version
 *		2 of the License, or (at your option) any later version.
 *
 *	History
 *	ROSE 001	Jonathan(G4KLX)	Cloned from nr_timer.c
 */

#include <linux/config.h>
#if defined(CONFIG_ROSE) || defined(CONFIG_ROSE_MODULE)
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
#include <linux/in.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/timer.h>
#include <linux/string.h>
#include <linux/sockios.h>
#include <linux/net.h>
#include <net/ax25.h>
#include <linux/inet.h>
#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <net/sock.h>
#include <asm/segment.h>
#include <asm/system.h>
#include <linux/fcntl.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
#include <net/rose.h>

static void rose_timer(unsigned long);

/*
 *	Linux set timer
 */
void rose_set_timer(struct sock *sk)
{
	unsigned long flags;

	save_flags(flags); cli();
	del_timer(&sk->timer);
	restore_flags(flags);

	sk->timer.data     = (unsigned long)sk;
	sk->timer.function = &rose_timer;
	sk->timer.expires  = jiffies + (HZ / 10);

	add_timer(&sk->timer);
}

/*
 *	ROSE Timer
 *
 *	This routine is called every 100ms. Decrement timer by this
 *	amount - if expired then process the event.
 */
static void rose_timer(unsigned long param)
{
	struct sock *sk = (struct sock *)param;

	switch (sk->protinfo.rose->state) {
		case ROSE_STATE_0:
			/* Magic here: If we listen() and a new link dies before it
			   is accepted() it isn't 'dead' so doesn't get removed. */
			if (sk->destroy || (sk->state == TCP_LISTEN && sk->dead)) {
				del_timer(&sk->timer);
				rose_destroy_socket(sk);
				return;
			}
			break;

		case ROSE_STATE_3:
			/*
			 * Check for the state of the receive buffer.
			 */
			if (atomic_read(&sk->rmem_alloc) < (sk->rcvbuf / 2) &&
			    (sk->protinfo.rose->condition & ROSE_COND_OWN_RX_BUSY)) {
				sk->protinfo.rose->condition &= ~ROSE_COND_OWN_RX_BUSY;
				sk->protinfo.rose->condition &= ~ROSE_COND_ACK_PENDING;
				sk->protinfo.rose->vl         = sk->protinfo.rose->vr;
				sk->protinfo.rose->timer      = 0;
				rose_write_internal(sk, ROSE_RR);
				break;
			}
			/*
			 * Check for frames to transmit.
			 */
			rose_kick(sk);
			break;

		default:
			break;
	}

	if (sk->protinfo.rose->timer == 0 || --sk->protinfo.rose->timer > 0) {
		rose_set_timer(sk);
		return;
	}

	/*
	 * Timer has expired, it may have been T1, T2, T3 or HB. We can tell
	 * by the socket state.
	 */
	switch (sk->protinfo.rose->state) {
		case ROSE_STATE_3:	/* HB */
			if (sk->protinfo.rose->condition & ROSE_COND_ACK_PENDING) {
				sk->protinfo.rose->condition &= ~ROSE_COND_ACK_PENDING;
				rose_enquiry_response(sk);
			}
			break;

		case ROSE_STATE_1:	/* T1 */
		case ROSE_STATE_4:	/* T2 */
			rose_write_internal(sk, ROSE_CLEAR_REQUEST);
			sk->protinfo.rose->state = ROSE_STATE_2;
			sk->protinfo.rose->timer = sk->protinfo.rose->t3;
			break;

		case ROSE_STATE_2:	/* T3 */
			rose_clear_queues(sk);
			sk->protinfo.rose->state = ROSE_STATE_0;
			sk->state                = TCP_CLOSE;
			sk->err                  = ETIMEDOUT;
			sk->shutdown            |= SEND_SHUTDOWN;
			if (!sk->dead)
				sk->state_change(sk);
			sk->dead                 = 1;
			break;
	}

	rose_set_timer(sk);
}

#endif