162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *	X.25 Packet Layer release 002
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci *	This is ALPHA test software. This code may break your machine,
662306a36Sopenharmony_ci *	randomly fail to work with new releases, misbehave and/or generally
762306a36Sopenharmony_ci *	screw up. It might even work.
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci *	This code REQUIRES 2.1.15 or higher
1062306a36Sopenharmony_ci *
1162306a36Sopenharmony_ci *	History
1262306a36Sopenharmony_ci *	X.25 001	Jonathan Naylor	  Started coding.
1362306a36Sopenharmony_ci *	X.25 002	Jonathan Naylor	  Centralised disconnection code.
1462306a36Sopenharmony_ci *					  New timer architecture.
1562306a36Sopenharmony_ci *	2000-03-20	Daniela Squassoni Disabling/enabling of facilities
1662306a36Sopenharmony_ci *					  negotiation.
1762306a36Sopenharmony_ci *	2000-11-10	Henner Eisen	  Check and reset for out-of-sequence
1862306a36Sopenharmony_ci *					  i-frames.
1962306a36Sopenharmony_ci */
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#define pr_fmt(fmt) "X25: " fmt
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#include <linux/slab.h>
2462306a36Sopenharmony_ci#include <linux/errno.h>
2562306a36Sopenharmony_ci#include <linux/kernel.h>
2662306a36Sopenharmony_ci#include <linux/string.h>
2762306a36Sopenharmony_ci#include <linux/skbuff.h>
2862306a36Sopenharmony_ci#include <net/sock.h>
2962306a36Sopenharmony_ci#include <net/tcp_states.h>
3062306a36Sopenharmony_ci#include <net/x25.h>
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_cistatic int x25_queue_rx_frame(struct sock *sk, struct sk_buff *skb, int more)
3362306a36Sopenharmony_ci{
3462306a36Sopenharmony_ci	struct sk_buff *skbo, *skbn = skb;
3562306a36Sopenharmony_ci	struct x25_sock *x25 = x25_sk(sk);
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci	if (more) {
3862306a36Sopenharmony_ci		x25->fraglen += skb->len;
3962306a36Sopenharmony_ci		skb_queue_tail(&x25->fragment_queue, skb);
4062306a36Sopenharmony_ci		skb_set_owner_r(skb, sk);
4162306a36Sopenharmony_ci		return 0;
4262306a36Sopenharmony_ci	}
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci	if (x25->fraglen > 0) {	/* End of fragment */
4562306a36Sopenharmony_ci		int len = x25->fraglen + skb->len;
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci		if ((skbn = alloc_skb(len, GFP_ATOMIC)) == NULL){
4862306a36Sopenharmony_ci			kfree_skb(skb);
4962306a36Sopenharmony_ci			return 1;
5062306a36Sopenharmony_ci		}
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci		skb_queue_tail(&x25->fragment_queue, skb);
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci		skb_reset_transport_header(skbn);
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci		skbo = skb_dequeue(&x25->fragment_queue);
5762306a36Sopenharmony_ci		skb_copy_from_linear_data(skbo, skb_put(skbn, skbo->len),
5862306a36Sopenharmony_ci					  skbo->len);
5962306a36Sopenharmony_ci		kfree_skb(skbo);
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci		while ((skbo =
6262306a36Sopenharmony_ci			skb_dequeue(&x25->fragment_queue)) != NULL) {
6362306a36Sopenharmony_ci			skb_pull(skbo, (x25->neighbour->extended) ?
6462306a36Sopenharmony_ci					X25_EXT_MIN_LEN : X25_STD_MIN_LEN);
6562306a36Sopenharmony_ci			skb_copy_from_linear_data(skbo,
6662306a36Sopenharmony_ci						  skb_put(skbn, skbo->len),
6762306a36Sopenharmony_ci						  skbo->len);
6862306a36Sopenharmony_ci			kfree_skb(skbo);
6962306a36Sopenharmony_ci		}
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci		x25->fraglen = 0;
7262306a36Sopenharmony_ci	}
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci	skb_set_owner_r(skbn, sk);
7562306a36Sopenharmony_ci	skb_queue_tail(&sk->sk_receive_queue, skbn);
7662306a36Sopenharmony_ci	if (!sock_flag(sk, SOCK_DEAD))
7762306a36Sopenharmony_ci		sk->sk_data_ready(sk);
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	return 0;
8062306a36Sopenharmony_ci}
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci/*
8362306a36Sopenharmony_ci * State machine for state 1, Awaiting Call Accepted State.
8462306a36Sopenharmony_ci * The handling of the timer(s) is in file x25_timer.c.
8562306a36Sopenharmony_ci * Handling of state 0 and connection release is in af_x25.c.
8662306a36Sopenharmony_ci */
8762306a36Sopenharmony_cistatic int x25_state1_machine(struct sock *sk, struct sk_buff *skb, int frametype)
8862306a36Sopenharmony_ci{
8962306a36Sopenharmony_ci	struct x25_address source_addr, dest_addr;
9062306a36Sopenharmony_ci	int len;
9162306a36Sopenharmony_ci	struct x25_sock *x25 = x25_sk(sk);
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	switch (frametype) {
9462306a36Sopenharmony_ci	case X25_CALL_ACCEPTED: {
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci		x25_stop_timer(sk);
9762306a36Sopenharmony_ci		x25->condition = 0x00;
9862306a36Sopenharmony_ci		x25->vs        = 0;
9962306a36Sopenharmony_ci		x25->va        = 0;
10062306a36Sopenharmony_ci		x25->vr        = 0;
10162306a36Sopenharmony_ci		x25->vl        = 0;
10262306a36Sopenharmony_ci		x25->state     = X25_STATE_3;
10362306a36Sopenharmony_ci		sk->sk_state   = TCP_ESTABLISHED;
10462306a36Sopenharmony_ci		/*
10562306a36Sopenharmony_ci		 *	Parse the data in the frame.
10662306a36Sopenharmony_ci		 */
10762306a36Sopenharmony_ci		if (!pskb_may_pull(skb, X25_STD_MIN_LEN))
10862306a36Sopenharmony_ci			goto out_clear;
10962306a36Sopenharmony_ci		skb_pull(skb, X25_STD_MIN_LEN);
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci		len = x25_parse_address_block(skb, &source_addr,
11262306a36Sopenharmony_ci					      &dest_addr);
11362306a36Sopenharmony_ci		if (len > 0)
11462306a36Sopenharmony_ci			skb_pull(skb, len);
11562306a36Sopenharmony_ci		else if (len < 0)
11662306a36Sopenharmony_ci			goto out_clear;
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci		len = x25_parse_facilities(skb, &x25->facilities,
11962306a36Sopenharmony_ci					   &x25->dte_facilities,
12062306a36Sopenharmony_ci					   &x25->vc_facil_mask);
12162306a36Sopenharmony_ci		if (len > 0)
12262306a36Sopenharmony_ci			skb_pull(skb, len);
12362306a36Sopenharmony_ci		else if (len < 0)
12462306a36Sopenharmony_ci			goto out_clear;
12562306a36Sopenharmony_ci		/*
12662306a36Sopenharmony_ci		 *	Copy any Call User Data.
12762306a36Sopenharmony_ci		 */
12862306a36Sopenharmony_ci		if (skb->len > 0) {
12962306a36Sopenharmony_ci			if (skb->len > X25_MAX_CUD_LEN)
13062306a36Sopenharmony_ci				goto out_clear;
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci			skb_copy_bits(skb, 0, x25->calluserdata.cuddata,
13362306a36Sopenharmony_ci				skb->len);
13462306a36Sopenharmony_ci			x25->calluserdata.cudlength = skb->len;
13562306a36Sopenharmony_ci		}
13662306a36Sopenharmony_ci		if (!sock_flag(sk, SOCK_DEAD))
13762306a36Sopenharmony_ci			sk->sk_state_change(sk);
13862306a36Sopenharmony_ci		break;
13962306a36Sopenharmony_ci	}
14062306a36Sopenharmony_ci	case X25_CALL_REQUEST:
14162306a36Sopenharmony_ci		/* call collision */
14262306a36Sopenharmony_ci		x25->causediag.cause      = 0x01;
14362306a36Sopenharmony_ci		x25->causediag.diagnostic = 0x48;
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci		x25_write_internal(sk, X25_CLEAR_REQUEST);
14662306a36Sopenharmony_ci		x25_disconnect(sk, EISCONN, 0x01, 0x48);
14762306a36Sopenharmony_ci		break;
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci	case X25_CLEAR_REQUEST:
15062306a36Sopenharmony_ci		if (!pskb_may_pull(skb, X25_STD_MIN_LEN + 2))
15162306a36Sopenharmony_ci			goto out_clear;
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci		x25_write_internal(sk, X25_CLEAR_CONFIRMATION);
15462306a36Sopenharmony_ci		x25_disconnect(sk, ECONNREFUSED, skb->data[3], skb->data[4]);
15562306a36Sopenharmony_ci		break;
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci	default:
15862306a36Sopenharmony_ci		break;
15962306a36Sopenharmony_ci	}
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci	return 0;
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ciout_clear:
16462306a36Sopenharmony_ci	x25_write_internal(sk, X25_CLEAR_REQUEST);
16562306a36Sopenharmony_ci	x25->state = X25_STATE_2;
16662306a36Sopenharmony_ci	x25_start_t23timer(sk);
16762306a36Sopenharmony_ci	return 0;
16862306a36Sopenharmony_ci}
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci/*
17162306a36Sopenharmony_ci * State machine for state 2, Awaiting Clear Confirmation State.
17262306a36Sopenharmony_ci * The handling of the timer(s) is in file x25_timer.c
17362306a36Sopenharmony_ci * Handling of state 0 and connection release is in af_x25.c.
17462306a36Sopenharmony_ci */
17562306a36Sopenharmony_cistatic int x25_state2_machine(struct sock *sk, struct sk_buff *skb, int frametype)
17662306a36Sopenharmony_ci{
17762306a36Sopenharmony_ci	switch (frametype) {
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci		case X25_CLEAR_REQUEST:
18062306a36Sopenharmony_ci			if (!pskb_may_pull(skb, X25_STD_MIN_LEN + 2))
18162306a36Sopenharmony_ci				goto out_clear;
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci			x25_write_internal(sk, X25_CLEAR_CONFIRMATION);
18462306a36Sopenharmony_ci			x25_disconnect(sk, 0, skb->data[3], skb->data[4]);
18562306a36Sopenharmony_ci			break;
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci		case X25_CLEAR_CONFIRMATION:
18862306a36Sopenharmony_ci			x25_disconnect(sk, 0, 0, 0);
18962306a36Sopenharmony_ci			break;
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci		default:
19262306a36Sopenharmony_ci			break;
19362306a36Sopenharmony_ci	}
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	return 0;
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ciout_clear:
19862306a36Sopenharmony_ci	x25_write_internal(sk, X25_CLEAR_REQUEST);
19962306a36Sopenharmony_ci	x25_start_t23timer(sk);
20062306a36Sopenharmony_ci	return 0;
20162306a36Sopenharmony_ci}
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci/*
20462306a36Sopenharmony_ci * State machine for state 3, Connected State.
20562306a36Sopenharmony_ci * The handling of the timer(s) is in file x25_timer.c
20662306a36Sopenharmony_ci * Handling of state 0 and connection release is in af_x25.c.
20762306a36Sopenharmony_ci */
20862306a36Sopenharmony_cistatic int x25_state3_machine(struct sock *sk, struct sk_buff *skb, int frametype, int ns, int nr, int q, int d, int m)
20962306a36Sopenharmony_ci{
21062306a36Sopenharmony_ci	int queued = 0;
21162306a36Sopenharmony_ci	int modulus;
21262306a36Sopenharmony_ci	struct x25_sock *x25 = x25_sk(sk);
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci	modulus = (x25->neighbour->extended) ? X25_EMODULUS : X25_SMODULUS;
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci	switch (frametype) {
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci		case X25_RESET_REQUEST:
21962306a36Sopenharmony_ci			x25_write_internal(sk, X25_RESET_CONFIRMATION);
22062306a36Sopenharmony_ci			x25_stop_timer(sk);
22162306a36Sopenharmony_ci			x25->condition = 0x00;
22262306a36Sopenharmony_ci			x25->vs        = 0;
22362306a36Sopenharmony_ci			x25->vr        = 0;
22462306a36Sopenharmony_ci			x25->va        = 0;
22562306a36Sopenharmony_ci			x25->vl        = 0;
22662306a36Sopenharmony_ci			x25_requeue_frames(sk);
22762306a36Sopenharmony_ci			break;
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci		case X25_CLEAR_REQUEST:
23062306a36Sopenharmony_ci			if (!pskb_may_pull(skb, X25_STD_MIN_LEN + 2))
23162306a36Sopenharmony_ci				goto out_clear;
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci			x25_write_internal(sk, X25_CLEAR_CONFIRMATION);
23462306a36Sopenharmony_ci			x25_disconnect(sk, 0, skb->data[3], skb->data[4]);
23562306a36Sopenharmony_ci			break;
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci		case X25_RR:
23862306a36Sopenharmony_ci		case X25_RNR:
23962306a36Sopenharmony_ci			if (!x25_validate_nr(sk, nr)) {
24062306a36Sopenharmony_ci				x25_clear_queues(sk);
24162306a36Sopenharmony_ci				x25_write_internal(sk, X25_RESET_REQUEST);
24262306a36Sopenharmony_ci				x25_start_t22timer(sk);
24362306a36Sopenharmony_ci				x25->condition = 0x00;
24462306a36Sopenharmony_ci				x25->vs        = 0;
24562306a36Sopenharmony_ci				x25->vr        = 0;
24662306a36Sopenharmony_ci				x25->va        = 0;
24762306a36Sopenharmony_ci				x25->vl        = 0;
24862306a36Sopenharmony_ci				x25->state     = X25_STATE_4;
24962306a36Sopenharmony_ci			} else {
25062306a36Sopenharmony_ci				x25_frames_acked(sk, nr);
25162306a36Sopenharmony_ci				if (frametype == X25_RNR) {
25262306a36Sopenharmony_ci					x25->condition |= X25_COND_PEER_RX_BUSY;
25362306a36Sopenharmony_ci				} else {
25462306a36Sopenharmony_ci					x25->condition &= ~X25_COND_PEER_RX_BUSY;
25562306a36Sopenharmony_ci				}
25662306a36Sopenharmony_ci			}
25762306a36Sopenharmony_ci			break;
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci		case X25_DATA:	/* XXX */
26062306a36Sopenharmony_ci			x25->condition &= ~X25_COND_PEER_RX_BUSY;
26162306a36Sopenharmony_ci			if ((ns != x25->vr) || !x25_validate_nr(sk, nr)) {
26262306a36Sopenharmony_ci				x25_clear_queues(sk);
26362306a36Sopenharmony_ci				x25_write_internal(sk, X25_RESET_REQUEST);
26462306a36Sopenharmony_ci				x25_start_t22timer(sk);
26562306a36Sopenharmony_ci				x25->condition = 0x00;
26662306a36Sopenharmony_ci				x25->vs        = 0;
26762306a36Sopenharmony_ci				x25->vr        = 0;
26862306a36Sopenharmony_ci				x25->va        = 0;
26962306a36Sopenharmony_ci				x25->vl        = 0;
27062306a36Sopenharmony_ci				x25->state     = X25_STATE_4;
27162306a36Sopenharmony_ci				break;
27262306a36Sopenharmony_ci			}
27362306a36Sopenharmony_ci			x25_frames_acked(sk, nr);
27462306a36Sopenharmony_ci			if (ns == x25->vr) {
27562306a36Sopenharmony_ci				if (x25_queue_rx_frame(sk, skb, m) == 0) {
27662306a36Sopenharmony_ci					x25->vr = (x25->vr + 1) % modulus;
27762306a36Sopenharmony_ci					queued = 1;
27862306a36Sopenharmony_ci				} else {
27962306a36Sopenharmony_ci					/* Should never happen */
28062306a36Sopenharmony_ci					x25_clear_queues(sk);
28162306a36Sopenharmony_ci					x25_write_internal(sk, X25_RESET_REQUEST);
28262306a36Sopenharmony_ci					x25_start_t22timer(sk);
28362306a36Sopenharmony_ci					x25->condition = 0x00;
28462306a36Sopenharmony_ci					x25->vs        = 0;
28562306a36Sopenharmony_ci					x25->vr        = 0;
28662306a36Sopenharmony_ci					x25->va        = 0;
28762306a36Sopenharmony_ci					x25->vl        = 0;
28862306a36Sopenharmony_ci					x25->state     = X25_STATE_4;
28962306a36Sopenharmony_ci					break;
29062306a36Sopenharmony_ci				}
29162306a36Sopenharmony_ci				if (atomic_read(&sk->sk_rmem_alloc) >
29262306a36Sopenharmony_ci				    (sk->sk_rcvbuf >> 1))
29362306a36Sopenharmony_ci					x25->condition |= X25_COND_OWN_RX_BUSY;
29462306a36Sopenharmony_ci			}
29562306a36Sopenharmony_ci			/*
29662306a36Sopenharmony_ci			 *	If the window is full Ack it immediately, else
29762306a36Sopenharmony_ci			 *	start the holdback timer.
29862306a36Sopenharmony_ci			 */
29962306a36Sopenharmony_ci			if (((x25->vl + x25->facilities.winsize_in) % modulus) == x25->vr) {
30062306a36Sopenharmony_ci				x25->condition &= ~X25_COND_ACK_PENDING;
30162306a36Sopenharmony_ci				x25_stop_timer(sk);
30262306a36Sopenharmony_ci				x25_enquiry_response(sk);
30362306a36Sopenharmony_ci			} else {
30462306a36Sopenharmony_ci				x25->condition |= X25_COND_ACK_PENDING;
30562306a36Sopenharmony_ci				x25_start_t2timer(sk);
30662306a36Sopenharmony_ci			}
30762306a36Sopenharmony_ci			break;
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci		case X25_INTERRUPT_CONFIRMATION:
31062306a36Sopenharmony_ci			clear_bit(X25_INTERRUPT_FLAG, &x25->flags);
31162306a36Sopenharmony_ci			break;
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci		case X25_INTERRUPT:
31462306a36Sopenharmony_ci			if (sock_flag(sk, SOCK_URGINLINE))
31562306a36Sopenharmony_ci				queued = !sock_queue_rcv_skb(sk, skb);
31662306a36Sopenharmony_ci			else {
31762306a36Sopenharmony_ci				skb_set_owner_r(skb, sk);
31862306a36Sopenharmony_ci				skb_queue_tail(&x25->interrupt_in_queue, skb);
31962306a36Sopenharmony_ci				queued = 1;
32062306a36Sopenharmony_ci			}
32162306a36Sopenharmony_ci			sk_send_sigurg(sk);
32262306a36Sopenharmony_ci			x25_write_internal(sk, X25_INTERRUPT_CONFIRMATION);
32362306a36Sopenharmony_ci			break;
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci		default:
32662306a36Sopenharmony_ci			pr_warn("unknown %02X in state 3\n", frametype);
32762306a36Sopenharmony_ci			break;
32862306a36Sopenharmony_ci	}
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	return queued;
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ciout_clear:
33362306a36Sopenharmony_ci	x25_write_internal(sk, X25_CLEAR_REQUEST);
33462306a36Sopenharmony_ci	x25->state = X25_STATE_2;
33562306a36Sopenharmony_ci	x25_start_t23timer(sk);
33662306a36Sopenharmony_ci	return 0;
33762306a36Sopenharmony_ci}
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci/*
34062306a36Sopenharmony_ci * State machine for state 4, Awaiting Reset Confirmation State.
34162306a36Sopenharmony_ci * The handling of the timer(s) is in file x25_timer.c
34262306a36Sopenharmony_ci * Handling of state 0 and connection release is in af_x25.c.
34362306a36Sopenharmony_ci */
34462306a36Sopenharmony_cistatic int x25_state4_machine(struct sock *sk, struct sk_buff *skb, int frametype)
34562306a36Sopenharmony_ci{
34662306a36Sopenharmony_ci	struct x25_sock *x25 = x25_sk(sk);
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci	switch (frametype) {
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci		case X25_RESET_REQUEST:
35162306a36Sopenharmony_ci			x25_write_internal(sk, X25_RESET_CONFIRMATION);
35262306a36Sopenharmony_ci			fallthrough;
35362306a36Sopenharmony_ci		case X25_RESET_CONFIRMATION: {
35462306a36Sopenharmony_ci			x25_stop_timer(sk);
35562306a36Sopenharmony_ci			x25->condition = 0x00;
35662306a36Sopenharmony_ci			x25->va        = 0;
35762306a36Sopenharmony_ci			x25->vr        = 0;
35862306a36Sopenharmony_ci			x25->vs        = 0;
35962306a36Sopenharmony_ci			x25->vl        = 0;
36062306a36Sopenharmony_ci			x25->state     = X25_STATE_3;
36162306a36Sopenharmony_ci			x25_requeue_frames(sk);
36262306a36Sopenharmony_ci			break;
36362306a36Sopenharmony_ci		}
36462306a36Sopenharmony_ci		case X25_CLEAR_REQUEST:
36562306a36Sopenharmony_ci			if (!pskb_may_pull(skb, X25_STD_MIN_LEN + 2))
36662306a36Sopenharmony_ci				goto out_clear;
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ci			x25_write_internal(sk, X25_CLEAR_CONFIRMATION);
36962306a36Sopenharmony_ci			x25_disconnect(sk, 0, skb->data[3], skb->data[4]);
37062306a36Sopenharmony_ci			break;
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci		default:
37362306a36Sopenharmony_ci			break;
37462306a36Sopenharmony_ci	}
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci	return 0;
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ciout_clear:
37962306a36Sopenharmony_ci	x25_write_internal(sk, X25_CLEAR_REQUEST);
38062306a36Sopenharmony_ci	x25->state = X25_STATE_2;
38162306a36Sopenharmony_ci	x25_start_t23timer(sk);
38262306a36Sopenharmony_ci	return 0;
38362306a36Sopenharmony_ci}
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci/*
38662306a36Sopenharmony_ci * State machine for state 5, Call Accepted / Call Connected pending (X25_ACCPT_APPRV_FLAG).
38762306a36Sopenharmony_ci * The handling of the timer(s) is in file x25_timer.c
38862306a36Sopenharmony_ci * Handling of state 0 and connection release is in af_x25.c.
38962306a36Sopenharmony_ci */
39062306a36Sopenharmony_cistatic int x25_state5_machine(struct sock *sk, struct sk_buff *skb, int frametype)
39162306a36Sopenharmony_ci{
39262306a36Sopenharmony_ci	struct x25_sock *x25 = x25_sk(sk);
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci	switch (frametype) {
39562306a36Sopenharmony_ci		case X25_CLEAR_REQUEST:
39662306a36Sopenharmony_ci			if (!pskb_may_pull(skb, X25_STD_MIN_LEN + 2)) {
39762306a36Sopenharmony_ci				x25_write_internal(sk, X25_CLEAR_REQUEST);
39862306a36Sopenharmony_ci				x25->state = X25_STATE_2;
39962306a36Sopenharmony_ci				x25_start_t23timer(sk);
40062306a36Sopenharmony_ci				return 0;
40162306a36Sopenharmony_ci			}
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci			x25_write_internal(sk, X25_CLEAR_CONFIRMATION);
40462306a36Sopenharmony_ci			x25_disconnect(sk, 0, skb->data[3], skb->data[4]);
40562306a36Sopenharmony_ci			break;
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci		default:
40862306a36Sopenharmony_ci			break;
40962306a36Sopenharmony_ci	}
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci	return 0;
41262306a36Sopenharmony_ci}
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci/* Higher level upcall for a LAPB frame */
41562306a36Sopenharmony_ciint x25_process_rx_frame(struct sock *sk, struct sk_buff *skb)
41662306a36Sopenharmony_ci{
41762306a36Sopenharmony_ci	struct x25_sock *x25 = x25_sk(sk);
41862306a36Sopenharmony_ci	int queued = 0, frametype, ns, nr, q, d, m;
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ci	if (x25->state == X25_STATE_0)
42162306a36Sopenharmony_ci		return 0;
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci	frametype = x25_decode(sk, skb, &ns, &nr, &q, &d, &m);
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ci	switch (x25->state) {
42662306a36Sopenharmony_ci	case X25_STATE_1:
42762306a36Sopenharmony_ci		queued = x25_state1_machine(sk, skb, frametype);
42862306a36Sopenharmony_ci		break;
42962306a36Sopenharmony_ci	case X25_STATE_2:
43062306a36Sopenharmony_ci		queued = x25_state2_machine(sk, skb, frametype);
43162306a36Sopenharmony_ci		break;
43262306a36Sopenharmony_ci	case X25_STATE_3:
43362306a36Sopenharmony_ci		queued = x25_state3_machine(sk, skb, frametype, ns, nr, q, d, m);
43462306a36Sopenharmony_ci		break;
43562306a36Sopenharmony_ci	case X25_STATE_4:
43662306a36Sopenharmony_ci		queued = x25_state4_machine(sk, skb, frametype);
43762306a36Sopenharmony_ci		break;
43862306a36Sopenharmony_ci	case X25_STATE_5:
43962306a36Sopenharmony_ci		queued = x25_state5_machine(sk, skb, frametype);
44062306a36Sopenharmony_ci		break;
44162306a36Sopenharmony_ci	}
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ci	x25_kick(sk);
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci	return queued;
44662306a36Sopenharmony_ci}
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ciint x25_backlog_rcv(struct sock *sk, struct sk_buff *skb)
44962306a36Sopenharmony_ci{
45062306a36Sopenharmony_ci	int queued = x25_process_rx_frame(sk, skb);
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_ci	if (!queued)
45362306a36Sopenharmony_ci		kfree_skb(skb);
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci	return 0;
45662306a36Sopenharmony_ci}
457