18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *	LAPB release 002
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci *	This code REQUIRES 2.1.15 or higher/ NET3.038
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci *	History
88c2ecf20Sopenharmony_ci *	LAPB 001	Jonathan Naylor	Started Coding
98c2ecf20Sopenharmony_ci *	LAPB 002	Jonathan Naylor	New timer architecture.
108c2ecf20Sopenharmony_ci */
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#include <linux/errno.h>
158c2ecf20Sopenharmony_ci#include <linux/types.h>
168c2ecf20Sopenharmony_ci#include <linux/socket.h>
178c2ecf20Sopenharmony_ci#include <linux/in.h>
188c2ecf20Sopenharmony_ci#include <linux/kernel.h>
198c2ecf20Sopenharmony_ci#include <linux/jiffies.h>
208c2ecf20Sopenharmony_ci#include <linux/timer.h>
218c2ecf20Sopenharmony_ci#include <linux/string.h>
228c2ecf20Sopenharmony_ci#include <linux/sockios.h>
238c2ecf20Sopenharmony_ci#include <linux/net.h>
248c2ecf20Sopenharmony_ci#include <linux/inet.h>
258c2ecf20Sopenharmony_ci#include <linux/skbuff.h>
268c2ecf20Sopenharmony_ci#include <net/sock.h>
278c2ecf20Sopenharmony_ci#include <linux/uaccess.h>
288c2ecf20Sopenharmony_ci#include <linux/fcntl.h>
298c2ecf20Sopenharmony_ci#include <linux/mm.h>
308c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
318c2ecf20Sopenharmony_ci#include <net/lapb.h>
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_cistatic void lapb_t1timer_expiry(struct timer_list *);
348c2ecf20Sopenharmony_cistatic void lapb_t2timer_expiry(struct timer_list *);
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_civoid lapb_start_t1timer(struct lapb_cb *lapb)
378c2ecf20Sopenharmony_ci{
388c2ecf20Sopenharmony_ci	del_timer(&lapb->t1timer);
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci	lapb->t1timer.function = lapb_t1timer_expiry;
418c2ecf20Sopenharmony_ci	lapb->t1timer.expires  = jiffies + lapb->t1;
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci	add_timer(&lapb->t1timer);
448c2ecf20Sopenharmony_ci}
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_civoid lapb_start_t2timer(struct lapb_cb *lapb)
478c2ecf20Sopenharmony_ci{
488c2ecf20Sopenharmony_ci	del_timer(&lapb->t2timer);
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci	lapb->t2timer.function = lapb_t2timer_expiry;
518c2ecf20Sopenharmony_ci	lapb->t2timer.expires  = jiffies + lapb->t2;
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci	add_timer(&lapb->t2timer);
548c2ecf20Sopenharmony_ci}
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_civoid lapb_stop_t1timer(struct lapb_cb *lapb)
578c2ecf20Sopenharmony_ci{
588c2ecf20Sopenharmony_ci	del_timer(&lapb->t1timer);
598c2ecf20Sopenharmony_ci}
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_civoid lapb_stop_t2timer(struct lapb_cb *lapb)
628c2ecf20Sopenharmony_ci{
638c2ecf20Sopenharmony_ci	del_timer(&lapb->t2timer);
648c2ecf20Sopenharmony_ci}
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ciint lapb_t1timer_running(struct lapb_cb *lapb)
678c2ecf20Sopenharmony_ci{
688c2ecf20Sopenharmony_ci	return timer_pending(&lapb->t1timer);
698c2ecf20Sopenharmony_ci}
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_cistatic void lapb_t2timer_expiry(struct timer_list *t)
728c2ecf20Sopenharmony_ci{
738c2ecf20Sopenharmony_ci	struct lapb_cb *lapb = from_timer(lapb, t, t2timer);
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci	if (lapb->condition & LAPB_ACK_PENDING_CONDITION) {
768c2ecf20Sopenharmony_ci		lapb->condition &= ~LAPB_ACK_PENDING_CONDITION;
778c2ecf20Sopenharmony_ci		lapb_timeout_response(lapb);
788c2ecf20Sopenharmony_ci	}
798c2ecf20Sopenharmony_ci}
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_cistatic void lapb_t1timer_expiry(struct timer_list *t)
828c2ecf20Sopenharmony_ci{
838c2ecf20Sopenharmony_ci	struct lapb_cb *lapb = from_timer(lapb, t, t1timer);
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci	switch (lapb->state) {
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci		/*
888c2ecf20Sopenharmony_ci		 *	If we are a DCE, keep going DM .. DM .. DM
898c2ecf20Sopenharmony_ci		 */
908c2ecf20Sopenharmony_ci		case LAPB_STATE_0:
918c2ecf20Sopenharmony_ci			if (lapb->mode & LAPB_DCE)
928c2ecf20Sopenharmony_ci				lapb_send_control(lapb, LAPB_DM, LAPB_POLLOFF, LAPB_RESPONSE);
938c2ecf20Sopenharmony_ci			break;
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci		/*
968c2ecf20Sopenharmony_ci		 *	Awaiting connection state, send SABM(E), up to N2 times.
978c2ecf20Sopenharmony_ci		 */
988c2ecf20Sopenharmony_ci		case LAPB_STATE_1:
998c2ecf20Sopenharmony_ci			if (lapb->n2count == lapb->n2) {
1008c2ecf20Sopenharmony_ci				lapb_clear_queues(lapb);
1018c2ecf20Sopenharmony_ci				lapb->state = LAPB_STATE_0;
1028c2ecf20Sopenharmony_ci				lapb_disconnect_indication(lapb, LAPB_TIMEDOUT);
1038c2ecf20Sopenharmony_ci				lapb_dbg(0, "(%p) S1 -> S0\n", lapb->dev);
1048c2ecf20Sopenharmony_ci				return;
1058c2ecf20Sopenharmony_ci			} else {
1068c2ecf20Sopenharmony_ci				lapb->n2count++;
1078c2ecf20Sopenharmony_ci				if (lapb->mode & LAPB_EXTENDED) {
1088c2ecf20Sopenharmony_ci					lapb_dbg(1, "(%p) S1 TX SABME(1)\n",
1098c2ecf20Sopenharmony_ci						 lapb->dev);
1108c2ecf20Sopenharmony_ci					lapb_send_control(lapb, LAPB_SABME, LAPB_POLLON, LAPB_COMMAND);
1118c2ecf20Sopenharmony_ci				} else {
1128c2ecf20Sopenharmony_ci					lapb_dbg(1, "(%p) S1 TX SABM(1)\n",
1138c2ecf20Sopenharmony_ci						 lapb->dev);
1148c2ecf20Sopenharmony_ci					lapb_send_control(lapb, LAPB_SABM, LAPB_POLLON, LAPB_COMMAND);
1158c2ecf20Sopenharmony_ci				}
1168c2ecf20Sopenharmony_ci			}
1178c2ecf20Sopenharmony_ci			break;
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci		/*
1208c2ecf20Sopenharmony_ci		 *	Awaiting disconnection state, send DISC, up to N2 times.
1218c2ecf20Sopenharmony_ci		 */
1228c2ecf20Sopenharmony_ci		case LAPB_STATE_2:
1238c2ecf20Sopenharmony_ci			if (lapb->n2count == lapb->n2) {
1248c2ecf20Sopenharmony_ci				lapb_clear_queues(lapb);
1258c2ecf20Sopenharmony_ci				lapb->state = LAPB_STATE_0;
1268c2ecf20Sopenharmony_ci				lapb_disconnect_confirmation(lapb, LAPB_TIMEDOUT);
1278c2ecf20Sopenharmony_ci				lapb_dbg(0, "(%p) S2 -> S0\n", lapb->dev);
1288c2ecf20Sopenharmony_ci				return;
1298c2ecf20Sopenharmony_ci			} else {
1308c2ecf20Sopenharmony_ci				lapb->n2count++;
1318c2ecf20Sopenharmony_ci				lapb_dbg(1, "(%p) S2 TX DISC(1)\n", lapb->dev);
1328c2ecf20Sopenharmony_ci				lapb_send_control(lapb, LAPB_DISC, LAPB_POLLON, LAPB_COMMAND);
1338c2ecf20Sopenharmony_ci			}
1348c2ecf20Sopenharmony_ci			break;
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci		/*
1378c2ecf20Sopenharmony_ci		 *	Data transfer state, restransmit I frames, up to N2 times.
1388c2ecf20Sopenharmony_ci		 */
1398c2ecf20Sopenharmony_ci		case LAPB_STATE_3:
1408c2ecf20Sopenharmony_ci			if (lapb->n2count == lapb->n2) {
1418c2ecf20Sopenharmony_ci				lapb_clear_queues(lapb);
1428c2ecf20Sopenharmony_ci				lapb->state = LAPB_STATE_0;
1438c2ecf20Sopenharmony_ci				lapb_stop_t2timer(lapb);
1448c2ecf20Sopenharmony_ci				lapb_disconnect_indication(lapb, LAPB_TIMEDOUT);
1458c2ecf20Sopenharmony_ci				lapb_dbg(0, "(%p) S3 -> S0\n", lapb->dev);
1468c2ecf20Sopenharmony_ci				return;
1478c2ecf20Sopenharmony_ci			} else {
1488c2ecf20Sopenharmony_ci				lapb->n2count++;
1498c2ecf20Sopenharmony_ci				lapb_requeue_frames(lapb);
1508c2ecf20Sopenharmony_ci				lapb_kick(lapb);
1518c2ecf20Sopenharmony_ci			}
1528c2ecf20Sopenharmony_ci			break;
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci		/*
1558c2ecf20Sopenharmony_ci		 *	Frame reject state, restransmit FRMR frames, up to N2 times.
1568c2ecf20Sopenharmony_ci		 */
1578c2ecf20Sopenharmony_ci		case LAPB_STATE_4:
1588c2ecf20Sopenharmony_ci			if (lapb->n2count == lapb->n2) {
1598c2ecf20Sopenharmony_ci				lapb_clear_queues(lapb);
1608c2ecf20Sopenharmony_ci				lapb->state = LAPB_STATE_0;
1618c2ecf20Sopenharmony_ci				lapb_disconnect_indication(lapb, LAPB_TIMEDOUT);
1628c2ecf20Sopenharmony_ci				lapb_dbg(0, "(%p) S4 -> S0\n", lapb->dev);
1638c2ecf20Sopenharmony_ci				return;
1648c2ecf20Sopenharmony_ci			} else {
1658c2ecf20Sopenharmony_ci				lapb->n2count++;
1668c2ecf20Sopenharmony_ci				lapb_transmit_frmr(lapb);
1678c2ecf20Sopenharmony_ci			}
1688c2ecf20Sopenharmony_ci			break;
1698c2ecf20Sopenharmony_ci	}
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci	lapb_start_t1timer(lapb);
1728c2ecf20Sopenharmony_ci}
173