OSDN Git Service

NFC: digital: Enforce NFC-DEP PNI sequencing
authorMark A. Greer <mgreer@animalcreek.com>
Tue, 23 Sep 2014 23:38:07 +0000 (16:38 -0700)
committerSamuel Ortiz <sameo@linux.intel.com>
Fri, 28 Nov 2014 11:38:47 +0000 (12:38 +0100)
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 <thierry.escande@linux.intel.com>
Tested-by: Thierry Escande <thierry.escande@linux.intel.com>
Signed-off-by: Mark A. Greer <mgreer@animalcreek.com>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
net/nfc/digital_dep.c

index d5e669b..95a6989 100644 (file)
@@ -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)