Integrate neard post 0.6 changes - handover code
authorOlivier Guiter <olivier.guiter@linux.intel.com>
Wed, 26 Sep 2012 08:40:06 +0000 (10:40 +0200)
committerOlivier Guiter <olivier.guiter@linux.intel.com>
Wed, 26 Sep 2012 08:40:06 +0000 (10:40 +0200)
26 files changed:
HACKING [new file with mode: 0644]
Makefile.am
doc/agent-api.txt [new file with mode: 0644]
doc/coding-style.txt [new file with mode: 0644]
doc/features.txt [new file with mode: 0644]
gdbus/object.c
plugins/handover.c
plugins/mifare.c
plugins/nfctype1.c
plugins/nfctype2.c
plugins/nfctype3.c
plugins/nfctype4.c
plugins/npp.c
plugins/p2p.c
plugins/p2p.h
plugins/snep.c
src/adapter.c
src/bluetooth.c
src/device.c
src/error.c
src/ndef.c
src/near.h
src/tag.c
test/bt-handover [new file with mode: 0755]
test/monitor-near
test/simple-agent [new file with mode: 0755]

diff --git a/HACKING b/HACKING
new file mode 100644 (file)
index 0000000..478653c
--- /dev/null
+++ b/HACKING
@@ -0,0 +1,87 @@
+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.
index d39d4e4..e8d0691 100644 (file)
@@ -72,7 +72,7 @@ EXTRA_DIST = src/genbuiltin $(doc_files)
 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
diff --git a/doc/agent-api.txt b/doc/agent-api.txt
new file mode 100644 (file)
index 0000000..e1a5330
--- /dev/null
@@ -0,0 +1,105 @@
+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.
diff --git a/doc/coding-style.txt b/doc/coding-style.txt
new file mode 100644 (file)
index 0000000..47f9c4a
--- /dev/null
@@ -0,0 +1,344 @@
+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);
diff --git a/doc/features.txt b/doc/features.txt
new file mode 100644 (file)
index 0000000..5745dc0
--- /dev/null
@@ -0,0 +1,45 @@
+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.
index 900e7ab..9689006 100644 (file)
@@ -645,8 +645,8 @@ static dbus_bool_t emit_signal_valist(DBusConnection *conn,
                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;
        }
index 8ba550a..c8ba895 100644 (file)
@@ -90,6 +90,7 @@ static void free_hr_ndef(gpointer data)
 
        if (ndef != NULL)
                g_free(ndef->ndef);
+
        g_free(ndef);
 }
 
@@ -134,7 +135,7 @@ static int handover_ndef_parse(int client_fd, struct hr_ndef *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.
@@ -158,7 +159,7 @@ static int handover_ndef_parse(int client_fd, struct hr_ndef *ndef)
        return err;
 
 fail:
-       near_error("ndef parsing failed (%d)", err);
+       near_error("ndef parsing failed %d", err);
 
        handover_close(client_fd, 0);
 
@@ -186,7 +187,7 @@ static near_bool_t handover_read_cfg_records(int client_fd,
 
        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;
        }
 
@@ -375,7 +376,7 @@ static near_bool_t handover_read(int client_fd,
 
        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);
        }
@@ -408,7 +409,7 @@ static gboolean handover_push_event(GIOChannel *channel,
                                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);
 
