aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorWaldemar Rymarkiewicz <waldemar.rymarkiewicz@tieto.com>2012-09-21 08:02:46 -0400
committerSamuel Ortiz <sameo@linux.intel.com>2012-09-24 18:17:27 -0400
commit12bfd1e8906637757a0bc42970f0fc11a9918019 (patch)
treebd72d458f4083227ed0fd237fcfed30d06ab866a /net
parent9010e39f508ee57dc9a7675073659cb9d019a802 (diff)
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>
Diffstat (limited to 'net')
-rw-r--r--net/nfc/hci/llc_shdlc.c38
1 files changed, 31 insertions, 7 deletions
diff --git a/net/nfc/hci/llc_shdlc.c b/net/nfc/hci/llc_shdlc.c
index a7931c7c57f2..3afde1ecd925 100644
--- a/net/nfc/hci/llc_shdlc.c
+++ b/net/nfc/hci/llc_shdlc.c
@@ -32,7 +32,8 @@ enum shdlc_state {
32 SHDLC_DISCONNECTED = 0, 32 SHDLC_DISCONNECTED = 0,
33 SHDLC_CONNECTING = 1, 33 SHDLC_CONNECTING = 1,
34 SHDLC_NEGOCIATING = 2, 34 SHDLC_NEGOCIATING = 2,
35 SHDLC_CONNECTED = 3 35 SHDLC_HALF_CONNECTED = 3,
36 SHDLC_CONNECTED = 4
36}; 37};
37 38
38struct llc_shdlc { 39struct llc_shdlc {
@@ -363,7 +364,7 @@ static void llc_shdlc_connect_complete(struct llc_shdlc *shdlc, int r)
363 shdlc->nr = 0; 364 shdlc->nr = 0;
364 shdlc->dnr = 0; 365 shdlc->dnr = 0;
365 366
366 shdlc->state = SHDLC_CONNECTED; 367 shdlc->state = SHDLC_HALF_CONNECTED;
367 } else { 368 } else {
368 shdlc->state = SHDLC_DISCONNECTED; 369 shdlc->state = SHDLC_DISCONNECTED;
369 } 370 }
@@ -414,9 +415,13 @@ static void llc_shdlc_rcv_u_frame(struct llc_shdlc *shdlc,
414 415
415 switch (u_frame_modifier) { 416 switch (u_frame_modifier) {
416 case U_FRAME_RSET: 417 case U_FRAME_RSET:
417 if ((shdlc->state == SHDLC_NEGOCIATING) || 418 switch (shdlc->state) {
418 (shdlc->state == SHDLC_CONNECTING)) { 419 case SHDLC_NEGOCIATING:
419 /* we sent RSET, but chip wants to negociate */ 420 case SHDLC_CONNECTING:
421 /*
422 * We sent RSET, but chip wants to negociate or we
423 * got RSET before we managed to send out our.
424 */
420 if (skb->len > 0) 425 if (skb->len > 0)
421 w = skb->data[0]; 426 w = skb->data[0];
422 427
@@ -431,19 +436,31 @@ static void llc_shdlc_rcv_u_frame(struct llc_shdlc *shdlc,
431 r = llc_shdlc_connect_send_ua(shdlc); 436 r = llc_shdlc_connect_send_ua(shdlc);
432 llc_shdlc_connect_complete(shdlc, r); 437 llc_shdlc_connect_complete(shdlc, r);
433 } 438 }
434 } else if (shdlc->state == SHDLC_CONNECTED) { 439 break;
440 case SHDLC_HALF_CONNECTED:
441 /*
442 * Chip resent RSET due to its timeout - Ignote it
443 * as we already sent UA.
444 */
445 break;
446 case SHDLC_CONNECTED:
435 /* 447 /*
436 * Chip wants to reset link. This is unexpected and 448 * Chip wants to reset link. This is unexpected and
437 * unsupported. 449 * unsupported.
438 */ 450 */
439 shdlc->hard_fault = -ECONNRESET; 451 shdlc->hard_fault = -ECONNRESET;
452 break;
453 default:
454 break;
440 } 455 }
441 break; 456 break;
442 case U_FRAME_UA: 457 case U_FRAME_UA:
443 if ((shdlc->state == SHDLC_CONNECTING && 458 if ((shdlc->state == SHDLC_CONNECTING &&
444 shdlc->connect_tries > 0) || 459 shdlc->connect_tries > 0) ||
445 (shdlc->state == SHDLC_NEGOCIATING)) 460 (shdlc->state == SHDLC_NEGOCIATING)) {
446 llc_shdlc_connect_complete(shdlc, 0); 461 llc_shdlc_connect_complete(shdlc, 0);
462 shdlc->state = SHDLC_CONNECTED;
463 }
447 break; 464 break;
448 default: 465 default:
449 break; 466 break;
@@ -470,11 +487,17 @@ static void llc_shdlc_handle_rcv_queue(struct llc_shdlc *shdlc)
470 switch (control & SHDLC_CONTROL_HEAD_MASK) { 487 switch (control & SHDLC_CONTROL_HEAD_MASK) {
471 case SHDLC_CONTROL_HEAD_I: 488 case SHDLC_CONTROL_HEAD_I:
472 case SHDLC_CONTROL_HEAD_I2: 489 case SHDLC_CONTROL_HEAD_I2:
490 if (shdlc->state == SHDLC_HALF_CONNECTED)
491 shdlc->state = SHDLC_CONNECTED;
492
473 ns = (control & SHDLC_CONTROL_NS_MASK) >> 3; 493 ns = (control & SHDLC_CONTROL_NS_MASK) >> 3;
474 nr = control & SHDLC_CONTROL_NR_MASK; 494 nr = control & SHDLC_CONTROL_NR_MASK;
475 llc_shdlc_rcv_i_frame(shdlc, skb, ns, nr); 495 llc_shdlc_rcv_i_frame(shdlc, skb, ns, nr);
476 break; 496 break;
477 case SHDLC_CONTROL_HEAD_S: 497 case SHDLC_CONTROL_HEAD_S:
498 if (shdlc->state == SHDLC_HALF_CONNECTED)
499 shdlc->state = SHDLC_CONNECTED;
500
478 s_frame_type = (control & SHDLC_CONTROL_TYPE_MASK) >> 3; 501 s_frame_type = (control & SHDLC_CONTROL_TYPE_MASK) >> 3;
479 nr = control & SHDLC_CONTROL_NR_MASK; 502 nr = control & SHDLC_CONTROL_NR_MASK;
480 llc_shdlc_rcv_s_frame(shdlc, s_frame_type, nr); 503 llc_shdlc_rcv_s_frame(shdlc, s_frame_type, nr);
@@ -633,6 +656,7 @@ static void llc_shdlc_sm_work(struct work_struct *work)
633 break; 656 break;
634 } 657 }
635 break; 658 break;
659 case SHDLC_HALF_CONNECTED:
636 case SHDLC_CONNECTED: 660 case SHDLC_CONNECTED:
637 llc_shdlc_handle_rcv_queue(shdlc); 661 llc_shdlc_handle_rcv_queue(shdlc);
638 llc_shdlc_handle_send_queue(shdlc); 662 llc_shdlc_handle_send_queue(shdlc);