diff options
author | Samuel Ortiz <sameo@linux.intel.com> | 2012-05-30 11:48:29 -0400 |
---|---|---|
committer | Samuel Ortiz <sameo@linux.intel.com> | 2012-06-04 15:34:33 -0400 |
commit | 844579603889ef1ab1fdbf2223579d6842e62bfe (patch) | |
tree | 92abc58fa1d7ffbed6b1026ea599f0cf28bb2417 /net | |
parent | 6fbbdc16be3881aabaa4096c3466b9bbd361bd1f (diff) |
NFC: Requeue lost LLCP frames
When receiving an I or RR frame telling us that some of the pending queues
were not received, we should requeue them before the currently pending ones.
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Diffstat (limited to 'net')
-rw-r--r-- | net/nfc/llcp/llcp.c | 86 |
1 files changed, 55 insertions, 31 deletions
diff --git a/net/nfc/llcp/llcp.c b/net/nfc/llcp/llcp.c index b694313c2be5..0fc60da6a0a1 100644 --- a/net/nfc/llcp/llcp.c +++ b/net/nfc/llcp/llcp.c | |||
@@ -411,28 +411,6 @@ int nfc_llcp_set_remote_gb(struct nfc_dev *dev, u8 *gb, u8 gb_len) | |||
411 | local->remote_gb_len - 3); | 411 | local->remote_gb_len - 3); |
412 | } | 412 | } |
413 | 413 | ||
414 | static void nfc_llcp_tx_work(struct work_struct *work) | ||
415 | { | ||
416 | struct nfc_llcp_local *local = container_of(work, struct nfc_llcp_local, | ||
417 | tx_work); | ||
418 | struct sk_buff *skb; | ||
419 | |||
420 | skb = skb_dequeue(&local->tx_queue); | ||
421 | if (skb != NULL) { | ||
422 | pr_debug("Sending pending skb\n"); | ||
423 | print_hex_dump(KERN_DEBUG, "LLCP Tx: ", DUMP_PREFIX_OFFSET, | ||
424 | 16, 1, skb->data, skb->len, true); | ||
425 | |||
426 | nfc_data_exchange(local->dev, local->target_idx, | ||
427 | skb, nfc_llcp_recv, local); | ||
428 | } else { | ||
429 | nfc_llcp_send_symm(local->dev); | ||
430 | } | ||
431 | |||
432 | mod_timer(&local->link_timer, | ||
433 | jiffies + msecs_to_jiffies(local->remote_lto)); | ||
434 | } | ||
435 | |||
436 | static u8 nfc_llcp_dsap(struct sk_buff *pdu) | 414 | static u8 nfc_llcp_dsap(struct sk_buff *pdu) |
437 | { | 415 | { |
438 | return (pdu->data[0] & 0xfc) >> 2; | 416 | return (pdu->data[0] & 0xfc) >> 2; |
@@ -465,6 +443,45 @@ static void nfc_llcp_set_nrns(struct nfc_llcp_sock *sock, struct sk_buff *pdu) | |||
465 | sock->recv_ack_n = (sock->recv_n - 1) % 16; | 443 | sock->recv_ack_n = (sock->recv_n - 1) % 16; |
466 | } | 444 | } |
467 | 445 | ||
446 | static void nfc_llcp_tx_work(struct work_struct *work) | ||
447 | { | ||
448 | struct nfc_llcp_local *local = container_of(work, struct nfc_llcp_local, | ||
449 | tx_work); | ||
450 | struct sk_buff *skb; | ||
451 | struct sock *sk; | ||
452 | struct nfc_llcp_sock *llcp_sock; | ||
453 | |||
454 | skb = skb_dequeue(&local->tx_queue); | ||
455 | if (skb != NULL) { | ||
456 | sk = skb->sk; | ||
457 | llcp_sock = nfc_llcp_sock(sk); | ||
458 | if (llcp_sock != NULL) { | ||
459 | int ret; | ||
460 | |||
461 | pr_debug("Sending pending skb\n"); | ||
462 | print_hex_dump(KERN_DEBUG, "LLCP Tx: ", | ||
463 | DUMP_PREFIX_OFFSET, 16, 1, | ||
464 | skb->data, skb->len, true); | ||
465 | |||
466 | ret = nfc_data_exchange(local->dev, local->target_idx, | ||
467 | skb, nfc_llcp_recv, local); | ||
468 | |||
469 | if (!ret && nfc_llcp_ptype(skb) == LLCP_PDU_I) { | ||
470 | skb = skb_get(skb); | ||
471 | skb_queue_tail(&llcp_sock->tx_pending_queue, | ||
472 | skb); | ||
473 | } | ||
474 | } else { | ||
475 | nfc_llcp_send_symm(local->dev); | ||
476 | } | ||
477 | } else { | ||
478 | nfc_llcp_send_symm(local->dev); | ||
479 | } | ||
480 | |||
481 | mod_timer(&local->link_timer, | ||
482 | jiffies + msecs_to_jiffies(2 * local->remote_lto)); | ||
483 | } | ||
484 | |||
468 | static struct nfc_llcp_sock *nfc_llcp_connecting_sock_get(struct nfc_llcp_local *local, | 485 | static struct nfc_llcp_sock *nfc_llcp_connecting_sock_get(struct nfc_llcp_local *local, |
469 | u8 ssap) | 486 | u8 ssap) |
470 | { | 487 | { |
@@ -705,7 +722,7 @@ int nfc_llcp_queue_i_frames(struct nfc_llcp_sock *sock) | |||
705 | /* Try to queue some I frames for transmission */ | 722 | /* Try to queue some I frames for transmission */ |
706 | while (sock->remote_ready && | 723 | while (sock->remote_ready && |
707 | skb_queue_len(&sock->tx_pending_queue) < sock->rw) { | 724 | skb_queue_len(&sock->tx_pending_queue) < sock->rw) { |
708 | struct sk_buff *pdu, *pending_pdu; | 725 | struct sk_buff *pdu; |
709 | 726 | ||
710 | pdu = skb_dequeue(&sock->tx_queue); | 727 | pdu = skb_dequeue(&sock->tx_queue); |
711 | if (pdu == NULL) | 728 | if (pdu == NULL) |
@@ -714,10 +731,7 @@ int nfc_llcp_queue_i_frames(struct nfc_llcp_sock *sock) | |||
714 | /* Update N(S)/N(R) */ | 731 | /* Update N(S)/N(R) */ |
715 | nfc_llcp_set_nrns(sock, pdu); | 732 | nfc_llcp_set_nrns(sock, pdu); |
716 | 733 | ||
717 | pending_pdu = skb_clone(pdu, GFP_KERNEL); | ||
718 | |||
719 | skb_queue_tail(&local->tx_queue, pdu); | 734 | skb_queue_tail(&local->tx_queue, pdu); |
720 | skb_queue_tail(&sock->tx_pending_queue, pending_pdu); | ||
721 | nr_frames++; | 735 | nr_frames++; |
722 | } | 736 | } |
723 | 737 | ||
@@ -774,11 +788,21 @@ static void nfc_llcp_recv_hdlc(struct nfc_llcp_local *local, | |||
774 | 788 | ||
775 | llcp_sock->send_ack_n = nr; | 789 | llcp_sock->send_ack_n = nr; |
776 | 790 | ||
777 | skb_queue_walk_safe(&llcp_sock->tx_pending_queue, s, tmp) | 791 | /* Remove and free all skbs until ns == nr */ |
778 | if (nfc_llcp_ns(s) <= nr) { | 792 | skb_queue_walk_safe(&llcp_sock->tx_pending_queue, s, tmp) { |
779 | skb_unlink(s, &llcp_sock->tx_pending_queue); | 793 | skb_unlink(s, &llcp_sock->tx_pending_queue); |
780 | kfree_skb(s); | 794 | kfree_skb(s); |
781 | } | 795 | |
796 | if (nfc_llcp_ns(s) == nr) | ||
797 | break; | ||
798 | } | ||
799 | |||
800 | /* Re-queue the remaining skbs for transmission */ | ||
801 | skb_queue_reverse_walk_safe(&llcp_sock->tx_pending_queue, | ||
802 | s, tmp) { | ||
803 | skb_unlink(s, &llcp_sock->tx_pending_queue); | ||
804 | skb_queue_head(&local->tx_queue, s); | ||
805 | } | ||
782 | } | 806 | } |
783 | 807 | ||
784 | if (ptype == LLCP_PDU_RR) | 808 | if (ptype == LLCP_PDU_RR) |