162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
562306a36Sopenharmony_ci * Copyright (C) 2002 Ralf Baechle DO1GRB (ralf@gnu.org)
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci#include <linux/errno.h>
862306a36Sopenharmony_ci#include <linux/types.h>
962306a36Sopenharmony_ci#include <linux/socket.h>
1062306a36Sopenharmony_ci#include <linux/in.h>
1162306a36Sopenharmony_ci#include <linux/kernel.h>
1262306a36Sopenharmony_ci#include <linux/jiffies.h>
1362306a36Sopenharmony_ci#include <linux/timer.h>
1462306a36Sopenharmony_ci#include <linux/string.h>
1562306a36Sopenharmony_ci#include <linux/sockios.h>
1662306a36Sopenharmony_ci#include <linux/net.h>
1762306a36Sopenharmony_ci#include <net/ax25.h>
1862306a36Sopenharmony_ci#include <linux/inet.h>
1962306a36Sopenharmony_ci#include <linux/netdevice.h>
2062306a36Sopenharmony_ci#include <linux/skbuff.h>
2162306a36Sopenharmony_ci#include <net/sock.h>
2262306a36Sopenharmony_ci#include <net/tcp_states.h>
2362306a36Sopenharmony_ci#include <linux/fcntl.h>
2462306a36Sopenharmony_ci#include <linux/mm.h>
2562306a36Sopenharmony_ci#include <linux/interrupt.h>
2662306a36Sopenharmony_ci#include <net/rose.h>
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_cistatic void rose_heartbeat_expiry(struct timer_list *t);
2962306a36Sopenharmony_cistatic void rose_timer_expiry(struct timer_list *);
3062306a36Sopenharmony_cistatic void rose_idletimer_expiry(struct timer_list *);
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_civoid rose_start_heartbeat(struct sock *sk)
3362306a36Sopenharmony_ci{
3462306a36Sopenharmony_ci	sk_stop_timer(sk, &sk->sk_timer);
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci	sk->sk_timer.function = rose_heartbeat_expiry;
3762306a36Sopenharmony_ci	sk->sk_timer.expires  = jiffies + 5 * HZ;
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci	sk_reset_timer(sk, &sk->sk_timer, sk->sk_timer.expires);
4062306a36Sopenharmony_ci}
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_civoid rose_start_t1timer(struct sock *sk)
4362306a36Sopenharmony_ci{
4462306a36Sopenharmony_ci	struct rose_sock *rose = rose_sk(sk);
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci	sk_stop_timer(sk, &rose->timer);
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci	rose->timer.function = rose_timer_expiry;
4962306a36Sopenharmony_ci	rose->timer.expires  = jiffies + rose->t1;
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci	sk_reset_timer(sk, &rose->timer, rose->timer.expires);
5262306a36Sopenharmony_ci}
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_civoid rose_start_t2timer(struct sock *sk)
5562306a36Sopenharmony_ci{
5662306a36Sopenharmony_ci	struct rose_sock *rose = rose_sk(sk);
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci	sk_stop_timer(sk, &rose->timer);
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	rose->timer.function = rose_timer_expiry;
6162306a36Sopenharmony_ci	rose->timer.expires  = jiffies + rose->t2;
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	sk_reset_timer(sk, &rose->timer, rose->timer.expires);
6462306a36Sopenharmony_ci}
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_civoid rose_start_t3timer(struct sock *sk)
6762306a36Sopenharmony_ci{
6862306a36Sopenharmony_ci	struct rose_sock *rose = rose_sk(sk);
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci	sk_stop_timer(sk, &rose->timer);
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	rose->timer.function = rose_timer_expiry;
7362306a36Sopenharmony_ci	rose->timer.expires  = jiffies + rose->t3;
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	sk_reset_timer(sk, &rose->timer, rose->timer.expires);
7662306a36Sopenharmony_ci}
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_civoid rose_start_hbtimer(struct sock *sk)
7962306a36Sopenharmony_ci{
8062306a36Sopenharmony_ci	struct rose_sock *rose = rose_sk(sk);
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	sk_stop_timer(sk, &rose->timer);
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci	rose->timer.function = rose_timer_expiry;
8562306a36Sopenharmony_ci	rose->timer.expires  = jiffies + rose->hb;
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	sk_reset_timer(sk, &rose->timer, rose->timer.expires);
8862306a36Sopenharmony_ci}
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_civoid rose_start_idletimer(struct sock *sk)
9162306a36Sopenharmony_ci{
9262306a36Sopenharmony_ci	struct rose_sock *rose = rose_sk(sk);
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	sk_stop_timer(sk, &rose->idletimer);
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	if (rose->idle > 0) {
9762306a36Sopenharmony_ci		rose->idletimer.function = rose_idletimer_expiry;
9862306a36Sopenharmony_ci		rose->idletimer.expires  = jiffies + rose->idle;
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci		sk_reset_timer(sk, &rose->idletimer, rose->idletimer.expires);
10162306a36Sopenharmony_ci	}
10262306a36Sopenharmony_ci}
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_civoid rose_stop_heartbeat(struct sock *sk)
10562306a36Sopenharmony_ci{
10662306a36Sopenharmony_ci	sk_stop_timer(sk, &sk->sk_timer);
10762306a36Sopenharmony_ci}
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_civoid rose_stop_timer(struct sock *sk)
11062306a36Sopenharmony_ci{
11162306a36Sopenharmony_ci	sk_stop_timer(sk, &rose_sk(sk)->timer);
11262306a36Sopenharmony_ci}
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_civoid rose_stop_idletimer(struct sock *sk)
11562306a36Sopenharmony_ci{
11662306a36Sopenharmony_ci	sk_stop_timer(sk, &rose_sk(sk)->idletimer);
11762306a36Sopenharmony_ci}
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_cistatic void rose_heartbeat_expiry(struct timer_list *t)
12062306a36Sopenharmony_ci{
12162306a36Sopenharmony_ci	struct sock *sk = from_timer(sk, t, sk_timer);
12262306a36Sopenharmony_ci	struct rose_sock *rose = rose_sk(sk);
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	bh_lock_sock(sk);
12562306a36Sopenharmony_ci	switch (rose->state) {
12662306a36Sopenharmony_ci	case ROSE_STATE_0:
12762306a36Sopenharmony_ci		/* Magic here: If we listen() and a new link dies before it
12862306a36Sopenharmony_ci		   is accepted() it isn't 'dead' so doesn't get removed. */
12962306a36Sopenharmony_ci		if (sock_flag(sk, SOCK_DESTROY) ||
13062306a36Sopenharmony_ci		    (sk->sk_state == TCP_LISTEN && sock_flag(sk, SOCK_DEAD))) {
13162306a36Sopenharmony_ci			bh_unlock_sock(sk);
13262306a36Sopenharmony_ci			rose_destroy_socket(sk);
13362306a36Sopenharmony_ci			sock_put(sk);
13462306a36Sopenharmony_ci			return;
13562306a36Sopenharmony_ci		}
13662306a36Sopenharmony_ci		break;
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci	case ROSE_STATE_3:
13962306a36Sopenharmony_ci		/*
14062306a36Sopenharmony_ci		 * Check for the state of the receive buffer.
14162306a36Sopenharmony_ci		 */
14262306a36Sopenharmony_ci		if (atomic_read(&sk->sk_rmem_alloc) < (sk->sk_rcvbuf / 2) &&
14362306a36Sopenharmony_ci		    (rose->condition & ROSE_COND_OWN_RX_BUSY)) {
14462306a36Sopenharmony_ci			rose->condition &= ~ROSE_COND_OWN_RX_BUSY;
14562306a36Sopenharmony_ci			rose->condition &= ~ROSE_COND_ACK_PENDING;
14662306a36Sopenharmony_ci			rose->vl         = rose->vr;
14762306a36Sopenharmony_ci			rose_write_internal(sk, ROSE_RR);
14862306a36Sopenharmony_ci			rose_stop_timer(sk);	/* HB */
14962306a36Sopenharmony_ci			break;
15062306a36Sopenharmony_ci		}
15162306a36Sopenharmony_ci		break;
15262306a36Sopenharmony_ci	}
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci	rose_start_heartbeat(sk);
15562306a36Sopenharmony_ci	bh_unlock_sock(sk);
15662306a36Sopenharmony_ci	sock_put(sk);
15762306a36Sopenharmony_ci}
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_cistatic void rose_timer_expiry(struct timer_list *t)
16062306a36Sopenharmony_ci{
16162306a36Sopenharmony_ci	struct rose_sock *rose = from_timer(rose, t, timer);
16262306a36Sopenharmony_ci	struct sock *sk = &rose->sock;
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci	bh_lock_sock(sk);
16562306a36Sopenharmony_ci	switch (rose->state) {
16662306a36Sopenharmony_ci	case ROSE_STATE_1:	/* T1 */
16762306a36Sopenharmony_ci	case ROSE_STATE_4:	/* T2 */
16862306a36Sopenharmony_ci		rose_write_internal(sk, ROSE_CLEAR_REQUEST);
16962306a36Sopenharmony_ci		rose->state = ROSE_STATE_2;
17062306a36Sopenharmony_ci		rose_start_t3timer(sk);
17162306a36Sopenharmony_ci		break;
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	case ROSE_STATE_2:	/* T3 */
17462306a36Sopenharmony_ci		rose->neighbour->use--;
17562306a36Sopenharmony_ci		rose_disconnect(sk, ETIMEDOUT, -1, -1);
17662306a36Sopenharmony_ci		break;
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci	case ROSE_STATE_3:	/* HB */
17962306a36Sopenharmony_ci		if (rose->condition & ROSE_COND_ACK_PENDING) {
18062306a36Sopenharmony_ci			rose->condition &= ~ROSE_COND_ACK_PENDING;
18162306a36Sopenharmony_ci			rose_enquiry_response(sk);
18262306a36Sopenharmony_ci		}
18362306a36Sopenharmony_ci		break;
18462306a36Sopenharmony_ci	}
18562306a36Sopenharmony_ci	bh_unlock_sock(sk);
18662306a36Sopenharmony_ci	sock_put(sk);
18762306a36Sopenharmony_ci}
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_cistatic void rose_idletimer_expiry(struct timer_list *t)
19062306a36Sopenharmony_ci{
19162306a36Sopenharmony_ci	struct rose_sock *rose = from_timer(rose, t, idletimer);
19262306a36Sopenharmony_ci	struct sock *sk = &rose->sock;
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci	bh_lock_sock(sk);
19562306a36Sopenharmony_ci	rose_clear_queues(sk);
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	rose_write_internal(sk, ROSE_CLEAR_REQUEST);
19862306a36Sopenharmony_ci	rose_sk(sk)->state = ROSE_STATE_2;
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci	rose_start_t3timer(sk);
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	sk->sk_state     = TCP_CLOSE;
20362306a36Sopenharmony_ci	sk->sk_err       = 0;
20462306a36Sopenharmony_ci	sk->sk_shutdown |= SEND_SHUTDOWN;
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	if (!sock_flag(sk, SOCK_DEAD)) {
20762306a36Sopenharmony_ci		sk->sk_state_change(sk);
20862306a36Sopenharmony_ci		sock_set_flag(sk, SOCK_DEAD);
20962306a36Sopenharmony_ci	}
21062306a36Sopenharmony_ci	bh_unlock_sock(sk);
21162306a36Sopenharmony_ci	sock_put(sk);
21262306a36Sopenharmony_ci}
213