- fix mifare write support
[librfid] / src / rfid_proto_mifare_classic.c
index 10de288..4032b80 100644 (file)
@@ -1,7 +1,7 @@
 
 /* Mifare Classic implementation, PCD side.
  *
- * (C) 2005 by Harald Welte <laforge@gnumonks.org>
+ * (C) 2005-2006 by Harald Welte <laforge@gnumonks.org>
  *
  */
 
 #include <string.h>
 #include <errno.h>
 
-#include <rfid/rfid.h>
-#include <rfid/rfid_protocol.h>
-#include <rfid/rfid_layer2.h>
-#include <rfid/rfid_protocol_mifare_classic.h>
+#include <librfid/rfid.h>
+#include <librfid/rfid_protocol.h>
+#include <librfid/rfid_layer2.h>
+#include <librfid/rfid_protocol_mifare_classic.h>
 
-#include <rfid/rfid_reader.h>
+#include <librfid/rfid_reader.h>
 
 #include "rfid_iso14443_common.h"
 
@@ -57,13 +57,16 @@ mfcl_read(struct rfid_protocol_handle *ph, unsigned int page,
        tx[0] = MIFARE_CL_CMD_READ;
        tx[1] = page & 0xff;
 
-       ret = ph->l2h->l2->fn.transcieve(ph->l2h, RFID_MIFARE_FRAME, tx,
-                                        sizeof(tx), rx_buf, &real_rx_len,
-                                        MIFARE_CL_READ_FWT, 0);
+       ret = rfid_layer2_transceive(ph->l2h, RFID_MIFARE_FRAME, tx,
+                                    sizeof(tx), rx_buf, &real_rx_len,
+                                    MIFARE_CL_READ_FWT, 0);
 
        if (ret < 0)
                return ret;
 
+       if (real_rx_len == 1 && *rx_buf == 0x04)
+               return -EPERM;
+
        if (real_rx_len < *rx_len)
                *rx_len = real_rx_len;
 
@@ -82,23 +85,57 @@ mfcl_write(struct rfid_protocol_handle *ph, unsigned int page,
        unsigned int rx_len;
        int ret;
 
-       if (tx_len != 16 || page > MIFARE_CL_PAGE_MAX)
+       if (page > MIFARE_CL_PAGE_MAX)
                return -EINVAL;
 
-       tx[0] = MIFARE_CL_CMD_WRITE16;
-       tx[1] = page & 0xff;
+       if (tx_len != 16 && tx_len != 4)
+               return -EINVAL;
+       
+       if (tx_len == 16) {
+               tx[0] = MIFARE_CL_CMD_WRITE16;
+               tx[1] = page & 0xff;
 
-       memcpy(tx+2, tx_data, 16);
+               ret = rfid_layer2_transceive(ph->l2h, RFID_MIFARE_FRAME, tx,
+                                            2, rx, &rx_len, 
+                                            MIFARE_CL_WRITE_FWT, 0);
+               if (ret < 0)
+                       return ret;
 
-       ret = ph->l2h->l2->fn.transcieve(ph->l2h, RFID_MIFARE_FRAME, tx,
-                                        sizeof(tx), rx, &rx_len, 
-                                        MIFARE_CL_WRITE_FWT, 0);
-                                       
-       if (ret < 0)
-               return ret;
+               ret = rfid_layer2_transceive(ph->l2h, RFID_MIFARE_FRAME, tx_data,
+                                            tx_len, rx, &rx_len,
+                                            MIFARE_CL_WRITE_FWT, 0);
+               if (ret < 0)
+                       return ret;
+
+               if (rx[0] != MIFARE_UL_RESP_ACK)
+                       return -EIO;
+
+               ret = rfid_layer2_transceive(ph->l2h, RFID_MIFARE_FRAME, tx,
+                                            sizeof(tx), rx, &rx_len, 
+                                            MIFARE_CL_WRITE_FWT, 0);
+               if (ret < 0)
+                       return ret;
+
+               if (rx[0] != MIFARE_UL_RESP_ACK)
+                       return -EIO;
 
-       if (rx[0] != MIFARE_UL_RESP_ACK)
-               return -EIO;
+       } else if (tx_len == 4) {
+
+               tx[0] = MIFARE_CL_CMD_WRITE4;
+               tx[1] = page & 0xff;
+
+               memcpy(tx+2, tx_data, 4);
+
+               ret = rfid_layer2_transceive(ph->l2h, RFID_MIFARE_FRAME, tx,
+                                            2+4, rx, &rx_len, 
+                                            MIFARE_CL_WRITE_FWT, 0);
+               if (ret < 0)
+                       return ret;
+
+               if (rx[0] != MIFARE_UL_RESP_ACK)
+                       return -EIO;
+
+       }
 
        return ret;
 }
@@ -107,17 +144,24 @@ static struct rfid_protocol_handle *
 mfcl_init(struct rfid_layer2_handle *l2h)
 {
        struct rfid_protocol_handle *ph;
-       ph = malloc(sizeof(struct rfid_protocol_handle));
+
+       if (l2h->l2->id != RFID_LAYER2_ISO14443A)
+               return NULL;
+
+       if (l2h->uid_len != 4)
+               return NULL;
+
+       ph = malloc_protocol_handle(sizeof(struct rfid_protocol_handle));
        return ph;
 }
 
 static int mfcl_fini(struct rfid_protocol_handle *ph)
 {
-       free(ph);
+       free_protocol_handle(ph);
        return 0;
 }
 
-struct rfid_protocol rfid_protocol_mfcl = {
+const struct rfid_protocol rfid_protocol_mfcl = {
        .id     = RFID_PROTOCOL_MIFARE_CLASSIC,
        .name   = "Mifare Classic",
        .fn     = {