summaryrefslogtreecommitdiffstats
path: root/net/nfc
diff options
context:
space:
mode:
authorSamuel Ortiz2012-11-01 23:36:07 +0100
committerSamuel Ortiz2012-11-19 23:57:01 +0100
commitbe02b6b624005d47c388f799ce23714136430217 (patch)
tree2e440fa1279d91f0791e3ee3248c2120bc4855aa /net/nfc
parentNFC: Stop sending LLCP frames when tx queues are getting too deep (diff)
downloadkernel-qcow2-linux-be02b6b624005d47c388f799ce23714136430217.tar.gz
kernel-qcow2-linux-be02b6b624005d47c388f799ce23714136430217.tar.xz
kernel-qcow2-linux-be02b6b624005d47c388f799ce23714136430217.zip
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')
-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)
if (llcp_sock == NULL && nfc_llcp_ptype(skb) == LLCP_PDU_I) {
nfc_llcp_send_symm(local->dev);
} else {
+ struct sk_buff *copy_skb = NULL;
+ u8 ptype = nfc_llcp_ptype(skb);
int ret;
pr_debug("Sending pending skb\n");
@@ -663,22 +665,29 @@ static void nfc_llcp_tx_work(struct work_struct *work)
DUMP_PREFIX_OFFSET, 16, 1,
skb->data, skb->len, true);
+ if (ptype == LLCP_PDU_I)
+ copy_skb = skb_copy(skb, GFP_ATOMIC);
+
nfc_llcp_send_to_raw_sock(local, skb,
NFC_LLCP_DIRECTION_TX);
ret = nfc_data_exchange(local->dev, local->target_idx,
skb, nfc_llcp_recv, local);
- if (!ret && nfc_llcp_ptype(skb) == LLCP_PDU_I) {
- skb = skb_get(skb);
- skb_queue_tail(&llcp_sock->tx_pending_queue,
- skb);
+ if (ret) {
+ kfree_skb(copy_skb);
+ goto out;
}
+
+ if (ptype == LLCP_PDU_I && copy_skb)
+ skb_queue_tail(&llcp_sock->tx_pending_queue,
+ copy_skb);
}
} else {
nfc_llcp_send_symm(local->dev);
}
+out:
mod_timer(&local->link_timer,
jiffies + msecs_to_jiffies(2 * local->remote_lto));
}