diff options
Diffstat (limited to 'net/nfc/hci/llc_shdlc.c')
-rw-r--r-- | net/nfc/hci/llc_shdlc.c | 38 |
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 | ||
38 | struct llc_shdlc { | 39 | struct 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); |