#include <stdint.h>
#include <errno.h>
#include <string.h>
+#include <math.h>
#include <sys/socket.h>
#include <linux/socket.h>
#define APDU_OK 0x9000
#define APDU_NOT_FOUND 0x6A82
+/* PICC Level Commands */
+#define PICC_CLASS 0x90
+#define GET_VERSION 0x60
+#define CREATE_APPLICATION 0xCA
+#define SELECT_APPLICATION 0x5A
+#define CREATE_STD_DATA_FILE 0xCD
+#define WRITE_DATA_TO_FILE 0x3D
+
+#define DESFire_EV1_MAJOR_VERSION 0x01
+#define PICC_LEVEL_APDU_OK 0x9100
+#define GET_VERSION_FRAME_RESPONSE_BYTE 0xAF
+#define DESFIRE_KEY_SETTINGS 0x0F
+#define DESFIRE_NUM_OF_KEYS 0x21
+#define DESFIRE_CC_FILE_NUM 0x01
+#define DESFIRE_NDEF_FILE_NUM 0x02
+#define DESFIRE_COMMSET 0x00
+#define MAPPING_VERSION 0x20
+#define FREE_READ_ACCESS 0x00
+#define FREE_WRITE_ACCESS 0x00
+
+#define MIFARE_DESFIRE_EV1_SIZE(x) (pow(2, (x >> 1)))
+
#define T4_ALL_ACCESS 0x00
#define T4_READ_ONLY 0xFF
uint8_t tlv_blocks[];
} __attribute__((packed));
+struct desfire_app {
+ uint8_t aid[3];
+ uint8_t key_settings;
+ uint8_t number_of_keys;
+ uint8_t file_id[2];
+ uint8_t iso_appname[7];
+} __attribute__((packed));
+
+struct desfire_std_file {
+ uint8_t file_num;
+ uint8_t file_id[2];
+ uint8_t comm_set;
+ uint8_t access_rights[2];
+ uint8_t size[3];
+} __attribute__((packed));
+
+struct desfire_cc_file {
+ uint8_t file_num;
+ uint8_t offset[3];
+ uint8_t max_len[3];
+ uint8_t cc_len[2];
+ uint8_t version;
+ uint8_t mle[2];
+ uint8_t mlc[2];
+ uint8_t ndef_tlv[4];
+ uint8_t ndef_size[2];
+ uint8_t read_access;
+ uint8_t write_access;
+} __attribute__((packed));
+
struct t4_cookie {
uint32_t adapter_idx;
uint32_t target_idx;
uint16_t max_ndef_size;
uint8_t write_access;
struct near_ndef_message *ndef;
+ uint16_t memory_size;
};
/* ISO functions: This code prepares APDU */
uint8_t param2,
uint8_t *cmd_data,
uint8_t cmd_data_length,
+ near_bool_t le,
near_recv cb,
void *in_data)
{
struct type4_cmd *cmd;
struct t4_cookie *in_rcv = in_data;
+ uint8_t total_cmd_length;
int err;
- DBG("CLA:x%02x INS:x%02x P1:%02x P2:%02x",
+ DBG("CLA-%02x INS-%02x P1-%02x P2-%02x",
class, instruction, param1, param2);
- cmd = g_try_malloc0(APDU_HEADER_LEN + cmd_data_length);
+ if (le == FALSE) {
+ if (cmd_data)
+ total_cmd_length = APDU_HEADER_LEN + cmd_data_length;
+ else
+ total_cmd_length = APDU_HEADER_LEN;
+ } else { /* Extra byte for Le */
+ total_cmd_length = APDU_HEADER_LEN + cmd_data_length + 1;
+ }
+
+ cmd = g_try_malloc0(total_cmd_length);
if (cmd == NULL) {
DBG("Mem alloc failed");
err = -ENOMEM;
cmd->param2 = param2 ;
cmd->data_length = cmd_data_length;
- if (cmd_data)
+ if (cmd_data) {
memcpy(cmd->data, cmd_data, cmd_data_length);
- else
- cmd_data_length = 0 ;
+ /* The Le byte set to 0x00 defined that any length
+ * of PICC response is allowed */
+ if (le == TRUE)
+ cmd->data[cmd_data_length] = 0;
+ }
err = near_adapter_send(in_rcv->adapter_idx, (uint8_t *)cmd,
- APDU_HEADER_LEN + cmd_data_length , cb, in_rcv);
+ total_cmd_length, cb, in_rcv);
if (err < 0)
g_free(in_rcv);
0x00, /* P2: First or only occurrence */
filename, /* cmd_data */
fnamelen, /* uint8_t cmd_data_length*/
+ FALSE,
cb,
cookie);
}
(uint8_t)(offset & 0xFF),
0, /* no data send */
readsize, /* bytes to read */
+ FALSE,
cb,
cookie);
}
(uint8_t)(offset & 0xFF),
data, /* length of NDEF data */
nlen, /* NLEN + NDEF data */
+ FALSE,
cb,
cookie);
}
return t4_cookie_release(err, cookie);
}
+static int select_ndef_file(uint8_t *resp, int length, void *data)
+{
+ struct t4_cookie *cookie = data;
+ int err = 0;
+
+ DBG("%d", length);
+
+ if (length < 0) {
+ err = length;
+ goto out_err;
+ }
+
+ if (APDU_STATUS(resp + STATUS_WORD_1) != APDU_OK) {
+ near_error("select ndef file resp failed %02X",
+ resp[length - 1]);
+ err = -EIO;
+ goto out_err;
+ }
+
+ DBG("ndef file selected");
+
+ if (cookie->cb)
+ cookie->cb(cookie->adapter_idx, cookie->target_idx, 0);
+
+out_err:
+ return t4_cookie_release(err, cookie);
+}
+
+static int read_cc_file(uint8_t *resp, int length, void *data)
+{
+ struct t4_cookie *cookie = data;
+ struct near_tag *tag;
+ struct type4_cc *read_cc = NULL;
+ int err = 0;
+
+ DBG("%d", length);
+
+ if (length < 0) {
+ err = length;
+ goto out_err;
+ }
+
+ /* Check APDU error ( the two last bytes of the resp) */
+ if (APDU_STATUS(resp + length - 2) != APDU_OK) {
+ near_error("read cc failed SWx%04x",
+ APDU_STATUS(resp + length - 2));
+ err = -EIO;
+ goto out_err;
+ }
+
+ /* -2 for status word and -1 is for NFC first byte... */
+ read_cc = g_try_malloc0(length - 2 - NFC_STATUS_BYTE_LEN);
+ if (read_cc == NULL) {
+ err = -ENOMEM;
+ goto out_err;
+ }
+
+ memcpy(read_cc, &resp[1], length - 2 - NFC_STATUS_BYTE_LEN) ;
+ cookie->c_apdu_max_size = g_ntohs(read_cc->max_C_apdu_data_size);
+ cookie->max_ndef_size = g_ntohs(read_cc->tlv_fc.max_ndef_size);
+
+ tag = near_tag_get_tag(cookie->adapter_idx, cookie->target_idx);
+ if (tag == NULL) {
+ err = -EINVAL;
+ goto out_err;
+ }
+
+ near_tag_set_max_ndef_size(tag, cookie->memory_size);
+ near_tag_set_c_apdu_max_size(tag, cookie->c_apdu_max_size);
+
+ if (read_cc->tlv_fc.tag != 0x4) {
+ near_error("NDEF File not found") ;
+ err = -EINVAL ;
+ goto out_err;
+ }
+
+ err = ISO_Select((uint8_t *)&read_cc->tlv_fc.file_id,
+ LEN_ISO_CC_FILEID, 0, select_ndef_file, cookie);
+ if (err < 0) {
+ near_error("select ndef file req failed %d", err);
+ goto out_err;
+ }
+
+ g_free(read_cc);
+ return 0;
+
+out_err:
+ g_free(read_cc);
+ return t4_cookie_release(err, cookie);
+}
+
+static int select_cc_file(uint8_t *resp, int length, void *data)
+{
+ int err = 0;
+ struct t4_cookie *cookie = data;
+
+ if (length < 0) {
+ near_error("CC file select resp failed %d", length);
+ err = length;
+ goto out_err;
+ }
+
+ if (APDU_STATUS(resp + STATUS_WORD_1) != APDU_OK) {
+ near_error("CC file select response %02X",
+ resp[length - 1]);
+ err = -EIO;
+ goto out_err;
+ }
+
+ err = ISO_ReadBinary(0, LEN_ISO_CC_READ_SIZE, read_cc_file, cookie);
+ if (err < 0) {
+ near_error("read cc file req failed %d", err);
+ goto out_err;
+ }
+
+ return 0;
+
+out_err:
+ return t4_cookie_release(err, cookie);
+}
+
+static int select_iso_appname_v2(uint8_t *resp, int length, void *data)
+{
+ int err = 0;
+ struct t4_cookie *cookie = data;
+
+ if (length < 0) {
+ near_error("iso app select resp failed %d", length);
+ err = length;
+ goto out_err;
+ }
+
+ if (resp[NFC_STATUS] != 0x00) {
+ near_error("iso app select response %02X",
+ resp[length - 1]);
+ err = -EIO;
+ goto out_err;
+ }
+
+ err = ISO_Select(iso_cc_fileid, LEN_ISO_CC_FILEID, 0,
+ select_cc_file, cookie);
+ if (err < 0) {
+ near_error("select cc req failed %d", err);
+ goto out_err;
+ }
+
+ return 0;
+
+out_err:
+ return t4_cookie_release(err, cookie);
+}
+
+static int format_resp(uint8_t *resp, int length, void *data)
+{
+ int err = 0;
+ struct t4_cookie *cookie = data;
+ struct near_tag *tag;
+
+ DBG("");
+
+ if (length < 0) {
+ near_error("write data to ndef file resp failed %d", length);
+ err = length;
+ goto out_err;
+ }
+
+ if (APDU_STATUS(resp + 1) != PICC_LEVEL_APDU_OK) {
+ near_error("wrtie data to ndef file response %02X",
+ resp[length - 1]);
+ err = -EIO;
+ goto out_err;
+ }
+
+ tag = near_tag_get_tag(cookie->adapter_idx, cookie->target_idx);
+ if (tag == NULL) {
+ err = -EINVAL;
+ goto out_err;
+ }
+
+ DBG("Formatting is done");
+ near_tag_set_blank(tag, FALSE);
+
+ /*
+ * 1) Till now all commands which are used for formatting are
+ * at mifare desfire level. Now select iso appname_v2,
+ * cc file and ndef file with ISO 7816-4 commands.
+ * 2) Selecting ndef file means making sure that read write
+ * operations will perform on NDEF file.
+ */
+ err = ISO_Select(iso_appname_v2, ARRAY_SIZE(iso_appname_v2),
+ 0x4, select_iso_appname_v2, cookie);
+ if (err < 0) {
+ near_error("iso_select appnamev2 req failed %d", err);
+ goto out_err;
+ }
+
+ return 0;
+
+out_err:
+ return t4_cookie_release(err, cookie);
+}
+
+static int write_data_to_ndef_file(uint8_t *resp, int length, void *data)
+{
+ int err = 0;
+ struct t4_cookie *cookie = data;
+ uint8_t *cmd_data = NULL;
+ uint8_t cmd_data_length;
+ uint8_t ndef_file_offset[] = {0x00, 0x00, 0x00};
+ uint8_t empty_ndef_file_len[] = {0x02, 0x00, 0x00}; /* 000002h */
+ uint8_t ndef_nlen[] = {0x00, 0x00}; /* 0000h */
+
+ DBG("");
+
+ if (length < 0) {
+ near_error("create ndef file resp failed %d", length);
+ err = length;
+ goto out_err;
+ }
+
+ if (APDU_STATUS(resp + 1) != PICC_LEVEL_APDU_OK) {
+ near_error("create ndef file response %02X",
+ resp[length - 1]);
+ err = -EIO;
+ goto out_err;
+ }
+
+ /* Step8 : Write data to NDEF file ( no NDEF message) */
+ cmd_data_length = 1 /* File num */
+ + ARRAY_SIZE(ndef_file_offset)
+ + ARRAY_SIZE(empty_ndef_file_len)
+ + ARRAY_SIZE(ndef_nlen);
+
+ cmd_data = g_try_malloc0(cmd_data_length);
+ if (cmd_data == NULL) {
+ err = -ENOMEM;
+ goto out_err;
+ }
+
+ cmd_data[0] = DESFIRE_NDEF_FILE_NUM;
+ memcpy(cmd_data + 1, ndef_file_offset, ARRAY_SIZE(ndef_file_offset));
+ memcpy(cmd_data + 4, empty_ndef_file_len,
+ ARRAY_SIZE(empty_ndef_file_len));
+ memcpy(cmd_data + 7, ndef_nlen, ARRAY_SIZE(ndef_nlen));
+
+ err = ISO_send_cmd(PICC_CLASS, WRITE_DATA_TO_FILE,
+ 0x00, 0x00, cmd_data, cmd_data_length,
+ TRUE, format_resp, cookie);
+ if (err < 0) {
+ near_error("wrtie data to ndef file req failed %d", err);
+ goto out_err;
+ }
+
+ g_free(cmd_data);
+ return 0;
+
+out_err:
+ g_free(cmd_data);
+ return t4_cookie_release(err, cookie);
+}
+
+static int create_ndef_file(uint8_t *resp, int length, void *data)
+{
+ int err = 0;
+ struct t4_cookie *cookie = data;
+ struct desfire_std_file *ndef = NULL;
+ uint8_t iso_ndef_file_id[] = {0x04, 0xE1}; /* E104h */
+ uint8_t ndef_file_access_rights[] = {0xE0, 0xEE}; /* EEE0h */
+
+ DBG("");
+
+ if (length < 0) {
+ near_error("write data to cc file resp failed %d", length);
+ err = length;
+ goto out_err;
+ }
+
+ if (APDU_STATUS(resp + 1) != PICC_LEVEL_APDU_OK) {
+ near_error("write data to cc file response %02X",
+ resp[length - 1]);
+ err = -EIO;
+ goto out_err;
+ }
+
+ ndef = g_try_malloc0(sizeof(struct desfire_std_file));
+ if (ndef == NULL) {
+ err = -ENOMEM;
+ goto out_err;
+ }
+
+ ndef->file_num = DESFIRE_NDEF_FILE_NUM;
+ memcpy(ndef->file_id, iso_ndef_file_id, ARRAY_SIZE(iso_ndef_file_id));
+ ndef->comm_set = DESFIRE_COMMSET;
+ memcpy(ndef->access_rights, ndef_file_access_rights,
+ ARRAY_SIZE(ndef_file_access_rights));
+ ndef->size[0] = 0;
+ ndef->size[1] = (uint8_t) (cookie->memory_size >> 8);
+ ndef->size[2] = (uint8_t) cookie->memory_size;
+
+ err = ISO_send_cmd(PICC_CLASS, CREATE_STD_DATA_FILE,
+ 0x00, 0x00, (uint8_t *)ndef,
+ sizeof(struct desfire_std_file),
+ TRUE, write_data_to_ndef_file, cookie);
+ if (err < 0) {
+ near_error("create ndef file req failed %d", err);
+ goto out_err;
+ }
+
+ g_free(ndef);
+ return 0;
+
+out_err:
+ g_free(ndef);
+ return t4_cookie_release(err, cookie);
+}
+
+static int write_data_to_cc_file(uint8_t *resp, int length, void *data)
+{
+ int err = 0;
+ struct t4_cookie *cookie = data;
+ struct desfire_cc_file *cc = NULL;
+ uint8_t cc_file_offset[] = {0x00, 0x00, 0x00};
+ uint8_t cc_file_max_len[] = {0x0F, 0x00, 0x00}; /* 00000Fh */
+ uint8_t cc_len[] = {0x00, 0x0F}; /* 000Fh*/
+ uint8_t mle_r_apdu[] = {0x00, 0x3B}; /* 003Bh */
+ uint8_t mlc_c_apdu[] = {0x00, 0x34}; /* 0034h */
+ /* T: 04, L: 06: V: E104h (NDEF ISO FID = E104h)*/
+ uint8_t ndef_tlv[] = {0x04, 0x06, 0xE1, 0x04};
+
+
+ DBG("");
+
+ if (length < 0) {
+ near_error("create cc file resp failed %d", length);
+ err = length;
+ goto out_err;
+ }
+
+ if (APDU_STATUS(resp + 1) != PICC_LEVEL_APDU_OK) {
+ near_error("create cc file response %02X",
+ resp[length - 1]);
+ err = -EIO;
+ goto out_err;
+ }
+
+ cc = g_try_malloc0(sizeof(struct desfire_cc_file));
+ if (cc == NULL) {
+ err = -ENOMEM;
+ goto out_err;
+ }
+
+ cc->file_num = DESFIRE_CC_FILE_NUM;
+ memcpy(cc->offset, cc_file_offset, ARRAY_SIZE(cc_file_offset));
+ memcpy(cc->max_len, cc_file_max_len, ARRAY_SIZE(cc_file_max_len));
+ memcpy(cc->cc_len, cc_len, ARRAY_SIZE(cc_len));
+ cc->version = MAPPING_VERSION;
+ memcpy(cc->mle, mle_r_apdu, ARRAY_SIZE(mle_r_apdu));
+ memcpy(cc->mlc, mlc_c_apdu, ARRAY_SIZE(mlc_c_apdu));
+ memcpy(cc->ndef_tlv, ndef_tlv, ARRAY_SIZE(ndef_tlv));
+ cc->ndef_size[0] = (uint8_t) (cookie->memory_size >> 8);
+ cc->ndef_size[1] = (uint8_t) cookie->memory_size;
+ cc->read_access = FREE_READ_ACCESS;
+ cc->write_access = FREE_WRITE_ACCESS;
+
+ err = ISO_send_cmd(PICC_CLASS, WRITE_DATA_TO_FILE,
+ 0x00, 0x00, (uint8_t *)cc,
+ sizeof(struct desfire_cc_file),
+ TRUE, create_ndef_file, cookie);
+ if (err < 0) {
+ near_error("write data to cc file req failed %d", err);
+ goto out_err;
+ }
+
+ g_free(cc);
+ return 0;
+
+out_err:
+ g_free(cc);
+ return t4_cookie_release(err, cookie);
+}
+
+static int create_cc_file(uint8_t *resp, int length, void *data)
+{
+ int err = 0;
+ struct t4_cookie *cookie = data;
+ struct desfire_std_file *cc = NULL;
+ uint8_t iso_cc_file_id[] = {0x03, 0xe1}; /* E103h */
+ uint8_t cc_file_access_rights[] = {0xE0, 0xEE}; /* EEE0h */
+ uint8_t cc_file_max_len[] = {0x0F, 0x00, 0x00}; /* 00000Fh */
+
+ DBG("");
+
+ if (length < 0) {
+ near_error("select application1 resp failed %d", length);
+ err = length;
+ goto out_err;
+ }
+
+ if (APDU_STATUS(resp + 1) != PICC_LEVEL_APDU_OK) {
+ near_error("select application1 response %02X",
+ resp[length - 1]);
+ err = -EIO;
+ goto out_err;
+ }
+
+ cc = g_try_malloc0(sizeof(struct desfire_std_file));
+ if (cc == NULL) {
+ err = -ENOMEM;
+ goto out_err;
+ }
+
+ cc->file_num = DESFIRE_CC_FILE_NUM;
+ memcpy(cc->file_id, iso_cc_file_id, ARRAY_SIZE(iso_cc_file_id));
+ cc->comm_set = DESFIRE_COMMSET;
+ memcpy(cc->access_rights, cc_file_access_rights,
+ ARRAY_SIZE(cc_file_access_rights));
+ memcpy(cc->size, cc_file_max_len, ARRAY_SIZE(cc_file_max_len));
+
+ err = ISO_send_cmd(PICC_CLASS,
+ CREATE_STD_DATA_FILE,
+ 0x00, 0x00, (uint8_t *)cc,
+ sizeof(struct desfire_std_file),
+ TRUE, write_data_to_cc_file, cookie);
+ if (err < 0) {
+ near_error("create cc file req failed %d", err);
+ goto out_err;
+ }
+
+ g_free(cc);
+ return 0;
+
+out_err:
+ g_free(cc);
+ return t4_cookie_release(err, cookie);
+}
+
+static int select_application_1(uint8_t *resp, int length, void *data)
+{
+ int err = 0;
+ struct t4_cookie *cookie = data;
+ uint8_t *cmd_data = NULL;
+ uint8_t cmd_data_length;
+ uint8_t desfire_aid_1[] = {0x01, 0x00, 0x00}; /* 000001h */
+
+ DBG("");
+
+ if (length < 0) {
+ near_error("create application resp failed %d", length);
+ err = length;
+ goto out_err;
+ }
+
+ if (APDU_STATUS(resp + 1) != PICC_LEVEL_APDU_OK) {
+ near_error("create application response %02X",
+ resp[length - 1]);
+ err = -EIO;
+ goto out_err;
+ }
+
+ /* Step4 : Select application (which is created just now) */
+ cmd_data_length = ARRAY_SIZE(desfire_aid_1);
+ cmd_data = g_try_malloc0(cmd_data_length);
+ if (cmd_data == NULL) {
+ err = -ENOMEM;
+ goto out_err;
+ }
+
+ memcpy(cmd_data, desfire_aid_1, cmd_data_length);
+ err = ISO_send_cmd(PICC_CLASS, SELECT_APPLICATION,
+ 0x00, 0x00, cmd_data, cmd_data_length,
+ TRUE, create_cc_file, cookie);
+ if (err < 0) {
+ near_error("select application1 req failed %d", err);
+ goto out_err;
+ }
+
+ g_free(cmd_data);
+ return 0;
+
+out_err:
+ g_free(cmd_data);
+ return t4_cookie_release(err, cookie);
+}
+
+static int create_application(uint8_t *resp, int length, void *data)
+{
+ int err = 0;
+ struct t4_cookie *cookie = data;
+ uint8_t desfire_aid_1[] = {0x01, 0x00, 0x00}; /* 000001h */
+ uint8_t desfire_file_id[] = {0x10, 0xE1}; /* E110h */
+ struct desfire_app *app = NULL;
+
+ DBG("");
+
+ if (length < 0) {
+ near_error("select application resp failed %d", length);
+ err = length;
+ goto out_err;
+ }
+
+ if (APDU_STATUS(resp + 1) != PICC_LEVEL_APDU_OK) {
+ near_error("select application response %02X",
+ resp[length - 1]);
+ err = -EIO;
+ goto out_err;
+ }
+
+ app = g_try_malloc0(sizeof(struct desfire_app));
+ if (app == NULL) {
+ err = -ENOMEM;
+ goto out_err;
+ }
+
+ memcpy(app->aid, desfire_aid_1, ARRAY_SIZE(desfire_aid_1));
+ app->key_settings = DESFIRE_KEY_SETTINGS;
+ app->number_of_keys = DESFIRE_NUM_OF_KEYS;
+ memcpy(app->file_id, desfire_file_id, ARRAY_SIZE(desfire_file_id));
+ memcpy(app->iso_appname, iso_appname_v2, ARRAY_SIZE(iso_appname_v2));
+
+ /* Step3 : Create Application */
+ err = ISO_send_cmd(PICC_CLASS, CREATE_APPLICATION,
+ 0x00, 0x00, (uint8_t *)app,
+ sizeof(struct desfire_app),
+ TRUE, select_application_1, cookie);
+ if (err < 0) {
+ near_error("create application req failed %d", err);
+ goto out_err;
+ }
+
+ g_free(app);
+ return 0;
+
+out_err:
+ g_free(app);
+ return t4_cookie_release(err, cookie);
+}
+
+static int select_application(uint8_t *resp, int length, void *data)
+{
+ int err;
+ struct t4_cookie *cookie = data;
+ uint8_t *cmd_data = NULL;
+ uint8_t cmd_data_length;
+ uint8_t desfire_aid[] = {0x00, 0x00, 0x00}; /* 000000h */
+
+ DBG("");
+
+ if (length < 0) {
+ near_error("get version3 resp failed %d", length);
+ err = length;
+ goto out_err;
+ }
+
+ if (resp[length - 1] != 0x00) {
+ near_error("get version3 response %02X",
+ resp[length - 1]);
+ err = -EIO;
+ goto out_err;
+ }
+
+ /* AID : 000000h */
+ cmd_data_length = ARRAY_SIZE(desfire_aid);
+ cmd_data = g_try_malloc0(cmd_data_length);
+ if (cmd_data == NULL) {
+ err = -ENOMEM;
+ goto out_err;
+ }
+
+ memcpy(cmd_data, desfire_aid, cmd_data_length);
+ /* Step2 : Select Application */
+ err = ISO_send_cmd(PICC_CLASS,
+ SELECT_APPLICATION,
+ 0x00, 0x00, cmd_data, cmd_data_length,
+ TRUE, create_application, cookie);
+ if (err < 0) {
+ near_error("select application req failed %d", err);
+ goto out_err;
+ }
+
+ g_free(cmd_data);
+ return 0;
+
+out_err:
+ g_free(cmd_data);
+ return t4_cookie_release(err, cookie);
+}
+
+static int get_version_frame3(uint8_t *resp, int length, void *data)
+{
+ int err;
+ struct t4_cookie *cookie = data;
+
+ DBG("");
+
+ if (length < 0) {
+ near_error("get version2 resp failed %d", length);
+ err = length;
+ goto out_err;
+ }
+
+ if (resp[4] == 0x01 /* Major Version */
+ && resp[length - 1] == GET_VERSION_FRAME_RESPONSE_BYTE) {
+
+ err = ISO_send_cmd(PICC_CLASS,
+ GET_VERSION_FRAME_RESPONSE_BYTE,
+ 0x00, 0x00, NULL, 0, FALSE,
+ select_application, cookie);
+ if (err < 0) {
+ near_error("get version3 req failed %d", err);
+ goto out_err;
+ }
+ } else {
+ near_error("get version2 response %02X", resp[length - 1]);
+ err = -EIO;
+ goto out_err;
+ }
+
+ return 0;
+
+out_err:
+ return t4_cookie_release(err, cookie);
+}
+
+static int get_version_frame2(uint8_t *resp, int length, void *data)
+{
+ int err;
+ struct t4_cookie *cookie = data;
+
+ DBG("");
+
+ if (length < 0) {
+ near_error(" get version resp failed %d", length);
+ err = length;
+ goto out_err;
+ }
+
+ if (resp[4] == 0x01 /* Major Version */
+ && resp[length - 1] == GET_VERSION_FRAME_RESPONSE_BYTE) {
+
+ cookie->memory_size = MIFARE_DESFIRE_EV1_SIZE(resp[6]);
+ err = ISO_send_cmd(PICC_CLASS,
+ GET_VERSION_FRAME_RESPONSE_BYTE,
+ 0x00, 0x00, NULL, 0, FALSE,
+ get_version_frame3, cookie);
+ if (err < 0) {
+ near_error("get version2 req failed %d", err);
+ goto out_err;
+ }
+ } else {
+ near_error("get version response %02X", resp[length - 1]);
+ err = -EIO;
+ goto out_err;
+ }
+
+ return 0;
+
+out_err:
+ return t4_cookie_release(err, cookie);
+}
+
+/* Steps to format Type 4 (MIFARE DESFire EV1) tag as per AN1104.pdf from nxp.
+ * 1) Get version to determine memory size of tag
+ * 2) Select applciation with AID equal to 000000h (PICC level)
+ * 3) Create application with AID equal to 000001h
+ * 4) Select application (Select previously created application in step3)
+ * 5) Create std data file with File number equal to 01h (CC file), ISOFileID
+ * equal to E103h, ComSet equal to 00h, AccesRights to EEEEh, FileSize bigger
+ * equal to 00000Fh
+ * 6) Write data to CC file with CCLEN equal to 000Fh, Mapping version equal to
+ * 20h, MLe equal to 003Bh, MLc equal to 0034h, and NDEF File control TLV
+ * equal to: T=04h, L=06h, V=E1 04 (NDEF ISO FID = E104h), 08 00 (NDEF File
+ * size = 2048 Bytes) 00 (free read access) 00 (free write access)
+ * 7) Create std data file with File number equal to 02h (NDEF File DESFireFId),
+ * ISO FileID equal to E104h, ComSet equal to 00h, ComSet equal to 00h,
+ * AccessRights equal to EEE0h, FileSize equal to 000800h (2048 bytes)
+ * 8) Write data to write content of the NDEF File with NLEN equal to 0000h, and
+ * no NDEF messsage.
+ * 9) Now Formatting is done, then select ISO appname2, select CC file and read.
+ * 10) Select NDEF file (by doing last two steps means, making sure that read
+ * write operations perform on NDEF file).
+ * */
+
+static int nfctype4_format(uint32_t adapter_idx, uint32_t target_idx,
+ near_tag_io_cb cb)
+{
+ int err;
+ struct t4_cookie *cookie;
+
+ DBG("");
+
+ cookie = g_try_malloc0(sizeof(struct t4_cookie));
+ if (cookie == NULL)
+ return -ENOMEM;
+
+ cookie->adapter_idx = adapter_idx;
+ cookie->target_idx = target_idx;
+ cookie->cb = cb;
+
+ /* Step1 : Get Version */
+ err = ISO_send_cmd(PICC_CLASS, GET_VERSION,
+ 0x00, 0x00, NULL, 0, FALSE,
+ get_version_frame2, cookie);
+
+ if (err < 0) {
+ near_error("get version req failed %d", err);
+ g_free(cookie);
+ }
+
+ return err;
+}
+
static struct near_tag_driver type4_driver = {
.type = NFC_PROTO_ISO14443,
.priority = NEAR_TAG_PRIORITY_DEFAULT,
.read = nfctype4_read,
.write = nfctype4_write,
.check_presence = nfctype4_check_presence,
+ .format = nfctype4_format,
};
static int nfctype4_init(void)