--- /dev/null
+Hacking on Near Field Communication manager
+*******************************************
+
+
+Build tools requirements
+========================
+
+When building and testing directly from the repository it is important to
+have at least automake version 1.10 or later installed. All modern
+distributions should default to the latest version, but it seems that
+Debian's default is still an earlier version:
+
+ Check version
+ # dpkg -l '*automake*'
+
+ Install new version
+ # apt-get install automake1.10
+ # update-alternatives --config automake
+
+
+Working with the source code repository
+=======================================
+
+The repository contains two extra scripts that accomplish the bootstrap
+process. One is called "bootstrap" which is the basic scripts that uses the
+autotools scripts to create the needed files for building and installing.
+It makes sure to call the right programs depending on the usage of shared or
+static libraries or translations etc.
+
+The second program is called "bootstrap-configure". This program will make
+sure to properly clean the repository, call the "bootstrap" script and then
+call configure with proper settings for development. It will use the best
+options and pass them over to configure. These options normally include
+the enabling the maintainer mode and the debugging features.
+
+So while in a normal source project the call "./configure ..." is used to
+configure the project with its settings like prefix and extra options. In
+case of bare repositories call "./bootstrap-configure" and it will bootstrap
+the repository and calls configure with all the correct options to make
+development easier.
+
+In case of preparing for a release with "make distcheck", don't use
+bootstrap-configure since it could export development specific settings.
+
+So the normal steps to checkout, build and install such a repository is
+like this:
+
+ Checkout repository
+ # git clone git://git.kernel.org/pub/scm/network/.../neard.git
+ # cd neard
+
+ Configure and build
+ # ./bootstrap-configure
+ # make
+
+ Check installation
+ # make install DESTDIR=$PWD/x
+ # find x
+ # rm -rf x
+
+ Check distribution
+ # make distcheck
+
+ Final installation
+ # sudo make install
+
+ Remove autogenerated files
+ # make maintainer-clean
+
+
+Running from within the source code repository
+==============================================
+
+When using "./configure --enable-maintainer-mode" the automake scripts will
+use the plugins directly from within the repository. This removes the need
+to use "make install" when testing "neard". The "bootstrap-configure"
+automatically includes this option.
+
+ Run daemon in foreground with debugging
+ # ./src/neard -n -d 'src/*'
+
+For production installations or distribution packaging it is important that
+the "--enable-maintainer-mode" option is NOT used.
+
+The debugging option -d takes an argument. This argument can be a comma
+separated list of file names like 'src/main.c,src/manager.c' to enable debugs
+in these files. Simple glob style pattern matching is supported in this list.
test_scripts = test/disable-adapter test/enable-adapter test/list-adapters \
test/dump-device test/dump-tag test/dump-record \
test/monitor-near test/start-poll test/stop-poll test/write-tag \
- test/push-device
+ test/push-device test/bt-handover
if TEST
testdir = $(pkglibdir)/test
--- /dev/null
+HandoverAgent hierarchy
+=======================
+
+Service unique name
+Interface org.neard.HandoverAgent
+Object path freely definable
+
+Methods dict RequestOOB(dict values) [experimental]
+
+ This method gets called when the service daemon
+ needs to get Out Of Band data from the handover
+ agent, typically the BlueZ daemon.
+
+ The service daemon will use this OOB data to build
+ a Handover Request or Select message and send it to
+ remote device.
+
+ Values parameter is optional. It should be a dictionary
+ where the keys are the field names and the values are
+ the actual fields. If provided it should contain remote
+ Out Of Band data received in Handover Request message.
+ Those data will be stored for future use (i.e. when
+ remote initialize pairing) and providing those will not
+ initialize pairing.
+
+ The return value should be a dictionary where the
+ keys are the field names and the values are the
+ actual fields.
+
+ Possible Errors: org.neard.HandoverAgent.Error.NotSupported
+ org.neard.HandoverAgent.Error.NoSuchDevice
+ org.neard.HandoverAgent.Error.InProgress
+ org.neard.HandoverAgent.Error.Failed
+
+ void PushOOB(dict values) [experimental]
+
+ This method gets called when service daemon received
+ Handover Select message from selector and needs to pass
+ remote Out Of Band data to agent to start handover.
+
+ If there is no Bluetooth adapter or if it doesn't
+ support simple pairing the agent will return an error.
+
+ Agent shall implicitly initialize pairing if needed.
+
+ This function returns when alternative carrier
+ (Bluetooth) is ready to be used i.e. pairing has
+ finished.
+
+ Parameter should be a dictionary where the keys are the
+ field names and the values are the actual fields.
+
+ Possible Errors: org.neard.HandoverAgent.Error.NotSupported
+ org.neard.HandoverAgent.Error.NoSuchDevice
+ org.neard.HandoverAgent.Error.InProgress
+ org.neard.HandoverAgent.Error.Failed
+
+ void Release() [experimental]
+
+ This method gets called when the service daemon
+ unregisters the agent. An agent can use it to do
+ cleanup tasks. There is no need to unregister the
+ agent, because when this method gets called it has
+ already been unregistered.
+
+Fields array{byte} EIR
+
+ This is EIR blob. Used by SSP capable devices.
+
+ array{byte} nokia.com:bt
+
+ This is a proprietary extension blob used by some
+ Nokia Bluetooth 2.0 devices.
+
+
+NDEFAgent hierarchy
+=======================
+
+Service unique name
+Interface org.neard.NDEFAgent
+Object path freely definable
+
+Methods dict GetNDEF(dict values) [experimental]
+
+ This method gets called when the service daemon
+ found an NDEF matching the registered type.
+
+ The parameter is a dictionary where the keys are the
+ field names and the values are the actual fields.
+
+ void Release() [experimental]
+
+ This method gets called when the service daemon
+ unregisters the agent. An agent can use it to do
+ cleanup tasks. There is no need to unregister the
+ agent, because when this method gets called it has
+ already been unregistered.
+
+Fields array{byte} NDEF
+
+ This is the raw NDEF data.
+
+ object Record
+
+ This is a record object path.
--- /dev/null
+Every project has its coding style, and neard is not an exception. This
+document describes the preferred coding style for neard code, in order to keep
+some level of consistency among developers so that code can be easily
+understood and maintained, and also to help your code survive under
+maintainer's fastidious eyes so that you can get a passport for your patch
+ASAP.
+
+First of all, neard coding style must follow every rule for Linux kernel
+(http://www.kernel.org/doc/Documentation/CodingStyle). There also exists a tool
+named checkpatch.pl to help you check the compliance with it. Just type
+"checkpatch.pl --no-tree patch_name" to check your patch. In theory, you need
+to clean up all the warnings and errors except this one: "ERROR: Missing
+Signed-off-by: line(s)". neard does not used Signed-Off lines, so including
+them is actually an error. In certain circumstances one can ignore the 80
+character per line limit. This is generally only allowed if the alternative
+would make the code even less readable.
+
+Besides the kernel coding style above, neard has special flavors for its own.
+Some of them are mandatory (marked as 'M'), while some others are optional
+(marked as 'O'), but generally preferred.
+
+M1: Blank line before and after an if/while/do/for statement
+============================================================
+There should be a blank line before if statement unless the if is nested and
+not preceded by an expression or variable declaration.
+
+Example:
+1)
+a = 1;
+if (b) { // wrong
+
+2)
+a = 1
+
+if (b) {
+}
+a = 2; // wrong
+
+3)
+if (a) {
+ if (b) // correct
+
+4)
+b = 2;
+
+if (a) { // correct
+
+}
+
+b = 3;
+
+The only exception to this rule applies when a variable is being allocated:
+array = g_try_new0(int, 20);
+if (array == NULL) // Correct
+ return;
+
+
+M2: Multiple line comment
+=========================
+If your comments have more then one line, please start it from the second line.
+
+Example:
+/*
+ * first line comment // correct
+ * ...
+ * last line comment
+ */
+
+
+M3: Space before and after operator
+===================================
+There should be a space before and after each operator.
+
+Example:
+a + b; // correct
+
+
+M4: Wrap long lines
+===================
+If your condition in if, while, for statement or a function declaration is too
+long to fit in one line, the new line needs to be indented not aligned with the
+body.
+
+Example:
+1)
+if (call->status == CALL_STATUS_ACTIVE ||
+ call->status == CALL_STATUS_HELD) { // wrong
+ neard_dbus_dict_append();
+
+2)
+if (call->status == CALL_STATUS_ACTIVE ||
+ call->status == CALL_STATUS_HELD) { // correct
+ neard_dbus_dict_append();
+
+3)
+gboolean sim_ust_is_available(unsigned char *service_ust, unsigned char len,
+ num sim_ust_service index) // wrong
+{
+ int a;
+ ...
+}
+
+4)
+gboolean sim_ust_is_available(unsigned char *service_ust, unsigned char len,
+ enum sim_ust_service index) // correct
+{
+ int a;
+ ...
+}
+
+If the line being wrapped is a function call or function declaration, the
+preferred style is to indent at least past the opening parenthesis. Indenting
+further is acceptable as well (as long as you don't hit the 80 character
+limit).
+
+If this is not possible due to hitting the 80 character limit, then indenting
+as far as possible to the right without hitting the limit is preferred.
+
+Example:
+
+1)
+gboolean sim_ust_is_available(unsigned char *service_ust, unsigned char len,
+ enum sim_ust_service index); // worse
+
+2)
+gboolean sim_ust_is_available(unsigned char *service_ust, unsigned char len,
+ enum sim_ust_service index);
+ // better
+
+M5: Git commit message 50/72 formatting
+=======================================
+The commit message header should be within 50 characters. And if you have
+detailed explanatory text, wrap it to 72 character.
+
+
+M6: Space when doing type casting
+=================================
+There should be a space between new type and variable.
+
+Example:
+1)
+a = (int *)b; // wrong
+2)
+a = (int *) b; // correct
+
+
+M7: Don't initialize variable unnecessarily
+===========================================
+When declaring a variable, try not to initialize it unless necessary.
+
+Example:
+int i = 1; // wrong
+
+for (i = 0; i < 3; i++) {
+}
+
+
+M8: Use g_try_malloc instead of g_malloc
+========================================
+When g_malloc fails, the whole program would exit. Most of time, this is not
+the expected behavior, and you may want to use g_try_malloc instead.
+
+Example:
+additional = g_try_malloc(len - 1); // correct
+if (additional == NULL)
+ return FALSE;
+
+
+M9: Follow the order of include header elements
+===============================================
+When writing an include header the various elements should be in the following
+order:
+ - #includes
+ - forward declarations
+ - #defines
+ - enums
+ - typedefs
+ - function declarations and inline function definitions
+
+
+M10: Internal headers must not use include guards
+=================================================
+Any time when creating a new header file with non-public API, that header
+must not contain include guards.
+
+
+M11: Naming of enums
+====================
+
+Enums must have a descriptive name. The enum type should be small caps and
+it should not be typedef-ed. Enum contents should be in CAPITAL letters and
+prefixed by the enum type name.
+
+Example:
+
+enum animal_type {
+ ANIMAL_TYPE_FOUR_LEGS,
+ ANIMAL_TYPE_EIGHT_LEGS,
+ ANIMAL_TYPE_TWO_LEGS,
+};
+
+If the enum contents have values (e.g. from specification) the formatting
+should be as follows:
+
+enum animal_type {
+ ANIMAL_TYPE_FOUR_LEGS = 4,
+ ANIMAL_TYPE_EIGHT_LEGS = 8,
+ ANIMAL_TYPE_TWO_LEGS = 2,
+};
+
+M12: Enum as switch variable
+====================
+
+If the variable of a switch is an enum, you must not include a default in
+switch body. The reason for this is: If later on you modify the enum by adding
+a new type, and forget to change the switch accordingly, the compiler will
+complain the new added type hasn't been handled.
+
+Example:
+
+enum animal_type {
+ ANIMAL_TYPE_FOUR_LEGS = 4,
+ ANIMAL_TYPE_EIGHT_LEGS = 8,
+ ANIMAL_TYPE_TWO_LEGS = 2,
+};
+
+enum animal_type t;
+
+switch (t) {
+case ANIMAL_TYPE_FOUR_LEGS:
+ ...
+ break;
+case ANIMAL_TYPE_EIGHT_LEGS:
+ ...
+ break;
+case ANIMAL_TYPE_TWO_LEGS:
+ ...
+ break;
+default: // wrong
+ break;
+}
+
+However if the enum comes from an external header file outside neard
+we cannot make any assumption of how the enum is defined and this
+rule might not apply.
+
+M13: Check for pointer being NULL
+=================================
+
+When checking if a pointer or a return value is NULL, explicitly compare to
+NULL rather than use the shorter check with "!" operator.
+
+Example:
+1)
+array = g_try_new0(int, 20);
+if (!array) // Wrong
+ return;
+
+2)
+if (!g_at_chat_get_slave(chat)) // Wrong
+ return -EINVAL;
+
+3)
+array = g_try_new0(int, 20);
+if (array == NULL) // Correct
+ return;
+
+
+M14: Always use parenthesis with sizeof
+=======================================
+The expression argument to the sizeof operator should always be in
+parenthesis, too.
+
+Example:
+1)
+memset(stuff, 0, sizeof(*stuff));
+
+2)
+memset(stuff, 0, sizeof *stuff); // Wrong
+
+
+M15: Use void if function has no parameters
+===========================================================
+A function with no parameters must use void in the parameter list.
+
+Example:
+1)
+void foo(void)
+{
+}
+
+2)
+void foo() // Wrong
+{
+}
+
+M16: Don't use hex value with shift operators
+==============================================
+The expression argument to the shift operators should not be in hex.
+
+Example:
+
+1)
+1 << y
+
+2)
+0x1 << y // Wrong
+
+O1: Shorten the name
+====================
+Better to use abbreviation, rather than full name, to name a variable,
+function, struct, etc.
+
+Example:
+supplementary_service // too long
+ss // better
+
+O2: Try to avoid complex if body
+================================
+It's better not to have a complicated statement for if. You may judge its
+contrary condition and return | break | continue | goto ASAP.
+
+Example:
+1)
+if (a) { // worse
+ struct voicecall *v;
+ call = synthesize_outgoing_call(vc, vc->pending);
+ v = voicecall_create(vc, call);
+ v->detect_time = time(NULL);
+ DBG("Registering new call: %d", call->id);
+ voicecall_dbus_register(v);
+} else
+ return;
+
+2)
+if (!a)
+ return;
+
+struct voicecall *v;
+call = synthesize_outgoing_call(vc, vc->pending);
+v = voicecall_create(vc, call);
+v->detect_time = time(NULL);
+DBG("Registering new call: %d", call->id);
+voicecall_dbus_register(v);
--- /dev/null
+neard - Near Field Communication daemon
+=======================================
+
+Purpose
+=======
+
+This document describes all the major functionalities
+supported by neard.
+
+
+Reader Mode
+===========
+Supported tags:
+
+ * Type 1: Supported.
+ * Type 2: Supported.
+ * MIFARE classic 1K and 4K supported.
+ * Type 3: Supported.
+ * Type 4: Supported.
+
+
+Card Emulation Mode
+===================
+Not supported.
+
+
+Writer Mode
+===========
+Supported tags:
+
+ * Type 1: Supported.
+ * Type 2: Supported.
+ * Type 3: Supported.
+ * Type 4: Supported.
+
+
+Peer To Peer Mode
+=================
+neard reads and write NDEFs from p2p devices, through SNEP and NPP.
+Both initiator and target modes are supported.
+
+
+Handover
+========
+WIP.
goto fail;
if (g_dbus_args_have_signature(args, signal) == FALSE) {
- error("%s.%s: expected signature'%s' but got '%s'",
- interface, name, args, signature);
+ error("%s.%s: got unexpected signature '%s'", interface, name,
+ dbus_message_get_signature(signal));
ret = FALSE;
goto fail;
}
if (ndef != NULL)
g_free(ndef->ndef);
+
g_free(ndef);
}
* exchange with a Hr), so we have to do some actions (e.g.:
* pairing with bluetooth)
*/
- if (strncmp((char *)(ndef->ndef + FRAME_TYPE_OFFSET), "Hr", 2) == 0) {
+ if (strncmp((char *) (ndef->ndef + FRAME_TYPE_OFFSET), "Hr", 2) == 0) {
/*
* The first entry on the record list is the Hr record.
* We build the Hs based on it.
return err;
fail:
- near_error("ndef parsing failed (%d)", err);
+ near_error("ndef parsing failed %d", err);
handover_close(client_fd, 0);
ndef = g_hash_table_lookup(hr_ndef_hash, GINT_TO_POINTER(client_fd));
if (ndef == NULL) {
- near_error("hr_ndef should exist !!!");
+ near_error("hr_ndef should exist");
return FALSE;
}
ndef = g_hash_table_lookup(hr_ndef_hash, GINT_TO_POINTER(client_fd));
if (ndef == NULL) {
- /* First call: allocate and read header bytes*/
+ /* First call: allocate and read header bytes */
return handover_read_initialize(client_fd, adapter_idx,
target_idx, cb);
}
GIOCondition condition, gpointer data)
{
near_bool_t ret;
- struct hr_push_client *client = (struct hr_push_client *)data;
+ struct hr_push_client *client = (struct hr_push_client *) data;
DBG("condition 0x%x", condition);
struct near_p2p_driver handover_driver = {
.name = "Handover",
.service_name = NEAR_DEVICE_SN_HANDOVER,
+ .fallback_service_name = NEAR_DEVICE_SN_SNEP,
.read = handover_read,
.push = handover_push,
.close = handover_close,
#include <near/ndef.h>
#include <near/tlv.h>
-/* NXP Application Notes:
+/*
+ * NXP Application Notes:
* AN1304, AN1305, ...
* http://www.nxp.com/technical-support-portal/53420/71108/application-notes
- * */
+ */
-/* Prototype */
+/* Prototypes */
int mifare_read(uint32_t adapter_idx, uint32_t target_idx,
near_tag_io_cb cb, enum near_tag_sub_type tgt_subtype);
+int mifare_check_presence(uint32_t adapter_idx, uint32_t target_idx,
+ near_tag_io_cb cb, enum near_tag_sub_type tgt_subtype);
+
+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);
+
/* MIFARE command set */
-#define MF_CMD_WRITE 0xA2
+#define MF_CMD_WRITE 0xA0
#define MF_CMD_READ 0x30
#define MF_CMD_AUTH_KEY_A 0x60
#define NFC_AID_TAG 0xE103
-/* Define boundaries for 1K / 2K / 4K
+/*
+ * Define boundaries for 1K / 2K / 4K
* 1K: sector 0 to 15 (3 blocks each + trailer block )
* 2K: sector 0 to 31 (3 blocks each + trailer block )
* 4K: sector 0 to 31 (3 blocks each + trailer block )
* and sector 32 to 39 (15 blocks each + trailer block )
- * */
+ */
#define DEFAULT_BLOCK_SIZE 16 /* MF_CMD_READ */
#define STD_BLK_SECT_TRAILER 4 /* bl per sect with trailer 1K/2K */
#define MAD1_1ST_BLOCK 0x00 /* 1st block of sector 0 */
#define MAD2_GPB_BITS 0x02 /* MAD v2 flag */
-#define MAD2_SECTOR 0x10 /* Sector 0 is for MAD2 */
+#define MAD2_SECTOR 0x10 /* Sector 16 is for MAD2 */
#define MAD2_1ST_BLOCK 0x40 /* 1st block of MAD2 */
#define MAD_V1_AIDS_LEN 15 /* 1 to 0x0F */
#define MAD_V2_AIDS_LEN 23 /*0x11 to 0x27 */
+#define NFC_1ST_BLOCK 0x04 /* Sectors from 1 are for NFC */
+
/* 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;
struct MAD_2 *mad_2;
GSList *g_sect_list; /* Global sectors list */
- /* For read functions */
- near_recv rs_next_fct; /* next function */
- int rs_block_start; /* first block */
- int rs_block_end; /* last block */
- int rs_completed; /* read blocks */
+ /* For read and write functions */
+ near_recv rws_next_fct; /* next function */
+ int rws_block_start; /* first block */
+ int rws_block_end; /* last block */
+ int rws_completed; /* read blocks */
+
+
+ /* For read only */
int rs_length; /* read length */
uint8_t *rs_pmem; /* Stored read sector */
int rs_max_length; /* available size */
uint8_t *nfc_data;
size_t nfc_data_length;
+
+ /* For write only */
+ struct near_ndef_message *ndef; /* message to write */
+ size_t ndef_length; /* message length */
};
struct type2_cmd {
uint8_t data[];
} __attribute__((packed));
+struct mf_write_cmd {
+ uint8_t cmd;
+ uint8_t block;
+ uint8_t data[DEFAULT_BLOCK_SIZE];
+} __attribute__((packed));
+
struct mifare_cmd {
uint8_t cmd;
uint8_t block;
uint8_t nfcid[NFC_NFCID1_MAXSIZE];
} __attribute__((packed));
-/* Common free func */
-static int mifare_release(int err, struct mifare_cookie *cookie)
+static int mifare_release(int err, void *data)
{
+ struct mifare_cookie *cookie = data;
+
DBG("%p", cookie);
if (cookie == NULL)
g_slist_free(cookie->g_sect_list);
g_free(cookie->mad_1);
g_free(cookie->mad_2);
+
+ if (cookie->ndef)
+ g_free(cookie->ndef->data);
+
+ g_free(cookie->ndef);
g_free(cookie);
cookie = NULL;
return err;
}
-/* Mifare_generic MAD unlock block function
+/*
+ * Mifare_generic MAD unlock block function
* This function send unlock code to the tag, and so, allow access
* to the complete related sector.
*/
struct mifare_cookie *cookie = data;
uint8_t *key_ref;
- /* For MADs sectors we use public key A (a0a1a2a3a4a5) but
- * for NFC sectors we use NFC_KEY_A (d3f7d3f7d3f7)
- * */
+ /*
+ * For MADs sectors we use public key A (a0a1a2a3a4a5) but
+- * for NFC sectors we use NFC_KEY_A (d3f7d3f7d3f7)
+ */
if ((block_id == MAD1_1ST_BLOCK) || (block_id == MAD2_1ST_BLOCK))
key_ref = MAD_public_key;
else
/* CMD AUTHENTICATION */
cmd.cmd = MF_CMD_AUTH_KEY_A;
- /* We want to authenticate the 1st bloc of the sector */
+ /* Authenticate will be on the 1st block of the sector */
cmd.block = block_id;
/* Store the AUTH KEY */
cookie);
}
-/* Common MIFARE Bloc read:
+/*
+ * Common MIFARE Block read:
* Each call will read 16 bytes from tag... so to read 1 sector,
- * we must call it 4 times or 16 times (minus 1 or not for the trailer block)
+ * it has to be called it 4 times or 16 times
+ * (minus 1 or not for the trailer block)
*
* data: mifare_cookie *mf_ck
* mf_ck->read_block: block number to read
- * */
+ */
static int mifare_read_block(uint8_t block_id,
void *data,
near_recv far_func)
/* save the length: */
mf_ck->rs_length = mf_ck->rs_length + length;
- memcpy(mf_ck->rs_pmem + mf_ck->rs_completed * DEFAULT_BLOCK_SIZE,
+ memcpy(mf_ck->rs_pmem + mf_ck->rws_completed * DEFAULT_BLOCK_SIZE,
resp + 1,/* ignore reader byte */
length);
/* Next block */
- mf_ck->rs_completed = mf_ck->rs_completed + 1;
+ mf_ck->rws_completed = mf_ck->rws_completed + 1;
- if ((mf_ck->rs_block_start + mf_ck->rs_completed) < mf_ck->rs_block_end)
+ if ((mf_ck->rws_block_start + mf_ck->rws_completed)
+ < mf_ck->rws_block_end)
err = mifare_read_block(
- (mf_ck->rs_block_start + mf_ck->rs_completed),
+ (mf_ck->rws_block_start + mf_ck->rws_completed),
data,
mifare_read_sector_cb);
else {
/* Now Process the callback ! */
- err = (*mf_ck->rs_next_fct)(mf_ck->rs_pmem,
+ err = (*mf_ck->rws_next_fct)(mf_ck->rs_pmem,
mf_ck->rs_length, data);
}
return err;
}
/* And run the read process on the first block of the sector */
- err = mifare_read_block(mf_ck->rs_block_start, data,
+ err = mifare_read_block(mf_ck->rws_block_start, data,
mifare_read_sector_cb);
if (err < 0)
return err;
}
-/* This function reads a complete sector, using block per block function.
+/*
+ * This function reads a complete sector, using block per block function.
* sector sizes can be:
* Sectors 0 to 31:
* 48 bytes: 3*16 no trailer
mf_ck->rs_pmem = pmem; /* where to store */
mf_ck->rs_max_length = memsize; /* max size to store */
mf_ck->rs_length = 0; /* no bytes yet */
- mf_ck->rs_completed = 0; /* blocks read */
+ mf_ck->rws_completed = 0; /* blocks read */
/* According to tag size, compute the correct block offset */
if (sector_id < T4K_BOUNDARY)
- mf_ck->rs_block_start = sector_id * 4; /* 1st block to read */
+ mf_ck->rws_block_start = sector_id * 4; /* 1st block to read */
else
- mf_ck->rs_block_start =
+ mf_ck->rws_block_start =
(sector_id - T4K_BOUNDARY) * 16 + T4K_BLK_OFF;
/* Find blocks_per_sect, according to position and trailer or not */
else
blocks_count = (EXT_BLK_PER_SECT + trailer);
- mf_ck->rs_block_end = mf_ck->rs_block_start + blocks_count;
+ mf_ck->rws_block_end = mf_ck->rws_block_start + blocks_count;
- mf_ck->rs_next_fct = next_func; /* leaving function */
+ mf_ck->rws_next_fct = next_func; /* leaving function */
- /* As we are on the first block of a sector, we unlock it */
- err = mifare_unlock_sector(mf_ck->rs_block_start,
+ /* Being on the first block of a sector, unlock it */
+ err = mifare_unlock_sector(mf_ck->rws_block_start,
mifare_read_sector_unlocked, mf_ck);
return err;
uint8_t *nfc_data;
size_t nfc_data_length;
- DBG("READ DONE");
+ DBG("Done reading");
nfc_data = near_tag_get_data(mf_ck->tag, &nfc_data_length);
if (nfc_data == NULL) {
return mifare_release(err, mf_ck);
}
-/* Prepare read NFC loop
- */
+/* Prepare read NFC loop */
static int mifare_read_NFC(void *data)
{
struct mifare_cookie *mf_ck = data;
goto out_err;
}
- /* Time to read the NFC data */
- err = mifare_read_NFC(mf_ck);
+ /* Time to read or write the NFC data */
+ err = mf_ck->command(mf_ck);
return err;
return mifare_release(err, mf_ck);
}
-/* Transitional function - async
- */
+/* Transitional function - async */
static int read_MAD2_complete(uint8_t *empty, int iempty, void *data)
{
return mifare_process_MADs(data);
}
-/* This function reads the MAD2 sector
- */
+/* This function reads the MAD2 sector */
static int mifare_read_MAD2(void *data)
{
struct mifare_cookie *mf_ck = data;
DBG("");
- /* As auth is ok, we allocate Mifare Access Directory v1 */
+ /* As auth is ok, allocate Mifare Access Directory v1 */
mf_ck->mad_2 = g_try_malloc0(STD_SECTOR_SIZE);
if (mf_ck->mad_2 == NULL) {
near_error("Memory allocation failed (MAD2)");
return mifare_release(err, mf_ck);
}
-/* This function checks, in MAD1, if there's a MAD2 directory
+/*
+ * This function checks, in MAD1, if there's a MAD2 directory
* available. This is is the case for 2K and 4K tag
- * If MAD2 exists, we want to read it, elsewhere we process the
- * current MAD
+ * If MAD2 exists, read it, elsewhere process the current MAD
*/
static int read_MAD1_complete(uint8_t *empty, int iempty, void *data)
{
DBG("");
- /* Check if we need to get MAD2 sector (bits 0..1)*/
+ /* Check if there's a need to get MAD2 sector */
if ((mf_ck->mad_1->GPB & 0x03) == MAD2_GPB_BITS)
err = mifare_read_MAD2(mf_ck);
else
return err;
}
-/* Function called to read the first MAD sector
+/*
+ * Function called to read the first MAD sector
* MAD is mandatory
*/
static int mifare_read_MAD1(uint8_t *resp, int length, void *data)
return err;
}
- /* As auth is ok, we allocate Mifare Access Directory v1
- * allocated size is also STD_SECTOR_SIZE */
+ /*
+ * As auth is ok, allocate Mifare Access Directory v1
+ * allocated size is also STD_SECTOR_SIZE
+ */
mf_ck->mad_1 = g_try_malloc0(STD_SECTOR_SIZE);
if (mf_ck->mad_1 == NULL) {
near_error("Memory allocation failed (MAD1)");
return mifare_release(err, mf_ck);
}
-/* MIFARE: entry point:
+/*
+ * MIFARE: entry point:
* Read all the MAD sectors (0x00, 0x10) to get the Application Directory
* entries.
* On sector 0x00, App. directory is on block 0x01 & block 0x02
* On sector 0x10, App. directory is on block 0x40, 0x41 & 0x42
- * On reading, we ignore the CRC.
+ * On reading, CRC is ignored.
*/
int mifare_read(uint32_t adapter_idx, uint32_t target_idx,
near_tag_io_cb cb, enum near_tag_sub_type tgt_subtype)
cookie->adapter_idx = adapter_idx;
cookie->target_idx = target_idx;
cookie->cb = cb;
+ cookie->command = mifare_read_NFC;
- /* Need to unlock before reading
+ /*
+ * Need to unlock before reading
* This will check if public keys are allowed (and, so, NDEF could
* be "readable"...
- * */
+ */
err = mifare_unlock_sector(MAD1_1ST_BLOCK, /* related block */
mifare_read_MAD1, /* callback function */
cookie); /* target data */
return 0;
}
+
+static int check_presence(uint8_t *resp, int length, void *data)
+{
+ struct mifare_cookie *cookie = data;
+ int err = 0;
+
+ DBG("%d", length);
+
+ if (length < 0)
+ err = -EIO;
+
+ if (cookie->cb)
+ cookie->cb(cookie->adapter_idx, cookie->target_idx, err);
+
+ return err;
+}
+
+int mifare_check_presence(uint32_t adapter_idx, uint32_t target_idx,
+ near_tag_io_cb cb, enum near_tag_sub_type tgt_subtype)
+{
+ struct mifare_cmd cmd;
+ struct mifare_cookie *cookie;
+ uint8_t *key_ref = MAD_public_key;
+ int err;
+
+ DBG("");
+
+ /* Check supported and tested Mifare type */
+ switch (tgt_subtype) {
+ case NEAR_TAG_NFC_T2_MIFARE_CLASSIC_1K:
+ case NEAR_TAG_NFC_T2_MIFARE_CLASSIC_4K:
+ break;
+ default:
+ near_error("Mifare tag type %d not supported.", tgt_subtype);
+ return -1;
+ }
+
+ /* Alloc global cookie */
+ cookie = g_try_malloc0(sizeof(struct mifare_cookie));
+ if (cookie == NULL)
+ return -ENOMEM;
+
+ /* Get the nfcid1 */
+ cookie->nfcid1 = near_tag_get_nfcid(adapter_idx, target_idx,
+ &cookie->nfcid1_len);
+ cookie->adapter_idx = adapter_idx;
+ cookie->target_idx = target_idx;
+ cookie->cb = cb;
+
+ /*
+ * To check presence of Mifare Classic Tag,
+ * send authentication command instead of read one
+ */
+ cmd.cmd = MF_CMD_AUTH_KEY_A;
+
+ /* Authenticate the 1st block of the MAD sector */
+ cmd.block = MAD1_1ST_BLOCK;
+
+ /* Store the AUTH KEY */
+ memcpy(&cmd.key, key_ref, MAD_KEY_LEN);
+
+ /* add the UID */
+ memcpy(&cmd.nfcid, cookie->nfcid1, cookie->nfcid1_len);
+
+ err = 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;
+}
+
+/*
+ * Common MIFARE Block write:
+ * Each call will write 16 bytes to tag... so to write 1 sector,
+ * it has to be called it 4 or 16 times (minus 1 for the trailer block)
+ */
+static int mifare_write_block(uint8_t block_id, void *data,
+ near_recv far_func)
+{
+ struct mf_write_cmd cmd;
+ struct mifare_cookie *mf_ck = data;
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.cmd = MF_CMD_WRITE; /* MIFARE WRITE */
+ cmd.block = block_id;
+
+ if ((mf_ck->ndef->offset + DEFAULT_BLOCK_SIZE) <
+ mf_ck->ndef->length) {
+ memcpy(cmd.data, mf_ck->ndef->data +
+ mf_ck->ndef->offset, DEFAULT_BLOCK_SIZE);
+ mf_ck->ndef->offset += DEFAULT_BLOCK_SIZE;
+ } else {
+ memcpy(cmd.data, mf_ck->ndef->data + mf_ck->ndef->offset,
+ mf_ck->ndef->length - mf_ck->ndef->offset);
+ mf_ck->ndef->offset = mf_ck->ndef->length + 1;
+ }
+
+ return near_adapter_send(mf_ck->adapter_idx,
+ (uint8_t *) &cmd, sizeof(cmd),
+ far_func, data);
+}
+
+static int mifare_correct_length_cb(uint8_t *resp, int length, void *data)
+{
+ struct mifare_cookie *mf_ck = data;
+
+ DBG("Done writing");
+
+ if (mf_ck->cb)
+ mf_ck->cb(mf_ck->adapter_idx, mf_ck->target_idx, 0);
+
+ return mifare_release(0, mf_ck);
+}
+
+/* After writing ndef message, its length has to be updated */
+static int mifare_correct_length(uint8_t *resp, int length, void *data)
+{
+ struct mifare_cookie *mf_ck = data;
+
+ DBG("");
+
+ /* Correct length field */
+ mf_ck->ndef->data[1] = mf_ck->ndef_length;
+ /* and ndef offset so it points to the beginning */
+ mf_ck->ndef->offset = 0;
+
+ /* Run the write process only on the first block of the sector */
+ return mifare_write_block(NFC_1ST_BLOCK, mf_ck,
+ mifare_correct_length_cb);
+}
+
+static int mifare_write_sector_cb(uint8_t *resp, int length, void *data)
+{
+ struct mifare_cookie *mf_ck = data;
+ int err;
+
+ /* Next block */
+ mf_ck->rws_completed = mf_ck->rws_completed + 1;
+
+ /* Check if it's the last block */
+ if ((mf_ck->rws_block_start + mf_ck->rws_completed)
+ < mf_ck->rws_block_end) {
+ /* then check if there's still data to write */
+ if (mf_ck->ndef->offset < mf_ck->ndef->length)
+ err = mifare_write_block(
+ mf_ck->rws_block_start + mf_ck->rws_completed,
+ data, mifare_write_sector_cb);
+ else
+ /* No more Data to write */
+ /* Correct length of the ndef message */
+ err = mifare_unlock_sector(NFC_1ST_BLOCK,
+ mifare_correct_length, mf_ck);
+ } else {
+ /* Process the callback */
+ err = (*mf_ck->rws_next_fct)(resp, length, data);
+ }
+
+ if (err < 0)
+ return mifare_release(err, mf_ck);
+
+ return err;
+
+}
+
+static int mifare_write_sector_unlocked(uint8_t *resp, int length, void *data)
+{
+ struct mifare_cookie *mf_ck = data;
+
+ /* 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);
+}
+
+/*
+ * This function writes a complete sector, using block per block function.
+ * sector sizes can be:
+ * Sectors 0 to 31:
+ * 48 bytes: 3*16 (no trailer)
+ * Sectors 32 to 39:
+ * 240 bytes: 15*16 (no trailer)
+ *
+ * Unlock is done at the beginning of each sector.
+ */
+static int mifare_write_sector(void *cookie,
+ uint8_t sector_id, /* sector to write */
+ near_recv next_func)
+{
+ struct mifare_cookie *mf_ck = cookie;
+ int blocks_count;
+
+ DBG("");
+
+ /* Prepare call values */
+
+ /* According to tag size, compute the correct block offset */
+ if (sector_id < T4K_BOUNDARY)
+ mf_ck->rws_block_start = sector_id * STD_BLK_SECT_TRAILER;
+ else
+ mf_ck->rws_block_start = T4K_BLK_OFF +
+ (sector_id - T4K_BOUNDARY) * EXT_BLK_SECT_TRAILER;
+
+ /* Find blocks_per_sect, according to position, no trailer */
+ if (sector_id < T4K_BOUNDARY)
+ blocks_count = STD_BLK_PER_SECT;
+ else
+ blocks_count = EXT_BLK_PER_SECT;
+
+ mf_ck->rws_block_end = mf_ck->rws_block_start + blocks_count;
+ mf_ck->rws_completed = 0;
+ mf_ck->rws_next_fct = next_func;
+
+ /* Being on the first block of the sector, unlock it */
+ return mifare_unlock_sector(mf_ck->rws_block_start,
+ mifare_write_sector_unlocked, mf_ck);
+}
+
+static int mifare_write_NFC_loop(uint8_t *resp, int length, void *data)
+{
+ struct mifare_cookie *mf_ck = data;
+ int err = 0;
+
+ if (length < 0 || resp[0] != 0) {
+ err = -EIO;
+ goto out_err;
+ }
+
+ /* Something more to write? */;
+ if (mf_ck->ndef->offset < mf_ck->ndef->length) {
+ err = mifare_write_sector(data, /* cookie */
+ GPOINTER_TO_INT(mf_ck->g_sect_list->data),
+ mifare_write_NFC_loop); /* next function */
+
+ mf_ck->g_sect_list = g_slist_remove(mf_ck->g_sect_list,
+ mf_ck->g_sect_list->data);
+
+ if (err < 0)
+ goto out_err;
+
+ } else {
+ /* Correct length of an NDEF message */
+ err = mifare_unlock_sector(NFC_1ST_BLOCK,
+ mifare_correct_length, mf_ck);
+
+ if (err < 0)
+ goto out_err;
+ }
+
+ return err;
+out_err:
+ return mifare_release(err, mf_ck);
+}
+
+static int mifare_write_NFC(void *data)
+{
+ struct mifare_cookie *mf_ck = data;
+ int err;
+
+ DBG("");
+
+ mf_ck->rws_completed = 0; /* written blocks */
+
+ /* First write here: */
+ err = mifare_write_sector(data, /* cookie */
+ GPOINTER_TO_INT(mf_ck->g_sect_list->data), /* sector id */
+ mifare_write_NFC_loop); /* next function */
+
+ mf_ck->g_sect_list = g_slist_remove(mf_ck->g_sect_list,
+ mf_ck->g_sect_list->data);
+
+ 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)
+{
+ struct mifare_cookie *cookie;
+ struct near_tag *tag;
+ size_t tag_size;
+ int err;
+
+ DBG("");
+
+ /* Check supported and tested Mifare type */
+ switch (tgt_subtype) {
+ case NEAR_TAG_NFC_T2_MIFARE_CLASSIC_1K:
+ case NEAR_TAG_NFC_T2_MIFARE_CLASSIC_4K:
+ break;
+ default:
+ near_error("Mifare tag type %d not supported.", tgt_subtype);
+ return -1;
+ }
+
+ /* Check if there's enough space on tag */
+ tag = near_tag_get_tag(adapter_idx, target_idx);
+ near_tag_get_data(tag, &tag_size);
+
+ if (tag_size < ndef->length) {
+ near_error("Not enough space on tag");
+ return -ENOSPC;
+ }
+
+ /* Alloc global cookie */
+ cookie = g_try_malloc0(sizeof(struct mifare_cookie));
+ if (cookie == NULL)
+ return -ENOMEM;
+
+ /* Get the nfcid1 */
+ cookie->nfcid1 = near_tag_get_nfcid(adapter_idx, target_idx,
+ &cookie->nfcid1_len);
+ cookie->adapter_idx = adapter_idx;
+ 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;
+ /*
+ * Mifare Classic Tag needs to be unlocked before writing
+ * This will check if public keys are allowed (NDEF could be "readable")
+ */
+ err = mifare_unlock_sector(MAD1_1ST_BLOCK, /* related block */
+ mifare_read_MAD1, /* callback */
+ cookie); /* target data */
+
+ if (err < 0)
+ return mifare_release(err, cookie);
+
+ return 0;
+}
memcpy(cmd->uid, tag->uid, UID_LENGTH);
}
-static void t1_cookie_release(struct t1_cookie *cookie)
+static int t1_cookie_release(int err, void *data)
{
+ struct t1_cookie *cookie = data;
+
+ DBG("%p", cookie);
+
if (cookie == NULL)
- return;
+ return err;
if (cookie->ndef)
g_free(cookie->ndef->data);
g_free(cookie->ndef);
g_free(cookie);
cookie = NULL;
+
+ return err;
}
-/* Read segments (128 bytes)and store them to the tag data block */
-static int segment_read_recv(uint8_t *resp, int length, void *data)
+/* Read segments (128 bytes) and store them to the tag data block */
+static int data_recv(uint8_t *resp, int length, void *data)
{
struct type1_tag *t1_tag = data;
struct type1_cmd t1_cmd;
length = length - LEN_STATUS_BYTE; /* ignore first byte */
- /* Add data to tag mem*/
+ /* Add data to tag mem */
tagdata = near_tag_get_data(t1_tag->tag, &data_length);
- memcpy(tagdata + t1_tag->data_read, resp+1, length);
+ memcpy(tagdata + t1_tag->data_read, resp + 1, length);
/* Next segment */
t1_tag->data_read = t1_tag->data_read + length;
t1_cmd.addr = (t1_tag->current_seg << 4) & 0xFF;
err = near_adapter_send(t1_tag->adapter_idx,
- (uint8_t *)&t1_cmd, sizeof(t1_cmd),
- segment_read_recv, t1_tag);
+ (uint8_t *) &t1_cmd, sizeof(t1_cmd),
+ data_recv, t1_tag);
if (err < 0)
goto out_err;
} else { /* This is the end */
return err;
}
-/* The dynamic read function:
+/*
+ * The dynamic read function:
* Bytes [0..3] : CC
* [4..8]: TLV Lock ControlIT (0x01, 0x03, v1, V2, V3)
* [9..13]: TLV Reserved Memory Control (0x02, 0x03, V1, V2, V3)
pndef = pndef + 5; /* skip TLV Lock bits bytes */
pndef = pndef + 5; /* skip TLV ControlIT bytes */
- /* Save first NFC bytes to tag memory
+ /*
+ * Save first NFC bytes to tag memory
* 10 blocks[0x3..0xC] of 8 bytes + 2 bytes from block 2
- * */
+ */
memcpy(tagdata, pndef, 10 * BLOCK_SIZE + 2);
/* Read the next one, up to the end of the data area */
return near_adapter_send(t1_tag->adapter_idx,
(uint8_t *)&t1_cmd, sizeof(t1_cmd),
- segment_read_recv, t1_tag);
+ data_recv, t1_tag);
}
static int meta_recv(uint8_t *resp, int length, void *data)
{
struct t1_cookie *cookie = data;
struct near_tag *tag;
- struct type1_tag *t1_tag = NULL;
+ struct type1_tag *t1_tag;
uint8_t *cc;
int err = -EOPNOTSUPP;
/* First byte is cmd status */
if (resp[OFFSET_STATUS_CMD] != 0) {
- DBG("Command failed: 0x%x",resp[OFFSET_STATUS_CMD]);
+ DBG("Command failed: 0x%x", resp[OFFSET_STATUS_CMD]);
err = -EIO;
goto out_err;
}
t1_tag->tag = tag;
memcpy(t1_tag->uid, cookie->uid, UID_LENGTH);
- /*s Set the ReadWrite flag */
+ /* Set the ReadWrite flag */
if (TAG_T1_WRITE_FLAG(cc) == TYPE1_NOWRITE_ACCESS)
near_tag_set_ro(tag, TRUE);
else
near_tag_set_memory_layout(tag, NEAR_TAG_MEMORY_DYNAMIC);
err = read_dynamic_tag(cc, length, t1_tag);
} else {
- err = -EOPNOTSUPP ;
+ err = -EOPNOTSUPP;
}
+ if (err < 0)
+ g_free(t1_tag);
+
out_err:
DBG("err %d", err);
if (err < 0 && cookie->cb)
cookie->cb(cookie->adapter_idx, cookie->target_idx, err);
- t1_cookie_release(cookie);
-
- return err;
+ return t1_cookie_release(err, cookie);
}
/*
/* First byte is cmd status */
if (resp[OFFSET_STATUS_CMD] != 0) {
- DBG("Command failed: 0x%x",resp[OFFSET_STATUS_CMD]);
+ DBG("Command failed: 0x%x", resp[OFFSET_STATUS_CMD]);
err = -EIO;
goto out_err;
}
if (err < 0 && cookie->cb)
cookie->cb(cookie->adapter_idx, cookie->target_idx, err);
- t1_cookie_release(cookie);
+ return t1_cookie_release(err, cookie);
+}
+
+static int nfctype1_read_meta(uint32_t adapter_idx, uint32_t target_idx,
+ near_tag_io_cb cb, uint8_t *uid)
+{
+ struct type1_cmd cmd;
+ struct t1_cookie *cookie;
+ int err;
+
+ DBG("");
+
+ memset(&cmd, 0, sizeof(cmd));
+
+ cookie = g_try_malloc0(sizeof(struct t1_cookie));
+ if (cookie == NULL)
+ return -ENOMEM;
+
+ cookie->adapter_idx = adapter_idx;
+ cookie->target_idx = target_idx;
+ cookie->cb = cb;
+
+ if (uid != NULL) {
+ cmd.cmd = CMD_READ_ALL; /* Read ALL cmd give 124 bytes */
+ 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);
+ } else {
+ cmd.cmd = CMD_RID;
+
+ err = near_adapter_send(adapter_idx, (uint8_t *) &cmd,
+ sizeof(cmd), rid_resp, cookie);
+ }
+
+ if (err < 0)
+ t1_cookie_release(err, cookie);
return err;
}
static int nfctype1_read(uint32_t adapter_idx,
uint32_t target_idx, near_tag_io_cb cb)
{
- struct type1_cmd t1_cmd;
- struct t1_cookie *cookie;
- uint8_t *uid, uid_length;
+ uint8_t *uid;
+ uint8_t uid_length;
+ int err;
DBG("");
uid = near_tag_get_nfcid(adapter_idx, target_idx, &uid_length);
if (uid == NULL || uid_length != UID_LENGTH) {
- if (uid != NULL && uid_length != UID_LENGTH) {
+ if (uid != NULL) {
near_error("Invalid UID");
g_free(uid);
return -EINVAL;
}
- t1_cmd.cmd = CMD_RID;
- t1_cmd.addr = 0;
- t1_cmd.data[0] = 0;
- memset(t1_cmd.uid, 0, UID_LENGTH);
-
- cookie = g_try_malloc0(sizeof(struct t1_cookie));
- if (cookie == NULL) {
- g_free(uid);
- return -ENOMEM;
- }
-
- cookie->adapter_idx = adapter_idx;
- cookie->target_idx = target_idx;
- cookie->cb = cb;
-
- return near_adapter_send(adapter_idx,
- (uint8_t *)&t1_cmd, sizeof(t1_cmd),
- rid_resp, cookie);
+ return nfctype1_read_meta(adapter_idx, target_idx, cb, NULL);
}
- t1_cmd.cmd = CMD_READ_ALL; /* Read ALL cmd give 124 bytes */
- t1_cmd.addr = 0; /* NA */
- t1_cmd.data[0] = 0;
- memcpy(t1_cmd.uid, uid, UID_LENGTH);
-
- cookie = g_try_malloc0(sizeof(struct t1_cookie));
- if (cookie == NULL) {
- g_free(uid);
- return -ENOMEM;
- }
-
- cookie->adapter_idx = adapter_idx;
- cookie->target_idx = target_idx;
- memcpy(cookie->uid, uid, UID_LENGTH);
- cookie->cb = cb;
+ err = nfctype1_read_meta(adapter_idx, target_idx, cb, uid);
g_free(uid);
- return near_adapter_send(adapter_idx, (uint8_t *)&t1_cmd, sizeof(t1_cmd),
- meta_recv, cookie);
+ return err;
}
static int write_nmn_e1_resp(uint8_t *resp, int length, void *data)
cookie->cb(cookie->adapter_idx, cookie->target_idx, err);
- t1_cookie_release(cookie);
-
- return err;
+ return t1_cookie_release(err, cookie);
}
static int write_nmn_e1(struct t1_cookie *cookie)
cmd.data[0] = TYPE1_MAGIC;
memcpy(cmd.uid, cookie->uid, UID_LENGTH);
- return near_adapter_send(cookie->adapter_idx, (uint8_t *)&cmd,
+ return near_adapter_send(cookie->adapter_idx, (uint8_t *) &cmd,
sizeof(cmd), write_nmn_e1_resp, cookie);
}
-static int data_write(uint8_t *resp, int length, void *data)
+static int data_write_resp(uint8_t *resp, int length, void *data)
{
struct t1_cookie *cookie = data;
uint8_t addr = 0;
if (length < 0) {
err = length;
- goto out;
+ goto out_err;
}
if (resp[OFFSET_STATUS_CMD] != 0) {
err = -EIO;
- goto out;
+ goto out_err;
}
if (cookie->ndef->offset > cookie->ndef->length)
cookie->ndef->offset++;
cookie->current_byte++;
- err = near_adapter_send(cookie->adapter_idx, (uint8_t *)&cmd,
- sizeof(cmd), data_write, cookie);
+ err = near_adapter_send(cookie->adapter_idx, (uint8_t *) &cmd,
+ sizeof(cmd), data_write_resp, cookie);
if (err < 0)
- goto out;
+ goto out_err;
return 0;
-out:
+out_err:
if (err < 0 && cookie->cb)
cookie->cb(cookie->adapter_idx, cookie->target_idx, err);
- t1_cookie_release(cookie);
-
- return err;
+ return t1_cookie_release(err, cookie);
}
-static int write_nmn_0(uint32_t adapter_idx, uint32_t target_idx,
+static int data_write(uint32_t adapter_idx, uint32_t target_idx,
struct near_ndef_message *ndef, near_tag_io_cb cb)
{
int err;
g_free(uid);
- err = near_adapter_send(cookie->adapter_idx, (uint8_t *)&cmd,
- sizeof(cmd), data_write, cookie);
+ err = near_adapter_send(cookie->adapter_idx, (uint8_t *) &cmd,
+ sizeof(cmd), data_write_resp, cookie);
if (err < 0)
- goto out;
+ goto out_err;
return 0;
-out:
- t1_cookie_release(cookie);
-
- return err;
+out_err:
+ return t1_cookie_release(err, cookie);
}
/*
return -EINVAL;
/* This check is valid for only static tags.
- * Max data length on Type 2 Tag including TLV's
+ * Max data length on Type 1 Tag including TLV's
* is TYPE1_STATIC_MAX_DATA_SIZE */
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 data");
- return -ENOMEM;
+ near_error("not enough space on tag");
+ return -ENOSPC;
}
}
- return write_nmn_0(adapter_idx, target_idx, ndef, cb);
+ return data_write(adapter_idx, target_idx, ndef, cb);
}
static int check_presence(uint8_t *resp, int length, void *data)
cookie->cb(cookie->adapter_idx,
cookie->target_idx, err);
- t1_cookie_release(cookie);
-
- return err;
+ return t1_cookie_release(err, cookie);
}
static int nfctype1_check_presence(uint32_t adapter_idx,
cookie->target_idx = target_idx;
cookie->cb = cb;
- err = near_adapter_send(adapter_idx, (uint8_t *)&t1_cmd, sizeof(t1_cmd),
- check_presence, cookie);
+ err = near_adapter_send(adapter_idx, (uint8_t *) &t1_cmd,
+ sizeof(t1_cmd), check_presence, cookie);
if (err < 0)
- goto out;
+ goto out_err;
return 0;
-out:
- t1_cookie_release(cookie);
-
- return err;
+out_err:
+ return t1_cookie_release(err, cookie);
}
static int format_resp(uint8_t *resp, int length, void *data)
if (length < 0 || resp[0] != 0) {
err = -EIO;
- goto out;
+ goto out_err;
}
if (cookie->current_byte < LEN_CC_BYTES) {
cookie->current_byte++;
memcpy(cmd.uid, cookie->uid, UID_LENGTH);
- err = near_adapter_send(cookie->adapter_idx, (uint8_t *)&cmd,
+ err = near_adapter_send(cookie->adapter_idx, (uint8_t *) &cmd,
sizeof(cmd), format_resp, cookie);
if (err < 0)
- goto out;
+ goto out_err;
return 0;
} else {
tag = near_tag_get_tag(cookie->adapter_idx, cookie->target_idx);
if (tag == NULL) {
err = -EINVAL;
- goto out;
+ goto out_err;
}
DBG("Done formatting");
near_tag_set_blank(tag, FALSE);
}
-out:
+out_err:
if (cookie->cb)
cookie->cb(cookie->adapter_idx, cookie->target_idx, err);
- t1_cookie_release(cookie);
-
- return err;
+ return t1_cookie_release(err, cookie);
}
static int nfctype1_format(uint32_t adapter_idx, uint32_t target_idx,
cookie = g_try_malloc0(sizeof(struct t1_cookie));
if (cookie == NULL) {
err = -EINVAL;
- goto out;
+ goto out_err;
}
cookie->adapter_idx = adapter_idx;
memcpy(cmd.uid, cookie->uid, UID_LENGTH);
g_free(uid);
- err = near_adapter_send(cookie->adapter_idx, (uint8_t *)&cmd,
+ err = near_adapter_send(cookie->adapter_idx, (uint8_t *) &cmd,
sizeof(cmd), format_resp, cookie);
if (err < 0)
- goto out;
+ goto out_err;
return 0;
-out:
+out_err:
g_free(cookie);
g_free(uid);
extern int mifare_read(uint32_t adapter_idx, uint32_t target_idx,
near_tag_io_cb cb, enum near_tag_sub_type tgt_subtype);
+extern int mifare_check_presence(uint32_t adapter_idx, uint32_t target_idx,
+ near_tag_io_cb cb, enum near_tag_sub_type tgt_subtype);
+
+extern 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);
+
#define CMD_READ 0x30
#define CMD_READ_SIZE 0x02
uint8_t read_write;
};
-static void t2_cookie_release(struct t2_cookie *cookie)
+static int t2_cookie_release(int err, void *data)
{
+ struct t2_cookie *cookie = data;
+
+ DBG("%p", cookie);
+
if (cookie == NULL)
- return;
+ return err;
if (cookie->ndef)
g_free(cookie->ndef->data);
g_free(cookie->ndef);
g_free(cookie);
cookie = NULL;
+
+ return err;
}
static int data_recv(uint8_t *resp, int length, void *data)
DBG("adapter %d", adapter_idx);
return near_adapter_send(adapter_idx,
- (uint8_t *)&cmd, CMD_READ_SIZE,
+ (uint8_t *) &cmd, CMD_READ_SIZE,
data_recv, tag);
}
adapter_idx = near_tag_get_adapter_idx(tag->tag);
return near_adapter_send(adapter_idx,
- (uint8_t *)&cmd, CMD_READ_SIZE,
+ (uint8_t *) &cmd, CMD_READ_SIZE,
data_recv, tag);
}
if (length < 0) {
err = length;
- goto out;
+ goto out_err;
}
if (resp[0] != 0) {
err = -EIO;
- goto out;
+ goto out_err;
}
cc = TAG_DATA_CC(resp + NFC_HEADER_SIZE);
TYPE2_DATA_SIZE_48 << 3));
if (err < 0)
- goto out;
+ goto out_err;
tag = near_tag_get_tag(cookie->adapter_idx, cookie->target_idx);
if (tag == NULL) {
err = -ENOMEM;
- goto out;
+ goto out_err;
}
t2_tag = g_try_malloc0(sizeof(struct type2_tag));
if (t2_tag == NULL) {
err = -ENOMEM;
- goto out;
+ goto out_err;
}
t2_tag->adapter_idx = cookie->adapter_idx;
err = data_read(t2_tag);
if (err < 0)
- goto out;
+ goto out_tag;
- t2_cookie_release(cookie);
+ return t2_cookie_release(err, cookie);
- return 0;
+out_tag:
+ g_free(t2_tag);
-out:
+out_err:
if (err < 0 && cookie->cb)
cookie->cb(cookie->adapter_idx, cookie->target_idx, err);
- t2_cookie_release(cookie);
-
- return err;
+ return t2_cookie_release(err, cookie);
}
static int nfctype2_read_meta(uint32_t adapter_idx, uint32_t target_idx,
cookie->target_idx = target_idx;
cookie->cb = cb;
- err = near_adapter_send(adapter_idx, (uint8_t *)&cmd, CMD_READ_SIZE,
+ err = near_adapter_send(adapter_idx, (uint8_t *) &cmd, CMD_READ_SIZE,
meta_recv, cookie);
if (err < 0)
g_free(cookie);
/* 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,
+ err = mifare_read(adapter_idx, target_idx,
cb, tgt_subtype);
break;
default:
- DBG("Unknown TAG Type 2 subtype (%d)", tgt_subtype);
+ DBG("Unknown Tag Type 2 subtype %d", tgt_subtype);
err = -1;
break;
}
if (length < 0 || resp[0] != 0) {
err = -EIO;
- goto out;
+ goto out_err;
}
if (cookie->ndef->offset > cookie->ndef->length) {
if (cookie->cb)
cookie->cb(cookie->adapter_idx, cookie->target_idx, 0);
- t2_cookie_release(cookie);
-
- return 0;
+ return t2_cookie_release(0, cookie);
}
cmd.cmd = CMD_WRITE;
cookie->ndef->offset = cookie->ndef->length + 1;
}
- err = near_adapter_send(cookie->adapter_idx, (uint8_t *)&cmd,
+ err = near_adapter_send(cookie->adapter_idx, (uint8_t *) &cmd,
sizeof(cmd), data_write_resp, cookie);
-
if (err < 0)
- goto out;
+ goto out_err;
return 0;
-out:
+out_err:
if (err < 0 && cookie->cb)
cookie->cb(cookie->adapter_idx, cookie->target_idx, err);
- t2_cookie_release(cookie);
-
- return err;
+ return t2_cookie_release(err, cookie);
}
static int data_write(uint32_t adapter_idx, uint32_t target_idx,
cookie->ndef->offset += BLOCK_SIZE;
cookie->current_block++;
- err = near_adapter_send(cookie->adapter_idx, (uint8_t *)&cmd,
+ err = near_adapter_send(cookie->adapter_idx, (uint8_t *) &cmd,
sizeof(cmd), data_write_resp, cookie);
if (err < 0)
- goto out;
+ goto out_err;
return 0;
-out:
- t2_cookie_release(cookie);
-
- return err;
+out_err:
+ return t2_cookie_release(err, cookie);
}
static int nfctype2_write(uint32_t adapter_idx, uint32_t target_idx,
{
struct near_tag *tag;
enum near_tag_sub_type tgt_subtype;
+ int err;
DBG("");
tgt_subtype = near_tag_get_subtype(adapter_idx, target_idx);
- if (tgt_subtype != NEAR_TAG_NFC_T2_MIFARE_ULTRALIGHT) {
- DBG("Unknown Tag Type 2 subtype (%d)", tgt_subtype);
- return -1;
- }
-
- /* This check is valid for only static tags.
- * Max data length on Type 2 Tag including TLV's is NDEF_MAX_SIZE */
- 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;
+ switch (tgt_subtype) {
+ case NEAR_TAG_NFC_T2_MIFARE_ULTRALIGHT:
+ /*
+ * This check is valid for only static tags.
+ * Max data length on Type 2 Tag
+ * including TLV's is NDEF_MAX_SIZE
+ */
+ 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 = data_write(adapter_idx, target_idx, ndef, cb);
+ break;
+ /* 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,
+ cb, tgt_subtype);
+ break;
+ default:
+ DBG("Unknown TAG Type 2 subtype %d", tgt_subtype);
+ err = -EINVAL;
+ break;
}
- return data_write(adapter_idx, target_idx, ndef, cb);
+ return err;
}
static int check_presence(uint8_t *resp, int length, void *data)
cookie->cb(cookie->adapter_idx,
cookie->target_idx, err);
- t2_cookie_release(cookie);
-
- return err;
+ return t2_cookie_release(err, cookie);
}
static int nfctype2_check_presence(uint32_t adapter_idx, uint32_t target_idx,
{
struct type2_cmd cmd;
struct t2_cookie *cookie;
+ enum near_tag_sub_type tgt_subtype;
int err;
DBG("");
- cmd.cmd = CMD_READ;
- cmd.block = META_BLOCK_START;
+ tgt_subtype = near_tag_get_subtype(adapter_idx, target_idx);
- cookie = g_try_malloc0(sizeof(struct t2_cookie));
- if (cookie == NULL)
- return -ENOMEM;
+ switch (tgt_subtype) {
+ case NEAR_TAG_NFC_T2_MIFARE_ULTRALIGHT:
+ cmd.cmd = CMD_READ;
+ cmd.block = META_BLOCK_START;
- cookie->adapter_idx = adapter_idx;
- cookie->target_idx = target_idx;
- cookie->cb = cb;
+ cookie = g_try_malloc0(sizeof(struct t2_cookie));
+ if (cookie == NULL)
+ return -ENOMEM;
- err = near_adapter_send(adapter_idx, (uint8_t *)&cmd, CMD_READ_SIZE,
- check_presence, cookie);
- if (err < 0)
- goto out;
+ cookie->adapter_idx = adapter_idx;
+ cookie->target_idx = target_idx;
+ cookie->cb = cb;
- return 0;
+ err = near_adapter_send(adapter_idx, (uint8_t *) &cmd,
+ CMD_READ_SIZE, check_presence, cookie);
+ if (err < 0)
+ goto out_err;
-out:
- t2_cookie_release(cookie);
+ 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,
+ 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);
}
static int format_resp(uint8_t *resp, int length, void *data)
if (length < 0 || resp[0] != 0) {
err = -EIO;
- goto out;
+ goto out_err;
}
tag = near_tag_get_tag(cookie->adapter_idx, cookie->target_idx);
if (tag == NULL) {
err = -EINVAL;
- goto out;
+ goto out_err;
}
DBG("Done formatting");
near_tag_set_blank(tag, FALSE);
-out:
+out_err:
if (cookie->cb)
cookie->cb(cookie->adapter_idx, cookie->target_idx, err);
- t2_cookie_release(cookie);
-
- return err;
+ return t2_cookie_release(err, cookie);
}
static int nfctype2_format(uint32_t adapter_idx, uint32_t target_idx,
tgt_subtype = near_tag_get_subtype(adapter_idx, target_idx);
if (tgt_subtype != NEAR_TAG_NFC_T2_MIFARE_ULTRALIGHT) {
- DBG("Unknown Tag Type 2 subtype (%d)", tgt_subtype);
+ DBG("Unknown Tag Type 2 subtype %d", tgt_subtype);
return -1;
}
if (t2_cc == NULL || cc_ndef == NULL || cookie == NULL) {
err = -ENOMEM;
- goto out;
+ goto out_err;
}
t2_cc->magic = TYPE2_MAGIC;
cookie->target_idx = target_idx;
cookie->current_block = CC_BLOCK_START;
cookie->ndef = cc_ndef;
- cookie->ndef->data = (uint8_t *)t2_cc;
+ cookie->ndef->data = (uint8_t *) t2_cc;
cookie->cb = cb;
cmd.cmd = CMD_WRITE;
cmd.block = CC_BLOCK_START;
- memcpy(cmd.data, (uint8_t *)t2_cc, BLOCK_SIZE);
+ memcpy(cmd.data, (uint8_t *) t2_cc, BLOCK_SIZE);
- err = near_adapter_send(cookie->adapter_idx, (uint8_t *)&cmd,
+ err = near_adapter_send(cookie->adapter_idx, (uint8_t *) &cmd,
sizeof(cmd), format_resp, cookie);
-out:
+out_err:
if (err < 0) {
g_free(t2_cc);
g_free(cc_ndef);
uint8_t mc_block[BLOCK_SIZE];
};
-static void t3_cookie_release(struct t3_cookie *cookie)
+static int t3_cookie_release(int err, void *data)
{
+ struct t3_cookie *cookie = data;
+
+ DBG("%p", cookie);
+
if (cookie == NULL)
- return;
+ return err;
if (cookie->ndef != NULL)
g_free(cookie->ndef->data);
g_free(cookie->ndef);
g_free(cookie);
cookie = NULL;
+
+ return err;
}
/* common: Initialize structure to write block */
/* common: Initialize structure to read block */
static void prepare_read_block(uint8_t cur_block,
uint8_t *UID,
- struct type3_cmd *cmd )
+ struct type3_cmd *cmd)
{
- cmd->cmd = CMD_READ_WO_ENCRYPT; /* command */
+ cmd->cmd = CMD_READ_WO_ENCRYPT; /* command */
memcpy(cmd->data, UID, LEN_ID); /* IDm */
cmd->data[LEN_ID] = 1; /* number of service */
int err = 0;
if (resp[OFS_NFC_STATUS] != 0) {
- DBG("NFC Command failed: 0x%x",resp[OFS_NFC_STATUS]);
+ DBG("NFC Command failed: 0x%x", resp[OFS_NFC_STATUS]);
err = -EIO;
}
- if (resp[OFS_CMD_RESP] != reply_code ) {
+ if (resp[OFS_CMD_RESP] != reply_code) {
DBG("Felica cmd failed: 0x%x", resp[OFS_CMD_RESP]);
err = -EIO;
}
return err;
}
-static int nfctype3_data_recv(uint8_t *resp, int length, void *data)
+static int data_recv(uint8_t *resp, int length, void *data)
{
struct type3_tag *tag = data;
struct type3_cmd cmd;
if (length < 0) {
err = -EIO;
- goto out;
+ goto out_err;
}
nfc_data = near_tag_get_data(tag->tag, &data_length);
- length_read = length - OFS_READ_DATA ;
+ length_read = length - OFS_READ_DATA;
current_length = tag->current_block * BLOCK_SIZE;
if (current_length + (length - OFS_READ_DATA) > data_length)
length_read = data_length - current_length;
tag->current_block += read_blocks;
prepare_read_block(DATA_BLOCK_START + tag->current_block,
- tag->IDm, &cmd );
+ tag->IDm, &cmd);
+
+ err = near_adapter_send(adapter_idx, (uint8_t *) &cmd, cmd.len,
+ data_recv, tag);
- err = near_adapter_send(adapter_idx, (uint8_t *)&cmd, cmd.len,
- nfctype3_data_recv, tag);
if (err < 0)
- goto out;
+ goto out_err;
return 0;
-out:
+out_err:
if (err < 0 && tag->cb)
tag->cb(adapter_idx, target_idx, err);
return err;
}
-static int nfctype3_data_read(struct type3_tag *tag)
+static int data_read(struct type3_tag *tag)
{
struct type3_cmd cmd;
uint32_t adapter_idx;
return near_adapter_send(adapter_idx,
(uint8_t *) &cmd, cmd.len,
- nfctype3_data_recv, tag);
+ data_recv, tag);
}
/* Read block 0 to retrieve the data length */
int err = 0;
struct near_tag *tag;
struct type3_tag *t3_tag = NULL;
- uint32_t ndef_data_length;
+ uint32_t ndef_data_length;
DBG("%d", length);
if (length < 0) {
err = -EIO;
- goto out;
+ goto out_err;
}
err = check_recv_frame(resp, RESP_READ_WO_ENCRYPT);
if (err < 0)
- goto out;
+ goto out_err;
if (resp[OFS_READ_FLAG] != 0) {
DBG("Status 0x%x", resp[OFS_READ_FLAG]);
err = -EIO;
- goto out;
+ goto out_err;
}
/* Block 0:[11 - 13]: length is a 3 bytes value */
err = near_tag_add_data(cookie->adapter_idx, cookie->target_idx,
NULL, ndef_data_length);
if (err < 0)
- goto out;
+ goto out_err;
tag = near_tag_get_tag(cookie->adapter_idx, cookie->target_idx);
if (tag == NULL) {
err = -ENOMEM;
- goto out;
+ goto out_err;
}
/* Block 0:[10]: RW Flag. 1 for RW */
t3_tag = g_try_malloc0(sizeof(struct type3_tag));
if (t3_tag == NULL) {
err = -ENOMEM;
- goto out;
+ goto out_err;
}
- memcpy(t3_tag->IDm, cookie->IDm , LEN_ID);
+ memcpy(t3_tag->IDm, cookie->IDm, LEN_ID);
near_tag_set_idm(tag, cookie->IDm, LEN_ID);
near_tag_set_attr_block(tag, resp + OFS_READ_DATA, BLOCK_SIZE);
t3_tag->cb = cookie->cb;
t3_tag->tag = tag;
- err = nfctype3_data_read(t3_tag);
+ err = data_read(t3_tag);
-out:
+out_err:
if (err < 0) {
if (cookie->cb)
cookie->cb(cookie->adapter_idx, cookie->target_idx,
g_free(t3_tag);
}
- t3_cookie_release(cookie);
-
- return err;
+ return t3_cookie_release(err, cookie);
}
static int poll_ndef_system_code(uint8_t *resp, int length, void *data)
int err = 0;
struct type3_cmd cmd;
- DBG(" length: %d", length);
+ DBG("length: %d", length);
if (length < 0) {
err = -EIO;
- goto out;
+ goto out_err;
}
err = check_recv_frame(resp, RESP_POLL);
if (err < 0)
- goto out;
+ goto out_err;
prepare_read_block(META_BLOCK_START, cookie->IDm, &cmd);
- err = near_adapter_send(cookie->adapter_idx, (uint8_t *)&cmd,
+ err = near_adapter_send(cookie->adapter_idx, (uint8_t *) &cmd,
cmd.len, nfctype3_recv_block_0, cookie);
if (err < 0)
- goto out;
+ goto out_err;
return 0;
-out:
+out_err:
if (err < 0 && cookie->cb)
cookie->cb(cookie->adapter_idx,
cookie->target_idx, err);
- t3_cookie_release(cookie);
-
- return err;
+ return t3_cookie_release(err, cookie);
}
static int check_sys_op_in_mc_block(uint8_t *resp, int length, void *data)
if (length < 0) {
err = -EIO;
- goto out;
+ goto out_err;
}
err = check_recv_frame(resp, RESP_READ_WO_ENCRYPT);
if (err < 0)
- goto out;
+ goto out_err;
if (resp[SYSTEM_OPTION_OFFSET] == 0x00) {
DBG("Blank tag detected");
cookie->target_idx,
NULL, 1 /* dummy length */);
if (err < 0)
- goto out;
+ goto out_err;
tag = near_tag_get_tag(cookie->adapter_idx,
cookie->target_idx);
if (tag == NULL) {
err = -ENOMEM;
- goto out;
+ goto out_err;
}
near_tag_set_idm(tag, cookie->IDm, LEN_ID);
cookie->cb(cookie->adapter_idx,
cookie->target_idx, 0);
- t3_cookie_release(cookie);
-
- return 0;
+ return t3_cookie_release(0, cookie);
} else {
/* CMD POLL */
cmd.cmd = CMD_POLL; /* POLL command */
/* data len + 2 bytes */
cmd.len = LEN_CMD + LEN_CMD_LEN + 4 ;
- err = near_adapter_send(cookie->adapter_idx, (uint8_t *)&cmd,
+ err = near_adapter_send(cookie->adapter_idx, (uint8_t *) &cmd,
cmd.len , poll_ndef_system_code, cookie);
}
if (err < 0)
- goto out;
+ goto out_err;
return 0;
-out:
+out_err:
if (err < 0 && cookie->cb)
cookie->cb(cookie->adapter_idx, cookie->target_idx, err);
- t3_cookie_release(cookie);
-
- return err;
+ return t3_cookie_release(err, cookie);
}
static int receive_system_code(uint8_t *resp, int length, void *data)
struct type3_cmd cmd;
uint16_t system_code;
- DBG(" length: %d", length);
+ DBG("length: %d", length);
if (length < 0) {
err = -EIO;
- goto out;
+ goto out_err;
}
err = check_recv_frame(resp, RESP_POLL);
if (err < 0)
- goto out;
+ goto out_err;
cookie->ic_type = resp[IC_TYPE_OFFSET];
memcpy(cookie->IDm, resp + OFS_IDM, LEN_ID);
- system_code = ((uint16_t)(resp[length - 2])) << 8;
+ system_code = ((uint16_t) (resp[length - 2])) << 8;
system_code |= resp[length - 1];
switch (resp[IC_TYPE_OFFSET]) {
case FELICA_LITE_IC_TYPE:
prepare_read_block(FELICA_LITE_MC_BLOCK, cookie->IDm, &cmd);
- err = near_adapter_send(cookie->adapter_idx, (uint8_t *)&cmd,
+ err = near_adapter_send(cookie->adapter_idx, (uint8_t *) &cmd,
cmd.len, check_sys_op_in_mc_block,
cookie);
break;
/* data len + 2 bytes */
cmd.len = LEN_CMD + LEN_CMD_LEN + 4 ;
- err = near_adapter_send(cookie->adapter_idx, (uint8_t *)&cmd,
+ err = near_adapter_send(cookie->adapter_idx, (uint8_t *) &cmd,
cmd.len, poll_ndef_system_code, cookie);
}
if (err < 0)
- goto out;
+ goto out_err;
return 0;
-out:
+out_err:
if (err < 0 && cookie->cb)
cookie->cb(cookie->adapter_idx, cookie->target_idx, err);
- t3_cookie_release(cookie);
-
- return err;
+ return t3_cookie_release(err, cookie);
}
static int nfctype3_read(uint32_t adapter_idx,
cmd.data[3] = 0x00; /* time slot */
/* data len + 2 bytes */
- cmd.len = LEN_CMD + LEN_CMD_LEN + 4 ;
+ cmd.len = LEN_CMD + LEN_CMD_LEN + 4;
cookie = g_try_malloc0(sizeof(struct t3_cookie));
if (cookie == NULL)
cookie->target_idx = target_idx;
cookie->cb = cb;
- err = near_adapter_send(adapter_idx, (uint8_t *)&cmd,
- cmd.len , receive_system_code, cookie);
+ err = near_adapter_send(adapter_idx, (uint8_t *) &cmd,
+ cmd.len, receive_system_code, cookie);
if (err < 0)
g_free(cookie);
if (length < 0) {
err = -EIO;
- goto out;
+ goto out_err;
}
err = check_recv_frame(resp, RESP_WRITE_WO_ENCRYPT);
if (err < 0)
- goto out;
+ goto out_err;
DBG("Done writing");
-out:
+out_err:
if (cookie->cb)
cookie->cb(cookie->adapter_idx, cookie->target_idx, err);
- t3_cookie_release(cookie);
-
- return err;
+ return t3_cookie_release(err, cookie);
}
static int update_attr_block(struct t3_cookie *cookie)
if (length < 0) {
err = -EIO;
- goto out;
+ goto out_err;
}
err = check_recv_frame(resp, RESP_WRITE_WO_ENCRYPT);
if (err < 0)
- goto out;
+ goto out_err;
if (cookie->ndef->offset >= cookie->ndef->length) {
err = update_attr_block(cookie);
if (err < 0)
- goto out;
+ goto out_err;
return 0;
}
cookie->current_block++;
cookie->ndef->offset += BLOCK_SIZE;
- err = near_adapter_send(cookie->adapter_idx, (uint8_t *)&cmd, cmd.len,
+ err = near_adapter_send(cookie->adapter_idx, (uint8_t *) &cmd, cmd.len,
data_write_resp, cookie);
if (err < 0)
- goto out;
+ goto out_err;
return 0;
-out:
+out_err:
if (err < 0 && cookie->cb)
cookie->cb(cookie->adapter_idx, cookie->target_idx, err);
- t3_cookie_release(cookie);
-
- return err;
+ return t3_cookie_release(err, cookie);
}
static int data_write(uint32_t adapter_idx, uint32_t target_idx,
cookie = g_try_malloc0(sizeof(struct t3_cookie));
if (cookie == NULL) {
err = -ENOMEM;
- goto out;
+ goto out_err;
}
cookie->adapter_idx = adapter_idx;
idm = near_tag_get_idm(tag, &len);
if (idm == NULL) {
err = -EINVAL;
- goto out;
+ goto out_err;
}
memcpy(cookie->IDm, idm, len);
attr = near_tag_get_attr_block(tag, &len);
if (attr == NULL) {
err = -EINVAL;
- goto out;
+ goto out_err;
}
memcpy(cookie->attr, attr, len);
- nmaxb = (((uint16_t)(cookie->attr[3])) << 8) | cookie->attr[4];
+ 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;
+ goto out_err;
}
cookie->attr[9] = 0x0F; /* writing data in progress */
for (i = 0; i < 14; i++)
checksum += cookie->attr[i];
- cookie->attr[14] = (uint8_t)(checksum >> 8);
- cookie->attr[15] = (uint8_t)(checksum);
+ cookie->attr[14] = (uint8_t) (checksum >> 8);
+ cookie->attr[15] = (uint8_t) checksum;
prepare_write_block(cookie->IDm, &cmd, cookie->current_block,
cookie->attr);
cookie->current_block++;
- err = near_adapter_send(adapter_idx, (uint8_t *)&cmd, cmd.len,
+ err = near_adapter_send(adapter_idx, (uint8_t *) &cmd, cmd.len,
data_write_resp, cookie);
if (err < 0)
- goto out;
+ goto out_err;
return 0;
-out:
- t3_cookie_release(cookie);
-
- return err;
+out_err:
+ return t3_cookie_release(err, cookie);
}
static int nfctype3_write(uint32_t adapter_idx, uint32_t target_idx,
return data_write(adapter_idx, target_idx, ndef, tag, cb);
}
-static int nfctype3_check_recv_UID(uint8_t *resp, int length, void *data)
+static int check_presence(uint8_t *resp, int length, void *data)
{
- struct t3_cookie *rcv_cookie = data;
+ struct t3_cookie *cookie = data;
int err = 0;
DBG("length %d", length);
if (length < 0)
err = -EIO;
- if (rcv_cookie->cb)
- rcv_cookie->cb(rcv_cookie->adapter_idx,
- rcv_cookie->target_idx, err);
-
- t3_cookie_release(rcv_cookie);
+ if (cookie->cb)
+ cookie->cb(cookie->adapter_idx,
+ cookie->target_idx, err);
- return err;
+ return t3_cookie_release(err, cookie);
}
static int nfctype3_check_presence(uint32_t adapter_idx,
cookie->target_idx = target_idx;
cookie->cb = cb;
- err = near_adapter_send(adapter_idx, (uint8_t *)&cmd,
- cmd.len , nfctype3_check_recv_UID, cookie);
+ err = near_adapter_send(adapter_idx, (uint8_t *) &cmd,
+ cmd.len, check_presence, cookie);
+
if (err < 0)
- goto out;
+ goto out_err;
return 0;
-out:
- t3_cookie_release(cookie);
-
- return err;
+out_err:
+ return t3_cookie_release(err, cookie);
}
static int format_resp(uint8_t *resp, int length, void *data)
if (length < 0) {
err = -EIO;
- goto out;
+ goto out_err;
}
err = check_recv_frame(resp, RESP_WRITE_WO_ENCRYPT);
if (err < 0)
- goto out;
+ goto out_err;
tag = near_tag_get_tag(cookie->adapter_idx, cookie->target_idx);
if (tag == NULL) {
err = -ENOMEM;
- goto out;
+ goto out_err;
}
near_tag_set_ro(tag, FALSE);
DBG("Formatting is done");
-out:
+out_err:
if (cookie->cb)
cookie->cb(cookie->adapter_idx, cookie->target_idx, err);
- t3_cookie_release(cookie);
-
- return err;
+ return t3_cookie_release(err, cookie);
}
static int write_attr_block(uint8_t *resp, int length , void *data)
if (length < 0) {
err = -EIO;
- goto out;
+ goto out_err;
}
err = check_recv_frame(resp, RESP_WRITE_WO_ENCRYPT);
if (err < 0)
- goto out;
+ goto out_err;
cookie->attr[0] = NDEF_MAPPING_VERSION;
cookie->attr[1] = MAX_READ_BLOCKS_PER_CHECK;
prepare_write_block(cookie->IDm, &cmd, META_BLOCK_START,
cookie->attr);
- err = near_adapter_send(cookie->adapter_idx, (uint8_t *)&cmd,
+ err = near_adapter_send(cookie->adapter_idx, (uint8_t *) &cmd,
cmd.len, format_resp, cookie);
if (err < 0)
- goto out;
+ goto out_err;
return 0;
-out:
+out_err:
if (err < 0 && cookie->cb)
cookie->cb(cookie->adapter_idx, cookie->target_idx, err);
- t3_cookie_release(cookie);
-
- return err;
+ return t3_cookie_release(err, cookie);
}
static int write_mc_block(uint8_t *resp, int length, void *data)
if (length < 0) {
err = -EIO;
- goto out;
+ goto out_err;
}
err = check_recv_frame(resp, RESP_READ_WO_ENCRYPT);
if (err < 0)
- goto out;
+ goto out_err;
if (resp[OFS_READ_FLAG] != 0) {
DBG("Status 0x%x", resp[OFS_READ_FLAG]);
err = -EIO;
- goto out;
+ goto out_err;
}
memcpy(cookie->mc_block, resp + 14, BLOCK_SIZE);
cookie->mc_block[3] = 1;
prepare_write_block(cookie->IDm, &cmd, FELICA_LITE_MC_BLOCK,
cookie->mc_block);
- err = near_adapter_send(cookie->adapter_idx, (uint8_t *)&cmd,
+ err = near_adapter_send(cookie->adapter_idx, (uint8_t *) &cmd,
cmd.len, write_attr_block, cookie);
if (err < 0)
- goto out;
+ goto out_err;
return 0;
-out:
+out_err:
if (err < 0 && cookie->cb)
cookie->cb(cookie->adapter_idx, cookie->target_idx, err);
- t3_cookie_release(cookie);
-
- return err;
+ return t3_cookie_release(err, cookie);
}
static int nfctype3_format(uint32_t adapter_idx,
idm = near_tag_get_idm(tag, &len);
if (idm == NULL) {
err = -EINVAL;
- goto out;
+ goto out_err;
}
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,
+ err = near_adapter_send(cookie->adapter_idx, (uint8_t *) &cmd,
cmd.len, write_mc_block, cookie);
if (err < 0)
- goto out;
+ goto out_err;
return 0;
-out:
- t3_cookie_release(cookie);
-
- return err;
+out_err:
+ return t3_cookie_release(err, cookie);
}
static struct near_tag_driver type1_driver = {
#include <near/ndef.h>
#include <near/tlv.h>
-#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
#define NFC_STATUS 0
#define NFC_STATUS_BYTE_LEN 1
cmd->data[cmd_data_length] = 0;
}
- err = near_adapter_send(in_rcv->adapter_idx, (uint8_t *)cmd,
+ 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 ISO_send_cmd(
0x00, /* CLA */
0xB0, /* INS: Select file */
- (uint8_t)((offset & 0xFF00)>>8),
- (uint8_t)(offset & 0xFF),
+ (uint8_t) ((offset & 0xFF00) >> 8),
+ (uint8_t) (offset & 0xFF),
0, /* no data send */
readsize, /* bytes to read */
FALSE,
return ISO_send_cmd(
0x00, /* CLA */
0xD6, /* INS: Select file */
- (uint8_t)((offset & 0xFF00) >> 8),
- (uint8_t)(offset & 0xFF),
+ (uint8_t) ((offset & 0xFF00) >> 8),
+ (uint8_t) (offset & 0xFF),
data, /* length of NDEF data */
nlen, /* NLEN + NDEF data */
FALSE,
cookie);
}
-static int t4_cookie_release(int err, struct t4_cookie *cookie)
+static int t4_cookie_release(int err, void *data)
{
+ struct t4_cookie *cookie = data;
+
+ DBG("%p", cookie);
+
if (cookie == NULL)
return err;
cookie->r_apdu_max_size, data_read_cb, cookie);
else
err = ISO_ReadBinary(cookie->read_data + 2,
- (uint8_t)remain_bytes, data_read_cb, cookie);
+ (uint8_t) remain_bytes, data_read_cb, cookie);
if (err < 0)
goto out_err;
static int t4_readbin_NDEF_ID(uint8_t *resp, int length, void *data)
{
- struct t4_cookie *cookie = data ;
+ struct t4_cookie *cookie = data;
struct near_tag *tag;
- int err = 0;
+ int err;
DBG("%d", length);
else
near_tag_set_ro(tag, FALSE);
- /* TODO: see how we can get the UID value:
- * near_tag_set_uid(tag, resp + NFC_HEADER_SIZE, 8);
- * */
+ /*
+ * TODO: see how we can get the UID value:
+ * near_tag_set_uid(tag, resp + NFC_HEADER_SIZE, 8);
+ */
/* Read 1st block */
err = ISO_ReadBinary(2, cookie->r_apdu_max_size - 2,
static int t4_select_NDEF_ID(uint8_t *resp, int length, void *data)
{
struct t4_cookie *cookie = data;
- int err = 0;
+ int err;
DBG("%d", length);
static int t4_readbin_cc(uint8_t *resp, int length, void *data)
{
- struct t4_cookie *cookie = data ;
- struct type4_cc *read_cc ;
- int err = 0;
+ struct t4_cookie *cookie = data;
+ struct type4_cc *read_cc;
+ int err;
DBG("%d", length);
memcpy(read_cc, &resp[1], length - 2 - NFC_STATUS_BYTE_LEN) ;
cookie->r_apdu_max_size = g_ntohs(read_cc->max_R_apdu_data_size) -
- APDU_HEADER_LEN ;
+ APDU_HEADER_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);
- /* TODO 5.1.1 :TLV blocks can be zero, one or more... */
- /* 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 ;
+ /* TODO 5.1.1: TLV blocks can be zero, one or more... */
+ /* 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;
}
/* save rw conditions */
cookie->write_access = read_cc->tlv_fc.write_access;
- err = ISO_Select((uint8_t *)&read_cc->tlv_fc.file_id,
+ err = 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;
static int t4_select_cc(uint8_t *resp, int length, void *data)
{
struct t4_cookie *cookie = data;
- int err = 0;
+ int err;
DBG("%d", length);
static int t4_select_file_by_name_v1(uint8_t *resp, int length, void *data)
{
struct t4_cookie *cookie = data;
- int err = 0 ;
+ int err;
DBG("%d", length);
static int t4_select_file_by_name_v2(uint8_t *resp, int length, void *data)
{
struct t4_cookie *cookie = data;
- int err = 0 ;
+ int err;
DBG("%d", length);
uint32_t target_idx, near_tag_io_cb cb)
{
struct t4_cookie *cookie;
- int err = 0;
+ int err;
DBG("");
cookie->target_idx = target_idx;
cookie->cb = cb;
cookie->tag = NULL;
- cookie->read_data = 0;;
+ cookie->read_data = 0;
/* Check for V2 type 4 tag */
err = ISO_Select(iso_appname_v2, ARRAY_SIZE(iso_appname_v2),
cookie = g_try_malloc0(sizeof(struct t4_cookie));
if (cookie == NULL) {
err = -ENOMEM;
- goto out;
+ goto out_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;
+ goto out_err;
}
if ((cookie->ndef->length - cookie->ndef->offset) >
}
if (err < 0)
- goto out;
+ goto out_err;
return 0;
-out:
- t4_cookie_release(err, cookie);
-
- return err;
+out_err:
+ return t4_cookie_release(err, cookie);
}
static int nfctype4_write(uint32_t adapter_idx, uint32_t target_idx,
uint32_t target_idx, near_tag_io_cb cb)
{
struct t4_cookie *cookie;
- int err = 0;
+ int err;
DBG("");
cookie->target_idx = target_idx;
cookie->cb = cb;
cookie->tag = NULL;
- cookie->read_data = 0;;
+ cookie->read_data = 0;
/* Check for V2 type 4 tag */
err = ISO_Select(iso_appname_v2, ARRAY_SIZE(iso_appname_v2),
struct near_p2p_driver npp_driver = {
.name = "NPP",
.service_name = NEAR_DEVICE_SN_NPP,
+ .fallback_service_name = NULL,
.read = npp_read,
};
DBG("");
- client_data = (struct p2p_data *)data;
+ client_data = (struct p2p_data *) data;
if (client_data->driver->close != NULL)
client_data->driver->close(client_data->fd, 0);
}
client_addr_len = sizeof(client_addr);
- client_fd = accept(server_fd, (struct sockaddr *)&client_addr,
+ client_fd = accept(server_fd, (struct sockaddr *) &client_addr,
&client_addr_len);
if (client_fd < 0) {
near_error("accept failed %d", client_fd);
addr.service_name_len = strlen(driver->service_name);
strcpy(addr.service_name, driver->service_name);
- err = bind(fd, (struct sockaddr *)&addr,
+ err = bind(fd, (struct sockaddr *) &addr,
sizeof(struct sockaddr_nfc_llcp));
if (err < 0) {
if (errno == EADDRINUSE) {
G_IO_IN | G_IO_HUP | G_IO_NVAL | G_IO_ERR,
p2p_listener_event,
(gpointer) server_data);
+ g_io_channel_unref(channel);
server_list = g_list_append(server_list, server_data);
static int p2p_listen(uint32_t adapter_idx, near_device_io_cb cb)
{
- int err = 0;
+ int err = -1;
GSList *list;
for (list = driver_list; list != NULL; list = list->next) {
struct near_p2p_driver *driver = list->data;
- err &= p2p_bind(driver, adapter_idx, cb);
+ if (p2p_bind(driver, adapter_idx, cb) == 0)
+ err = 0;
}
return err;
addr.service_name_len = strlen(driver->service_name);
strcpy(addr.service_name, driver->service_name);
- err = connect(fd, (struct sockaddr *)&addr,
+ err = connect(fd, (struct sockaddr *) &addr,
sizeof(struct sockaddr_nfc_llcp));
if (err < 0) {
near_error("Connect failed %d", err);
if (strcmp(driver->service_name, service_name) != 0)
continue;
-
+ /*
+ * Because of Android's implementation, we have use SNEP for
+ * Handover. So, on Handover session, we try to connect to
+ * the handover service and fallback to SNEP on connect fail.
+ */
fd = p2p_connect(adapter_idx, target_idx, ndef, cb, driver);
if (fd < 0)
- return fd;
-
- return driver->push(fd, adapter_idx, target_idx, ndef, cb);
+ return p2p_push(adapter_idx, target_idx, ndef,
+ (char *) driver->fallback_service_name, cb);
+ else
+ return driver->push(fd, adapter_idx, target_idx,
+ ndef, cb);
}
return -1;
struct near_p2p_driver {
const char *name;
const char *service_name;
+ const char *fallback_service_name;
near_bool_t (*read)(int client_fd,
uint32_t adapter_idx, uint32_t target_idx,
near_device_io_cb cb);
#define SNEP_RESP_REJECT 0xff
#define SNEP_REQ_PUT_HEADER_LENGTH 6
+#define SNEP_REQ_GET_HEADER_LENGTH 10
/* TODO: Right now it is dummy, need to get correct value
* from lower layers */
#define SNEP_REQ_MAX_FRAGMENT_LENGTH 128
struct p2p_snep_data {
+ uint8_t request_code;
uint8_t *nfc_data;
uint32_t nfc_data_length;
uint32_t nfc_data_current_length;
g_hash_table_remove(snep_client_hash, GINT_TO_POINTER(client_fd));
}
+static void snep_response_with_info(int client_fd, uint8_t response,
+ uint8_t *data, int length)
+{
+ struct p2p_snep_resp_frame *resp;
+
+ DBG("Response with info 0x%x (len:%d)", response, length);
+
+ resp = g_try_malloc0(sizeof(struct p2p_snep_resp_frame) + length);
+ if (resp == NULL) {
+ DBG("Memory allocation error");
+ return;
+ }
+
+ /* Fill */
+ resp->version = SNEP_VERSION;
+ resp->response = response;
+ resp->length = GUINT32_TO_BE(length);
+ memcpy(resp->info, data, length);
+
+ send(client_fd, resp, sizeof(struct p2p_snep_resp_frame) + length, 0);
+
+ g_free(resp);
+}
+
+/*
+ * snep_parse_handover_record
+ *
+ * The hr frame should be here BUT:
+ * The first 4 bytes are the Max Allowed Length
+ *
+ * - Because of an Android's BUGs:
+ * - the Hr frame is not correct; a Hr record
+ * is embedded in a ... Hr record !!! The author
+ * used 'Hr' instead of 'cr'
+ * - The OOB block is badly written:
+ * - the payload ID should be the same in the 'ac' record
+ * and the OOB record.
+ * - The OOB data length bytes must be swapped (Big endian to Little E.)
+ *
+ * The hack fixes the first issue (bluetooth.c fixes the second) !
+ * */
+static void snep_parse_handover_record(int client_fd, uint8_t *ndef,
+ uint32_t nfc_data_length)
+{
+ GList *records;
+ struct near_ndef_message *msg;
+
+ if (ndef == NULL)
+ return;
+
+ /*
+ * Bugfix Android: Fix 'cr' instead of 'Hr'
+ * Bug is in Google:HandoverManager.java:645
+ */
+ if (strncmp((char *)(ndef + 9), "Hr", 2) == 0)
+ *(ndef + 9) = 'c';
+
+ /* Parse the incoming frame */
+ records = near_ndef_parse(ndef, nfc_data_length);
+
+ /*
+ * If we received a Hr, we must build a Hs and send it.
+ * If the frame is a Hs, nothing more to do (SNEP REPLY is SUCCESS and
+ * the pairing is done in near_ndef_parse()
+ * */
+ if (strncmp((char *)(ndef + 3), "Hr", 2) == 0) {
+ msg = near_ndef_prepare_handover_record("Hs", records->data,
+ NEAR_CARRIER_BLUETOOTH);
+
+ near_info("Send SNEP / Hs frame");
+ snep_response_with_info(client_fd, SNEP_RESP_SUCCESS,
+ msg->data, msg->length);
+ g_free(msg->data);
+ g_free(msg);
+ }
+
+ near_ndef_records_free(records);
+
+ return;
+}
+
static near_bool_t snep_read_ndef(int client_fd,
struct p2p_snep_data *snep_data)
{
return TRUE;
}
- snep_response_noinfo(client_fd, SNEP_RESP_SUCCESS);
- if (near_device_add_data(snep_data->adapter_idx, snep_data->target_idx,
- snep_data->nfc_data,
- snep_data->nfc_data_length) < 0)
- goto out;
-
- device = near_device_get_device(snep_data->adapter_idx,
- snep_data->target_idx);
- if (device == NULL)
- goto out;
-
- records = near_ndef_parse(snep_data->nfc_data,
+ if (snep_data->request_code == SNEP_REQ_GET) {
+ /*
+ * This goes against the SNEP specification:
+ * "The default server SHALL NOT accept Get requests." but
+ * the first Android Handover implementation (Jelly Bean)
+ * does Handover through SNEP via GET frames...Since Android
+ * seems popular these days, we'd better support that spec
+ * violation.
+ *
+ * Parse the Hr and send a Hs
+ * Max allowed size in the first 4 bytes
+ */
+ snep_parse_handover_record(client_fd, snep_data->nfc_data + 4,
+ snep_data->nfc_data_length - 4);
+ } else {
+ snep_response_noinfo(client_fd, SNEP_RESP_SUCCESS);
+ if (near_device_add_data(snep_data->adapter_idx,
+ snep_data->target_idx,
+ snep_data->nfc_data,
+ snep_data->nfc_data_length) < 0)
+ goto out;
+
+ device = near_device_get_device(snep_data->adapter_idx,
+ snep_data->target_idx);
+ if (device == NULL)
+ goto out;
+
+ records = near_ndef_parse(snep_data->nfc_data,
snep_data->nfc_data_length);
- near_device_add_records(device, records, snep_data->cb, 0);
+ near_device_add_records(device, records, snep_data->cb, 0);
+ }
out:
g_hash_table_remove(snep_client_hash, GINT_TO_POINTER(client_fd));
g_hash_table_insert(snep_client_hash,
GINT_TO_POINTER(client_fd), snep_data);
+ snep_data->request_code = frame.request;
+
DBG("Request 0x%x", frame.request);
switch (frame.request) {
case SNEP_REQ_CONTINUE:
- case SNEP_REQ_GET:
near_error("Unsupported SNEP request code");
snep_response_noinfo(client_fd, SNEP_RESP_NOT_IMPL);
return FALSE;
+ case SNEP_REQ_GET:
case SNEP_REQ_PUT:
return snep_read_ndef(client_fd, snep_data);
}
DBG("");
- data = (struct p2p_snep_put_req_data *)userdata;
+ data = (struct p2p_snep_put_req_data *) userdata;
close(data->fd);
static int snep_push_response(struct p2p_snep_put_req_data *req)
{
struct p2p_snep_resp_frame frame;
+ uint8_t *ndef;
+ uint32_t ndef_len;
int bytes_recv, err;
DBG("");
return bytes_recv;
}
+ /* Check frame length */
+ frame.length = g_ntohl(frame.length);
+
DBG("Response 0x%x", frame.response);
switch (frame.response) {
return frame.response;
case SNEP_RESP_SUCCESS:
+ if (frame.length == 0)
+ return 0;
+
+ /* Get the incoming data */
+ ndef_len = frame.length;
+ ndef = g_try_malloc0(ndef_len);
+ if (ndef == NULL)
+ return -ENOMEM;
+
+ bytes_recv = recv(req->fd, ndef, ndef_len, 0);
+ if (bytes_recv < 0) {
+ near_error("Could not read SNEP frame %d", bytes_recv);
+ return bytes_recv;
+ }
+
+ /* Not enough bytes */
+ if (bytes_recv < 6)
+ return -EINVAL;
+
+ if (strncmp((char *)(ndef + 3), "Hs", 2) == 0)
+ snep_parse_handover_record(req->fd, ndef, ndef_len);
+
+ g_free(ndef);
+
return 0;
}
GIOChannel *channel;
gboolean fragmenting;
int err;
+ int snep_req_header_length, snep_additional_length;
DBG("");
max_fragment_len = SNEP_REQ_MAX_FRAGMENT_LENGTH;
header.version = SNEP_VERSION;
- header.request = SNEP_REQ_PUT;
- header.length = GUINT32_TO_BE(ndef->length);
+
+ /* Check if Hr or Hs for Handover over SNEP */
+ if (*(char *)(ndef->data + 3) == 'H') {
+ header.request = SNEP_REQ_GET; /* Get for android */
+ snep_req_header_length = SNEP_REQ_GET_HEADER_LENGTH;
+ snep_additional_length = 4; /* 4 Acceptable Length */
+ } else {
+ header.request = SNEP_REQ_PUT;
+ snep_req_header_length = SNEP_REQ_PUT_HEADER_LENGTH;
+ snep_additional_length = 0;
+ }
+
+ header.length = GUINT32_TO_BE(ndef->length + snep_additional_length);
fragment = g_try_malloc0(sizeof(struct snep_fragment));
if (fragment == NULL) {
goto error;
}
- if (max_fragment_len >= (ndef->length + SNEP_REQ_PUT_HEADER_LENGTH)) {
- fragment->len = ndef->length + SNEP_REQ_PUT_HEADER_LENGTH;
+ if (max_fragment_len >= (ndef->length + snep_req_header_length)) {
+ fragment->len = ndef->length + snep_req_header_length;
fragmenting = FALSE;
} else {
fragment->len = max_fragment_len;
goto error;
}
- memcpy(fragment->data, (uint8_t *)&header,
- SNEP_REQ_PUT_HEADER_LENGTH);
+ /* Header to data - common header */
+ memcpy(fragment->data, (uint8_t *)&header, SNEP_REQ_PUT_HEADER_LENGTH);
+
+ /* if GET, we add the Acceptable length */
+ if (header.request == SNEP_REQ_GET)
+ *(uint32_t *)(fragment->data + SNEP_REQ_PUT_HEADER_LENGTH) =
+ GUINT32_TO_BE(snep_req_header_length);
if (fragmenting == TRUE) {
- memcpy(fragment->data + SNEP_REQ_PUT_HEADER_LENGTH,
- ndef->data,
- max_fragment_len - SNEP_REQ_PUT_HEADER_LENGTH);
- ndef->offset = max_fragment_len - SNEP_REQ_PUT_HEADER_LENGTH;
+ memcpy(fragment->data + snep_req_header_length, ndef->data,
+ max_fragment_len - snep_req_header_length);
+ ndef->offset = max_fragment_len - snep_req_header_length;
err = snep_push_prepare_fragments(req, ndef);
if (err < 0) {
}
} else {
- memcpy(fragment->data + SNEP_REQ_PUT_HEADER_LENGTH,
+ memcpy(fragment->data + snep_req_header_length,
ndef->data, ndef->length);
}
struct near_p2p_driver snep_driver = {
.name = "SNEP",
.service_name = NEAR_DEVICE_SN_SNEP,
+ .fallback_service_name = NEAR_DEVICE_SN_NPP,
.read = snep_read,
.push = snep_push,
.close = snep_close,
err = __near_netlink_adapter_enable(adapter->idx, powered);
if (err < 0) {
- if (err == -EALREADY)
- return __near_error_already_enabled(msg);
+ if (err == -EALREADY) {
+ if (powered == TRUE)
+ return __near_error_already_enabled(msg);
+ else
+ return __near_error_already_disabled(msg);
+ }
return __near_error_failed(msg, -err);
}
DBG("conn %p", conn);
+ if (adapter->polling == FALSE)
+ return __near_error_not_polling(msg);
+
err = __near_netlink_stop_poll(adapter->idx);
if (err < 0)
return __near_error_failed(msg, -err);
if (dep == FALSE && adapter->constant_poll == TRUE)
adapter_start_poll(adapter);
+ if (dep == FALSE) {
+ uint32_t target_idx;
+
+ target_idx = __neard_device_get_idx(adapter->device_link);
+ __near_adapter_remove_target(idx, target_idx);
+ } else {
+ __near_adapter_devices_changed(idx);
+ }
+
return 0;
}
return;
}
-
- __near_adapter_devices_changed(adapter_idx);
}
static int adapter_add_tag(struct near_adapter *adapter, uint32_t target_idx,
adapter->dep_up = TRUE;
polling_changed(adapter);
+ __near_adapter_devices_changed(idx);
+
return adapter_add_device(adapter, 0, nfcid, nfcid_len);
}
return -ENOLINK;
tag_type = __near_tag_get_type(adapter->tag_link);
- target_idx = __near_tag_get_idx(adapter->tag_link);
+ target_idx = near_tag_get_target_idx(adapter->tag_link);
DBG("tag type %d", tag_type);
DBG("req %p cb %p data %p", req, cb, data);
- req->target_idx = __near_tag_get_idx(adapter->tag_link);
+ req->target_idx = near_tag_get_target_idx(adapter->tag_link);
req->cb = cb;
req->data = data;
#define COD_SIZE 3
#define OOB_SP_SIZE 16
+#define get_unaligned(ptr) \
+({ \
+ struct __attribute__((packed)) { \
+ typeof(*(ptr)) __v; \
+ } *__p = (typeof(__p)) (ptr); \
+ __p->__v; \
+})
+
struct near_oob_data {
char *def_adapter;
oob = g_try_malloc0(sizeof(struct near_oob_data));
if (version == BT_MIME_V2_1) {
- /* Total OOB data size (including size bytes)*/
- bt_oob_data_size = *((uint16_t *)(bt_data));
+ /*
+ * Total OOB data size (including size bytes)
+ * Some implementations (e.g. Android 4.1) stores
+ * the data_size in big endian but NDEF forum spec (BT Secure
+ * Simple Pairing) requires a little endian. At the same time,
+ * the NDEF forum NDEF spec define a payload length as single
+ * byte (and the payload size IS the oob data size).
+ */
+ bt_oob_data_size =
+ GUINT16_FROM_LE(get_unaligned((uint16_t *) bt_data));
+ if (bt_oob_data_size > 0xFF) /* Big Endian */
+ bt_oob_data_size = GUINT16_FROM_BE(bt_oob_data_size);
+
bt_oob_data_size -= 2 ; /* remove oob datas size len */
/* First item: BD_ADDR (mandatory) */
/* check and get the default adapter */
oob->def_adapter = g_strdup(bt_def_oob_data.def_adapter);
- if (oob->bt_name == NULL) {
+ if (oob->def_adapter == NULL) {
near_error("bt_get_default_adapter failed");
bt_eir_free(oob);
return -EIO;
return device->path;
}
+uint32_t __neard_device_get_idx(struct near_device *device)
+{
+ return device->target_idx;
+}
+
static void append_records(DBusMessageIter *iter, void *user_data)
{
struct near_device *device = user_data;
".NotFound", "Not found");
}
+DBusMessage *__near_error_not_polling(DBusMessage *msg)
+{
+ return g_dbus_create_error(msg, NFC_ERROR_INTERFACE
+ ".Failed", "Not polling");
+}
+
DBusMessage *__near_error_no_carrier(DBusMessage *msg)
{
return g_dbus_create_error(msg, NFC_ERROR_INTERFACE
/* Carrier data reference length */
ac_record->cdr_len = rec[offset];
+ offset++;
/* Carrier data reference */
- offset++;
ac_record->cdr = rec[offset];
offset = offset + ac_record->cdr_len;
DBusMessage *__near_error_not_supported(DBusMessage *msg);
DBusMessage *__near_error_not_implemented(DBusMessage *msg);
DBusMessage *__near_error_not_found(DBusMessage *msg);
+DBusMessage *__near_error_not_polling(DBusMessage *msg);
DBusMessage *__near_error_no_carrier(DBusMessage *msg);
DBusMessage *__near_error_in_progress(DBusMessage *msg);
DBusMessage *__near_error_already_exists(DBusMessage *msg);
uint8_t *nfcid, uint8_t nfcid_len);
void __near_tag_remove(struct near_tag *tag);
const char *__near_tag_get_path(struct near_tag *tag);
-uint32_t __near_tag_get_idx(struct near_tag *tag);
uint32_t __near_tag_get_type(struct near_tag *tag);
void __near_tag_append_records(struct near_tag *tag, DBusMessageIter *iter);
int __near_tag_read(struct near_tag *tag, near_tag_io_cb cb);
int __near_device_init(void);
void __near_device_cleanup(void);
const char *__near_device_get_path(struct near_device *device);
+uint32_t __neard_device_get_idx(struct near_device *device);
struct near_device *__near_device_add(uint32_t idx, uint32_t target_idx,
uint8_t *nfcid, uint8_t nfcid_len);
void __near_device_remove(struct near_device *device);
return tag->path;
}
-
-uint32_t __near_tag_get_idx(struct near_tag *tag)
-{
- return tag->target_idx;
-}
-
uint32_t __near_tag_get_type(struct near_tag *tag)
{
return tag->type;
--- /dev/null
+#!/usr/bin/python
+
+import os
+import sys
+import gobject
+
+import dbus
+import dbus.mainloop.glib
+
+from dbus.lowlevel import MethodCallMessage, HANDLER_RESULT_NOT_YET_HANDLED
+
+mainloop = gobject.MainLoop()
+
+def property_changed_adapter(name, value, path):
+ if name in ["Devices"]:
+ if (len(value) == 0):
+ print "Lost device, exiting"
+ mainloop.quit()
+ else:
+ device_path = value[0]
+
+ print "Pairing with %s" % (device_path)
+
+ device = dbus.Interface(bus.get_object("org.neard", device_path), "org.neard.Device")
+ device.Push(({ "Type" : "Handover", "Carrier" : "bluetooth"}))
+
+if __name__ == '__main__':
+ dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
+
+ bus = dbus.SystemBus()
+
+ bluez_manager = dbus.Interface(bus.get_object("org.bluez", "/"), "org.bluez.Manager")
+
+ bluez_adapter_path = bluez_manager.DefaultAdapter()
+
+ bluez_adapter = dbus.Interface(bus.get_object("org.bluez", bluez_adapter_path),
+ "org.bluez.Adapter")
+
+ for bluez_path in bluez_adapter.ListDevices():
+ print("Removing %s" % (bluez_path))
+ bluez_adapter.RemoveDevice(bluez_path)
+
+
+ manager = dbus.Interface(bus.get_object("org.neard", "/"),
+ "org.neard.Manager")
+
+ properties = manager.GetProperties()
+ device_path = properties["Adapters"][0]
+ adapter = dbus.Interface(bus.get_object("org.neard", device_path),
+ "org.neard.Adapter")
+
+ adapter_properties = adapter.GetProperties()
+
+ for key in adapter_properties.keys():
+ if key in ["Polling"]:
+ if adapter_properties[key] == dbus.Boolean(1):
+ print "Stoping poll on %s" % (device_path)
+ adapter.StopPollLoop()
+
+ print "Starting poll on %s" % (device_path)
+ adapter.StartPollLoop("Initiator")
+
+ bus.add_signal_receiver(property_changed_adapter,
+ bus_name="org.neard",
+ dbus_interface="org.neard.Adapter",
+ signal_name = "PropertyChanged",
+ path_keyword="path")
+
+ mainloop.run()
adapter = path[path.rfind("/") + 1:]
if name in ["Polling"]:
val = extract_bool(value)
- elif name in ["Tags"]:
+ elif name in ["Tags", "Devices"]:
val = extract_list(value)
else:
val = str(value)
--- /dev/null
+#!/usr/bin/python
+
+import gobject
+
+import dbus
+import dbus.service
+import dbus.mainloop.glib
+import sys
+
+class NDEFAgent(dbus.service.Object):
+
+ @dbus.service.method("org.neard.NDEFAgent",
+ in_signature='', out_signature='')
+ def Release(self):
+ print "Release"
+ mainloop.quit()
+
+ @dbus.service.method("org.neard.NDEFAgent",
+ in_signature='a{sv}',
+ out_signature='')
+ def GetNDEF(self, fields):
+ print "GetNDEF"
+
+ if fields.has_key("Records"):
+ for path in fields["Records"]:
+ print "Record path %s" % (path)
+
+ return
+
+ @dbus.service.method("org.neard.NDEFAgent",
+ in_signature='', out_signature='')
+ def Cancel(self):
+ print "Cancel"
+
+def print_usage():
+ print "Usage:"
+ print "For NDEF agent:"
+ print "%s NDEF Type=<record type>" % (sys.argv[0])
+ print "Help: %s help" % (sys.argv[0])
+ sys.exit(1)
+
+if __name__ == '__main__':
+ if len(sys.argv) == 2 and sys.argv[1] == "help":
+ print_usage()
+
+ dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
+
+ bus = dbus.SystemBus()
+ manager = dbus.Interface(bus.get_object('org.neard', "/"),
+ 'org.neard.Manager')
+
+ if len(sys.argv) > 2:
+ if sys.argv[1] == "NDEF":
+ path = "/test/ndef/agent"
+ object = NDEFAgent(bus, path)
+ rec_type = sys.argv[2].replace("Type=", "", 1)
+
+ manager.RegisterNDEFAgent(path, rec_type)
+
+ mainloop = gobject.MainLoop()
+ mainloop.run()