@@ -467,6 +468,7 @@ static int handover_push(int client_fd,
 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,
index db71536..72120fe 100644 (file)
 #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 */
@@ -93,12 +102,14 @@ static uint8_t MAD_NFC_key[] = {0xd3, 0xf7, 0xd3, 0xf7, 0xd3, 0xf7};
 #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];
@@ -131,22 +142,30 @@ struct mifare_cookie {
        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 {
@@ -155,6 +174,12 @@ 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;
@@ -162,9 +187,10 @@ struct mifare_cmd {
        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)
@@ -180,13 +206,19 @@ static int mifare_release(int err, struct mifare_cookie *cookie)
        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.
  */
@@ -198,9 +230,10 @@ static int mifare_unlock_sector(int block_id,
        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
@@ -209,7 +242,7 @@ static int mifare_unlock_sector(int block_id,
         /* 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 */
@@ -224,13 +257,15 @@ static int mifare_unlock_sector(int block_id,
                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)
@@ -262,21 +297,22 @@ static int mifare_read_sector_cb(uint8_t *resp, int length, void *data)
        /* 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);
        }
 
@@ -298,7 +334,7 @@ static int mifare_read_sector_unlocked(uint8_t *resp, int length, void *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)
@@ -309,7 +345,8 @@ out_err:
        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
@@ -337,13 +374,13 @@ static int mifare_read_sector(void *cookie,
        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 */
@@ -352,12 +389,12 @@ static int mifare_read_sector(void *cookie,
        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;
@@ -403,7 +440,7 @@ static int mifare_read_NFC_loop(uint8_t *resp, int length, void *data)
                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) {
@@ -421,8 +458,7 @@ out_err:
        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;
@@ -510,8 +546,8 @@ done_mad:
                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;
 
@@ -519,15 +555,13 @@ out_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;
@@ -535,7 +569,7 @@ static int mifare_read_MAD2(void *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)");
@@ -558,10 +592,10 @@ out_err:
        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)
 {
@@ -570,7 +604,7 @@ 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
@@ -579,7 +613,8 @@ static int read_MAD1_complete(uint8_t *empty, int iempty, void *data)
        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)
@@ -594,8 +629,10 @@ 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)");
@@ -619,12 +656,13 @@ out_err:
        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)
@@ -655,11 +693,13 @@ int mifare_read(uint32_t adapter_idx, uint32_t target_idx,
        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 */
@@ -668,3 +708,348 @@ int mifare_read(uint32_t adapter_idx, uint32_t target_idx,
 
        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;
+}
index 4b78a35..4042429 100644 (file)
@@ -119,10 +119,14 @@ static void t1_init_cmd(struct type1_tag *tag, struct type1_cmd *cmd)
        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);
@@ -130,10 +134,12 @@ static void t1_cookie_release(struct t1_cookie *cookie)
        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;
@@ -151,9 +157,9 @@ static int segment_read_recv(uint8_t *resp, int length, void *data)
 
        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;
@@ -167,8 +173,8 @@ static int segment_read_recv(uint8_t *resp, int length, void *data)
                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 */
@@ -189,7 +195,8 @@ out_err:
        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)
@@ -213,9 +220,10 @@ static int read_dynamic_tag(uint8_t *cc, int length, void *data)
        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 */
@@ -232,14 +240,14 @@ static int read_dynamic_tag(uint8_t *cc, int length, void *data)
 
        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;
@@ -253,7 +261,7 @@ static int meta_recv(uint8_t *resp, int length, void *data)
 
        /* 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;
        }
@@ -297,7 +305,7 @@ static int meta_recv(uint8_t *resp, int length, void *data)
        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
@@ -331,18 +339,19 @@ static int meta_recv(uint8_t *resp, int length, void *data)
                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);
 }
 
 /*
@@ -361,7 +370,7 @@ static int rid_resp(uint8_t *resp, int length, void *data)
 
        /* 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;
        }
@@ -390,7 +399,44 @@ 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;
 }
@@ -399,61 +445,29 @@ out_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)
@@ -473,9 +487,7 @@ 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)
@@ -489,11 +501,11 @@ 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;
@@ -504,12 +516,12 @@ static int data_write(uint8_t *resp, int length, void *data)
 
        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)
@@ -528,23 +540,21 @@ static int data_write(uint8_t *resp, int length, void *data)
        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;
@@ -582,17 +592,15 @@ static int write_nmn_0(uint32_t adapter_idx, uint32_t target_idx,
 
        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);
 }
 
 /*
@@ -621,16 +629,16 @@ static int nfctype1_write(uint32_t adapter_idx, uint32_t target_idx,
                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)
@@ -647,9 +655,7 @@ 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,
@@ -683,17 +689,15 @@ 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)
@@ -708,7 +712,7 @@ 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) {
@@ -719,30 +723,28 @@ static int format_resp(uint8_t *resp, int length, void *data)
                cookie->current_byte++;
                memcpy(cmd.uid, cookie->uid, UID_LENGTH);
 
-               err = near_adapter_send(cookie->adapter_idx, (uint8_t *)&cmd,
+               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,
@@ -773,7 +775,7 @@ 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;
@@ -795,14 +797,14 @@ static int nfctype1_format(uint32_t adapter_idx, uint32_t target_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);
 
index 2858f24..62f6d0e 100644 (file)
 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
 
@@ -97,10 +104,14 @@ struct type2_cc {
        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);
@@ -108,6 +119,8 @@ static void t2_cookie_release(struct t2_cookie *cookie)
        g_free(cookie->ndef);
        g_free(cookie);
        cookie = NULL;
+
+       return err;
 }
 
 static int data_recv(uint8_t *resp, int length, void *data)
@@ -162,7 +175,7 @@ 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);
 }
 
@@ -181,7 +194,7 @@ static int data_read(struct type2_tag *tag)
        adapter_idx = near_tag_get_adapter_idx(tag->tag);
 
        return near_adapter_send(adapter_idx,
-                               (uint8_t *)&cmd, CMD_READ_SIZE,
+                               (uint8_t *) &cmd, CMD_READ_SIZE,
                                        data_recv, tag);
 }
 
@@ -197,12 +210,12 @@ static int meta_recv(uint8_t *resp, int length, void *data)
 
        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);
@@ -213,18 +226,18 @@ static int meta_recv(uint8_t *resp, int length, void *data)
                        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;
@@ -248,19 +261,18 @@ static int meta_recv(uint8_t *resp, int length, void *data)
 
        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,
@@ -283,7 +295,7 @@ 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);
@@ -309,12 +321,12 @@ static int nfctype2_read(uint32_t adapter_idx,
        /* 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;
        }
@@ -332,7 +344,7 @@ static int data_write_resp(uint8_t *resp, int length, void *data)
 
        if (length < 0 || resp[0] != 0) {
                err = -EIO;
-               goto out;
+               goto out_err;
        }
 
        if (cookie->ndef->offset > cookie->ndef->length) {
@@ -341,9 +353,7 @@ static int data_write_resp(uint8_t *resp, int length, void *data)
                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;
@@ -361,22 +371,19 @@ static int data_write_resp(uint8_t *resp, int length, void *data)
                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,
@@ -405,18 +412,16 @@ 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,
@@ -425,6 +430,7 @@ 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("");
 
@@ -437,21 +443,35 @@ static int nfctype2_write(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);
-               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)
@@ -468,9 +488,7 @@ 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,
@@ -478,32 +496,49 @@ 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)
@@ -516,25 +551,23 @@ 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,
@@ -558,7 +591,7 @@ 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;
        }
 
@@ -568,7 +601,7 @@ static int nfctype2_format(uint32_t adapter_idx, uint32_t target_idx,
 
        if (t2_cc == NULL || cc_ndef == NULL || cookie == NULL) {
                err = -ENOMEM;
-               goto out;
+               goto out_err;
        }
 
        t2_cc->magic = TYPE2_MAGIC;
@@ -580,17 +613,17 @@ static int nfctype2_format(uint32_t adapter_idx, uint32_t target_idx,
        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);
index b23c230..ffb401a 100644 (file)
@@ -135,10 +135,14 @@ struct t3_cookie {
        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);
@@ -146,6 +150,8 @@ static void t3_cookie_release(struct t3_cookie *cookie)
        g_free(cookie->ndef);
        g_free(cookie);
        cookie = NULL;
+
+       return err;
 }
 
 /* common: Initialize structure to write block */
@@ -170,9 +176,9 @@ static void prepare_write_block(uint8_t *UID, struct type3_cmd *cmd,
 /* 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 */
@@ -192,11 +198,11 @@ static int check_recv_frame(uint8_t *resp, uint8_t reply_code)
        int err = 0;
 
        if (resp[OFS_NFC_STATUS] != 0) {
-               DBG("NFC Command failed: 0x%x",resp[OFS_NFC_STATUS]);
+               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;
        }
@@ -204,7 +210,7 @@ static int check_recv_frame(uint8_t *resp, uint8_t reply_code)
        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;
@@ -222,11 +228,11 @@ static int nfctype3_data_recv(uint8_t *resp, int length, void *data)
 
        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;
@@ -252,16 +258,17 @@ static int nfctype3_data_recv(uint8_t *resp, int length, void *data)
        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);
 
@@ -270,7 +277,7 @@ out:
        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;
@@ -286,7 +293,7 @@ static int nfctype3_data_read(struct type3_tag *tag)
 
        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 */
@@ -296,23 +303,23 @@ static int nfctype3_recv_block_0(uint8_t *resp, int length, void *data)
        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 */
@@ -325,12 +332,12 @@ static int nfctype3_recv_block_0(uint8_t *resp, int length, void *data)
        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 */
@@ -342,10 +349,10 @@ static int nfctype3_recv_block_0(uint8_t *resp, int length, void *data)
        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);
@@ -356,9 +363,9 @@ static int nfctype3_recv_block_0(uint8_t *resp, int length, void *data)
        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,
@@ -367,9 +374,7 @@ out:
                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)
@@ -378,34 +383,32 @@ 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)
@@ -419,12 +422,12 @@ 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");
@@ -433,13 +436,13 @@ static int check_sys_op_in_mc_block(uint8_t *resp, int length, void *data)
                                        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);
@@ -450,9 +453,7 @@ static int check_sys_op_in_mc_block(uint8_t *resp, int length, void *data)
                        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 */
@@ -463,22 +464,20 @@ static int check_sys_op_in_mc_block(uint8_t *resp, int length, void *data)
                /* 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)
@@ -488,26 +487,26 @@ 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;
@@ -523,22 +522,20 @@ static int receive_system_code(uint8_t *resp, int length, void *data)
                /* 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,
@@ -558,7 +555,7 @@ 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)
@@ -568,8 +565,8 @@ static int nfctype3_read(uint32_t adapter_idx,
        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);
 
@@ -585,22 +582,20 @@ static int update_attr_block_cb(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;
 
        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)
@@ -640,17 +635,17 @@ static int data_write_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;
 
        if (cookie->ndef->offset >= cookie->ndef->length) {
                err = update_attr_block(cookie);
                if (err < 0)
-                       goto out;
+                       goto out_err;
 
                return 0;
        }
@@ -669,20 +664,18 @@ static int data_write_resp(uint8_t *resp, int length, void *data)
        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,
@@ -702,7 +695,7 @@ 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;
@@ -714,7 +707,7 @@ static int data_write(uint32_t adapter_idx, uint32_t target_idx,
        idm = near_tag_get_idm(tag, &len);
        if (idm == NULL) {
                err = -EINVAL;
-               goto out;
+               goto out_err;
        }
 
        memcpy(cookie->IDm, idm, len);
@@ -722,16 +715,16 @@ static int data_write(uint32_t adapter_idx, uint32_t target_idx,
        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 */
