+ver 0.7
+ Added support for Android Jelly Bean handover.
+ Added a Bluetooth handover automated script.
+ Added MIFARE Classic writing support.
+ Added MIFARE read only check support.
+ Added MIFARE check presence support.
+ Fixed a tag writing related double free.
+ Fixed tag plugins memory leaks.
+ Fixed tag plugins callback calls code paths.
+ Fixed URI NDEF writing.
+
ver 0.6
Added tag formatting support for Type 1, 3 an 4.
Added blank tag detection for Type 1, 3 and 4.
AC_PREREQ(2.60)
-AC_INIT(neard, 0.6)
+AC_INIT(neard, 0.7)
AM_INIT_AUTOMAKE([foreign subdir-objects color-tests])
AM_CONFIG_HEADER(config.h)
#include <unistd.h>
typedef int (*near_recv)(uint8_t *resp, int length, void *data);
+typedef int (*near_release)(int err, void *data);
int near_adapter_connect(uint32_t idx, uint32_t target_idx, uint8_t protocol);
int near_adapter_disconnect(uint32_t idx);
-int near_adapter_send(uint32_t idx, uint8_t *buf, size_t length, near_recv rx_cb, void *data);
+int near_adapter_send(uint32_t idx, uint8_t *buf, size_t length,
+ near_recv rx_cb, void *data, near_release data_rel);
int near_adapter_recv(uint32_t idx, uint8_t *buf, size_t length);
#endif
+* Wed Oct 10 2012 Olivier < olivier.guiter@intel.com> - 0.7
+- Upgrade to version 0.7
* Tue Aug 28 2012 Arron < arron.wang@intel.com> - 0.6
- Upgrade to version 0.6
+
%define kernel_target adaptation-intel-automotive
Name: neard
Summary: Near Field Communication Manager
-Version: 0.6
-Release: 7
+Version: 0.7
+Release: 1
Group: System Environment/Daemons
License: GPLv2
Source0: http://www.kernel.org/pub/linux/network/nfc/%{name}-%{version}.tar.bz2
#define NFC_1ST_BLOCK 0x04 /* Sectors from 1 are for NFC */
+#define ACC_BITS_LEN 3
+
+/* Access bits for data blocks mask */
+static uint8_t DATA_access_mask[] = {0x77, 0x77, 0x77};
+
+/* Write with key A access bits configuration */
+static uint8_t WRITE_with_key_A[] = {0x77, 0x07, 0x00};
+
/* MAD1 sector structure. Start at block 0x00 */
struct MAD_1 {
uint8_t man_info[16];
struct near_tag *tag;
near_tag_io_cb cb;
near_recv next_far_func;
- int (*command)(void *data); /* read or write after unlocking sector */
/* For MAD access */
struct MAD_1 *mad_1;
/* For write only */
struct near_ndef_message *ndef; /* message to write */
size_t ndef_length; /* message length */
+
+ /* For access check */
+ int (*acc_check_function)(void *data); /* acc check fnc */
+ uint8_t *acc_bits_mask; /* blocks to check */
+ uint8_t *acc_rights; /* condition */
+ int (*acc_denied_fct)(void *data);/* fnc to call on access denial */
+ GSList *acc_sect; /* sector from g_sect_list to check */
};
struct type2_cmd {
return near_adapter_send(cookie->adapter_idx, (uint8_t *)&cmd,
sizeof(cmd) - NFC_NFCID1_MAXSIZE + cookie->nfcid1_len,
- next_far_fct,
- cookie);
+ next_far_fct, cookie, mifare_release);
}
/*
cmd.cmd = MF_CMD_READ; /* MIFARE READ */
cmd.block = block_id;
- return near_adapter_send(mf_ck->adapter_idx,
- (uint8_t *) &cmd, 2,
- far_func, data);
+ return near_adapter_send(mf_ck->adapter_idx, (uint8_t *) &cmd, 2,
+ far_func, mf_ck, mifare_release);
+}
+
+/*
+ * Check access rights
+ * Function processes sector trailer received from tag and checks access rights.
+ * In case specified access isn't granted it calls appropriate
+ * access denial function.
+ * If access is granted, previous action (e.g. read, write) is continued.
+ */
+static int mifare_check_rights_cb(uint8_t *resp, int length, void *data)
+{
+ struct mifare_cookie *mf_ck = data;
+ int err;
+ uint8_t *c;
+ int i;
+
+ if (length < 0) {
+ err = length;
+ goto out_err;
+ }
+
+ /* skip reader byte and key A */
+ c = resp + 1 + MAD_KEY_LEN;
+
+ for (i = 0; i < ACC_BITS_LEN; i++) {
+ if ((c[i] & mf_ck->acc_bits_mask[i]) != mf_ck->acc_rights[i]) {
+ (*mf_ck->acc_denied_fct)(data);
+ return 0;
+ }
+ }
+
+ /* Continue previous action (read/write) */
+ err = (*mf_ck->rws_next_fct)(resp, length, data);
+
+ if (err < 0)
+ goto out_err;
+
+ return err;
+
+out_err:
+ return mifare_release(err, mf_ck);
+}
+
+/* Calls to mifare_read_block to get sector trailer */
+static int mifare_check_rights(uint8_t *resp, int length, void *data)
+{
+ struct mifare_cookie *mf_ck = data;
+ int err;
+
+ err = mifare_read_block(mf_ck->rws_block_start, mf_ck,
+ mifare_check_rights_cb);
+
+ if (err < 0)
+ return mifare_release(err, mf_ck);
+
+ return err;
}
static int mifare_read_sector_cb(uint8_t *resp, int length, void *data)
if (length < 0) {
err = length;
- return err;
+ goto out_err;
}
/* And run the read process on the first block of the sector */
err = mifare_read_block(mf_ck->rws_block_start, data,
return err;
out_err:
- return err;
+ return mifare_release(err, mf_ck);
}
/*
if (length < 0) {
err = length;
- return err;
+ goto out_err;
}
/* ptr to the next read ptr */
/* Additional sectors to read ? */;
- if (mf_ck->g_sect_list->next != NULL) {
+ if (mf_ck->g_sect_list != NULL && mf_ck->g_sect_list->next != NULL) {
err = mifare_read_sector(data, /* cookie */
mf_ck->nfc_data, /* where to store */
}
/* Prepare read NFC loop */
-static int mifare_read_NFC(void *data)
+static int mifare_read_NFC(uint8_t *resp, int length, void *data)
{
struct mifare_cookie *mf_ck = data;
int err;
int i;
int global_tag_size = 0;
int ioffset;
+ uint8_t *tag_data;
+ size_t data_size;
DBG("");
goto out_err;
}
- for (i = 0; i < MAD_V1_AIDS_LEN; i++) {
+ /* Skip non-NFC sectors at the beginning of the tag, if any */
+ for (i = 0 ; i < MAD_V1_AIDS_LEN; i++) {
+ if (mf_ck->mad_1->aids[i] == NFC_AID_TAG)
+ break;
+ }
+
+ /*
+ * NFC sectors have to be continuous,
+ * so only some sectors at the beginning and at the end of tag
+ * can be non-NFC.
+ */
+ for (; i < MAD_V1_AIDS_LEN; i++) {
if (mf_ck->mad_1->aids[i] != NFC_AID_TAG)
- continue;
+ goto done_mad;
/* Save in the global list */
mf_ck->g_sect_list = g_slist_append(mf_ck->g_sect_list,
if (mf_ck->mad_2 == NULL)
goto done_mad;
- for (i = 0; i < MAD_V2_AIDS_LEN; i++) {
+ /*
+ * If all sectors from MAD1 were non-NFC,
+ * skip initial non-NFC sectors from MAD2
+ */
+ i = 0;
+
+ if (global_tag_size == 0)
+ for (; i < MAD_V2_AIDS_LEN; i++)
+ if (mf_ck->mad_2->aids[i] == NFC_AID_TAG)
+ break;
+
+ for (; i < MAD_V2_AIDS_LEN; i++) {
if (mf_ck->mad_2->aids[i] != NFC_AID_TAG)
- continue;
+ goto done_mad;
mf_ck->g_sect_list = g_slist_append( mf_ck->g_sect_list,
GINT_TO_POINTER(ioffset + i));
}
done_mad:
+ if (global_tag_size == 0) {
+
+ /* no NFC sectors - mark tag as blank */
+ near_error("TAG Global size: [%d], not valid NFC tag.",
+ global_tag_size);
+ return -ENODEV;
+ }
+
/* n sectors, each sector is 3 blocks, each block is 16 bytes */
DBG("TAG Global size: [%d]", global_tag_size);
- err = near_tag_add_data(mf_ck->adapter_idx,
- mf_ck->target_idx,
- NULL, /* Empty */
- global_tag_size);
- if (err < 0)
- goto out_err;
-
mf_ck->tag = near_tag_get_tag(mf_ck->adapter_idx, mf_ck->target_idx);
if (mf_ck->tag == NULL) {
err = -ENOMEM;
goto out_err;
}
- /* Time to read or write the NFC data */
- err = mf_ck->command(mf_ck);
+ /* don't allocate new data before writing */
+ tag_data = near_tag_get_data(mf_ck->tag, &data_size);
+ if (tag_data == NULL) {
+ err = near_tag_add_data(mf_ck->adapter_idx,
+ mf_ck->target_idx,
+ NULL, /* Empty */
+ global_tag_size);
+
+ if (err < 0)
+ goto out_err;
+ }
+
+ /* Check access rights */
+ err = mf_ck->acc_check_function(data);
+
+ if (err < 0)
+ goto out_err;
return err;
return mifare_release(err, mf_ck);
}
+/* If first NFC sector isn't writable, mark whole tag as read only */
+static int is_read_only(void *data)
+{
+ struct mifare_cookie *mf_ck = data;
+
+ DBG("Tag is read only");
+
+ near_tag_set_ro(mf_ck->tag, TRUE);
+
+ /* Continue previous action (read) */
+ (*mf_ck->rws_next_fct)(NULL, 0, data);
+
+ return 0;
+}
+
+
+static int mifare_check_read_only(void *data)
+{
+ struct mifare_cookie *mf_ck = data;
+ int err;
+
+ DBG("");
+
+ /*
+ * As authorisation with key B is not supported,
+ * in case writing with key A is not permitted, tag is read-only
+ */
+ mf_ck->acc_bits_mask = DATA_access_mask;
+ mf_ck->acc_rights = WRITE_with_key_A;
+
+ /* Check acces rights of first NFC sector */
+ mf_ck->rws_block_start = NFC_1ST_BLOCK + STD_BLK_PER_SECT;
+ /* Afterwards read tag */
+ mf_ck->rws_next_fct = mifare_read_NFC;
+ /* In case of writing access denial, set read only */
+ mf_ck->acc_denied_fct = is_read_only;
+
+ err = mifare_unlock_sector(mf_ck->rws_block_start,
+ mifare_check_rights, mf_ck);
+
+ if (err < 0)
+ return mifare_release(err, mf_ck);
+
+ return err;
+}
+
/*
* MIFARE: entry point:
* Read all the MAD sectors (0x00, 0x10) to get the Application Directory
cookie->adapter_idx = adapter_idx;
cookie->target_idx = target_idx;
cookie->cb = cb;
- cookie->command = mifare_read_NFC;
+
+ /* check access rights - while reading just check read only */
+ cookie->acc_check_function = mifare_check_read_only;
/*
* Need to unlock before reading
DBG("%d", length);
- if (length < 0)
+ if (length < 0) {
err = -EIO;
+ goto out;
+ }
if (cookie->cb)
cookie->cb(cookie->adapter_idx, cookie->target_idx, err);
- return err;
+out:
+ return mifare_release(err, cookie);
}
int mifare_check_presence(uint32_t adapter_idx, uint32_t target_idx,
struct mifare_cmd cmd;
struct mifare_cookie *cookie;
uint8_t *key_ref = MAD_public_key;
- int err;
DBG("");
/* add the UID */
memcpy(&cmd.nfcid, cookie->nfcid1, cookie->nfcid1_len);
- err = near_adapter_send(cookie->adapter_idx,
+ return near_adapter_send(cookie->adapter_idx,
(uint8_t *) &cmd,
sizeof(cmd) - NFC_NFCID1_MAXSIZE + cookie->nfcid1_len,
check_presence,
- cookie);
-
- if (err < 0)
- goto out_err;
-
- return err;
-
-out_err:
- mifare_release(err, cookie);
-
- return err;
+ cookie, mifare_release);
}
/*
return near_adapter_send(mf_ck->adapter_idx,
(uint8_t *) &cmd, sizeof(cmd),
- far_func, data);
+ far_func, data, NULL);
}
static int mifare_correct_length_cb(uint8_t *resp, int length, void *data)
static int mifare_write_sector_unlocked(uint8_t *resp, int length, void *data)
{
struct mifare_cookie *mf_ck = data;
+ int err;
+
+ if (length < 0) {
+ err = length;
+ goto out_err;
+ }
/* Run the write process on the first block of the sector */
- return mifare_write_block(mf_ck->rws_block_start, data,
- mifare_write_sector_cb);
+ err = mifare_write_block(mf_ck->rws_block_start, data,
+ mifare_write_sector_cb);
+
+ if (err < 0)
+ goto out_err;
+ return err;
+
+out_err:
+ return mifare_release(err, mf_ck);
}
/*
return err;
}
+static int mifare_check_rights_loop(uint8_t *resp, int length, void *data)
+{
+ struct mifare_cookie *mf_ck = data;
+ int err;
+ int sector_id;
+
+ if (mf_ck->acc_sect->next != NULL) {
+
+ mf_ck->acc_sect = mf_ck->acc_sect->next;
+ sector_id = GPOINTER_TO_INT(mf_ck->acc_sect->data);
+
+ if (sector_id < T4K_BOUNDARY)
+ mf_ck->rws_block_start = sector_id * 4
+ + STD_BLK_PER_SECT;
+ else
+ mf_ck->rws_block_start = T4K_BLK_OFF + EXT_BLK_PER_SECT
+ + (sector_id - T4K_BOUNDARY) * 16;
+
+ err = mifare_unlock_sector(mf_ck->rws_block_start,
+ mifare_check_rights, mf_ck);
+ } else {
+ /* Full access granted, start writing */
+ err = mifare_write_NFC(data);
+ }
+
+ if (err < 0)
+ return mifare_release(err, mf_ck);
+
+ return err;
+}
+
+
+/*
+ * If one of NFC sectors isn't writable,
+ * tag size for writing is smaller than actual memory size,
+ * so calculate it and check if it is enough for ndef message.
+ */
+static int writing_not_permitted(void *data)
+{
+ struct mifare_cookie *mf_ck = data;
+ unsigned int new_tag_size = 0;
+ int sector_id;
+ int i;
+
+ sector_id = GPOINTER_TO_INT(mf_ck->acc_sect->data);
+ DBG("Writing sector %i not permitted", sector_id);
+
+ /* Read only sector found, calculate new tag size */
+ if (sector_id <= MAD_V1_AIDS_LEN) {
+ for (i = GPOINTER_TO_INT(mf_ck->g_sect_list->data);
+ i < sector_id; i++)
+ new_tag_size += SECTOR_SIZE;
+ } else {
+ /* Start from first NFC sector */
+ for (i = GPOINTER_TO_INT(mf_ck->g_sect_list->data);
+ i <= MAD_V1_AIDS_LEN; i++)
+ new_tag_size += SECTOR_SIZE;
+
+ /*
+ * If any of previous sector was NFC, skip MAD2
+ * If not, leave "i" as it was
+ */
+ if (i < MAD2_SECTOR)
+ i = MAD2_SECTOR + 1;
+
+ for (; i < sector_id; i++) {
+ if (i < T4K_BOUNDARY)
+ new_tag_size += SECTOR_SIZE;
+ else
+ new_tag_size += BIG_SECTOR_SIZE;
+ }
+ }
+
+ DBG("TAG writable sectors' size: [%d].", new_tag_size);
+
+ /* Check if there's enough space on tag */
+ if (new_tag_size < mf_ck->ndef->length) {
+ near_error("Not enough space on tag");
+
+ if (mf_ck->cb)
+ mf_ck->cb(mf_ck->adapter_idx,
+ mf_ck->target_idx, -ENOSPC);
+
+ mifare_release(0, data);
+ return -ENOSPC;
+ }
+
+ /* Enough space on tag, continue writing */
+ mifare_write_NFC(data);
+
+ return 0;
+}
+
+static int mifare_check_rights_NFC(void *data)
+{
+ struct mifare_cookie *mf_ck = data;
+ int err;
+
+ DBG("");
+
+ /*
+ * As authorisation with key B is not supported,
+ * in case writing with key A is not permitted, tag is read-only
+ */
+ mf_ck->acc_bits_mask = DATA_access_mask;
+ mf_ck->acc_rights = WRITE_with_key_A;
+
+ mf_ck->acc_sect = mf_ck->g_sect_list;
+ mf_ck->rws_block_start = NFC_1ST_BLOCK + STD_BLK_PER_SECT;
+ mf_ck->rws_next_fct = mifare_check_rights_loop;
+
+ mf_ck->acc_denied_fct = writing_not_permitted;
+ err = mifare_unlock_sector(mf_ck->rws_block_start,
+ mifare_check_rights, mf_ck);
+
+ if (err < 0)
+ return mifare_release(err, mf_ck);
+
+ return err;
+}
+
int mifare_write(uint32_t adapter_idx, uint32_t target_idx,
struct near_ndef_message *ndef,
near_tag_io_cb cb, enum near_tag_sub_type tgt_subtype)
cookie->target_idx = target_idx;
cookie->cb = cb;
- cookie->command = mifare_write_NFC;
cookie->ndef = ndef;
/* Save ndef length */
cookie->ndef_length = cookie->ndef->data[1];
cookie->ndef->data[1] = 0;
+
+ /*
+ * Check if all sectors are writable
+ * if not, message may be too long to be written
+ */
+ cookie->acc_check_function = mifare_check_rights_NFC;
+
/*
* Mifare Classic Tag needs to be unlocked before writing
* This will check if public keys are allowed (NDEF could be "readable")
if (cookie == NULL)
return err;
+ if (cookie->cb != NULL)
+ cookie->cb(cookie->adapter_idx, cookie->target_idx, err);
+
if (cookie->ndef)
g_free(cookie->ndef->data);
uint8_t *tagdata;
size_t data_length;
- int err;
-
DBG("%d", length);
- if (length < 0) {
- err = length;
- goto out_err;
- }
+ if (length < 0)
+ return length;
length = length - LEN_STATUS_BYTE; /* ignore first byte */
t1_cmd.cmd = CMD_READ_SEGS;
t1_cmd.addr = (t1_tag->current_seg << 4) & 0xFF;
- err = near_adapter_send(t1_tag->adapter_idx,
+ return near_adapter_send(t1_tag->adapter_idx,
(uint8_t *) &t1_cmd, sizeof(t1_cmd),
- data_recv, t1_tag);
- if (err < 0)
- goto out_err;
+ data_recv, t1_tag, NULL);
} else { /* This is the end */
GList *records;
records = near_tlv_parse(tagdata, data_length);
near_tag_add_records(t1_tag->tag, records, t1_tag->cb, 0);
- err = 0;
-
/* free memory */
g_free(t1_tag);
- }
-out_err:
- return err;
+ return 0;
+ }
}
/*
return near_adapter_send(t1_tag->adapter_idx,
(uint8_t *)&t1_cmd, sizeof(t1_cmd),
- data_recv, t1_tag);
+ data_recv, t1_tag, NULL);
}
static int meta_recv(uint8_t *resp, int length, void *data)
} else if ((resp[OFFSET_HEADER_ROM] & 0xF0) == HR0_TYPE2_HIGH) {
near_tag_set_memory_layout(tag, NEAR_TAG_MEMORY_DYNAMIC);
err = read_dynamic_tag(cc, length, t1_tag);
+ /*
+ * As reading isn't complete,
+ * callback shouldn't be called while freeing the cookie
+ */
+ cookie->cb = NULL;
} else {
err = -EOPNOTSUPP;
}
out_err:
DBG("err %d", err);
- if (err < 0 && cookie->cb)
- cookie->cb(cookie->adapter_idx, cookie->target_idx, err);
-
return t1_cookie_release(err, cookie);
}
return near_adapter_send(cookie->adapter_idx,
(uint8_t *)&t1_cmd, sizeof(t1_cmd),
- meta_recv, cookie);
+ meta_recv, cookie, t1_cookie_release);
out_err:
DBG("err %d", err);
- if (err < 0 && cookie->cb)
- cookie->cb(cookie->adapter_idx, cookie->target_idx, err);
-
return t1_cookie_release(err, cookie);
}
{
struct type1_cmd cmd;
struct t1_cookie *cookie;
- int err;
DBG("");
memcpy(cmd.uid, uid, UID_LENGTH);
memcpy(cookie->uid, uid, UID_LENGTH);
- err = near_adapter_send(adapter_idx, (uint8_t *) &cmd,
- sizeof(cmd), meta_recv, cookie);
+ return near_adapter_send(adapter_idx, (uint8_t *) &cmd,
+ sizeof(cmd), meta_recv, cookie,
+ t1_cookie_release);
} else {
cmd.cmd = CMD_RID;
- err = near_adapter_send(adapter_idx, (uint8_t *) &cmd,
- sizeof(cmd), rid_resp, cookie);
+ return near_adapter_send(adapter_idx, (uint8_t *) &cmd,
+ sizeof(cmd), rid_resp, cookie,
+ t1_cookie_release);
}
-
- if (err < 0)
- t1_cookie_release(err, cookie);
-
- return err;
}
/* First step: RID to get the tag UID */
DBG("Done writing");
- cookie->cb(cookie->adapter_idx, cookie->target_idx, err);
-
return t1_cookie_release(err, cookie);
}
memcpy(cmd.uid, cookie->uid, UID_LENGTH);
return near_adapter_send(cookie->adapter_idx, (uint8_t *) &cmd,
- sizeof(cmd), write_nmn_e1_resp, cookie);
+ sizeof(cmd), write_nmn_e1_resp, cookie,
+ t1_cookie_release);
}
static int data_write_resp(uint8_t *resp, int length, void *data)
cookie->current_byte++;
err = near_adapter_send(cookie->adapter_idx, (uint8_t *) &cmd,
- sizeof(cmd), data_write_resp, cookie);
+ sizeof(cmd), data_write_resp, cookie,
+ NULL);
if (err < 0)
goto out_err;
return 0;
out_err:
- if (err < 0 && cookie->cb)
- cookie->cb(cookie->adapter_idx, cookie->target_idx, err);
-
return t1_cookie_release(err, cookie);
}
uid = near_tag_get_nfcid(adapter_idx, target_idx, &uid_length);
if (uid == NULL || uid_length != UID_LENGTH) {
near_error("Invalid type 1 UID");
- return -EINVAL;
+ err = -EINVAL;
+ goto out_err;
}
cmd.cmd = CMD_WRITE_E;
if (cookie == NULL) {
g_free(uid);
err = -ENOMEM;
- return err;
+ goto out_err;
}
cookie->adapter_idx = adapter_idx;
g_free(uid);
- err = near_adapter_send(cookie->adapter_idx, (uint8_t *) &cmd,
- sizeof(cmd), data_write_resp, cookie);
- if (err < 0)
- goto out_err;
-
- return 0;
-
+ return near_adapter_send(cookie->adapter_idx, (uint8_t *) &cmd,
+ sizeof(cmd), data_write_resp, cookie,
+ t1_cookie_release);
out_err:
- return t1_cookie_release(err, cookie);
+ if (cb != NULL)
+ cb(adapter_idx, target_idx, err);
+
+ return err;
}
/*
near_tag_io_cb cb)
{
struct near_tag *tag;
+ int err;
DBG("");
- if (ndef == NULL || cb == NULL)
- return -EINVAL;
+ if (ndef == NULL || cb == NULL) {
+ err = -EINVAL;
+ goto out_err;
+ }
tag = near_tag_get_tag(adapter_idx, target_idx);
- if (tag == NULL)
- return -EINVAL;
+ if (tag == NULL) {
+ err = -EINVAL;
+ goto out_err;
+ }
/* This check is valid for only static tags.
* Max data length on Type 1 Tag including TLV's
if (near_tag_get_memory_layout(tag) == NEAR_TAG_MEMORY_STATIC) {
if ((ndef->length + 3) > TYPE1_STATIC_MAX_DATA_SIZE) {
near_error("not enough space on tag");
- return -ENOSPC;
+ err = -ENOSPC;
+ goto out_err;
}
}
return data_write(adapter_idx, target_idx, ndef, cb);
+
+ if (err < 0)
+ goto out_err;
+
+ return 0;
+
+out_err:
+ if (cb != NULL)
+ cb(adapter_idx, target_idx, err);
+
+ return err;
}
static int check_presence(uint8_t *resp, int length, void *data)
if (length < 0)
err = -EIO;
- if (cookie->cb)
- cookie->cb(cookie->adapter_idx,
- cookie->target_idx, err);
-
return t1_cookie_release(err, cookie);
}
struct type1_cmd t1_cmd;
struct t1_cookie *cookie;
uint8_t *uid, uid_length;
- int err;
DBG("");
cookie->target_idx = target_idx;
cookie->cb = cb;
- err = near_adapter_send(adapter_idx, (uint8_t *) &t1_cmd,
- sizeof(t1_cmd), check_presence, cookie);
- if (err < 0)
- goto out_err;
-
- return 0;
-
-out_err:
- return t1_cookie_release(err, cookie);
+ return near_adapter_send(adapter_idx, (uint8_t *) &t1_cmd,
+ sizeof(t1_cmd), check_presence, cookie,
+ t1_cookie_release);
}
static int format_resp(uint8_t *resp, int length, void *data)
cookie->current_byte++;
memcpy(cmd.uid, cookie->uid, UID_LENGTH);
- err = near_adapter_send(cookie->adapter_idx, (uint8_t *) &cmd,
- sizeof(cmd), format_resp, cookie);
- if (err < 0)
- goto out_err;
-
- return 0;
+ return near_adapter_send(cookie->adapter_idx, (uint8_t *) &cmd,
+ sizeof(cmd), format_resp, cookie,
+ t1_cookie_release);
} else {
tag = near_tag_get_tag(cookie->adapter_idx, cookie->target_idx);
if (tag == NULL) {
}
out_err:
- if (cookie->cb)
- cookie->cb(cookie->adapter_idx, cookie->target_idx, err);
-
return t1_cookie_release(err, cookie);
}
g_free(uid);
err = near_adapter_send(cookie->adapter_idx, (uint8_t *) &cmd,
- sizeof(cmd), format_resp, cookie);
+ sizeof(cmd), format_resp, cookie,
+ t1_cookie_release);
if (err < 0)
goto out_err;
if (cookie == NULL)
return err;
+ if (cookie->cb != NULL)
+ cookie->cb(cookie->adapter_idx, cookie->target_idx, err);
+
if (cookie->ndef)
g_free(cookie->ndef->data);
return near_adapter_send(adapter_idx,
(uint8_t *) &cmd, CMD_READ_SIZE,
- data_recv, tag);
+ data_recv, tag, NULL);
}
static int data_read(struct type2_tag *tag)
adapter_idx = near_tag_get_adapter_idx(tag->tag);
return near_adapter_send(adapter_idx,
- (uint8_t *) &cmd, CMD_READ_SIZE,
- data_recv, tag);
+ (uint8_t *) &cmd, CMD_READ_SIZE,
+ data_recv, tag, NULL);
}
static int meta_recv(uint8_t *resp, int length, void *data)
if (err < 0)
goto out_tag;
+ /*
+ * As reading isn't complete,
+ * callback shouldn't be called while freeing the cookie
+ */
+ cookie->cb = NULL;
return t2_cookie_release(err, cookie);
out_tag:
g_free(t2_tag);
out_err:
- if (err < 0 && cookie->cb)
- cookie->cb(cookie->adapter_idx, cookie->target_idx, err);
-
return t2_cookie_release(err, cookie);
}
{
struct type2_cmd cmd;
struct t2_cookie *cookie;
- int err;
DBG("");
cookie->target_idx = target_idx;
cookie->cb = cb;
- err = near_adapter_send(adapter_idx, (uint8_t *) &cmd, CMD_READ_SIZE,
- meta_recv, cookie);
- if (err < 0)
- g_free(cookie);
-
- return err;
+ return near_adapter_send(adapter_idx, (uint8_t *) &cmd, CMD_READ_SIZE,
+ meta_recv, cookie, t2_cookie_release);
}
static int nfctype2_read(uint32_t adapter_idx,
uint32_t target_idx, near_tag_io_cb cb)
{
- int err;
enum near_tag_sub_type tgt_subtype;
DBG("");
switch (tgt_subtype) {
case NEAR_TAG_NFC_T2_MIFARE_ULTRALIGHT:
- err = nfctype2_read_meta(adapter_idx, target_idx, cb);
- break;
+ return nfctype2_read_meta(adapter_idx, target_idx, cb);
/* Specific Mifare read access */
case NEAR_TAG_NFC_T2_MIFARE_CLASSIC_1K:
case NEAR_TAG_NFC_T2_MIFARE_CLASSIC_4K:
- err = mifare_read(adapter_idx, target_idx,
+ return mifare_read(adapter_idx, target_idx,
cb, tgt_subtype);
- break;
default:
DBG("Unknown Tag Type 2 subtype %d", tgt_subtype);
- err = -1;
- break;
+ return -1;
}
-
- return err;
}
static int data_write_resp(uint8_t *resp, int length, void *data)
if (cookie->ndef->offset > cookie->ndef->length) {
DBG("Done writing");
- if (cookie->cb)
- cookie->cb(cookie->adapter_idx, cookie->target_idx, 0);
-
return t2_cookie_release(0, cookie);
}
cookie->ndef->offset = cookie->ndef->length + 1;
}
- err = near_adapter_send(cookie->adapter_idx, (uint8_t *) &cmd,
- sizeof(cmd), data_write_resp, cookie);
-
- if (err < 0)
- goto out_err;
-
- return 0;
+ return near_adapter_send(cookie->adapter_idx, (uint8_t *) &cmd,
+ sizeof(cmd), data_write_resp, cookie,
+ t2_cookie_release);
out_err:
- if (err < 0 && cookie->cb)
- cookie->cb(cookie->adapter_idx, cookie->target_idx, err);
-
return t2_cookie_release(err, cookie);
}
DBG("");
cookie = g_try_malloc0(sizeof(struct t2_cookie));
- if (cookie == NULL)
- return -ENOMEM;
+ if (cookie == NULL) {
+ err = -ENOMEM;
+ if (cb != NULL)
+ cb(adapter_idx, target_idx, err);
+ return err;
+ }
cookie->adapter_idx = adapter_idx;
cookie->target_idx = target_idx;
cookie->ndef->offset += BLOCK_SIZE;
cookie->current_block++;
- err = near_adapter_send(cookie->adapter_idx, (uint8_t *) &cmd,
- sizeof(cmd), data_write_resp, cookie);
-
- if (err < 0)
- goto out_err;
-
- return 0;
-
-out_err:
- return t2_cookie_release(err, cookie);
+ return near_adapter_send(cookie->adapter_idx, (uint8_t *) &cmd,
+ sizeof(cmd), data_write_resp, cookie,
+ t2_cookie_release);
}
static int nfctype2_write(uint32_t adapter_idx, uint32_t target_idx,
DBG("");
- if (ndef == NULL || cb == NULL)
- return -EINVAL;
+ if (ndef == NULL || cb == NULL) {
+ err = -EINVAL;
+ goto out_err;
+ }
tag = near_tag_get_tag(adapter_idx, target_idx);
- if (tag == NULL)
- return -EINVAL;
+ if (tag == NULL) {
+ err = -EINVAL;
+ goto out_err;
+ }
tgt_subtype = near_tag_get_subtype(adapter_idx, target_idx);
if (near_tag_get_memory_layout(tag) == NEAR_TAG_MEMORY_STATIC) {
if ((ndef->length + 3) > NDEF_MAX_SIZE) {
near_error("not enough space on tag");
- return -ENOSPC;
+ err = -ENOSPC;
+ goto out_err;
}
}
- err = data_write(adapter_idx, target_idx, ndef, cb);
- break;
- /* Specific Mifare write access */
+ return data_write(adapter_idx, target_idx, ndef, cb);
+
+ /* Specific Mifare write access */
case NEAR_TAG_NFC_T2_MIFARE_CLASSIC_1K:
case NEAR_TAG_NFC_T2_MIFARE_CLASSIC_4K:
- err = mifare_write(adapter_idx, target_idx, ndef,
+ return mifare_write(adapter_idx, target_idx, ndef,
cb, tgt_subtype);
- break;
default:
DBG("Unknown TAG Type 2 subtype %d", tgt_subtype);
err = -EINVAL;
- break;
+ goto out_err;
}
+ return 0;
+
+out_err:
+ if (cb != NULL)
+ cb(adapter_idx, target_idx, err);
+
return err;
}
if (length < 0)
err = -EIO;
- if (cookie->cb)
- cookie->cb(cookie->adapter_idx,
- cookie->target_idx, err);
-
return t2_cookie_release(err, cookie);
}
struct type2_cmd cmd;
struct t2_cookie *cookie;
enum near_tag_sub_type tgt_subtype;
- int err;
DBG("");
cookie->target_idx = target_idx;
cookie->cb = cb;
- err = near_adapter_send(adapter_idx, (uint8_t *) &cmd,
- CMD_READ_SIZE, check_presence, cookie);
- if (err < 0)
- goto out_err;
+ return near_adapter_send(adapter_idx, (uint8_t *) &cmd,
+ CMD_READ_SIZE, check_presence, cookie,
+ t2_cookie_release);
- break;
/* Specific Mifare check presence */
case NEAR_TAG_NFC_T2_MIFARE_CLASSIC_1K:
case NEAR_TAG_NFC_T2_MIFARE_CLASSIC_4K:
- err = mifare_check_presence(adapter_idx, target_idx,
+ return mifare_check_presence(adapter_idx, target_idx,
cb, tgt_subtype);
- break;
default:
DBG("Unknown TAG Type 2 subtype %d", tgt_subtype);
- err = -1;
- break;
- }
- return err;
-
-out_err:
- return t2_cookie_release(err, cookie);
+ return -1;
+ }
}
static int format_resp(uint8_t *resp, int length, void *data)
near_tag_set_blank(tag, FALSE);
out_err:
- if (cookie->cb)
- cookie->cb(cookie->adapter_idx, cookie->target_idx, err);
-
return t2_cookie_release(err, cookie);
}
memcpy(cmd.data, (uint8_t *) t2_cc, BLOCK_SIZE);
err = near_adapter_send(cookie->adapter_idx, (uint8_t *) &cmd,
- sizeof(cmd), format_resp, cookie);
+ sizeof(cmd), format_resp, cookie, NULL);
out_err:
if (err < 0) {
if (cookie == NULL)
return err;
+ if (cookie->cb != NULL)
+ cookie->cb(cookie->adapter_idx, cookie->target_idx, err);
+
if (cookie->ndef != NULL)
g_free(cookie->ndef->data);
/* common: Simple checks on received frame */
static int check_recv_frame(uint8_t *resp, uint8_t reply_code)
{
- int err = 0;
-
if (resp[OFS_NFC_STATUS] != 0) {
DBG("NFC Command failed: 0x%x", resp[OFS_NFC_STATUS]);
- err = -EIO;
+ return -EIO;
}
if (resp[OFS_CMD_RESP] != reply_code) {
DBG("Felica cmd failed: 0x%x", resp[OFS_CMD_RESP]);
- err = -EIO;
+ return -EIO;
}
- return err;
+ return 0;
}
static int data_recv(uint8_t *resp, int length, void *data)
tag->IDm, &cmd);
err = near_adapter_send(adapter_idx, (uint8_t *) &cmd, cmd.len,
- data_recv, tag);
+ data_recv, tag, NULL);
if (err < 0)
goto out_err;
return near_adapter_send(adapter_idx,
(uint8_t *) &cmd, cmd.len,
- data_recv, tag);
+ data_recv, tag, NULL);
}
/* Read block 0 to retrieve the data length */
err = data_read(t3_tag);
-out_err:
- if (err < 0) {
- if (cookie->cb)
- cookie->cb(cookie->adapter_idx, cookie->target_idx,
- err);
+ /*
+ * As reading isn't complete,
+ * callback shouldn't be called while freeing the cookie
+ */
+ if (err == 0)
+ cookie->cb = NULL;
+out_err:
+ if (err < 0)
g_free(t3_tag);
- }
return t3_cookie_release(err, cookie);
}
prepare_read_block(META_BLOCK_START, cookie->IDm, &cmd);
err = near_adapter_send(cookie->adapter_idx, (uint8_t *) &cmd,
- cmd.len, nfctype3_recv_block_0, cookie);
+ cmd.len, nfctype3_recv_block_0, cookie, NULL);
if (err < 0)
goto out_err;
return 0;
out_err:
- if (err < 0 && cookie->cb)
- cookie->cb(cookie->adapter_idx,
- cookie->target_idx, err);
-
return t3_cookie_release(err, cookie);
}
near_tag_set_ic_type(tag, cookie->ic_type);
near_tag_set_blank(tag, TRUE);
- if (cookie->cb)
- cookie->cb(cookie->adapter_idx,
- cookie->target_idx, 0);
-
return t3_cookie_release(0, cookie);
} else {
/* CMD POLL */
cmd.len = LEN_CMD + LEN_CMD_LEN + 4 ;
err = near_adapter_send(cookie->adapter_idx, (uint8_t *) &cmd,
- cmd.len , poll_ndef_system_code, cookie);
+ cmd.len , poll_ndef_system_code, cookie, NULL);
}
if (err < 0)
return 0;
out_err:
- if (err < 0 && cookie->cb)
- cookie->cb(cookie->adapter_idx, cookie->target_idx, err);
-
return t3_cookie_release(err, cookie);
}
prepare_read_block(FELICA_LITE_MC_BLOCK, cookie->IDm, &cmd);
err = near_adapter_send(cookie->adapter_idx, (uint8_t *) &cmd,
cmd.len, check_sys_op_in_mc_block,
- cookie);
+ cookie, NULL);
break;
case FELICA_LITE_S_IC_TYPE:
cmd.len = LEN_CMD + LEN_CMD_LEN + 4 ;
err = near_adapter_send(cookie->adapter_idx, (uint8_t *) &cmd,
- cmd.len, poll_ndef_system_code, cookie);
+ cmd.len, poll_ndef_system_code, cookie,
+ NULL);
}
if (err < 0)
return 0;
out_err:
- if (err < 0 && cookie->cb)
- cookie->cb(cookie->adapter_idx, cookie->target_idx, err);
-
return t3_cookie_release(err, cookie);
}
{
struct type3_cmd cmd;
struct t3_cookie *cookie;
- int err;
DBG("");
cookie->target_idx = target_idx;
cookie->cb = cb;
- err = near_adapter_send(adapter_idx, (uint8_t *) &cmd,
- cmd.len, receive_system_code, cookie);
- if (err < 0)
- g_free(cookie);
-
- return err;
+ return near_adapter_send(adapter_idx, (uint8_t *) &cmd, cmd.len,
+ receive_system_code, cookie,
+ t3_cookie_release);
}
static int update_attr_block_cb(uint8_t *resp, int length, void *data)
DBG("Done writing");
out_err:
- if (cookie->cb)
- cookie->cb(cookie->adapter_idx, cookie->target_idx, err);
-
return t3_cookie_release(err, cookie);
}
prepare_write_block(cookie->IDm, &cmd, 0, cookie->attr);
return near_adapter_send(cookie->adapter_idx, (uint8_t *) &cmd, cmd.len,
- update_attr_block_cb, cookie);
+ update_attr_block_cb, cookie,
+ t3_cookie_release);
}
static int data_write_resp(uint8_t *resp, int length, void *data)
cookie->ndef->offset += BLOCK_SIZE;
err = near_adapter_send(cookie->adapter_idx, (uint8_t *) &cmd, cmd.len,
- data_write_resp, cookie);
+ data_write_resp, cookie, NULL);
if (err < 0)
goto out_err;
return 0;
out_err:
- if (err < 0 && cookie->cb)
- cookie->cb(cookie->adapter_idx, cookie->target_idx, err);
-
return t3_cookie_release(err, cookie);
}
DBG("");
cookie = g_try_malloc0(sizeof(struct t3_cookie));
+
if (cookie == NULL) {
err = -ENOMEM;
- goto out_err;
+
+ if (cb != NULL)
+ cb(adapter_idx, target_idx, err);
+
+ return err;
}
cookie->adapter_idx = adapter_idx;
cookie->current_block = 0;
idm = near_tag_get_idm(tag, &len);
- if (idm == NULL) {
- err = -EINVAL;
- goto out_err;
- }
+ if (idm == NULL)
+ return t3_cookie_release(-EINVAL, cookie);
memcpy(cookie->IDm, idm, len);
attr = near_tag_get_attr_block(tag, &len);
- if (attr == NULL) {
- err = -EINVAL;
- goto out_err;
- }
+ if (attr == NULL)
+ return t3_cookie_release(-EINVAL, cookie);
memcpy(cookie->attr, attr, len);
nmaxb = (((uint16_t) (cookie->attr[3])) << 8) | cookie->attr[4];
if (cookie->ndef->length > (nmaxb * BLOCK_SIZE)) {
near_error("not enough space on tag");
- err = -ENOSPC;
- goto out_err;
+
+ return t3_cookie_release(-ENOSPC, cookie);
}
cookie->attr[9] = 0x0F; /* writing data in progress */
cookie->attr);
cookie->current_block++;
- err = near_adapter_send(adapter_idx, (uint8_t *) &cmd, cmd.len,
- data_write_resp, cookie);
- if (err < 0)
- goto out_err;
-
- return 0;
-
-out_err:
- return t3_cookie_release(err, cookie);
+ return near_adapter_send(adapter_idx, (uint8_t *) &cmd, cmd.len,
+ data_write_resp, cookie,
+ t3_cookie_release);
}
static int nfctype3_write(uint32_t adapter_idx, uint32_t target_idx,
near_tag_io_cb cb)
{
struct near_tag *tag;
+ int err;
DBG("");
- if (ndef == NULL || cb == NULL)
- return -EINVAL;
+ if (ndef == NULL || cb == NULL) {
+ err = -EINVAL;
+ goto out_err;
+ }
tag = near_tag_get_tag(adapter_idx, target_idx);
- if (tag == NULL)
- return -EINVAL;
+ if (tag == NULL) {
+ err = -EINVAL;
+ goto out_err;
+ }
+
+ err = data_write(adapter_idx, target_idx, ndef, tag, cb);
- return data_write(adapter_idx, target_idx, ndef, tag, cb);
+out_err:
+ if (cb != NULL)
+ cb(adapter_idx, target_idx, err);
+
+ return err;
}
static int check_presence(uint8_t *resp, int length, void *data)
if (length < 0)
err = -EIO;
- if (cookie->cb)
- cookie->cb(cookie->adapter_idx,
- cookie->target_idx, err);
-
return t3_cookie_release(err, cookie);
}
{
struct type3_cmd cmd;
struct t3_cookie *cookie;
- int err;
DBG("");
cookie->target_idx = target_idx;
cookie->cb = cb;
- err = near_adapter_send(adapter_idx, (uint8_t *) &cmd,
- cmd.len, check_presence, cookie);
-
- if (err < 0)
- goto out_err;
-
- return 0;
-
-out_err:
- return t3_cookie_release(err, cookie);
+ return near_adapter_send(adapter_idx, (uint8_t *) &cmd,
+ cmd.len, check_presence, cookie,
+ t3_cookie_release);
}
static int format_resp(uint8_t *resp, int length, void *data)
DBG("Formatting is done");
out_err:
- if (cookie->cb)
- cookie->cb(cookie->adapter_idx, cookie->target_idx, err);
-
return t3_cookie_release(err, cookie);
}
cookie->attr);
err = near_adapter_send(cookie->adapter_idx, (uint8_t *) &cmd,
- cmd.len, format_resp, cookie);
+ cmd.len, format_resp, cookie, NULL);
if (err < 0)
goto out_err;
return 0;
out_err:
- if (err < 0 && cookie->cb)
- cookie->cb(cookie->adapter_idx, cookie->target_idx, err);
-
return t3_cookie_release(err, cookie);
}
prepare_write_block(cookie->IDm, &cmd, FELICA_LITE_MC_BLOCK,
cookie->mc_block);
err = near_adapter_send(cookie->adapter_idx, (uint8_t *) &cmd,
- cmd.len, write_attr_block, cookie);
+ cmd.len, write_attr_block, cookie, NULL);
if (err < 0)
goto out_err;
return 0;
out_err:
- if (err < 0 && cookie->cb)
- cookie->cb(cookie->adapter_idx, cookie->target_idx, err);
-
return t3_cookie_release(err, cookie);
}
struct t3_cookie *cookie;
uint8_t ic_type;
uint8_t *idm, len;
- int err;
DBG("");
cookie->ic_type = ic_type;
idm = near_tag_get_idm(tag, &len);
- if (idm == NULL) {
- err = -EINVAL;
- goto out_err;
- }
+ if (idm == NULL)
+ return t3_cookie_release(-EINVAL, cookie);
memcpy(cookie->IDm, idm, len);
prepare_read_block(FELICA_LITE_MC_BLOCK, cookie->IDm, &cmd);
- err = near_adapter_send(cookie->adapter_idx, (uint8_t *) &cmd,
- cmd.len, write_mc_block, cookie);
- if (err < 0)
- goto out_err;
- return 0;
+ return near_adapter_send(cookie->adapter_idx, (uint8_t *) &cmd, cmd.len,
+ write_mc_block, cookie,
+ t3_cookie_release);
-out_err:
- return t3_cookie_release(err, cookie);
}
static struct near_tag_driver type1_driver = {
uint16_t memory_size;
};
+static int t4_cookie_release(int err, void *data)
+{
+ struct t4_cookie *cookie = data;
+
+ DBG("%p", cookie);
+
+ if (cookie == NULL)
+ return err;
+
+ if (err < 0 && cookie->cb)
+ cookie->cb(cookie->adapter_idx, cookie->target_idx, err);
+
+ if (cookie->ndef)
+ g_free(cookie->ndef->data);
+
+ g_free(cookie->ndef);
+ g_free(cookie);
+
+ return err;
+}
+
/* ISO functions: This code prepares APDU */
static int ISO_send_cmd(uint8_t class,
uint8_t instruction,
cmd->data[cmd_data_length] = 0;
}
- err = near_adapter_send(in_rcv->adapter_idx, (uint8_t *) cmd,
- total_cmd_length, cb, in_rcv);
- if (err < 0)
- g_free(in_rcv);
+ return near_adapter_send(in_rcv->adapter_idx, (uint8_t *) cmd,
+ total_cmd_length, cb, in_rcv,
+ t4_cookie_release);
out_err:
/* On exit, clean memory */
cookie);
}
-static int t4_cookie_release(int err, void *data)
-{
- struct t4_cookie *cookie = data;
-
- DBG("%p", cookie);
-
- if (cookie == NULL)
- return err;
-
- if (err < 0 && cookie->cb)
- cookie->cb(cookie->adapter_idx, cookie->target_idx, err);
-
- if (cookie->ndef)
- g_free(cookie->ndef->data);
-
- g_free(cookie->ndef);
- g_free(cookie);
-
- return err;
-}
-
static int data_read_cb(uint8_t *resp, int length, void *data)
{
struct t4_cookie *cookie = data ;
uint8_t *nfc_data;
size_t data_length, length_read, current_length;
uint16_t remain_bytes;
- int err = 0;
DBG("%d", length);
if (length < 0)
- return t4_cookie_release(err, cookie);
+ return t4_cookie_release(length, cookie);
if (APDU_STATUS(resp + length - 2) != APDU_OK) {
DBG("Fail read_cb SW:x%04x", APDU_STATUS(resp + length - 2));
- err = -EIO;
- return t4_cookie_release(err, cookie);
+
+ return t4_cookie_release(-EIO, cookie);
}
nfc_data = near_tag_get_data(cookie->tag, &data_length);
records = near_ndef_parse(nfc_data, data_length);
near_tag_add_records(cookie->tag, records, cookie->cb, 0);
- err = 0;
- goto out_err;
+ return t4_cookie_release(0, cookie);
}
cookie->read_data += length ;
remain_bytes = (data_length - cookie->read_data);
if (remain_bytes >= cookie->r_apdu_max_size)
- err = ISO_ReadBinary(cookie->read_data + 2,
+ return ISO_ReadBinary(cookie->read_data + 2,
cookie->r_apdu_max_size, data_read_cb, cookie);
else
- err = ISO_ReadBinary(cookie->read_data + 2,
+ return ISO_ReadBinary(cookie->read_data + 2,
(uint8_t) remain_bytes, data_read_cb, cookie);
- if (err < 0)
- goto out_err;
-
- return err;
-
-out_err:
- return t4_cookie_release(err, cookie);
}
static int t4_readbin_NDEF_ID(uint8_t *resp, int length, void *data)
DBG("%d", length);
- if (length < 0) {
- err = length;
- goto out_err;
- }
+ if (length < 0)
+ return t4_cookie_release(length, cookie);
if (APDU_STATUS(resp + length - 2) != APDU_OK) {
DBG("Fail SW:x%04x", APDU_STATUS(resp + length - 2));
- err = -EIO;
- goto out_err;
+
+ return t4_cookie_release(-EIO, cookie);
}
/* Add data to the tag */
err = near_tag_add_data(cookie->adapter_idx, cookie->target_idx, NULL,
g_ntohs(*((uint16_t *)(resp + NFC_STATUS_BYTE_LEN))));
if (err < 0)
- goto out_err;
+ return t4_cookie_release(err, cookie);
tag = near_tag_get_tag(cookie->adapter_idx, cookie->target_idx);
- if (tag == NULL) {
- err = -ENOMEM;
- goto out_err;
- }
+ if (tag == NULL)
+ return t4_cookie_release(-ENOMEM, cookie);
near_tag_set_max_ndef_size(tag, cookie->max_ndef_size);
near_tag_set_c_apdu_max_size(tag, cookie->c_apdu_max_size);
*/
/* Read 1st block */
- err = ISO_ReadBinary(2, cookie->r_apdu_max_size - 2,
+ return ISO_ReadBinary(2, cookie->r_apdu_max_size - 2,
data_read_cb, cookie);
- if (err < 0)
- goto out_err;
-
- return err;
-
-out_err:
- return t4_cookie_release(err, cookie);
}
static int t4_select_NDEF_ID(uint8_t *resp, int length, void *data)
{
struct t4_cookie *cookie = data;
- int err;
DBG("%d", length);
- if (length < 0) {
- err = length;
- goto out_err;
- }
+ if (length < 0)
+ return t4_cookie_release(length, cookie);
/* Check for APDU error */
if (APDU_STATUS(resp + STATUS_WORD_1) != APDU_OK) {
DBG("Fail SW:x%04x", APDU_STATUS(resp + STATUS_WORD_1));
- err = -EIO;
- goto out_err;
+
+ return t4_cookie_release(-EIO, cookie);
}
/* Read 0x0f bytes, to grab the NDEF msg length */
- err = ISO_ReadBinary(0, LEN_ISO_CC_READ_SIZE,
+ return ISO_ReadBinary(0, LEN_ISO_CC_READ_SIZE,
t4_readbin_NDEF_ID, cookie);
- if (err < 0)
- goto out_err;
-
- return err;
-
-out_err:
- return t4_cookie_release(err, cookie);
}
static int t4_readbin_cc(uint8_t *resp, int length, void *data)
{
struct t4_cookie *cookie = data;
struct type4_cc *read_cc;
- int err;
DBG("%d", length);
- if (length < 0) {
- err = length;
- goto out_err;
- }
+ if (length < 0)
+ return t4_cookie_release(length, cookie);
/* Check APDU error ( the two last bytes of the resp) */
if (APDU_STATUS(resp + length - 2) != APDU_OK) {
DBG("Fail SW:x%04x", APDU_STATUS(resp + length - 2));
- err = -EIO;
- goto out_err;
+
+ return t4_cookie_release(-EIO, cookie);
}
/* -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) {
DBG("Mem alloc failed");
- err = -ENOMEM;
- goto out_err;
+
+ return t4_cookie_release(-ENOMEM, cookie);
}
memcpy(read_cc, &resp[1], length - 2 - NFC_STATUS_BYTE_LEN) ;
/* TODO 5.1.2: Must ignore proprietary blocks (x05)... */
if (read_cc->tlv_fc.tag != 0x4) {
DBG("NDEF File Control tag not found");
- err = -EINVAL;
- goto out_err;
+
+ return t4_cookie_release(-EINVAL, cookie);
}
/* save rw conditions */
cookie->write_access = read_cc->tlv_fc.write_access;
- err = ISO_Select((uint8_t *) &read_cc->tlv_fc.file_id,
+ return ISO_Select((uint8_t *) &read_cc->tlv_fc.file_id,
LEN_ISO_CC_FILEID, 0, t4_select_NDEF_ID, cookie);
- if (err < 0)
- goto out_err;
-
- return err;
-
-out_err:
- return t4_cookie_release(err, cookie);
}
static int t4_select_cc(uint8_t *resp, int length, void *data)
DBG("%d", length);
- if (length < 0) {
- err = length;
- goto out_err;
- }
+ if (length < 0)
+ return t4_cookie_release(length, cookie);
/* Check for APDU error */
if (APDU_STATUS(resp + STATUS_WORD_1) != APDU_OK) {
err = near_tag_add_data(cookie->adapter_idx, cookie->target_idx,
NULL, 1 /* dummy length */);
if (err < 0)
- goto out_err;
+ return t4_cookie_release(err, cookie);
cookie->tag = near_tag_get_tag(cookie->adapter_idx,
cookie->target_idx);
- if (cookie->tag == NULL) {
- err = -ENOMEM;
- goto out_err;
- }
+ if (cookie->tag == NULL)
+ return t4_cookie_release(-ENOMEM, cookie);
near_tag_set_blank(cookie->tag, TRUE);
return t4_cookie_release(0, cookie);
}
- err = ISO_ReadBinary(0, LEN_ISO_CC_READ_SIZE, t4_readbin_cc, cookie);
- if (err < 0)
- goto out_err;
-
- return err;
-
-out_err:
- return t4_cookie_release(err, cookie);
+ return ISO_ReadBinary(0, LEN_ISO_CC_READ_SIZE, t4_readbin_cc, cookie);
}
static int t4_select_file_by_name_v1(uint8_t *resp, int length, void *data)
{
struct t4_cookie *cookie = data;
- int err;
DBG("%d", length);
- if (length < 0) {
- err = length;
- goto out_err;
- }
+ if (length < 0)
+ return t4_cookie_release(length, cookie);
/* Check for APDU error */
if (APDU_STATUS(resp + STATUS_WORD_1) != APDU_OK) {
DBG("V1 Fail SW:x%04x", APDU_STATUS(resp + STATUS_WORD_1));
- err = -EIO;
- goto out_err;
- }
- if (resp[NFC_STATUS] != 0) {
- err = -EIO;
- goto out_err;
+ return t4_cookie_release(-EIO, cookie);
}
+ if (resp[NFC_STATUS] != 0)
+ return t4_cookie_release(-EIO, cookie);
+
/* Jump to select phase */
- err = ISO_Select(iso_cc_fileid, LEN_ISO_CC_FILEID, 0,
+ return ISO_Select(iso_cc_fileid, LEN_ISO_CC_FILEID, 0,
t4_select_cc, cookie);
- if (err < 0)
- goto out_err;
-
- return err;
-
-out_err:
- return t4_cookie_release(err, cookie);
}
static int t4_select_file_by_name_v2(uint8_t *resp, int length, void *data)
{
struct t4_cookie *cookie = data;
- int err;
DBG("%d", length);
- if (length < 0) {
- err = length;
- goto out_err;
- }
+ if (length < 0)
+ t4_cookie_release(length, cookie);
/* Check for APDU error - Not found */
if (APDU_STATUS(resp + STATUS_WORD_1) == APDU_NOT_FOUND) {
DBG("Fallback to V1");
- err = ISO_Select(iso_appname_v1, ARRAY_SIZE(iso_appname_v1),
- 0x4, t4_select_file_by_name_v1, cookie);
- if (err < 0)
- goto out_err;
- return err;
+ return ISO_Select(iso_appname_v1, ARRAY_SIZE(iso_appname_v1),
+ 0x4, t4_select_file_by_name_v1, cookie);
}
if (APDU_STATUS(resp + STATUS_WORD_1) != APDU_OK) {
DBG("V2 Fail SW:x%04x", APDU_STATUS(resp + STATUS_WORD_1));
- err = -EIO;
- goto out_err;
- }
- if (resp[NFC_STATUS] != 0) {
- err = -EIO;
- goto out_err;
+ return t4_cookie_release(-EIO, cookie);
}
- /* Jump to select phase */
- err = ISO_Select(iso_cc_fileid, LEN_ISO_CC_FILEID, 0,
- t4_select_cc, cookie);
- if (err < 0)
- goto out_err;
-
- return err;
+ if (resp[NFC_STATUS] != 0)
+ return t4_cookie_release(-EIO, cookie);
-out_err:
- return t4_cookie_release(err, cookie);
+ /* Jump to select phase */
+ return ISO_Select(iso_cc_fileid, LEN_ISO_CC_FILEID, 0, t4_select_cc,
+ cookie);
}
static int nfctype4_read(uint32_t adapter_idx,
uint32_t target_idx, near_tag_io_cb cb)
{
struct t4_cookie *cookie;
- int err;
DBG("");
cookie = g_try_malloc0(sizeof(struct t4_cookie));
- if (cookie == NULL) {
- err = -ENOMEM;
- goto out_err;
- }
+ if (cookie == NULL)
+ return -ENOMEM;
cookie->adapter_idx = adapter_idx;
cookie->target_idx = target_idx;
cookie->read_data = 0;
/* Check for V2 type 4 tag */
- err = ISO_Select(iso_appname_v2, ARRAY_SIZE(iso_appname_v2),
- 0x4, t4_select_file_by_name_v2, cookie);
- if (err < 0)
- goto out_err;
-
- return err;
-
-out_err:
- return t4_cookie_release(err, cookie);
+ return ISO_Select(iso_appname_v2, ARRAY_SIZE(iso_appname_v2),
+ 0x4, t4_select_file_by_name_v2, cookie);
}
static int data_write_cb(uint8_t *resp, int length, void *data)
DBG("%d", length);
if (length < 0)
- return t4_cookie_release(err, cookie);
+ return t4_cookie_release(length, cookie);
if (APDU_STATUS(resp + length - 2) != APDU_OK) {
near_error("write failed SWx%04x",
APDU_STATUS(resp + length - 2));
- err = -EIO;
- return t4_cookie_release(err, cookie);
+ return t4_cookie_release(-EIO, cookie);
}
if (cookie->ndef->offset >= cookie->ndef->length) {
int err;
cookie = g_try_malloc0(sizeof(struct t4_cookie));
+
if (cookie == NULL) {
err = -ENOMEM;
- goto out_err;
+
+ if (cb != NULL)
+ cb(adapter_idx, target_idx, err);
+
+ return err;
}
cookie->adapter_idx = adapter_idx;
if (cookie->max_ndef_size < cookie->ndef->length) {
near_error("not enough space on tag to write data");
- err = -ENOMEM;
- goto out_err;
+
+ return t4_cookie_release(-ENOMEM, cookie);
}
if ((cookie->ndef->length - cookie->ndef->offset) >
struct near_ndef_message *ndef, near_tag_io_cb cb)
{
struct near_tag *tag;
+ int err;
DBG("");
- if (ndef == NULL || cb == NULL)
- return -EINVAL;
+ if (ndef == NULL || cb == NULL) {
+ err = -EINVAL;
+ goto out_err;
+ }
tag = near_tag_get_tag(adapter_idx, target_idx);
- if (tag == NULL)
- return -EINVAL;
+ if (tag == NULL) {
+ err = -EINVAL;
+ goto out_err;
+ }
+
+ err = data_write(adapter_idx, target_idx, ndef, tag, cb);
- return data_write(adapter_idx, target_idx, ndef, tag, cb);
+out_err:
+ if (cb != NULL)
+ cb(adapter_idx, target_idx, err);
+
+ return err;
}
static int check_presence(uint8_t *resp, int length, void *data)
uint32_t target_idx, near_tag_io_cb cb)
{
struct t4_cookie *cookie;
- int err;
DBG("");
cookie = g_try_malloc0(sizeof(struct t4_cookie));
- if (cookie == NULL) {
- err = -ENOMEM;
- goto out_err;
- }
+ if (cookie == NULL)
+ return -ENOMEM;
cookie->adapter_idx = adapter_idx;
cookie->target_idx = target_idx;
cookie->read_data = 0;
/* Check for V2 type 4 tag */
- err = ISO_Select(iso_appname_v2, ARRAY_SIZE(iso_appname_v2),
- 0x4, check_presence, cookie);
- if (err < 0)
- goto out_err;
-
- return err;
-
-out_err:
- return t4_cookie_release(err, cookie);
+ return ISO_Select(iso_appname_v2, ARRAY_SIZE(iso_appname_v2),
+ 0x4, check_presence, 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 (length < 0)
+ return t4_cookie_release(length, cookie);
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;
+
+ return t4_cookie_release(-EIO, cookie);
}
DBG("ndef file selected");
if (cookie->cb)
cookie->cb(cookie->adapter_idx, cookie->target_idx, 0);
-out_err:
- return t4_cookie_release(err, cookie);
+ return t4_cookie_release(0, cookie);
}
static int read_cc_file(uint8_t *resp, int length, void *data)
if (length < 0) {
near_error("CC file select resp failed %d", length);
- err = length;
- goto out_err;
+
+ return t4_cookie_release(length, cookie);
}
if (APDU_STATUS(resp + STATUS_WORD_1) != APDU_OK) {
near_error("CC file select response %02X",
resp[length - 1]);
- err = -EIO;
- goto out_err;
+
+ return t4_cookie_release(-EIO, cookie);
}
err = ISO_ReadBinary(0, LEN_ISO_CC_READ_SIZE, read_cc_file, cookie);
if (length < 0) {
near_error("iso app select resp failed %d", length);
- err = length;
- goto out_err;
+
+ return t4_cookie_release(length, cookie);
}
if (resp[NFC_STATUS] != 0x00) {
near_error("iso app select response %02X",
resp[length - 1]);
- err = -EIO;
- goto out_err;
+
+ return t4_cookie_release(-EIO, cookie);
}
err = ISO_Select(iso_cc_fileid, LEN_ISO_CC_FILEID, 0,
if (length < 0) {
near_error("write data to ndef file resp failed %d", length);
- err = length;
- goto out_err;
+
+ return t4_cookie_release(length, cookie);
}
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;
+
+ return t4_cookie_release(-EIO, cookie);
}
tag = near_tag_get_tag(cookie->adapter_idx, cookie->target_idx);
- if (tag == NULL) {
- err = -EINVAL;
- goto out_err;
- }
+ if (tag == NULL)
+ return t4_cookie_release(-EINVAL, cookie);
DBG("Formatting is done");
near_tag_set_blank(tag, FALSE);
goto out_err;
}
- return 0;
+ return err;
out_err:
return t4_cookie_release(err, cookie);
if (length < 0) {
near_error("get version2 resp failed %d", length);
- err = length;
- goto out_err;
+
+ return t4_cookie_release(length, cookie);
}
if (resp[4] == 0x01 /* Major Version */
select_application, cookie);
if (err < 0) {
near_error("get version3 req failed %d", err);
- goto out_err;
+
+ return t4_cookie_release(err, cookie);
}
} else {
near_error("get version2 response %02X", resp[length - 1]);
- err = -EIO;
- goto out_err;
+
+ return t4_cookie_release(-EIO, cookie);
}
return 0;
-
-out_err:
- return t4_cookie_release(err, cookie);
}
static int get_version_frame2(uint8_t *resp, int length, void *data)
if (length < 0) {
near_error(" get version resp failed %d", length);
- err = length;
- goto out_err;
+
+ return t4_cookie_release(length, cookie);
}
if (resp[4] == 0x01 /* Major Version */
get_version_frame3, cookie);
if (err < 0) {
near_error("get version2 req failed %d", err);
- goto out_err;
+
+ return t4_cookie_release(err, cookie);
}
} else {
near_error("get version response %02X", resp[length - 1]);
- err = -EIO;
- goto out_err;
+
+ return t4_cookie_release(-EIO, cookie);
}
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.
}
int near_adapter_send(uint32_t idx, uint8_t *buf, size_t length,
- near_recv cb, void *data)
+ near_recv cb, void *data, near_release data_rel)
{
struct near_adapter *adapter;
struct near_adapter_ioreq *req = NULL;
DBG("idx %d", idx);
adapter = g_hash_table_lookup(adapter_hash, GINT_TO_POINTER(idx));
- if (adapter == NULL)
- return -ENODEV;
+ if (adapter == NULL) {
+ err = -ENODEV;
+ goto out_err;
+ }
- if (adapter->tag_sock == -1 || adapter->tag_link == NULL)
- return -ENOLINK;
+ if (adapter->tag_sock == -1 || adapter->tag_link == NULL) {
+ err = -ENOLINK;
+ goto out_err;
+ }
if (cb != NULL && adapter->watch != 0) {
req = g_try_malloc0(sizeof(*req));
- if (req == NULL)
- return -ENOMEM;
+ if (req == NULL) {
+ err = -ENOMEM;
+ goto out_err;
+ }
DBG("req %p cb %p data %p", req, cb, data);
g_list_delete_link(adapter->ioreq_list, last);
}
+ if (data_rel != NULL)
+ return (*data_rel)(err, data);
+
return err;
}
{
struct near_tag *tag = data;
struct near_ndef_message *ndef, *ndef_with_header = NULL;
- int err;
+ int tlv_len_size, err;
DBG("conn %p", conn);
switch (tag->type) {
case NFC_PROTO_JEWEL:
case NFC_PROTO_MIFARE:
+ if (ndef->length < 0xff)
+ tlv_len_size = 3;
+ else
+ tlv_len_size = 5;
+
ndef_with_header = g_try_malloc0(sizeof(
struct near_ndef_message));
if (ndef_with_header == NULL)
goto fail;
ndef_with_header->offset = 0;
- ndef_with_header->length = ndef->length + 3;
- ndef_with_header->data = g_try_malloc0(ndef->length + 3);
+ ndef_with_header->length = ndef->length + tlv_len_size;
+ ndef_with_header->data =
+ g_try_malloc0(ndef->length + tlv_len_size);
if (ndef_with_header->data == NULL)
goto fail;
ndef_with_header->data[0] = TLV_NDEF;
- ndef_with_header->data[1] = ndef->length;
- memcpy(ndef_with_header->data + 2, ndef->data, ndef->length);
- ndef_with_header->data[ndef->length + 2] = TLV_END;
+ if (ndef->length < 0xff) {
+ ndef_with_header->data[1] = ndef->length;
+ } else {
+ ndef_with_header->data[1] = 0xff;
+ ndef_with_header->data[2] =
+ (uint8_t)(ndef->length >> 8);
+ ndef_with_header->data[3] = (uint8_t)(ndef->length);
+ }
+
+ memcpy(ndef_with_header->data + tlv_len_size - 1, ndef->data,
+ ndef->length);
+ ndef_with_header->data[ndef->length + tlv_len_size - 1] =
+ TLV_END;
break;
case NFC_PROTO_FELICA: