aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThierry Escande <thierry.escande@collabora.com>2016-07-08 09:52:39 -0400
committerSamuel Ortiz <sameo@linux.intel.com>2016-07-10 19:55:42 -0400
commit1d984c2e03c1fb21539a9f50627e312788512013 (patch)
treefe898192971b22ae77a37720a63737c3a0a9023c
parent3cc952dbf1a7176b9247da4cd2612c9ddc1d1b51 (diff)
NFC: digital: Fix handling of saved PDU sk_buff pointers
This patch fixes the way an I-PDU is saved in case it needs to be sent again. It is now copied using pskb_copy() and not simply referenced using skb_get() since it could be modified by the driver. digital_in_send_saved_skb() and digital_tg_send_saved_skb() still get a reference on the saved skb which is re-sent but release it if the send operation fails. That way the caller doesn't have to take care about skb ref in case of error. RTOX supervisor PDU must not be saved as this can override a previously saved I-PDU that should be re-sent later on. Signed-off-by: Thierry Escande <thierry.escande@collabora.com> Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
-rw-r--r--include/net/nfc/digital.h1
-rw-r--r--net/nfc/digital_dep.c59
2 files changed, 29 insertions, 31 deletions
diff --git a/include/net/nfc/digital.h b/include/net/nfc/digital.h
index 506e3f6eabef..f9a4e4771861 100644
--- a/include/net/nfc/digital.h
+++ b/include/net/nfc/digital.h
@@ -237,7 +237,6 @@ struct nfc_digital_dev {
237 int nack_count; 237 int nack_count;
238 238
239 struct sk_buff *saved_skb; 239 struct sk_buff *saved_skb;
240 unsigned int saved_skb_len;
241 240
242 u16 target_fsc; 241 u16 target_fsc;
243 242
diff --git a/net/nfc/digital_dep.c b/net/nfc/digital_dep.c
index b62c85dc12a2..804585cb3f8e 100644
--- a/net/nfc/digital_dep.c
+++ b/net/nfc/digital_dep.c
@@ -524,8 +524,7 @@ static int digital_in_send_ack(struct nfc_digital_dev *ddev,
524 524
525 ddev->skb_add_crc(skb); 525 ddev->skb_add_crc(skb);
526 526
527 ddev->saved_skb = skb_get(skb); 527 ddev->saved_skb = pskb_copy(skb, GFP_KERNEL);
528 ddev->saved_skb_len = skb->len;
529 528
530 rc = digital_in_send_cmd(ddev, skb, 1500, digital_in_recv_dep_res, 529 rc = digital_in_send_cmd(ddev, skb, 1500, digital_in_recv_dep_res,
531 data_exch); 530 data_exch);
@@ -627,16 +626,10 @@ static int digital_in_send_rtox(struct nfc_digital_dev *ddev,
627 626
628 ddev->skb_add_crc(skb); 627 ddev->skb_add_crc(skb);
629 628
630 ddev->saved_skb = skb_get(skb);
631 ddev->saved_skb_len = skb->len;
632
633 rc = digital_in_send_cmd(ddev, skb, 1500, digital_in_recv_dep_res, 629 rc = digital_in_send_cmd(ddev, skb, 1500, digital_in_recv_dep_res,
634 data_exch); 630 data_exch);
635 if (rc) { 631 if (rc)
636 kfree_skb(skb); 632 kfree_skb(skb);
637 kfree_skb(ddev->saved_skb);
638 ddev->saved_skb = NULL;
639 }
640 633
641 return rc; 634 return rc;
642} 635}
@@ -644,11 +637,19 @@ static int digital_in_send_rtox(struct nfc_digital_dev *ddev,
644static int digital_in_send_saved_skb(struct nfc_digital_dev *ddev, 637static int digital_in_send_saved_skb(struct nfc_digital_dev *ddev,
645 struct digital_data_exch *data_exch) 638 struct digital_data_exch *data_exch)
646{ 639{
640 int rc;
641
642 if (!ddev->saved_skb)
643 return -EINVAL;
644
647 skb_get(ddev->saved_skb); 645 skb_get(ddev->saved_skb);
648 skb_push(ddev->saved_skb, ddev->saved_skb_len);
649 646
650 return digital_in_send_cmd(ddev, ddev->saved_skb, 1500, 647 rc = digital_in_send_cmd(ddev, ddev->saved_skb, 1500,
651 digital_in_recv_dep_res, data_exch); 648 digital_in_recv_dep_res, data_exch);
649 if (rc)
650 kfree_skb(ddev->saved_skb);
651
652 return rc;
652} 653}
653 654
654static void digital_in_recv_dep_res(struct nfc_digital_dev *ddev, void *arg, 655static void digital_in_recv_dep_res(struct nfc_digital_dev *ddev, void *arg,
@@ -812,17 +813,12 @@ static void digital_in_recv_dep_res(struct nfc_digital_dev *ddev, void *arg,
812 case DIGITAL_NFC_DEP_PFB_SUPERVISOR_PDU: 813 case DIGITAL_NFC_DEP_PFB_SUPERVISOR_PDU:
813 if (!DIGITAL_NFC_DEP_PFB_IS_TIMEOUT(pfb)) { /* ATN */ 814 if (!DIGITAL_NFC_DEP_PFB_IS_TIMEOUT(pfb)) { /* ATN */
814 rc = digital_in_send_saved_skb(ddev, data_exch); 815 rc = digital_in_send_saved_skb(ddev, data_exch);
815 if (rc) { 816 if (rc)
816 kfree_skb(ddev->saved_skb);
817 goto error; 817 goto error;
818 }
819 818
820 return; 819 return;
821 } 820 }
822 821
823 kfree_skb(ddev->saved_skb);
824 ddev->saved_skb = NULL;
825
826 rc = digital_in_send_rtox(ddev, data_exch, resp->data[0]); 822 rc = digital_in_send_rtox(ddev, data_exch, resp->data[0]);
827 if (rc) 823 if (rc)
828 goto error; 824 goto error;
@@ -876,8 +872,7 @@ int digital_in_send_dep_req(struct nfc_digital_dev *ddev,
876 872
877 ddev->skb_add_crc(tmp_skb); 873 ddev->skb_add_crc(tmp_skb);
878 874
879 ddev->saved_skb = skb_get(tmp_skb); 875 ddev->saved_skb = pskb_copy(tmp_skb, GFP_KERNEL);
880 ddev->saved_skb_len = tmp_skb->len;
881 876
882 rc = digital_in_send_cmd(ddev, tmp_skb, 1500, digital_in_recv_dep_res, 877 rc = digital_in_send_cmd(ddev, tmp_skb, 1500, digital_in_recv_dep_res,
883 data_exch); 878 data_exch);
@@ -956,8 +951,7 @@ static int digital_tg_send_ack(struct nfc_digital_dev *ddev,
956 951
957 ddev->skb_add_crc(skb); 952 ddev->skb_add_crc(skb);
958 953
959 ddev->saved_skb = skb_get(skb); 954 ddev->saved_skb = pskb_copy(skb, GFP_KERNEL);
960 ddev->saved_skb_len = skb->len;
961 955
962 rc = digital_tg_send_cmd(ddev, skb, 1500, digital_tg_recv_dep_req, 956 rc = digital_tg_send_cmd(ddev, skb, 1500, digital_tg_recv_dep_req,
963 data_exch); 957 data_exch);
@@ -1009,11 +1003,19 @@ static int digital_tg_send_atn(struct nfc_digital_dev *ddev)
1009 1003
1010static int digital_tg_send_saved_skb(struct nfc_digital_dev *ddev) 1004static int digital_tg_send_saved_skb(struct nfc_digital_dev *ddev)
1011{ 1005{
1006 int rc;
1007
1008 if (!ddev->saved_skb)
1009 return -EINVAL;
1010
1012 skb_get(ddev->saved_skb); 1011 skb_get(ddev->saved_skb);
1013 skb_push(ddev->saved_skb, ddev->saved_skb_len);
1014 1012
1015 return digital_tg_send_cmd(ddev, ddev->saved_skb, 1500, 1013 rc = digital_tg_send_cmd(ddev, ddev->saved_skb, 1500,
1016 digital_tg_recv_dep_req, NULL); 1014 digital_tg_recv_dep_req, NULL);
1015 if (rc)
1016 kfree_skb(ddev->saved_skb);
1017
1018 return rc;
1017} 1019}
1018 1020
1019static void digital_tg_recv_dep_req(struct nfc_digital_dev *ddev, void *arg, 1021static void digital_tg_recv_dep_req(struct nfc_digital_dev *ddev, void *arg,
@@ -1163,10 +1165,8 @@ static void digital_tg_recv_dep_req(struct nfc_digital_dev *ddev, void *arg,
1163 ddev->atn_count = 0; 1165 ddev->atn_count = 0;
1164 1166
1165 rc = digital_tg_send_saved_skb(ddev); 1167 rc = digital_tg_send_saved_skb(ddev);
1166 if (rc) { 1168 if (rc)
1167 kfree_skb(ddev->saved_skb);
1168 goto exit; 1169 goto exit;
1169 }
1170 } 1170 }
1171 1171
1172 return; 1172 return;
@@ -1235,8 +1235,7 @@ int digital_tg_send_dep_res(struct nfc_digital_dev *ddev, struct sk_buff *skb)
1235 1235
1236 ddev->skb_add_crc(tmp_skb); 1236 ddev->skb_add_crc(tmp_skb);
1237 1237
1238 ddev->saved_skb = skb_get(tmp_skb); 1238 ddev->saved_skb = pskb_copy(tmp_skb, GFP_KERNEL);
1239 ddev->saved_skb_len = tmp_skb->len;
1240 1239
1241 rc = digital_tg_send_cmd(ddev, tmp_skb, 1500, digital_tg_recv_dep_req, 1240 rc = digital_tg_send_cmd(ddev, tmp_skb, 1500, digital_tg_recv_dep_req,
1242 NULL); 1241 NULL);