@@ -740,24 +733,22 @@ static int data_write(uint32_t adapter_idx, uint32_t target_idx,
        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,
@@ -778,9 +769,9 @@ 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);
@@ -788,13 +779,11 @@ static int nfctype3_check_recv_UID(uint8_t *resp, int length, void *data)
        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,
@@ -824,17 +813,16 @@ 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)
@@ -847,17 +835,17 @@ 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);
@@ -867,13 +855,11 @@ static int format_resp(uint8_t *resp, int length, void *data)
 
        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)
@@ -887,12 +873,12 @@ 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;
@@ -918,20 +904,18 @@ static int write_attr_block(uint8_t *resp, int length , void *data)
        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)
@@ -944,17 +928,17 @@ 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);
@@ -965,20 +949,18 @@ static int write_mc_block(uint8_t *resp, int length, void *data)
        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,
@@ -1013,23 +995,21 @@ 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 = {
index 76289a5..8a00e3d 100644 (file)
@@ -40,7 +40,7 @@
 #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
@@ -207,7 +207,7 @@ static int ISO_send_cmd(uint8_t class,
                        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);
@@ -248,8 +248,8 @@ static int ISO_ReadBinary(uint16_t offset, uint8_t readsize,
        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,
@@ -265,8 +265,8 @@ static int ISO_Update(uint16_t offset, uint8_t nlen,
        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,
@@ -274,8 +274,12 @@ static int ISO_Update(uint16_t offset, uint8_t nlen,
                        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;
 
@@ -342,7 +346,7 @@ static int data_read_cb(uint8_t *resp, int length, void *data)
                                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;
 
@@ -354,9 +358,9 @@ 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);
 
@@ -396,9 +400,10 @@ static int t4_readbin_NDEF_ID(uint8_t *resp, int length, void *data)
        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,
@@ -415,7 +420,7 @@ out_err:
 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);
 
@@ -445,9 +450,9 @@ out_err:
 
 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);
 
@@ -474,22 +479,22 @@ static int t4_readbin_cc(uint8_t *resp, int length, void *data)
        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;
@@ -503,7 +508,7 @@ 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);
 
