NFC: Don't handle consequent RSET frames after UA

During processing incoming RSET frame chip, possibly due to
its internal timout, can retrnasmit an another RSET which
is next queued for processing in shdlc layer.

In case when we accept processed RSET skip those remaining on
the rcv queue until chip will send it's first S or I frame.
This will mean the chip completed connection as well.

Signed-off-by: Waldemar Rymarkiewicz <waldemar.rymarkiewicz@tieto.com>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
diff --git a/net/nfc/hci/llc_shdlc.c b/net/nfc/hci/llc_shdlc.c
index a7931c7..3afde1e 100644
--- a/net/nfc/hci/llc_shdlc.c
+++ b/net/nfc/hci/llc_shdlc.c
@@ -32,7 +32,8 @@
 	SHDLC_DISCONNECTED = 0,
 	SHDLC_CONNECTING = 1,
 	SHDLC_NEGOCIATING = 2,
-	SHDLC_CONNECTED = 3
+	SHDLC_HALF_CONNECTED = 3,
+	SHDLC_CONNECTED = 4
 };
 
 struct llc_shdlc {
@@ -363,7 +364,7 @@
 		shdlc->nr = 0;
 		shdlc->dnr = 0;
 
-		shdlc->state = SHDLC_CONNECTED;
+		shdlc->state = SHDLC_HALF_CONNECTED;
 	} else {
 		shdlc->state = SHDLC_DISCONNECTED;
 	}
@@ -414,9 +415,13 @@
 
 	switch (u_frame_modifier) {
 	case U_FRAME_RSET:
-		if ((shdlc->state == SHDLC_NEGOCIATING) ||
-					(shdlc->state == SHDLC_CONNECTING)) {
-			/* we sent RSET, but chip wants to negociate */
+		switch (shdlc->state) {
+		case SHDLC_NEGOCIATING:
+		case SHDLC_CONNECTING:
+			/*
+			 * We sent RSET, but chip wants to negociate or we
+			 * got RSET before we managed to send out our.
+			 */
 			if (skb->len > 0)
 				w = skb->data[0];
 
@@ -431,19 +436,31 @@
 				r = llc_shdlc_connect_send_ua(shdlc);
 				llc_shdlc_connect_complete(shdlc, r);
 			}
-		} else if (shdlc->state == SHDLC_CONNECTED) {
+			break;
+		case SHDLC_HALF_CONNECTED:
+			/*
+			 * Chip resent RSET due to its timeout - Ignote it
+			 * as we already sent UA.
+			 */
+			break;
+		case SHDLC_CONNECTED:
 			/*
 			 * Chip wants to reset link. This is unexpected and
 			 * unsupported.
 			 */
 			shdlc->hard_fault = -ECONNRESET;
+			break;
+		default:
+			break;
 		}
 		break;
 	case U_FRAME_UA:
 		if ((shdlc->state == SHDLC_CONNECTING &&
 		     shdlc->connect_tries > 0) ||
-		    (shdlc->state == SHDLC_NEGOCIATING))
+		    (shdlc->state == SHDLC_NEGOCIATING)) {
 			llc_shdlc_connect_complete(shdlc, 0);
+			shdlc->state = SHDLC_CONNECTED;
+		}
 		break;
 	default:
 		break;
@@ -470,11 +487,17 @@
 		switch (control & SHDLC_CONTROL_HEAD_MASK) {
 		case SHDLC_CONTROL_HEAD_I:
 		case SHDLC_CONTROL_HEAD_I2:
+			if (shdlc->state == SHDLC_HALF_CONNECTED)
+				shdlc->state = SHDLC_CONNECTED;
+
 			ns = (control & SHDLC_CONTROL_NS_MASK) >> 3;
 			nr = control & SHDLC_CONTROL_NR_MASK;
 			llc_shdlc_rcv_i_frame(shdlc, skb, ns, nr);
 			break;
 		case SHDLC_CONTROL_HEAD_S:
+			if (shdlc->state == SHDLC_HALF_CONNECTED)
+				shdlc->state = SHDLC_CONNECTED;
+
 			s_frame_type = (control & SHDLC_CONTROL_TYPE_MASK) >> 3;
 			nr = control & SHDLC_CONTROL_NR_MASK;
 			llc_shdlc_rcv_s_frame(shdlc, s_frame_type, nr);
@@ -633,6 +656,7 @@
 			break;
 		}
 		break;
+	case SHDLC_HALF_CONNECTED:
 	case SHDLC_CONNECTED:
 		llc_shdlc_handle_rcv_queue(shdlc);
 		llc_shdlc_handle_send_queue(shdlc);