aboutsummaryrefslogtreecommitdiffstats
path: root/net/nfc/llcp
diff options
context:
space:
mode:
authorSamuel Ortiz <sameo@linux.intel.com>2012-11-01 18:36:07 -0400
committerSamuel Ortiz <sameo@linux.intel.com>2012-11-19 17:57:01 -0500
commitbe02b6b624005d47c388f799ce23714136430217 (patch)
tree2e440fa1279d91f0791e3ee3248c2120bc4855aa /net/nfc/llcp
parentdd2bf43ffcf0d1bba94d20abc6cc44ed294db66b (diff)
NFC: Queue a copy of the transmitted LLCP skb
Drivers are allowed to modify the sent skb and thus we need to make a copy of it before passing it to the driver. Without this fix, LLCP Tx skbs were not queued properly as the ptype check was failing due to e.g. the pn533 driver skb_pushing the Tx skb. Reported-by: Thierry Escande <thierry.escande@linux.intel.com> Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Diffstat (limited to 'net/nfc/llcp')
-rw-r--r--net/nfc/llcp/llcp.c17
1 files changed, 13 insertions, 4 deletions
diff --git a/net/nfc/llcp/llcp.c b/net/nfc/llcp/llcp.c
index f6804532047a..66733335345f 100644
--- a/net/nfc/llcp/llcp.c
+++ b/net/nfc/llcp/llcp.c
@@ -656,6 +656,8 @@ static void nfc_llcp_tx_work(struct work_struct *work)
656 if (llcp_sock == NULL && nfc_llcp_ptype(skb) == LLCP_PDU_I) { 656 if (llcp_sock == NULL && nfc_llcp_ptype(skb) == LLCP_PDU_I) {
657 nfc_llcp_send_symm(local->dev); 657 nfc_llcp_send_symm(local->dev);
658 } else { 658 } else {
659 struct sk_buff *copy_skb = NULL;
660 u8 ptype = nfc_llcp_ptype(skb);
659 int ret; 661 int ret;
660 662
661 pr_debug("Sending pending skb\n"); 663 pr_debug("Sending pending skb\n");
@@ -663,22 +665,29 @@ static void nfc_llcp_tx_work(struct work_struct *work)
663 DUMP_PREFIX_OFFSET, 16, 1, 665 DUMP_PREFIX_OFFSET, 16, 1,
664 skb->data, skb->len, true); 666 skb->data, skb->len, true);
665 667
668 if (ptype == LLCP_PDU_I)
669 copy_skb = skb_copy(skb, GFP_ATOMIC);
670
666 nfc_llcp_send_to_raw_sock(local, skb, 671 nfc_llcp_send_to_raw_sock(local, skb,
667 NFC_LLCP_DIRECTION_TX); 672 NFC_LLCP_DIRECTION_TX);
668 673
669 ret = nfc_data_exchange(local->dev, local->target_idx, 674 ret = nfc_data_exchange(local->dev, local->target_idx,
670 skb, nfc_llcp_recv, local); 675 skb, nfc_llcp_recv, local);
671 676
672 if (!ret && nfc_llcp_ptype(skb) == LLCP_PDU_I) { 677 if (ret) {
673 skb = skb_get(skb); 678 kfree_skb(copy_skb);
674 skb_queue_tail(&llcp_sock->tx_pending_queue, 679 goto out;
675 skb);
676 } 680 }
681
682 if (ptype == LLCP_PDU_I && copy_skb)
683 skb_queue_tail(&llcp_sock->tx_pending_queue,
684 copy_skb);
677 } 685 }
678 } else { 686 } else {
679 nfc_llcp_send_symm(local->dev); 687 nfc_llcp_send_symm(local->dev);
680 } 688 }
681 689
690out:
682 mod_timer(&local->link_timer, 691 mod_timer(&local->link_timer,
683 jiffies + msecs_to_jiffies(2 * local->remote_lto)); 692 jiffies + msecs_to_jiffies(2 * local->remote_lto));
684} 693}