@@ -550,7 +555,7 @@ out_err:
 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);
 
@@ -586,7 +591,7 @@ out_err:
 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);
 
@@ -633,7 +638,7 @@ static int nfctype4_read(uint32_t adapter_idx,
                uint32_t target_idx, near_tag_io_cb cb)
 {
        struct t4_cookie *cookie;
-       int err = 0;
+       int err;
 
        DBG("");
 
@@ -647,7 +652,7 @@ static int nfctype4_read(uint32_t adapter_idx,
        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),
@@ -720,7 +725,7 @@ static int data_write(uint32_t adapter_idx, uint32_t target_idx,
        cookie = g_try_malloc0(sizeof(struct t4_cookie));
        if (cookie == NULL) {
                err = -ENOMEM;
-               goto out;
+               goto out_err;
        }
 
        cookie->adapter_idx = adapter_idx;
@@ -735,7 +740,7 @@ static int data_write(uint32_t adapter_idx, uint32_t target_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) >
@@ -754,14 +759,12 @@ static int data_write(uint32_t adapter_idx, uint32_t target_idx,
        }
 
        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,
@@ -802,7 +805,7 @@ static int nfctype4_check_presence(uint32_t adapter_idx,
                uint32_t target_idx, near_tag_io_cb cb)
 {
        struct t4_cookie *cookie;
-       int err = 0;
+       int err;
 
        DBG("");
 
@@ -816,7 +819,7 @@ static int nfctype4_check_presence(uint32_t adapter_idx,
        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),
index 9f40291..33136ba 100644 (file)
@@ -144,6 +144,7 @@ static near_bool_t npp_read(int client_fd,
 struct near_p2p_driver npp_driver = {
        .name = "NPP",
        .service_name = NEAR_DEVICE_SN_NPP,
+       .fallback_service_name = NULL,
        .read = npp_read,
 };
 
index f6352a1..845165f 100644 (file)
@@ -106,7 +106,7 @@ static void free_client_data(gpointer data)
 
        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);
@@ -165,7 +165,7 @@ static gboolean p2p_listener_event(GIOChannel *channel, GIOCondition condition,
        }
 
        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);
@@ -224,7 +224,7 @@ static int p2p_bind(struct near_p2p_driver *driver, uint32_t adapter_idx,
        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) {
@@ -264,6 +264,7 @@ static int p2p_bind(struct near_p2p_driver *driver, uint32_t adapter_idx,
                                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);
 
@@ -272,13 +273,14 @@ static int p2p_bind(struct near_p2p_driver *driver, uint32_t adapter_idx,
 
 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;
@@ -305,7 +307,7 @@ static int p2p_connect(uint32_t adapter_idx, uint32_t target_idx,
        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);
@@ -331,12 +333,18 @@ static int p2p_push(uint32_t adapter_idx, uint32_t target_idx,
 
                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;
index 5b74fb6..033ecd2 100644 (file)
@@ -26,6 +26,7 @@
 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);
index 488b765..9bde428 100644 (file)
 #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;
@@ -143,6 +145,87 @@ static void snep_close(int client_fd, int err)
        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)
 {
@@ -184,20 +267,37 @@ static near_bool_t snep_read_ndef(int client_fd,
                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));
@@ -257,14 +357,16 @@ static near_bool_t snep_read(int 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);
        }
@@ -289,7 +391,7 @@ static void free_snep_push_data(gpointer userdata, int status)
 
        DBG("");
 
-       data = (struct p2p_snep_put_req_data *)userdata;
+       data = (struct p2p_snep_put_req_data *) userdata;
 
        close(data->fd);
 
@@ -328,6 +430,8 @@ static int snep_send_fragment(struct p2p_snep_put_req_data *req)
 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("");
@@ -338,6 +442,9 @@ static int snep_push_response(struct p2p_snep_put_req_data *req)
                return bytes_recv;
        }
 
+       /* Check frame length */
+       frame.length = g_ntohl(frame.length);
+
        DBG("Response 0x%x", frame.response);
 
        switch (frame.response) {
@@ -351,6 +458,30 @@ static int snep_push_response(struct p2p_snep_put_req_data *req)
                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;
        }
 
@@ -430,6 +561,7 @@ static int snep_push(int fd, uint32_t adapter_idx, uint32_t target_idx,
        GIOChannel *channel;
        gboolean fragmenting;
        int err;
+       int snep_req_header_length, snep_additional_length;
 
        DBG("");
 
@@ -453,8 +585,19 @@ static int snep_push(int fd, uint32_t adapter_idx, uint32_t target_idx,
 
        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) {
@@ -462,8 +605,8 @@ static int snep_push(int fd, uint32_t adapter_idx, uint32_t target_idx,
                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;
@@ -477,14 +620,18 @@ static int snep_push(int fd, uint32_t adapter_idx, uint32_t target_idx,
                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) {
@@ -494,7 +641,7 @@ static int snep_push(int fd, uint32_t adapter_idx, uint32_t target_idx,
                }
 
        } else {
-               memcpy(fragment->data + SNEP_REQ_PUT_HEADER_LENGTH,
+               memcpy(fragment->data + snep_req_header_length,
                                        ndef->data, ndef->length);
        }
 
@@ -521,6 +668,7 @@ error:
 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,
index 2ec0af6..e5f9e6a 100644 (file)
@@ -368,8 +368,12 @@ static DBusMessage *set_property(DBusConnection *conn,
 
                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);
                }
@@ -420,6 +424,9 @@ static DBusMessage *stop_poll_loop(DBusConnection *conn,
 
        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);
@@ -577,6 +584,15 @@ int __near_adapter_set_dep_state(uint32_t idx, near_bool_t dep)
        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;
 }
 
@@ -673,8 +689,6 @@ static void device_read_cb(uint32_t adapter_idx, uint32_t target_idx,
 
                return;
        }
-
-       __near_adapter_devices_changed(adapter_idx);
 }
 
 static int adapter_add_tag(struct near_adapter *adapter, uint32_t target_idx,
@@ -804,6 +818,8 @@ int __near_adapter_add_device(uint32_t idx, uint8_t *nfcid, uint8_t nfcid_len)
        adapter->dep_up = TRUE;
        polling_changed(adapter);
 
+       __near_adapter_devices_changed(idx);
+
        return adapter_add_device(adapter, 0, nfcid, nfcid_len);
 }
 
@@ -972,7 +988,7 @@ int near_adapter_disconnect(uint32_t idx)
                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);
 
@@ -1017,7 +1033,7 @@ int near_adapter_send(uint32_t idx, uint8_t *buf, size_t length,
 
                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;
 
index 1a4d4d1..60c65e3 100644 (file)
 #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;
 
@@ -620,8 +628,19 @@ int __near_bluetooth_parse_oob_record(uint8_t version, uint8_t *bt_data,
        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) */
@@ -680,7 +699,7 @@ int __near_bluetooth_parse_oob_record(uint8_t version, uint8_t *bt_data,
 
        /* 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;
index 4a201e8..de9cbe8 100644 (file)
@@ -117,6 +117,11 @@ const char *__near_device_get_path(struct near_device *device)
        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;
index f166380..4012b5b 100644 (file)
@@ -119,6 +119,12 @@ DBusMessage *__near_error_not_found(DBusMessage *msg)
                                                ".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
index e6c909d..2dd51e8 100644 (file)
@@ -1552,9 +1552,9 @@ static struct near_ndef_ac_record *parse_ac_record(uint8_t *rec,
 
        /* 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;
 
index 1b9ccb1..aee34be 100644 (file)
@@ -51,6 +51,7 @@ DBusMessage *__near_error_not_unique(DBusMessage *msg);
 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);
@@ -116,7 +117,6 @@ struct near_tag *__near_tag_add(uint32_t idx, uint32_t target_idx,
                                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);
@@ -130,6 +130,7 @@ int __near_tag_check_presence(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);
index 4450b92..b4aff76 100644 (file)
--- a/src/tag.c
+++ b/src/tag.c
@@ -624,12 +624,6 @@ const char *__near_tag_get_path(struct near_tag *tag)
        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;
diff --git a/test/bt-handover b/test/bt-handover
new file mode 100755 (executable)
index 0000000..95b6dbf
--- /dev/null
@@ -0,0 +1,69 @@
+#!/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()
index 5758df0..fef307e 100755 (executable)
@@ -26,7 +26,7 @@ def property_changed_adapter(name, value, path):
     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)
diff --git a/test/simple-agent b/test/simple-agent
new file mode 100755 (executable)
index 0000000..4db0a9f
--- /dev/null
@@ -0,0 +1,61 @@
+#!/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()