Commit 12bfd1e8 authored by Waldemar Rymarkiewicz's avatar Waldemar Rymarkiewicz Committed by Samuel Ortiz

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: default avatarWaldemar Rymarkiewicz <waldemar.rymarkiewicz@tieto.com>
Signed-off-by: default avatarSamuel Ortiz <sameo@linux.intel.com>
parent 9010e39f
......@@ -32,7 +32,8 @@ enum shdlc_state {
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 @@ static void llc_shdlc_connect_complete(struct llc_shdlc *shdlc, int r)
shdlc->nr = 0;
shdlc->dnr = 0;
shdlc->state = SHDLC_CONNECTED;
shdlc->state = SHDLC_HALF_CONNECTED;
} else {
shdlc->state = SHDLC_DISCONNECTED;
}
......@@ -414,9 +415,13 @@ static void llc_shdlc_rcv_u_frame(struct llc_shdlc *shdlc,
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 @@ static void llc_shdlc_rcv_u_frame(struct llc_shdlc *shdlc,
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 @@ static void llc_shdlc_handle_rcv_queue(struct llc_shdlc *shdlc)
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 @@ static void llc_shdlc_sm_work(struct work_struct *work)
break;
}
break;
case SHDLC_HALF_CONNECTED:
case SHDLC_CONNECTED:
llc_shdlc_handle_rcv_queue(shdlc);
llc_shdlc_handle_send_queue(shdlc);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment