/* Mifare Classic implementation, PCD side.
*
- * (C) 2005 by Harald Welte <laforge@gnumonks.org>
+ * (C) 2005-2008 by Harald Welte <laforge@gnumonks.org>
*
*/
*
* 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>
#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,
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 = rfid_layer2_transceive(ph->l2h, RFID_MIFARE_FRAME, tx,
- sizeof(tx), rx, &rx_len,
+ 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;
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 = {
.read = &mfcl_read,
.write = &mfcl_write,
.fini = &mfcl_fini,
+ .getopt = &mfcl_getopt,
},
};
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;
+}