aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSamuel Ortiz <sameo@linux.intel.com>2012-05-30 11:48:29 -0400
committerSamuel Ortiz <sameo@linux.intel.com>2012-06-04 15:34:33 -0400
commit844579603889ef1ab1fdbf2223579d6842e62bfe (patch)
tree92abc58fa1d7ffbed6b1026ea599f0cf28bb2417
parent6fbbdc16be3881aabaa4096c3466b9bbd361bd1f (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>
-rw-r--r--net/nfc/llcp/llcp.c86
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
414static 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
436static u8 nfc_llcp_dsap(struct sk_buff *pdu) 414static 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
446static 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
468static struct nfc_llcp_sock *nfc_llcp_connecting_sock_get(struct nfc_llcp_local *local, 485static 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)