162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *	LAPB release 002
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci *	This code REQUIRES 2.1.15 or higher/ NET3.038
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci *	History
862306a36Sopenharmony_ci *	LAPB 001	Jonathan Naulor	Started Coding
962306a36Sopenharmony_ci *	LAPB 002	Jonathan Naylor	New timer architecture.
1062306a36Sopenharmony_ci *	2000-10-29	Henner Eisen	lapb_data_indication() return status.
1162306a36Sopenharmony_ci */
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#include <linux/errno.h>
1662306a36Sopenharmony_ci#include <linux/types.h>
1762306a36Sopenharmony_ci#include <linux/socket.h>
1862306a36Sopenharmony_ci#include <linux/in.h>
1962306a36Sopenharmony_ci#include <linux/kernel.h>
2062306a36Sopenharmony_ci#include <linux/timer.h>
2162306a36Sopenharmony_ci#include <linux/string.h>
2262306a36Sopenharmony_ci#include <linux/sockios.h>
2362306a36Sopenharmony_ci#include <linux/net.h>
2462306a36Sopenharmony_ci#include <linux/inet.h>
2562306a36Sopenharmony_ci#include <linux/netdevice.h>
2662306a36Sopenharmony_ci#include <linux/skbuff.h>
2762306a36Sopenharmony_ci#include <linux/slab.h>
2862306a36Sopenharmony_ci#include <net/sock.h>
2962306a36Sopenharmony_ci#include <linux/uaccess.h>
3062306a36Sopenharmony_ci#include <linux/fcntl.h>
3162306a36Sopenharmony_ci#include <linux/mm.h>
3262306a36Sopenharmony_ci#include <linux/interrupt.h>
3362306a36Sopenharmony_ci#include <net/lapb.h>
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci/*
3662306a36Sopenharmony_ci *	State machine for state 0, Disconnected State.
3762306a36Sopenharmony_ci *	The handling of the timer(s) is in file lapb_timer.c.
3862306a36Sopenharmony_ci */
3962306a36Sopenharmony_cistatic void lapb_state0_machine(struct lapb_cb *lapb, struct sk_buff *skb,
4062306a36Sopenharmony_ci				struct lapb_frame *frame)
4162306a36Sopenharmony_ci{
4262306a36Sopenharmony_ci	switch (frame->type) {
4362306a36Sopenharmony_ci	case LAPB_SABM:
4462306a36Sopenharmony_ci		lapb_dbg(1, "(%p) S0 RX SABM(%d)\n", lapb->dev, frame->pf);
4562306a36Sopenharmony_ci		if (lapb->mode & LAPB_EXTENDED) {
4662306a36Sopenharmony_ci			lapb_dbg(1, "(%p) S0 TX DM(%d)\n",
4762306a36Sopenharmony_ci				 lapb->dev, frame->pf);
4862306a36Sopenharmony_ci			lapb_send_control(lapb, LAPB_DM, frame->pf,
4962306a36Sopenharmony_ci					  LAPB_RESPONSE);
5062306a36Sopenharmony_ci		} else {
5162306a36Sopenharmony_ci			lapb_dbg(1, "(%p) S0 TX UA(%d)\n",
5262306a36Sopenharmony_ci				 lapb->dev, frame->pf);
5362306a36Sopenharmony_ci			lapb_dbg(0, "(%p) S0 -> S3\n", lapb->dev);
5462306a36Sopenharmony_ci			lapb_send_control(lapb, LAPB_UA, frame->pf,
5562306a36Sopenharmony_ci					  LAPB_RESPONSE);
5662306a36Sopenharmony_ci			lapb_stop_t1timer(lapb);
5762306a36Sopenharmony_ci			lapb_stop_t2timer(lapb);
5862306a36Sopenharmony_ci			lapb->state     = LAPB_STATE_3;
5962306a36Sopenharmony_ci			lapb->condition = 0x00;
6062306a36Sopenharmony_ci			lapb->n2count   = 0;
6162306a36Sopenharmony_ci			lapb->vs        = 0;
6262306a36Sopenharmony_ci			lapb->vr        = 0;
6362306a36Sopenharmony_ci			lapb->va        = 0;
6462306a36Sopenharmony_ci			lapb_connect_indication(lapb, LAPB_OK);
6562306a36Sopenharmony_ci		}
6662306a36Sopenharmony_ci		break;
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci	case LAPB_SABME:
6962306a36Sopenharmony_ci		lapb_dbg(1, "(%p) S0 RX SABME(%d)\n", lapb->dev, frame->pf);
7062306a36Sopenharmony_ci		if (lapb->mode & LAPB_EXTENDED) {
7162306a36Sopenharmony_ci			lapb_dbg(1, "(%p) S0 TX UA(%d)\n",
7262306a36Sopenharmony_ci				 lapb->dev, frame->pf);
7362306a36Sopenharmony_ci			lapb_dbg(0, "(%p) S0 -> S3\n", lapb->dev);
7462306a36Sopenharmony_ci			lapb_send_control(lapb, LAPB_UA, frame->pf,
7562306a36Sopenharmony_ci					  LAPB_RESPONSE);
7662306a36Sopenharmony_ci			lapb_stop_t1timer(lapb);
7762306a36Sopenharmony_ci			lapb_stop_t2timer(lapb);
7862306a36Sopenharmony_ci			lapb->state     = LAPB_STATE_3;
7962306a36Sopenharmony_ci			lapb->condition = 0x00;
8062306a36Sopenharmony_ci			lapb->n2count   = 0;
8162306a36Sopenharmony_ci			lapb->vs        = 0;
8262306a36Sopenharmony_ci			lapb->vr        = 0;
8362306a36Sopenharmony_ci			lapb->va        = 0;
8462306a36Sopenharmony_ci			lapb_connect_indication(lapb, LAPB_OK);
8562306a36Sopenharmony_ci		} else {
8662306a36Sopenharmony_ci			lapb_dbg(1, "(%p) S0 TX DM(%d)\n",
8762306a36Sopenharmony_ci				 lapb->dev, frame->pf);
8862306a36Sopenharmony_ci			lapb_send_control(lapb, LAPB_DM, frame->pf,
8962306a36Sopenharmony_ci					  LAPB_RESPONSE);
9062306a36Sopenharmony_ci		}
9162306a36Sopenharmony_ci		break;
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	case LAPB_DISC:
9462306a36Sopenharmony_ci		lapb_dbg(1, "(%p) S0 RX DISC(%d)\n", lapb->dev, frame->pf);
9562306a36Sopenharmony_ci		lapb_dbg(1, "(%p) S0 TX UA(%d)\n", lapb->dev, frame->pf);
9662306a36Sopenharmony_ci		lapb_send_control(lapb, LAPB_UA, frame->pf, LAPB_RESPONSE);
9762306a36Sopenharmony_ci		break;
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci	default:
10062306a36Sopenharmony_ci		break;
10162306a36Sopenharmony_ci	}
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci	kfree_skb(skb);
10462306a36Sopenharmony_ci}
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci/*
10762306a36Sopenharmony_ci *	State machine for state 1, Awaiting Connection State.
10862306a36Sopenharmony_ci *	The handling of the timer(s) is in file lapb_timer.c.
10962306a36Sopenharmony_ci */
11062306a36Sopenharmony_cistatic void lapb_state1_machine(struct lapb_cb *lapb, struct sk_buff *skb,
11162306a36Sopenharmony_ci				struct lapb_frame *frame)
11262306a36Sopenharmony_ci{
11362306a36Sopenharmony_ci	switch (frame->type) {
11462306a36Sopenharmony_ci	case LAPB_SABM:
11562306a36Sopenharmony_ci		lapb_dbg(1, "(%p) S1 RX SABM(%d)\n", lapb->dev, frame->pf);
11662306a36Sopenharmony_ci		if (lapb->mode & LAPB_EXTENDED) {
11762306a36Sopenharmony_ci			lapb_dbg(1, "(%p) S1 TX DM(%d)\n",
11862306a36Sopenharmony_ci				 lapb->dev, frame->pf);
11962306a36Sopenharmony_ci			lapb_send_control(lapb, LAPB_DM, frame->pf,
12062306a36Sopenharmony_ci					  LAPB_RESPONSE);
12162306a36Sopenharmony_ci		} else {
12262306a36Sopenharmony_ci			lapb_dbg(1, "(%p) S1 TX UA(%d)\n",
12362306a36Sopenharmony_ci				 lapb->dev, frame->pf);
12462306a36Sopenharmony_ci			lapb_send_control(lapb, LAPB_UA, frame->pf,
12562306a36Sopenharmony_ci					  LAPB_RESPONSE);
12662306a36Sopenharmony_ci		}
12762306a36Sopenharmony_ci		break;
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci	case LAPB_SABME:
13062306a36Sopenharmony_ci		lapb_dbg(1, "(%p) S1 RX SABME(%d)\n", lapb->dev, frame->pf);
13162306a36Sopenharmony_ci		if (lapb->mode & LAPB_EXTENDED) {
13262306a36Sopenharmony_ci			lapb_dbg(1, "(%p) S1 TX UA(%d)\n",
13362306a36Sopenharmony_ci				 lapb->dev, frame->pf);
13462306a36Sopenharmony_ci			lapb_send_control(lapb, LAPB_UA, frame->pf,
13562306a36Sopenharmony_ci					  LAPB_RESPONSE);
13662306a36Sopenharmony_ci		} else {
13762306a36Sopenharmony_ci			lapb_dbg(1, "(%p) S1 TX DM(%d)\n",
13862306a36Sopenharmony_ci				 lapb->dev, frame->pf);
13962306a36Sopenharmony_ci			lapb_send_control(lapb, LAPB_DM, frame->pf,
14062306a36Sopenharmony_ci					  LAPB_RESPONSE);
14162306a36Sopenharmony_ci		}
14262306a36Sopenharmony_ci		break;
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci	case LAPB_DISC:
14562306a36Sopenharmony_ci		lapb_dbg(1, "(%p) S1 RX DISC(%d)\n", lapb->dev, frame->pf);
14662306a36Sopenharmony_ci		lapb_dbg(1, "(%p) S1 TX DM(%d)\n", lapb->dev, frame->pf);
14762306a36Sopenharmony_ci		lapb_send_control(lapb, LAPB_DM, frame->pf, LAPB_RESPONSE);
14862306a36Sopenharmony_ci		break;
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	case LAPB_UA:
15162306a36Sopenharmony_ci		lapb_dbg(1, "(%p) S1 RX UA(%d)\n", lapb->dev, frame->pf);
15262306a36Sopenharmony_ci		if (frame->pf) {
15362306a36Sopenharmony_ci			lapb_dbg(0, "(%p) S1 -> S3\n", lapb->dev);
15462306a36Sopenharmony_ci			lapb_stop_t1timer(lapb);
15562306a36Sopenharmony_ci			lapb_stop_t2timer(lapb);
15662306a36Sopenharmony_ci			lapb->state     = LAPB_STATE_3;
15762306a36Sopenharmony_ci			lapb->condition = 0x00;
15862306a36Sopenharmony_ci			lapb->n2count   = 0;
15962306a36Sopenharmony_ci			lapb->vs        = 0;
16062306a36Sopenharmony_ci			lapb->vr        = 0;
16162306a36Sopenharmony_ci			lapb->va        = 0;
16262306a36Sopenharmony_ci			lapb_connect_confirmation(lapb, LAPB_OK);
16362306a36Sopenharmony_ci		}
16462306a36Sopenharmony_ci		break;
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	case LAPB_DM:
16762306a36Sopenharmony_ci		lapb_dbg(1, "(%p) S1 RX DM(%d)\n", lapb->dev, frame->pf);
16862306a36Sopenharmony_ci		if (frame->pf) {
16962306a36Sopenharmony_ci			lapb_dbg(0, "(%p) S1 -> S0\n", lapb->dev);
17062306a36Sopenharmony_ci			lapb_clear_queues(lapb);
17162306a36Sopenharmony_ci			lapb->state = LAPB_STATE_0;
17262306a36Sopenharmony_ci			lapb_start_t1timer(lapb);
17362306a36Sopenharmony_ci			lapb_stop_t2timer(lapb);
17462306a36Sopenharmony_ci			lapb_disconnect_indication(lapb, LAPB_REFUSED);
17562306a36Sopenharmony_ci		}
17662306a36Sopenharmony_ci		break;
17762306a36Sopenharmony_ci	}
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	kfree_skb(skb);
18062306a36Sopenharmony_ci}
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci/*
18362306a36Sopenharmony_ci *	State machine for state 2, Awaiting Release State.
18462306a36Sopenharmony_ci *	The handling of the timer(s) is in file lapb_timer.c
18562306a36Sopenharmony_ci */
18662306a36Sopenharmony_cistatic void lapb_state2_machine(struct lapb_cb *lapb, struct sk_buff *skb,
18762306a36Sopenharmony_ci				struct lapb_frame *frame)
18862306a36Sopenharmony_ci{
18962306a36Sopenharmony_ci	switch (frame->type) {
19062306a36Sopenharmony_ci	case LAPB_SABM:
19162306a36Sopenharmony_ci	case LAPB_SABME:
19262306a36Sopenharmony_ci		lapb_dbg(1, "(%p) S2 RX {SABM,SABME}(%d)\n",
19362306a36Sopenharmony_ci			 lapb->dev, frame->pf);
19462306a36Sopenharmony_ci		lapb_dbg(1, "(%p) S2 TX DM(%d)\n", lapb->dev, frame->pf);
19562306a36Sopenharmony_ci		lapb_send_control(lapb, LAPB_DM, frame->pf, LAPB_RESPONSE);
19662306a36Sopenharmony_ci		break;
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci	case LAPB_DISC:
19962306a36Sopenharmony_ci		lapb_dbg(1, "(%p) S2 RX DISC(%d)\n", lapb->dev, frame->pf);
20062306a36Sopenharmony_ci		lapb_dbg(1, "(%p) S2 TX UA(%d)\n", lapb->dev, frame->pf);
20162306a36Sopenharmony_ci		lapb_send_control(lapb, LAPB_UA, frame->pf, LAPB_RESPONSE);
20262306a36Sopenharmony_ci		break;
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	case LAPB_UA:
20562306a36Sopenharmony_ci		lapb_dbg(1, "(%p) S2 RX UA(%d)\n", lapb->dev, frame->pf);
20662306a36Sopenharmony_ci		if (frame->pf) {
20762306a36Sopenharmony_ci			lapb_dbg(0, "(%p) S2 -> S0\n", lapb->dev);
20862306a36Sopenharmony_ci			lapb->state = LAPB_STATE_0;
20962306a36Sopenharmony_ci			lapb_start_t1timer(lapb);
21062306a36Sopenharmony_ci			lapb_stop_t2timer(lapb);
21162306a36Sopenharmony_ci			lapb_disconnect_confirmation(lapb, LAPB_OK);
21262306a36Sopenharmony_ci		}
21362306a36Sopenharmony_ci		break;
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci	case LAPB_DM:
21662306a36Sopenharmony_ci		lapb_dbg(1, "(%p) S2 RX DM(%d)\n", lapb->dev, frame->pf);
21762306a36Sopenharmony_ci		if (frame->pf) {
21862306a36Sopenharmony_ci			lapb_dbg(0, "(%p) S2 -> S0\n", lapb->dev);
21962306a36Sopenharmony_ci			lapb->state = LAPB_STATE_0;
22062306a36Sopenharmony_ci			lapb_start_t1timer(lapb);
22162306a36Sopenharmony_ci			lapb_stop_t2timer(lapb);
22262306a36Sopenharmony_ci			lapb_disconnect_confirmation(lapb, LAPB_NOTCONNECTED);
22362306a36Sopenharmony_ci		}
22462306a36Sopenharmony_ci		break;
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci	case LAPB_I:
22762306a36Sopenharmony_ci	case LAPB_REJ:
22862306a36Sopenharmony_ci	case LAPB_RNR:
22962306a36Sopenharmony_ci	case LAPB_RR:
23062306a36Sopenharmony_ci		lapb_dbg(1, "(%p) S2 RX {I,REJ,RNR,RR}(%d)\n",
23162306a36Sopenharmony_ci		       lapb->dev, frame->pf);
23262306a36Sopenharmony_ci		lapb_dbg(1, "(%p) S2 RX DM(%d)\n", lapb->dev, frame->pf);
23362306a36Sopenharmony_ci		if (frame->pf)
23462306a36Sopenharmony_ci			lapb_send_control(lapb, LAPB_DM, frame->pf,
23562306a36Sopenharmony_ci					  LAPB_RESPONSE);
23662306a36Sopenharmony_ci		break;
23762306a36Sopenharmony_ci	}
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci	kfree_skb(skb);
24062306a36Sopenharmony_ci}
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci/*
24362306a36Sopenharmony_ci *	State machine for state 3, Connected State.
24462306a36Sopenharmony_ci *	The handling of the timer(s) is in file lapb_timer.c
24562306a36Sopenharmony_ci */
24662306a36Sopenharmony_cistatic void lapb_state3_machine(struct lapb_cb *lapb, struct sk_buff *skb,
24762306a36Sopenharmony_ci				struct lapb_frame *frame)
24862306a36Sopenharmony_ci{
24962306a36Sopenharmony_ci	int queued = 0;
25062306a36Sopenharmony_ci	int modulus = (lapb->mode & LAPB_EXTENDED) ? LAPB_EMODULUS :
25162306a36Sopenharmony_ci						     LAPB_SMODULUS;
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	switch (frame->type) {
25462306a36Sopenharmony_ci	case LAPB_SABM:
25562306a36Sopenharmony_ci		lapb_dbg(1, "(%p) S3 RX SABM(%d)\n", lapb->dev, frame->pf);
25662306a36Sopenharmony_ci		if (lapb->mode & LAPB_EXTENDED) {
25762306a36Sopenharmony_ci			lapb_dbg(1, "(%p) S3 TX DM(%d)\n",
25862306a36Sopenharmony_ci				 lapb->dev, frame->pf);
25962306a36Sopenharmony_ci			lapb_send_control(lapb, LAPB_DM, frame->pf,
26062306a36Sopenharmony_ci					  LAPB_RESPONSE);
26162306a36Sopenharmony_ci		} else {
26262306a36Sopenharmony_ci			lapb_dbg(1, "(%p) S3 TX UA(%d)\n",
26362306a36Sopenharmony_ci				 lapb->dev, frame->pf);
26462306a36Sopenharmony_ci			lapb_send_control(lapb, LAPB_UA, frame->pf,
26562306a36Sopenharmony_ci					  LAPB_RESPONSE);
26662306a36Sopenharmony_ci			lapb_stop_t1timer(lapb);
26762306a36Sopenharmony_ci			lapb_stop_t2timer(lapb);
26862306a36Sopenharmony_ci			lapb->condition = 0x00;
26962306a36Sopenharmony_ci			lapb->n2count   = 0;
27062306a36Sopenharmony_ci			lapb->vs        = 0;
27162306a36Sopenharmony_ci			lapb->vr        = 0;
27262306a36Sopenharmony_ci			lapb->va        = 0;
27362306a36Sopenharmony_ci			lapb_requeue_frames(lapb);
27462306a36Sopenharmony_ci		}
27562306a36Sopenharmony_ci		break;
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci	case LAPB_SABME:
27862306a36Sopenharmony_ci		lapb_dbg(1, "(%p) S3 RX SABME(%d)\n", lapb->dev, frame->pf);
27962306a36Sopenharmony_ci		if (lapb->mode & LAPB_EXTENDED) {
28062306a36Sopenharmony_ci			lapb_dbg(1, "(%p) S3 TX UA(%d)\n",
28162306a36Sopenharmony_ci				 lapb->dev, frame->pf);
28262306a36Sopenharmony_ci			lapb_send_control(lapb, LAPB_UA, frame->pf,
28362306a36Sopenharmony_ci					  LAPB_RESPONSE);
28462306a36Sopenharmony_ci			lapb_stop_t1timer(lapb);
28562306a36Sopenharmony_ci			lapb_stop_t2timer(lapb);
28662306a36Sopenharmony_ci			lapb->condition = 0x00;
28762306a36Sopenharmony_ci			lapb->n2count   = 0;
28862306a36Sopenharmony_ci			lapb->vs        = 0;
28962306a36Sopenharmony_ci			lapb->vr        = 0;
29062306a36Sopenharmony_ci			lapb->va        = 0;
29162306a36Sopenharmony_ci			lapb_requeue_frames(lapb);
29262306a36Sopenharmony_ci		} else {
29362306a36Sopenharmony_ci			lapb_dbg(1, "(%p) S3 TX DM(%d)\n",
29462306a36Sopenharmony_ci				 lapb->dev, frame->pf);
29562306a36Sopenharmony_ci			lapb_send_control(lapb, LAPB_DM, frame->pf,
29662306a36Sopenharmony_ci					  LAPB_RESPONSE);
29762306a36Sopenharmony_ci		}
29862306a36Sopenharmony_ci		break;
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci	case LAPB_DISC:
30162306a36Sopenharmony_ci		lapb_dbg(1, "(%p) S3 RX DISC(%d)\n", lapb->dev, frame->pf);
30262306a36Sopenharmony_ci		lapb_dbg(0, "(%p) S3 -> S0\n", lapb->dev);
30362306a36Sopenharmony_ci		lapb_clear_queues(lapb);
30462306a36Sopenharmony_ci		lapb_send_control(lapb, LAPB_UA, frame->pf, LAPB_RESPONSE);
30562306a36Sopenharmony_ci		lapb_start_t1timer(lapb);
30662306a36Sopenharmony_ci		lapb_stop_t2timer(lapb);
30762306a36Sopenharmony_ci		lapb->state = LAPB_STATE_0;
30862306a36Sopenharmony_ci		lapb_disconnect_indication(lapb, LAPB_OK);
30962306a36Sopenharmony_ci		break;
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci	case LAPB_DM:
31262306a36Sopenharmony_ci		lapb_dbg(1, "(%p) S3 RX DM(%d)\n", lapb->dev, frame->pf);
31362306a36Sopenharmony_ci		lapb_dbg(0, "(%p) S3 -> S0\n", lapb->dev);
31462306a36Sopenharmony_ci		lapb_clear_queues(lapb);
31562306a36Sopenharmony_ci		lapb->state = LAPB_STATE_0;
31662306a36Sopenharmony_ci		lapb_start_t1timer(lapb);
31762306a36Sopenharmony_ci		lapb_stop_t2timer(lapb);
31862306a36Sopenharmony_ci		lapb_disconnect_indication(lapb, LAPB_NOTCONNECTED);
31962306a36Sopenharmony_ci		break;
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci	case LAPB_RNR:
32262306a36Sopenharmony_ci		lapb_dbg(1, "(%p) S3 RX RNR(%d) R%d\n",
32362306a36Sopenharmony_ci			 lapb->dev, frame->pf, frame->nr);
32462306a36Sopenharmony_ci		lapb->condition |= LAPB_PEER_RX_BUSY_CONDITION;
32562306a36Sopenharmony_ci		lapb_check_need_response(lapb, frame->cr, frame->pf);
32662306a36Sopenharmony_ci		if (lapb_validate_nr(lapb, frame->nr)) {
32762306a36Sopenharmony_ci			lapb_check_iframes_acked(lapb, frame->nr);
32862306a36Sopenharmony_ci		} else {
32962306a36Sopenharmony_ci			lapb->frmr_data = *frame;
33062306a36Sopenharmony_ci			lapb->frmr_type = LAPB_FRMR_Z;
33162306a36Sopenharmony_ci			lapb_transmit_frmr(lapb);
33262306a36Sopenharmony_ci			lapb_dbg(0, "(%p) S3 -> S4\n", lapb->dev);
33362306a36Sopenharmony_ci			lapb_start_t1timer(lapb);
33462306a36Sopenharmony_ci			lapb_stop_t2timer(lapb);
33562306a36Sopenharmony_ci			lapb->state   = LAPB_STATE_4;
33662306a36Sopenharmony_ci			lapb->n2count = 0;
33762306a36Sopenharmony_ci		}
33862306a36Sopenharmony_ci		break;
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci	case LAPB_RR:
34162306a36Sopenharmony_ci		lapb_dbg(1, "(%p) S3 RX RR(%d) R%d\n",
34262306a36Sopenharmony_ci			 lapb->dev, frame->pf, frame->nr);
34362306a36Sopenharmony_ci		lapb->condition &= ~LAPB_PEER_RX_BUSY_CONDITION;
34462306a36Sopenharmony_ci		lapb_check_need_response(lapb, frame->cr, frame->pf);
34562306a36Sopenharmony_ci		if (lapb_validate_nr(lapb, frame->nr)) {
34662306a36Sopenharmony_ci			lapb_check_iframes_acked(lapb, frame->nr);
34762306a36Sopenharmony_ci		} else {
34862306a36Sopenharmony_ci			lapb->frmr_data = *frame;
34962306a36Sopenharmony_ci			lapb->frmr_type = LAPB_FRMR_Z;
35062306a36Sopenharmony_ci			lapb_transmit_frmr(lapb);
35162306a36Sopenharmony_ci			lapb_dbg(0, "(%p) S3 -> S4\n", lapb->dev);
35262306a36Sopenharmony_ci			lapb_start_t1timer(lapb);
35362306a36Sopenharmony_ci			lapb_stop_t2timer(lapb);
35462306a36Sopenharmony_ci			lapb->state   = LAPB_STATE_4;
35562306a36Sopenharmony_ci			lapb->n2count = 0;
35662306a36Sopenharmony_ci		}
35762306a36Sopenharmony_ci		break;
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	case LAPB_REJ:
36062306a36Sopenharmony_ci		lapb_dbg(1, "(%p) S3 RX REJ(%d) R%d\n",
36162306a36Sopenharmony_ci			 lapb->dev, frame->pf, frame->nr);
36262306a36Sopenharmony_ci		lapb->condition &= ~LAPB_PEER_RX_BUSY_CONDITION;
36362306a36Sopenharmony_ci		lapb_check_need_response(lapb, frame->cr, frame->pf);
36462306a36Sopenharmony_ci		if (lapb_validate_nr(lapb, frame->nr)) {
36562306a36Sopenharmony_ci			lapb_frames_acked(lapb, frame->nr);
36662306a36Sopenharmony_ci			lapb_stop_t1timer(lapb);
36762306a36Sopenharmony_ci			lapb->n2count = 0;
36862306a36Sopenharmony_ci			lapb_requeue_frames(lapb);
36962306a36Sopenharmony_ci		} else {
37062306a36Sopenharmony_ci			lapb->frmr_data = *frame;
37162306a36Sopenharmony_ci			lapb->frmr_type = LAPB_FRMR_Z;
37262306a36Sopenharmony_ci			lapb_transmit_frmr(lapb);
37362306a36Sopenharmony_ci			lapb_dbg(0, "(%p) S3 -> S4\n", lapb->dev);
37462306a36Sopenharmony_ci			lapb_start_t1timer(lapb);
37562306a36Sopenharmony_ci			lapb_stop_t2timer(lapb);
37662306a36Sopenharmony_ci			lapb->state   = LAPB_STATE_4;
37762306a36Sopenharmony_ci			lapb->n2count = 0;
37862306a36Sopenharmony_ci		}
37962306a36Sopenharmony_ci		break;
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci	case LAPB_I:
38262306a36Sopenharmony_ci		lapb_dbg(1, "(%p) S3 RX I(%d) S%d R%d\n",
38362306a36Sopenharmony_ci			 lapb->dev, frame->pf, frame->ns, frame->nr);
38462306a36Sopenharmony_ci		if (!lapb_validate_nr(lapb, frame->nr)) {
38562306a36Sopenharmony_ci			lapb->frmr_data = *frame;
38662306a36Sopenharmony_ci			lapb->frmr_type = LAPB_FRMR_Z;
38762306a36Sopenharmony_ci			lapb_transmit_frmr(lapb);
38862306a36Sopenharmony_ci			lapb_dbg(0, "(%p) S3 -> S4\n", lapb->dev);
38962306a36Sopenharmony_ci			lapb_start_t1timer(lapb);
39062306a36Sopenharmony_ci			lapb_stop_t2timer(lapb);
39162306a36Sopenharmony_ci			lapb->state   = LAPB_STATE_4;
39262306a36Sopenharmony_ci			lapb->n2count = 0;
39362306a36Sopenharmony_ci			break;
39462306a36Sopenharmony_ci		}
39562306a36Sopenharmony_ci		if (lapb->condition & LAPB_PEER_RX_BUSY_CONDITION)
39662306a36Sopenharmony_ci			lapb_frames_acked(lapb, frame->nr);
39762306a36Sopenharmony_ci		else
39862306a36Sopenharmony_ci			lapb_check_iframes_acked(lapb, frame->nr);
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci		if (frame->ns == lapb->vr) {
40162306a36Sopenharmony_ci			int cn;
40262306a36Sopenharmony_ci			cn = lapb_data_indication(lapb, skb);
40362306a36Sopenharmony_ci			queued = 1;
40462306a36Sopenharmony_ci			/*
40562306a36Sopenharmony_ci			 * If upper layer has dropped the frame, we
40662306a36Sopenharmony_ci			 * basically ignore any further protocol
40762306a36Sopenharmony_ci			 * processing. This will cause the peer
40862306a36Sopenharmony_ci			 * to re-transmit the frame later like
40962306a36Sopenharmony_ci			 * a frame lost on the wire.
41062306a36Sopenharmony_ci			 */
41162306a36Sopenharmony_ci			if (cn == NET_RX_DROP) {
41262306a36Sopenharmony_ci				pr_debug("rx congestion\n");
41362306a36Sopenharmony_ci				break;
41462306a36Sopenharmony_ci			}
41562306a36Sopenharmony_ci			lapb->vr = (lapb->vr + 1) % modulus;
41662306a36Sopenharmony_ci			lapb->condition &= ~LAPB_REJECT_CONDITION;
41762306a36Sopenharmony_ci			if (frame->pf)
41862306a36Sopenharmony_ci				lapb_enquiry_response(lapb);
41962306a36Sopenharmony_ci			else {
42062306a36Sopenharmony_ci				if (!(lapb->condition &
42162306a36Sopenharmony_ci				      LAPB_ACK_PENDING_CONDITION)) {
42262306a36Sopenharmony_ci					lapb->condition |= LAPB_ACK_PENDING_CONDITION;
42362306a36Sopenharmony_ci					lapb_start_t2timer(lapb);
42462306a36Sopenharmony_ci				}
42562306a36Sopenharmony_ci			}
42662306a36Sopenharmony_ci		} else {
42762306a36Sopenharmony_ci			if (lapb->condition & LAPB_REJECT_CONDITION) {
42862306a36Sopenharmony_ci				if (frame->pf)
42962306a36Sopenharmony_ci					lapb_enquiry_response(lapb);
43062306a36Sopenharmony_ci			} else {
43162306a36Sopenharmony_ci				lapb_dbg(1, "(%p) S3 TX REJ(%d) R%d\n",
43262306a36Sopenharmony_ci					 lapb->dev, frame->pf, lapb->vr);
43362306a36Sopenharmony_ci				lapb->condition |= LAPB_REJECT_CONDITION;
43462306a36Sopenharmony_ci				lapb_send_control(lapb, LAPB_REJ, frame->pf,
43562306a36Sopenharmony_ci						  LAPB_RESPONSE);
43662306a36Sopenharmony_ci				lapb->condition &= ~LAPB_ACK_PENDING_CONDITION;
43762306a36Sopenharmony_ci			}
43862306a36Sopenharmony_ci		}
43962306a36Sopenharmony_ci		break;
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci	case LAPB_FRMR:
44262306a36Sopenharmony_ci		lapb_dbg(1, "(%p) S3 RX FRMR(%d) %5ph\n",
44362306a36Sopenharmony_ci			 lapb->dev, frame->pf,
44462306a36Sopenharmony_ci			 skb->data);
44562306a36Sopenharmony_ci		lapb_establish_data_link(lapb);
44662306a36Sopenharmony_ci		lapb_dbg(0, "(%p) S3 -> S1\n", lapb->dev);
44762306a36Sopenharmony_ci		lapb_requeue_frames(lapb);
44862306a36Sopenharmony_ci		lapb->state = LAPB_STATE_1;
44962306a36Sopenharmony_ci		break;
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_ci	case LAPB_ILLEGAL:
45262306a36Sopenharmony_ci		lapb_dbg(1, "(%p) S3 RX ILLEGAL(%d)\n", lapb->dev, frame->pf);
45362306a36Sopenharmony_ci		lapb->frmr_data = *frame;
45462306a36Sopenharmony_ci		lapb->frmr_type = LAPB_FRMR_W;
45562306a36Sopenharmony_ci		lapb_transmit_frmr(lapb);
45662306a36Sopenharmony_ci		lapb_dbg(0, "(%p) S3 -> S4\n", lapb->dev);
45762306a36Sopenharmony_ci		lapb_start_t1timer(lapb);
45862306a36Sopenharmony_ci		lapb_stop_t2timer(lapb);
45962306a36Sopenharmony_ci		lapb->state   = LAPB_STATE_4;
46062306a36Sopenharmony_ci		lapb->n2count = 0;
46162306a36Sopenharmony_ci		break;
46262306a36Sopenharmony_ci	}
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci	if (!queued)
46562306a36Sopenharmony_ci		kfree_skb(skb);
46662306a36Sopenharmony_ci}
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_ci/*
46962306a36Sopenharmony_ci *	State machine for state 4, Frame Reject State.
47062306a36Sopenharmony_ci *	The handling of the timer(s) is in file lapb_timer.c.
47162306a36Sopenharmony_ci */
47262306a36Sopenharmony_cistatic void lapb_state4_machine(struct lapb_cb *lapb, struct sk_buff *skb,
47362306a36Sopenharmony_ci				struct lapb_frame *frame)
47462306a36Sopenharmony_ci{
47562306a36Sopenharmony_ci	switch (frame->type) {
47662306a36Sopenharmony_ci	case LAPB_SABM:
47762306a36Sopenharmony_ci		lapb_dbg(1, "(%p) S4 RX SABM(%d)\n", lapb->dev, frame->pf);
47862306a36Sopenharmony_ci		if (lapb->mode & LAPB_EXTENDED) {
47962306a36Sopenharmony_ci			lapb_dbg(1, "(%p) S4 TX DM(%d)\n",
48062306a36Sopenharmony_ci				 lapb->dev, frame->pf);
48162306a36Sopenharmony_ci			lapb_send_control(lapb, LAPB_DM, frame->pf,
48262306a36Sopenharmony_ci					  LAPB_RESPONSE);
48362306a36Sopenharmony_ci		} else {
48462306a36Sopenharmony_ci			lapb_dbg(1, "(%p) S4 TX UA(%d)\n",
48562306a36Sopenharmony_ci				 lapb->dev, frame->pf);
48662306a36Sopenharmony_ci			lapb_dbg(0, "(%p) S4 -> S3\n", lapb->dev);
48762306a36Sopenharmony_ci			lapb_send_control(lapb, LAPB_UA, frame->pf,
48862306a36Sopenharmony_ci					  LAPB_RESPONSE);
48962306a36Sopenharmony_ci			lapb_stop_t1timer(lapb);
49062306a36Sopenharmony_ci			lapb_stop_t2timer(lapb);
49162306a36Sopenharmony_ci			lapb->state     = LAPB_STATE_3;
49262306a36Sopenharmony_ci			lapb->condition = 0x00;
49362306a36Sopenharmony_ci			lapb->n2count   = 0;
49462306a36Sopenharmony_ci			lapb->vs        = 0;
49562306a36Sopenharmony_ci			lapb->vr        = 0;
49662306a36Sopenharmony_ci			lapb->va        = 0;
49762306a36Sopenharmony_ci			lapb_connect_indication(lapb, LAPB_OK);
49862306a36Sopenharmony_ci		}
49962306a36Sopenharmony_ci		break;
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_ci	case LAPB_SABME:
50262306a36Sopenharmony_ci		lapb_dbg(1, "(%p) S4 RX SABME(%d)\n", lapb->dev, frame->pf);
50362306a36Sopenharmony_ci		if (lapb->mode & LAPB_EXTENDED) {
50462306a36Sopenharmony_ci			lapb_dbg(1, "(%p) S4 TX UA(%d)\n",
50562306a36Sopenharmony_ci				 lapb->dev, frame->pf);
50662306a36Sopenharmony_ci			lapb_dbg(0, "(%p) S4 -> S3\n", lapb->dev);
50762306a36Sopenharmony_ci			lapb_send_control(lapb, LAPB_UA, frame->pf,
50862306a36Sopenharmony_ci					  LAPB_RESPONSE);
50962306a36Sopenharmony_ci			lapb_stop_t1timer(lapb);
51062306a36Sopenharmony_ci			lapb_stop_t2timer(lapb);
51162306a36Sopenharmony_ci			lapb->state     = LAPB_STATE_3;
51262306a36Sopenharmony_ci			lapb->condition = 0x00;
51362306a36Sopenharmony_ci			lapb->n2count   = 0;
51462306a36Sopenharmony_ci			lapb->vs        = 0;
51562306a36Sopenharmony_ci			lapb->vr        = 0;
51662306a36Sopenharmony_ci			lapb->va        = 0;
51762306a36Sopenharmony_ci			lapb_connect_indication(lapb, LAPB_OK);
51862306a36Sopenharmony_ci		} else {
51962306a36Sopenharmony_ci			lapb_dbg(1, "(%p) S4 TX DM(%d)\n",
52062306a36Sopenharmony_ci				 lapb->dev, frame->pf);
52162306a36Sopenharmony_ci			lapb_send_control(lapb, LAPB_DM, frame->pf,
52262306a36Sopenharmony_ci					  LAPB_RESPONSE);
52362306a36Sopenharmony_ci		}
52462306a36Sopenharmony_ci		break;
52562306a36Sopenharmony_ci	}
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ci	kfree_skb(skb);
52862306a36Sopenharmony_ci}
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci/*
53162306a36Sopenharmony_ci *	Process an incoming LAPB frame
53262306a36Sopenharmony_ci */
53362306a36Sopenharmony_civoid lapb_data_input(struct lapb_cb *lapb, struct sk_buff *skb)
53462306a36Sopenharmony_ci{
53562306a36Sopenharmony_ci	struct lapb_frame frame;
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci	if (lapb_decode(lapb, skb, &frame) < 0) {
53862306a36Sopenharmony_ci		kfree_skb(skb);
53962306a36Sopenharmony_ci		return;
54062306a36Sopenharmony_ci	}
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_ci	switch (lapb->state) {
54362306a36Sopenharmony_ci	case LAPB_STATE_0:
54462306a36Sopenharmony_ci		lapb_state0_machine(lapb, skb, &frame); break;
54562306a36Sopenharmony_ci	case LAPB_STATE_1:
54662306a36Sopenharmony_ci		lapb_state1_machine(lapb, skb, &frame); break;
54762306a36Sopenharmony_ci	case LAPB_STATE_2:
54862306a36Sopenharmony_ci		lapb_state2_machine(lapb, skb, &frame); break;
54962306a36Sopenharmony_ci	case LAPB_STATE_3:
55062306a36Sopenharmony_ci		lapb_state3_machine(lapb, skb, &frame); break;
55162306a36Sopenharmony_ci	case LAPB_STATE_4:
55262306a36Sopenharmony_ci		lapb_state4_machine(lapb, skb, &frame); break;
55362306a36Sopenharmony_ci	}
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci	lapb_kick(lapb);
55662306a36Sopenharmony_ci}
557