From 485fdc9bb6f81d68aa30b399b9bc33cf27d65ba4 Mon Sep 17 00:00:00 2001 From: "Mark A. Greer" Date: Tue, 23 Sep 2014 16:38:07 -0700 Subject: NFC: digital: Enforce NFC-DEP PNI sequencing NFC-DEP DEP_REQ and DEP_RES exchanges using 'I' and 'ACK/NACK' PDUs have a sequence number called the Packet Number Information (PNI). The PNI is incremented (modulo 4) after every DEP_REQ/ DEP_RES pair and should be verified by the digital layer code. That verification isn't always done, though, so add code to make sure that it is done. Reviewed-by: Thierry Escande Tested-by: Thierry Escande Signed-off-by: Mark A. Greer Signed-off-by: Samuel Ortiz --- net/nfc/digital_dep.c | 36 +++++++++++++++++++++++++++++++++--- 1 file changed, 33 insertions(+), 3 deletions(-) (limited to 'net/nfc/digital_dep.c') diff --git a/net/nfc/digital_dep.c b/net/nfc/digital_dep.c index d5e669b0dedf..95a69898d5f5 100644 --- a/net/nfc/digital_dep.c +++ b/net/nfc/digital_dep.c @@ -447,8 +447,18 @@ static void digital_in_recv_dep_res(struct nfc_digital_dev *ddev, void *arg, case DIGITAL_NFC_DEP_PFB_ACK_NACK_PDU: pr_err("Received a ACK/NACK PDU\n"); - rc = -EIO; - goto error; + + if (DIGITAL_NFC_DEP_PFB_PNI(pfb) != ddev->curr_nfc_dep_pni) { + PROTOCOL_ERR("14.12.3.3"); + rc = -EIO; + goto exit; + } + + ddev->curr_nfc_dep_pni = + DIGITAL_NFC_DEP_PFB_PNI(ddev->curr_nfc_dep_pni + 1); + + rc = -EINVAL; + goto exit; case DIGITAL_NFC_DEP_PFB_SUPERVISOR_PDU: if (!DIGITAL_NFC_DEP_PFB_IS_TIMEOUT(pfb)) { @@ -592,9 +602,22 @@ static void digital_tg_recv_dep_req(struct nfc_digital_dev *ddev, void *arg, switch (DIGITAL_NFC_DEP_PFB_TYPE(pfb)) { case DIGITAL_NFC_DEP_PFB_I_PDU: pr_debug("DIGITAL_NFC_DEP_PFB_I_PDU\n"); - ddev->curr_nfc_dep_pni = DIGITAL_NFC_DEP_PFB_PNI(pfb); + + if (DIGITAL_NFC_DEP_PFB_PNI(pfb) != ddev->curr_nfc_dep_pni) { + PROTOCOL_ERR("14.12.3.4"); + rc = -EIO; + goto exit; + } + + rc = 0; break; case DIGITAL_NFC_DEP_PFB_ACK_NACK_PDU: + if (DIGITAL_NFC_DEP_PFB_PNI(pfb) != ddev->curr_nfc_dep_pni) { + PROTOCOL_ERR("14.12.3.4"); + rc = -EIO; + goto exit; + } + pr_err("Received a ACK/NACK PDU\n"); rc = -EINVAL; goto exit; @@ -629,6 +652,9 @@ int digital_tg_send_dep_res(struct nfc_digital_dev *ddev, struct sk_buff *skb) sizeof(ddev->did)); } + ddev->curr_nfc_dep_pni = + DIGITAL_NFC_DEP_PFB_PNI(ddev->curr_nfc_dep_pni + 1); + digital_skb_push_dep_sod(ddev, skb); ddev->skb_add_crc(skb); @@ -677,6 +703,8 @@ static int digital_tg_send_psl_res(struct nfc_digital_dev *ddev, u8 did, ddev->skb_add_crc(skb); + ddev->curr_nfc_dep_pni = 0; + rc = digital_tg_send_cmd(ddev, skb, 0, digital_tg_send_psl_res_complete, (void *)(unsigned long)rf_tech); if (rc) @@ -800,6 +828,8 @@ static int digital_tg_send_atr_res(struct nfc_digital_dev *ddev, ddev->skb_add_crc(skb); + ddev->curr_nfc_dep_pni = 0; + rc = digital_tg_send_cmd(ddev, skb, 999, digital_tg_send_atr_res_complete, NULL); if (rc) -- cgit v1.2.3