aboutsummaryrefslogtreecommitdiffstats
path: root/net/nfc/hci/llc_shdlc.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/nfc/hci/llc_shdlc.c')
-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);