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) Joerg Reuter DL1BKE (jreuter@yaina.de)
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci#include <linux/errno.h>
862306a36Sopenharmony_ci#include <linux/types.h>
962306a36Sopenharmony_ci#include <linux/socket.h>
1062306a36Sopenharmony_ci#include <linux/spinlock.h>
1162306a36Sopenharmony_ci#include <linux/in.h>
1262306a36Sopenharmony_ci#include <linux/kernel.h>
1362306a36Sopenharmony_ci#include <linux/jiffies.h>
1462306a36Sopenharmony_ci#include <linux/timer.h>
1562306a36Sopenharmony_ci#include <linux/string.h>
1662306a36Sopenharmony_ci#include <linux/sockios.h>
1762306a36Sopenharmony_ci#include <linux/net.h>
1862306a36Sopenharmony_ci#include <net/tcp_states.h>
1962306a36Sopenharmony_ci#include <net/ax25.h>
2062306a36Sopenharmony_ci#include <linux/inet.h>
2162306a36Sopenharmony_ci#include <linux/netdevice.h>
2262306a36Sopenharmony_ci#include <linux/skbuff.h>
2362306a36Sopenharmony_ci#include <net/sock.h>
2462306a36Sopenharmony_ci#include <linux/uaccess.h>
2562306a36Sopenharmony_ci#include <linux/fcntl.h>
2662306a36Sopenharmony_ci#include <linux/mm.h>
2762306a36Sopenharmony_ci#include <linux/interrupt.h>
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_cistatic void ax25_ds_timeout(struct timer_list *);
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci/*
3262306a36Sopenharmony_ci *	Add DAMA slave timeout timer to timer list.
3362306a36Sopenharmony_ci *	Unlike the connection based timers the timeout function gets
3462306a36Sopenharmony_ci *	triggered every second. Please note that NET_AX25_DAMA_SLAVE_TIMEOUT
3562306a36Sopenharmony_ci *	(aka /proc/sys/net/ax25/{dev}/dama_slave_timeout) is still in
3662306a36Sopenharmony_ci *	1/10th of a second.
3762306a36Sopenharmony_ci */
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_civoid ax25_ds_setup_timer(ax25_dev *ax25_dev)
4062306a36Sopenharmony_ci{
4162306a36Sopenharmony_ci	timer_setup(&ax25_dev->dama.slave_timer, ax25_ds_timeout, 0);
4262306a36Sopenharmony_ci}
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_civoid ax25_ds_del_timer(ax25_dev *ax25_dev)
4562306a36Sopenharmony_ci{
4662306a36Sopenharmony_ci	if (ax25_dev)
4762306a36Sopenharmony_ci		del_timer(&ax25_dev->dama.slave_timer);
4862306a36Sopenharmony_ci}
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_civoid ax25_ds_set_timer(ax25_dev *ax25_dev)
5162306a36Sopenharmony_ci{
5262306a36Sopenharmony_ci	if (ax25_dev == NULL)		/* paranoia */
5362306a36Sopenharmony_ci		return;
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci	ax25_dev->dama.slave_timeout =
5662306a36Sopenharmony_ci		msecs_to_jiffies(ax25_dev->values[AX25_VALUES_DS_TIMEOUT]) / 10;
5762306a36Sopenharmony_ci	mod_timer(&ax25_dev->dama.slave_timer, jiffies + HZ);
5862306a36Sopenharmony_ci}
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci/*
6162306a36Sopenharmony_ci *	DAMA Slave Timeout
6262306a36Sopenharmony_ci *	Silently discard all (slave) connections in case our master forgot us...
6362306a36Sopenharmony_ci */
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_cistatic void ax25_ds_timeout(struct timer_list *t)
6662306a36Sopenharmony_ci{
6762306a36Sopenharmony_ci	ax25_dev *ax25_dev = from_timer(ax25_dev, t, dama.slave_timer);
6862306a36Sopenharmony_ci	ax25_cb *ax25;
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci	if (ax25_dev == NULL || !ax25_dev->dama.slave)
7162306a36Sopenharmony_ci		return;			/* Yikes! */
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci	if (!ax25_dev->dama.slave_timeout || --ax25_dev->dama.slave_timeout) {
7462306a36Sopenharmony_ci		ax25_ds_set_timer(ax25_dev);
7562306a36Sopenharmony_ci		return;
7662306a36Sopenharmony_ci	}
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci	spin_lock(&ax25_list_lock);
7962306a36Sopenharmony_ci	ax25_for_each(ax25, &ax25_list) {
8062306a36Sopenharmony_ci		if (ax25->ax25_dev != ax25_dev || !(ax25->condition & AX25_COND_DAMA_MODE))
8162306a36Sopenharmony_ci			continue;
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci		ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
8462306a36Sopenharmony_ci		ax25_disconnect(ax25, ETIMEDOUT);
8562306a36Sopenharmony_ci	}
8662306a36Sopenharmony_ci	spin_unlock(&ax25_list_lock);
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	ax25_dev_dama_off(ax25_dev);
8962306a36Sopenharmony_ci}
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_civoid ax25_ds_heartbeat_expiry(ax25_cb *ax25)
9262306a36Sopenharmony_ci{
9362306a36Sopenharmony_ci	struct sock *sk=ax25->sk;
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci	if (sk)
9662306a36Sopenharmony_ci		bh_lock_sock(sk);
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci	switch (ax25->state) {
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci	case AX25_STATE_0:
10162306a36Sopenharmony_ci	case AX25_STATE_2:
10262306a36Sopenharmony_ci		/* Magic here: If we listen() and a new link dies before it
10362306a36Sopenharmony_ci		   is accepted() it isn't 'dead' so doesn't get removed. */
10462306a36Sopenharmony_ci		if (!sk || sock_flag(sk, SOCK_DESTROY) ||
10562306a36Sopenharmony_ci		    (sk->sk_state == TCP_LISTEN &&
10662306a36Sopenharmony_ci		     sock_flag(sk, SOCK_DEAD))) {
10762306a36Sopenharmony_ci			if (sk) {
10862306a36Sopenharmony_ci				sock_hold(sk);
10962306a36Sopenharmony_ci				ax25_destroy_socket(ax25);
11062306a36Sopenharmony_ci				bh_unlock_sock(sk);
11162306a36Sopenharmony_ci				/* Ungrab socket and destroy it */
11262306a36Sopenharmony_ci				sock_put(sk);
11362306a36Sopenharmony_ci			} else
11462306a36Sopenharmony_ci				ax25_destroy_socket(ax25);
11562306a36Sopenharmony_ci			return;
11662306a36Sopenharmony_ci		}
11762306a36Sopenharmony_ci		break;
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	case AX25_STATE_3:
12062306a36Sopenharmony_ci		/*
12162306a36Sopenharmony_ci		 * Check the state of the receive buffer.
12262306a36Sopenharmony_ci		 */
12362306a36Sopenharmony_ci		if (sk != NULL) {
12462306a36Sopenharmony_ci			if (atomic_read(&sk->sk_rmem_alloc) <
12562306a36Sopenharmony_ci			    (sk->sk_rcvbuf >> 1) &&
12662306a36Sopenharmony_ci			    (ax25->condition & AX25_COND_OWN_RX_BUSY)) {
12762306a36Sopenharmony_ci				ax25->condition &= ~AX25_COND_OWN_RX_BUSY;
12862306a36Sopenharmony_ci				ax25->condition &= ~AX25_COND_ACK_PENDING;
12962306a36Sopenharmony_ci				break;
13062306a36Sopenharmony_ci			}
13162306a36Sopenharmony_ci		}
13262306a36Sopenharmony_ci		break;
13362306a36Sopenharmony_ci	}
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci	if (sk)
13662306a36Sopenharmony_ci		bh_unlock_sock(sk);
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci	ax25_start_heartbeat(ax25);
13962306a36Sopenharmony_ci}
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci/* dl1bke 960114: T3 works much like the IDLE timeout, but
14262306a36Sopenharmony_ci *                gets reloaded with every frame for this
14362306a36Sopenharmony_ci *		  connection.
14462306a36Sopenharmony_ci */
14562306a36Sopenharmony_civoid ax25_ds_t3timer_expiry(ax25_cb *ax25)
14662306a36Sopenharmony_ci{
14762306a36Sopenharmony_ci	ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
14862306a36Sopenharmony_ci	ax25_dama_off(ax25);
14962306a36Sopenharmony_ci	ax25_disconnect(ax25, ETIMEDOUT);
15062306a36Sopenharmony_ci}
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci/* dl1bke 960228: close the connection when IDLE expires.
15362306a36Sopenharmony_ci *		  unlike T3 this timer gets reloaded only on
15462306a36Sopenharmony_ci *		  I frames.
15562306a36Sopenharmony_ci */
15662306a36Sopenharmony_civoid ax25_ds_idletimer_expiry(ax25_cb *ax25)
15762306a36Sopenharmony_ci{
15862306a36Sopenharmony_ci	ax25_clear_queues(ax25);
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci	ax25->n2count = 0;
16162306a36Sopenharmony_ci	ax25->state = AX25_STATE_2;
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci	ax25_calculate_t1(ax25);
16462306a36Sopenharmony_ci	ax25_start_t1timer(ax25);
16562306a36Sopenharmony_ci	ax25_stop_t3timer(ax25);
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	if (ax25->sk != NULL) {
16862306a36Sopenharmony_ci		bh_lock_sock(ax25->sk);
16962306a36Sopenharmony_ci		ax25->sk->sk_state     = TCP_CLOSE;
17062306a36Sopenharmony_ci		ax25->sk->sk_err       = 0;
17162306a36Sopenharmony_ci		ax25->sk->sk_shutdown |= SEND_SHUTDOWN;
17262306a36Sopenharmony_ci		if (!sock_flag(ax25->sk, SOCK_DEAD)) {
17362306a36Sopenharmony_ci			ax25->sk->sk_state_change(ax25->sk);
17462306a36Sopenharmony_ci			sock_set_flag(ax25->sk, SOCK_DEAD);
17562306a36Sopenharmony_ci		}
17662306a36Sopenharmony_ci		bh_unlock_sock(ax25->sk);
17762306a36Sopenharmony_ci	}
17862306a36Sopenharmony_ci}
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci/* dl1bke 960114: The DAMA protocol requires to send data and SABM/DISC
18162306a36Sopenharmony_ci *                within the poll of any connected channel. Remember
18262306a36Sopenharmony_ci *                that we are not allowed to send anything unless we
18362306a36Sopenharmony_ci *                get polled by the Master.
18462306a36Sopenharmony_ci *
18562306a36Sopenharmony_ci *                Thus we'll have to do parts of our T1 handling in
18662306a36Sopenharmony_ci *                ax25_enquiry_response().
18762306a36Sopenharmony_ci */
18862306a36Sopenharmony_civoid ax25_ds_t1_timeout(ax25_cb *ax25)
18962306a36Sopenharmony_ci{
19062306a36Sopenharmony_ci	switch (ax25->state) {
19162306a36Sopenharmony_ci	case AX25_STATE_1:
19262306a36Sopenharmony_ci		if (ax25->n2count == ax25->n2) {
19362306a36Sopenharmony_ci			if (ax25->modulus == AX25_MODULUS) {
19462306a36Sopenharmony_ci				ax25_disconnect(ax25, ETIMEDOUT);
19562306a36Sopenharmony_ci				return;
19662306a36Sopenharmony_ci			} else {
19762306a36Sopenharmony_ci				ax25->modulus = AX25_MODULUS;
19862306a36Sopenharmony_ci				ax25->window  = ax25->ax25_dev->values[AX25_VALUES_WINDOW];
19962306a36Sopenharmony_ci				ax25->n2count = 0;
20062306a36Sopenharmony_ci				ax25_send_control(ax25, AX25_SABM, AX25_POLLOFF, AX25_COMMAND);
20162306a36Sopenharmony_ci			}
20262306a36Sopenharmony_ci		} else {
20362306a36Sopenharmony_ci			ax25->n2count++;
20462306a36Sopenharmony_ci			if (ax25->modulus == AX25_MODULUS)
20562306a36Sopenharmony_ci				ax25_send_control(ax25, AX25_SABM, AX25_POLLOFF, AX25_COMMAND);
20662306a36Sopenharmony_ci			else
20762306a36Sopenharmony_ci				ax25_send_control(ax25, AX25_SABME, AX25_POLLOFF, AX25_COMMAND);
20862306a36Sopenharmony_ci		}
20962306a36Sopenharmony_ci		break;
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci	case AX25_STATE_2:
21262306a36Sopenharmony_ci		if (ax25->n2count == ax25->n2) {
21362306a36Sopenharmony_ci			ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
21462306a36Sopenharmony_ci			if (!sock_flag(ax25->sk, SOCK_DESTROY))
21562306a36Sopenharmony_ci				ax25_disconnect(ax25, ETIMEDOUT);
21662306a36Sopenharmony_ci			return;
21762306a36Sopenharmony_ci		} else {
21862306a36Sopenharmony_ci			ax25->n2count++;
21962306a36Sopenharmony_ci		}
22062306a36Sopenharmony_ci		break;
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci	case AX25_STATE_3:
22362306a36Sopenharmony_ci		if (ax25->n2count == ax25->n2) {
22462306a36Sopenharmony_ci			ax25_send_control(ax25, AX25_DM, AX25_POLLON, AX25_RESPONSE);
22562306a36Sopenharmony_ci			ax25_disconnect(ax25, ETIMEDOUT);
22662306a36Sopenharmony_ci			return;
22762306a36Sopenharmony_ci		} else {
22862306a36Sopenharmony_ci			ax25->n2count++;
22962306a36Sopenharmony_ci		}
23062306a36Sopenharmony_ci		break;
23162306a36Sopenharmony_ci	}
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci	ax25_calculate_t1(ax25);
23462306a36Sopenharmony_ci	ax25_start_t1timer(ax25);
23562306a36Sopenharmony_ci}
236