xref: /openbmc/linux/net/nfc/hci/llc_shdlc.c (revision 4a61cd6687fc6348d08724676d34e38160d6cf9b)
1*4a61cd66SEric Lapuyade /*
2*4a61cd66SEric Lapuyade  * shdlc Link Layer Control
3*4a61cd66SEric Lapuyade  *
4*4a61cd66SEric Lapuyade  * Copyright (C) 2012  Intel Corporation. All rights reserved.
5*4a61cd66SEric Lapuyade  *
6*4a61cd66SEric Lapuyade  * This program is free software; you can redistribute it and/or modify it
7*4a61cd66SEric Lapuyade  * under the terms and conditions of the GNU General Public License,
8*4a61cd66SEric Lapuyade  * version 2, as published by the Free Software Foundation.
9*4a61cd66SEric Lapuyade  *
10*4a61cd66SEric Lapuyade  * This program is distributed in the hope that it will be useful,
11*4a61cd66SEric Lapuyade  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12*4a61cd66SEric Lapuyade  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13*4a61cd66SEric Lapuyade  * GNU General Public License for more details.
14*4a61cd66SEric Lapuyade  *
15*4a61cd66SEric Lapuyade  * You should have received a copy of the GNU General Public License
16*4a61cd66SEric Lapuyade  * along with this program; if not, write to the
17*4a61cd66SEric Lapuyade  * Free Software Foundation, Inc.,
18*4a61cd66SEric Lapuyade  * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19*4a61cd66SEric Lapuyade  */
20*4a61cd66SEric Lapuyade 
21*4a61cd66SEric Lapuyade #define pr_fmt(fmt) "shdlc: %s: " fmt, __func__
22*4a61cd66SEric Lapuyade 
23*4a61cd66SEric Lapuyade #include <linux/types.h>
24*4a61cd66SEric Lapuyade #include <linux/sched.h>
25*4a61cd66SEric Lapuyade #include <linux/export.h>
26*4a61cd66SEric Lapuyade #include <linux/wait.h>
27*4a61cd66SEric Lapuyade #include <linux/slab.h>
28*4a61cd66SEric Lapuyade #include <linux/skbuff.h>
29*4a61cd66SEric Lapuyade 
30*4a61cd66SEric Lapuyade #include "llc.h"
31*4a61cd66SEric Lapuyade 
32*4a61cd66SEric Lapuyade enum shdlc_state {
33*4a61cd66SEric Lapuyade 	SHDLC_DISCONNECTED = 0,
34*4a61cd66SEric Lapuyade 	SHDLC_CONNECTING = 1,
35*4a61cd66SEric Lapuyade 	SHDLC_NEGOCIATING = 2,
36*4a61cd66SEric Lapuyade 	SHDLC_CONNECTED = 3
37*4a61cd66SEric Lapuyade };
38*4a61cd66SEric Lapuyade 
39*4a61cd66SEric Lapuyade struct llc_shdlc {
40*4a61cd66SEric Lapuyade 	struct nfc_hci_dev *hdev;
41*4a61cd66SEric Lapuyade 	xmit_to_drv_t xmit_to_drv;
42*4a61cd66SEric Lapuyade 	rcv_to_hci_t rcv_to_hci;
43*4a61cd66SEric Lapuyade 
44*4a61cd66SEric Lapuyade 	struct mutex state_mutex;
45*4a61cd66SEric Lapuyade 	enum shdlc_state state;
46*4a61cd66SEric Lapuyade 	int hard_fault;
47*4a61cd66SEric Lapuyade 
48*4a61cd66SEric Lapuyade 	wait_queue_head_t *connect_wq;
49*4a61cd66SEric Lapuyade 	int connect_tries;
50*4a61cd66SEric Lapuyade 	int connect_result;
51*4a61cd66SEric Lapuyade 	struct timer_list connect_timer;/* aka T3 in spec 10.6.1 */
52*4a61cd66SEric Lapuyade 
53*4a61cd66SEric Lapuyade 	u8 w;				/* window size */
54*4a61cd66SEric Lapuyade 	bool srej_support;
55*4a61cd66SEric Lapuyade 
56*4a61cd66SEric Lapuyade 	struct timer_list t1_timer;	/* send ack timeout */
57*4a61cd66SEric Lapuyade 	bool t1_active;
58*4a61cd66SEric Lapuyade 
59*4a61cd66SEric Lapuyade 	struct timer_list t2_timer;	/* guard/retransmit timeout */
60*4a61cd66SEric Lapuyade 	bool t2_active;
61*4a61cd66SEric Lapuyade 
62*4a61cd66SEric Lapuyade 	int ns;				/* next seq num for send */
63*4a61cd66SEric Lapuyade 	int nr;				/* next expected seq num for receive */
64*4a61cd66SEric Lapuyade 	int dnr;			/* oldest sent unacked seq num */
65*4a61cd66SEric Lapuyade 
66*4a61cd66SEric Lapuyade 	struct sk_buff_head rcv_q;
67*4a61cd66SEric Lapuyade 
68*4a61cd66SEric Lapuyade 	struct sk_buff_head send_q;
69*4a61cd66SEric Lapuyade 	bool rnr;			/* other side is not ready to receive */
70*4a61cd66SEric Lapuyade 
71*4a61cd66SEric Lapuyade 	struct sk_buff_head ack_pending_q;
72*4a61cd66SEric Lapuyade 
73*4a61cd66SEric Lapuyade 	struct work_struct sm_work;
74*4a61cd66SEric Lapuyade 
75*4a61cd66SEric Lapuyade 	int tx_headroom;
76*4a61cd66SEric Lapuyade 	int tx_tailroom;
77*4a61cd66SEric Lapuyade 
78*4a61cd66SEric Lapuyade 	llc_failure_t llc_failure;
79*4a61cd66SEric Lapuyade };
80*4a61cd66SEric Lapuyade 
81*4a61cd66SEric Lapuyade #define SHDLC_LLC_HEAD_ROOM	2
82*4a61cd66SEric Lapuyade 
83*4a61cd66SEric Lapuyade #define SHDLC_MAX_WINDOW	4
84*4a61cd66SEric Lapuyade #define SHDLC_SREJ_SUPPORT	false
85*4a61cd66SEric Lapuyade 
86*4a61cd66SEric Lapuyade #define SHDLC_CONTROL_HEAD_MASK	0xe0
87*4a61cd66SEric Lapuyade #define SHDLC_CONTROL_HEAD_I	0x80
88*4a61cd66SEric Lapuyade #define SHDLC_CONTROL_HEAD_I2	0xa0
89*4a61cd66SEric Lapuyade #define SHDLC_CONTROL_HEAD_S	0xc0
90*4a61cd66SEric Lapuyade #define SHDLC_CONTROL_HEAD_U	0xe0
91*4a61cd66SEric Lapuyade 
92*4a61cd66SEric Lapuyade #define SHDLC_CONTROL_NS_MASK	0x38
93*4a61cd66SEric Lapuyade #define SHDLC_CONTROL_NR_MASK	0x07
94*4a61cd66SEric Lapuyade #define SHDLC_CONTROL_TYPE_MASK	0x18
95*4a61cd66SEric Lapuyade 
96*4a61cd66SEric Lapuyade #define SHDLC_CONTROL_M_MASK	0x1f
97*4a61cd66SEric Lapuyade 
98*4a61cd66SEric Lapuyade enum sframe_type {
99*4a61cd66SEric Lapuyade 	S_FRAME_RR = 0x00,
100*4a61cd66SEric Lapuyade 	S_FRAME_REJ = 0x01,
101*4a61cd66SEric Lapuyade 	S_FRAME_RNR = 0x02,
102*4a61cd66SEric Lapuyade 	S_FRAME_SREJ = 0x03
103*4a61cd66SEric Lapuyade };
104*4a61cd66SEric Lapuyade 
105*4a61cd66SEric Lapuyade enum uframe_modifier {
106*4a61cd66SEric Lapuyade 	U_FRAME_UA = 0x06,
107*4a61cd66SEric Lapuyade 	U_FRAME_RSET = 0x19
108*4a61cd66SEric Lapuyade };
109*4a61cd66SEric Lapuyade 
110*4a61cd66SEric Lapuyade #define SHDLC_CONNECT_VALUE_MS	5
111*4a61cd66SEric Lapuyade #define SHDLC_T1_VALUE_MS(w)	((5 * w) / 4)
112*4a61cd66SEric Lapuyade #define SHDLC_T2_VALUE_MS	300
113*4a61cd66SEric Lapuyade 
114*4a61cd66SEric Lapuyade #define SHDLC_DUMP_SKB(info, skb)				  \
115*4a61cd66SEric Lapuyade do {								  \
116*4a61cd66SEric Lapuyade 	pr_debug("%s:\n", info);				  \
117*4a61cd66SEric Lapuyade 	print_hex_dump(KERN_DEBUG, "shdlc: ", DUMP_PREFIX_OFFSET, \
118*4a61cd66SEric Lapuyade 		       16, 1, skb->data, skb->len, 0);		  \
119*4a61cd66SEric Lapuyade } while (0)
120*4a61cd66SEric Lapuyade 
121*4a61cd66SEric Lapuyade /* checks x < y <= z modulo 8 */
122*4a61cd66SEric Lapuyade static bool llc_shdlc_x_lt_y_lteq_z(int x, int y, int z)
123*4a61cd66SEric Lapuyade {
124*4a61cd66SEric Lapuyade 	if (x < z)
125*4a61cd66SEric Lapuyade 		return ((x < y) && (y <= z)) ? true : false;
126*4a61cd66SEric Lapuyade 	else
127*4a61cd66SEric Lapuyade 		return ((y > x) || (y <= z)) ? true : false;
128*4a61cd66SEric Lapuyade }
129*4a61cd66SEric Lapuyade 
130*4a61cd66SEric Lapuyade /* checks x <= y < z modulo 8 */
131*4a61cd66SEric Lapuyade static bool llc_shdlc_x_lteq_y_lt_z(int x, int y, int z)
132*4a61cd66SEric Lapuyade {
133*4a61cd66SEric Lapuyade 	if (x <= z)
134*4a61cd66SEric Lapuyade 		return ((x <= y) && (y < z)) ? true : false;
135*4a61cd66SEric Lapuyade 	else			/* x > z -> z+8 > x */
136*4a61cd66SEric Lapuyade 		return ((y >= x) || (y < z)) ? true : false;
137*4a61cd66SEric Lapuyade }
138*4a61cd66SEric Lapuyade 
139*4a61cd66SEric Lapuyade static struct sk_buff *llc_shdlc_alloc_skb(struct llc_shdlc *shdlc,
140*4a61cd66SEric Lapuyade 					   int payload_len)
141*4a61cd66SEric Lapuyade {
142*4a61cd66SEric Lapuyade 	struct sk_buff *skb;
143*4a61cd66SEric Lapuyade 
144*4a61cd66SEric Lapuyade 	skb = alloc_skb(shdlc->tx_headroom + SHDLC_LLC_HEAD_ROOM +
145*4a61cd66SEric Lapuyade 			shdlc->tx_tailroom + payload_len, GFP_KERNEL);
146*4a61cd66SEric Lapuyade 	if (skb)
147*4a61cd66SEric Lapuyade 		skb_reserve(skb, shdlc->tx_headroom + SHDLC_LLC_HEAD_ROOM);
148*4a61cd66SEric Lapuyade 
149*4a61cd66SEric Lapuyade 	return skb;
150*4a61cd66SEric Lapuyade }
151*4a61cd66SEric Lapuyade 
152*4a61cd66SEric Lapuyade /* immediately sends an S frame. */
153*4a61cd66SEric Lapuyade static int llc_shdlc_send_s_frame(struct llc_shdlc *shdlc,
154*4a61cd66SEric Lapuyade 				  enum sframe_type sframe_type, int nr)
155*4a61cd66SEric Lapuyade {
156*4a61cd66SEric Lapuyade 	int r;
157*4a61cd66SEric Lapuyade 	struct sk_buff *skb;
158*4a61cd66SEric Lapuyade 
159*4a61cd66SEric Lapuyade 	pr_debug("sframe_type=%d nr=%d\n", sframe_type, nr);
160*4a61cd66SEric Lapuyade 
161*4a61cd66SEric Lapuyade 	skb = llc_shdlc_alloc_skb(shdlc, 0);
162*4a61cd66SEric Lapuyade 	if (skb == NULL)
163*4a61cd66SEric Lapuyade 		return -ENOMEM;
164*4a61cd66SEric Lapuyade 
165*4a61cd66SEric Lapuyade 	*skb_push(skb, 1) = SHDLC_CONTROL_HEAD_S | (sframe_type << 3) | nr;
166*4a61cd66SEric Lapuyade 
167*4a61cd66SEric Lapuyade 	r = shdlc->xmit_to_drv(shdlc->hdev, skb);
168*4a61cd66SEric Lapuyade 
169*4a61cd66SEric Lapuyade 	kfree_skb(skb);
170*4a61cd66SEric Lapuyade 
171*4a61cd66SEric Lapuyade 	return r;
172*4a61cd66SEric Lapuyade }
173*4a61cd66SEric Lapuyade 
174*4a61cd66SEric Lapuyade /* immediately sends an U frame. skb may contain optional payload */
175*4a61cd66SEric Lapuyade static int llc_shdlc_send_u_frame(struct llc_shdlc *shdlc,
176*4a61cd66SEric Lapuyade 				  struct sk_buff *skb,
177*4a61cd66SEric Lapuyade 				  enum uframe_modifier uframe_modifier)
178*4a61cd66SEric Lapuyade {
179*4a61cd66SEric Lapuyade 	int r;
180*4a61cd66SEric Lapuyade 
181*4a61cd66SEric Lapuyade 	pr_debug("uframe_modifier=%d\n", uframe_modifier);
182*4a61cd66SEric Lapuyade 
183*4a61cd66SEric Lapuyade 	*skb_push(skb, 1) = SHDLC_CONTROL_HEAD_U | uframe_modifier;
184*4a61cd66SEric Lapuyade 
185*4a61cd66SEric Lapuyade 	r = shdlc->xmit_to_drv(shdlc->hdev, skb);
186*4a61cd66SEric Lapuyade 
187*4a61cd66SEric Lapuyade 	kfree_skb(skb);
188*4a61cd66SEric Lapuyade 
189*4a61cd66SEric Lapuyade 	return r;
190*4a61cd66SEric Lapuyade }
191*4a61cd66SEric Lapuyade 
192*4a61cd66SEric Lapuyade /*
193*4a61cd66SEric Lapuyade  * Free ack_pending frames until y_nr - 1, and reset t2 according to
194*4a61cd66SEric Lapuyade  * the remaining oldest ack_pending frame sent time
195*4a61cd66SEric Lapuyade  */
196*4a61cd66SEric Lapuyade static void llc_shdlc_reset_t2(struct llc_shdlc *shdlc, int y_nr)
197*4a61cd66SEric Lapuyade {
198*4a61cd66SEric Lapuyade 	struct sk_buff *skb;
199*4a61cd66SEric Lapuyade 	int dnr = shdlc->dnr;	/* MUST initially be < y_nr */
200*4a61cd66SEric Lapuyade 
201*4a61cd66SEric Lapuyade 	pr_debug("release ack pending up to frame %d excluded\n", y_nr);
202*4a61cd66SEric Lapuyade 
203*4a61cd66SEric Lapuyade 	while (dnr != y_nr) {
204*4a61cd66SEric Lapuyade 		pr_debug("release ack pending frame %d\n", dnr);
205*4a61cd66SEric Lapuyade 
206*4a61cd66SEric Lapuyade 		skb = skb_dequeue(&shdlc->ack_pending_q);
207*4a61cd66SEric Lapuyade 		kfree_skb(skb);
208*4a61cd66SEric Lapuyade 
209*4a61cd66SEric Lapuyade 		dnr = (dnr + 1) % 8;
210*4a61cd66SEric Lapuyade 	}
211*4a61cd66SEric Lapuyade 
212*4a61cd66SEric Lapuyade 	if (skb_queue_empty(&shdlc->ack_pending_q)) {
213*4a61cd66SEric Lapuyade 		if (shdlc->t2_active) {
214*4a61cd66SEric Lapuyade 			del_timer_sync(&shdlc->t2_timer);
215*4a61cd66SEric Lapuyade 			shdlc->t2_active = false;
216*4a61cd66SEric Lapuyade 
217*4a61cd66SEric Lapuyade 			pr_debug
218*4a61cd66SEric Lapuyade 			    ("All sent frames acked. Stopped T2(retransmit)\n");
219*4a61cd66SEric Lapuyade 		}
220*4a61cd66SEric Lapuyade 	} else {
221*4a61cd66SEric Lapuyade 		skb = skb_peek(&shdlc->ack_pending_q);
222*4a61cd66SEric Lapuyade 
223*4a61cd66SEric Lapuyade 		mod_timer(&shdlc->t2_timer, *(unsigned long *)skb->cb +
224*4a61cd66SEric Lapuyade 			  msecs_to_jiffies(SHDLC_T2_VALUE_MS));
225*4a61cd66SEric Lapuyade 		shdlc->t2_active = true;
226*4a61cd66SEric Lapuyade 
227*4a61cd66SEric Lapuyade 		pr_debug
228*4a61cd66SEric Lapuyade 		    ("Start T2(retransmit) for remaining unacked sent frames\n");
229*4a61cd66SEric Lapuyade 	}
230*4a61cd66SEric Lapuyade }
231*4a61cd66SEric Lapuyade 
232*4a61cd66SEric Lapuyade /*
233*4a61cd66SEric Lapuyade  * Receive validated frames from lower layer. skb contains HCI payload only.
234*4a61cd66SEric Lapuyade  * Handle according to algorithm at spec:10.8.2
235*4a61cd66SEric Lapuyade  */
236*4a61cd66SEric Lapuyade static void llc_shdlc_rcv_i_frame(struct llc_shdlc *shdlc,
237*4a61cd66SEric Lapuyade 				  struct sk_buff *skb, int ns, int nr)
238*4a61cd66SEric Lapuyade {
239*4a61cd66SEric Lapuyade 	int x_ns = ns;
240*4a61cd66SEric Lapuyade 	int y_nr = nr;
241*4a61cd66SEric Lapuyade 
242*4a61cd66SEric Lapuyade 	pr_debug("recvd I-frame %d, remote waiting frame %d\n", ns, nr);
243*4a61cd66SEric Lapuyade 
244*4a61cd66SEric Lapuyade 	if (shdlc->state != SHDLC_CONNECTED)
245*4a61cd66SEric Lapuyade 		goto exit;
246*4a61cd66SEric Lapuyade 
247*4a61cd66SEric Lapuyade 	if (x_ns != shdlc->nr) {
248*4a61cd66SEric Lapuyade 		llc_shdlc_send_s_frame(shdlc, S_FRAME_REJ, shdlc->nr);
249*4a61cd66SEric Lapuyade 		goto exit;
250*4a61cd66SEric Lapuyade 	}
251*4a61cd66SEric Lapuyade 
252*4a61cd66SEric Lapuyade 	if (shdlc->t1_active == false) {
253*4a61cd66SEric Lapuyade 		shdlc->t1_active = true;
254*4a61cd66SEric Lapuyade 		mod_timer(&shdlc->t1_timer, jiffies +
255*4a61cd66SEric Lapuyade 			  msecs_to_jiffies(SHDLC_T1_VALUE_MS(shdlc->w)));
256*4a61cd66SEric Lapuyade 		pr_debug("(re)Start T1(send ack)\n");
257*4a61cd66SEric Lapuyade 	}
258*4a61cd66SEric Lapuyade 
259*4a61cd66SEric Lapuyade 	if (skb->len) {
260*4a61cd66SEric Lapuyade 		shdlc->rcv_to_hci(shdlc->hdev, skb);
261*4a61cd66SEric Lapuyade 		skb = NULL;
262*4a61cd66SEric Lapuyade 	}
263*4a61cd66SEric Lapuyade 
264*4a61cd66SEric Lapuyade 	shdlc->nr = (shdlc->nr + 1) % 8;
265*4a61cd66SEric Lapuyade 
266*4a61cd66SEric Lapuyade 	if (llc_shdlc_x_lt_y_lteq_z(shdlc->dnr, y_nr, shdlc->ns)) {
267*4a61cd66SEric Lapuyade 		llc_shdlc_reset_t2(shdlc, y_nr);
268*4a61cd66SEric Lapuyade 
269*4a61cd66SEric Lapuyade 		shdlc->dnr = y_nr;
270*4a61cd66SEric Lapuyade 	}
271*4a61cd66SEric Lapuyade 
272*4a61cd66SEric Lapuyade exit:
273*4a61cd66SEric Lapuyade 	kfree_skb(skb);
274*4a61cd66SEric Lapuyade }
275*4a61cd66SEric Lapuyade 
276*4a61cd66SEric Lapuyade static void llc_shdlc_rcv_ack(struct llc_shdlc *shdlc, int y_nr)
277*4a61cd66SEric Lapuyade {
278*4a61cd66SEric Lapuyade 	pr_debug("remote acked up to frame %d excluded\n", y_nr);
279*4a61cd66SEric Lapuyade 
280*4a61cd66SEric Lapuyade 	if (llc_shdlc_x_lt_y_lteq_z(shdlc->dnr, y_nr, shdlc->ns)) {
281*4a61cd66SEric Lapuyade 		llc_shdlc_reset_t2(shdlc, y_nr);
282*4a61cd66SEric Lapuyade 		shdlc->dnr = y_nr;
283*4a61cd66SEric Lapuyade 	}
284*4a61cd66SEric Lapuyade }
285*4a61cd66SEric Lapuyade 
286*4a61cd66SEric Lapuyade static void llc_shdlc_requeue_ack_pending(struct llc_shdlc *shdlc)
287*4a61cd66SEric Lapuyade {
288*4a61cd66SEric Lapuyade 	struct sk_buff *skb;
289*4a61cd66SEric Lapuyade 
290*4a61cd66SEric Lapuyade 	pr_debug("ns reset to %d\n", shdlc->dnr);
291*4a61cd66SEric Lapuyade 
292*4a61cd66SEric Lapuyade 	while ((skb = skb_dequeue_tail(&shdlc->ack_pending_q))) {
293*4a61cd66SEric Lapuyade 		skb_pull(skb, 1);	/* remove control field */
294*4a61cd66SEric Lapuyade 		skb_queue_head(&shdlc->send_q, skb);
295*4a61cd66SEric Lapuyade 	}
296*4a61cd66SEric Lapuyade 	shdlc->ns = shdlc->dnr;
297*4a61cd66SEric Lapuyade }
298*4a61cd66SEric Lapuyade 
299*4a61cd66SEric Lapuyade static void llc_shdlc_rcv_rej(struct llc_shdlc *shdlc, int y_nr)
300*4a61cd66SEric Lapuyade {
301*4a61cd66SEric Lapuyade 	struct sk_buff *skb;
302*4a61cd66SEric Lapuyade 
303*4a61cd66SEric Lapuyade 	pr_debug("remote asks retransmition from frame %d\n", y_nr);
304*4a61cd66SEric Lapuyade 
305*4a61cd66SEric Lapuyade 	if (llc_shdlc_x_lteq_y_lt_z(shdlc->dnr, y_nr, shdlc->ns)) {
306*4a61cd66SEric Lapuyade 		if (shdlc->t2_active) {
307*4a61cd66SEric Lapuyade 			del_timer_sync(&shdlc->t2_timer);
308*4a61cd66SEric Lapuyade 			shdlc->t2_active = false;
309*4a61cd66SEric Lapuyade 			pr_debug("Stopped T2(retransmit)\n");
310*4a61cd66SEric Lapuyade 		}
311*4a61cd66SEric Lapuyade 
312*4a61cd66SEric Lapuyade 		if (shdlc->dnr != y_nr) {
313*4a61cd66SEric Lapuyade 			while ((shdlc->dnr = ((shdlc->dnr + 1) % 8)) != y_nr) {
314*4a61cd66SEric Lapuyade 				skb = skb_dequeue(&shdlc->ack_pending_q);
315*4a61cd66SEric Lapuyade 				kfree_skb(skb);
316*4a61cd66SEric Lapuyade 			}
317*4a61cd66SEric Lapuyade 		}
318*4a61cd66SEric Lapuyade 
319*4a61cd66SEric Lapuyade 		llc_shdlc_requeue_ack_pending(shdlc);
320*4a61cd66SEric Lapuyade 	}
321*4a61cd66SEric Lapuyade }
322*4a61cd66SEric Lapuyade 
323*4a61cd66SEric Lapuyade /* See spec RR:10.8.3 REJ:10.8.4 */
324*4a61cd66SEric Lapuyade static void llc_shdlc_rcv_s_frame(struct llc_shdlc *shdlc,
325*4a61cd66SEric Lapuyade 				  enum sframe_type s_frame_type, int nr)
326*4a61cd66SEric Lapuyade {
327*4a61cd66SEric Lapuyade 	struct sk_buff *skb;
328*4a61cd66SEric Lapuyade 
329*4a61cd66SEric Lapuyade 	if (shdlc->state != SHDLC_CONNECTED)
330*4a61cd66SEric Lapuyade 		return;
331*4a61cd66SEric Lapuyade 
332*4a61cd66SEric Lapuyade 	switch (s_frame_type) {
333*4a61cd66SEric Lapuyade 	case S_FRAME_RR:
334*4a61cd66SEric Lapuyade 		llc_shdlc_rcv_ack(shdlc, nr);
335*4a61cd66SEric Lapuyade 		if (shdlc->rnr == true) {	/* see SHDLC 10.7.7 */
336*4a61cd66SEric Lapuyade 			shdlc->rnr = false;
337*4a61cd66SEric Lapuyade 			if (shdlc->send_q.qlen == 0) {
338*4a61cd66SEric Lapuyade 				skb = llc_shdlc_alloc_skb(shdlc, 0);
339*4a61cd66SEric Lapuyade 				if (skb)
340*4a61cd66SEric Lapuyade 					skb_queue_tail(&shdlc->send_q, skb);
341*4a61cd66SEric Lapuyade 			}
342*4a61cd66SEric Lapuyade 		}
343*4a61cd66SEric Lapuyade 		break;
344*4a61cd66SEric Lapuyade 	case S_FRAME_REJ:
345*4a61cd66SEric Lapuyade 		llc_shdlc_rcv_rej(shdlc, nr);
346*4a61cd66SEric Lapuyade 		break;
347*4a61cd66SEric Lapuyade 	case S_FRAME_RNR:
348*4a61cd66SEric Lapuyade 		llc_shdlc_rcv_ack(shdlc, nr);
349*4a61cd66SEric Lapuyade 		shdlc->rnr = true;
350*4a61cd66SEric Lapuyade 		break;
351*4a61cd66SEric Lapuyade 	default:
352*4a61cd66SEric Lapuyade 		break;
353*4a61cd66SEric Lapuyade 	}
354*4a61cd66SEric Lapuyade }
355*4a61cd66SEric Lapuyade 
356*4a61cd66SEric Lapuyade static void llc_shdlc_connect_complete(struct llc_shdlc *shdlc, int r)
357*4a61cd66SEric Lapuyade {
358*4a61cd66SEric Lapuyade 	pr_debug("result=%d\n", r);
359*4a61cd66SEric Lapuyade 
360*4a61cd66SEric Lapuyade 	del_timer_sync(&shdlc->connect_timer);
361*4a61cd66SEric Lapuyade 
362*4a61cd66SEric Lapuyade 	if (r == 0) {
363*4a61cd66SEric Lapuyade 		shdlc->ns = 0;
364*4a61cd66SEric Lapuyade 		shdlc->nr = 0;
365*4a61cd66SEric Lapuyade 		shdlc->dnr = 0;
366*4a61cd66SEric Lapuyade 
367*4a61cd66SEric Lapuyade 		shdlc->state = SHDLC_CONNECTED;
368*4a61cd66SEric Lapuyade 	} else {
369*4a61cd66SEric Lapuyade 		shdlc->state = SHDLC_DISCONNECTED;
370*4a61cd66SEric Lapuyade 	}
371*4a61cd66SEric Lapuyade 
372*4a61cd66SEric Lapuyade 	shdlc->connect_result = r;
373*4a61cd66SEric Lapuyade 
374*4a61cd66SEric Lapuyade 	wake_up(shdlc->connect_wq);
375*4a61cd66SEric Lapuyade }
376*4a61cd66SEric Lapuyade 
377*4a61cd66SEric Lapuyade static int llc_shdlc_connect_initiate(struct llc_shdlc *shdlc)
378*4a61cd66SEric Lapuyade {
379*4a61cd66SEric Lapuyade 	struct sk_buff *skb;
380*4a61cd66SEric Lapuyade 
381*4a61cd66SEric Lapuyade 	pr_debug("\n");
382*4a61cd66SEric Lapuyade 
383*4a61cd66SEric Lapuyade 	skb = llc_shdlc_alloc_skb(shdlc, 2);
384*4a61cd66SEric Lapuyade 	if (skb == NULL)
385*4a61cd66SEric Lapuyade 		return -ENOMEM;
386*4a61cd66SEric Lapuyade 
387*4a61cd66SEric Lapuyade 	*skb_put(skb, 1) = SHDLC_MAX_WINDOW;
388*4a61cd66SEric Lapuyade 	*skb_put(skb, 1) = SHDLC_SREJ_SUPPORT ? 1 : 0;
389*4a61cd66SEric Lapuyade 
390*4a61cd66SEric Lapuyade 	return llc_shdlc_send_u_frame(shdlc, skb, U_FRAME_RSET);
391*4a61cd66SEric Lapuyade }
392*4a61cd66SEric Lapuyade 
393*4a61cd66SEric Lapuyade static int llc_shdlc_connect_send_ua(struct llc_shdlc *shdlc)
394*4a61cd66SEric Lapuyade {
395*4a61cd66SEric Lapuyade 	struct sk_buff *skb;
396*4a61cd66SEric Lapuyade 
397*4a61cd66SEric Lapuyade 	pr_debug("\n");
398*4a61cd66SEric Lapuyade 
399*4a61cd66SEric Lapuyade 	skb = llc_shdlc_alloc_skb(shdlc, 0);
400*4a61cd66SEric Lapuyade 	if (skb == NULL)
401*4a61cd66SEric Lapuyade 		return -ENOMEM;
402*4a61cd66SEric Lapuyade 
403*4a61cd66SEric Lapuyade 	return llc_shdlc_send_u_frame(shdlc, skb, U_FRAME_UA);
404*4a61cd66SEric Lapuyade }
405*4a61cd66SEric Lapuyade 
406*4a61cd66SEric Lapuyade static void llc_shdlc_rcv_u_frame(struct llc_shdlc *shdlc,
407*4a61cd66SEric Lapuyade 				  struct sk_buff *skb,
408*4a61cd66SEric Lapuyade 				  enum uframe_modifier u_frame_modifier)
409*4a61cd66SEric Lapuyade {
410*4a61cd66SEric Lapuyade 	u8 w = SHDLC_MAX_WINDOW;
411*4a61cd66SEric Lapuyade 	bool srej_support = SHDLC_SREJ_SUPPORT;
412*4a61cd66SEric Lapuyade 	int r;
413*4a61cd66SEric Lapuyade 
414*4a61cd66SEric Lapuyade 	pr_debug("u_frame_modifier=%d\n", u_frame_modifier);
415*4a61cd66SEric Lapuyade 
416*4a61cd66SEric Lapuyade 	switch (u_frame_modifier) {
417*4a61cd66SEric Lapuyade 	case U_FRAME_RSET:
418*4a61cd66SEric Lapuyade 		if (shdlc->state == SHDLC_NEGOCIATING) {
419*4a61cd66SEric Lapuyade 			/* we sent RSET, but chip wants to negociate */
420*4a61cd66SEric Lapuyade 			if (skb->len > 0)
421*4a61cd66SEric Lapuyade 				w = skb->data[0];
422*4a61cd66SEric Lapuyade 
423*4a61cd66SEric Lapuyade 			if (skb->len > 1)
424*4a61cd66SEric Lapuyade 				srej_support = skb->data[1] & 0x01 ? true :
425*4a61cd66SEric Lapuyade 					       false;
426*4a61cd66SEric Lapuyade 
427*4a61cd66SEric Lapuyade 			if ((w <= SHDLC_MAX_WINDOW) &&
428*4a61cd66SEric Lapuyade 			    (SHDLC_SREJ_SUPPORT || (srej_support == false))) {
429*4a61cd66SEric Lapuyade 				shdlc->w = w;
430*4a61cd66SEric Lapuyade 				shdlc->srej_support = srej_support;
431*4a61cd66SEric Lapuyade 				r = llc_shdlc_connect_send_ua(shdlc);
432*4a61cd66SEric Lapuyade 				llc_shdlc_connect_complete(shdlc, r);
433*4a61cd66SEric Lapuyade 			}
434*4a61cd66SEric Lapuyade 		} else if (shdlc->state == SHDLC_CONNECTED) {
435*4a61cd66SEric Lapuyade 			/*
436*4a61cd66SEric Lapuyade 			 * Chip wants to reset link. This is unexpected and
437*4a61cd66SEric Lapuyade 			 * unsupported.
438*4a61cd66SEric Lapuyade 			 */
439*4a61cd66SEric Lapuyade 			shdlc->hard_fault = -ECONNRESET;
440*4a61cd66SEric Lapuyade 		}
441*4a61cd66SEric Lapuyade 		break;
442*4a61cd66SEric Lapuyade 	case U_FRAME_UA:
443*4a61cd66SEric Lapuyade 		if ((shdlc->state == SHDLC_CONNECTING &&
444*4a61cd66SEric Lapuyade 		     shdlc->connect_tries > 0) ||
445*4a61cd66SEric Lapuyade 		    (shdlc->state == SHDLC_NEGOCIATING))
446*4a61cd66SEric Lapuyade 			llc_shdlc_connect_complete(shdlc, 0);
447*4a61cd66SEric Lapuyade 		break;
448*4a61cd66SEric Lapuyade 	default:
449*4a61cd66SEric Lapuyade 		break;
450*4a61cd66SEric Lapuyade 	}
451*4a61cd66SEric Lapuyade 
452*4a61cd66SEric Lapuyade 	kfree_skb(skb);
453*4a61cd66SEric Lapuyade }
454*4a61cd66SEric Lapuyade 
455*4a61cd66SEric Lapuyade static void llc_shdlc_handle_rcv_queue(struct llc_shdlc *shdlc)
456*4a61cd66SEric Lapuyade {
457*4a61cd66SEric Lapuyade 	struct sk_buff *skb;
458*4a61cd66SEric Lapuyade 	u8 control;
459*4a61cd66SEric Lapuyade 	int nr;
460*4a61cd66SEric Lapuyade 	int ns;
461*4a61cd66SEric Lapuyade 	enum sframe_type s_frame_type;
462*4a61cd66SEric Lapuyade 	enum uframe_modifier u_frame_modifier;
463*4a61cd66SEric Lapuyade 
464*4a61cd66SEric Lapuyade 	if (shdlc->rcv_q.qlen)
465*4a61cd66SEric Lapuyade 		pr_debug("rcvQlen=%d\n", shdlc->rcv_q.qlen);
466*4a61cd66SEric Lapuyade 
467*4a61cd66SEric Lapuyade 	while ((skb = skb_dequeue(&shdlc->rcv_q)) != NULL) {
468*4a61cd66SEric Lapuyade 		control = skb->data[0];
469*4a61cd66SEric Lapuyade 		skb_pull(skb, 1);
470*4a61cd66SEric Lapuyade 		switch (control & SHDLC_CONTROL_HEAD_MASK) {
471*4a61cd66SEric Lapuyade 		case SHDLC_CONTROL_HEAD_I:
472*4a61cd66SEric Lapuyade 		case SHDLC_CONTROL_HEAD_I2:
473*4a61cd66SEric Lapuyade 			ns = (control & SHDLC_CONTROL_NS_MASK) >> 3;
474*4a61cd66SEric Lapuyade 			nr = control & SHDLC_CONTROL_NR_MASK;
475*4a61cd66SEric Lapuyade 			llc_shdlc_rcv_i_frame(shdlc, skb, ns, nr);
476*4a61cd66SEric Lapuyade 			break;
477*4a61cd66SEric Lapuyade 		case SHDLC_CONTROL_HEAD_S:
478*4a61cd66SEric Lapuyade 			s_frame_type = (control & SHDLC_CONTROL_TYPE_MASK) >> 3;
479*4a61cd66SEric Lapuyade 			nr = control & SHDLC_CONTROL_NR_MASK;
480*4a61cd66SEric Lapuyade 			llc_shdlc_rcv_s_frame(shdlc, s_frame_type, nr);
481*4a61cd66SEric Lapuyade 			kfree_skb(skb);
482*4a61cd66SEric Lapuyade 			break;
483*4a61cd66SEric Lapuyade 		case SHDLC_CONTROL_HEAD_U:
484*4a61cd66SEric Lapuyade 			u_frame_modifier = control & SHDLC_CONTROL_M_MASK;
485*4a61cd66SEric Lapuyade 			llc_shdlc_rcv_u_frame(shdlc, skb, u_frame_modifier);
486*4a61cd66SEric Lapuyade 			break;
487*4a61cd66SEric Lapuyade 		default:
488*4a61cd66SEric Lapuyade 			pr_err("UNKNOWN Control=%d\n", control);
489*4a61cd66SEric Lapuyade 			kfree_skb(skb);
490*4a61cd66SEric Lapuyade 			break;
491*4a61cd66SEric Lapuyade 		}
492*4a61cd66SEric Lapuyade 	}
493*4a61cd66SEric Lapuyade }
494*4a61cd66SEric Lapuyade 
495*4a61cd66SEric Lapuyade static int llc_shdlc_w_used(int ns, int dnr)
496*4a61cd66SEric Lapuyade {
497*4a61cd66SEric Lapuyade 	int unack_count;
498*4a61cd66SEric Lapuyade 
499*4a61cd66SEric Lapuyade 	if (dnr <= ns)
500*4a61cd66SEric Lapuyade 		unack_count = ns - dnr;
501*4a61cd66SEric Lapuyade 	else
502*4a61cd66SEric Lapuyade 		unack_count = 8 - dnr + ns;
503*4a61cd66SEric Lapuyade 
504*4a61cd66SEric Lapuyade 	return unack_count;
505*4a61cd66SEric Lapuyade }
506*4a61cd66SEric Lapuyade 
507*4a61cd66SEric Lapuyade /* Send frames according to algorithm at spec:10.8.1 */
508*4a61cd66SEric Lapuyade static void llc_shdlc_handle_send_queue(struct llc_shdlc *shdlc)
509*4a61cd66SEric Lapuyade {
510*4a61cd66SEric Lapuyade 	struct sk_buff *skb;
511*4a61cd66SEric Lapuyade 	int r;
512*4a61cd66SEric Lapuyade 	unsigned long time_sent;
513*4a61cd66SEric Lapuyade 
514*4a61cd66SEric Lapuyade 	if (shdlc->send_q.qlen)
515*4a61cd66SEric Lapuyade 		pr_debug
516*4a61cd66SEric Lapuyade 		    ("sendQlen=%d ns=%d dnr=%d rnr=%s w_room=%d unackQlen=%d\n",
517*4a61cd66SEric Lapuyade 		     shdlc->send_q.qlen, shdlc->ns, shdlc->dnr,
518*4a61cd66SEric Lapuyade 		     shdlc->rnr == false ? "false" : "true",
519*4a61cd66SEric Lapuyade 		     shdlc->w - llc_shdlc_w_used(shdlc->ns, shdlc->dnr),
520*4a61cd66SEric Lapuyade 		     shdlc->ack_pending_q.qlen);
521*4a61cd66SEric Lapuyade 
522*4a61cd66SEric Lapuyade 	while (shdlc->send_q.qlen && shdlc->ack_pending_q.qlen < shdlc->w &&
523*4a61cd66SEric Lapuyade 	       (shdlc->rnr == false)) {
524*4a61cd66SEric Lapuyade 
525*4a61cd66SEric Lapuyade 		if (shdlc->t1_active) {
526*4a61cd66SEric Lapuyade 			del_timer_sync(&shdlc->t1_timer);
527*4a61cd66SEric Lapuyade 			shdlc->t1_active = false;
528*4a61cd66SEric Lapuyade 			pr_debug("Stopped T1(send ack)\n");
529*4a61cd66SEric Lapuyade 		}
530*4a61cd66SEric Lapuyade 
531*4a61cd66SEric Lapuyade 		skb = skb_dequeue(&shdlc->send_q);
532*4a61cd66SEric Lapuyade 
533*4a61cd66SEric Lapuyade 		*skb_push(skb, 1) = SHDLC_CONTROL_HEAD_I | (shdlc->ns << 3) |
534*4a61cd66SEric Lapuyade 				    shdlc->nr;
535*4a61cd66SEric Lapuyade 
536*4a61cd66SEric Lapuyade 		pr_debug("Sending I-Frame %d, waiting to rcv %d\n", shdlc->ns,
537*4a61cd66SEric Lapuyade 			 shdlc->nr);
538*4a61cd66SEric Lapuyade 	/*	SHDLC_DUMP_SKB("shdlc frame written", skb); */
539*4a61cd66SEric Lapuyade 
540*4a61cd66SEric Lapuyade 		r = shdlc->xmit_to_drv(shdlc->hdev, skb);
541*4a61cd66SEric Lapuyade 		if (r < 0) {
542*4a61cd66SEric Lapuyade 			shdlc->hard_fault = r;
543*4a61cd66SEric Lapuyade 			break;
544*4a61cd66SEric Lapuyade 		}
545*4a61cd66SEric Lapuyade 
546*4a61cd66SEric Lapuyade 		shdlc->ns = (shdlc->ns + 1) % 8;
547*4a61cd66SEric Lapuyade 
548*4a61cd66SEric Lapuyade 		time_sent = jiffies;
549*4a61cd66SEric Lapuyade 		*(unsigned long *)skb->cb = time_sent;
550*4a61cd66SEric Lapuyade 
551*4a61cd66SEric Lapuyade 		skb_queue_tail(&shdlc->ack_pending_q, skb);
552*4a61cd66SEric Lapuyade 
553*4a61cd66SEric Lapuyade 		if (shdlc->t2_active == false) {
554*4a61cd66SEric Lapuyade 			shdlc->t2_active = true;
555*4a61cd66SEric Lapuyade 			mod_timer(&shdlc->t2_timer, time_sent +
556*4a61cd66SEric Lapuyade 				  msecs_to_jiffies(SHDLC_T2_VALUE_MS));
557*4a61cd66SEric Lapuyade 			pr_debug("Started T2 (retransmit)\n");
558*4a61cd66SEric Lapuyade 		}
559*4a61cd66SEric Lapuyade 	}
560*4a61cd66SEric Lapuyade }
561*4a61cd66SEric Lapuyade 
562*4a61cd66SEric Lapuyade static void llc_shdlc_connect_timeout(unsigned long data)
563*4a61cd66SEric Lapuyade {
564*4a61cd66SEric Lapuyade 	struct llc_shdlc *shdlc = (struct llc_shdlc *)data;
565*4a61cd66SEric Lapuyade 
566*4a61cd66SEric Lapuyade 	pr_debug("\n");
567*4a61cd66SEric Lapuyade 
568*4a61cd66SEric Lapuyade 	queue_work(system_nrt_wq, &shdlc->sm_work);
569*4a61cd66SEric Lapuyade }
570*4a61cd66SEric Lapuyade 
571*4a61cd66SEric Lapuyade static void llc_shdlc_t1_timeout(unsigned long data)
572*4a61cd66SEric Lapuyade {
573*4a61cd66SEric Lapuyade 	struct llc_shdlc *shdlc = (struct llc_shdlc *)data;
574*4a61cd66SEric Lapuyade 
575*4a61cd66SEric Lapuyade 	pr_debug("SoftIRQ: need to send ack\n");
576*4a61cd66SEric Lapuyade 
577*4a61cd66SEric Lapuyade 	queue_work(system_nrt_wq, &shdlc->sm_work);
578*4a61cd66SEric Lapuyade }
579*4a61cd66SEric Lapuyade 
580*4a61cd66SEric Lapuyade static void llc_shdlc_t2_timeout(unsigned long data)
581*4a61cd66SEric Lapuyade {
582*4a61cd66SEric Lapuyade 	struct llc_shdlc *shdlc = (struct llc_shdlc *)data;
583*4a61cd66SEric Lapuyade 
584*4a61cd66SEric Lapuyade 	pr_debug("SoftIRQ: need to retransmit\n");
585*4a61cd66SEric Lapuyade 
586*4a61cd66SEric Lapuyade 	queue_work(system_nrt_wq, &shdlc->sm_work);
587*4a61cd66SEric Lapuyade }
588*4a61cd66SEric Lapuyade 
589*4a61cd66SEric Lapuyade static void llc_shdlc_sm_work(struct work_struct *work)
590*4a61cd66SEric Lapuyade {
591*4a61cd66SEric Lapuyade 	struct llc_shdlc *shdlc = container_of(work, struct llc_shdlc, sm_work);
592*4a61cd66SEric Lapuyade 	int r;
593*4a61cd66SEric Lapuyade 
594*4a61cd66SEric Lapuyade 	pr_debug("\n");
595*4a61cd66SEric Lapuyade 
596*4a61cd66SEric Lapuyade 	mutex_lock(&shdlc->state_mutex);
597*4a61cd66SEric Lapuyade 
598*4a61cd66SEric Lapuyade 	switch (shdlc->state) {
599*4a61cd66SEric Lapuyade 	case SHDLC_DISCONNECTED:
600*4a61cd66SEric Lapuyade 		skb_queue_purge(&shdlc->rcv_q);
601*4a61cd66SEric Lapuyade 		skb_queue_purge(&shdlc->send_q);
602*4a61cd66SEric Lapuyade 		skb_queue_purge(&shdlc->ack_pending_q);
603*4a61cd66SEric Lapuyade 		break;
604*4a61cd66SEric Lapuyade 	case SHDLC_CONNECTING:
605*4a61cd66SEric Lapuyade 		if (shdlc->hard_fault) {
606*4a61cd66SEric Lapuyade 			llc_shdlc_connect_complete(shdlc, shdlc->hard_fault);
607*4a61cd66SEric Lapuyade 			break;
608*4a61cd66SEric Lapuyade 		}
609*4a61cd66SEric Lapuyade 
610*4a61cd66SEric Lapuyade 		if (shdlc->connect_tries++ < 5)
611*4a61cd66SEric Lapuyade 			r = llc_shdlc_connect_initiate(shdlc);
612*4a61cd66SEric Lapuyade 		else
613*4a61cd66SEric Lapuyade 			r = -ETIME;
614*4a61cd66SEric Lapuyade 		if (r < 0)
615*4a61cd66SEric Lapuyade 			llc_shdlc_connect_complete(shdlc, r);
616*4a61cd66SEric Lapuyade 		else {
617*4a61cd66SEric Lapuyade 			mod_timer(&shdlc->connect_timer, jiffies +
618*4a61cd66SEric Lapuyade 				  msecs_to_jiffies(SHDLC_CONNECT_VALUE_MS));
619*4a61cd66SEric Lapuyade 
620*4a61cd66SEric Lapuyade 			shdlc->state = SHDLC_NEGOCIATING;
621*4a61cd66SEric Lapuyade 		}
622*4a61cd66SEric Lapuyade 		break;
623*4a61cd66SEric Lapuyade 	case SHDLC_NEGOCIATING:
624*4a61cd66SEric Lapuyade 		if (timer_pending(&shdlc->connect_timer) == 0) {
625*4a61cd66SEric Lapuyade 			shdlc->state = SHDLC_CONNECTING;
626*4a61cd66SEric Lapuyade 			queue_work(system_nrt_wq, &shdlc->sm_work);
627*4a61cd66SEric Lapuyade 		}
628*4a61cd66SEric Lapuyade 
629*4a61cd66SEric Lapuyade 		llc_shdlc_handle_rcv_queue(shdlc);
630*4a61cd66SEric Lapuyade 
631*4a61cd66SEric Lapuyade 		if (shdlc->hard_fault) {
632*4a61cd66SEric Lapuyade 			llc_shdlc_connect_complete(shdlc, shdlc->hard_fault);
633*4a61cd66SEric Lapuyade 			break;
634*4a61cd66SEric Lapuyade 		}
635*4a61cd66SEric Lapuyade 		break;
636*4a61cd66SEric Lapuyade 	case SHDLC_CONNECTED:
637*4a61cd66SEric Lapuyade 		llc_shdlc_handle_rcv_queue(shdlc);
638*4a61cd66SEric Lapuyade 		llc_shdlc_handle_send_queue(shdlc);
639*4a61cd66SEric Lapuyade 
640*4a61cd66SEric Lapuyade 		if (shdlc->t1_active && timer_pending(&shdlc->t1_timer) == 0) {
641*4a61cd66SEric Lapuyade 			pr_debug
642*4a61cd66SEric Lapuyade 			    ("Handle T1(send ack) elapsed (T1 now inactive)\n");
643*4a61cd66SEric Lapuyade 
644*4a61cd66SEric Lapuyade 			shdlc->t1_active = false;
645*4a61cd66SEric Lapuyade 			r = llc_shdlc_send_s_frame(shdlc, S_FRAME_RR,
646*4a61cd66SEric Lapuyade 						   shdlc->nr);
647*4a61cd66SEric Lapuyade 			if (r < 0)
648*4a61cd66SEric Lapuyade 				shdlc->hard_fault = r;
649*4a61cd66SEric Lapuyade 		}
650*4a61cd66SEric Lapuyade 
651*4a61cd66SEric Lapuyade 		if (shdlc->t2_active && timer_pending(&shdlc->t2_timer) == 0) {
652*4a61cd66SEric Lapuyade 			pr_debug
653*4a61cd66SEric Lapuyade 			    ("Handle T2(retransmit) elapsed (T2 inactive)\n");
654*4a61cd66SEric Lapuyade 
655*4a61cd66SEric Lapuyade 			shdlc->t2_active = false;
656*4a61cd66SEric Lapuyade 
657*4a61cd66SEric Lapuyade 			llc_shdlc_requeue_ack_pending(shdlc);
658*4a61cd66SEric Lapuyade 			llc_shdlc_handle_send_queue(shdlc);
659*4a61cd66SEric Lapuyade 		}
660*4a61cd66SEric Lapuyade 
661*4a61cd66SEric Lapuyade 		if (shdlc->hard_fault) {
662*4a61cd66SEric Lapuyade 			shdlc->llc_failure(shdlc->hdev, shdlc->hard_fault);
663*4a61cd66SEric Lapuyade 		}
664*4a61cd66SEric Lapuyade 		break;
665*4a61cd66SEric Lapuyade 	default:
666*4a61cd66SEric Lapuyade 		break;
667*4a61cd66SEric Lapuyade 	}
668*4a61cd66SEric Lapuyade 	mutex_unlock(&shdlc->state_mutex);
669*4a61cd66SEric Lapuyade }
670*4a61cd66SEric Lapuyade 
671*4a61cd66SEric Lapuyade /*
672*4a61cd66SEric Lapuyade  * Called from syscall context to establish shdlc link. Sleeps until
673*4a61cd66SEric Lapuyade  * link is ready or failure.
674*4a61cd66SEric Lapuyade  */
675*4a61cd66SEric Lapuyade static int llc_shdlc_connect(struct llc_shdlc *shdlc)
676*4a61cd66SEric Lapuyade {
677*4a61cd66SEric Lapuyade 	DECLARE_WAIT_QUEUE_HEAD_ONSTACK(connect_wq);
678*4a61cd66SEric Lapuyade 
679*4a61cd66SEric Lapuyade 	pr_debug("\n");
680*4a61cd66SEric Lapuyade 
681*4a61cd66SEric Lapuyade 	mutex_lock(&shdlc->state_mutex);
682*4a61cd66SEric Lapuyade 
683*4a61cd66SEric Lapuyade 	shdlc->state = SHDLC_CONNECTING;
684*4a61cd66SEric Lapuyade 	shdlc->connect_wq = &connect_wq;
685*4a61cd66SEric Lapuyade 	shdlc->connect_tries = 0;
686*4a61cd66SEric Lapuyade 	shdlc->connect_result = 1;
687*4a61cd66SEric Lapuyade 
688*4a61cd66SEric Lapuyade 	mutex_unlock(&shdlc->state_mutex);
689*4a61cd66SEric Lapuyade 
690*4a61cd66SEric Lapuyade 	queue_work(system_nrt_wq, &shdlc->sm_work);
691*4a61cd66SEric Lapuyade 
692*4a61cd66SEric Lapuyade 	wait_event(connect_wq, shdlc->connect_result != 1);
693*4a61cd66SEric Lapuyade 
694*4a61cd66SEric Lapuyade 	return shdlc->connect_result;
695*4a61cd66SEric Lapuyade }
696*4a61cd66SEric Lapuyade 
697*4a61cd66SEric Lapuyade static void llc_shdlc_disconnect(struct llc_shdlc *shdlc)
698*4a61cd66SEric Lapuyade {
699*4a61cd66SEric Lapuyade 	pr_debug("\n");
700*4a61cd66SEric Lapuyade 
701*4a61cd66SEric Lapuyade 	mutex_lock(&shdlc->state_mutex);
702*4a61cd66SEric Lapuyade 
703*4a61cd66SEric Lapuyade 	shdlc->state = SHDLC_DISCONNECTED;
704*4a61cd66SEric Lapuyade 
705*4a61cd66SEric Lapuyade 	mutex_unlock(&shdlc->state_mutex);
706*4a61cd66SEric Lapuyade 
707*4a61cd66SEric Lapuyade 	queue_work(system_nrt_wq, &shdlc->sm_work);
708*4a61cd66SEric Lapuyade }
709*4a61cd66SEric Lapuyade 
710*4a61cd66SEric Lapuyade /*
711*4a61cd66SEric Lapuyade  * Receive an incoming shdlc frame. Frame has already been crc-validated.
712*4a61cd66SEric Lapuyade  * skb contains only LLC header and payload.
713*4a61cd66SEric Lapuyade  * If skb == NULL, it is a notification that the link below is dead.
714*4a61cd66SEric Lapuyade  */
715*4a61cd66SEric Lapuyade static void llc_shdlc_recv_frame(struct llc_shdlc *shdlc, struct sk_buff *skb)
716*4a61cd66SEric Lapuyade {
717*4a61cd66SEric Lapuyade 	if (skb == NULL) {
718*4a61cd66SEric Lapuyade 		pr_err("NULL Frame -> link is dead\n");
719*4a61cd66SEric Lapuyade 		shdlc->hard_fault = -EREMOTEIO;
720*4a61cd66SEric Lapuyade 	} else {
721*4a61cd66SEric Lapuyade 		SHDLC_DUMP_SKB("incoming frame", skb);
722*4a61cd66SEric Lapuyade 		skb_queue_tail(&shdlc->rcv_q, skb);
723*4a61cd66SEric Lapuyade 	}
724*4a61cd66SEric Lapuyade 
725*4a61cd66SEric Lapuyade 	queue_work(system_nrt_wq, &shdlc->sm_work);
726*4a61cd66SEric Lapuyade }
727*4a61cd66SEric Lapuyade 
728*4a61cd66SEric Lapuyade static void *llc_shdlc_init(struct nfc_hci_dev *hdev, xmit_to_drv_t xmit_to_drv,
729*4a61cd66SEric Lapuyade 			    rcv_to_hci_t rcv_to_hci, int tx_headroom,
730*4a61cd66SEric Lapuyade 			    int tx_tailroom, int *rx_headroom, int *rx_tailroom,
731*4a61cd66SEric Lapuyade 			    llc_failure_t llc_failure)
732*4a61cd66SEric Lapuyade {
733*4a61cd66SEric Lapuyade 	struct llc_shdlc *shdlc;
734*4a61cd66SEric Lapuyade 
735*4a61cd66SEric Lapuyade 	*rx_headroom = SHDLC_LLC_HEAD_ROOM;
736*4a61cd66SEric Lapuyade 	*rx_tailroom = 0;
737*4a61cd66SEric Lapuyade 
738*4a61cd66SEric Lapuyade 	shdlc = kzalloc(sizeof(struct llc_shdlc), GFP_KERNEL);
739*4a61cd66SEric Lapuyade 	if (shdlc == NULL)
740*4a61cd66SEric Lapuyade 		return NULL;
741*4a61cd66SEric Lapuyade 
742*4a61cd66SEric Lapuyade 	mutex_init(&shdlc->state_mutex);
743*4a61cd66SEric Lapuyade 	shdlc->state = SHDLC_DISCONNECTED;
744*4a61cd66SEric Lapuyade 
745*4a61cd66SEric Lapuyade 	init_timer(&shdlc->connect_timer);
746*4a61cd66SEric Lapuyade 	shdlc->connect_timer.data = (unsigned long)shdlc;
747*4a61cd66SEric Lapuyade 	shdlc->connect_timer.function = llc_shdlc_connect_timeout;
748*4a61cd66SEric Lapuyade 
749*4a61cd66SEric Lapuyade 	init_timer(&shdlc->t1_timer);
750*4a61cd66SEric Lapuyade 	shdlc->t1_timer.data = (unsigned long)shdlc;
751*4a61cd66SEric Lapuyade 	shdlc->t1_timer.function = llc_shdlc_t1_timeout;
752*4a61cd66SEric Lapuyade 
753*4a61cd66SEric Lapuyade 	init_timer(&shdlc->t2_timer);
754*4a61cd66SEric Lapuyade 	shdlc->t2_timer.data = (unsigned long)shdlc;
755*4a61cd66SEric Lapuyade 	shdlc->t2_timer.function = llc_shdlc_t2_timeout;
756*4a61cd66SEric Lapuyade 
757*4a61cd66SEric Lapuyade 	shdlc->w = SHDLC_MAX_WINDOW;
758*4a61cd66SEric Lapuyade 	shdlc->srej_support = SHDLC_SREJ_SUPPORT;
759*4a61cd66SEric Lapuyade 
760*4a61cd66SEric Lapuyade 	skb_queue_head_init(&shdlc->rcv_q);
761*4a61cd66SEric Lapuyade 	skb_queue_head_init(&shdlc->send_q);
762*4a61cd66SEric Lapuyade 	skb_queue_head_init(&shdlc->ack_pending_q);
763*4a61cd66SEric Lapuyade 
764*4a61cd66SEric Lapuyade 	INIT_WORK(&shdlc->sm_work, llc_shdlc_sm_work);
765*4a61cd66SEric Lapuyade 
766*4a61cd66SEric Lapuyade 	shdlc->hdev = hdev;
767*4a61cd66SEric Lapuyade 	shdlc->xmit_to_drv = xmit_to_drv;
768*4a61cd66SEric Lapuyade 	shdlc->rcv_to_hci = rcv_to_hci;
769*4a61cd66SEric Lapuyade 	shdlc->tx_headroom = tx_headroom;
770*4a61cd66SEric Lapuyade 	shdlc->tx_tailroom = tx_tailroom;
771*4a61cd66SEric Lapuyade 	shdlc->llc_failure = llc_failure;
772*4a61cd66SEric Lapuyade 
773*4a61cd66SEric Lapuyade 	return shdlc;
774*4a61cd66SEric Lapuyade }
775*4a61cd66SEric Lapuyade 
776*4a61cd66SEric Lapuyade static void llc_shdlc_deinit(struct nfc_llc *llc)
777*4a61cd66SEric Lapuyade {
778*4a61cd66SEric Lapuyade 	struct llc_shdlc *shdlc = nfc_llc_get_data(llc);
779*4a61cd66SEric Lapuyade 
780*4a61cd66SEric Lapuyade 	skb_queue_purge(&shdlc->rcv_q);
781*4a61cd66SEric Lapuyade 	skb_queue_purge(&shdlc->send_q);
782*4a61cd66SEric Lapuyade 	skb_queue_purge(&shdlc->ack_pending_q);
783*4a61cd66SEric Lapuyade 
784*4a61cd66SEric Lapuyade 	kfree(shdlc);
785*4a61cd66SEric Lapuyade }
786*4a61cd66SEric Lapuyade 
787*4a61cd66SEric Lapuyade static int llc_shdlc_start(struct nfc_llc *llc)
788*4a61cd66SEric Lapuyade {
789*4a61cd66SEric Lapuyade 	struct llc_shdlc *shdlc = nfc_llc_get_data(llc);
790*4a61cd66SEric Lapuyade 
791*4a61cd66SEric Lapuyade 	return llc_shdlc_connect(shdlc);
792*4a61cd66SEric Lapuyade }
793*4a61cd66SEric Lapuyade 
794*4a61cd66SEric Lapuyade static int llc_shdlc_stop(struct nfc_llc *llc)
795*4a61cd66SEric Lapuyade {
796*4a61cd66SEric Lapuyade 	struct llc_shdlc *shdlc = nfc_llc_get_data(llc);
797*4a61cd66SEric Lapuyade 
798*4a61cd66SEric Lapuyade 	llc_shdlc_disconnect(shdlc);
799*4a61cd66SEric Lapuyade 
800*4a61cd66SEric Lapuyade 	return 0;
801*4a61cd66SEric Lapuyade }
802*4a61cd66SEric Lapuyade 
803*4a61cd66SEric Lapuyade static void llc_shdlc_rcv_from_drv(struct nfc_llc *llc, struct sk_buff *skb)
804*4a61cd66SEric Lapuyade {
805*4a61cd66SEric Lapuyade 	struct llc_shdlc *shdlc = nfc_llc_get_data(llc);
806*4a61cd66SEric Lapuyade 
807*4a61cd66SEric Lapuyade 	llc_shdlc_recv_frame(shdlc, skb);
808*4a61cd66SEric Lapuyade }
809*4a61cd66SEric Lapuyade 
810*4a61cd66SEric Lapuyade static int llc_shdlc_xmit_from_hci(struct nfc_llc *llc, struct sk_buff *skb)
811*4a61cd66SEric Lapuyade {
812*4a61cd66SEric Lapuyade 	struct llc_shdlc *shdlc = nfc_llc_get_data(llc);
813*4a61cd66SEric Lapuyade 
814*4a61cd66SEric Lapuyade 	skb_queue_tail(&shdlc->send_q, skb);
815*4a61cd66SEric Lapuyade 
816*4a61cd66SEric Lapuyade 	queue_work(system_nrt_wq, &shdlc->sm_work);
817*4a61cd66SEric Lapuyade 
818*4a61cd66SEric Lapuyade 	return 0;
819*4a61cd66SEric Lapuyade }
820*4a61cd66SEric Lapuyade 
821*4a61cd66SEric Lapuyade static struct nfc_llc_ops llc_shdlc_ops = {
822*4a61cd66SEric Lapuyade 	.init = llc_shdlc_init,
823*4a61cd66SEric Lapuyade 	.deinit = llc_shdlc_deinit,
824*4a61cd66SEric Lapuyade 	.start = llc_shdlc_start,
825*4a61cd66SEric Lapuyade 	.stop = llc_shdlc_stop,
826*4a61cd66SEric Lapuyade 	.rcv_from_drv = llc_shdlc_rcv_from_drv,
827*4a61cd66SEric Lapuyade 	.xmit_from_hci = llc_shdlc_xmit_from_hci,
828*4a61cd66SEric Lapuyade };
829*4a61cd66SEric Lapuyade 
830*4a61cd66SEric Lapuyade int nfc_llc_shdlc_register()
831*4a61cd66SEric Lapuyade {
832*4a61cd66SEric Lapuyade 	return nfc_llc_register(LLC_SHDLC_NAME, &llc_shdlc_ops);
833*4a61cd66SEric Lapuyade }
834*4a61cd66SEric Lapuyade EXPORT_SYMBOL(nfc_llc_shdlc_register);
835