xref: /openbmc/linux/net/lapb/lapb_timer.c (revision 65d2dbb3)
1ee5d8f4dSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  *	LAPB release 002
41da177e4SLinus Torvalds  *
51da177e4SLinus Torvalds  *	This code REQUIRES 2.1.15 or higher/ NET3.038
61da177e4SLinus Torvalds  *
71da177e4SLinus Torvalds  *	History
81da177e4SLinus Torvalds  *	LAPB 001	Jonathan Naylor	Started Coding
91da177e4SLinus Torvalds  *	LAPB 002	Jonathan Naylor	New timer architecture.
101da177e4SLinus Torvalds  */
111da177e4SLinus Torvalds 
12a508da6cSJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
13a508da6cSJoe Perches 
141da177e4SLinus Torvalds #include <linux/errno.h>
151da177e4SLinus Torvalds #include <linux/types.h>
161da177e4SLinus Torvalds #include <linux/socket.h>
171da177e4SLinus Torvalds #include <linux/in.h>
181da177e4SLinus Torvalds #include <linux/kernel.h>
191da177e4SLinus Torvalds #include <linux/jiffies.h>
201da177e4SLinus Torvalds #include <linux/timer.h>
211da177e4SLinus Torvalds #include <linux/string.h>
221da177e4SLinus Torvalds #include <linux/sockios.h>
231da177e4SLinus Torvalds #include <linux/net.h>
241da177e4SLinus Torvalds #include <linux/inet.h>
251da177e4SLinus Torvalds #include <linux/skbuff.h>
261da177e4SLinus Torvalds #include <net/sock.h>
277c0f6ba6SLinus Torvalds #include <linux/uaccess.h>
281da177e4SLinus Torvalds #include <linux/fcntl.h>
291da177e4SLinus Torvalds #include <linux/mm.h>
301da177e4SLinus Torvalds #include <linux/interrupt.h>
311da177e4SLinus Torvalds #include <net/lapb.h>
321da177e4SLinus Torvalds 
3383a37b32SKees Cook static void lapb_t1timer_expiry(struct timer_list *);
3483a37b32SKees Cook static void lapb_t2timer_expiry(struct timer_list *);
351da177e4SLinus Torvalds 
lapb_start_t1timer(struct lapb_cb * lapb)361da177e4SLinus Torvalds void lapb_start_t1timer(struct lapb_cb *lapb)
371da177e4SLinus Torvalds {
381da177e4SLinus Torvalds 	del_timer(&lapb->t1timer);
391da177e4SLinus Torvalds 
40841b86f3SKees Cook 	lapb->t1timer.function = lapb_t1timer_expiry;
411da177e4SLinus Torvalds 	lapb->t1timer.expires  = jiffies + lapb->t1;
421da177e4SLinus Torvalds 
43*65d2dbb3SXie He 	lapb->t1timer_running = true;
441da177e4SLinus Torvalds 	add_timer(&lapb->t1timer);
451da177e4SLinus Torvalds }
461da177e4SLinus Torvalds 
lapb_start_t2timer(struct lapb_cb * lapb)471da177e4SLinus Torvalds void lapb_start_t2timer(struct lapb_cb *lapb)
481da177e4SLinus Torvalds {
491da177e4SLinus Torvalds 	del_timer(&lapb->t2timer);
501da177e4SLinus Torvalds 
51841b86f3SKees Cook 	lapb->t2timer.function = lapb_t2timer_expiry;
521da177e4SLinus Torvalds 	lapb->t2timer.expires  = jiffies + lapb->t2;
531da177e4SLinus Torvalds 
54*65d2dbb3SXie He 	lapb->t2timer_running = true;
551da177e4SLinus Torvalds 	add_timer(&lapb->t2timer);
561da177e4SLinus Torvalds }
571da177e4SLinus Torvalds 
lapb_stop_t1timer(struct lapb_cb * lapb)581da177e4SLinus Torvalds void lapb_stop_t1timer(struct lapb_cb *lapb)
591da177e4SLinus Torvalds {
60*65d2dbb3SXie He 	lapb->t1timer_running = false;
611da177e4SLinus Torvalds 	del_timer(&lapb->t1timer);
621da177e4SLinus Torvalds }
631da177e4SLinus Torvalds 
lapb_stop_t2timer(struct lapb_cb * lapb)641da177e4SLinus Torvalds void lapb_stop_t2timer(struct lapb_cb *lapb)
651da177e4SLinus Torvalds {
66*65d2dbb3SXie He 	lapb->t2timer_running = false;
671da177e4SLinus Torvalds 	del_timer(&lapb->t2timer);
681da177e4SLinus Torvalds }
691da177e4SLinus Torvalds 
lapb_t1timer_running(struct lapb_cb * lapb)701da177e4SLinus Torvalds int lapb_t1timer_running(struct lapb_cb *lapb)
711da177e4SLinus Torvalds {
72*65d2dbb3SXie He 	return lapb->t1timer_running;
731da177e4SLinus Torvalds }
741da177e4SLinus Torvalds 
lapb_t2timer_expiry(struct timer_list * t)7583a37b32SKees Cook static void lapb_t2timer_expiry(struct timer_list *t)
761da177e4SLinus Torvalds {
7783a37b32SKees Cook 	struct lapb_cb *lapb = from_timer(lapb, t, t2timer);
781da177e4SLinus Torvalds 
79b491e6a7SXie He 	spin_lock_bh(&lapb->lock);
80b491e6a7SXie He 	if (timer_pending(&lapb->t2timer)) /* A new timer has been set up */
81b491e6a7SXie He 		goto out;
82*65d2dbb3SXie He 	if (!lapb->t2timer_running) /* The timer has been stopped */
83b491e6a7SXie He 		goto out;
84b491e6a7SXie He 
851da177e4SLinus Torvalds 	if (lapb->condition & LAPB_ACK_PENDING_CONDITION) {
861da177e4SLinus Torvalds 		lapb->condition &= ~LAPB_ACK_PENDING_CONDITION;
871da177e4SLinus Torvalds 		lapb_timeout_response(lapb);
881da177e4SLinus Torvalds 	}
89*65d2dbb3SXie He 	lapb->t2timer_running = false;
90b491e6a7SXie He 
91b491e6a7SXie He out:
92b491e6a7SXie He 	spin_unlock_bh(&lapb->lock);
931da177e4SLinus Torvalds }
941da177e4SLinus Torvalds 
lapb_t1timer_expiry(struct timer_list * t)9583a37b32SKees Cook static void lapb_t1timer_expiry(struct timer_list *t)
961da177e4SLinus Torvalds {
9783a37b32SKees Cook 	struct lapb_cb *lapb = from_timer(lapb, t, t1timer);
981da177e4SLinus Torvalds 
99b491e6a7SXie He 	spin_lock_bh(&lapb->lock);
100b491e6a7SXie He 	if (timer_pending(&lapb->t1timer)) /* A new timer has been set up */
101b491e6a7SXie He 		goto out;
102*65d2dbb3SXie He 	if (!lapb->t1timer_running) /* The timer has been stopped */
103b491e6a7SXie He 		goto out;
104b491e6a7SXie He 
1051da177e4SLinus Torvalds 	switch (lapb->state) {
1061da177e4SLinus Torvalds 
1071da177e4SLinus Torvalds 		/*
10862480b99SMartin Schiller 		 *	If we are a DCE, send DM up to N2 times, then switch to
10962480b99SMartin Schiller 		 *	STATE_1 and send SABM(E).
1101da177e4SLinus Torvalds 		 */
1111da177e4SLinus Torvalds 		case LAPB_STATE_0:
11262480b99SMartin Schiller 			if (lapb->mode & LAPB_DCE &&
11362480b99SMartin Schiller 			    lapb->n2count != lapb->n2) {
11462480b99SMartin Schiller 				lapb->n2count++;
1151da177e4SLinus Torvalds 				lapb_send_control(lapb, LAPB_DM, LAPB_POLLOFF, LAPB_RESPONSE);
11662480b99SMartin Schiller 			} else {
11762480b99SMartin Schiller 				lapb->state = LAPB_STATE_1;
11862480b99SMartin Schiller 				lapb_establish_data_link(lapb);
11962480b99SMartin Schiller 			}
1201da177e4SLinus Torvalds 			break;
1211da177e4SLinus Torvalds 
1221da177e4SLinus Torvalds 		/*
1231da177e4SLinus Torvalds 		 *	Awaiting connection state, send SABM(E), up to N2 times.
1241da177e4SLinus Torvalds 		 */
1251da177e4SLinus Torvalds 		case LAPB_STATE_1:
1261da177e4SLinus Torvalds 			if (lapb->n2count == lapb->n2) {
1271da177e4SLinus Torvalds 				lapb_clear_queues(lapb);
1281da177e4SLinus Torvalds 				lapb->state = LAPB_STATE_0;
1291da177e4SLinus Torvalds 				lapb_disconnect_indication(lapb, LAPB_TIMEDOUT);
130a508da6cSJoe Perches 				lapb_dbg(0, "(%p) S1 -> S0\n", lapb->dev);
131*65d2dbb3SXie He 				lapb->t1timer_running = false;
132b491e6a7SXie He 				goto out;
1331da177e4SLinus Torvalds 			} else {
1341da177e4SLinus Torvalds 				lapb->n2count++;
1351da177e4SLinus Torvalds 				if (lapb->mode & LAPB_EXTENDED) {
136a508da6cSJoe Perches 					lapb_dbg(1, "(%p) S1 TX SABME(1)\n",
137a508da6cSJoe Perches 						 lapb->dev);
1381da177e4SLinus Torvalds 					lapb_send_control(lapb, LAPB_SABME, LAPB_POLLON, LAPB_COMMAND);
1391da177e4SLinus Torvalds 				} else {
140a508da6cSJoe Perches 					lapb_dbg(1, "(%p) S1 TX SABM(1)\n",
141a508da6cSJoe Perches 						 lapb->dev);
1421da177e4SLinus Torvalds 					lapb_send_control(lapb, LAPB_SABM, LAPB_POLLON, LAPB_COMMAND);
1431da177e4SLinus Torvalds 				}
1441da177e4SLinus Torvalds 			}
1451da177e4SLinus Torvalds 			break;
1461da177e4SLinus Torvalds 
1471da177e4SLinus Torvalds 		/*
1481da177e4SLinus Torvalds 		 *	Awaiting disconnection state, send DISC, up to N2 times.
1491da177e4SLinus Torvalds 		 */
1501da177e4SLinus Torvalds 		case LAPB_STATE_2:
1511da177e4SLinus Torvalds 			if (lapb->n2count == lapb->n2) {
1521da177e4SLinus Torvalds 				lapb_clear_queues(lapb);
1531da177e4SLinus Torvalds 				lapb->state = LAPB_STATE_0;
1541da177e4SLinus Torvalds 				lapb_disconnect_confirmation(lapb, LAPB_TIMEDOUT);
155a508da6cSJoe Perches 				lapb_dbg(0, "(%p) S2 -> S0\n", lapb->dev);
156*65d2dbb3SXie He 				lapb->t1timer_running = false;
157b491e6a7SXie He 				goto out;
1581da177e4SLinus Torvalds 			} else {
1591da177e4SLinus Torvalds 				lapb->n2count++;
160a508da6cSJoe Perches 				lapb_dbg(1, "(%p) S2 TX DISC(1)\n", lapb->dev);
1611da177e4SLinus Torvalds 				lapb_send_control(lapb, LAPB_DISC, LAPB_POLLON, LAPB_COMMAND);
1621da177e4SLinus Torvalds 			}
1631da177e4SLinus Torvalds 			break;
1641da177e4SLinus Torvalds 
1651da177e4SLinus Torvalds 		/*
1661da177e4SLinus Torvalds 		 *	Data transfer state, restransmit I frames, up to N2 times.
1671da177e4SLinus Torvalds 		 */
1681da177e4SLinus Torvalds 		case LAPB_STATE_3:
1691da177e4SLinus Torvalds 			if (lapb->n2count == lapb->n2) {
1701da177e4SLinus Torvalds 				lapb_clear_queues(lapb);
1711da177e4SLinus Torvalds 				lapb->state = LAPB_STATE_0;
1721da177e4SLinus Torvalds 				lapb_stop_t2timer(lapb);
1731da177e4SLinus Torvalds 				lapb_disconnect_indication(lapb, LAPB_TIMEDOUT);
174a508da6cSJoe Perches 				lapb_dbg(0, "(%p) S3 -> S0\n", lapb->dev);
175*65d2dbb3SXie He 				lapb->t1timer_running = false;
176b491e6a7SXie He 				goto out;
1771da177e4SLinus Torvalds 			} else {
1781da177e4SLinus Torvalds 				lapb->n2count++;
1791da177e4SLinus Torvalds 				lapb_requeue_frames(lapb);
180a224bd36Sjosselin.costanzi@mobile-devices.fr 				lapb_kick(lapb);
1811da177e4SLinus Torvalds 			}
1821da177e4SLinus Torvalds 			break;
1831da177e4SLinus Torvalds 
1841da177e4SLinus Torvalds 		/*
1851da177e4SLinus Torvalds 		 *	Frame reject state, restransmit FRMR frames, up to N2 times.
1861da177e4SLinus Torvalds 		 */
1871da177e4SLinus Torvalds 		case LAPB_STATE_4:
1881da177e4SLinus Torvalds 			if (lapb->n2count == lapb->n2) {
1891da177e4SLinus Torvalds 				lapb_clear_queues(lapb);
1901da177e4SLinus Torvalds 				lapb->state = LAPB_STATE_0;
1911da177e4SLinus Torvalds 				lapb_disconnect_indication(lapb, LAPB_TIMEDOUT);
192a508da6cSJoe Perches 				lapb_dbg(0, "(%p) S4 -> S0\n", lapb->dev);
193*65d2dbb3SXie He 				lapb->t1timer_running = false;
194b491e6a7SXie He 				goto out;
1951da177e4SLinus Torvalds 			} else {
1961da177e4SLinus Torvalds 				lapb->n2count++;
1971da177e4SLinus Torvalds 				lapb_transmit_frmr(lapb);
1981da177e4SLinus Torvalds 			}
1991da177e4SLinus Torvalds 			break;
2001da177e4SLinus Torvalds 	}
2011da177e4SLinus Torvalds 
2021da177e4SLinus Torvalds 	lapb_start_t1timer(lapb);
203b491e6a7SXie He 
204b491e6a7SXie He out:
205b491e6a7SXie He 	spin_unlock_bh(&lapb->lock);
2061da177e4SLinus Torvalds }
207