add function to set mifare key from internal eeprom
[librfid] / src / rfid_proto_mifare_classic.c
index 99386a1..a6e2e4f 100644 (file)
@@ -1,7 +1,7 @@
 
 /* Mifare Classic implementation, PCD side.
  *
- * (C) 2005 by Harald Welte <laforge@gnumonks.org>
+ * (C) 2005-2008 by Harald Welte <laforge@gnumonks.org>
  *
  */
 
@@ -17,7 +17,7 @@
  *
  *  You should have received a copy of the GNU General Public License
  *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  */
 #include <stdio.h>
 #include <stdlib.h>
 #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"
 
@@ -38,9 +38,8 @@
 #define MIFARE_UL_CMD_WRITE    0xA2
 #define MIFARE_UL_CMD_READ     0x30
 
-/* FIXME */
-#define MIFARE_CL_READ_FWT     100
-#define MIFARE_CL_WRITE_FWT    100
+#define MIFARE_CL_READ_FWT     250
+#define MIFARE_CL_WRITE_FWT    600
 
 static int
 mfcl_read(struct rfid_protocol_handle *ph, unsigned int page,
@@ -57,9 +56,9 @@ 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;
@@ -79,24 +78,28 @@ static int
 mfcl_write(struct rfid_protocol_handle *ph, unsigned int page,
           unsigned char *tx_data, unsigned int tx_len)
 {
-       unsigned int i;
-       unsigned char tx[18];
+       unsigned char tx[2];
        unsigned char rx[1];
-       unsigned int rx_len;
+       unsigned int rx_len = sizeof(rx);
        int ret;
 
-       if (tx_len != 16 || page > MIFARE_CL_PAGE_MAX)
+       if (page > MIFARE_CL_PAGE_MAX)
                return -EINVAL;
 
+       if (tx_len != 16)
+               return -EINVAL;
+       
        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);
-                                       
+       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;
 
@@ -106,21 +109,65 @@ mfcl_write(struct rfid_protocol_handle *ph, unsigned int page,
        return ret;
 }
 
+static int 
+mfcl_getopt(struct rfid_protocol_handle *ph, int optname, void *optval,
+           unsigned int *optlen)
+{
+       int ret = -EINVAL;
+       u_int8_t atqa[2];
+       u_int8_t sak;
+       unsigned int atqa_size = sizeof(atqa);
+       unsigned int sak_size = sizeof(sak);
+       unsigned int *size = optval;
+
+       switch (optname) {
+       case RFID_OPT_PROTO_SIZE:
+               if (*optlen < sizeof(*size))
+                       return -EINVAL;
+               *optlen = sizeof(*size);
+               ret = 0;
+               rfid_layer2_getopt(ph->l2h, RFID_OPT_14443A_ATQA,
+                                  atqa, &atqa_size);
+               rfid_layer2_getopt(ph->l2h, RFID_OPT_14443A_SAK,
+                                  &sak, &sak_size);
+               if (atqa[0] == 0x04 && atqa[1] == 0x00) {
+                       if (sak == 0x09) {
+                               /* mifare mini */
+                               *size = 320;
+                       } else
+                               *size = 1024;
+               } else if (atqa[0] == 0x02 && atqa[1] == 0x00)
+                       *size = 4096;
+               else
+                       ret = -EIO;
+               break;
+       }
+
+       return ret;
+}
+
 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     = {
@@ -128,6 +175,7 @@ struct rfid_protocol rfid_protocol_mfcl = {
                .read           = &mfcl_read,
                .write          = &mfcl_write,
                .fini           = &mfcl_fini,
+               .getopt         = &mfcl_getopt,
        },
 };
 
@@ -139,6 +187,14 @@ int mfcl_set_key(struct rfid_protocol_handle *ph, unsigned char *key)
        return ph->l2h->rh->reader->mifare_classic.setkey(ph->l2h->rh, key);
 }
 
+int mfcl_set_key_ee(struct rfid_protocol_handle *ph, unsigned int addr)
+{
+       if (!ph->l2h->rh->reader->mifare_classic.setkey_ee)
+               return -ENODEV;
+
+       return ph->l2h->rh->reader->mifare_classic.setkey_ee(ph->l2h->rh, addr);
+}
+
 int mfcl_auth(struct rfid_protocol_handle *ph, u_int8_t cmd, u_int8_t block)
 {
        u_int32_t serno = *((u_int32_t *)ph->l2h->uid);
@@ -149,3 +205,33 @@ int mfcl_auth(struct rfid_protocol_handle *ph, u_int8_t cmd, u_int8_t block)
        return ph->l2h->rh->reader->mifare_classic.auth(ph->l2h->rh, cmd,
                                                       serno, block);
 }
+
+int mfcl_block2sector(u_int8_t block)
+{
+       if (block < MIFARE_CL_SMALL_SECTORS * MIFARE_CL_BLOCKS_P_SECTOR_1k)
+               return block/MIFARE_CL_BLOCKS_P_SECTOR_1k;
+       else
+               return (block - MIFARE_CL_SMALL_SECTORS * MIFARE_CL_BLOCKS_P_SECTOR_1k)
+                                       / MIFARE_CL_BLOCKS_P_SECTOR_4k;
+}
+
+int mfcl_sector2block(u_int8_t sector)
+{
+       if (sector < MIFARE_CL_SMALL_SECTORS)
+               return sector * MIFARE_CL_BLOCKS_P_SECTOR_1k;
+       else if (sector < MIFARE_CL_SMALL_SECTORS + MIFARE_CL_LARGE_SECTORS)
+               return MIFARE_CL_SMALL_SECTORS * MIFARE_CL_BLOCKS_P_SECTOR_1k + 
+                       (sector - MIFARE_CL_SMALL_SECTORS) * MIFARE_CL_BLOCKS_P_SECTOR_4k; 
+       else
+               return -EINVAL;
+}
+
+int mfcl_sector_blocks(u_int8_t sector)
+{
+       if (sector < MIFARE_CL_SMALL_SECTORS)
+               return MIFARE_CL_BLOCKS_P_SECTOR_1k;
+       else if (sector < MIFARE_CL_SMALL_SECTORS + MIFARE_CL_LARGE_SECTORS)
+               return MIFARE_CL_BLOCKS_P_SECTOR_4k;
+       else
+               return -EINVAL;
+}