tizen 2.4 release accepted/tizen/2.4/mobile/20151029.033601 submit/tizen_2.4/20151028.064016 tizen_2.4_mobile_release
authorjk7744.park <jk7744.park@samsung.com>
Sat, 24 Oct 2015 07:36:08 +0000 (16:36 +0900)
committerjk7744.park <jk7744.park@samsung.com>
Sat, 24 Oct 2015 07:36:08 +0000 (16:36 +0900)
137 files changed:
ChangeLog
Makefile.am
Makefile.plugins
Makefile.tools
android/Android.mk
android/Makefile.am
android/avctp.c
android/avdtp.c
android/avrcp-lib.c
android/avrcp-lib.h
android/avrcp.c
android/bluetoothd-snoop.c
android/gatt.c
android/hal-gatt.c
android/hal-ipc-api.txt
android/hal-msg.h
android/hal-sco.c
android/hardware/bt_gatt_server.h
android/hidhost.c
android/hog.c
android/hog.h
android/pan.c
android/pics-bnep.txt [new file with mode: 0644]
android/pixit-bnep.txt [new file with mode: 0644]
android/pts-bnep.txt [new file with mode: 0644]
attrib/gatt-service.c
attrib/gattrib.c
bluez.manifest
bluez.rule [new file with mode: 0644]
client/gatt.c
client/gatt.h
client/main.c
configure.ac
doc/adapter-api.txt
doc/advertising-api.txt [new file with mode: 0644]
doc/gatt-api.txt
doc/mgmt-api.txt
doc/test-coverage.txt
emulator/btdev.c
emulator/btdev.h
emulator/hciemu.c
emulator/hciemu.h
emulator/hfp.c
emulator/le.c
emulator/vhci.c
gdbus/client.c
gdbus/object.c
lib/bluetooth.c
lib/bluetooth.h
lib/bnep.h
lib/hci.c [changed mode: 0644->0755]
lib/hci.h [changed mode: 0644->0755]
lib/hci_lib.h [changed mode: 0644->0755]
lib/mgmt.h [changed mode: 0644->0755]
lib/uuid.h
monitor/btsnoop.c
monitor/btsnoop.h
monitor/control.c
monitor/control.h
monitor/main.c
monitor/packet.c
obexd/client/mns-tizen.c
obexd/client/pbap.c
obexd/plugins/mas.c
obexd/plugins/pbap.c
obexd/src/obex.c
packaging/bluez.spec [changed mode: 0644->0755]
plugins/policy.c
plugins/sixaxis.c
profiles/audio/a2dp.c
profiles/audio/avctp.c
profiles/audio/avctp.h
profiles/audio/avdtp.c
profiles/audio/avdtp.h
profiles/audio/avrcp.c
profiles/audio/control.c
profiles/audio/control.h
profiles/audio/media.c
profiles/gap/gas.c
profiles/network/bnep.c
profiles/network/bnep.h
profiles/network/connection.c
profiles/network/server.c
src/adapter.c [changed mode: 0644->0755]
src/adapter.h [changed mode: 0644->0755]
src/adapter_le_vsc_features.c
src/adapter_le_vsc_features.h
src/advertising.c [new file with mode: 0644]
src/advertising.h [new file with mode: 0644]
src/attrib-server.c
src/bluetooth.conf
src/bluetooth.service.in [changed mode: 0644->0755]
src/device.c [changed mode: 0644->0755]
src/device.h
src/eir.c
src/gatt-client.c
src/gatt-database.c
src/gatt.c
src/hcid.h
src/main.c
src/main.conf [new file with mode: 0644]
src/main_m.conf [changed mode: 0644->0755]
src/main_w.conf [changed mode: 0644->0755]
src/profile.c
src/shared/att.c
src/shared/att.h
src/shared/btsnoop.c
src/shared/btsnoop.h
src/shared/gatt-client.c
src/shared/gatt-client.h
src/shared/gatt-db.c
src/shared/gatt-db.h
src/shared/gatt-helpers.c
src/shared/tester.c
src/shared/tester.h
test/advertisement-example [new file with mode: 0644]
tools/bneptest.c [new file with mode: 0644]
tools/btgatt-client.c
tools/btgatt-server.c
tools/btmgmt.c
tools/btsnoop.c
tools/hciattach.c
tools/hciattach.h
tools/hciattach_sprd.c [new file with mode: 0644]
tools/hciattach_sprd.h [new file with mode: 0644]
tools/mgmt-tester.c
tools/oobtest.c
tools/pskey_get.c [new file with mode: 0644]
unit/test-avctp.c
unit/test-avdtp.c
unit/test-avrcp.c
unit/test-gatt.c
unit/test-gdbus-client.c
unit/test-hfp.c
unit/test-hog.c [new file with mode: 0644]
unit/test-sdp.c
unit/test-uhid.c

index 2c38828..8aed8be 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,33 @@
+ver 5.30:
+       Fix compilation error in C++ due to inline function.
+       Fix issue with missing storage of device information.
+       Fix issue with GATT client and gaps in service handles.
+       Fix issue with AVDTP discovery callback crashing.
+       Fix issue with AVCTP channel handling in case of conflicts.
+       Fix issue with AVRCP target and get capabilities command.
+       Add experimental support for LE advertising manager API.
+       Add support for Android 5.1 GATT MTU exchange API.
+
+ver 5.29:
+       Fix issue with AVCTP initial key repeat timeout.
+       Fix issue with Android application disconnect handling.
+       Fix issue with Android support and service notifications.
+       Fix issue with Android support and Exchange MTU Request.
+       Fix issue with Android HFP support and AT+CMER handling.
+       Fix issue with Android HFP support and SLC setup.
+       Fix issue with Android HFP support and call hold status.
+       Fix issue with Android HFP support and indicator handling.
+       Fix issue with Android HFP support and SCO/eSCO disconnection.
+       Fix issue with Android HID over GATT support and battery service.
+       Fix issue with GATT sending Exchange MTU Request for BR/EDR.
+       Fix issue with GATT notification support without CCC.
+       Fix issue with GATT object life-time after disconnects.
+       Fix issue with GATT notification handling API.
+       Add experimental support for GATT client D-Bus API.
+       Add experimental support for GATT server D-Bus API.
+       Add support for Multi Profile Specification.
+       Update Android qualification documentation to PTS 6.0 release.
+
 ver 5.28:
        Fix issue with GATT device discovery and probing.
        Fix issue with bearer selection for dual-mode devices.
index 70f31c9..f6c4ac8 100644 (file)
@@ -80,7 +80,7 @@ include_HEADERS += $(lib_headers)
 lib_LTLIBRARIES += lib/libbluetooth.la
 
 lib_libbluetooth_la_SOURCES = $(lib_headers) $(lib_sources)
-lib_libbluetooth_la_LDFLAGS = $(AM_LDFLAGS) -version-info 21:1:18
+lib_libbluetooth_la_LDFLAGS = $(AM_LDFLAGS) -version-info 21:3:18
 lib_libbluetooth_la_DEPENDENCIES = $(local_headers)
 endif
 
@@ -130,7 +130,7 @@ src_libshared_mainloop_la_SOURCES = $(shared_sources) \
 
 attrib_sources = attrib/att.h attrib/att-database.h attrib/att.c \
                attrib/gatt.h attrib/gatt.c \
-               attrib/gattrib.h attrib/gattrib.c  \
+               attrib/gattrib.h attrib/gattrib.c \
                attrib/gatt-service.h attrib/gatt-service.c
 
 btio_sources = btio/btio.h btio/btio.c
@@ -175,6 +175,7 @@ src_bluetoothd_SOURCES = $(builtin_sources) \
                        src/uinput.h \
                        src/plugin.h src/plugin.c \
                        src/storage.h src/storage.c \
+                       src/advertising.h src/advertising.c \
                        src/agent.h src/agent.c \
                        src/error.h src/error.c \
                        src/adapter.h src/adapter.c \
@@ -252,11 +253,13 @@ EXTRA_DIST += doc/mgmt-api.txt \
                doc/adapter-api.txt doc/device-api.txt \
                doc/agent-api.txt doc/profile-api.txt \
                doc/network-api.txt doc/media-api.txt \
-               doc/health-api.txt doc/sap-api.txt
+               doc/health-api.txt doc/sap-api.txt \
+               doc/input-api.txt
 
 EXTRA_DIST += doc/alert-api.txt \
                doc/proximity-api.txt doc/heartrate-api.txt \
-               doc/thermometer-api.txt doc/cyclingspeed-api.txt
+               doc/thermometer-api.txt doc/cyclingspeed-api.txt \
+               doc/gatt-api.txt doc/advertising-api.txt
 
 EXTRA_DIST += doc/obex-api.txt doc/obex-agent-api.txt
 
@@ -392,6 +395,21 @@ unit_test_gatt_SOURCES = unit/test-gatt.c
 unit_test_gatt_LDADD = src/libshared-glib.la \
                                lib/libbluetooth-internal.la @GLIB_LIBS@
 
+unit_tests += unit/test-hog
+
+unit_test_hog_SOURCES = unit/test-hog.c \
+                       $(btio_sources) \
+                       android/hog.h android/hog.c \
+                       android/scpp.h android/scpp.c \
+                       android/bas.h android/bas.c \
+                       android/dis.h android/dis.c \
+                       src/log.h src/log.c \
+                       attrib/att.h attrib/att.c \
+                       attrib/gatt.h attrib/gatt.c \
+                       attrib/gattrib.h attrib/gattrib.c
+unit_test_hog_LDADD = src/libshared-glib.la \
+                               lib/libbluetooth-internal.la @GLIB_LIBS@
+
 unit_tests += unit/test-gattrib
 
 unit_test_gattrib_SOURCES = unit/test-gattrib.c attrib/gattrib.c $(btio_sources) src/log.h src/log.c
index b850878..38f27ec 100644 (file)
@@ -97,6 +97,7 @@ builtin_sources += profiles/health/mcap.h profiles/health/mcap.c \
 endif
 endif
 
+if TIZEN_HEALTH_PLUGIN
 builtin_modules += gap
 builtin_sources += profiles/gap/gas.c
 
@@ -105,6 +106,7 @@ builtin_sources += profiles/scanparam/scan.c
 
 builtin_modules += deviceinfo
 builtin_sources += profiles/deviceinfo/deviceinfo.c
+endif
 
 if EXPERIMENTAL
 if TIZEN_UNUSED_PLUGIN
index 0dba04a..44f4f57 100644 (file)
@@ -122,7 +122,8 @@ if TOOLS
 bin_PROGRAMS += tools/hciattach tools/hciconfig tools/hcitool tools/hcidump \
                        tools/rfcomm tools/rctest tools/l2test tools/l2ping \
                        tools/sdptool tools/ciptool tools/bccmd \
-                       tools/bluemoon tools/hex2hcd tools/mpris-proxy
+                       tools/bluemoon tools/hex2hcd tools/mpris-proxy \
+                       tools/btsnoop
 
 tools_hciattach_SOURCES = tools/hciattach.c tools/hciattach.h \
                                                tools/hciattach_st.c \
@@ -131,6 +132,8 @@ tools_hciattach_SOURCES = tools/hciattach.c tools/hciattach.h \
                                                tools/hciattach_ath3k.c \
                                                tools/hciattach_qualcomm.c \
                                                tools/hciattach_intel.c \
+                                               tools/hciattach_sprd.c \
+                                               tools/pskey_get.c \
                                                tools/hciattach_bcm43xx.c
 #                                              src/log.c 
 #                                              tools/hciattach_bcm43xx.c
@@ -202,6 +205,9 @@ tools_mcaptest_SOURCES = tools/mcaptest.c \
                                profiles/health/mcap.h profiles/health/mcap.c
 tools_mcaptest_LDADD = lib/libbluetooth-internal.la @GLIB_LIBS@ -lrt
 
+tools_btsnoop_SOURCES = tools/btsnoop.c
+tools_btsnoop_LDADD = src/libshared-mainloop.la
+
 dist_man_MANS += tools/hciattach.1 tools/hciconfig.1 \
                        tools/hcitool.1 tools/hcidump.1 \
                        tools/rfcomm.1 tools/rctest.1 tools/l2ping.1 \
@@ -230,10 +236,10 @@ noinst_PROGRAMS += tools/bdaddr tools/avinfo tools/avtest \
                        tools/scotest tools/amptest tools/hwdb \
                        tools/hcieventmask tools/hcisecfilter \
                        tools/btmgmt tools/btinfo tools/btattach \
-                       tools/btsnoop tools/btproxy \
-                       tools/btiotest tools/mcaptest tools/cltest \
-                       tools/oobtest tools/seq2bseq tools/ibeacon \
-                       tools/btgatt-client tools/btgatt-server
+                       tools/btproxy \
+                       tools/btiotest tools/bneptest tools/mcaptest \
+                       tools/cltest tools/oobtest tools/seq2bseq \
+                       tools/ibeacon tools/btgatt-client tools/btgatt-server
 
 tools_bdaddr_SOURCES = tools/bdaddr.c src/oui.h src/oui.c
 tools_bdaddr_LDADD = lib/libbluetooth-internal.la @UDEV_LIBS@
@@ -260,9 +266,6 @@ tools_btinfo_LDADD = src/libshared-mainloop.la
 tools_btattach_SOURCES = tools/btattach.c monitor/bt.h
 tools_btattach_LDADD = src/libshared-mainloop.la
 
-tools_btsnoop_SOURCES = tools/btsnoop.c
-tools_btsnoop_LDADD = src/libshared-mainloop.la
-
 tools_btproxy_SOURCES = tools/btproxy.c monitor/bt.h
 tools_btproxy_LDADD = src/libshared-mainloop.la
 
@@ -275,6 +278,12 @@ tools_mcaptest_SOURCES = tools/mcaptest.c \
                                profiles/health/mcap.h profiles/health/mcap.c
 tools_mcaptest_LDADD = lib/libbluetooth-internal.la @GLIB_LIBS@
 
+tools_bneptest_SOURCES = tools/bneptest.c \
+                               btio/btio.h btio/btio.c \
+                               src/log.h src/log.c \
+                               profiles/network/bnep.h profiles/network/bnep.c
+tools_bneptest_LDADD = lib/libbluetooth-internal.la @GLIB_LIBS@
+
 tools_cltest_SOURCES = tools/cltest.c
 tools_cltest_LDADD = lib/libbluetooth-internal.la src/libshared-mainloop.la
 
@@ -370,4 +379,4 @@ test_scripts += test/sap_client.py test/bluezutils.py \
                test/service-ftp.xml test/simple-player test/test-nap \
                test/test-heartrate test/test-alert test/test-hfp \
                test/test-cyclingspeed test/opp-client test/ftp-client \
-               test/pbap-client test/map-client
+               test/pbap-client test/map-client test/advertisement-example
index 6c0eda8..f218805 100644 (file)
@@ -256,6 +256,41 @@ LOCAL_MODULE := mcaptest
 include $(BUILD_EXECUTABLE)
 
 #
+# bneptest
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+       bluez/src/log.c \
+       bluez/btio/btio.c \
+       bluez/lib/bluetooth.c \
+       bluez/lib/hci.c \
+       bluez/profiles/network/bnep.c \
+       bluez/tools/bneptest.c \
+
+LOCAL_C_INCLUDES := \
+       $(call include-path-for, glib) \
+       $(call include-path-for, glib)/glib \
+
+LOCAL_C_INCLUDES += \
+       $(LOCAL_PATH)/bluez \
+
+LOCAL_CFLAGS := $(BLUEZ_COMMON_CFLAGS)
+
+LOCAL_SHARED_LIBRARIES := \
+       libglib \
+
+LOCAL_STATIC_LIBRARIES := \
+       bluetooth-headers \
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
+LOCAL_MODULE_TAGS := debug
+LOCAL_MODULE := bneptest
+
+include $(BUILD_EXECUTABLE)
+
+#
 # avdtptest
 #
 
index 676daab..cb32bc3 100644 (file)
@@ -1,6 +1,6 @@
 if ANDROID
 
-AM_CFLAGS += -DANDROID_VERSION=0x050000
+AM_CFLAGS += -DANDROID_VERSION=0x050100
 
 android_plugindir = $(abs_top_srcdir)/android/.libs
 
@@ -258,6 +258,7 @@ EXTRA_DIST += android/Android.mk android/README \
                                android/pics-dis.txt \
                                android/pics-avdtp.txt \
                                android/pics-gavdp.txt \
+                               android/pics-bnep.txt \
                                android/pixit-l2cap.txt \
                                android/pixit-gap.txt \
                                android/pixit-did.txt \
@@ -285,6 +286,7 @@ EXTRA_DIST += android/Android.mk android/README \
                                android/pixit-avdtp.txt \
                                android/pixit-gavdp.txt \
                                android/pixit-sdp.txt \
+                               android/pixit-bnep.txt \
                                android/pts-rfcomm.txt \
                                android/pts-spp.txt \
                                android/pts-l2cap.txt \
@@ -311,4 +313,5 @@ EXTRA_DIST += android/Android.mk android/README \
                                android/pts-dis.txt \
                                android/pts-avdtp.txt \
                                android/pts-gavdp.txt \
-                               android/pts-sdp.txt
+                               android/pts-sdp.txt \
+                               android/pts-bnep.txt
index 758dbd4..6aa64cf 100644 (file)
@@ -162,6 +162,7 @@ struct key_pressed {
 };
 
 struct avctp {
+       unsigned int ref;
        int uinput;
 
        unsigned int passthrough_id;
@@ -708,6 +709,47 @@ static gboolean process_queue(void *user_data)
 
 }
 
+static struct avctp *avctp_ref(struct avctp *session)
+{
+       __sync_fetch_and_add(&session->ref, 1);
+
+       DBG("%p: ref=%d", session, session->ref);
+
+       return session;
+}
+
+static void avctp_unref(struct avctp *session)
+{
+       DBG("%p: ref=%d", session, session->ref);
+
+       if (__sync_sub_and_fetch(&session->ref, 1))
+               return;
+
+       if (session->browsing)
+               avctp_channel_destroy(session->browsing);
+
+       if (session->control)
+               avctp_channel_destroy(session->control);
+
+       if (session->destroy)
+               session->destroy(session->data);
+
+       g_free(session->handler);
+
+       if (session->key.timer > 0)
+               g_source_remove(session->key.timer);
+
+       if (session->uinput >= 0) {
+               DBG("AVCTP: closing uinput");
+
+               ioctl(session->uinput, UI_DEV_DESTROY);
+               close(session->uinput);
+               session->uinput = -1;
+       }
+
+       g_free(session);
+}
+
 static void control_response(struct avctp_channel *control,
                                        struct avctp_header *avctp,
                                        struct avc_header *avc,
@@ -733,6 +775,8 @@ static void control_response(struct avctp_channel *control,
                                                                control);
        }
 
+       avctp_ref(control->session);
+
        for (l = control->processed; l; l = l->next) {
                p = l->data;
                req = p->data;
@@ -744,13 +788,15 @@ static void control_response(struct avctp_channel *control,
                                                avc->subunit_type,
                                                operands, operand_count,
                                                req->user_data))
-                       return;
+                       break;
 
                control->processed = g_slist_remove(control->processed, p);
                pending_destroy(p, NULL);
 
-               return;
+               break;
        }
+
+       avctp_unref(control->session);
 }
 
 static void browsing_response(struct avctp_channel *browsing,
@@ -777,6 +823,8 @@ static void browsing_response(struct avctp_channel *browsing,
                                                                browsing);
        }
 
+       avctp_ref(browsing->session);
+
        for (l = browsing->processed; l; l = l->next) {
                p = l->data;
                req = p->data;
@@ -786,13 +834,15 @@ static void browsing_response(struct avctp_channel *browsing,
 
                if (req->func && req->func(browsing->session, operands,
                                                operand_count, req->user_data))
-                       return;
+                       break;
 
                browsing->processed = g_slist_remove(browsing->processed, p);
                pending_destroy(p, NULL);
 
-               return;
+               break;
        }
+
+       avctp_unref(browsing->session);
 }
 
 static gboolean session_browsing_cb(GIOChannel *chan, GIOCondition cond,
@@ -1563,7 +1613,7 @@ struct avctp *avctp_new(int fd, size_t imtu, size_t omtu, uint16_t version)
        control->watch = g_io_add_watch(session->control->io, cond,
                                                (GIOFunc) session_cb, session);
 
-       return session;
+       return avctp_ref(session);
 }
 
 int avctp_connect_browsing(struct avctp *session, int fd, size_t imtu,
@@ -1599,27 +1649,5 @@ void avctp_shutdown(struct avctp *session)
        if (!session)
                return;
 
-       if (session->browsing)
-               avctp_channel_destroy(session->browsing);
-
-       if (session->control)
-               avctp_channel_destroy(session->control);
-
-       if (session->destroy)
-               session->destroy(session->data);
-
-       g_free(session->handler);
-
-       if (session->key.timer > 0)
-               g_source_remove(session->key.timer);
-
-       if (session->uinput >= 0) {
-               DBG("AVCTP: closing uinput");
-
-               ioctl(session->uinput, UI_DEV_DESTROY);
-               close(session->uinput);
-               session->uinput = -1;
-       }
-
-       g_free(session);
+       avctp_unref(session);
 }
index e4fd2b7..7e61280 100644 (file)
@@ -784,6 +784,10 @@ static void handle_unanswered_req(struct avdtp *session,
        struct avdtp_local_sep *lsep;
        struct avdtp_error err;
 
+       if (!session->req->timeout)
+               /* Request is in process */
+               return;
+
        if (session->req->signal_id == AVDTP_ABORT) {
                /* Avoid freeing the Abort request here */
                DBG("handle_unanswered_req: Abort req, returning");
@@ -2017,6 +2021,9 @@ static gboolean session_cb(GIOChannel *chan, GIOCondition cond,
                break;
        }
 
+       /* Take a reference to protect against callback destroying session */
+       avdtp_ref(session);
+
        if (session->in.message_type == AVDTP_MSG_TYPE_COMMAND) {
                if (!avdtp_parse_cmd(session, session->in.transaction,
                                        session->in.signal_id,
@@ -2031,21 +2038,25 @@ static gboolean session_cb(GIOChannel *chan, GIOCondition cond,
                        goto next;
                }
 
+               avdtp_unref(session);
                return TRUE;
        }
 
        if (session->req == NULL) {
                error("No pending request, ignoring message");
+               avdtp_unref(session);
                return TRUE;
        }
 
        if (header->transaction != session->req->transaction) {
                error("Transaction label doesn't match");
+               avdtp_unref(session);
                return TRUE;
        }
 
        if (session->in.signal_id != session->req->signal_id) {
                error("Response signal doesn't match");
+               avdtp_unref(session);
                return TRUE;
        }
 
@@ -2085,7 +2096,10 @@ next:
        pending_req_free(session->req);
        session->req = NULL;
 
-       process_queue(session);
+       if (session->ref > 1)
+               process_queue(session);
+
+       avdtp_unref(session);
 
        return TRUE;
 
@@ -2508,12 +2522,12 @@ static gboolean avdtp_set_configuration_resp(struct avdtp *session,
 {
        struct avdtp_local_sep *sep = stream->lsep;
 
+       avdtp_sep_set_state(session, sep, AVDTP_STATE_CONFIGURED);
+
        if (sep->cfm && sep->cfm->set_configuration)
                sep->cfm->set_configuration(session, sep, stream, NULL,
                                                sep->user_data);
 
-       avdtp_sep_set_state(session, sep, AVDTP_STATE_CONFIGURED);
-
        return TRUE;
 }
 
@@ -2794,9 +2808,9 @@ static gboolean avdtp_parse_rej(struct avdtp *session,
                error("START request rejected: %s (%d)",
                                avdtp_strerror(&err), err.err.error_code);
                if (sep && sep->cfm && sep->cfm->start) {
+                       stream->starting = FALSE;
                        sep->cfm->start(session, sep, stream, &err,
                                        sep->user_data);
-                       stream->starting = FALSE;
                }
                return TRUE;
        case AVDTP_SUSPEND:
index 23dea62..4edfd0e 100644 (file)
@@ -367,6 +367,10 @@ void avrcp_shutdown(struct avrcp *session)
                        avctp_unregister_passthrough_handler(session->conn,
                                                session->passthrough_id);
 
+               if (session->browsing_id > 0)
+                       avctp_unregister_browsing_pdu_handler(session->conn,
+                                                       session->browsing_id);
+
                /* clear destroy callback that would call shutdown again */
                avctp_set_destroy_cb(session->conn, NULL, NULL);
                avctp_shutdown(session->conn);
@@ -2443,8 +2447,12 @@ static int parse_attribute_list(uint8_t *params, uint16_t params_len,
 
                if (item->len > 0) {
                        text[i] = g_strndup(item->data, item->len);
+                       attrs[i] = item->attr;
                        params_len -= item->len;
                        params += item->len;
+               } else {
+                       text[i] = NULL;
+                       attrs[i] = 0;
                }
        }
 
@@ -2457,6 +2465,12 @@ fail:
        return -EPROTO;
 }
 
+static void free_attribute_list(uint8_t number, char **text)
+{
+       while(number--)
+               g_free(text[number]);
+}
+
 static int parse_elements(struct avrcp_header *pdu, uint8_t *number,
                                                uint32_t *attrs, char **text)
 {
@@ -2531,6 +2545,9 @@ done:
        player->cfm->get_element_attributes(session, err, number, attrs, text,
                                                        player->user_data);
 
+       if (err == 0)
+               free_attribute_list(number, text);
+
        return FALSE;
 }
 
@@ -2855,6 +2872,9 @@ done:
        player->cfm->get_item_attributes(session, err, number, attrs, text,
                                                        player->user_data);
 
+       if (err == 0)
+               free_attribute_list(number, text);
+
        return FALSE;
 }
 
index 8e6ee40..add7739 100644 (file)
 #define AVRCP_MEDIA_SEARCH                     0x02
 #define AVRCP_MEDIA_NOW_PLAYING                        0x03
 
+/* SDP features */
+#define AVRCP_FEATURE_CATEGORY_1       0x0001
+#define AVRCP_FEATURE_CATEGORY_2       0x0002
+#define AVRCP_FEATURE_CATEGORY_3       0x0004
+#define AVRCP_FEATURE_CATEGORY_4       0x0008
+#define AVRCP_FEATURE_PLAYER_SETTINGS  0x0010
+#define AVRCP_FEATURE_GROUP_NAVIGATION 0x0020
+#define AVRCP_FEATURE_BROWSING         0x0040
+#define AVRCP_FEATURE_MULTIPLE_PLAYERS 0x0080
+
 /* Company IDs for vendor dependent commands */
 #define IEEEID_BTSIG           0x001958
 
index a0d412d..bcb4228 100644 (file)
 
 #define L2CAP_PSM_AVCTP 0x17
 
-#define AVRCP_FEATURE_CATEGORY_1       0x0001
-#define AVRCP_FEATURE_CATEGORY_2       0x0002
-#define AVRCP_FEATURE_CATEGORY_3       0x0004
-#define AVRCP_FEATURE_CATEGORY_4       0x0008
-
 static bdaddr_t adapter_addr;
 static uint32_t record_tg_id = 0;
 static uint32_t record_ct_id = 0;
index 035875a..ff2b7e5 100644 (file)
@@ -145,7 +145,11 @@ static int open_monitor(const char *path)
        struct sockaddr_hci addr;
        int opt = 1;
 
+#ifdef __TIZEN_PATCH__
+       snoop = btsnoop_create(path, BTSNOOP_TYPE_HCI, -1, -1);
+#else
        snoop = btsnoop_create(path, BTSNOOP_TYPE_HCI);
+#endif
        if (!snoop)
                return -1;
 
index 9c2a280..4da959f 100644 (file)
@@ -941,6 +941,55 @@ static bool get_local_mtu(struct gatt_device *dev, uint16_t *mtu)
        return true;
 }
 
+static void notify_client_mtu_change(struct app_connection *conn, bool success)
+{
+       struct hal_ev_gatt_client_configure_mtu ev;
+       size_t mtu;
+
+       g_attrib_get_buffer(conn->device->attrib, &mtu);
+
+       ev.conn_id = conn->id;
+       ev.status = success ? GATT_SUCCESS : GATT_FAILURE;
+       ev.mtu = mtu;
+
+       ipc_send_notif(hal_ipc, HAL_SERVICE_ID_GATT,
+                       HAL_EV_GATT_CLIENT_CONFIGURE_MTU, sizeof(ev), &ev);
+}
+
+static void notify_server_mtu(struct app_connection *conn)
+{
+       struct hal_ev_gatt_server_mtu_changed ev;
+       size_t mtu;
+
+       g_attrib_get_buffer(conn->device->attrib, &mtu);
+
+       ev.conn_id = conn->id;
+       ev.mtu = mtu;
+
+       ipc_send_notif(hal_ipc, HAL_SERVICE_ID_GATT,
+                       HAL_EV_GATT_SERVER_MTU_CHANGED, sizeof(ev), &ev);
+}
+
+static void notify_mtu_change(void *data, void *user_data)
+{
+       struct gatt_device *device = user_data;
+       struct app_connection *conn = data;
+
+       if (conn->device != device)
+               return;
+
+       switch (conn->app->type) {
+       case GATT_CLIENT:
+               notify_client_mtu_change(conn, true);
+               break;
+       case GATT_SERVER:
+               notify_server_mtu(conn);
+               break;
+       default:
+               break;
+       }
+}
+
 static bool update_mtu(struct gatt_device *device, uint16_t rmtu)
 {
        uint16_t mtu, lmtu;
@@ -965,6 +1014,8 @@ static bool update_mtu(struct gatt_device *device, uint16_t rmtu)
                return false;
        }
 
+       queue_foreach(app_connections, notify_mtu_change, device);
+
        return true;
 }
 
@@ -1600,6 +1651,11 @@ reply:
        data.status = status;
        queue_foreach(app_connections, notify_app_connect_status_by_device,
                                                                        &data);
+
+       /* For BR/EDR notify about MTU since it is not negotiable*/
+       if (cid != ATT_CID)
+               queue_foreach(app_connections, notify_mtu_change, dev);
+
        device_unref(dev);
 
        /* Check if we should restart scan */
@@ -5676,14 +5732,31 @@ static void handle_client_scan_filter_enable(const void *buf, uint16_t len)
 static void handle_client_configure_mtu(const void *buf, uint16_t len)
 {
        const struct hal_cmd_gatt_client_configure_mtu *cmd = buf;
+       static struct app_connection *conn;
+       uint8_t status;
 
-       DBG("conn_id %u", cmd->conn_id);
+       DBG("conn_id %u mtu %d", cmd->conn_id, cmd->mtu);
 
-       /* TODO */
+       conn = find_connection_by_id(cmd->conn_id);
+       if (!conn) {
+               status = HAL_STATUS_FAILED;
+               goto failed;
+       }
 
+       /*
+        * currently MTU is always exchanged on connection, just report current
+        * value
+        *
+        * TODO figure out when send failed status in notification
+        * TODO should we fail for BR/EDR?
+        */
+       notify_client_mtu_change(conn, false);
+       status = HAL_STATUS_SUCCESS;
+
+failed:
        ipc_send_rsp(hal_ipc, HAL_SERVICE_ID_GATT,
                                        HAL_OP_GATT_CLIENT_CONFIGURE_MTU,
-                                       HAL_STATUS_UNSUPPORTED);
+                                       status);
 }
 
 static void handle_client_conn_param_update(const void *buf, uint16_t len)
index 438ad61..f7217c7 100644 (file)
@@ -641,6 +641,16 @@ static void handle_server_congestion(void *buf, uint16_t len, int fd)
 #endif
 }
 
+static void handle_server_mtu_changed(void *buf, uint16_t len, int fd)
+{
+#if ANDROID_VERSION >= PLATFORM_VER(5, 1, 0)
+       struct hal_ev_gatt_server_mtu_changed *ev = buf;
+
+       if (cbs->server->mtu_changed_cb)
+               cbs->server->mtu_changed_cb(ev->conn_id, ev->mtu);
+#endif
+}
+
 /*
  * handlers will be called from notification thread context,
  * index in table equals to 'opcode - HAL_MINIMUM_EVENT'
@@ -784,6 +794,9 @@ static const struct hal_ipc_handler ev_handlers[] = {
        /* HAL_EV_GATT_SERVER_CONGESTION */
        { handle_server_congestion, false,
                sizeof(struct hal_ev_gatt_server_congestion) },
+       /* HAL_EV_GATT_SERVER_MTU_CHANGED */
+       { handle_server_mtu_changed, false,
+               sizeof(struct hal_ev_gatt_server_mtu_changed) },
        };
 
 /* Client API */
index 77f2f57..503b47a 100644 (file)
@@ -2329,6 +2329,11 @@ Notifications:
                Notification parameters: Connection ID (4 octets)
                                         Congested (1 octet)
 
+       Opcode 0xb0 - Server MTU Changed notification
+
+               Notification parameters: Connection ID (4 octets)
+                                        MTU (4 octets)
+
 
 Bluetooth Handsfree Client HAL (ID 10)
 ======================================
index 0ec07c7..698f45a 100644 (file)
@@ -2092,6 +2092,12 @@ struct hal_ev_gatt_server_congestion {
        uint8_t congested;
 } __attribute__((packed));
 
+#define HAL_EV_GATT_SERVER_MTU_CHANGED         0xb0
+struct hal_ev_gatt_server_mtu_changed {
+       int32_t conn_id;
+       int32_t mtu;
+} __attribute__((packed));
+
 #define HAL_GATT_PERMISSION_READ                       0x0001
 #define HAL_GATT_PERMISSION_READ_ENCRYPTED             0x0002
 #define HAL_GATT_PERMISSION_READ_ENCRYPTED_MITM                0x0004
index 380b2a8..2c95866 100644 (file)
@@ -1054,17 +1054,23 @@ static ssize_t in_read(struct audio_stream_in *stream, void *buffer,
                                                                size_t bytes)
 {
        struct sco_stream_in *in = (struct sco_stream_in *) stream;
-#if ANDROID_VERSION >= PLATFORM_VER(5, 0, 0)
-       size_t frame_size = audio_stream_in_frame_size(&in->stream);
-#else
-       size_t frame_size = audio_stream_frame_size(&stream->common);
-#endif
-       size_t frame_num = bytes / frame_size;
-       size_t input_frame_num = frame_num;
+       size_t frame_size, frame_num, input_frame_num;
        void *read_buf = buffer;
        size_t total = bytes;
        int ret;
 
+#if ANDROID_VERSION >= PLATFORM_VER(5, 0, 0)
+       frame_size = audio_stream_in_frame_size(&in->stream);
+#else
+       frame_size = audio_stream_frame_size(&stream->common);
+#endif
+
+       if (!frame_size)
+               return -1;
+
+       frame_num = bytes / frame_size;
+       input_frame_num = frame_num;
+
        DBG("Read from fd %d bytes %zu", sco_fd, bytes);
 
        if (ipc_get_sco_fd(&in->bd_addr) != SCO_STATUS_SUCCESS)
index 2b1de27..0d6cc1e 100644 (file)
@@ -117,6 +117,9 @@ typedef void (*indication_sent_callback)(int conn_id, int status);
  */
 typedef void (*congestion_callback)(int conn_id, bool congested);
 
+/** Callback invoked when the MTU for a given connection changes */
+typedef void (*mtu_changed_callback)(int conn_id, int mtu);
+
 typedef struct {
     register_server_callback        register_server_cb;
     connection_callback             connection_cb;
@@ -133,6 +136,7 @@ typedef struct {
     response_confirmation_callback  response_confirmation_cb;
     indication_sent_callback        indication_sent_cb;
     congestion_callback             congestion_cb;
+    mtu_changed_callback            mtu_changed_cb;
 } btgatt_server_callbacks_t;
 
 /** Represents the standard BT-GATT server interface. */
index 2e589f4..729b884 100644 (file)
@@ -817,7 +817,7 @@ static void hog_conn_cb(const bdaddr_t *addr, int err, void *attrib)
 
        if (!dev->hog) {
                /* TODO: Get device details and primary */
-               dev->hog = bt_hog_new("bluez-input-device", dev->vendor,
+               dev->hog = bt_hog_new_default("bluez-input-device", dev->vendor,
                                        dev->product, dev->version, NULL);
                if (!dev->hog) {
                        error("HoG: unable to create session");
index 88a5460..ff77bb3 100644 (file)
@@ -87,6 +87,7 @@ struct bt_hog {
        GAttrib                 *attrib;
        GSList                  *reports;
        struct bt_uhid          *uhid;
+       int                     uhid_fd;
        gboolean                has_report_id;
        uint16_t                bcdhid;
        uint8_t                 bcountrycode;
@@ -1170,8 +1171,16 @@ static void hog_free(void *data)
        g_free(hog);
 }
 
-struct bt_hog *bt_hog_new(const char *name, uint16_t vendor, uint16_t product,
-                                       uint16_t version, void *primary)
+struct bt_hog *bt_hog_new_default(const char *name, uint16_t vendor,
+                                       uint16_t product, uint16_t version,
+                                       void *primary)
+{
+       return bt_hog_new(-1, name, vendor, product, version, primary);
+}
+
+struct bt_hog *bt_hog_new(int fd, const char *name, uint16_t vendor,
+                                       uint16_t product, uint16_t version,
+                                       void *primary)
 {
        struct bt_hog *hog;
 
@@ -1180,23 +1189,17 @@ struct bt_hog *bt_hog_new(const char *name, uint16_t vendor, uint16_t product,
                return NULL;
 
        hog->gatt_op = queue_new();
-       if (!hog->gatt_op) {
-               hog_free(hog);
-               return NULL;
-       }
-
        hog->bas = queue_new();
-       if (!hog->bas) {
-               queue_destroy(hog->gatt_op, NULL);
-               hog_free(hog);
-               return NULL;
-       }
 
-       hog->uhid = bt_uhid_new_default();
-       if (!hog->uhid) {
+       if (fd < 0)
+               hog->uhid = bt_uhid_new_default();
+       else
+               hog->uhid = bt_uhid_new(fd);
+
+       hog->uhid_fd = fd;
+
+       if (!hog->gatt_op || !hog->bas || !hog->uhid) {
                hog_free(hog);
-               queue_destroy(hog->gatt_op, NULL);
-               queue_destroy(hog->bas, NULL);
                return NULL;
        }
 
@@ -1317,8 +1320,8 @@ static void hog_attach_hog(struct bt_hog *hog, struct gatt_primary *primary)
                return;
        }
 
-       instance = bt_hog_new(hog->name, hog->vendor, hog->product,
-                                                       hog->version, primary);
+       instance = bt_hog_new(hog->uhid_fd, hog->name, hog->vendor,
+                                       hog->product, hog->version, primary);
        if (!instance)
                return;
 
index ddb2cea..2a9b899 100644 (file)
 
 struct bt_hog;
 
-struct bt_hog *bt_hog_new(const char *name, uint16_t vendor, uint16_t product,
-                                       uint16_t version, void *primary);
+struct bt_hog *bt_hog_new_default(const char *name, uint16_t vendor,
+                                       uint16_t product, uint16_t version,
+                                       void *primary);
+
+struct bt_hog *bt_hog_new(int fd, const char *name, uint16_t vendor,
+                                       uint16_t product, uint16_t version,
+                                       void *primary);
 
 struct bt_hog *bt_hog_ref(struct bt_hog *hog);
 void bt_hog_unref(struct bt_hog *hog);
index 2afc92a..a1b173b 100644 (file)
@@ -324,14 +324,13 @@ static void connect_cb(GIOChannel *chan, GError *err, gpointer data)
        if (!dev->session)
                goto fail;
 
-       perr = bnep_connect(dev->session, bnep_conn_cb, dev);
+       perr = bnep_connect(dev->session, bnep_conn_cb, bnep_disconn_cb, dev,
+                                                                       dev);
        if (perr < 0) {
                error("bnep connect req failed: %s", strerror(-perr));
                goto fail;
        }
 
-       bnep_set_disconnect(dev->session, bnep_disconn_cb, dev);
-
        if (dev->io) {
                g_io_channel_unref(dev->io);
                dev->io = NULL;
@@ -463,8 +462,6 @@ static gboolean nap_setup_cb(GIOChannel *chan, GIOCondition cond,
 {
        struct pan_device *dev = user_data;
        uint8_t packet[BNEP_MTU];
-       struct bnep_setup_conn_req *req = (void *) packet;
-       uint16_t src_role, dst_role, rsp = BNEP_CONN_NOT_ALLOWED;
        int sk, n, err;
 
        if (cond & (G_IO_ERR | G_IO_HUP | G_IO_NVAL)) {
@@ -474,51 +471,38 @@ static gboolean nap_setup_cb(GIOChannel *chan, GIOCondition cond,
 
        sk = g_io_channel_unix_get_fd(chan);
 
+#ifndef  __TIZEN_PATCH__
        /* Reading BNEP_SETUP_CONNECTION_REQUEST_MSG */
        n = read(sk, packet, sizeof(packet));
+#else
+       /*
+        * BNEP_SETUP_CONNECTION_REQUEST_MSG should be read and left in case
+        * of kernel setup connection msg handling.
+        */
+       n = recv(sk, packet, sizeof(packet), MSG_PEEK);
+#endif
+
        if (n  < 0) {
                error("read(): %s(%d)", strerror(errno), errno);
                goto failed;
        }
 
-       /* Highest known control command id BNEP_FILTER_MULT_ADDR_RSP 0x06 */
-       if (req->type == BNEP_CONTROL &&
-                                       req->ctrl > BNEP_FILTER_MULT_ADDR_RSP) {
-               error("cmd not understood");
-               bnep_send_ctrl_rsp(sk, BNEP_CONTROL, BNEP_CMD_NOT_UNDERSTOOD,
-                                                               req->ctrl);
-               goto failed;
-       }
-
-       if (req->type != BNEP_CONTROL || req->ctrl != BNEP_SETUP_CONN_REQ) {
-               error("cmd is not BNEP_SETUP_CONN_REQ %02X %02X", req->type,
-                                                               req->ctrl);
-               goto failed;
-       }
-
-       rsp = bnep_setup_decode(req, &dst_role, &src_role);
-       if (rsp != BNEP_SUCCESS) {
-               error("bnep_setup_decode failed");
+       if (n < 3) {
+               error("pan: to few setup connection request data received");
                goto failed;
        }
 
        err = nap_create_bridge();
-       if (err < 0) {
+       if (err < 0)
                error("pan: Failed to create bridge: %s (%d)", strerror(-err),
                                                                        -err);
-               goto failed;
-       }
 
-       if (bnep_server_add(sk, dst_role, BNEP_BRIDGE, dev->iface,
-                                                       &dev->dst) < 0) {
+       if (bnep_server_add(sk, (err < 0) ? NULL : BNEP_BRIDGE, dev->iface,
+                                               &dev->dst, packet, n) < 0) {
                error("pan: server_connadd failed");
-               rsp = BNEP_CONN_NOT_ALLOWED;
                goto failed;
        }
 
-       rsp = BNEP_SUCCESS;
-       bnep_send_ctrl_rsp(sk, BNEP_CONTROL, BNEP_SETUP_CONN_RSP, rsp);
-
        dev->watch = g_io_add_watch(chan, G_IO_HUP | G_IO_ERR | G_IO_NVAL,
                                                        nap_watchdog_cb, dev);
        g_io_channel_unref(dev->io);
@@ -530,7 +514,6 @@ static gboolean nap_setup_cb(GIOChannel *chan, GIOCondition cond,
        return FALSE;
 
 failed:
-       bnep_send_ctrl_rsp(sk, BNEP_CONTROL, BNEP_SETUP_CONN_RSP, rsp);
        pan_device_remove(dev);
 
        return FALSE;
diff --git a/android/pics-bnep.txt b/android/pics-bnep.txt
new file mode 100644 (file)
index 0000000..09aa725
--- /dev/null
@@ -0,0 +1,26 @@
+BNEP PICS for the PTS tool.
+
+PTS version: 6.0
+
+* - different than PTS defaults
+# - not yet implemented/supported
+
+M - mandatory if such role selected
+O - optional
+
+               Profile Version
+-------------------------------------------------------------------------------
+Parameter Name Selected        Description
+-------------------------------------------------------------------------------
+TSPC_BNEP_1_1  True            BNEP Connection Setup (M)
+TSPC_BNEP_1_2  True (*)        BNEP Data Packet Reception (M)
+TSPC_BNEP_1_3  True (*)        BNEP Data Packet Transmission (M)
+TSPC_BNEP_1_3a True (*)        BNEP Compressed Packet Transmission (O)
+TSPC_BNEP_1_3b True (*)        BNEP Compressed Packet Transmission Source Only
+                               (O)
+TSPC_BNEP_1_4  True            BNEP Control Message Processing (M)
+TSPC_BNEP_1_5  True            BNEP Extension Header Processing (M)
+TSPC_BNEP_1_6  True            Network Protocol Filter Message Transmission (O)
+TSPC_BNEP_1_7  True            Multicast Address Filter Message Transmission
+                               (O)
+-------------------------------------------------------------------------------
diff --git a/android/pixit-bnep.txt b/android/pixit-bnep.txt
new file mode 100644 (file)
index 0000000..9a26cd2
--- /dev/null
@@ -0,0 +1,30 @@
+BNEP PIXIT for the PTS tool.
+
+PTS version: 6.0
+
+* - different than PTS defaults
+& - should be set to IUT Bluetooth address
+# - should be set to PTS's bin/audio folder
+
+Required PIXIT settings
+-------------------------------------------------------------------------------
+Parameter Name                 Value
+-------------------------------------------------------------------------------
+TSPX_class_of_device           04041C
+TSPX_security_control_data
+TSPX_content_protection_data
+TSPX_bd_addr_iut               112233445566 (*&)
+TSPX_delete_link_key           FALSE
+TSPX_pin_code                  1234
+TSPX_security_enabled          FALSE
+TSPX_time_guard                        300000
+TSPX_use_implicit_send         TRUE
+TSPX_auth_password             0000
+TSPX_auth_user_id              PTS
+TSPX_l2cap_psm                 000F
+TSPX_rfcomm_channel            8
+TSPX_no_confirmations          FALSE
+TSPX_UUID_dest_address         1116
+TSPX_UUID_source_address       1115
+TSPX_MAC_dest_address          000000000000 (*&)
+TSPX_MAC_source_address                000000000000 (*&)
diff --git a/android/pts-bnep.txt b/android/pts-bnep.txt
new file mode 100644 (file)
index 0000000..91ef1c5
--- /dev/null
@@ -0,0 +1,57 @@
+PTS test results for BNEP
+
+PTS version: 6.0
+Tested: 12-March-2015
+Android version: 5.0
+Kernel version: 3.20
+
+Results:
+PASS   test passed
+FAIL   test failed
+INC    test is inconclusive
+N/A    test is disabled due to PICS setup
+
+--------------------------------------------------------------------------------
+Test Name              Result  Notes
+--------------------------------------------------------------------------------
+TC_CTRL_BV_01_C                PASS    bneptest -s -b <bridge> -n <iface>
+TC_CTRL_BV_02_C                PASS    bneptest -c <PTS addr> -b <bridge> -n <iface>
+TC_CTRL_BV_03_C                PASS    bneptest -s -b <bridge> -n <iface>
+TC_CTRL_BV_04_C                PASS    PTS issue #13169
+                               bneptest -s -b <bridge> -n <iface>
+TC_CTRL_BV_05_C                PASS    PTS issue #13169
+                               bneptest -s -b <bridge> -n <iface>
+TC_CTRL_BV_06_C                PASS    PTS issue #13169
+                               bneptest -s -b <bridge> -n <iface>
+TC_CTRL_BV_07_C                PASS    PTS issue #13169
+                               bneptest -c <PTS addr> -b <bridge> -n <iface>
+                                       -t 3 -d 0 -e 1500 -y 1
+TC_CTRL_BV_08_C                PASS    PTS issue #13169
+                               bneptest -s -b <bridge> -n <iface>
+TC_CTRL_BV_09_C                PASS    bneptest -c <PTS addr> -b <bridge> -n <iface>
+                                       -t 5 -g 00:00:00:00:00:00
+                                       -j ff:ff:ff:ff:ff:ff -y 1
+TC_CTRL_BV_10_C                PASS    PTS issue #13169
+                               bneptest -s -b <bridge> -n <iface>
+TC_CTRL_BV_19_C                INC     JIRA #BA-343
+                               bneptest -s -b <bridge> -n <iface>
+TC_RX_TYPE_0_BV_11_C   PASS    bneptest -s -b <bridge> -n <iface>
+TC_RX_C_BV_12_C                PASS    bneptest -s -b <bridge> -n <iface>
+TC_RX_C_S_BV_13_C      PASS    bneptest -s -b <bridge> -n <iface>
+TC_RX_C_S_BV_14_C      PASS    bneptest -s -b <bridge> -n <iface>
+TC_RX_TYPE_0_BV_15_C   PASS    PTS issue #13169
+                               bneptest -s -b <bridge> -n <iface>
+TC_RX_TYPE_0_BV_16_C   PASS    PTS issue #13171
+                               bneptest -s -b <bridge> -n <iface>
+TC_RX_TYPE_0_BV_17_C   PASS    PTS issue #13169
+                               bneptest -s -b <bridge> -n <iface>
+TC_RX_TYPE_0_BV_18_C   PASS    PTS issue #13171
+                               bneptest -s -b <bridge> -n <iface>
+TC_TX_TYPE_0_BV_20_C   PASS    bneptest -c <PTS addr> -b <bridge> -n <iface>
+                                       -w 0 -k <src hw addr> -f <dst hw addr>
+TC_TX_C_BV_21_C                PASS    bneptest -c <PTS addr> -b <bridge> -n <iface>
+                                       -w 2 -k <src hw addr> -f <dst hw addr>
+TC_TX_C_S_BV_22_C      PASS    bneptest -c <PTS addr> -b <bridge> -n <iface>
+                                       -w 3 -k <src hw addr> -f <dst hw addr>
+TC_TX_C_D_BV_23_C      PASS    bneptest -c <PTS addr> -b <bridge> -n <iface>
+                                       -w 4 -k <src hw addr> -f <dst hw addr>
index 24e4f49..d4df218 100644 (file)
@@ -78,6 +78,10 @@ static GSList *parse_opts(gatt_option opt1, va_list args)
        struct attrib_cb *cb;
        GSList *l = NULL;
 
+#ifdef __TIZEN_PATCH__
+       if (opt == GATT_OPT_INVALID)
+               return NULL;
+#endif
        info = g_new0(struct gatt_info, 1);
        l = g_slist_append(l, info);
 
@@ -237,8 +241,8 @@ static gboolean add_descriptor(struct btd_adapter *adapter,
 /*     API not available in bluez 5.25
  * att_put_uuid(info->uuid, &atval[0]);*/
 
-       a = attrib_db_add(adapter, h++, &bt_uuid, ATT_NONE, ATT_NOT_PERMITTED,
-                                               atval, info->uuid.type / 8);
+       a = attrib_db_add(adapter, h++, &bt_uuid, ATT_AUTHENTICATION,
+                       ATT_AUTHENTICATION, atval, info->uuid.type / 8);
 
        if (a == NULL) {
                return FALSE;
index 699f927..2f61977 100644 (file)
@@ -231,8 +231,8 @@ void g_attrib_channel_unref(GAttrib *attrib)
 }
 #endif
 
-gboolean g_attrib_set_destroy_function(GAttrib *attrib,
-               GDestroyNotify destroy, gpointer user_data)
+gboolean g_attrib_set_destroy_function(GAttrib *attrib, GDestroyNotify destroy,
+                                                       gpointer user_data)
 {
        if (!attrib)
                return FALSE;
@@ -440,9 +440,24 @@ guint g_attrib_register(GAttrib *attrib, guint8 opcode, guint16 handle,
 
 uint8_t *g_attrib_get_buffer(GAttrib *attrib, size_t *len)
 {
+       uint16_t mtu;
+
        if (!attrib || !len)
                return NULL;
 
+       mtu = bt_att_get_mtu(attrib->att);
+
+       /*
+        * Clients of this expect a buffer to use.
+        *
+        * Pdu encoding in shared/att verifies if whole buffer fits the mtu,
+        * thus we should set the buflen also when mtu is reduced. But we
+        * need to reallocate the buffer only if mtu is larger.
+        */
+       if (mtu > attrib->buflen)
+               attrib->buf = g_realloc(attrib->buf, mtu);
+
+       attrib->buflen = mtu;
        *len = attrib->buflen;
        return attrib->buf;
 }
index 343920f..a21528a 100644 (file)
@@ -9,8 +9,6 @@
         <filesystem path="/usr/bin/l2ping" label="bluez" exec_label="bluez"/>
         <filesystem path="/usr/bin/rfcomm" label="bluez" exec_label="bluez"/>
         <filesystem path="/usr/bin/sdptool" label="bluez" exec_label="bluez"/>
-        <filesystem path="/usr/bin/mpris-proxy" exec_label="none"/>
-        <filesystem path="/usr/lib/udev/hid2hci" exec_label="none"/>
 
         <filesystem path="/etc/bluetooth/audio.conf" label="bluez"/>
         <filesystem path="/etc/bluetooth/main.conf" label="bluez"/>
         <filesystem path="/etc/bluetooth/rfcomm.conf" label="bluez"/>
 
         <filesystem path="/usr/lib/bluetooth/bluetoothd" label="bluez" exec_label="bluez"/>
+        <filesystem path="/usr/lib/udev/hid2hci" label="bluez" exec_label="bluez"/>
         <filesystem path="/usr/bin/hciattach" label="bluez" exec_label="bluez"/>
         <filesystem path="/usr/bin/hciconfig" label="bluez" exec_label="bluez"/>
+        <filesystem path="/usr/bin/mpris-proxy" label="bluez" exec_label="bluez"/>
+        <filesystem path="/usr/bin/btmon" label="bluez" exec_label="bluez"/>
+        <filesystem path="/usr/bin/btsnoop" label="bluez" exec_label="bluez"/>
+
+        <filesystem path="/etc/smack/accesses.d/bluez.rule" label="_" exec_label="none"/>
 
         <dbus name="org.bluez" own="bluez" bus="system">
             <node name="/org/bluez/device/connection">
diff --git a/bluez.rule b/bluez.rule
new file mode 100644 (file)
index 0000000..1c86495
--- /dev/null
@@ -0,0 +1,6 @@
+bluez syslogd -w----
+bluez device::sys_logging -w----
+bluez security-server::api-permissions -w----
+bluez dfms-kernel rwx---
+dbus bluez rwx---
+bluez _ rwx---
index 884c4f2..11c9081 100644 (file)
@@ -31,6 +31,7 @@
 #include <stdlib.h>
 #include <stdbool.h>
 #include <sys/uio.h>
+#include <wordexp.h>
 
 #include <readline/readline.h>
 #include <readline/history.h>
@@ -41,6 +42,9 @@
 #include "display.h"
 #include "gatt.h"
 
+#define PROFILE_PATH "/org/bluez/profile"
+#define PROFILE_INTERFACE "org.bluez.GattProfile1"
+
 /* String display constants */
 #define COLORED_NEW    COLOR_GREEN "NEW" COLOR_OFF
 #define COLORED_CHG    COLOR_YELLOW "CHG" COLOR_OFF
@@ -49,6 +53,7 @@
 static GList *services;
 static GList *characteristics;
 static GList *descriptors;
+static GList *managers;
 
 static void print_service(GDBusProxy *proxy, const char *description)
 {
@@ -424,12 +429,17 @@ static void write_attribute(GDBusProxy *proxy, char *arg)
 
                if (*entry == '\0')
                        continue;
-
+#ifndef __TIZEN_PATCH__
                if (i > 512) {
                        rl_printf("Too much data\n");
                        return;
                }
-
+#else
+               if (i >= 512) {
+                       rl_printf("Too much data\n");
+                       return;
+               }
+#endif
                val = strtol(entry, &endptr, 0);
                if (!endptr || *endptr != '\0' || val > UINT8_MAX) {
                        rl_printf("Invalid value at index %d\n", i);
@@ -512,3 +522,146 @@ void gatt_notify_attribute(GDBusProxy *proxy, bool enable)
        rl_printf("Unable to notify attribute %s\n",
                                                g_dbus_proxy_get_path(proxy));
 }
+
+static void register_profile_setup(DBusMessageIter *iter, void *user_data)
+{
+       wordexp_t *w = user_data;
+       DBusMessageIter uuids, opt;
+       const char *path = PROFILE_PATH;
+       size_t i;
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &path);
+
+       dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "s", &uuids);
+       for (i = 0; i < w->we_wordc; i++)
+               dbus_message_iter_append_basic(&uuids, DBUS_TYPE_STRING,
+                                                       &w->we_wordv[i]);
+       dbus_message_iter_close_container(iter, &uuids);
+
+       dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
+                                       DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+                                       DBUS_TYPE_STRING_AS_STRING
+                                       DBUS_TYPE_VARIANT_AS_STRING
+                                       DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
+                                       &opt);
+       dbus_message_iter_close_container(iter, &opt);
+
+}
+
+static void register_profile_reply(DBusMessage *message, void *user_data)
+{
+       DBusError error;
+
+       dbus_error_init(&error);
+
+       if (dbus_set_error_from_message(&error, message) == TRUE) {
+               rl_printf("Failed to register profile: %s\n", error.name);
+               dbus_error_free(&error);
+               return;
+       }
+
+       rl_printf("Profile registered\n");
+}
+
+void gatt_add_manager(GDBusProxy *proxy)
+{
+       managers = g_list_append(managers, proxy);
+}
+
+void gatt_remove_manager(GDBusProxy *proxy)
+{
+       managers = g_list_remove(managers, proxy);
+}
+
+static int match_proxy(const void *a, const void *b)
+{
+       GDBusProxy *proxy1 = (void *) a;
+       GDBusProxy *proxy2 = (void *) b;
+
+       return strcmp(g_dbus_proxy_get_path(proxy1),
+                                               g_dbus_proxy_get_path(proxy2));
+}
+
+static DBusMessage *release_profile(DBusConnection *conn,
+                                       DBusMessage *msg, void *user_data)
+{
+       g_dbus_unregister_interface(conn, PROFILE_PATH, PROFILE_INTERFACE);
+
+       return dbus_message_new_method_return(msg);
+}
+
+static const GDBusMethodTable methods[] = {
+       { GDBUS_METHOD("Release", NULL, NULL, release_profile) },
+       { }
+};
+
+void gatt_register_profile(DBusConnection *conn, GDBusProxy *proxy,
+                                                               wordexp_t *w)
+{
+       GList *l;
+
+       l = g_list_find_custom(managers, proxy, match_proxy);
+       if (!l) {
+               rl_printf("Unable to find GattManager proxy\n");
+               return;
+       }
+
+       if (g_dbus_register_interface(conn, PROFILE_PATH,
+                                       PROFILE_INTERFACE, methods,
+                                       NULL, NULL, NULL, NULL) == FALSE) {
+               rl_printf("Failed to register profile object\n");
+               return;
+       }
+
+       if (g_dbus_proxy_method_call(l->data, "RegisterProfile",
+                                               register_profile_setup,
+                                               register_profile_reply, w,
+                                               NULL) == FALSE) {
+               rl_printf("Failed register profile\n");
+               return;
+       }
+}
+
+static void unregister_profile_reply(DBusMessage *message, void *user_data)
+{
+       DBusConnection *conn = user_data;
+       DBusError error;
+
+       dbus_error_init(&error);
+
+       if (dbus_set_error_from_message(&error, message) == TRUE) {
+               rl_printf("Failed to unregister profile: %s\n", error.name);
+               dbus_error_free(&error);
+               return;
+       }
+
+       rl_printf("Profile unregistered\n");
+
+       g_dbus_unregister_interface(conn, PROFILE_PATH, PROFILE_INTERFACE);
+}
+
+static void unregister_profile_setup(DBusMessageIter *iter, void *user_data)
+{
+       const char *path = PROFILE_PATH;
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &path);
+}
+
+void gatt_unregister_profile(DBusConnection *conn, GDBusProxy *proxy)
+{
+       GList *l;
+
+       l = g_list_find_custom(managers, proxy, match_proxy);
+       if (!l) {
+               rl_printf("Unable to find GattManager proxy\n");
+               return;
+       }
+
+       if (g_dbus_proxy_method_call(l->data, "UnregisterProfile",
+                                               unregister_profile_setup,
+                                               unregister_profile_reply, conn,
+                                               NULL) == FALSE) {
+               rl_printf("Failed unregister profile\n");
+               return;
+       }
+}
index effee5e..689bb4d 100644 (file)
@@ -37,3 +37,10 @@ char *gatt_attribute_generator(const char *text, int state);
 void gatt_read_attribute(GDBusProxy *proxy);
 void gatt_write_attribute(GDBusProxy *proxy, const char *arg);
 void gatt_notify_attribute(GDBusProxy *proxy, bool enable);
+
+void gatt_add_manager(GDBusProxy *proxy);
+void gatt_remove_manager(GDBusProxy *proxy);
+
+void gatt_register_profile(DBusConnection *conn, GDBusProxy *proxy,
+                                                               wordexp_t *w);
+void gatt_unregister_profile(DBusConnection *conn, GDBusProxy *proxy);
index b9e2eb7..4e7a54a 100644 (file)
@@ -32,6 +32,7 @@
 #include <stdbool.h>
 #include <signal.h>
 #include <sys/signalfd.h>
+#include <wordexp.h>
 
 #include <readline/readline.h>
 #include <readline/history.h>
@@ -348,6 +349,8 @@ static void proxy_added(GDBusProxy *proxy, void *user_data)
                gatt_add_characteristic(proxy);
        } else if (!strcmp(interface, "org.bluez.GattDescriptor1")) {
                gatt_add_descriptor(proxy);
+       } else if (!strcmp(interface, "org.bluez.GattManager1")) {
+               gatt_add_manager(proxy);
        }
 }
 
@@ -443,6 +446,8 @@ static void proxy_removed(GDBusProxy *proxy, void *user_data)
 
                if (default_attr == proxy)
                        set_default_attribute(NULL);
+       } else if (!strcmp(interface, "org.bluez.GattManager1")) {
+               gatt_remove_manager(proxy);
        }
 }
 
@@ -1337,6 +1342,36 @@ static void cmd_notify(const char *arg)
        gatt_notify_attribute(default_attr, enable ? true : false);
 }
 
+static void cmd_register_profile(const char *arg)
+{
+       wordexp_t w;
+
+       if (check_default_ctrl() == FALSE)
+               return;
+
+       if (wordexp(arg, &w, WRDE_NOCMD)) {
+               rl_printf("Invalid argument\n");
+               return;
+       }
+
+       if (w.we_wordc == 0) {
+               rl_printf("Missing argument\n");
+               return;
+       }
+
+       gatt_register_profile(dbus_conn, default_ctrl, &w);
+
+       wordfree(&w);
+}
+
+static void cmd_unregister_profile(const char *arg)
+{
+       if (check_default_ctrl() == FALSE)
+               return;
+
+       gatt_unregister_profile(dbus_conn, default_ctrl);
+}
+
 static void cmd_version(const char *arg)
 {
        rl_printf("Version %s\n", VERSION);
@@ -1470,6 +1505,10 @@ static const struct {
        { "write",        "<data=[xx xx ...]>", cmd_write,
                                                "Write attribute value" },
        { "notify",       "<on/off>", cmd_notify, "Notify attribute value" },
+       { "register-profile", "<UUID ...>", cmd_register_profile,
+                                               "Register profile to connect" },
+       { "unregister-profile", NULL, cmd_unregister_profile,
+                                               "Unregister profile" },
        { "version",      NULL,       cmd_version, "Display version" },
        { "quit",         NULL,       cmd_quit, "Quit program" },
        { "exit",         NULL,       cmd_quit },
index a58720c..e10659b 100644 (file)
@@ -1,5 +1,5 @@
 AC_PREREQ(2.60)
-AC_INIT(bluez, 5.28)
+AC_INIT(bluez, 5.30)
 
 AM_INIT_AUTOMAKE([foreign subdir-objects color-tests silent-rules
                                        tar-pax no-dist-gzip dist-xz])
@@ -220,7 +220,7 @@ AC_ARG_ENABLE(manpages, AC_HELP_STRING([--enable-manpages],
 AM_CONDITIONAL(MANPAGES, test "${enable_manpages}" = "yes")
 
 AC_ARG_ENABLE(experimental, AC_HELP_STRING([--enable-experimental],
-                       [enable experimental plugins (NFC, ...)]),
+                       [enable experimental plugins (SAP, NFC, ...)]),
                                        [enable_experimental=${enableval}])
 AM_CONDITIONAL(EXPERIMENTAL, test "${enable_experimental}" = "yes")
 
index 5527993..c815cf0 100644 (file)
@@ -19,6 +19,8 @@ Methods               void StartDiscovery()
                        This process will start creating Device objects as
                        new devices are discovered.
 
+                       During discovery RSSI delta-threshold is imposed.
+
                        Possible errors: org.bluez.Error.NotReady
                                         org.bluez.Error.Failed
 
@@ -35,6 +37,73 @@ Methods              void StartDiscovery()
                                         org.bluez.Error.Failed
                                         org.bluez.Error.NotAuthorized
 
+               void RemoveDevice(object device)
+
+                       This removes the remote device object at the given
+                       path. It will remove also the pairing information.
+
+                       Possible errors: org.bluez.Error.InvalidArguments
+                                        org.bluez.Error.Failed
+
+               void SetDiscoveryFilter(dict filter) [Experimental]
+
+                       This method sets the device discovery filter for the
+                       caller. When this method is called with no filter
+                       parameter, filter is removed.
+
+                       Parameters that may be set in the filter dictionary
+                       include the following:
+
+                       array{string} UUIDs     : filtered service UUIDs
+                       int16         RSSI      : RSSI threshold value
+                       uint16        Pathloss  : Pathloss threshold value
+                       string        Transport : type of scan to run
+
+                       When a remote device is found that advertises any UUID
+                       from UUIDs, it will be reported if:
+                       - Pathloss and RSSI are both empty,
+                       - only Pathloss param is set, device advertise TX pwer,
+                         and computed pathloss is less than Pathloss param,
+                       - only RSSI param is set, and received RSSI is higher
+                         than RSSI param,
+
+                       Transport parameter determines the type of scan:
+                               "auto"  - interleaved scan, default value
+                               "bredr" - BR/EDR inquiry
+                               "le"    - LE scan only
+
+                       If "le" or "bredr" Transport is requested, and the
+                       controller doesn't support it, org.bluez.Error.Failed
+                       error will be returned. If "auto" transport is
+                       requested, scan will use LE, BREDR, or both, depending
+                       on what's currently enabled on the controller.
+
+                       When discovery filter is set, Device objects will be
+                       created as new devices with matching criteria are
+                       discovered. PropertiesChanged signals will be emitted
+                       for already existing Device objects, with updated RSSI
+                       value. If one or more discovery filters have been set,
+                       the RSSI delta-threshold, that is imposed by
+                       StartDiscovery by default, will not be applied.
+
+                       When multiple clients call SetDiscoveryFilter, their
+                       filters are internally merged, and notifications about
+                       new devices are sent to all clients. Therefore, each
+                       client must check that device updates actually match
+                       its filter.
+
+                       When SetDiscoveryFilter is called multiple times by the
+                       same client, last filter passed will be active for
+                       given client.
+
+                       SetDiscoveryFilter can be called before StartDiscovery.
+                       It is useful when client will create first discovery
+                       session, to ensure that proper scan will be started
+                       right after call to StartDiscovery.
+
+                       Possible errors: org.bluez.Error.NotReady
+                                        org.bluez.Error.Failed
+
 #ifdef __TIZEN_PATCH__
                void StartCustomDiscovery(string pattern)
 
@@ -179,14 +248,6 @@ Methods            void StartDiscovery()
                        Possible errors: org.bluez.Error.InvalidArguments
 #endif
 
-               void RemoveDevice(object device)
-
-                       This removes the remote device object at the given
-                       path. It will remove also the pairing information.
-
-                       Possible errors: org.bluez.Error.InvalidArguments
-                                        org.bluez.Error.Failed
-
 Properties     string Address [readonly]
 
                        The Bluetooth device address.
diff --git a/doc/advertising-api.txt b/doc/advertising-api.txt
new file mode 100644 (file)
index 0000000..7fb34ee
--- /dev/null
@@ -0,0 +1,101 @@
+BlueZ D-Bus LE Advertising API Description
+******************************************
+
+Advertising packets are structured data which is broadcast on the LE Advertising
+channels and available for all devices in range.  Because of the limited space
+available in LE Advertising packets (32 bytes), each packet's contents must be
+carefully controlled.
+
+BlueZ acts as a store for the Advertisement Data which is meant to be sent.
+It constructs the correct Advertisement Data from the structured
+data and configured the kernel to send the correct advertisement.
+
+Advertisement Data objects are registered freely and then referenced by BlueZ
+when constructing the data sent to the kernel.
+
+LE Advertisement Data hierarchy
+===============================
+
+Specifies the Advertisement Data to be broadcast and some advertising
+parameters.  Properties which are not present will not be included in the
+data.  Required advertisement data types will always be included.
+All UUIDs are 128-bit versions in the API, and 16 or 32-bit
+versions of the same UUID will be used in the advertising data as appropriate.
+
+Service                org.bluez
+Interface      org.bluez.LEAdvertisement1
+Object path    freely definable
+
+Methods                void Release() [noreply]
+
+                       This method gets called when the service daemon
+                       removes the Advertisement. A client can use it to do
+                       cleanup tasks. There is no need to call
+                       UnregisterAdvertisement because when this method gets
+                       called it has already been unregistered.
+
+Properties     string Type
+
+                       Determines the type of advertising packet requested.
+
+                       Possible values: "broadcast" or "peripheral"
+
+               array{string} ServiceUUIDs
+
+                       List of UUIDs to include in the "Service UUID" field of
+                       the Advertising Data.
+
+               dict ManufacturerData
+
+                       Manufactuer Data fields to include in
+                       the Advertising Data.  Keys are the Manufacturer ID
+                       to associate with the data.
+
+               array{string} SolicitUUIDs
+
+                       Array of UUIDs to include in "Service Solicitation"
+                       Advertisement Data.
+
+               dict ServiceData
+
+                       Service Data elements to include. The keys are the
+                       UUID to associate with the data.
+
+
+LE Advertising Manager hierarchy
+================================
+
+The Advertising Manager allows external applications to register Advertisement
+Data which should be broadcast to devices.  Advertisement Data elements must
+follow the API for LE Advertisement Data described above.
+
+Service                org.bluez
+Interface      org.bluez.LEAdvertisingManager1 [Experimental]
+Object path    /org/bluez/{hci0,hci1,...}
+
+Methods                RegisterAdvertisement(object advertisement, dict options)
+
+                       Registers an advertisement object to be sent over the LE
+                       Advertising channel.  The service must be exported
+                       under interface LEAdvertisement1. InvalidArguments
+                       indicates that the object has invalid or conflicting
+                       properties.  InvalidLength indicates that the data
+                       provided generates a data packet which is too long.
+                       The properties of this object are parser when it is
+                       registered, and any changes are ignored.
+                       Currently only one advertisement at a time is supported,
+                       attempting to register two advertisements will result in
+                       an AlreadyExists error.
+
+                       Possible errors: org.bluez.Error.InvalidArguments
+                                        org.bluez.Error.AlreadyExists
+                                        org.bluez.Error.InvalidLength
+
+               UnregisterAdvertisement(object advertisement)
+
+                       This unregisters an advertisement that has been
+                       prevously registered.  The object path parameter must
+                       match the same value that has been used on registration.
+
+                       Possible errors: org.bluez.Error.InvalidArguments
+                                        org.bluez.Error.DoesNotExist
index babdb61..3329ffd 100644 (file)
@@ -157,6 +157,13 @@ Properties string UUID [read-only]
                        descriptor objects will become available via
                        ObjectManager as soon as they get discovered.
 
+#ifdef __TIZEN_PATCH__
+               string Unicast [read-only]
+
+                       12:34:56:78:9A:BC remote device address, if address is set then
+                       notifications or indications shall be sent to only "XX_XX_XX_XX_XX_XX"
+                       device otherwise notification or indication shall be multicasted.
+#endif
 
 Characteristic Descriptors hierarchy
 ====================================
index 725e8cc..b4ddf77 100644 (file)
@@ -23,6 +23,7 @@ Linux kernel v3.15    Version 1.5
 Linux kernel v3.16     Version 1.6
 Linux kernel v3.17     Version 1.7
 Linux kernel v3.19     Version 1.8
+Linux kernel v4.1      Version 1.9 (not yet released)
 
 Version 1.1 introduces Set Device ID command.
 
@@ -54,6 +55,11 @@ an extra setting for enabling SSP debug mode.
 Version 1.8 introduces Start Service Discovery command. It also adds new
 Long Term Key types for LE Secure Connection feature.
 
+Version 1.9 introduces a new static address setting and allows the usage
+of Set Fast Connectable when controller is powered off. The existing Set
+Advertising command gained an extra setting for enabling undirected
+connectable advertising.
+
 
 Example
 =======
@@ -142,6 +148,9 @@ and Command Complete events:
 0x0F   Not Powered
 0x10   Cancelled
 0x11   Invalid Index
+0x12   RFKilled
+0x13   Already Paired
+0x14   Permission Denied
 
 As a general rule all commands generate the events as specified below,
 however invalid lengths or unknown commands will always generate a
@@ -415,21 +424,18 @@ Set Fast Connectable Command
        (e.g. not for single-mode LE ones). It will return Not Supported
        otherwise.
 
-       This command can only be used when the controller is powered on
-       and will return Not Powerd otherwise.
+       This command can be used when the controller is not powered and
+       all settings will be programmed once powered.
 
-       If connectable is not set, then this command will fail with
-       Rejected error.
+       The setting will be remembered during power down/up toggles.
 
        This command generates a Command Complete event on success or
        a Command Status event on failure.
 
        Possible errors:        Failed
                                Busy
-                               Rejected
                                Not Supported
                                Invalid Parameters
-                               Not Powered
                                Invalid Index
 
 
@@ -1040,6 +1046,7 @@ Pair Device Command
                                Invalid Parameters
                                Not Powered
                                Invalid Index
+                               Already Paired
 
 
 Cancel Pair Device Command
@@ -1299,16 +1306,14 @@ Add Remote Out Of Band Data Command
        Secure Connections is disabled, then of course this is the
        same as not providing any data at all.
 
-       When providing data for remote LE devices, then the Hash_192 field
-       is used to provide the Security Manager TK Value. The Randomizer_192
-       field is not used and shall be set to zero. The Hash_192 value can
-       also be set to zero and that means that no Out Of Band data for
-       LE legacy pairing is provided.
+       When providing data for remote LE devices, then the Hash_192 and
+       and Randomizer_192 fields are not used and shell be set to zero.
 
        The Hash_256 and Randomizer_256 fields can be used for LE secure
        connections Out Of Band data. If only LE secure connections data
        is provided the Hash_P192 and Randomizer_P192 fields can be set
-       to zero.
+       to zero. Currently there is no support for providing the Security
+       Manager TK Value for LE legacy pairing.
 
        If Secure Connections Only mode has been enabled, then providing
        Hash_P192 and Randomizer_P192 is not allowed. They are required
@@ -1561,12 +1566,37 @@ Set Advertising Command
        Return Parameters:      Current_Settings (4 Octets)
 
        This command is used to enable LE advertising on a controller
-       that supports it. The allowed values for the Advertising
-       command parameter are 0x00 and 0x01. All other values will
-       return Invalid Parameters.
+       that supports it. The allowed values for the Advertising command
+       parameter are 0x00, 0x01 and 0x02. All other values will return
+       Invalid Parameters.
 
-       A pre-requisite is that LE is already enabled, otherwise
-       this command will return a "rejected" response.
+       The value 0x00 disables advertising, the value 0x01 enables
+       advertising with considering of connectable setting and the
+       value 0x02 enables advertising in connectable mode.
+
+       Using value 0x01 means that when connectable setting is disabled,
+       the advertising happens with undirected non-connectable advertising
+       packets and a non-resovable random address is used. If connectable
+       setting is enabled, then undirected connectable advertising packets
+       and the identity address or resolvable private address are used.
+
+       LE Devices configured via Add Device command with Action 0x01
+       have no effect when using Advertising value 0x01 since only the
+       connectable setting is taken into account.
+
+       To utilize undirected connectable advertising without changing the
+       connectable setting, the value 0x02 can be utilized. It makes the
+       device connectable via LE without the requirement for being
+       connectable on BR/EDR (and/or LE).
+
+       The value 0x02 should be the preferred mode of operation when
+       implementing peripheral mode.
+
+       Using this command will temporarily deactive any configuration
+       made by the Add Advertising command. This command takes precedence.
+
+       A pre-requisite is that LE is already enabled, otherwise this
+       command will return a "rejected" response.
 
        This command generates a Command Complete event on success or a
        Command Status event on failure.
@@ -2361,7 +2391,6 @@ Read Local Out Of Band Extended Data Command
 
                LE Bluetooth Device Address
                LE Role
-               Security Manager TK Value (optional)
                LE Secure Connections Confirmation Value (optional)
                LE Secure Connections Random Value (optional)
                Appearance (optional)
@@ -2372,15 +2401,21 @@ Read Local Out Of Band Extended Data Command
        Random Value fields are only included when secure connections has been
        enabled.
 
+       The Security Manager TK Value from the Bluetooth specification can
+       not be provided by this command. The Out Of Band information here are
+       for asymmetric exchanges based on Diffie-Hellman key exchange. The
+       Security Manager TK Value is a symmetric random number that has to
+       be acquired and agreed upon differently.
+
        The returned information from BR/EDR controller and LE controller
        types are not related to each other. Once they have been used
        over an Out Of Band link, a new set of information shall be
        requested.
 
        When Secure Connections Only mode has been enabled, then the fields
-       for Simple Pairing Hash C-192, Simple Pairing Randomizer R-192 and
-       Security Manager TK Value are not returned. Only the fields for
-       the strong secure connections pairing are included.
+       for Simple Pairing Hash C-192 and Simple Pairing Randomizer R-192
+       are not returned. Only the fields for the strong secure connections
+       pairing are included.
 
        This command can only be used when the controller is powered.
 
@@ -2407,6 +2442,7 @@ Read Extended Controller Index List Command
        Return Parameters:      Num_Controllers (2 Octets)
                                Controller_Index[i] (2 Octets)
                                Controller_Type[i] (1 Octet)
+                               Controller_Bus[i] (1 Octet)
 
        This command returns the list of currently known controllers. It
        includes configured, unconfigured and alternate controllers.
@@ -2441,6 +2477,16 @@ Read Extended Controller Index List Command
        Alternate MAC/PHY controllers will be listed as 0x02. They do not
        support the difference between configured and unconfigured state.
 
+       The Controller_Bus parameter has these values:
+
+               0x00    Virtual
+               0x01    USB
+               0x02    PCMCIA
+               0x03    UART
+               0x04    RS232
+               0x05    PCI
+               0x06    SDIO
+
        Controllers marked as RAW only operation are currently not listed
        by this command.
 
@@ -2448,6 +2494,229 @@ Read Extended Controller Index List Command
        a Command Status event on failure.
 
 
+Read Advertising Features Command
+=================================
+
+       Command Code:           0x003d
+       Controller Index:       <controller id>
+       Command Parameters:
+       Return Parameters:      Supported_Flags (4 Octets)
+                               Max_Adv_Data_Len (1 Octet)
+                               Max_Scan_Rsp_Len (1 Octet)
+                               Max_Instances (1 Octet)
+                               Num_Instances (1 Octet)
+                               Instance[i] (1 Octet)
+
+       This command is used to read the advertising features supported
+       by the controller and stack.
+
+       With the Supported_Flags field the possible values for the Flags
+       field in Add Advertising command provided:
+
+               0       Switch into Connectable mode
+               1       Advertise as Discoverable
+               2       Advertise as Limited Discoverable
+               3       Add Flags field to Adv_Data
+               4       Add TX Power field to Adv_Data
+               5       Add Appearance field to Scan_Rsp
+               6       Add Local Name in Scan_Rsp
+
+       The Flags bit 0 indicates support for connectable advertising
+       and for switching to connectable advertising independent of the
+       connectable global setting. When this flag is not supported, then
+       the global connectable setting determines if undirected connectable,
+       undirected scannable or undirected non-connectable advertising is
+       used. It also determines the use of non-resolvable random address
+       versus identity address or resolvable private address.
+
+       The Flags bit 1 indicates support for advertising with discoverable
+       mode enabled. Users of this flag will decrease the Max_Adv_Data_Len
+       by 3 octets. In this case the advertising data flags are managed
+       and added in front of the provided advertising data.
+
+       The Flags bit 2 indicates support for advertising with limited
+       discoverable mode enabled. Users of this flag will decrease the
+       Max_Adv_Data_Len by 3 octets. In this case the advertising data
+       flags are managed and added in front of the provided advertising
+       data.
+
+       The Flags bit 3 indicates support for automatically keeping the
+       Flags field of the advertising data updated. Users of this flag
+       will decrease the Max_Adv_Data_Len by 3 octets and need to keep
+       that in mind. The Flags field will be added in front of the
+       advertising data provided by the user. Note that with Flags bit 1
+       and Flags bit 2, this one will be implicitly used even if it is
+       not marked as supported.
+
+       The Flags bit 4 indicates support for automatically adding the
+       TX Power value to the advertising data. Users of this flag will
+       decrease the Max_Adv_Data_Len by 3 octets. The TX Power field will
+       be added at the end of the user provided advertising data. If the
+       controller does not support TX Power information, then this bit will
+       not be set.
+
+       The Flags bit 5 indicates support for automatically adding the
+       Apperance value to the scan response data. Users of this flag
+       will decrease the Max_Scan_Rsp_len by 4 octets. The Appearance
+       field will be added in front of the scan response data provided
+       by the user. If the appearance value is not supported, then this
+       bit will not be set.
+
+       The Flags bit 6 indicates support for automatically adding the
+       Local Name value to the scan response data. This flag indicates
+       an opportunistic approach for the Local Name. If enough space
+       in the scan response data is available, it will be added. If the
+       space is limited a short version or no name information. The
+       Local Name will be added at the end of the scan response data.
+
+       The valid range for Instance identifiers is 1-254. The value 0
+       is reserved for internal use and the value 255 is reserved for
+       future extensions. However the Max_Instances value for indicating
+       the number of supported Instances can be also 0 if the controller
+       does not support any advertising.
+
+       The Max_Adv_Data_Len and Max_Scan_Rsp_Len provides extra
+       information about the maximum length of the data fields. For
+       now this will always return the value 31. Different flags
+       however might decrease the actual available length in these
+       data fields.
+
+       With Num_Instances and Instance array the current occupied
+       Instance identifiers can be retrieved.
+
+       This command generates a Command Complete event on success or
+       a Command Status event on failure.
+
+       Possible errors:        Invalid Parameters
+                               Invalid Index
+
+
+Add Advertising Command
+=======================
+
+       Command Code:           0x003e
+       Controller Index:       <controller id>
+       Command Parameters:     Instance (1 Octet)
+                               Flags (4 Octets)
+                               Duration (2 Octets)
+                               Timeout (2 Octets)
+                               Adv_Data_Len (1 Octet)
+                               Scan_Rsp_len (1 Octet)
+                               Adv_Data (0-255 Octets)
+                               Scan_Rsp (0-255 Octets)
+       Return Parameters:      Instance (1 Octet)
+
+       This command is used to configure an advertising instance that
+       can be used to switch a Bluetooth Low Energy controller into
+       advertising mode.
+
+       Added advertising information with this command will be ignored
+       when using the Set Advertising command to enable advertising. The
+       usage of Set Advertising command take precedence over this command.
+
+       The Instance identifier is a value between 1 and the number of
+       supported instances. The value 0 is reserved.
+
+       With the Flags value the type of advertising is controlled and
+       the following flags are defined:
+
+               0       Switch into Connectable mode
+               1       Advertise as Discoverable
+               2       Advertise as Limited Discoverable
+               3       Add Flags field to Adv_Data
+               4       Add TX Power field to Adv_Data
+               5       Add Appearance field to Scan_Rsp
+               6       Add Local Name in Scan_Rsp
+
+       When the connectable flag is set, then the controller will use
+       undirected connectable advertising. The value of the connectable
+       setting can be overwritten this way. This is useful to switch a
+       controller into connectable mode only for LE operation. This is
+       similar to the mode 0x02 from the Set Advertising command.
+
+       When the connectable flag is not set, then the controller will
+       use advertising based on the connectable setting. When using
+       non-connectable or scannable advertising, the controller will
+       be programmed with a non-resolvable random address. When the
+       system is connectable, then the identity address or resolvable
+       private address will be used.
+
+       Using the connectable flag is useful for peripheral mode support
+       where BR/EDR (and/or LE) is controlled by Add Device. This allows
+       making the peripheral connectable without having to interfere
+       with the global connectable setting.
+
+       If Scan_Rsp_Len is zero and connectable flag is not set and
+       the global connectable setting is off, then non-connectable
+       advertising is used. If Scan_Rsp_Len is larger than zero and
+       connectable flag is not set and the global advertising is off,
+       then scannable advertising is used. This small difference is
+       supported to provide less air traffic for devices implementing
+       broadcaster role.
+
+       The Duration parameter configures the length of an Instance. The
+       value is in seconds and a value of 0 indicates an automatic choice
+       for the Duration. If only one advertising Instance has been added,
+       then the Duration value will be ignored. It only applies for the
+       case where multiple Instances are configured. In that case every
+       Instance will be available for the Duration time and after that
+       it switches to the next one. This is a simple round-robin based
+       approach.
+
+       The Timeout parameter configures the life-time of an Instance. In
+       case the value 0 is used it indicates no expiration time. If a
+       timeout value is provided, then the advertising Instace will be
+       automatically removed when the timeout passes. The value for the
+       timeout is in seconds. Powering down a controller will invalidate
+       all advertising Instances and it is not possible to add a new
+       Instance with a timeout when the controller is powered down.
+
+       When a Timeout is provided, then the Duration substracts from
+       the actual Timeout value of that Instance. For example an Instance
+       with Timeout of 6 and Duration of 2 will be scheduled exactly 3
+       times. Other Instances have no influence on the Timeout.
+
+       A pre-requisite is that LE is already enabled, otherwise this
+       command will return a "rejected" response.
+
+       This command can be used when the controller is not powered and
+       all settings will be programmed once powered.
+
+       This command generates a Command Complete event on success or a
+       Command Status event on failure.
+
+       Possible errors:        Failed
+                               Rejected
+                               Not Supported
+                               Invalid Parameters
+                               Invalid Index
+
+
+Remove Advertising Command
+==========================
+
+       Command Code:           0x003f
+       Controller Index:       <controller id>
+       Command Parameters:     Instance (1 Octet)
+       Return Parameters:      Instance (1 Octet)
+
+       This command is used to remove an advertising instance that
+       can be used to switch a Bluetooth Low Energy controller into
+       advertising mode.
+
+       When the Instance parameter is zero, then all previously added
+       advertising Instances will be removed.
+
+       This command can be used when the controller is not powered and
+       all settings will be programmed once powered.
+
+       This command generates a Command Complete event on success or
+       a Command Status event on failure.
+
+       Possible errors:        Invalid Parameters
+                               Invalid Index
+
+
 Command Complete Event
 ======================
 
@@ -3200,13 +3469,14 @@ Extended Index Added Event
        Event Code:             0x0020
        Controller Index:       <controller id>
        Event Parameters:       Controller_Type (1 Octet)
+                               Controller_Bus (1 Octet)
 
        This event indicates that a new controller index has been
        added to the system.
 
        This event will only be used after Read Extended Controller Index
        List has been used at least once. If it has not been used, then
-       Index Added and Unconfigured Index Added are send instead.
+       Index Added and Unconfigured Index Added are sent instead.
 
 
 Extended Index Removed Event
@@ -3215,10 +3485,79 @@ Extended Index Removed Event
        Event Code:             0x0021
        Controller Index:       <controller id>
        Event Parameters:       Controller_Type (1 Octet)
+                               Controller_Bus (1 Octet)
 
        This event indicates that an existing controller index has been
        removed from the system.
 
        This event will only be used after Read Extended Controller Index
        List has been used at least once. If it has not been used, then
-       Index Removed and Unconfigured Index Removed are send instead.
+       Index Removed and Unconfigured Index Removed are sent instead.
+
+
+Local Out Of Band Extended Data Updated Event
+=============================================
+
+       Event Code:             0x0022
+       Controller Index:       <controller id>
+       Event Parameters:       Address_Type (1 Octet)
+                               EIR_Data_Length (2 Octets)
+                               EIR_Data (0-65535 Octets)
+
+       This event is used when the Read Local Out Of Band Extended Data
+       command has been used and some other user requested a new set
+       of local out-of-band data. This allows for the original caller
+       to adjust the data.
+
+       Possible values for the Address_Type parameter are a bit-wise or
+       of the following bits:
+
+               0       BR/EDR
+               1       LE Public
+               2       LE Random
+
+       By combining these e.g. the following values are possible:
+
+               1       BR/EDR
+               6       LE (public & random)
+               7       Reserved (not in use)
+
+       The value for EIR_Data_Length and content for EIR_Data is the
+       same as described in Read Local Out Of Band Extended Data command.
+
+       When LE Privacy is used and LE Secure Connections out-of-band
+       data has been requested, then this event will be emitted every
+       time the Resolvable Private Address (RPA) gets changed. The new
+       RPA will be included in the EIR_Data.
+
+       The event will only be sent to management sockets other than the
+       one through which the command was sent. It will additionally also
+       only be sent to sockets that have used the command at least once.
+
+
+Advertising Added Event
+=======================
+
+       Event Code:             0x0023
+       Controller Index:       <controller id>
+       Event Parameters:       Instance (1 Octet)
+
+       This event indicates that an advertising instance has been added
+       using the Add Advertising command.
+
+       The event will only be sent to management sockets other than the
+       one through which the command was sent.
+
+
+Advertising Removed Event
+=========================
+
+       Event Code:             0x0024
+       Controller Index:       <controller id>
+       Event Parameters:       Instance (1 Octet)
+
+       This event indicates that an advertising instance has been removed
+       using the Remove Advertising command.
+
+       The event will only be sent to management sockets other than the
+       one through which the command was sent.
index 505bb27..06253c6 100644 (file)
@@ -29,9 +29,10 @@ test-gobex-header      28    OBEX header handling
 test-gobex-apparam       18    OBEX apparam handling
 test-gobex-transfer      36    OBEX transfer handling
 test-gdbus-client        13    D-Bus client handling
-test-gatt               131    GATT qualification test cases
+test-gatt               159    GATT qualification test cases
+test-hog                  6    HID Over GATT qualification test cases
                        -----
-                        706
+                        740
 
 
 Automated end-to-end testing
@@ -39,7 +40,7 @@ Automated end-to-end testing
 
 Application            Count   Description
 -------------------------------------------
-mgmt-tester             243    Kernel management interface testing
+mgmt-tester             293    Kernel management interface testing
 l2cap-tester             27    Kernel L2CAP implementation testing
 rfcomm-tester             9    Kernel RFCOMM implementation testing
 smp-tester                5    Kernel SMP implementation testing
@@ -47,7 +48,7 @@ sco-tester               8    Kernel SCO implementation testing
 gap-tester                1    Daemon D-Bus API testing
 hci-tester               14    Controller hardware testing
                        -----
-                        307
+                        357
 
 
 Android end-to-end testing
index b50df0f..9642e86 100644 (file)
@@ -314,11 +314,8 @@ static void set_common_commands_bredrle(struct btdev *btdev)
        btdev->commands[15] |= 0x02;    /* Read BD ADDR */
 }
 
-static void set_bredr_commands(struct btdev *btdev)
+static void set_common_commands_bredr20(struct btdev *btdev)
 {
-       set_common_commands_all(btdev);
-       set_common_commands_bredrle(btdev);
-
        btdev->commands[0]  |= 0x01;    /* Inquiry */
        btdev->commands[0]  |= 0x02;    /* Inquiry Cancel */
        btdev->commands[0]  |= 0x10;    /* Create Connection */
@@ -371,6 +368,14 @@ static void set_bredr_commands(struct btdev *btdev)
        btdev->commands[14] |= 0x40;    /* Read Local Extended Features */
        btdev->commands[15] |= 0x01;    /* Read Country Code */
        btdev->commands[16] |= 0x04;    /* Enable Device Under Test Mode */
+}
+
+static void set_bredr_commands(struct btdev *btdev)
+{
+       set_common_commands_all(btdev);
+       set_common_commands_bredrle(btdev);
+       set_common_commands_bredr20(btdev);
+
        btdev->commands[16] |= 0x08;    /* Setup Synchronous Connection */
        btdev->commands[17] |= 0x01;    /* Read Extended Inquiry Response */
        btdev->commands[17] |= 0x02;    /* Write Extended Inquiry Response */
@@ -385,6 +390,13 @@ static void set_bredr_commands(struct btdev *btdev)
        btdev->commands[30] |= 0x08;    /* Get MWS Transport Layer Config */
 }
 
+static void set_bredr20_commands(struct btdev *btdev)
+{
+       set_common_commands_all(btdev);
+       set_common_commands_bredrle(btdev);
+       set_common_commands_bredr20(btdev);
+}
+
 static void set_le_commands(struct btdev *btdev)
 {
        set_common_commands_all(btdev);
@@ -496,6 +508,25 @@ static void set_bredr_features(struct btdev *btdev)
        btdev->max_page = 1;
 }
 
+static void set_bredr20_features(struct btdev *btdev)
+{
+       btdev->features[0] |= 0x04;     /* Encryption */
+       btdev->features[0] |= 0x20;     /* Role switch */
+       btdev->features[0] |= 0x80;     /* Sniff mode */
+       btdev->features[1] |= 0x08;     /* SCO link */
+       btdev->features[3] |= 0x40;     /* RSSI with inquiry results */
+       btdev->features[3] |= 0x80;     /* Extended SCO link */
+       btdev->features[4] |= 0x08;     /* AFH capable slave */
+       btdev->features[4] |= 0x10;     /* AFH classification slave */
+       btdev->features[5] |= 0x02;     /* Sniff subrating */
+       btdev->features[5] |= 0x04;     /* Pause encryption */
+       btdev->features[5] |= 0x08;     /* AFH capable master */
+       btdev->features[5] |= 0x10;     /* AFH classification master */
+       btdev->features[7] |= 0x80;     /* Extended features */
+
+       btdev->max_page = 1;
+}
+
 static void set_le_features(struct btdev *btdev)
 {
        btdev->features[4] |= 0x20;     /* BR/EDR Not Supported */
@@ -521,31 +552,34 @@ struct btdev *btdev_create(enum btdev_type type, uint16_t id)
        btdev->type = type;
 
        btdev->manufacturer = 63;
-
-       if (type == BTDEV_TYPE_BREDR)
-               btdev->version = 0x05;
-       else
-               btdev->version = 0x08;
-
        btdev->revision = 0x0000;
 
        switch (btdev->type) {
        case BTDEV_TYPE_BREDRLE:
+               btdev->version = 0x08;
                set_bredrle_features(btdev);
                set_bredrle_commands(btdev);
                break;
        case BTDEV_TYPE_BREDR:
+               btdev->version = 0x05;
                set_bredr_features(btdev);
                set_bredr_commands(btdev);
                break;
        case BTDEV_TYPE_LE:
+               btdev->version = 0x08;
                set_le_features(btdev);
                set_le_commands(btdev);
                break;
        case BTDEV_TYPE_AMP:
+               btdev->version = 0x01;
                set_amp_features(btdev);
                set_amp_commands(btdev);
                break;
+       case BTDEV_TYPE_BREDR20:
+               btdev->version = 0x04;
+               set_bredr20_features(btdev);
+               set_bredr20_commands(btdev);
+               break;
        }
 
        btdev->page_scan_interval = 0x0800;
index 32c708f..4b724a7 100644 (file)
@@ -62,6 +62,7 @@ enum btdev_type {
        BTDEV_TYPE_BREDR,
        BTDEV_TYPE_LE,
        BTDEV_TYPE_AMP,
+       BTDEV_TYPE_BREDR20,
 };
 
 enum btdev_hook_type {
index fe2f662..4881a24 100644 (file)
@@ -327,6 +327,9 @@ struct hciemu *hciemu_new(enum hciemu_type type)
        case HCIEMU_TYPE_LE:
                hciemu->btdev_type = BTDEV_TYPE_LE;
                break;
+       case HCIEMU_TYPE_LEGACY:
+               hciemu->btdev_type = BTDEV_TYPE_BREDR20;
+               break;
        default:
                return NULL;
        }
index d948867..41ca3fc 100644 (file)
@@ -30,6 +30,7 @@ enum hciemu_type {
        HCIEMU_TYPE_BREDRLE,
        HCIEMU_TYPE_BREDR,
        HCIEMU_TYPE_LE,
+       HCIEMU_TYPE_LEGACY,
 };
 
 enum hciemu_hook_type {
index 1edecb9..e70054a 100644 (file)
@@ -30,6 +30,7 @@
 #include <errno.h>
 #include <unistd.h>
 #include <stdlib.h>
+#include <string.h>
 #include <sys/socket.h>
 #include <sys/un.h>
 
index 755c6ae..dc51469 100644 (file)
@@ -32,6 +32,7 @@
 #include <string.h>
 #include <sys/socket.h>
 #include <sys/un.h>
+#include <sys/uio.h>
 
 #include "lib/bluetooth.h"
 #include "lib/hci.h"
index 0001a4b..6bba4e2 100644 (file)
@@ -32,6 +32,7 @@
 #include <unistd.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/uio.h>
 
 #include "lib/bluetooth.h"
 #include "lib/hci.h"
index fe0c0db..48711ae 100644 (file)
@@ -1111,7 +1111,8 @@ static void get_managed_objects(GDBusClient *client)
        if (!client->connected)
                return;
 
-       if (!client->proxy_added && !client->proxy_removed) {
+       if ((!client->proxy_added && !client->proxy_removed) ||
+                                                       !client->root_path) {
                refresh_properties(client);
                return;
        }
@@ -1212,7 +1213,7 @@ GDBusClient *g_dbus_client_new_full(DBusConnection *connection,
        GDBusClient *client;
        unsigned int i;
 
-       if (!connection || !service || !root_path)
+       if (!connection || !service)
                return NULL;
 
        client = g_try_new0(GDBusClient, 1);
@@ -1238,6 +1239,10 @@ GDBusClient *g_dbus_client_new_full(DBusConnection *connection,
                                                service_connect,
                                                service_disconnect,
                                                client, NULL);
+
+       if (!root_path)
+               return g_dbus_client_ref(client);
+
        client->added_watch = g_dbus_add_signal_watch(connection, service,
                                                client->root_path,
                                                DBUS_INTERFACE_OBJECT_MANAGER,
index 0cac5ff..d5456d2 100644 (file)
@@ -34,6 +34,7 @@
 #include "gdbus.h"
 
 #ifdef __TIZEN_PATCH__
+#if 0
 #include <syslog.h>
 static void gdbus_dbg(const char *format, ...)
 {
@@ -45,6 +46,7 @@ static void gdbus_dbg(const char *format, ...)
 
        va_end(ap);
 }
+#endif
 #else
 #define info(fmt...)
 #endif
@@ -1095,9 +1097,11 @@ static DBusHandlerResult generic_message(DBusConnection *connection,
                                                iface->user_data) == TRUE)
                        return DBUS_HANDLER_RESULT_HANDLED;
 #ifdef __TIZEN_PATCH__
+#if 0
                gdbus_dbg("%s: %s.%s()", dbus_message_get_path(message),
                                                        iface->name, method->name);
 #endif
+#endif
                return process_message(connection, message, method,
                                                        iface->user_data);
        }
index 4fe5941..91e714e 100644 (file)
@@ -1239,6 +1239,30 @@ const char *bt_compidtostr(int compid)
                return "IPS Group Inc.";
        case 488:
                return "STIR";
+       case 489:
+               return "Sano, Inc";
+       case 490:
+               return "Advanced Application Design, Inc.";
+       case 491:
+               return "AutoMap LLC";
+       case 492:
+               return "Spreadtrum Communications Shanghai Ltd";
+       case 493:
+               return "CuteCircuit LTD";
+       case 494:
+               return "Valeo Service";
+       case 495:
+               return "Fullpower Technologies, Inc.";
+       case 496:
+               return "KloudNation";
+       case 497:
+               return "Zebra Technologies Corporation";
+       case 498:
+               return "Itron, Inc.";
+       case 499:
+               return "The University of Tokyo";
+       case 500:
+               return "UTC Fire and Security";
        case 65535:
                return "internal use";
        default:
index 6ca64b6..852a6b2 100644 (file)
@@ -345,8 +345,8 @@ typedef struct {
 
 static inline void bswap_128(const void *src, void *dst)
 {
-       const uint8_t *s = src;
-       uint8_t *d = dst;
+       const uint8_t *s = (const uint8_t *) src;
+       uint8_t *d = (uint8_t *) dst;
        int i;
 
        for (i = 0; i < 16; i++)
index 2bbfb17..0a74836 100644 (file)
@@ -103,6 +103,12 @@ struct bnep_set_filter_req {
        uint8_t  list[0];
 } __attribute__((packed));
 
+struct bnep_ctrl_cmd_not_understood_cmd {
+       uint8_t type;
+       uint8_t ctrl;
+       uint8_t unkn_ctrl;
+} __attribute__((packed));
+
 struct bnep_control_rsp {
        uint8_t  type;
        uint8_t  ctrl;
@@ -120,6 +126,11 @@ struct bnep_ext_hdr {
 #define BNEPCONNDEL    _IOW('B', 201, int)
 #define BNEPGETCONNLIST        _IOR('B', 210, int)
 #define BNEPGETCONNINFO        _IOR('B', 211, int)
+#ifdef  __TIZEN_PATCH__
+#define BNEPGETSUPPFEAT        _IOR('B', 212, int)
+
+#define BNEP_SETUP_RESPONSE    0
+#endif
 
 struct bnep_connadd_req {
        int      sock;          /* Connected socket */
old mode 100644 (file)
new mode 100755 (executable)
index bc453f7..7fd251f
--- a/lib/hci.c
+++ b/lib/hci.c
@@ -592,7 +592,8 @@ static hci_map commands_map[] = {
        { "LE Receiver Test",                           228 },
        { "LE Transmitter Test",                        229 },
        { "LE Test End",                                230 },
-       { "Reserved",                                   231 },
+       { "LE Read Maximum Data Length",                231 },
+       { "Reserved",                                   232 },
 
        { NULL }
 };
@@ -3117,3 +3118,133 @@ int hci_le_read_remote_features(int dd, uint16_t handle, uint8_t *features, int
 
        return 0;
 }
+
+#ifdef __TIZEN_PATCH__
+int hci_le_read_maximum_data_length(
+       int dd, uint8_t *status, uint16_t *tx_octets,
+       uint16_t *tx_time, uint16_t *rx_octets,
+       uint16_t *rx_time, int to)
+{
+       le_read_maximum_data_length_rp rp;
+       struct hci_request rq;
+
+       memset(&rq, 0, sizeof(rq));
+       memset(&rp, 0, sizeof(rp));
+
+       rq.ogf = OGF_LE_CTL;
+       rq.ocf = OCF_LE_READ_MAXIMUM_DATA_LENGTH;
+       rq.rparam = &rp;
+       rq.rlen = LE_READ_MAXIMUM_DATA_LENGTH_SIZE;
+
+       if (hci_send_req(dd, &rq, to) < 0)
+               return -1;
+
+       if (rp.status) {
+               errno = EIO;
+               return -1;
+       }
+
+       *tx_octets = rp.max_tx_octets;
+       *tx_time = rp.max_tx_time;
+       *rx_octets = rp.max_rx_octets;
+       *rx_time = rp.max_rx_time;
+       *status = rp.status;
+       return 0;
+}
+
+int hci_le_write_host_suggested_data_length(
+               int dd, uint16_t *def_tx_octets,
+               uint16_t *def_tx_time, int to)
+{
+       le_write_host_suggested_data_length_cp cp;
+       struct hci_request rq;
+       uint8_t status;
+
+       memset(&cp, 0, sizeof(cp));
+       cp.def_tx_octets = def_tx_octets;
+       cp.def_tx_time = def_tx_time;
+
+       memset(&rq, 0, sizeof(rq));
+       rq.ogf = OGF_LE_CTL;
+       rq.ocf = OCF_LE_WRITE_HOST_SUGGESTED_DATA_LENGTH;
+       rq.cparam = &cp;
+       rq.clen = LE_WRITE_HOST_SUGGESTED_DATA_LENGTH_CP_SIZE;
+       rq.rparam = &status;
+       rq.rlen = 1;
+
+       if (hci_send_req(dd, &rq, to) < 0)
+               return -1;
+
+       if (status) {
+               errno = EIO;
+               return -1;
+       }
+
+       return 0;
+}
+
+int hci_le_read_host_suggested_data_length(
+       int dd, uint8_t *status, uint16_t *def_tx_octets,
+       uint16_t *def_tx_time, int to)
+{
+       le_read_host_suggested_data_length_rp rp;
+       struct hci_request rq;
+
+       memset(&rp, 0, sizeof(rp));
+       memset(&rq, 0, sizeof(rq));
+
+       rq.ogf = OGF_LE_CTL;
+       rq.ocf = OCF_LE_READ_HOST_SUGGESTED_DATA_LENGTH;
+       rq.rparam = &rp;
+       rq.rlen = LE_READ_HOST_SUGGESTED_DATA_LENGTH_SIZE;
+
+       if (hci_send_req(dd, &rq, to) < 0)
+               return -1;
+
+       if (rp.status) {
+               errno = EIO;
+               return -1;
+       }
+
+       *def_tx_octets = rp.def_tx_octets;
+       *def_tx_time = rp.def_tx_time;
+       *status = rp.status;
+       return 0;
+}
+
+int hci_le_set_data_length(
+               int dd, const bdaddr_t *bdaddr, uint16_t *max_tx_octets,
+               uint16_t *max_tx_time, int to)
+{
+       le_set_data_length_cp cp;
+       le_set_data_length_rp rp;
+       struct hci_request rq;
+       uint8_t status;
+
+       memset(&cp, 0, sizeof(cp));
+       memset(&rp, 0, sizeof(rp));
+
+       bacpy(&cp.bdaddr, bdaddr);
+       cp.max_tx_octets = max_tx_octets;
+       cp.max_tx_time = max_tx_time;
+
+       memset(&rq, 0, sizeof(rq));
+       rq.ogf = OGF_LE_CTL;
+       rq.ocf = OCF_LE_SET_DATA_LENGTH;
+       rq.cparam = &cp;
+       rq.clen = LE_SET_DATA_LENGTH_CP_SIZE;
+       rq.rparam = &rp;
+       rq.rlen = LE_SET_DATA_LENGTH_RP_SIZE;
+
+       if (hci_send_req(dd, &rq, to) < 0)
+               return -1;
+
+       if (rp.status) {
+               errno = EIO;
+               return -1;
+       }
+
+       return 0;
+}
+
+#endif
old mode 100644 (file)
new mode 100755 (executable)
index 8f524ff..ae7be46
--- a/lib/hci.h
+++ b/lib/hci.h
@@ -1710,6 +1710,52 @@ typedef struct {
 } __attribute__ ((packed)) le_test_end_rp;
 #define LE_TEST_END_RP_SIZE 3
 
+#ifdef __TIZEN_PATCH__
+#define OCF_LE_READ_MAXIMUM_DATA_LENGTH        0x002F
+typedef struct {
+       uint8_t status;
+       uint16_t max_tx_octets;
+       uint16_t max_tx_time;
+       uint16_t max_rx_octets;
+       uint16_t max_rx_time;
+} __attribute__ ((packed))
+le_read_maximum_data_length_rp;
+#define LE_READ_MAXIMUM_DATA_LENGTH_SIZE 9
+
+#define OCF_LE_WRITE_HOST_SUGGESTED_DATA_LENGTH        0x0030
+typedef struct {
+       uint16_t def_tx_octets;
+       uint16_t def_tx_time;
+} __attribute__ ((packed))
+le_write_host_suggested_data_length_cp;
+#define LE_WRITE_HOST_SUGGESTED_DATA_LENGTH_CP_SIZE 4
+
+#define OCF_LE_READ_HOST_SUGGESTED_DATA_LENGTH 0x0024
+typedef struct {
+       uint8_t status;
+       uint16_t def_tx_octets;
+       uint16_t def_tx_time;
+} __attribute__ ((packed))
+le_read_host_suggested_data_length_rp;
+#define LE_READ_HOST_SUGGESTED_DATA_LENGTH_SIZE 5
+
+#define OCF_LE_SET_DATA_LENGTH 0x0022
+typedef struct {
+       bdaddr_t bdaddr;
+       uint16_t max_tx_octets;
+       uint16_t max_tx_time;
+} __attribute__ ((packed))
+le_set_data_length_cp;
+#define LE_SET_DATA_LENGTH_CP_SIZE 10
+
+typedef struct {
+       uint16_t handle;
+       uint8_t status;
+} __attribute__ ((packed))
+le_set_data_length_rp;
+#define LE_SET_DATA_LENGTH_RP_SIZE 3
+#endif
+
 #define OCF_LE_ADD_DEVICE_TO_RESOLV_LIST       0x0027
 typedef struct {
        uint8_t         bdaddr_type;
old mode 100644 (file)
new mode 100755 (executable)
index 55aeb17..c766f11
@@ -141,7 +141,18 @@ int hci_le_clear_resolving_list(int dd, int to);
 int hci_le_read_resolving_list_size(int dd, uint8_t *size, int to);
 int hci_le_set_address_resolution_enable(int dev_id, uint8_t enable, int to);
 int hci_le_read_remote_features(int dd, uint16_t handle, uint8_t *features, int to);
-
+#ifdef __TIZEN_PATCH__
+int hci_le_read_maximum_data_length(
+       int dd, uint8_t *status, uint16_t *tx_octets,
+       uint16_t *tx_time, uint16_t *rx_octets,
+       uint16_t *rx_time, int to );
+int hci_le_write_host_suggested_data_length(int dd, uint16_t *def_tx_octets,
+       uint16_t *def_tx_time, int to);
+int hci_le_read_host_suggested_data_length(int dd, uint8_t *status,
+       uint16_t *def_tx_octets, uint16_t *def_tx_time, int to);
+int hci_le_set_data_length(int dd, const bdaddr_t *bdaddr,
+               uint16_t *max_tx_octets, uint16_t *max_tx_time, int to);
+#endif
 int hci_for_each_dev(int flag, int(*func)(int dd, int dev_id, long arg), long arg);
 int hci_get_route(bdaddr_t *bdaddr);
 
old mode 100644 (file)
new mode 100755 (executable)
index 357875c..de9512e
@@ -46,6 +46,8 @@
 #define MGMT_STATUS_CANCELLED          0x10
 #define MGMT_STATUS_INVALID_INDEX      0x11
 #define MGMT_STATUS_RFKILLED           0x12
+#define MGMT_STATUS_ALREADY_PAIRED     0x13
+#define MGMT_STATUS_PERMISSION_DENIED  0x14
 
 struct mgmt_hdr {
        uint16_t opcode;
@@ -272,14 +274,10 @@ struct mgmt_cp_user_passkey_neg_reply {
 
 #define MGMT_OP_READ_LOCAL_OOB_DATA    0x0020
 struct mgmt_rp_read_local_oob_data {
-       uint8_t hash[16];
-       uint8_t randomizer[16];
-} __packed;
-struct mgmt_rp_read_local_oob_ext_data {
        uint8_t hash192[16];
-       uint8_t randomizer192[16];
+       uint8_t rand192[16];
        uint8_t hash256[16];
-       uint8_t randomizer256[16];
+       uint8_t rand256[16];
 } __packed;
 
 #define MGMT_OP_ADD_REMOTE_OOB_DATA    0x0021
@@ -455,7 +453,67 @@ struct mgmt_cp_start_service_discovery {
        uint16_t uuid_count;
        uint8_t uuids[0][16];
 } __packed;
-#define MGMT_START_SERVICE_DISCOVERY_SIZE      4
+
+#define MGMT_OP_READ_LOCAL_OOB_EXT_DATA        0x003B
+struct mgmt_cp_read_local_oob_ext_data {
+       uint8_t  type;
+} __packed;
+struct mgmt_rp_read_local_oob_ext_data {
+       uint8_t  type;
+       uint16_t eir_len;
+       uint8_t  eir[0];
+} __packed;
+
+#define MGMT_OP_READ_EXT_INDEX_LIST    0x003C
+struct mgmt_rp_read_ext_index_list {
+       uint16_t num_controllers;
+       struct {
+               uint16_t index;
+               uint8_t type;
+               uint8_t bus;
+       } entry[0];
+} __packed;
+
+#define MGMT_OP_READ_ADV_FEATURES      0x003D
+struct mgmt_rp_read_adv_features {
+       uint32_t supported_flags;
+       uint8_t  max_adv_data_len;
+       uint8_t  max_scan_rsp_len;
+       uint8_t  max_instances;
+       uint8_t  num_instances;
+       uint8_t  instance[0];
+} __packed;
+
+#define MGMT_OP_ADD_ADVERTISING                0x003E
+struct mgmt_cp_add_advertising {
+       uint8_t  instance;
+       uint32_t flags;
+       uint16_t duration;
+       uint16_t timeout;
+       uint8_t  adv_data_len;
+       uint8_t  scan_rsp_len;
+       uint8_t  data[0];
+} __packed;
+struct mgmt_rp_add_advertising {
+       uint8_t instance;
+} __packed;
+
+#define MGMT_ADV_FLAG_CONNECTABLE      (1 << 0)
+#define MGMT_ADV_FLAG_DISCOV           (1 << 1)
+#define MGMT_ADV_FLAG_LIMITED_DISCOV   (1 << 2)
+#define MGMT_ADV_FLAG_MANAGED_FLAGS    (1 << 3)
+#define MGMT_ADV_FLAG_TX_POWER         (1 << 4)
+#define MGMT_ADV_FLAG_APPEARANCE       (1 << 5)
+#define MGMT_ADV_FLAG_LOCAL_NAME       (1 << 6)
+
+#define MGMT_OP_REMOVE_ADVERTISING     0x003F
+struct mgmt_cp_remove_advertising {
+       uint8_t instance;
+} __packed;
+#define MGMT_REMOVE_ADVERTISING_SIZE   1
+struct mgmt_rp_remove_advertising {
+       uint8_t instance;
+} __packed;
 
 #define MGMT_EV_CMD_COMPLETE           0x0001
 struct mgmt_ev_cmd_complete {
@@ -483,7 +541,7 @@ struct mgmt_ev_controller_error {
 
 #define MGMT_EV_CLASS_OF_DEV_CHANGED   0x0007
 struct mgmt_ev_class_of_dev_changed {
-       uint8_t class_of_dev[3];
+       uint8_t dev_class[3];
 } __packed;
 
 #define MGMT_EV_LOCAL_NAME_CHANGED     0x0008
@@ -640,6 +698,35 @@ struct mgmt_ev_new_conn_param {
 
 #define MGMT_EV_NEW_CONFIG_OPTIONS     0x001f
 
+#define MGMT_EV_EXT_INDEX_ADDED                0x0020
+struct mgmt_ev_ext_index_added {
+       uint8_t type;
+       uint8_t bus;
+} __packed;
+
+#define MGMT_EV_EXT_INDEX_REMOVED      0x0021
+struct mgmt_ev_ext_index_removed {
+       uint8_t type;
+       uint8_t bus;
+} __packed;
+
+#define MGMT_EV_LOCAL_OOB_DATA_UPDATED 0x0022
+struct mgmt_ev_local_oob_data_updated {
+       uint8_t  type;
+       uint16_t eir_len;
+       uint8_t  eir[0];
+} __packed;
+
+#define MGMT_EV_ADVERTISING_ADDED      0x0023
+struct mgmt_ev_advertising_added {
+       uint8_t instance;
+} __packed;
+
+#define MGMT_EV_ADVERTISING_REMOVED    0x0024
+struct mgmt_ev_advertising_removed {
+       uint8_t instance;
+} __packed;
+
 static const char *mgmt_op[] = {
        "<0x0000>",
        "Read Version",
@@ -649,7 +736,7 @@ static const char *mgmt_op[] = {
        "Set Powered",
        "Set Discoverable",
        "Set Connectable",
-       "Set Fast Connectable",         /* 0x0008 */
+       "Set Fast Connectable",                 /* 0x0008 */
        "Set Bondable",
        "Set Link Security",
        "Set Secure Simple Pairing",
@@ -657,7 +744,7 @@ static const char *mgmt_op[] = {
        "Set Low Energy",
        "Set Dev Class",
        "Set Local Name",
-       "Add UUID",                     /* 0x0010 */
+       "Add UUID",                                     /* 0x0010 */
        "Remove UUID",
        "Load Link Keys",
        "Load Long Term Keys",
@@ -665,7 +752,7 @@ static const char *mgmt_op[] = {
        "Get Connections",
        "PIN Code Reply",
        "PIN Code Neg Reply",
-       "Set IO Capability",            /* 0x0018 */
+       "Set IO Capability",                            /* 0x0018 */
        "Pair Device",
        "Cancel Pair Device",
        "Unpair Device",
@@ -673,7 +760,7 @@ static const char *mgmt_op[] = {
        "User Confirm Neg Reply",
        "User Passkey Reply",
        "User Passkey Neg Reply",
-       "Read Local OOB Data",          /* 0x0020 */
+       "Read Local OOB Data",                          /* 0x0020 */
        "Add Remote OOB Data",
        "Remove Remove OOB Data",
        "Start Discovery",
@@ -681,7 +768,7 @@ static const char *mgmt_op[] = {
        "Confirm Name",
        "Block Device",
        "Unblock Device",
-       "Set Device ID",
+       "Set Device ID",                                /* 0x0028 */
        "Set Advertising",
        "Set BR/EDR",
        "Set Static Address",
@@ -689,7 +776,7 @@ static const char *mgmt_op[] = {
        "Set Secure Connections",
        "Set Debug Keys",
        "Set Privacy",
-       "Load Identity Resolving Keys",
+       "Load Identity Resolving Keys",                 /* 0x0030 */
        "Get Connection Information",
        "Get Clock Information",
        "Add Device",
@@ -697,9 +784,14 @@ static const char *mgmt_op[] = {
        "Load Connection Parameters",
        "Read Unconfigured Index List",
        "Read Controller Configuration Information",
-       "Set External Configuration",
+       "Set External Configuration",                   /* 0x0038 */
        "Set Public Address",
        "Start Service Discovery",
+       "Read Local Out Of Band Extended Data",
+       "Read Extended Controller Index List",
+       "Read Advertising Features",
+       "Add Advertising",
+       "Remove Advertising",
 };
 
 static const char *mgmt_ev[] = {
@@ -735,6 +827,11 @@ static const char *mgmt_ev[] = {
        "Unconfigured Index Added",
        "Unconfigured Index Removed",
        "New Configuration Options",
+       "Extended Index Added",
+       "Extended Index Removed",
+       "Local Out Of Band Extended Data Updated",
+       "Advertising Added",
+       "Advertising Removed",
 };
 
 static const char *mgmt_status[] = {
@@ -757,6 +854,8 @@ static const char *mgmt_status[] = {
        "Cancelled",
        "Invalid Index",
        "Blocked through rfkill",
+       "Already Paired",
+       "Permission Denied",
 };
 
 #ifdef __TIZEN_PATCH__
@@ -893,6 +992,51 @@ struct mgmt_rp_get_adv_tx_power {
        int8_t adv_tx_power;
 } __packed;
 
+#define MGMT_OP_ENABLE_6LOWPAN         (TIZEN_OP_CODE_BASE + 0x12)
+struct mgmt_cp_enable_6lowpan {
+       uint8_t enable_6lowpan;
+} __packed;
+
+#define MGMT_OP_CONNECT_6LOWPAN        (TIZEN_OP_CODE_BASE + 0x13)
+struct mgmt_cp_connect_6lowpan {
+       struct mgmt_addr_info addr;
+} __packed;
+
+#define MGMT_OP_DISCONNECT_6LOWPAN     (TIZEN_OP_CODE_BASE + 0x14)
+struct mgmt_cp_disconnect_6lowpan {
+       struct mgmt_addr_info addr;
+} __packed;
+
+#define MGMT_OP_LE_READ_MAXIMUM_DATA_LENGTH    (TIZEN_OP_CODE_BASE + 0x15)
+struct mgmt_rp_le_read_maximum_data_length {
+       uint8_t status;
+       uint16_t max_tx_octets;
+       uint16_t max_tx_time;
+       uint16_t max_rx_octets;
+       uint16_t max_rx_time;
+} __packed;
+
+#define MGMT_OP_LE_WRITE_HOST_SUGGESTED_DATA_LENGTH    (TIZEN_OP_CODE_BASE + 0x16)
+struct mgmt_cp_le_write_host_suggested_data_length {
+       uint16_t def_tx_octets;
+       uint16_t def_tx_time;
+} __packed;
+
+#define MGMT_OP_LE_READ_HOST_SUGGESTED_DATA_LENGTH     (TIZEN_OP_CODE_BASE + 0x17)
+struct mgmt_rp_le_read_host_suggested_data_length {
+       uint8_t status;
+       uint16_t def_tx_octets;
+       uint16_t def_tx_time;
+} __packed;
+
+#define MGMT_OP_LE_SET_DATA_LENGTH     (TIZEN_OP_CODE_BASE + 0x18)
+struct mgmt_cp_le_set_data_length {
+       bdaddr_t bdaddr;
+       uint16_t max_tx_octets;
+       uint16_t max_tx_time;
+} __packed;
+#define MGMT_LE_SET_DATA_LENGTH_SIZE    10
+
 /*  Currently there is no support in kernel for below MGMT cmd opcodes. */
 #if 0 // Not defined in kernel
 #define MGMT_OP_READ_RSSI                      (TIZEN_OP_CODE_BASE + 0x11)
@@ -1018,6 +1162,22 @@ struct mgmt_ev_vendor_specific_multi_adv_state_changed {
        int16_t connection_handle;
 } __packed;
 
+#define MGMT_EV_6LOWPAN_CONN_STATE_CHANGED             (TIZEN_EV_BASE + 0x0c)
+struct mgmt_ev_6lowpan_conn_state_changed {
+       struct  mgmt_addr_info addr;
+       uint8_t connected;
+} __packed;
+
+
+#define MGMT_EV_LE_DATA_LENGTH_CHANGED         (TIZEN_EV_BASE + 0x0d)
+struct mgmt_ev_le_data_length_changed {
+       struct  mgmt_addr_info addr;
+       int16_t max_tx_octets;
+       int16_t max_tx_time;
+       int16_t max_rx_octets;
+       int16_t max_rx_time;
+} __packed;
+
 /*  Currently there is no support in kernel for below MGMT events. */
 #if 0 // Not defined in kernel
 #define MGMT_EV_NEW_LOCAL_IRK                  (TIZEN_EV_BASE + 0x0b)
@@ -1044,7 +1204,9 @@ static const char *mgmt_tizen_op[] = {
        "Set Manufacturer Data",
        "LE Set Scan Parameters",
        "Set Voice Setting",
-       "Get Adv Tx Power"
+       "Get Adv Tx Power",
+       "Connect BT 6LOWPAN",
+       "Disconnect BT 6LOWPAN"
 };
 
 static const char *mgmt_tizen_ev[] = {
@@ -1060,6 +1222,7 @@ static const char *mgmt_tizen_ev[] = {
        "LE Connection Update Failed",
        "LE Device Found",
        "Multi Adv State Change",
+       "BT 6LOWPAN state Change"
 };
 #endif /* End of __TIZEN_PATCH__ */
 
index 396558c..98e9627 100644 (file)
@@ -130,6 +130,9 @@ extern "C" {
 #define GATT_CHARAC_SOFTWARE_REVISION_STRING           0x2A28
 #define GATT_CHARAC_MANUFACTURER_NAME_STRING           0x2A29
 #define GATT_CHARAC_PNP_ID                             0x2A50
+#ifdef __TIZEN_PATCH__
+#define GATT_CHARAC_CENTRAL_RPA_RESOLUTION             0x2AA6
+#endif
 
 /* GATT Characteristic Descriptors */
 #define GATT_CHARAC_EXT_PROPER_UUID                    0x2900
@@ -142,6 +145,11 @@ extern "C" {
 #define GATT_EXTERNAL_REPORT_REFERENCE                 0x2907
 #define GATT_REPORT_REFERENCE                          0x2908
 
+#ifdef __TIZEN_PATCH__
+/* GATT Service UUIDs : Defined  by SIG */
+#define GATT_IPSP_UUID         0x1820
+#endif
+
 typedef struct {
        enum {
                BT_UUID_UNSPEC = 0,
index a32335a..35005ff 100644 (file)
@@ -66,7 +66,16 @@ static uint32_t btsnoop_type = 0;
 static int btsnoop_fd = -1;
 static uint16_t btsnoop_index = 0xffff;
 
+#ifdef __TIZEN_PATCH__
+static char *btsnoop_path = NULL;
+static int16_t btsnoop_rotate = -1;
+static ssize_t btsnoop_size = -1;
+
+void btsnoop_create(const char *path, uint32_t type,
+               int16_t rotate_count, ssize_t file_size)
+#else
 void btsnoop_create(const char *path, uint32_t type)
+#endif
 {
        struct btsnoop_hdr hdr;
        ssize_t written;
@@ -91,8 +100,103 @@ void btsnoop_create(const char *path, uint32_t type)
                btsnoop_fd = -1;
                return;
        }
+
+#ifdef __TIZEN_PATCH__
+       if (rotate_count > 0 && file_size > 0) {
+               btsnoop_path = strdup(path);
+               btsnoop_rotate = rotate_count;
+               btsnoop_size = file_size;
+       }
+#endif
+}
+
+#ifdef __TIZEN_PATCH__
+static void btsnoop_create_2(void)
+{
+       struct btsnoop_hdr hdr;
+       ssize_t written;
+
+       if (btsnoop_fd >= 0)
+               close(btsnoop_fd);
+
+       btsnoop_fd = open(btsnoop_path,
+                       O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC,
+                       S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+       if (btsnoop_fd < 0)
+               goto fail;
+
+       memcpy(hdr.id, btsnoop_id, sizeof(btsnoop_id));
+       hdr.version = htobe32(btsnoop_version);
+       hdr.type = htobe32(btsnoop_type);
+
+       written = write(btsnoop_fd, &hdr, BTSNOOP_HDR_SIZE);
+       if (written < 0) {
+               close(btsnoop_fd);
+               btsnoop_fd = -1;
+               goto fail;
+       }
+
+       return;
+
+fail:
+       free(btsnoop_path);
+       btsnoop_rotate = -1;
+       btsnoop_size = -1;
+       btsnoop_index = 0xffff;
+
+       return;
 }
 
+static void btsnoop_rotate_files(void)
+{
+       char *filename = NULL;
+       char *new_filename = NULL;
+       int i;
+       int postfix_width = 0;
+       int err;
+
+       if (btsnoop_rotate <= 1)
+               return;
+
+       for (i = btsnoop_rotate / 10; i; i /= 10)
+               postfix_width++;
+
+       for (i = btsnoop_rotate - 2; i >= 0; i--) {
+               if (i == 0) {
+                       filename = strdup(btsnoop_path);
+                       err = (filename == NULL) ? -1 : 0;
+               } else {
+                       err = asprintf(&filename, "%s.%0*d",
+                                       btsnoop_path, postfix_width, i);
+               }
+
+               if (err < 0 || access(filename, F_OK) < 0)
+                       goto done;
+
+               err = asprintf(&new_filename, "%s.%0*d",
+                               btsnoop_path, postfix_width, i + 1);
+               if (err < 0)
+                       goto done;
+
+               err = rename(filename, new_filename)
+
+done:
+               if (new_filename) {
+                       free(new_filename);
+                       new_filename = NULL;
+               }
+
+               if (filename) {
+                       free(filename);
+                       filename = NULL;
+               }
+
+               if (err < 0)
+                       break;
+       }
+}
+#endif
+
 void btsnoop_write(struct timeval *tv, uint32_t flags,
                                        const void *data, uint16_t size)
 {
@@ -108,6 +212,17 @@ void btsnoop_write(struct timeval *tv, uint32_t flags,
        pkt.drops = htobe32(0);
        pkt.ts    = htobe64(ts + 0x00E03AB44A676000ll);
 
+#ifdef __TIZEN_PATCH__
+       if ((btsnoop_rotate > 0 && btsnoop_size > 0) &&
+                       lseek(btsnoop_fd, 0x00, SEEK_CUR) +
+                       BTSNOOP_PKT_SIZE + size > btsnoop_size) {
+               btsnoop_rotate_files();
+               btsnoop_create_2();
+               if (btsnoop_fd < 0)
+                       return;
+       }
+#endif
+
        written = write(btsnoop_fd, &pkt, BTSNOOP_PKT_SIZE);
        if (written < 0)
                return;
@@ -423,6 +538,15 @@ void btsnoop_close(void)
        if (btsnoop_fd < 0)
                return;
 
+#ifdef __TIZEN_PATCH__
+       if (btsnoop_path) {
+               free(btsnoop_path);
+               btsnoop_path = NULL;
+       }
+       btsnoop_rotate = -1;
+       btsnoop_size = -1;
+#endif
+
        close(btsnoop_fd);
        btsnoop_fd = -1;
 
index be4e2ed..10f76f2 100644 (file)
@@ -48,7 +48,12 @@ struct btsnoop_opcode_new_index {
        char     name[8];
 } __attribute__((packed));
 
+#ifdef __TIZEN_PATCH__
+void btsnoop_create(const char *path, uint32_t type,
+               int16_t rotate_count, ssize_t file_size);
+#else
 void btsnoop_create(const char *path, uint32_t type);
+#endif
 void btsnoop_write(struct timeval *tv, uint32_t flags,
                                        const void *data, uint16_t size);
 void btsnoop_write_hci(struct timeval *tv, uint16_t index, uint16_t opcode,
index 44cc1da..e88a6e3 100644 (file)
@@ -97,6 +97,40 @@ static void mgmt_unconf_index_removed(uint16_t len, const void *buf)
        packet_hexdump(buf, len);
 }
 
+static void mgmt_ext_index_added(uint16_t len, const void *buf)
+{
+       const struct mgmt_ev_ext_index_added *ev = buf;
+
+       if (len < sizeof(*ev)) {
+               printf("* Malformed Extended Index Added control\n");
+               return;
+       }
+
+       printf("@ Extended Index Added: %u (%u)\n", ev->type, ev->bus);
+
+       buf += sizeof(*ev);
+       len -= sizeof(*ev);
+
+       packet_hexdump(buf, len);
+}
+
+static void mgmt_ext_index_removed(uint16_t len, const void *buf)
+{
+       const struct mgmt_ev_ext_index_removed *ev = buf;
+
+       if (len < sizeof(*ev)) {
+               printf("* Malformed Extended Index Removed control\n");
+               return;
+       }
+
+       printf("@ Extended Index Removed: %u (%u)\n", ev->type, ev->bus);
+
+       buf += sizeof(*ev);
+       len -= sizeof(*ev);
+
+       packet_hexdump(buf, len);
+}
+
 static void mgmt_controller_error(uint16_t len, const void *buf)
 {
        const struct mgmt_ev_controller_error *ev = buf;
@@ -197,9 +231,9 @@ static void mgmt_class_of_dev_changed(uint16_t len, const void *buf)
        }
 
        printf("@ Class of Device Changed: 0x%2.2x%2.2x%2.2x\n",
-                                               ev->class_of_dev[2],
-                                               ev->class_of_dev[1],
-                                               ev->class_of_dev[0]);
+                                               ev->dev_class[2],
+                                               ev->dev_class[1],
+                                               ev->dev_class[0]);
 
        buf += sizeof(*ev);
        len -= sizeof(*ev);
@@ -704,6 +738,40 @@ static void mgmt_new_conn_param(uint16_t len, const void *buf)
        packet_hexdump(buf, len);
 }
 
+static void mgmt_advertising_added(uint16_t len, const void *buf)
+{
+       const struct mgmt_ev_advertising_added *ev = buf;
+
+       if (len < sizeof(*ev)) {
+               printf("* Malformed Advertising Added control\n");
+               return;
+       }
+
+       printf("@ Advertising Added: %u\n", ev->instance);
+
+       buf += sizeof(*ev);
+       len -= sizeof(*ev);
+
+       packet_hexdump(buf, len);
+}
+
+static void mgmt_advertising_removed(uint16_t len, const void *buf)
+{
+       const struct mgmt_ev_advertising_removed *ev = buf;
+
+       if (len < sizeof(*ev)) {
+               printf("* Malformed Advertising Removed control\n");
+               return;
+       }
+
+       printf("@ Advertising Removed: %u\n", ev->instance);
+
+       buf += sizeof(*ev);
+       len -= sizeof(*ev);
+
+       packet_hexdump(buf, len);
+}
+
 void control_message(uint16_t opcode, const void *data, uint16_t size)
 {
        switch (opcode) {
@@ -794,6 +862,18 @@ void control_message(uint16_t opcode, const void *data, uint16_t size)
        case MGMT_EV_NEW_CONFIG_OPTIONS:
                mgmt_new_config_options(size, data);
                break;
+       case MGMT_EV_EXT_INDEX_ADDED:
+               mgmt_ext_index_added(size, data);
+               break;
+       case MGMT_EV_EXT_INDEX_REMOVED:
+               mgmt_ext_index_removed(size, data);
+               break;
+       case MGMT_EV_ADVERTISING_ADDED:
+               mgmt_advertising_added(size, data);
+               break;
+       case MGMT_EV_ADVERTISING_REMOVED:
+               mgmt_advertising_removed(size, data);
+               break;
        default:
                printf("* Unknown control (code %d len %d)\n", opcode, size);
                packet_hexdump(data, size);
@@ -1044,9 +1124,18 @@ void control_server(const char *path)
        server_fd = fd;
 }
 
+#ifdef __TIZEN_PATCH__
+bool control_writer(const char *path, int16_t rotate_count, ssize_t file_size)
+#else
 bool control_writer(const char *path)
+#endif
 {
+#ifdef __TIZEN_PATCH__
+       btsnoop_file = btsnoop_create(path, BTSNOOP_TYPE_MONITOR,
+                       rotate_count, file_size);
+#else
        btsnoop_file = btsnoop_create(path, BTSNOOP_TYPE_MONITOR);
+#endif
 
        return !!btsnoop_file;
 }
index 28f16db..87876d0 100644 (file)
 
 #include <stdint.h>
 
+#ifdef __TIZEN_PATCH__
+bool control_writer(const char *path, int16_t rotate_count, ssize_t file_size);
+#else
 bool control_writer(const char *path);
+#endif
 void control_reader(const char *path);
 void control_server(const char *path);
 int control_tracing(void);
index de48db5..90ecf35 100644 (file)
@@ -66,6 +66,10 @@ static void usage(void)
                "\t-T, --date             Show time and date information\n"
                "\t-S, --sco              Dump SCO traffic\n"
                "\t-E, --ellisys [ip]     Send Ellisys HCI Injection\n"
+#ifdef __TIZEN_PATCH__
+               "\t-C, --count <num>      Save traces by <num> rotation\n"
+               "\t-W, --size <num>       Save traces at most <num> size\n"
+#endif
                "\t-h, --help             Show help options\n");
 }
 
@@ -79,6 +83,10 @@ static const struct option main_options[] = {
        { "date",    no_argument,       NULL, 'T' },
        { "sco",     no_argument,       NULL, 'S' },
        { "ellisys", required_argument, NULL, 'E' },
+#ifdef __TIZEN_PATCH__
+       { "count",   required_argument, NULL, 'C' },
+       { "size",    required_argument, NULL, 'W' },
+#endif
        { "todo",    no_argument,       NULL, '#' },
        { "version", no_argument,       NULL, 'v' },
        { "help",    no_argument,       NULL, 'h' },
@@ -93,6 +101,10 @@ int main(int argc, char *argv[])
        const char *analyze_path = NULL;
        const char *ellisys_server = NULL;
        unsigned short ellisys_port = 0;
+#ifdef __TIZEN_PATCH__
+       int16_t rotate_count = -1;
+       ssize_t file_size = -1;
+#endif
        const char *str;
        int exit_status;
        sigset_t mask;
@@ -104,8 +116,13 @@ int main(int argc, char *argv[])
        for (;;) {
                int opt;
 
+#ifdef __TIZEN_PATCH__
+               opt = getopt_long(argc, argv, "r:w:a:s:i:tTSE:C:W:vh",
+                                               main_options, NULL);
+#else
                opt = getopt_long(argc, argv, "r:w:a:s:i:tTSE:vh",
                                                main_options, NULL);
+#endif
                if (opt < 0)
                        break;
 
@@ -149,6 +166,14 @@ int main(int argc, char *argv[])
                        ellisys_server = optarg;
                        ellisys_port = 24352;
                        break;
+#ifdef __TIZEN_PATCH__
+               case 'C':
+                       rotate_count = atoi(optarg);
+                       break;
+               case 'W':
+                       file_size = atoll(optarg);
+                       break;
+#endif
                case '#':
                        packet_todo();
                        lmp_todo();
@@ -199,10 +224,18 @@ int main(int argc, char *argv[])
                return EXIT_SUCCESS;
        }
 
+#ifdef __TIZEN_PATCH__
+       if (writer_path && !control_writer(writer_path,
+                               rotate_count, file_size)) {
+               printf("Failed to open '%s'\n", writer_path);
+               return EXIT_FAILURE;
+       }
+#else
        if (writer_path && !control_writer(writer_path)) {
                printf("Failed to open '%s'\n", writer_path);
                return EXIT_FAILURE;
        }
+#endif
 
        if (ellisys_server)
                ellisys_enable(ellisys_server, ellisys_port);
index 8db485f..b2267a6 100644 (file)
@@ -5872,7 +5872,7 @@ static void le_set_adv_parameters_cmd(const void *data, uint8_t size)
                str = "Scannable undirected - ADV_SCAN_IND";
                break;
        case 0x03:
-               str = "Non connectable undirect - ADV_NONCONN_IND";
+               str = "Non connectable undirected - ADV_NONCONN_IND";
                break;
        case 0x04:
                str = "Connectable directed - ADV_DIRECT_IND (low duty cycle)";
index 4952225..b254cd3 100644 (file)
@@ -30,6 +30,8 @@
 #include <string.h>
 
 #include "log.h"
+#include "gobex/gobex.h"
+#include "gobex/gobex-apparam.h"
 
 #include "transfer.h"
 #include "session.h"
@@ -135,7 +137,8 @@ static DBusMessage *send_event(DBusConnection *connection,
 {
        struct mns_data *mns = user_data;
        struct obc_transfer *transfer;
-       struct sendevent_apparam apparam;
+       guint8  masinstanceid;
+       GObexApparam *apparam;
        gchar *event_type;
        gchar *folder;
        gchar *old_folder;
@@ -170,12 +173,12 @@ static DBusMessage *send_event(DBusConnection *connection,
        if (transfer == NULL)
                goto fail;
 
-       apparam.masinstanceid_tag = MAP_AP_MASINSTANCEID;
-       apparam.masinstanceid_len = 1;
        /* Obexd currently supports single SDP for MAS */
-       apparam.masinstanceid = 0;
+       masinstanceid = 0;
+       apparam = g_obex_apparam_set_uint8(NULL, MAP_AP_MASINSTANCEID,
+                                                               masinstanceid);
 
-       obc_transfer_set_apparam(transfer, &apparam);
+       obc_transfer_set_apparam(transfer, apparam);
 
        if (obc_session_queue(mns->session, transfer, NULL, NULL, &err))
                return dbus_message_new_method_return(message);
index 4b868f0..c803437 100644 (file)
@@ -218,7 +218,11 @@ static char *build_phonebook_path(const char *location, const char *item)
                internal = TRUE;
        } else if (!g_ascii_strncasecmp(location, "sim", 3)) {
                if (strlen(location) == 3)
+#ifdef __TIZEN_PATCH__
+                       tmp = g_strdup("SIM1");
+#else
                        tmp = g_strdup("sim1");
+#endif
                else
                        tmp = g_ascii_strup(location, 4);
 
index 7036497..8d0531a 100644 (file)
@@ -178,9 +178,14 @@ static void mas_disconnect(struct obex_session *os, void *user_data)
        DBG("");
 
        manager_unregister_session(os);
-       messages_disconnect(mas->backend_data);
+#ifdef __TIZEN_PATCH__
+       if (mas)
+#endif
+       {
+               messages_disconnect(mas->backend_data);
 
-       mas_clean(mas);
+               mas_clean(mas);
+       }
 }
 
 static int mas_get(struct obex_session *os, void *user_data)
index 68417a0..7892664 100644 (file)
@@ -828,18 +828,17 @@ static void *vobject_list_open(const char *name, int oflag, mode_t mode,
        int ret;
        void *request;
 
+       if (name == NULL) {
+               ret = -EBADR;
+               goto fail;
+       }
+
        DBG("name %s context %p valid %d", name, context, pbap->cache.valid);
 
        if (oflag != O_RDONLY) {
                ret = -EPERM;
                goto fail;
        }
-
-       if (name == NULL) {
-               ret = -EBADR;
-               goto fail;
-       }
-
 #ifdef __TIZEN_PATCH__
        if (strcmp(name, "/telecom/mch") == 0)
                pbap->params->required_missedcall_call_header = TRUE;
index 788bffc..9083246 100644 (file)
@@ -773,7 +773,11 @@ int obex_put_stream_start(struct obex_session *os, const char *filename)
        int err;
 
        os->object = os->driver->open(filename, O_WRONLY | O_CREAT | O_TRUNC,
+#ifdef __TIZEN_PATCH__
+                                       0644, os->service_data,
+#else
                                        0600, os->service_data,
+#endif
                                        os->size != OBJECT_SIZE_UNKNOWN ?
                                        (size_t *) &os->size : NULL, &err);
        if (os->object == NULL) {
old mode 100644 (file)
new mode 100755 (executable)
index a9c4335..a19a3de
@@ -1,7 +1,7 @@
 Name:       bluez
 Summary:    Bluetooth utilities
-Version:    5.28
-Release:    1
+Version:    5.30
+Release:    2
 #VCS:        framework/connectivity/bluez#bluez_4.101-slp2+22-132-g5d15421a5bd7101225aecd7c25b592b9a9ca218b
 Group:      Applications/System
 License:    GPL-2.0+ and LGPL-2.1+ and Apache-2.0
@@ -82,19 +82,24 @@ bluez-test contains test utilities for BlueZ testing.
 %if "%{?tizen_profile_name}" == "wearable"
 export CFLAGS="${CFLAGS} -D__TIZEN_PATCH__ -D__BROADCOM_PATCH__ -D__BT_SCMST_FEATURE__ -DSUPPORT_SMS_ONLY -D__BROADCOM_QOS_PATCH__ -DTIZEN_WEARABLE"
 %else
-%if "%{?tizen_profile_name}" == "mobile"
+%if "%{?tizen_profile_name}" == "mobile" || "%{?tizen_profile_name}" == "tv"
 export CFLAGS="${CFLAGS} -D__TIZEN_PATCH__ -DSUPPORT_SMS_ONLY -DBLUEZ5_27_GATT_CLIENT"
+%if "%{?tizen_target_name}" == "Z300H" || "%{?tizen_target_name}" == "TM1"
+export CFLAGS="${CFLAGS} -D__SPRD_QOS_PATCH__"
+%else
 export CFLAGS="${CFLAGS} -D__BROADCOM_PATCH__"
 %endif
 %endif
+%endif
 
 export LDFLAGS=" -lncurses -Wl,--as-needed "
-export CFLAGS+=" -DPBAP_SIM_ENABLE"
+export CFLAGS+=" -DPBAP_SIM_ENABLE -DSUPPORT_AVRCP_TARGET"
 %reconfigure --disable-static \
                        --sysconfdir=%{_sysconfdir} \
                        --localstatedir=%{_localstatedir} \
                        --with-systemdsystemunitdir=%{_libdir}/systemd/system \
                        --with-systemduserunitdir=%{_libdir}/systemd/user \
+                       --libexecdir=%{_libdir} \
                        --enable-debug \
                        --enable-pie \
                        --enable-serial \
@@ -120,7 +125,7 @@ export CFLAGS+=" -DPBAP_SIM_ENABLE"
 %endif
                        --enable-experimental \
                        --enable-autopair=no \
-%if "%{?tizen_profile_name}" == "mobile"
+%if "%{?tizen_profile_name}" == "mobile" || "%{?tizen_profile_name}" == "tv"
                        --enable-network \
                        --enable-hid=yes \
 %else
@@ -133,11 +138,16 @@ make %{?jobs:-j%jobs}
 %install
 rm -rf %{buildroot}
 %make_install
+# fixed to support new rpm and build environment
+install -d -m 0755 %{buildroot}/var/lib/bluetooth
+install -d -m 0755 %{buildroot}%{_libdir}/bluetooth/plugins
+install -d -m 0755 %{buildroot}%{_libdir}/bluetooth/obex/plugins
+install -d -m 0755 %{buildroot}%{_libdir}/obex/plugins
 
 %if "%{?tizen_profile_name}" == "wearable"
 install -D -m 0644 src/main_w.conf %{buildroot}%{_sysconfdir}/bluetooth/main.conf
 %else
-%if "%{?tizen_profile_name}" == "mobile"
+%if "%{?tizen_profile_name}" == "mobile" || "%{?tizen_profile_name}" == "tv"
 install -D -m 0644 src/main_m.conf %{buildroot}%{_sysconfdir}/bluetooth/main.conf
 %endif
 %endif
@@ -152,7 +162,11 @@ install -D -m 0644 COPYING %{buildroot}%{_datadir}/license/libbluetooth-devel
 install -D -m 0755 %SOURCE101 %{buildroot}%{_bindir}/obex-root-setup
 install -D -m 0755 %SOURCE102 %{buildroot}%{_sysconfdir}/obex/root-setup.d/000_create-symlinks
 
-#ln -sf bluetooth.service %{buildroot}%{_libdir}/systemd/system/dbus-org.bluez.service
+install -D -m 0644 bluez.rule %{buildroot}%{_sysconfdir}/smack/accesses.d/bluez.rule
+
+%if "%{?tizen_profile_name}" == "common"
+ln -sf bluetooth.service %{buildroot}%{_libdir}/systemd/system/dbus-org.bluez.service
+%endif
 
 %post -n libbluetooth3 -p /sbin/ldconfig
 
@@ -167,6 +181,7 @@ install -D -m 0755 %SOURCE102 %{buildroot}%{_sysconfdir}/obex/root-setup.d/000_c
 %{_sysconfdir}/bluetooth/network.conf
 #%{_sysconfdir}/bluetooth/rfcomm.conf
 %{_sysconfdir}/dbus-1/system.d/bluetooth.conf
+%{_sysconfdir}/smack/accesses.d/bluez.rule
 %{_datadir}/man/*/*
 %{_libexecdir}/bluetooth/bluetoothd
 %{_bindir}/hciconfig
@@ -180,15 +195,22 @@ install -D -m 0755 %SOURCE102 %{buildroot}%{_sysconfdir}/obex/root-setup.d/000_c
 %{_bindir}/mpris-proxy
 %{_bindir}/rfcomm
 %{_bindir}/hcitool
+%{_bindir}/btmon
+%{_bindir}/btsnoop
 %dir %{_libdir}/bluetooth/plugins
-%exclude %{_libdir}/systemd/system/bluetooth.service
-#%exclude %{_libdir}/systemd/system/dbus-org.bluez.service
 %dir %{_localstatedir}/lib/bluetooth
 %dir %{_libexecdir}/bluetooth
-%exclude %{_datadir}/dbus-1/system-services/org.bluez.service
 %{_datadir}/license/bluez
 %{_libdir}/udev/hid2hci
 %{_libdir}/udev/rules.d/97-hid2hci.rules
+%if "%{?tizen_profile_name}" == "common"
+%{_libdir}/systemd/system/bluetooth.service
+%{_libdir}/systemd/system/dbus-org.bluez.service
+%{_datadir}/dbus-1/system-services/org.bluez.service
+%else
+%exclude %{_libdir}/systemd/system/bluetooth.service
+%exclude %{_datadir}/dbus-1/system-services/org.bluez.service
+%endif
 
 %files -n libbluetooth3
 %defattr(-,root,root,-)
@@ -220,7 +242,6 @@ install -D -m 0755 %SOURCE102 %{buildroot}%{_sysconfdir}/obex/root-setup.d/000_c
 %{_bindir}/rctest
 %{_bindir}/bccmd
 %{_bindir}/bluetoothctl
-%{_bindir}/btmon
 %{_bindir}/hcidump
 %{_bindir}/bluemoon
 %{_bindir}/hex2hcd
index bc9beba..978a2d6 100644 (file)
 #endif
 #define SOURCE_RETRY_TIMEOUT 2
 #define SINK_RETRY_TIMEOUT SOURCE_RETRY_TIMEOUT
+#define CT_RETRY_TIMEOUT 1
+#define TG_RETRY_TIMEOUT CT_RETRY_TIMEOUT
 #define SOURCE_RETRIES 1
 #define SINK_RETRIES SOURCE_RETRIES
+#define CT_RETRIES 1
+#define TG_RETRIES CT_RETRIES
 
 /* Tracking of remote services to be auto-reconnected upon link loss */
 
@@ -87,7 +91,9 @@ struct policy_data {
        guint sink_timer;
        uint8_t sink_retries;
        guint ct_timer;
+       uint8_t ct_retries;
        guint tg_timer;
+       uint8_t tg_retries;
 };
 
 static void policy_connect(struct policy_data *data,
@@ -116,6 +122,7 @@ static gboolean policy_connect_ct(gpointer user_data)
        struct btd_service *service;
 
        data->ct_timer = 0;
+       data->ct_retries++;
 
        service = btd_device_get_service(data->dev, AVRCP_REMOTE_UUID);
        if (service != NULL)
@@ -124,13 +131,13 @@ static gboolean policy_connect_ct(gpointer user_data)
        return FALSE;
 }
 
-static void policy_set_ct_timer(struct policy_data *data)
+static void policy_set_ct_timer(struct policy_data *data, int timeout)
 {
        if (data->ct_timer > 0)
                g_source_remove(data->ct_timer);
 
-       data->ct_timer = g_timeout_add_seconds(CONTROL_CONNECT_TIMEOUT,
-                                               policy_connect_ct, data);
+       data->ct_timer = g_timeout_add_seconds(timeout, policy_connect_ct,
+                                                                       data);
 }
 
 static struct policy_data *find_data(struct btd_device *dev)
@@ -267,13 +274,13 @@ static void sink_cb(struct btd_service *service, btd_service_state_t old_state,
                         * avrcp connection immediately; irrespective of local
                         * or remote initiated a2dp connection
                         */
-                       policy_set_ct_timer(data);
+                       policy_set_ct_timer(data, CONTROL_CONNECT_TIMEOUT);
 #else
                        policy_connect(data, controller);
 #endif
                else if (btd_service_get_state(controller) !=
                                                BTD_SERVICE_STATE_CONNECTED)
-                       policy_set_ct_timer(data);
+                       policy_set_ct_timer(data, CONTROL_CONNECT_TIMEOUT);
                break;
        case BTD_SERVICE_STATE_DISCONNECTING:
                break;
@@ -286,6 +293,7 @@ static gboolean policy_connect_tg(gpointer user_data)
        struct btd_service *service;
 
        data->tg_timer = 0;
+       data->tg_retries++;
 
        service = btd_device_get_service(data->dev, AVRCP_TARGET_UUID);
        if (service != NULL)
@@ -294,18 +302,18 @@ static gboolean policy_connect_tg(gpointer user_data)
        return FALSE;
 }
 
-static void policy_set_tg_timer(struct policy_data *data)
+static void policy_set_tg_timer(struct policy_data *data, int timeout)
 {
        if (data->tg_timer > 0)
                g_source_remove(data->tg_timer);
 
+
 #ifdef __TIZEN_PATCH__
        data->tg_timer = g_timeout_add_seconds(TARGET_CONNECT_TIMEOUT,
                                                        policy_connect_tg,
                                                        data);
 #else
-       data->tg_timer = g_timeout_add_seconds(CONTROL_CONNECT_TIMEOUT,
-                                                       policy_connect_tg,
+       data->tg_timer = g_timeout_add_seconds(timeout, policy_connect_tg,
                                                        data);
 #endif
 }
@@ -394,7 +402,7 @@ static void source_cb(struct btd_service *service,
                        policy_connect(data, target);
                else if (btd_service_get_state(target) !=
                                                BTD_SERVICE_STATE_CONNECTED)
-                       policy_set_tg_timer(data);
+                       policy_set_tg_timer(data, CONTROL_CONNECT_TIMEOUT);
                break;
        case BTD_SERVICE_STATE_DISCONNECTING:
                break;
@@ -420,6 +428,23 @@ static void controller_cb(struct btd_service *service,
                }
                break;
        case BTD_SERVICE_STATE_DISCONNECTED:
+               if (old_state == BTD_SERVICE_STATE_CONNECTING) {
+                       int err = btd_service_get_error(service);
+
+                       if (err == -EAGAIN) {
+                               if (data->ct_retries < CT_RETRIES)
+                                       policy_set_ct_timer(data,
+                                                       CT_RETRY_TIMEOUT);
+                               else
+                                       data->ct_retries = 0;
+                               break;
+                       } else if (data->ct_timer > 0) {
+                               g_source_remove(data->ct_timer);
+                               data->ct_timer = 0;
+                       }
+               } else if (old_state == BTD_SERVICE_STATE_CONNECTED) {
+                       data->ct_retries = 0;
+               }
                break;
        case BTD_SERVICE_STATE_CONNECTING:
                break;
@@ -453,6 +478,23 @@ static void target_cb(struct btd_service *service,
                }
                break;
        case BTD_SERVICE_STATE_DISCONNECTED:
+               if (old_state == BTD_SERVICE_STATE_CONNECTING) {
+                       int err = btd_service_get_error(service);
+
+                       if (err == -EAGAIN) {
+                               if (data->tg_retries < TG_RETRIES)
+                                       policy_set_tg_timer(data,
+                                                       TG_RETRY_TIMEOUT);
+                               else
+                                       data->tg_retries = 0;
+                               break;
+                       } else if (data->tg_timer > 0) {
+                               g_source_remove(data->tg_timer);
+                               data->tg_timer = 0;
+                       }
+               } else if (old_state == BTD_SERVICE_STATE_CONNECTED) {
+                       data->tg_retries = 0;
+               }
                break;
        case BTD_SERVICE_STATE_CONNECTING:
                break;
index c93f5d4..fcc93bc 100644 (file)
@@ -302,7 +302,7 @@ static bool setup_device(int fd, int index, struct btd_adapter *adapter)
        btd_device_device_set_name(device, devices[index].name);
        btd_device_set_pnpid(device, devices[index].source, devices[index].vid,
                                devices[index].pid, devices[index].version);
-       btd_device_set_temporary(device, FALSE);
+       btd_device_set_temporary(device, false);
 
        return true;
 }
index 50efb93..ef81614 100644 (file)
@@ -375,13 +375,6 @@ static void stream_state_changed(struct avdtp_stream *stream,
                return;
        }
 
-#ifdef __TIZEN_PATCH__
-       if (new_state == AVDTP_STATE_STREAMING && sep->suspend_timer) {
-               g_source_remove(sep->suspend_timer);
-               sep->suspend_timer = 0;
-       }
-#endif
-
        if (new_state != AVDTP_STATE_IDLE)
                return;
 
@@ -405,7 +398,6 @@ static gboolean auto_config(gpointer data)
 {
        struct a2dp_setup *setup = data;
        struct btd_device *dev = NULL;
-
        struct btd_service *service;
 
        /* Check if configuration was aborted */
@@ -455,6 +447,41 @@ static void endpoint_setconf_cb(struct a2dp_setup *setup, gboolean ret)
        auto_config(setup);
 }
 
+static gboolean endpoint_match_codec_ind(struct avdtp *session,
+                               struct avdtp_media_codec_capability *codec,
+                               void *user_data)
+{
+       struct a2dp_sep *sep = user_data;
+       a2dp_vendor_codec_t *remote_codec;
+       a2dp_vendor_codec_t *local_codec;
+       uint8_t *capabilities;
+       size_t length;
+
+       if (codec->media_codec_type != A2DP_CODEC_VENDOR)
+               return TRUE;
+
+       if (sep->endpoint == NULL)
+               return FALSE;
+
+       length = sep->endpoint->get_capabilities(sep, &capabilities,
+                                                       sep->user_data);
+       if (length < sizeof(a2dp_vendor_codec_t))
+               return FALSE;
+
+       local_codec = (a2dp_vendor_codec_t *) capabilities;
+       remote_codec = (a2dp_vendor_codec_t *) codec->data;
+
+       if (remote_codec->vendor_id != local_codec->vendor_id)
+               return FALSE;
+
+       if (remote_codec->codec_id != local_codec->codec_id)
+               return FALSE;
+
+       DBG("vendor 0x%08x codec 0x%04x", btohl(remote_codec->vendor_id),
+                                               btohs(remote_codec->codec_id));
+       return TRUE;
+}
+
 static gboolean endpoint_setconf_ind(struct avdtp *session,
                                                struct avdtp_local_sep *sep,
                                                struct avdtp_stream *stream,
@@ -1122,6 +1149,7 @@ static struct avdtp_sep_cfm cfm = {
 };
 
 static struct avdtp_sep_ind endpoint_ind = {
+       .match_codec            = endpoint_match_codec_ind,
        .get_capability         = endpoint_getcap_ind,
        .set_configuration      = endpoint_setconf_ind,
        .get_configuration      = getconf_ind,
@@ -1331,6 +1359,13 @@ struct avdtp *a2dp_avdtp_get(struct btd_device *device)
                        return NULL;
        }
 
+#ifdef __TIZEN_PATCH__
+       if (chan->auth_id) {
+               DBG("auth is already going...");
+               return NULL;
+       }
+#endif
+
        if (chan->session)
                return avdtp_ref(chan->session);
 
@@ -1769,9 +1804,11 @@ static struct a2dp_sep *a2dp_find_sep(struct avdtp *session, GSList *list,
 
        for (; list; list = list->next) {
                struct a2dp_sep *sep = list->data;
+#ifdef __TIZEN_PATCH__
                struct avdtp_remote_sep *rsep;
                struct avdtp_media_codec_capability *cap;
                struct avdtp_service_capability *service;
+#endif
 
                /* Use sender's endpoint if available */
                if (sender) {
@@ -1784,7 +1821,7 @@ static struct a2dp_sep *a2dp_find_sep(struct avdtp *session, GSList *list,
                        if (g_strcmp0(sender, name) != 0)
                                continue;
                }
-
+#ifdef __TIZEN_PATCH__
                rsep = avdtp_find_remote_sep(session, sep->lsep);
                if (rsep == NULL)
                        continue;
@@ -1792,19 +1829,18 @@ static struct a2dp_sep *a2dp_find_sep(struct avdtp *session, GSList *list,
                service = avdtp_get_codec(rsep);
                cap = (struct avdtp_media_codec_capability *) service->data;
 
-#ifdef __TIZEN_PATCH__
                if (cap->media_codec_type != A2DP_CODEC_VENDOR) {
                        selected_sep = sep;
                        continue;
                }
 #else
-               if (cap->media_codec_type != A2DP_CODEC_VENDOR)
-                       return sep;
-#endif
-
                if (check_vendor_codec(sep, cap->data,
                                        service->length - sizeof(*cap)))
                        return sep;
+
+#endif
+               return sep;
+
        }
 
 #ifdef __TIZEN_PATCH__
index 197373a..34b0183 100644 (file)
@@ -580,7 +580,8 @@ static void avctp_disconnected(struct avctp *session)
        g_free(session);
 }
 
-static void avctp_set_state(struct avctp *session, avctp_state_t new_state)
+static void avctp_set_state(struct avctp *session, avctp_state_t new_state,
+                                                                       int err)
 {
        GSList *l;
        avctp_state_t old_state = session->state;
@@ -593,7 +594,8 @@ static void avctp_set_state(struct avctp *session, avctp_state_t new_state)
                if (cb->dev && cb->dev != session->device)
                        continue;
 
-               cb->cb(session->device, old_state, new_state, cb->user_data);
+               cb->cb(session->device, old_state, new_state, err,
+                                                               cb->user_data);
        }
 
        switch (new_state) {
@@ -947,7 +949,7 @@ send:
 
 failed:
        DBG("AVCTP Browsing: disconnected");
-       avctp_set_state(session, AVCTP_STATE_CONNECTED);
+       avctp_set_state(session, AVCTP_STATE_CONNECTED, 0);
 
        if (session->browsing) {
                avctp_channel_destroy(session->browsing);
@@ -1043,7 +1045,7 @@ done:
 
 failed:
        DBG("AVCTP session %p got disconnected", session);
-       avctp_set_state(session, AVCTP_STATE_DISCONNECTED);
+       avctp_set_state(session, AVCTP_STATE_DISCONNECTED, -EIO);
        return FALSE;
 }
 
@@ -1200,7 +1202,7 @@ static void avctp_connect_browsing_cb(GIOChannel *chan, GError *err,
                                G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
                                (GIOFunc) session_browsing_cb, session);
 
-       avctp_set_state(session, AVCTP_STATE_BROWSING_CONNECTED);
+       avctp_set_state(session, AVCTP_STATE_BROWSING_CONNECTED, 0);
 
        /* Process any request that was pending the connection to complete */
        if (browsing->process_id == 0 && !g_queue_is_empty(browsing->queue))
@@ -1209,7 +1211,7 @@ static void avctp_connect_browsing_cb(GIOChannel *chan, GError *err,
        return;
 
 fail:
-       avctp_set_state(session, AVCTP_STATE_CONNECTED);
+       avctp_set_state(session, AVCTP_STATE_CONNECTED, 0);
 
        if (session->browsing) {
                avctp_channel_destroy(session->browsing);
@@ -1225,7 +1227,7 @@ static void avctp_connect_cb(GIOChannel *chan, GError *err, gpointer data)
        GError *gerr = NULL;
 
        if (err) {
-               avctp_set_state(session, AVCTP_STATE_DISCONNECTED);
+               avctp_set_state(session, AVCTP_STATE_DISCONNECTED, -EIO);
                error("%s", err->message);
                return;
        }
@@ -1236,7 +1238,7 @@ static void avctp_connect_cb(GIOChannel *chan, GError *err, gpointer data)
                        BT_IO_OPT_IMTU, &omtu,
                        BT_IO_OPT_INVALID);
        if (gerr) {
-               avctp_set_state(session, AVCTP_STATE_DISCONNECTED);
+               avctp_set_state(session, AVCTP_STATE_DISCONNECTED, -EIO);
                error("%s", gerr->message);
                g_error_free(gerr);
                return;
@@ -1269,7 +1271,7 @@ static void avctp_connect_cb(GIOChannel *chan, GError *err, gpointer data)
 
        init_uinput(session);
 
-       avctp_set_state(session, AVCTP_STATE_CONNECTED);
+       avctp_set_state(session, AVCTP_STATE_CONNECTED, 0);
 }
 
 static void auth_cb(DBusError *derr, void *user_data)
@@ -1286,7 +1288,7 @@ static void auth_cb(DBusError *derr, void *user_data)
 
        if (derr && dbus_error_is_set(derr)) {
                error("Access denied: %s", derr->message);
-               avctp_set_state(session, AVCTP_STATE_DISCONNECTED);
+               avctp_set_state(session, AVCTP_STATE_DISCONNECTED, -EIO);
                return;
        }
 
@@ -1294,7 +1296,7 @@ static void auth_cb(DBusError *derr, void *user_data)
                                                                NULL, &err)) {
                error("bt_io_accept: %s", err->message);
                g_error_free(err);
-               avctp_set_state(session, AVCTP_STATE_DISCONNECTED);
+               avctp_set_state(session, AVCTP_STATE_DISCONNECTED, -EIO);
        }
 }
 
@@ -1356,10 +1358,17 @@ static void avctp_control_confirm(struct avctp *session, GIOChannel *chan,
        if (session->control != NULL) {
                error("Control: Refusing unexpected connect");
                g_io_channel_shutdown(chan, TRUE, NULL);
+
+               /*
+                * Close AVCTP channel if remote tried connect
+                * at the same time
+                * AVRCP SPEC V1.5 4.1.1 Connection Establishment
+                */
+               avctp_set_state(session, AVCTP_STATE_DISCONNECTED, -EAGAIN);
                return;
        }
 
-       avctp_set_state(session, AVCTP_STATE_CONNECTING);
+       avctp_set_state(session, AVCTP_STATE_CONNECTING, 0);
        session->control = avctp_channel_create(session, chan, NULL);
 
        src = btd_adapter_get_address(device_get_adapter(dev));
@@ -1382,7 +1391,7 @@ static void avctp_control_confirm(struct avctp *session, GIOChannel *chan,
        return;
 
 drop:
-       avctp_set_state(session, AVCTP_STATE_DISCONNECTED);
+       avctp_set_state(session, AVCTP_STATE_DISCONNECTED, -EIO);
 }
 
 static void avctp_browsing_confirm(struct avctp *session, GIOChannel *chan,
@@ -1398,7 +1407,7 @@ static void avctp_browsing_confirm(struct avctp *session, GIOChannel *chan,
 
        if (bt_io_accept(chan, avctp_connect_browsing_cb, session, NULL,
                                                                &err)) {
-               avctp_set_state(session, AVCTP_STATE_BROWSING_CONNECTING);
+               avctp_set_state(session, AVCTP_STATE_BROWSING_CONNECTING, 0);
                return;
        }
 
@@ -1988,7 +1997,7 @@ struct avctp *avctp_connect(struct btd_device *device)
        if (session->state > AVCTP_STATE_DISCONNECTED)
                return session;
 
-       avctp_set_state(session, AVCTP_STATE_CONNECTING);
+       avctp_set_state(session, AVCTP_STATE_CONNECTING, 0);
 
        src = btd_adapter_get_address(session->server->adapter);
 
@@ -2000,7 +2009,7 @@ struct avctp *avctp_connect(struct btd_device *device)
                                BT_IO_OPT_PSM, AVCTP_CONTROL_PSM,
                                BT_IO_OPT_INVALID);
        if (err) {
-               avctp_set_state(session, AVCTP_STATE_DISCONNECTED);
+               avctp_set_state(session, AVCTP_STATE_DISCONNECTED, -EIO);
                error("%s", err->message);
                g_error_free(err);
                return NULL;
@@ -2025,7 +2034,7 @@ int avctp_connect_browsing(struct avctp *session)
        if (session->browsing != NULL)
                return 0;
 
-       avctp_set_state(session, AVCTP_STATE_BROWSING_CONNECTING);
+       avctp_set_state(session, AVCTP_STATE_BROWSING_CONNECTING, 0);
 
        src = btd_adapter_get_address(session->server->adapter);
 
@@ -2055,7 +2064,7 @@ void avctp_disconnect(struct avctp *session)
        if (session->state == AVCTP_STATE_DISCONNECTED)
                return;
 
-       avctp_set_state(session, AVCTP_STATE_DISCONNECTED);
+       avctp_set_state(session, AVCTP_STATE_DISCONNECTED, -EIO);
 }
 
 struct avctp *avctp_get(struct btd_device *device)
index 05fceb4..6c19ce4 100644 (file)
@@ -122,7 +122,7 @@ typedef enum {
 typedef void (*avctp_state_cb) (struct btd_device *dev,
                                avctp_state_t old_state,
                                avctp_state_t new_state,
-                               void *user_data);
+                               int err, void *user_data);
 
 typedef bool (*avctp_passthrough_cb) (struct avctp *session,
                                        uint8_t op, bool pressed,
index f2bfd51..92bd561 100644 (file)
 #include <unistd.h>
 #include <assert.h>
 
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/sdp.h>
-#include <bluetooth/sdp_lib.h>
+#include <glib.h>
+
+#include "lib/bluetooth.h"
+#include "lib/sdp.h"
+#include "lib/sdp_lib.h"
 #include "lib/uuid.h"
 
 #ifdef __TIZEN_PATCH__
@@ -46,9 +48,6 @@
 #endif /* __BROADCOM_QOS_PATCH__ */
 #endif /* __TIZEN_PATCH__ */
 
-#include <glib.h>
-
-
 #include "btio/btio.h"
 #include "src/log.h"
 #include "src/shared/util.h"
@@ -971,6 +970,9 @@ static gboolean send_broadcom_a2dp_qos(bdaddr_t *dst, gboolean qos_high)
 
        dd = hci_open_dev(0);
 
+       if (dd < 0)
+               return FALSE;
+
        cr = g_malloc0(sizeof(*cr) + sizeof(struct hci_conn_info));
 
        cr->type = ACL_LINK;
@@ -1188,7 +1190,8 @@ static void finalize_discovery(struct avdtp *session, int err)
        if (discover->id > 0)
                g_source_remove(discover->id);
 
-       discover->cb(session, session->seps, err ? &avdtp_err : NULL,
+       if (discover->cb)
+               discover->cb(session, session->seps, err ? &avdtp_err : NULL,
                                                        discover->user_data);
        g_free(discover);
        session->discover = NULL;
@@ -1340,12 +1343,14 @@ static gboolean disconnect_timeout(gpointer user_data)
        }
 
 #ifdef __TIZEN_PATCH__
-       adapter = device_get_adapter(session->device);
-       bdaddr = device_get_address(session->device);
-       if (adapter && bdaddr)
-               device = btd_adapter_find_device(adapter, bdaddr, BDADDR_BREDR);
-       if (!device)
-               error("device is NOT found");
+       if (session->device) {
+               adapter = device_get_adapter(session->device);
+               bdaddr = device_get_address(session->device);
+               if (adapter && bdaddr)
+                       device = btd_adapter_find_device(adapter, bdaddr, BDADDR_BREDR);
+               if (!device)
+                       error("device is NOT found");
+       }
 #endif
 
        connection_lost(session, ETIMEDOUT);
@@ -1448,6 +1453,11 @@ struct avdtp_remote_sep *avdtp_find_remote_sep(struct avdtp *session,
                if (codec_data->media_codec_type != lsep->codec)
                        continue;
 
+               if (lsep->ind && lsep->ind->match_codec)
+                       if (!lsep->ind->match_codec(session, codec_data,
+                                                       lsep->user_data))
+                               continue;
+
                if (sep->stream == NULL)
                        return sep;
        }
index d3e04de..ec0b9f1 100644 (file)
@@ -172,6 +172,9 @@ struct avdtp_sep_cfm {
 /* Callbacks for indicating when we received a new command. The return value
  * indicates whether the command should be rejected or accepted */
 struct avdtp_sep_ind {
+       gboolean (*match_codec) (struct avdtp *session,
+                               struct avdtp_media_codec_capability *codec,
+                               void *user_data);
        gboolean (*get_capability) (struct avdtp *session,
                                        struct avdtp_local_sep *sep,
                                        gboolean get_all,
index 3fe4b00..911a889 100644 (file)
@@ -274,6 +274,7 @@ void avrcp_stop_position_timer(void);
 unsigned int pos_timer_id = 0;
 #endif
 
+#ifdef SUPPORT_AVRCP_CONTROL
 static sdp_record_t *avrcp_ct_record(void)
 {
        sdp_list_t *svclass_id, *pfseq, *apseq, *apseq1, *root;
@@ -285,8 +286,13 @@ static sdp_record_t *avrcp_ct_record(void)
        uint16_t lp = AVCTP_CONTROL_PSM, ap = AVCTP_BROWSING_PSM;
 #ifdef __TIZEN_PATCH__
        uint16_t avrcp_ver = 0x0103, avctp_ver = 0x0104;
-       uint16_t feat = AVRCP_FEATURE_CATEGORY_1;
-
+       uint16_t feat = 0;
+#ifdef ENABLE_AVRCP_CATEGORY1
+       feat = AVRCP_FEATURE_CATEGORY_1;
+#endif
+#ifdef ENABLE_AVRCP_CATEGORY2
+       feat = feat | AVRCP_FEATURE_CATEGORY_2;
+#endif
 #else
        uint16_t avrcp_ver = 0x0105, avctp_ver = 0x0103;
        uint16_t feat = ( AVRCP_FEATURE_CATEGORY_1 |
@@ -373,7 +379,9 @@ static sdp_record_t *avrcp_ct_record(void)
 
        return record;
 }
+#endif
 
+#ifdef SUPPORT_AVRCP_TARGET
 static sdp_record_t *avrcp_tg_record(void)
 {
        sdp_list_t *svclass_id, *pfseq, *apseq, *root, *apseq_browsing;
@@ -390,8 +398,14 @@ static sdp_record_t *avrcp_tg_record(void)
        uint16_t lp_browsing = AVCTP_BROWSING_PSM;
 #ifdef __TIZEN_PATCH__
        uint16_t avrcp_ver = 0x0103, avctp_ver = 0x0104;
-       uint16_t feat = AVRCP_FEATURE_CATEGORY_1 |
-                                       AVRCP_FEATURE_PLAYER_SETTINGS;
+       uint16_t feat = 0;
+#ifdef ENABLE_AVRCP_CATEGORY1
+       feat = AVRCP_FEATURE_CATEGORY_1 |
+               AVRCP_FEATURE_PLAYER_SETTINGS;
+#endif
+#ifdef ENABLE_AVRCP_CATEGORY2
+       feat = feat | AVRCP_FEATURE_CATEGORY_2;
+#endif
 #else
        uint16_t avrcp_ver = 0x0104, avctp_ver = 0x0103;
        uint16_t feat = ( AVRCP_FEATURE_CATEGORY_1 |
@@ -477,6 +491,7 @@ static sdp_record_t *avrcp_tg_record(void)
 
        return record;
 }
+#endif
 
 static unsigned int attr_get_max_val(uint8_t attr)
 {
@@ -3428,6 +3443,9 @@ static gboolean avrcp_get_capabilities_resp(struct avctp *conn,
                case AVRCP_EVENT_ADDRESSED_PLAYER_CHANGED:
                case AVRCP_EVENT_UIDS_CHANGED:
                case AVRCP_EVENT_AVAILABLE_PLAYERS_CHANGED:
+                       /* These events above are controller specific */
+                       if (!session->controller)
+                               break;
                case AVRCP_EVENT_VOLUME_CHANGED:
 #endif
                        avrcp_register_notification(session, event);
@@ -3435,6 +3453,9 @@ static gboolean avrcp_get_capabilities_resp(struct avctp *conn,
                }
        }
 
+       if (!session->controller)
+               return FALSE;
+
        if (!(events & (1 << AVRCP_EVENT_SETTINGS_CHANGED)))
                avrcp_list_player_attributes(session);
 
@@ -3555,6 +3576,7 @@ static void avrcp_connect_browsing(struct avrcp *session)
                                                        session);
 }
 
+#ifdef SUPPORT_AVRCP_TARGET
 static void target_init(struct avrcp *session)
 {
        struct avrcp_server *server = session->server;
@@ -3571,8 +3593,7 @@ static void target_init(struct avrcp *session)
        DBG("%p version 0x%04x", target, target->version);
 
        service = btd_device_get_service(session->dev, AVRCP_REMOTE_UUID);
-       if (service != NULL)
-               btd_service_connecting_complete(service, 0);
+       btd_service_connecting_complete(service, 0);
 
        player = g_slist_nth_data(server->players, 0);
        if (player != NULL) {
@@ -3608,7 +3629,9 @@ static void target_init(struct avrcp *session)
 
        avrcp_connect_browsing(session);
 }
+#endif
 
+#ifdef SUPPORT_AVRCP_CONTROL
 static void controller_init(struct avrcp *session)
 {
        struct avrcp_player *player;
@@ -3639,8 +3662,7 @@ static void controller_init(struct avrcp *session)
 #endif
 
        service = btd_device_get_service(session->dev, AVRCP_TARGET_UUID);
-       if (service != NULL)
-               btd_service_connecting_complete(service, 0);
+       btd_service_connecting_complete(service, 0);
 
        /* Only create player if category 1 is supported */
        if (!(controller->features & AVRCP_FEATURE_CATEGORY_1))
@@ -3668,6 +3690,7 @@ static void controller_init(struct avrcp *session)
 
        avrcp_connect_browsing(session);
 }
+#endif
 
 static void session_init_control(struct avrcp *session)
 {
@@ -3681,29 +3704,24 @@ static void session_init_control(struct avrcp *session)
                                                        handle_vendordep_pdu,
                                                        session);
        session->control_handlers = control_handlers;
-
+#ifdef SUPPORT_AVRCP_CONTROL
        if (btd_device_get_service(session->dev, AVRCP_TARGET_UUID) != NULL)
                controller_init(session);
+#endif
+#ifdef SUPPORT_AVRCP_TARGET
        if (btd_device_get_service(session->dev, AVRCP_REMOTE_UUID) != NULL)
                target_init(session);
+#endif
 }
 
 static void controller_destroy(struct avrcp *session)
 {
        struct avrcp_data *controller = session->controller;
-       struct btd_service *service;
 
        DBG("%p", controller);
 
        g_slist_free_full(controller->players, player_destroy);
 
-       service = btd_device_get_service(session->dev, AVRCP_TARGET_UUID);
-
-       if (session->control_id == 0)
-               btd_service_connecting_complete(service, -EIO);
-       else
-               btd_service_disconnecting_complete(service, 0);
-
        g_free(controller);
 }
 
@@ -3711,31 +3729,40 @@ static void target_destroy(struct avrcp *session)
 {
        struct avrcp_data *target = session->target;
        struct avrcp_player *player = target->player;
-       struct btd_service *service;
 
        DBG("%p", target);
 
        if (player != NULL)
                player->sessions = g_slist_remove(player->sessions, session);
 
-       service = btd_device_get_service(session->dev, AVRCP_REMOTE_UUID);
-
-       if (session->control_id == 0)
-               btd_service_connecting_complete(service, -EIO);
-       else
-               btd_service_disconnecting_complete(service, 0);
-
        g_free(target);
 }
 
-static void session_destroy(struct avrcp *session)
+static void session_destroy(struct avrcp *session, int err)
 {
        struct avrcp_server *server = session->server;
+       struct btd_service *service;
 
        server->sessions = g_slist_remove(server->sessions, session);
 
        session_abort_pending_pdu(session);
 
+       service = btd_device_get_service(session->dev, AVRCP_TARGET_UUID);
+       if (service != NULL) {
+               if (session->control_id == 0)
+                       btd_service_connecting_complete(service, err);
+               else
+                       btd_service_disconnecting_complete(service, 0);
+       }
+
+       service = btd_device_get_service(session->dev, AVRCP_REMOTE_UUID);
+       if (service != NULL) {
+               if (session->control_id == 0)
+                       btd_service_connecting_complete(service, err);
+               else
+                       btd_service_disconnecting_complete(service, 0);
+       }
+
        if (session->browsing_timer > 0)
                g_source_remove(session->browsing_timer);
 
@@ -3773,7 +3800,8 @@ static struct avrcp *session_create(struct avrcp_server *server,
 }
 
 static void state_changed(struct btd_device *device, avctp_state_t old_state,
-                               avctp_state_t new_state, void *user_data)
+                                       avctp_state_t new_state, int err,
+                                       void *user_data)
 {
        struct avrcp_server *server;
        struct avrcp *session;
@@ -3789,7 +3817,7 @@ static void state_changed(struct btd_device *device, avctp_state_t old_state,
                if (session == NULL)
                        break;
 
-               session_destroy(session);
+               session_destroy(session, err);
 
                break;
        case AVCTP_STATE_CONNECTING:
@@ -4008,6 +4036,7 @@ static void avrcp_target_remove(struct btd_service *service)
        control_unregister(service);
 }
 
+#ifdef SUPPORT_AVRCP_TARGET
 static void avrcp_target_server_remove(struct btd_profile *p,
                                                struct btd_adapter *adapter)
 {
@@ -4027,7 +4056,9 @@ static void avrcp_target_server_remove(struct btd_profile *p,
        if (server->ct_record_id == 0)
                avrcp_server_unregister(server);
 }
+#endif
 
+#ifdef SUPPORT_AVRCP_TARGET
 static int avrcp_target_server_probe(struct btd_profile *p,
                                                struct btd_adapter *adapter)
 {
@@ -4062,6 +4093,7 @@ done:
 
        return 0;
 }
+#endif
 
 static struct btd_profile avrcp_target_profile = {
        .name           = "audio-avrcp-target",
@@ -4072,9 +4104,10 @@ static struct btd_profile avrcp_target_profile = {
 
        .connect        = avrcp_connect,
        .disconnect     = avrcp_disconnect,
-
+#ifdef SUPPORT_AVRCP_TARGET
        .adapter_probe  = avrcp_target_server_probe,
        .adapter_remove = avrcp_target_server_remove,
+#endif
 };
 
 static int avrcp_controller_probe(struct btd_service *service)
@@ -4091,6 +4124,7 @@ static void avrcp_controller_remove(struct btd_service *service)
        control_unregister(service);
 }
 
+#ifdef SUPPORT_AVRCP_CONTROL
 static void avrcp_controller_server_remove(struct btd_profile *p,
                                                struct btd_adapter *adapter)
 {
@@ -4110,7 +4144,9 @@ static void avrcp_controller_server_remove(struct btd_profile *p,
        if (server->tg_record_id == 0)
                avrcp_server_unregister(server);
 }
+#endif
 
+#ifdef SUPPORT_AVRCP_CONTROL
 static int avrcp_controller_server_probe(struct btd_profile *p,
                                                struct btd_adapter *adapter)
 {
@@ -4145,6 +4181,7 @@ done:
 
        return 0;
 }
+#endif
 
 static struct btd_profile avrcp_controller_profile = {
        .name           = "avrcp-controller",
@@ -4155,8 +4192,10 @@ static struct btd_profile avrcp_controller_profile = {
 
        .connect        = avrcp_connect,
        .disconnect     = avrcp_disconnect,
+#ifdef SUPPORT_AVRCP_CONTROL
        .adapter_probe  = avrcp_controller_server_probe,
        .adapter_remove = avrcp_controller_server_remove,
+#endif
 };
 
 static int avrcp_init(void)
index 9110b0f..f4656d8 100644 (file)
@@ -71,7 +71,8 @@ struct control {
 };
 
 static void state_changed(struct btd_device *dev, avctp_state_t old_state,
-                               avctp_state_t new_state, void *user_data)
+                                       avctp_state_t new_state, int err,
+                                       void *user_data)
 {
        struct control *control = user_data;
        DBusConnection *conn = btd_get_dbus_connection();
@@ -337,13 +338,3 @@ int control_init_remote(struct btd_service *service)
 
        return 0;
 }
-
-gboolean control_is_active(struct btd_service *service)
-{
-       struct control *control = btd_service_get_user_data(service);
-
-       if (control && control->session)
-               return TRUE;
-
-       return FALSE;
-}
index da8f16c..4bda896 100644 (file)
@@ -29,7 +29,6 @@ struct btd_service;
 int control_init_target(struct btd_service *service);
 int control_init_remote(struct btd_service *service);
 void control_unregister(struct btd_service *service);
-gboolean control_is_active(struct btd_service *service);
 
 int control_connect(struct btd_service *service);
 int control_disconnect(struct btd_service *service);
index e9e4da9..3556682 100644 (file)
@@ -62,7 +62,6 @@
 #include "sink.h"
 #endif
 
-
 #define MEDIA_INTERFACE "org.bluez.Media1"
 #define MEDIA_ENDPOINT_INTERFACE "org.bluez.MediaEndpoint1"
 #define MEDIA_PLAYER_INTERFACE "org.mpris.MediaPlayer2.Player"
@@ -73,6 +72,8 @@
 #define SINK_SUSPEND_TIMEOUT 4         /* 4 seconds */
 
 unsigned int suspend_timer_id = 0;
+static gboolean a2dp_sink_support = false;
+static gboolean a2dp_source_support = true;
 #endif
 
 struct media_adapter {
@@ -1036,7 +1037,17 @@ static DBusMessage *register_endpoint(DBusConnection *conn, DBusMessage *msg,
        if (parse_properties(&props, &uuid, &delay_reporting, &codec,
                                                &capabilities, &size) < 0)
                return btd_error_invalid_args(msg);
+#ifdef __TIZEN_PATCH__
+       if(!a2dp_sink_support && !g_strcmp0(uuid, A2DP_SINK_UUID)) {
+               error("A2DP sink role is not supported.");
+               return btd_error_not_supported(msg);
+       }
 
+       if(!a2dp_source_support && !g_strcmp0(uuid, A2DP_SOURCE_UUID)) {
+               error("A2DP source role is not supported.");
+               return btd_error_not_supported(msg);
+       }
+#endif
        if (media_endpoint_create(adapter, sender, path, uuid, delay_reporting,
                                codec, capabilities, size, &err) == NULL) {
                if (err == -EPROTONOSUPPORT)
index 819a967..09aa832 100644 (file)
@@ -166,6 +166,40 @@ static void handle_appearance(struct gas *gas, uint16_t value_handle)
                DBG("Failed to send request to read appearance");
 }
 
+#ifdef __TIZEN_PATCH__
+static void read_rpa_res_characteristic_value_cb(bool success, uint8_t att_ecode,
+                                       const uint8_t *value, uint16_t length,
+                                       void *user_data)
+{
+       struct gas *gas = user_data;
+       uint8_t rpa_res_support;
+
+       if (!success) {
+               DBG("Reading RPA Resolution Char Value failed with ATT error: %u", att_ecode);
+               return;
+       }
+
+       /* The RPA Resolution Char Value value is a 8-bit unsigned integer */
+       if (length != 1) {
+               DBG("Malformed RPA resolution char value");
+               return;
+       }
+
+       rpa_res_support = *value;
+
+       DBG("GAP RPA Resolution Char Value: %d", rpa_res_support);
+
+       device_set_rpa_res_char_value(gas->device, rpa_res_support);
+}
+
+static void handle_rpa_res_characteristic_value(struct gas *gas, uint16_t value_handle)
+{
+       if (!bt_gatt_client_read_value(gas->client, value_handle,
+                                               read_rpa_res_characteristic_value_cb, gas, NULL))
+               DBG("Failed to send request to read RPA resolution Char Value");
+}
+#endif
+
 static bool uuid_cmp(uint16_t u16, const bt_uuid_t *uuid)
 {
        bt_uuid_t lhs;
@@ -192,6 +226,10 @@ static void handle_characteristic(struct gatt_db_attribute *attr,
                handle_device_name(gas, value_handle);
        else if (uuid_cmp(GATT_CHARAC_APPEARANCE, &uuid))
                handle_appearance(gas, value_handle);
+#ifdef __TIZEN_PATCH__
+       else if (uuid_cmp(GATT_CHARAC_CENTRAL_RPA_RESOLUTION, &uuid))
+               handle_rpa_res_characteristic_value(gas, value_handle);
+#endif
        else {
                char uuid_str[MAX_LEN_UUID_STR];
 
index 0350f92..1a1e1a6 100644 (file)
@@ -67,17 +67,6 @@ static unsigned long bnepgetconnlist;
 static unsigned long bnepgetconninfo;
 #endif
 
-static struct {
-       const char      *name;          /* Friendly name */
-       const char      *uuid128;       /* UUID 128 */
-       uint16_t        id;             /* Service class identifier */
-} __svc[] = {
-       { "panu",       PANU_UUID,      BNEP_SVC_PANU   },
-       { "gn",         GN_UUID,        BNEP_SVC_GN     },
-       { "nap",        NAP_UUID,       BNEP_SVC_NAP    },
-       { NULL }
-};
-
 struct __service_16 {
        uint16_t dst;
        uint16_t src;
@@ -98,26 +87,6 @@ struct bnep {
        void    *disconn_data;
 };
 
-const char *bnep_uuid(uint16_t id)
-{
-       int i;
-
-       for (i = 0; __svc[i].uuid128; i++)
-               if (__svc[i].id == id)
-                       return __svc[i].uuid128;
-       return NULL;
-}
-
-const char *bnep_name(uint16_t id)
-{
-       int i;
-
-       for (i = 0; __svc[i].name; i++)
-               if (__svc[i].id == id)
-                       return __svc[i].name;
-       return NULL;
-}
-
 int bnep_init(void)
 {
        ctl = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_BNEP);
@@ -191,6 +160,9 @@ static int bnep_connadd(int sk, uint16_t role, char *dev)
 
        req.sock = sk;
        req.role = role;
+#ifdef  __TIZEN_PATCH__
+       req.flags = (1 << BNEP_SETUP_RESPONSE);
+#endif
        if (ioctl(ctl, BNEPCONNADD, &req) < 0) {
                int err = -errno;
                error("bnep: Failed to add device %s: %s(%d)",
@@ -202,6 +174,20 @@ static int bnep_connadd(int sk, uint16_t role, char *dev)
        return 0;
 }
 
+#ifdef  __TIZEN_PATCH__
+static uint32_t bnep_getsuppfeat(void)
+{
+       uint32_t feat;
+
+       if (ioctl(ctl, BNEPGETSUPPFEAT, &feat) < 0)
+               feat = 0;
+
+       DBG("supported features: 0x%x", feat);
+
+       return feat;
+}
+#endif
+
 static int bnep_if_up(const char *devname)
 {
        struct ifreq ifr;
@@ -441,17 +427,21 @@ void bnep_free(struct bnep *session)
        g_free(session);
 }
 
-int bnep_connect(struct bnep *session, bnep_connect_cb conn_cb, void *data)
+int bnep_connect(struct bnep *session, bnep_connect_cb conn_cb,
+                                       bnep_disconnect_cb disconn_cb,
+                                       void *conn_data, void *disconn_data)
 {
        GError *gerr = NULL;
        int err;
 
-       if (!session || !conn_cb)
+       if (!session || !conn_cb || !disconn_cb)
                return -EINVAL;
 
        session->attempts = 0;
        session->conn_cb = conn_cb;
-       session->conn_data = data;
+       session->disconn_cb = disconn_cb;
+       session->conn_data = conn_data;
+       session->disconn_data = disconn_data;
 
        bt_io_get(session->io, &gerr, BT_IO_OPT_DEST_BDADDR, &session->dst_addr,
                                                        BT_IO_OPT_INVALID);
@@ -490,18 +480,6 @@ void bnep_disconnect(struct bnep *session)
        bnep_conndel(&session->dst_addr);
 }
 
-void bnep_set_disconnect(struct bnep *session, bnep_disconnect_cb disconn_cb,
-                                                               void *data)
-{
-       if (!session || !disconn_cb)
-               return;
-
-       if (!session->disconn_cb && !session->disconn_data) {
-               session->disconn_cb = disconn_cb;
-               session->disconn_data = data;
-       }
-}
-
 #ifndef  __TIZEN_PATCH__
 static int bnep_add_to_bridge(const char *devname, const char *bridge)
 {
@@ -576,65 +554,67 @@ static int bnep_del_from_bridge(const char *devname, const char *bridge)
        return err;
 }
 
-int bnep_server_add(int sk, uint16_t dst, char *bridge, char *iface,
-                                               const bdaddr_t *addr)
+static ssize_t bnep_send_ctrl_rsp(int sk, uint8_t ctrl, uint16_t resp)
 {
-       int err;
+       ssize_t sent;
 
-       if (!bridge || !iface || !addr)
-               return -EINVAL;
+       switch (ctrl) {
+       case BNEP_CMD_NOT_UNDERSTOOD: {
+               struct bnep_ctrl_cmd_not_understood_cmd rsp;
 
-       err = bnep_connadd(sk, dst, iface);
-       if (err < 0)
-               return err;
+               rsp.type = BNEP_CONTROL;
+               rsp.ctrl = ctrl;
+               rsp.unkn_ctrl = (uint8_t) resp;
 
-#ifndef  __TIZEN_PATCH__
-       err = bnep_add_to_bridge(iface, bridge);
-       if (err < 0) {
-               bnep_conndel(addr);
-               return err;
+               sent = send(sk, &rsp, sizeof(rsp), 0);
+               break;
        }
-#endif
-
-       return bnep_if_up(iface);
-}
-
-void bnep_server_delete(char *bridge, char *iface, const bdaddr_t *addr)
-{
-       if (!bridge || !iface || !addr)
-               return;
+       case BNEP_FILTER_MULT_ADDR_RSP:
+       case BNEP_FILTER_NET_TYPE_RSP:
+       case BNEP_SETUP_CONN_RSP: {
+               struct bnep_control_rsp rsp;
 
-       bnep_del_from_bridge(iface, bridge);
-       bnep_if_down(iface);
-       bnep_conndel(addr);
-}
+               rsp.type = BNEP_CONTROL;
+               rsp.ctrl = ctrl;
+               rsp.resp = htons(resp);
 
-ssize_t bnep_send_ctrl_rsp(int sk, uint8_t type, uint8_t ctrl, uint16_t resp)
-{
-       struct bnep_control_rsp rsp;
-
-       rsp.type = type;
-       rsp.ctrl = ctrl;
-       rsp.resp = htons(resp);
+               sent = send(sk, &rsp, sizeof(rsp), 0);
+               break;
+       }
+       default:
+               error("bnep: wrong response type");
+               sent = -1;
+               break;
+       }
 
-       return send(sk, &rsp, sizeof(rsp), 0);
+       return sent;
 }
 
-uint16_t bnep_setup_decode(struct bnep_setup_conn_req *req, uint16_t *dst,
-                                                               uint16_t *src)
+static uint16_t bnep_setup_decode(int sk, struct bnep_setup_conn_req *req,
+                                                               uint16_t *dst)
 {
        const uint8_t bt_base[] = { 0x00, 0x00, 0x10, 0x00, 0x80, 0x00,
                                        0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB };
+       uint16_t src;
        uint8_t *dest, *source;
        uint32_t val;
 
+#ifdef  __TIZEN_PATCH__
+       if (((req->type != BNEP_CONTROL) &&
+               (req->type != (BNEP_CONTROL | BNEP_EXT_HEADER)))  ||
+                                       req->ctrl != BNEP_SETUP_CONN_REQ)
+#else
+       if (req->type != BNEP_CONTROL || req->ctrl != BNEP_SETUP_CONN_REQ)
+#endif
+               return BNEP_CONN_NOT_ALLOWED;
+
        dest = req->service;
        source = req->service + req->uuid_size;
 
        switch (req->uuid_size) {
        case 2: /* UUID16 */
                *dst = get_be16(dest);
-               *src = get_be16(source);
+               src = get_be16(source);
                break;
        case 16: /* UUID128 */
                /* Check that the bytes in the UUID, except the service ID
@@ -658,7 +638,7 @@ uint16_t bnep_setup_decode(struct bnep_setup_conn_req *req, uint16_t *dst,
                if (val > 0xffff)
                        return BNEP_CONN_INVALID_SRC;
 
-               *src = val;
+               src = val;
                break;
        default:
                return BNEP_CONN_INVALID_SVC;
@@ -668,12 +648,12 @@ uint16_t bnep_setup_decode(struct bnep_setup_conn_req *req, uint16_t *dst,
        switch (*dst) {
        case BNEP_SVC_NAP:
        case BNEP_SVC_GN:
-               if (*src == BNEP_SVC_PANU)
+               if (src == BNEP_SVC_PANU)
                        return BNEP_SUCCESS;
                return BNEP_CONN_INVALID_SRC;
        case BNEP_SVC_PANU:
-               if (*src == BNEP_SVC_PANU || *src == BNEP_SVC_GN ||
-                                                       *src == BNEP_SVC_NAP)
+               if (src == BNEP_SVC_PANU || src == BNEP_SVC_GN ||
+                                                       src == BNEP_SVC_NAP)
                        return BNEP_SUCCESS;
 
                return BNEP_CONN_INVALID_SRC;
@@ -696,3 +676,157 @@ int bnep_conndel_wrapper(const bdaddr_t *dst)
 }
 #endif
 
+#ifdef  __TIZEN_PATCH__
+static int bnep_server_add_legacy(int sk, uint16_t dst, char *bridge,
+                                       char *iface, const bdaddr_t *addr,
+                                       uint8_t *setup_data, int len)
+{
+       int err, n;
+       uint16_t rsp;
+
+       n = read(sk, setup_data, len);
+       if (n != len) {
+               err = -EIO;
+               rsp = BNEP_CONN_NOT_ALLOWED;
+               goto reply;
+       }
+
+       err = bnep_connadd(sk, dst, iface);
+       if (err < 0) {
+               rsp = BNEP_CONN_NOT_ALLOWED;
+               goto reply;
+       }
+
+       err = bnep_if_up(iface);
+       if (err < 0) {
+               bnep_del_from_bridge(iface, bridge);
+               bnep_conndel(addr);
+               rsp = BNEP_CONN_NOT_ALLOWED;
+               goto reply;
+       }
+
+       rsp = BNEP_SUCCESS;
+
+reply:
+       if (bnep_send_ctrl_rsp(sk, BNEP_SETUP_CONN_RSP, rsp) < 0) {
+               err = -errno;
+               error("bnep: send ctrl rsp error: %s (%d)", strerror(errno),
+                                                               errno);
+       }
+
+       return err;
+}
+#endif
+
+int bnep_server_add(int sk, char *bridge, char *iface, const bdaddr_t *addr,
+                                               uint8_t *setup_data, int len)
+{
+       int err;
+#ifdef  __TIZEN_PATCH__
+       uint32_t feat;
+#endif
+       uint16_t rsp, dst;
+       struct bnep_setup_conn_req *req = (void *) setup_data;
+
+       /* Highest known Control command ID
+        * is BNEP_FILTER_MULT_ADDR_RSP = 0x06 */
+       if (req->type == BNEP_CONTROL &&
+                                       req->ctrl > BNEP_FILTER_MULT_ADDR_RSP) {
+               error("bnep: cmd not understood");
+               err = bnep_send_ctrl_rsp(sk, BNEP_CMD_NOT_UNDERSTOOD,
+                                                               req->ctrl);
+               if (err < 0)
+                       error("send not understood ctrl rsp error: %s (%d)",
+                                                       strerror(errno), errno);
+
+               return err;
+       }
+
+       /* Processing BNEP_SETUP_CONNECTION_REQUEST_MSG */
+       rsp = bnep_setup_decode(sk, req, &dst);
+       if (rsp != BNEP_SUCCESS) {
+               err = -rsp;
+               error("bnep: error while decoding setup connection request: %d",
+                                                                       rsp);
+#ifdef  __TIZEN_PATCH__
+               goto failed;
+#else
+               goto reply;
+#endif
+       }
+
+#ifdef  __TIZEN_PATCH__
+       feat = bnep_getsuppfeat();
+
+       /*
+        * Take out setup data if kernel doesn't support handling it, especially
+        * setup request. If kernel would have set session flags, they should
+        * be checked and handled respectively.
+        */
+       if (!feat || !(feat & (1 << BNEP_SETUP_RESPONSE)))
+               return bnep_server_add_legacy(sk, dst, bridge, iface, addr,
+                                                       setup_data, len);
+#endif
+
+       err = bnep_connadd(sk, dst, iface);
+       if (err < 0) {
+               rsp = BNEP_CONN_NOT_ALLOWED;
+#ifdef  __TIZEN_PATCH__
+               goto failed;
+#else
+               goto reply;
+#endif
+       }
+
+#ifndef  __TIZEN_PATCH__
+       err = bnep_add_to_bridge(iface, bridge);
+       if (err < 0)
+               goto failed_conn;
+#endif
+
+       err = bnep_if_up(iface);
+       if (err < 0)
+#ifdef  __TIZEN_PATCH__
+               goto failed_bridge;
+#else
+               rsp = BNEP_CONN_NOT_ALLOWED;
+#endif
+
+#ifdef  __TIZEN_PATCH__
+       return 0;
+
+failed_bridge:
+       bnep_del_from_bridge(iface, bridge);
+
+failed_conn:
+       bnep_conndel(addr);
+
+       return err;
+
+failed:
+       if (bnep_send_ctrl_rsp(sk, BNEP_SETUP_CONN_RSP, rsp) < 0) {
+               err = -errno;
+               error("bnep: send ctrl rsp error: %s (%d)", strerror(-err),
+                                                                       -err);
+       }
+#else
+reply:
+       if (bnep_send_ctrl_rsp(sk, BNEP_SETUP_CONN_RSP, rsp) < 0) {
+               err = -errno;
+               error("bnep: send ctrl rsp error: %s (%d)", strerror(errno),
+                                                                       errno);
+       }
+#endif
+
+       return err;
+}
+
+void bnep_server_delete(char *bridge, char *iface, const bdaddr_t *addr)
+{
+       if (!bridge || !iface || !addr)
+               return;
+
+       bnep_del_from_bridge(iface, bridge);
+       bnep_if_down(iface);
+       bnep_conndel(addr);
+}
index 7255f82..f915cf3 100644 (file)
@@ -26,27 +26,20 @@ struct bnep;
 int bnep_init(void);
 int bnep_cleanup(void);
 
-const char *bnep_uuid(uint16_t id);
-const char *bnep_name(uint16_t id);
-
 struct bnep *bnep_new(int sk, uint16_t local_role, uint16_t remote_role,
                                                                char *iface);
 void bnep_free(struct bnep *session);
 
 typedef void (*bnep_connect_cb) (char *iface, int err, void *data);
-int bnep_connect(struct bnep *b, bnep_connect_cb conn_cb, void *data);
 typedef void (*bnep_disconnect_cb) (void *data);
-void bnep_set_disconnect(struct bnep *session, bnep_disconnect_cb disconn_cb,
-                                                               void *data);
+int bnep_connect(struct bnep *session, bnep_connect_cb conn_cb,
+                                       bnep_disconnect_cb disconn_cb,
+                                       void *conn_data, void *disconn_data);
 void bnep_disconnect(struct bnep *session);
 
-int bnep_server_add(int sk, uint16_t dst, char *bridge, char *iface,
-                                                       const bdaddr_t *addr);
+int bnep_server_add(int sk, char *bridge, char *iface, const bdaddr_t *addr,
+                                               uint8_t *setup_data, int len);
 void bnep_server_delete(char *bridge, char *iface, const bdaddr_t *addr);
-
-ssize_t bnep_send_ctrl_rsp(int sk, uint8_t type, uint8_t ctrl, uint16_t resp);
-uint16_t bnep_setup_decode(struct bnep_setup_conn_req *req, uint16_t *dst,
-                                                               uint16_t *src);
 #ifdef  __TIZEN_PATCH__
 int bnep_if_down_wrapper(const char *devname);
 int bnep_conndel_wrapper(const bdaddr_t *dst);
index bb8e34c..e19e945 100644 (file)
@@ -274,14 +274,12 @@ static void connect_cb(GIOChannel *chan, GError *err, gpointer data)
        if (!nc->session)
                goto failed;
 
-       perr = bnep_connect(nc->session, bnep_conn_cb, nc);
+       perr = bnep_connect(nc->session, bnep_conn_cb, bnep_disconn_cb, nc, nc);
        if (perr < 0) {
                error("bnep connect(): %s (%d)", strerror(-perr), -perr);
                goto failed;
        }
 
-       bnep_set_disconnect(nc->session, bnep_disconn_cb, nc);
-
        if (nc->io) {
                g_io_channel_unref(nc->io);
                nc->io = NULL;
@@ -300,21 +298,26 @@ static DBusMessage *local_connect(DBusConnection *conn,
        struct btd_service *service;
        struct network_conn *nc;
        const char *svc;
-       const char *uuid;
        uint16_t id;
        int err;
+       char uuid_str[MAX_LEN_UUID_STR];
+       bt_uuid_t uuid16, uuid128;
 
        if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &svc,
                                                DBUS_TYPE_INVALID) == FALSE)
                return btd_error_invalid_args(msg);
 
        id = get_pan_srv_id(svc);
-       uuid = bnep_uuid(id);
-
-       if (uuid == NULL)
+       bt_uuid16_create(&uuid16, id);
+#ifdef  __TIZEN_PATCH__
+       bt_uuid_to_uuid128(&uuid16, &uuid128);
+#else
+       bt_uuid_to_uuid128(&uuid128, &uuid16);
+#endif
+       if (bt_uuid_to_string(&uuid128, uuid_str, MAX_LEN_UUID_STR) < 0)
                return btd_error_invalid_args(msg);
 
-       service = btd_device_get_service(peer->device, uuid);
+       service = btd_device_get_service(peer->device, uuid_str);
        if (service == NULL)
                return btd_error_not_supported(msg);
 
@@ -455,15 +458,29 @@ static gboolean network_property_get_uuid(const GDBusPropertyTable *property,
 {
        struct network_peer *peer = data;
        struct network_conn *nc;
-       const char *uuid;
+       char uuid_str[MAX_LEN_UUID_STR];
+#ifdef  __TIZEN_PATCH__
+       const char *uuid = uuid_str;
+#endif
+       bt_uuid_t uuid16, uuid128;
 
        nc = find_connection_by_state(peer->connections, CONNECTED);
        if (nc == NULL)
                return FALSE;
 
-       uuid = bnep_uuid(nc->id);
+       bt_uuid16_create(&uuid16, nc->id);
+#ifdef  __TIZEN_PATCH__
+       bt_uuid_to_uuid128(&uuid16, &uuid128);
+#else
+       bt_uuid_to_uuid128(&uuid128, &uuid16);
+#endif
+       bt_uuid_to_string(&uuid128, uuid_str, MAX_LEN_UUID_STR);
 
+#ifdef  __TIZEN_PATCH__
        dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &uuid);
+#else
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &uuid_str);
+#endif
 
        return TRUE;
 }
index 4f13902..2450fbe 100644 (file)
@@ -47,6 +47,7 @@
 #include "src/log.h"
 #include "src/error.h"
 #include "src/sdpd.h"
+#include "src/shared/util.h"
 
 #include "bnep.h"
 #include "server.h"
@@ -118,14 +119,38 @@ static struct network_server *find_server(GSList *list, uint16_t id)
 static struct network_server *find_server_by_uuid(GSList *list,
                                                        const char *uuid)
 {
-       for (; list; list = list->next) {
-               struct network_server *ns = list->data;
+       bt_uuid_t srv_uuid, bnep_uuid;
 
-               if (strcasecmp(uuid, bnep_uuid(ns->id)) == 0)
-                       return ns;
+       if (!bt_string_to_uuid(&srv_uuid, uuid)) {
+               for (; list; list = list->next) {
+                       struct network_server *ns = list->data;
 
-               if (strcasecmp(uuid, bnep_name(ns->id)) == 0)
-                       return ns;
+                       bt_uuid16_create(&bnep_uuid, ns->id);
+
+                       /* UUID value compare */
+                       if (!bt_uuid_cmp(&srv_uuid, &bnep_uuid))
+                               return ns;
+               }
+       } else {
+               for (; list; list = list->next) {
+                       struct network_server *ns = list->data;
+
+                       /* String value compare */
+                       switch (ns->id) {
+                       case BNEP_SVC_PANU:
+                               if (!strcasecmp(uuid, "panu"))
+                                       return ns;
+                               break;
+                       case BNEP_SVC_NAP:
+                               if (!strcasecmp(uuid, "nap"))
+                                       return ns;
+                               break;
+                       case BNEP_SVC_GN:
+                               if (!strcasecmp(uuid, "gn"))
+                                       return ns;
+                               break;
+                       }
+               }
        }
 
        return NULL;
@@ -373,12 +398,16 @@ static gboolean server_disconnected_cb(GIOChannel *chan,
 static gboolean bnep_setup(GIOChannel *chan,
                        GIOCondition cond, gpointer user_data)
 {
+       const uint8_t bt_base[] = { 0x00, 0x00, 0x10, 0x00, 0x80, 0x00,
+                                       0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB };
        struct network_adapter *na = user_data;
        struct network_server *ns;
        uint8_t packet[BNEP_MTU];
        struct bnep_setup_conn_req *req = (void *) packet;
-       uint16_t src_role, dst_role, rsp = BNEP_CONN_NOT_ALLOWED;
+       uint16_t dst_role = 0;
+       uint32_t val;
        int n, sk;
+       char *bridge = NULL;
 
        if (cond & G_IO_NVAL)
                return FALSE;
@@ -390,59 +419,64 @@ static gboolean bnep_setup(GIOChannel *chan,
 
        sk = g_io_channel_unix_get_fd(chan);
 
+#ifdef  __TIZEN_PATCH__
+       /*
+        * BNEP_SETUP_CONNECTION_REQUEST_MSG should be read and left in case
+        * of kernel setup connection msg handling.
+        */
+       n = recv(sk, packet, sizeof(packet), MSG_PEEK);
+#else
        /* Reading BNEP_SETUP_CONNECTION_REQUEST_MSG */
        n = read(sk, packet, sizeof(packet));
+#endif
        if (n < 0) {
                error("read(): %s(%d)", strerror(errno), errno);
                return FALSE;
        }
 
-       /* Highest known Control command ID
-        * is BNEP_FILTER_MULT_ADDR_RSP = 0x06 */
-       if (req->type == BNEP_CONTROL &&
-                               req->ctrl > BNEP_FILTER_MULT_ADDR_RSP) {
-               uint8_t pkt[3];
-
-               pkt[0] = BNEP_CONTROL;
-               pkt[1] = BNEP_CMD_NOT_UNDERSTOOD;
-               pkt[2] = req->ctrl;
-
-               send(sk, pkt, sizeof(pkt), 0);
-
+       /*
+        * Initial received data packet is BNEP_SETUP_CONNECTION_REQUEST_MSG
+        * minimal size of this frame is 3 octets: 1 byte of BNEP Type +
+        * 1 byte of BNEP Control Type + 1 byte of BNEP services UUID size.
+        */
+       if (n < 3) {
+               error("To few setup connection request data received");
                return FALSE;
        }
 
-       if (req->type != BNEP_CONTROL || req->ctrl != BNEP_SETUP_CONN_REQ)
-               return FALSE;
-
-       rsp = bnep_setup_decode(req, &dst_role, &src_role);
-       if (rsp != BNEP_SUCCESS)
-               goto reply;
+       switch (req->uuid_size) {
+       case 2:
+               dst_role = get_be16(req->service);
+               break;
+       case 16:
+               if (memcmp(&req->service[4], bt_base, sizeof(bt_base)) != 0)
+                       break;
 
-       rsp = BNEP_CONN_NOT_ALLOWED;
+               /* Intentional no-brake */
 
-       ns = find_server(na->servers, dst_role);
-       if (!ns) {
-               error("Server unavailable: (0x%x)", dst_role);
-               goto reply;
-       }
+       case 4:
+               val = get_be32(req->service);
+               if (val > 0xffff)
+                       break;
 
-       if (!ns->record_id) {
-               error("Service record not available");
-               goto reply;
+               dst_role = val;
+               break;
+       default:
+               break;
        }
 
-       if (!ns->bridge) {
-               error("Bridge interface not configured");
-               goto reply;
-       }
+       ns = find_server(na->servers, dst_role);
+       if (!ns || !ns->record_id || !ns->bridge)
+               error("Server error, bridge not initialized: (0x%x)", dst_role);
+       else
+               bridge = ns->bridge;
 
        strncpy(na->setup->dev, BNEP_INTERFACE, 16);
        na->setup->dev[15] = '\0';
 
-       if (bnep_server_add(sk, dst_role, ns->bridge, na->setup->dev,
-                                                       &na->setup->dst) < 0)
-               goto reply;
+       if (bnep_server_add(sk, bridge, na->setup->dev, &na->setup->dst,
+                                                       packet, n) < 0)
+               error("BNEP server cannot be added");
 
 #ifdef  __TIZEN_PATCH__
 {
@@ -470,11 +504,6 @@ static gboolean bnep_setup(GIOChannel *chan,
 
        na->setup = NULL;
 
-       rsp = BNEP_SUCCESS;
-
-reply:
-       bnep_send_ctrl_rsp(sk, BNEP_CONTROL, BNEP_SETUP_CONN_RSP, rsp);
-
        return FALSE;
 }
 
@@ -908,10 +937,10 @@ int server_register(struct btd_adapter *adapter, uint16_t id)
                goto done;
 
 #ifndef  __TIZEN_PATCH__
-       if (!g_dbus_register_interface(btd_get_dbus_connection(),
-                                       path, NETWORK_SERVER_INTERFACE,
-                                       server_methods, NULL, NULL,
-                                       na, path_unregister)) {
+       if (!g_dbus_register_interface(btd_get_dbus_connection(), path,
+                                               NETWORK_SERVER_INTERFACE,
+                                               server_methods, NULL, NULL, na,
+                                               path_unregister)) {
                error("D-Bus failed to register %s interface",
                                                NETWORK_SERVER_INTERFACE);
                server_free(ns);
old mode 100644 (file)
new mode 100755 (executable)
index 5872799..ace7e2a
@@ -74,6 +74,7 @@
 #include "attrib/gatt.h"
 #include "attrib-server.h"
 #include "gatt-database.h"
+#include "advertising.h"
 #include "eir.h"
 
 #ifdef __TIZEN_PATCH__
@@ -194,6 +195,13 @@ struct adv_info {
        int slot_id;    /* Reservied slot id is 0 (Single adv) */
        bool status;            /* Advertising status */
 };
+
+static GSList *read_requests = NULL;
+
+struct le_data_length_read_request {
+       struct btd_adapter *adapter;
+       DBusMessage *msg;
+};
 #endif
 
 struct btd_adapter {
@@ -227,6 +235,9 @@ struct btd_adapter {
        bool le_privacy_enabled;        /* whether LE Privacy feature enabled */
        char local_irk[MGMT_IRK_SIZE];  /* adapter local IRK */
        uint8_t disc_type;
+       bool ipsp_intialized;           /* Ipsp Initialization state */
+       struct le_data_length_read_handler *read_handler;
+       struct le_data_length_read_default_data_length_handler *def_read_handler;
 #endif
 
        bool discovering;               /* discovering property state */
@@ -250,6 +261,7 @@ struct btd_adapter {
        sdp_list_t *services;           /* Services associated to adapter */
 
        struct btd_gatt_database *database;
+       struct btd_advertising *adv_manager;
 
        gboolean initialized;
 #ifdef __TIZEN_PATCH__
@@ -287,9 +299,11 @@ struct btd_adapter {
 
        unsigned int pair_device_id;
        guint pair_device_timeout;
+
        unsigned int db_id;             /* Service event handler for GATT db */
 #ifdef __TIZEN_PATCH__
        guint private_addr_timeout;
+       uint8_t central_rpa_res_support;
 #endif
        bool is_default;                /* true if adapter is default one */
 };
@@ -301,6 +315,11 @@ enum {
        ENABLE_PRIVACY,
        GEN_IRK_THEN_ENABLE_PRIVACY
 };
+
+enum {
+       DEINIT_6LOWPAN,
+       INIT_6LOWPAN
+};
 #endif
 
 static struct btd_adapter *btd_adapter_lookup(uint16_t index)
@@ -1216,6 +1235,13 @@ static void adapter_service_insert(struct btd_adapter *adapter, sdp_record_t *re
 
        DBG("%s", adapter->path);
 
+#ifdef __TIZEN_PATCH__
+       if (rec == NULL) {
+               DBG("record is NULL return");
+               return;
+       }
+#endif
+
        /* skip record without a browse group */
        if (sdp_get_browse_groups(rec, &browse_list) < 0) {
                DBG("skipping record without browse group");
@@ -1314,6 +1340,7 @@ static void service_auth_cancel(struct service_auth *auth)
 
        g_free(auth);
 }
+
 #ifdef __TIZEN_PATCH__
 void btd_adapter_unpair_device(struct btd_adapter *adapter,
                                struct btd_device *dev)
@@ -2546,14 +2573,14 @@ static int set_adv_data_device_name(uint8_t *adv_data, int adv_len, char *name)
                        for (j = i; j < adv_len - 2; j++)
                                adv_data[j] = data[j + 2];
 
-                       adv_data[j] = name_len + 1;
                        if (name_len > ADV_DATA_MAX_LENGTH - adv_len) {
                                adv_data[j + 1] = EIR_NAME_SHORT;
-                               memcpy(adv_data + j + 2, name, ADV_DATA_MAX_LENGTH - adv_len);
+                               name_len = ADV_DATA_MAX_LENGTH - adv_len;
                        } else {
                                adv_data[j + 1] = EIR_NAME_COMPLETE;
-                               memcpy(adv_data + j + 2, name, name_len);
                        }
+                       adv_data[j] = name_len + 1;
+                       memcpy(adv_data + j + 2, name, name_len);
 
                        g_free(data);
                        return adv_len + name_len;
@@ -2960,12 +2987,6 @@ static DBusMessage *adapter_set_advertising_data(DBusConnection *conn,
                        return btd_error_failed(msg, "set advertising data failed");
                }
        } else {
-               if(adv_len > sizeof(cp)) {
-                       g_free(adv_data);
-                       DBG("Error: overrun advertising data length");
-                       return btd_error_failed(msg, "Overrun advertising data length");
-               }
-
                memcpy(&cp, adv_data, adv_len);
 
                if (mgmt_send(adapter->mgmt, MGMT_OP_SET_ADVERTISING_DATA,
@@ -3219,12 +3240,6 @@ static DBusMessage *adapter_set_scan_rsp_data(DBusConnection *conn,
                        return btd_error_failed(msg, "set advertising data failed");
                }
        } else {
-               if(adv_len > sizeof(cp)) {
-                       g_free(adv_data);
-                       DBG("Error: overrun scan response data length");
-                       return btd_error_failed(msg, "Overrun scan response data length");
-               }
-
                memcpy(&cp, adv_data, adv_len);
 
                if (mgmt_send(adapter->mgmt, MGMT_OP_SET_SCAN_RSP_DATA,
@@ -3584,7 +3599,7 @@ static  void adapter_get_adv_tx_power(void *data)
        return;
 }
 
-#ifdef __BROADCOM_PATCH__
+//#ifdef __BROADCOM_PATCH__
 static DBusMessage *set_wbs_parameters(DBusConnection *conn,
                                DBusMessage *msg, void *data)
 {
@@ -3669,6 +3684,358 @@ static DBusMessage *set_nb_parameters(DBusConnection *conn,
 
        return dbus_message_new_method_return(msg);
 }
+
+#ifdef __TIZEN_PATCH__
+void btd_adapter_set_read_le_data_length_handler(
+                       struct btd_adapter *adapter,
+                       struct le_data_length_read_handler *handler)
+{
+       adapter->read_handler = handler;
+}
+
+static void le_read_maximum_data_length_return_param_complete(
+                       uint8_t status, uint16_t length,
+                       const void *param, void *user_data)
+{
+       struct btd_adapter *adapter = user_data;
+       const struct mgmt_rp_le_read_maximum_data_length *rp = param;
+       uint16_t max_tx_octects, max_tx_time;
+       uint16_t max_rx_octects, max_rx_time;
+
+       if (status != MGMT_STATUS_SUCCESS) {
+               error("le read maximum data length failed: %s (0x%02x)",
+                       mgmt_errstr(status), status);
+               max_tx_octects = 0;
+               max_tx_time =0;
+               max_rx_octects = 0;
+               max_rx_time = 0;
+               return;
+       }
+
+       if (length < sizeof(*rp)) {
+               error("Too small le read maximum data length response");
+               g_free(adapter->read_handler);
+               return;
+       } else {
+               max_tx_octects = rp->max_tx_octets;
+               max_tx_time =rp->max_tx_time;
+               max_rx_octects = rp->max_rx_octets;
+               max_rx_time = rp->max_rx_time;
+       }
+
+       if (!adapter->read_handler ||
+               !adapter->read_handler->read_callback) {
+               g_free(adapter->read_handler);
+               return;
+       }
+
+       adapter->read_handler->read_callback(adapter,
+                       max_tx_octects, max_tx_time,
+                       max_rx_octects, max_rx_time,
+                       adapter->read_handler->user_data);
+
+       g_free(adapter->read_handler);
+       adapter->read_handler = NULL;
+}
+
+int btd_adapter_le_read_maximum_data_length(
+       struct btd_adapter *adapter)
+{
+       if (mgmt_send(adapter->mgmt,
+                        MGMT_OP_LE_READ_MAXIMUM_DATA_LENGTH,
+                        adapter->dev_id, 0, NULL,
+                        le_read_maximum_data_length_return_param_complete,
+                        adapter, NULL) > 0)
+               return 0;
+
+       return -EIO;
+}
+
+static gint read_request_cmp(gconstpointer a, gconstpointer b)
+{
+       const struct le_data_length_read_request *data = a;
+       const struct btd_adapter *adapter = b;
+
+       return data->adapter !=  adapter;
+}
+
+static struct le_data_length_read_request *find_read_le_data_length_request(
+       struct btd_adapter *adapter)
+{
+       GSList *match;
+
+       match = g_slist_find_custom(read_requests, adapter, read_request_cmp);
+
+       if (match)
+               return match->data;
+
+       return NULL;
+}
+
+static void le_read_data_length_complete(
+                       struct btd_adapter *adapter,
+                       uint16_t max_tx_octects, uint16_t max_tx_time,
+                       uint16_t max_rx_octects, uint16_t max_rx_time,
+                       void *user_data)
+{
+       DBusMessage *reply;
+       struct le_data_length_read_request *read_request;
+
+       read_request = find_read_le_data_length_request(adapter);
+       if (!read_request)
+               return;
+
+       reply = g_dbus_create_reply(read_request->msg,
+                               DBUS_TYPE_UINT16, &max_tx_octects,
+                               DBUS_TYPE_UINT16, &max_tx_time,
+                               DBUS_TYPE_UINT16, &max_rx_octects,
+                               DBUS_TYPE_UINT16, &max_rx_time,
+                               DBUS_TYPE_INVALID);
+
+       if (!reply) {
+               btd_error_failed(read_request->msg,
+                                       "Failed to read max data length.");
+               return;
+       }
+
+       read_requests = g_slist_remove(read_requests, read_request);
+       dbus_message_unref(read_request->msg);
+       g_free(read_request);
+
+       if (!g_dbus_send_message(dbus_conn, reply))
+               error("D-Bus send failed");
+}
+
+static DBusMessage *le_read_maximum_data_length(
+                       DBusConnection *conn, DBusMessage *msg,
+                       void *user_data)
+{
+       struct btd_adapter *adapter = user_data;
+       struct le_data_length_read_request *read_request;
+       struct le_data_length_read_handler *handler;
+
+       if (find_read_le_data_length_request(adapter))
+               return btd_error_in_progress(msg);
+
+       if (btd_adapter_le_read_maximum_data_length(adapter))
+               return btd_error_failed(msg, "Unable to read maximum le data length");
+
+       read_request = g_new(struct le_data_length_read_request, 1);
+
+       read_request->msg = dbus_message_ref(msg);
+       read_request->adapter = adapter;
+
+       read_requests = g_slist_append(read_requests, read_request);
+
+       handler = g_new0(struct le_data_length_read_handler, 1);
+
+       handler->read_callback =
+               (read_max_data_length_cb_t)le_read_data_length_complete;
+
+       btd_adapter_set_read_le_data_length_handler(
+                       read_request->adapter, handler);
+
+       return NULL;
+
+}
+
+void le_write_host_suggested_data_length_return_param_complete(
+                       uint8_t status, uint16_t length,
+                       const void *param, void *user_data)
+{
+       if (status != MGMT_STATUS_SUCCESS) {
+               error("le write host suggested data length failed: %s (0x%02x)",
+                       mgmt_errstr(status), status);
+       }
+
+       return;
+}
+
+static DBusMessage *le_write_host_suggested_default_data_length(
+                       DBusConnection *conn, DBusMessage *msg,
+                       void *user_data)
+{
+       struct btd_adapter *adapter = user_data;
+       struct mgmt_cp_le_write_host_suggested_data_length cp;
+       dbus_uint16_t def_tx_Octets;
+       dbus_uint16_t def_tx_time;
+
+       if (!(adapter->current_settings & MGMT_SETTING_POWERED))
+               return btd_error_not_ready(msg);
+
+       if (!dbus_message_get_args(msg, NULL,
+                                       DBUS_TYPE_UINT16, &def_tx_Octets,
+                                       DBUS_TYPE_UINT16, &def_tx_time,
+                                       DBUS_TYPE_INVALID))
+               return btd_error_invalid_args(msg);
+
+       memset(&cp, 0, sizeof(cp));
+       cp.def_tx_octets = def_tx_Octets;
+       cp.def_tx_time = def_tx_time;
+
+       if (mgmt_send(adapter->mgmt,
+                        MGMT_OP_LE_WRITE_HOST_SUGGESTED_DATA_LENGTH,
+                        adapter->dev_id, sizeof(cp), &cp,
+                        le_write_host_suggested_data_length_return_param_complete,
+                        adapter, NULL) > 0)
+               return dbus_message_new_method_return(msg);
+
+       return btd_error_failed(msg, "Unable to write host suggested le data length values");
+}
+
+static void le_read_suggested_default_data_length_return_param_complete(
+                       uint8_t status, uint16_t length,
+                       const void *param, void *user_data)
+{
+       struct btd_adapter *adapter = user_data;
+       const struct mgmt_rp_le_read_host_suggested_data_length *rp = param;
+       uint16_t def_tx_octects, def_tx_time;
+
+       if (status != MGMT_STATUS_SUCCESS) {
+               error("Read host suggested def le data length values failed: %s (0x%02x)",
+                       mgmt_errstr(status), status);
+               def_tx_octects = 0;
+               def_tx_time =0;
+               return;
+       }
+
+       if (length < sizeof(*rp)) {
+               goto done;;
+       } else {
+               def_tx_octects = rp->def_tx_octets;
+               def_tx_time =rp->def_tx_time;
+               DBG("retrieving host suggested data length values %d %d", def_tx_octects, def_tx_time);
+       }
+
+       if (!adapter->def_read_handler)
+               return;
+
+       if(!adapter->def_read_handler->read_callback) {
+               goto done;
+       }
+
+       adapter->def_read_handler->read_callback(adapter,
+                       def_tx_octects, def_tx_time,
+                       adapter->def_read_handler->user_data);
+done:
+       if (adapter->def_read_handler)
+               g_free(adapter->def_read_handler->user_data);
+
+       g_free(adapter->def_read_handler);
+       adapter->def_read_handler = NULL;
+}
+
+int btd_adapter_le_read_suggested_default_data_length(
+       struct btd_adapter *adapter)
+{
+       if (mgmt_send(adapter->mgmt,
+                        MGMT_OP_LE_READ_HOST_SUGGESTED_DATA_LENGTH,
+                        adapter->dev_id, 0, NULL,
+                        le_read_suggested_default_data_length_return_param_complete,
+                        adapter, NULL) > 0) {
+               return 0;
+       }
+
+       return -EIO;
+}
+
+static void le_read_host_suggested_default_length_complete(
+                       struct btd_adapter *adapter,
+                       uint16_t def_tx_octects, uint16_t def_tx_time,
+                       void *user_data)
+{
+       DBusMessage *reply;
+       struct le_data_length_read_request *read_request;
+
+       read_request = find_read_le_data_length_request(adapter);
+       if (!read_request)
+               return;
+
+       reply = g_dbus_create_reply(read_request->msg,
+                       DBUS_TYPE_UINT16, &def_tx_octects,
+                       DBUS_TYPE_UINT16, &def_tx_time,
+                       DBUS_TYPE_INVALID);
+
+       if (!reply) {
+               btd_error_failed(read_request->msg,
+                       "Failed to read host suggested def data length values");
+               return;
+       }
+
+       read_requests = g_slist_remove(read_requests, read_request);
+       dbus_message_unref(read_request->msg);
+       g_free(read_request);
+
+       if (!g_dbus_send_message(dbus_conn, reply))
+               error("D-Bus send failed");
+}
+
+static DBusMessage *le_read_host_suggested_default_data_length(
+                       DBusConnection *conn, DBusMessage *msg,
+                       void *user_data)
+{
+       struct btd_adapter *adapter = user_data;
+       struct le_data_length_read_request *read_request;
+       struct le_data_length_read_default_data_length_handler *handler;
+
+       if (find_read_le_data_length_request(adapter))
+               return btd_error_in_progress(msg);
+
+       if (btd_adapter_le_read_suggested_default_data_length(adapter))
+               return btd_error_failed(msg, "Unable to read host suggested def data length");
+
+       read_request = g_new(struct le_data_length_read_request, 1);
+
+       read_request->msg = dbus_message_ref(msg);
+       read_request->adapter = adapter;
+
+       read_requests = g_slist_append(read_requests, read_request);
+
+       handler = g_new0(struct le_data_length_read_default_data_length_handler, 1);
+
+       handler->read_callback =
+               (read_host_suggested_default_data_length_cb_t)le_read_host_suggested_default_length_complete;
+
+       read_request->adapter->def_read_handler = handler;
+
+       return NULL;
+}
+
+void le_set_data_length_return_param_complete(
+                       uint8_t status, uint16_t length,
+                       const void *param, void *user_data)
+{
+       if (status != MGMT_STATUS_SUCCESS) {
+               error("le_set_data_length failed: %s (0x%02x)",
+                       mgmt_errstr(status), status);
+       }
+
+       return;
+}
+
+int btd_adapter_le_set_data_length(struct btd_adapter *adapter, bdaddr_t *bdaddr,
+                               uint16_t max_tx_octets, uint16_t max_tx_time)
+{
+       struct mgmt_cp_le_set_data_length cp;
+
+       memset(&cp, 0, sizeof(cp));
+
+       bacpy(&cp.bdaddr, bdaddr);
+
+       cp.max_tx_octets = max_tx_octets;
+       cp.max_tx_time = max_tx_time;
+
+       if (mgmt_send(adapter->mgmt, MGMT_OP_LE_SET_DATA_LENGTH,
+                       adapter->dev_id, sizeof(cp), &cp,
+                       le_set_data_length_return_param_complete,
+                       adapter, NULL) > 0)
+               return 0;
+
+       return -EIO;
+}
+
+#endif
+
 static DBusMessage *adapter_set_manufacturer_data(DBusConnection *conn,
                                                DBusMessage *msg, void *data)
 {
@@ -3699,7 +4066,7 @@ static DBusMessage *adapter_set_manufacturer_data(DBusConnection *conn,
 
        return btd_error_failed(msg, "Set manufacturer data failed");
 }
-#endif /* __BROADCOM_PATCH__ */
+//#endif /* __BROADCOM_PATCH__ */
 #endif /* __TIZEN_PATCH__ */
 
 static DBusMessage *stop_discovery(DBusConnection *conn,
@@ -4003,11 +4370,13 @@ static void property_set_mode(struct btd_adapter *adapter, uint32_t setting,
        data->adapter = adapter;
        data->id = id;
 
-#ifdef __TIZEN_PATCH__
+/* Because of timing issue, sometimes pscan / iscan value was wrong. */
+#if 0
+/* #ifdef __TIZEN_PATCH__ */
        /*
-        * Use mgmt_reply to avoid dbus timeout in a state of bonding.
+        * Use mgmt_send_nowait to avoid dbus timeout in a state of bonding.
         */
-       if (mgmt_reply(adapter->mgmt, opcode, adapter->dev_id, len, param,
+       if (mgmt_send_nowait(adapter->mgmt, opcode, adapter->dev_id, len, param,
                                property_set_mode_complete, data, g_free) > 0)
 #else
        if (mgmt_send(adapter->mgmt, opcode, adapter->dev_id, len, param,
@@ -4043,14 +4412,6 @@ static void property_set_powered(const GDBusPropertyTable *property,
                return;
        }
 
-#ifdef __TIZEN_PATCH__
-       if (adapter_le_read_ble_feature_info())
-               g_dbus_emit_property_changed(dbus_conn, adapter->path,
-                       ADAPTER_INTERFACE, "SupportedLEFeatures");
-
-       adapter_get_adv_tx_power(adapter);
-#endif
-
        property_set_mode(adapter, MGMT_SETTING_POWERED, iter, id);
 }
 
@@ -4308,6 +4669,24 @@ static gboolean property_get_supported_le_features(
        return TRUE;
 }
 
+static gboolean property_get_ipsp_init_state(
+                                       const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct btd_adapter *adapter = data;
+       dbus_bool_t ipsp_initialized;
+
+       DBG("property_get_ipsp_init_state called");
+       if (adapter->ipsp_intialized)
+               ipsp_initialized = TRUE;
+       else
+               ipsp_initialized = FALSE;
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN,
+                                       &ipsp_initialized);
+
+       return TRUE;
+}
 #endif
 
 static gboolean property_get_uuids(const GDBusPropertyTable *property,
@@ -4471,6 +4850,152 @@ static DBusMessage *find_device(DBusConnection *conn, DBusMessage *msg,
 
        return reply;
 }
+
+static gboolean adapter_ipsp_connected(struct btd_adapter *adapter)
+{
+       GSList *l, *next;
+
+       DBG("%s", adapter->path);
+
+       for (l = adapter->connections; l != NULL; l = next) {
+               struct btd_device *dev = l->data;
+
+               next = g_slist_next(l);
+
+               if (device_is_ipsp_connected(dev))
+                       return TRUE;
+       }
+
+       return FALSE;
+}
+
+static void adapter_set_ipsp_init_state(struct btd_adapter *adapter, gboolean initialized)
+{
+       if (adapter->ipsp_intialized == initialized)
+               return;
+
+       adapter->ipsp_intialized = initialized;
+
+       DBG("Set Ipsp init state for adapter %s", adapter->path);
+
+       g_dbus_emit_property_changed(dbus_conn, adapter->path,
+                                               ADAPTER_INTERFACE, "IpspInitStateChanged");
+}
+
+static void deinitialize_6lowpan_complete(uint8_t status, uint16_t length,
+       const void *param, void *user_data)
+{
+       struct btd_adapter *adapter = user_data;
+       bool initialized = FALSE;
+
+       if (status != MGMT_STATUS_SUCCESS)
+               error("De-Initialize BT 6lowpan failed for hci%u: %s (0x%02x)",
+                       adapter->dev_id, mgmt_errstr(status), status);
+       else {
+               adapter_set_ipsp_init_state(adapter, initialized);
+               DBG("De-Initialize BT 6lowpan successfully for hci%u",
+                       adapter->dev_id);
+       }
+}
+
+static bool deinitialize_6lowpan(struct btd_adapter *adapter)
+{
+       struct mgmt_cp_enable_6lowpan cp;
+
+       memset(&cp, 0, sizeof(cp));
+
+       cp.enable_6lowpan = DEINIT_6LOWPAN;
+       if (mgmt_send(adapter->mgmt, MGMT_OP_ENABLE_6LOWPAN,
+                       adapter->dev_id, sizeof(cp), &cp,
+                       deinitialize_6lowpan_complete, adapter, NULL) > 0)
+               return true;
+
+       error("Failed to de-initialize BT 6Lowpan for index %u",
+               adapter->dev_id);
+       return false;
+}
+
+static void initialize_6lowpan_complete(uint8_t status, uint16_t length,
+       const void *param, void *user_data)
+{
+       struct btd_adapter *adapter = user_data;
+       bool initialized = TRUE;
+
+       if (status != MGMT_STATUS_SUCCESS)
+               error("Initialize BT 6lowpan failed for hci%u: %s (0x%02x)",
+                       adapter->dev_id, mgmt_errstr(status), status);
+       else {
+               adapter_set_ipsp_init_state(adapter, initialized);
+               DBG("Initialize BT 6lowpan successfully for hci%u",
+                       adapter->dev_id);
+       }
+}
+
+static bool initialize_6lowpan(struct btd_adapter *adapter)
+{
+       struct mgmt_cp_enable_6lowpan cp;
+
+       memset(&cp, 0, sizeof(cp));
+
+       cp.enable_6lowpan = INIT_6LOWPAN;
+       if (mgmt_send(adapter->mgmt, MGMT_OP_ENABLE_6LOWPAN,
+                       adapter->dev_id, sizeof(cp), &cp,
+                       initialize_6lowpan_complete, adapter, NULL) > 0)
+               return true;
+
+       error("Failed to initialize BT 6Lowpan for index %u",
+               adapter->dev_id);
+       return false;
+}
+
+static DBusMessage *adapter_initialize_ipsp(DBusConnection *conn,
+                                       DBusMessage *msg, void *data)
+{
+       struct btd_adapter *adapter = data;
+       dbus_bool_t err;
+
+       DBG("Initialize IPSP");
+
+       if (!(adapter->current_settings & MGMT_SETTING_POWERED))
+               return btd_error_not_ready(msg);
+
+       if (adapter->ipsp_intialized)
+               return btd_error_already_exists(msg);
+
+       /* Enable BT 6lowpan in kernel */
+       err = initialize_6lowpan(adapter);
+
+       if (!err)
+               return btd_error_failed(msg, "Failed to initialize BT 6lowpan");
+
+       return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *adapter_deinitialize_ipsp(DBusConnection *conn,
+                                       DBusMessage *msg, void *data)
+{
+       struct btd_adapter *adapter = data;
+       dbus_bool_t err;
+
+       DBG("De-initialize IPSP");
+
+       if (!(adapter->current_settings & MGMT_SETTING_POWERED))
+               return btd_error_not_ready(msg);
+
+       if (!adapter->ipsp_intialized)
+               return btd_error_not_permitted(msg, "IPSP not initialized");
+
+       if (adapter_ipsp_connected(adapter))
+               return btd_error_not_permitted(msg, "IPSP Client device found connected");
+
+       /* Disable BT 6lowpan in kernel */
+       err = deinitialize_6lowpan(adapter);
+
+       if (!err)
+               return btd_error_failed(msg, "Failed to deinitialize BT 6lowpan");
+
+       return dbus_message_new_method_return(msg);
+}
 #endif
 
 static DBusMessage *remove_device(DBusConnection *conn,
@@ -4494,7 +5019,7 @@ static DBusMessage *remove_device(DBusConnection *conn,
 
        device = list->data;
 
-       btd_device_set_temporary(device, TRUE);
+       btd_device_set_temporary(device, true);
 
        if (!btd_device_is_connected(device)) {
                btd_adapter_remove_device(adapter, device);
@@ -4546,7 +5071,6 @@ static const GDBusMethodTable adapter_methods[] = {
                                { "interval", "u" },
                                { "window", "u" }), NULL,
                        adapter_le_set_scan_params) },
-#ifdef __TIZEN_PATCH__ /* scan filter method - refered bt_gatt_client.h */
        { GDBUS_ASYNC_METHOD("scan_filter_param_setup",
                        GDBUS_ARGS({ "client_if", "i" }, { "action", "i" },
                                { "filt_index", "i" }, { "feat_seln", "i"},
@@ -4570,7 +5094,12 @@ static const GDBusMethodTable adapter_methods[] = {
        { GDBUS_ASYNC_METHOD("scan_filter_enable",
                        GDBUS_ARGS({ "client_if", "i" }, { "enable", "b" }), NULL,
                        adapter_le_scan_filter_enable) },
-#endif /* scan filter method */
+       { GDBUS_METHOD("InitializeIpsp",
+                       NULL, NULL,
+                       adapter_initialize_ipsp) },
+       { GDBUS_METHOD("DeinitializeIpsp",
+                       NULL, NULL,
+                       adapter_deinitialize_ipsp) },
        { GDBUS_METHOD("SetScanRespData",
                        GDBUS_ARGS({ "value", "ay" },
                                { "slot_id", "i" }), NULL,
@@ -4607,7 +5136,7 @@ static const GDBusMethodTable adapter_methods[] = {
                        GDBUS_ARGS({ "address", "s" }),
                        GDBUS_ARGS({ "device", "o" }),
                        find_device) },
-#ifdef __BROADCOM_PATCH__
+#ifdef __TIZEN_PATCH__
        { GDBUS_METHOD("SetWbsParameters",
                        GDBUS_ARGS({ "role", "s" }, { "bt_address", "s" }),
                        NULL,
@@ -4626,6 +5155,18 @@ static const GDBusMethodTable adapter_methods[] = {
 #endif
        { GDBUS_ASYNC_METHOD("RemoveDevice",
                        GDBUS_ARGS({ "device", "o" }), NULL, remove_device) },
+#ifdef __TIZEN_PATCH__
+       { GDBUS_ASYNC_METHOD("LEReadMaximumDataLength", NULL,
+                       GDBUS_ARGS({"maxTxOctets", "q" }, { "maxTxTime", "q" },
+                               {"maxRxOctets", "q" }, { "maxRxTime", "q" }),
+                       le_read_maximum_data_length)},
+       { GDBUS_ASYNC_METHOD("LEWriteHostSuggestedDataLength",
+                       GDBUS_ARGS({"def_tx_octets", "q" }, { "def_tx_time", "q" }), NULL,
+                       le_write_host_suggested_default_data_length)},
+       { GDBUS_ASYNC_METHOD("LEReadHostSuggestedDataLength", NULL,
+                       GDBUS_ARGS({"def_tx_octets", "q" }, { "def_tx_time", "q" }),
+                       le_read_host_suggested_default_data_length)},
+#endif
        { }
 };
 
@@ -4681,6 +5222,7 @@ static const GDBusPropertyTable adapter_properties[] = {
                                        property_set_connectable },
        { "Version", "s", property_get_version },
        { "SupportedLEFeatures", "as", property_get_supported_le_features},
+       { "IpspInitStateChanged", "b", property_get_ipsp_init_state},
 #endif
 
        { }
@@ -5289,7 +5831,7 @@ static void load_devices(struct btd_adapter *adapter)
                if (!device)
                        goto free;
 
-               btd_device_set_temporary(device, FALSE);
+               btd_device_set_temporary(device, false);
                adapter->devices = g_slist_append(adapter->devices, device);
 
                /* TODO: register services from pre-loaded list of primaries */
@@ -5560,6 +6102,13 @@ const char *btd_adapter_get_name(struct btd_adapter *adapter)
        return NULL;
 }
 
+#ifdef __TIZEN_PATCH__
+uint8_t btd_adapter_get_rpa_res_support_value(struct btd_adapter *adapter)
+{
+       return adapter->central_rpa_res_support;
+}
+#endif
+
 int adapter_connect_list_add(struct btd_adapter *adapter,
                                        struct btd_device *device)
 {
@@ -5858,6 +6407,14 @@ void adapter_auto_connect_remove(struct btd_adapter *adapter,
 
 static void adapter_start(struct btd_adapter *adapter)
 {
+#ifdef __TIZEN_PATCH__
+       if (adapter_le_read_ble_feature_info())
+               g_dbus_emit_property_changed(dbus_conn, adapter->path,
+                       ADAPTER_INTERFACE, "SupportedLEFeatures");
+
+       adapter_get_adv_tx_power(adapter);
+#endif
+
        g_dbus_emit_property_changed(dbus_conn, adapter->path,
                                                ADAPTER_INTERFACE, "Powered");
 
@@ -6932,6 +7489,8 @@ static struct btd_adapter *btd_adapter_new(uint16_t index)
                DBG("LE Privacy is enabled.");
        else
                DBG("LE Privacy is disabled.");
+
+       adapter->central_rpa_res_support = 0x00;
 #endif
        adapter->auths = g_queue_new();
 
@@ -6981,6 +7540,9 @@ static void adapter_remove(struct btd_adapter *adapter)
        btd_adapter_gatt_server_stop(adapter);
 #endif
 
+       btd_advertising_manager_destroy(adapter->adv_manager);
+       adapter->adv_manager = NULL;
+
        g_slist_free(adapter->pin_callbacks);
        adapter->pin_callbacks = NULL;
 
@@ -7196,6 +7758,7 @@ static void update_found_devices(struct btd_adapter *adapter,
        }
 
        device_set_last_addr_type(dev, bdaddr_type);
+       device_set_ipsp_connected(dev, FALSE);
 #else
        if (device_is_temporary(dev) && !adapter->discovery_list) {
                eir_data_free(&eir_data);
@@ -7211,18 +7774,22 @@ static void update_found_devices(struct btd_adapter *adapter,
 
        /* Report an unknown name to the kernel even if there is a short name
         * known, but still update the name with the known short name. */
+       name_known = device_name_known(dev);
+
+       if (eir_data.name && (eir_data.name_complete || !name_known))
+               btd_device_device_set_name(dev, eir_data.name);
+
 #ifdef __TIZEN_PATCH__
+       /* As this logic,  (eir_data.name_complete || !name_known) is always true.
+           So some abnormal UI bug occurs. Such like complete name display and
+           next time short name display.
+       */
        if (eir_data.name_complete)
                name_known = device_name_known(dev);
        else
                name_known = false;
-#else
-       name_known = device_name_known(dev);
 #endif
 
-       if (eir_data.name && (eir_data.name_complete || !name_known))
-               btd_device_device_set_name(dev, eir_data.name);
-
        if (eir_data.class != 0)
                device_set_class(dev, eir_data.class);
 
@@ -7602,9 +8169,6 @@ static gboolean process_auth_queue(gpointer user_data)
                if (auth->svc_id > 0)
                        return FALSE;
 
-/* The below patch should be removed after we provide the API
- * to control autorization for the specific UUID.
- */
                if (device_is_trusted(device) == TRUE) {
                        auth->cb(NULL, auth->user_data);
                        goto next;
@@ -8329,6 +8893,67 @@ static void multi_adv_state_change_callback(uint16_t index, uint16_t length,
                        ev->state_change_reason == 0)
                adapter_le_enable_multi_adv(TRUE, ev->adv_instance);
 }
+
+static void bt_6lowpan_conn_state_change_callback(uint16_t index, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       const struct mgmt_ev_6lowpan_conn_state_changed *ev = param;
+       struct btd_adapter *adapter = user_data;
+       struct btd_device *device;
+       char addr[18];
+       gboolean connected = 0;
+
+       if (length < sizeof(*ev)) {
+               error("Too small device connected event");
+               return;
+       }
+
+       ba2str(&ev->addr.bdaddr, addr);
+
+       DBG("hci%u device %s", index, addr);
+
+       device = btd_adapter_find_device(adapter, &ev->addr.bdaddr,
+                                                               ev->addr.type);
+       if (!device) {
+               error("Unable to get device object for %s", addr);
+               return;
+       }
+
+       if (ev->connected)
+               connected = TRUE;
+       else
+               connected = FALSE;
+
+       device_set_ipsp_connected(device, connected);
+}
+
+static void bt_le_data_length_changed_callback(uint16_t index, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       const struct mgmt_ev_le_data_length_changed *ev = param;
+       struct btd_adapter *adapter = user_data;
+       struct btd_device *device;
+       char addr[18];
+
+       if (length < sizeof(*ev)) {
+               error("Too small data length changed event");
+               return;
+       }
+
+       ba2str(&ev->addr.bdaddr, addr);
+
+       DBG("hci%u device %s", index, addr);
+
+       device = btd_adapter_find_device(adapter, &ev->addr.bdaddr,
+                                                               ev->addr.type);
+       if (!device) {
+               error("Unable to get device object for %s", addr);
+               return;
+       }
+
+       device_le_data_length_changed(device, ev->max_tx_octets, ev->max_tx_time,
+               ev->max_rx_octets, ev->max_rx_time);
+}
 #endif
 
 struct btd_adapter_pin_cb_iter *btd_adapter_pin_cb_iter_new(
@@ -8855,9 +9480,6 @@ static void new_link_key_callback(uint16_t index, uint16_t length,
                                                                key->pin_len);
 
                device_set_bonded(device, BDADDR_BREDR);
-
-               if (device_is_temporary(device))
-                       btd_device_set_temporary(device, FALSE);
        }
 
        bonding_complete(adapter, &addr->bdaddr, addr->type, 0);
@@ -8973,9 +9595,6 @@ static void new_long_term_key_callback(uint16_t index, uint16_t length,
                                        key->type, key->enc_size, ediv, rand);
 
                device_set_bonded(device, addr->type);
-
-               if (device_is_temporary(device))
-                       btd_device_set_temporary(device, FALSE);
        }
 
        bonding_complete(adapter, &addr->bdaddr, addr->type, 0);
@@ -9076,8 +9695,7 @@ static void new_csrk_callback(uint16_t index, uint16_t length,
        store_csrk(bdaddr, &key->addr.bdaddr, key->addr.type, key->val, 0,
                                                                key->type);
 
-       if (device_is_temporary(device))
-               btd_device_set_temporary(device, FALSE);
+       btd_device_set_temporary(device, false);
 }
 
 static void store_irk(struct btd_adapter *adapter, const bdaddr_t *peer,
@@ -9164,8 +9782,7 @@ static void new_irk_callback(uint16_t index, uint16_t length,
 
        store_irk(adapter, &addr->bdaddr, addr->type, irk->val);
 
-       if (device_is_temporary(device))
-               btd_device_set_temporary(device, FALSE);
+       btd_device_set_temporary(device, false);
 }
 
 static void store_conn_param(struct btd_adapter *adapter, const bdaddr_t *peer,
@@ -9338,12 +9955,14 @@ static void read_local_oob_data_complete(uint8_t status, uint16_t length,
                                                mgmt_errstr(status), status);
                hash = NULL;
                randomizer = NULL;
+#ifndef __TIZEN_PATCH__
        } else if (length < sizeof(*rp)) {
                error("Too small read local OOB data response");
                return;
+#endif
        } else {
-               hash = rp->hash;
-               randomizer = rp->randomizer;
+               hash = rp->hash192;
+               randomizer = rp->rand192;
        }
 
        if (!adapter->oob_handler || !adapter->oob_handler->read_local_cb)
@@ -9442,7 +10061,6 @@ static int set_did(struct btd_adapter *adapter, uint16_t vendor,
        return -EIO;
 }
 
-#ifndef __TIZEN_PATCH__
 static void services_modified(struct gatt_db_attribute *attrib, void *user_data)
 {
        struct btd_adapter *adapter = user_data;
@@ -9450,14 +10068,11 @@ static void services_modified(struct gatt_db_attribute *attrib, void *user_data)
        g_dbus_emit_property_changed(dbus_conn, adapter->path,
                                                ADAPTER_INTERFACE, "UUIDs");
 }
-#endif
 
 static int adapter_register(struct btd_adapter *adapter)
 {
        struct agent *agent;
-#ifndef __TIZEN_PATCH__
        struct gatt_db *db;
-#endif
 
        if (powering_down)
                return -EBUSY;
@@ -9492,7 +10107,6 @@ static int adapter_register(struct btd_adapter *adapter)
                agent_unref(agent);
        }
 
-#ifndef __TIZEN_PATCH__
        adapter->database = btd_gatt_database_new(adapter);
        if (!adapter->database) {
                error("Failed to create GATT database for adapter");
@@ -9504,10 +10118,23 @@ static int adapter_register(struct btd_adapter *adapter)
        adapter->db_id = gatt_db_register(db, services_modified,
                                                        services_modified,
                                                        adapter, NULL);
-#else
+
+/* Disable Old GATT Server */
+#if 0
        btd_adapter_gatt_server_start(adapter);
 #endif
 
+       /* Don't start advertising managers on non-LE controllers. */
+       if (adapter->supported_settings & MGMT_SETTING_LE) {
+               adapter->adv_manager = btd_advertising_manager_new(adapter);
+
+               /* LEAdvertisingManager1 is experimental so optional */
+               if (!adapter->adv_manager)
+                       error("Failed to register LEAdvertisingManager1 "
+                                               "interface for adapter");
+       } else {
+               info("Not starting LEAdvertisingManager, LE not supported");
+       }
        load_config(adapter);
        fix_storage(adapter);
        load_drivers(adapter);
@@ -9862,6 +10489,44 @@ static bool set_privacy(struct btd_adapter *adapter, bool privacy)
 
        return false;
 }
+
+int btd_adapter_connect_ipsp(struct btd_adapter *adapter,
+                                               const bdaddr_t *bdaddr,
+                                               uint8_t bdaddr_type)
+
+{
+       struct mgmt_cp_connect_6lowpan cp;
+
+       memset(&cp, 0, sizeof(cp));
+       bacpy(&cp.addr.bdaddr, bdaddr);
+       cp.addr.type = bdaddr_type;
+
+       if (mgmt_send(adapter->mgmt, MGMT_OP_CONNECT_6LOWPAN,
+                               adapter->dev_id, sizeof(cp), &cp,
+                               NULL, NULL, NULL) > 0)
+               return 0;
+
+       return -EIO;
+}
+
+int btd_adapter_disconnect_ipsp(struct btd_adapter *adapter,
+                                               const bdaddr_t *bdaddr,
+                                               uint8_t bdaddr_type)
+
+{
+       struct mgmt_cp_disconnect_6lowpan cp;
+
+       memset(&cp, 0, sizeof(cp));
+       bacpy(&cp.addr.bdaddr, bdaddr);
+       cp.addr.type = bdaddr_type;
+
+       if (mgmt_send(adapter->mgmt, MGMT_OP_DISCONNECT_6LOWPAN,
+                               adapter->dev_id, sizeof(cp), &cp,
+                               NULL, NULL, NULL) > 0)
+               return 0;
+
+       return -EIO;
+}
 #endif
 
 static void clear_devices_complete(uint8_t status, uint16_t length,
@@ -9983,9 +10648,17 @@ static void read_info_complete(uint8_t status, uint16_t length,
                break;
        }
 
-#if 0
        if (missing_settings & MGMT_SETTING_SECURE_CONN)
                set_mode(adapter, MGMT_OP_SET_SECURE_CONN, 0x01);
+       if (main_opts.fast_conn &&
+                       (missing_settings & MGMT_SETTING_FAST_CONNECTABLE))
+               set_mode(adapter, MGMT_OP_SET_FAST_CONNECTABLE, 0x01);
+
+#ifdef __TIZEN_PATCH__
+       /* Set the RPA resolution value to '1' if privacy is supported */
+       if (adapter->le_privacy_enabled &&
+                       adapter->supported_settings & MGMT_SETTING_PRIVACY)
+               adapter->central_rpa_res_support = 0x01;
 #endif
 
        err = adapter_register(adapter);
@@ -10156,6 +10829,16 @@ static void read_info_complete(uint8_t status, uint16_t length,
                                adapter->dev_id,
                                multi_adv_state_change_callback,
                                adapter, NULL);
+
+       mgmt_register(adapter->mgmt, MGMT_EV_6LOWPAN_CONN_STATE_CHANGED,
+                                               adapter->dev_id,
+                                               bt_6lowpan_conn_state_change_callback,
+                                               adapter, NULL);
+
+       mgmt_register(adapter->mgmt, MGMT_EV_LE_DATA_LENGTH_CHANGED,
+                                               adapter->dev_id,
+                                               bt_le_data_length_changed_callback,
+                                               adapter, NULL);
 #endif
 
        set_dev_class(adapter);
old mode 100644 (file)
new mode 100755 (executable)
index 84e33a0..69cf290
@@ -267,4 +267,32 @@ void btd_adapter_set_le_auto_connect(struct btd_adapter *adapter, gboolean auto_
 gboolean btd_adapter_disable_le_auto_connect(struct btd_adapter *adapter);
 void adapter_check_version(struct btd_adapter *adapter, uint8_t hci_ver);
 GSList *btd_adapter_get_connections(struct btd_adapter *adapter);
+int btd_adapter_connect_ipsp(struct btd_adapter *adapter,
+                                               const bdaddr_t *bdaddr,
+                                               uint8_t bdaddr_type);
+int btd_adapter_disconnect_ipsp(struct btd_adapter *adapter,
+                                               const bdaddr_t *bdaddr,
+                                               uint8_t bdaddr_type);
+
+typedef void (*read_max_data_length_cb_t) (struct btd_adapter *adapter,
+                                       const uint16_t max_txOctects,
+                                       const uint16_t max_txTime,
+                                       const uint16_t max_rxOctects,
+                                       const uint16_t max_rxTime,
+                                       void *user_data);
+
+struct le_data_length_read_handler {
+       read_max_data_length_cb_t read_callback;
+       void *user_data;
+};
+
+typedef void (*read_host_suggested_default_data_length_cb_t) (struct btd_adapter *adapter,
+                                       const uint16_t def_txOctects,
+                                       const uint16_t def_txTime,
+                                       void *user_data);
+
+struct le_data_length_read_default_data_length_handler {
+       read_host_suggested_default_data_length_cb_t read_callback;
+       void *user_data;
+};
 #endif
index 440938c..a18d3df 100644 (file)
@@ -1,5 +1,4 @@
 #ifdef __TIZEN_PATCH__
-#ifdef __BROADCOM_PATCH__
 
 #include <errno.h>
 
@@ -648,5 +647,4 @@ gboolean adapter_le_clear_scan_filter_data(int client_if, int filter_index)
        return TRUE;
 }
 
-#endif /* __BROADCOM_PATCH__ */
 #endif /* __TIZEN_PATCH__ */
index 6850e01..f06eac1 100644 (file)
@@ -128,8 +128,6 @@ typedef struct {
        uint8_t service_data_len;
 }adapter_le_service_data_params_t;
 
-#ifdef __BROADCOM_PATCH__
-
 /*****************************************************************************
 **  Defentions for HCI Error Codes that are past in the events
 */
@@ -427,35 +425,4 @@ gboolean adapter_le_set_scan_filter_data(int client_if, int action,
                                                        int data_len, uint8_t *p_data,
                                                        int mask_len, uint8_t *p_mask);
 gboolean adapter_le_clear_scan_filter_data(int client_if, int filter_index);
-#else /* __BROADCOM_PATCH__ */
-
-gboolean adapter_le_read_ble_feature_info(void) { return FALSE; }
-gboolean adapter_le_is_supported_multi_advertising(void)  { return FALSE; }
-gboolean adapter_le_is_supported_offloading(void) { return FALSE; }
-int adapter_le_get_max_adv_instance(void) { return 0; }
-int adapter_le_get_scan_filter_size(void) { return 0; }
-
-gboolean adapter_le_set_multi_adv_params (adapter_le_adv_inst_info_t *p_inst,
-                                       adapter_le_adv_param_t *p_params) { return FALSE; }
-gboolean adapter_le_set_multi_adv_data(uint8_t inst_id, gboolean is_scan_rsp,
-                                       uint8_t data_len, uint8_t *p_data) { return FALSE; }
-gboolean adapter_le_enable_multi_adv (gboolean enable, uint8_t inst_id)
-                                       { return FALSE; }
-
-gboolean adapter_le_enable_scan_filtering (gboolean enable) { return FALSE; }
-gboolean adapter_le_set_scan_filter_params(adapter_le_scan_filter_param_t *params)
-                                       { return FALSE; }
-gboolean adapter_le_set_scan_filter_data(int client_if, int action,
-                                                       int filt_type, int filter_index,
-                                                       int company_id,
-                                                       int company_id_mask,
-                                                       int uuid_len, uint8_t *p_uuid,
-                                                       int uuid_mask_len, uint8_t *p_uuid_mask,
-                                                       gchar *string, int addr_type,
-                                                       int data_len, uint8_t *p_data,
-                                                       int mask_len, uint8_t *p_mask)
-                                       { return FALSE; }
-gboolean adapter_le_clear_scan_filter_data(int client_if, int filter_index)
-                                       { return FALSE; }
-#endif /* __BROADCOM_PATCH__ */
 #endif /* __TIZEN_PATCH__ */
diff --git a/src/advertising.c b/src/advertising.c
new file mode 100644 (file)
index 0000000..04492f7
--- /dev/null
@@ -0,0 +1,399 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2015  Google Inc.
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ */
+
+#include "advertising.h"
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <dbus/dbus.h>
+#include <gdbus/gdbus.h>
+
+#include "lib/bluetooth.h"
+#include "lib/sdp.h"
+
+#include "adapter.h"
+#include "dbus-common.h"
+#include "error.h"
+#include "log.h"
+#include "src/shared/queue.h"
+#include "src/shared/util.h"
+
+#define LE_ADVERTISING_MGR_IFACE "org.bluez.LEAdvertisingManager1"
+#define LE_ADVERTISEMENT_IFACE "org.bluez.LEAdvertisement1"
+
+struct btd_advertising {
+       struct btd_adapter *adapter;
+       struct queue *ads;
+};
+
+#define AD_TYPE_BROADCAST 0
+#define AD_TYPE_PERIPHERAL 1
+
+struct advertisement {
+       struct btd_advertising *manager;
+       char *owner;
+       char *path;
+       GDBusClient *client;
+       GDBusProxy *proxy;
+       DBusMessage *reg;
+       uint8_t type; /* Advertising type */
+};
+
+static bool match_advertisement_path(const void *a, const void *b)
+{
+       const struct advertisement *ad = a;
+       const char *path = b;
+
+       return g_strcmp0(ad->path, path);
+}
+
+static void advertisement_free(void *data)
+{
+       struct advertisement *ad = data;
+
+       if (ad->client) {
+               g_dbus_client_set_disconnect_watch(ad->client, NULL, NULL);
+               g_dbus_client_unref(ad->client);
+       }
+
+       if (ad->proxy)
+               g_dbus_proxy_unref(ad->proxy);
+
+       if (ad->owner)
+               g_free(ad->owner);
+
+       if (ad->path)
+               g_free(ad->path);
+
+       free(ad);
+}
+
+static gboolean advertisement_free_idle_cb(void *data)
+{
+       advertisement_free(data);
+
+       return FALSE;
+}
+
+static void advertisement_release(void *data)
+{
+       struct advertisement *ad = data;
+       DBusMessage *message;
+
+       DBG("Releasing advertisement %s, %s", ad->owner, ad->path);
+
+       message = dbus_message_new_method_call(ad->owner, ad->path,
+                                                       LE_ADVERTISEMENT_IFACE,
+                                                       "Release");
+
+       if (!message) {
+               error("Couldn't allocate D-Bus message");
+               return;
+       }
+
+       g_dbus_send_message(btd_get_dbus_connection(), message);
+}
+
+static void advertisement_destroy(void *data)
+{
+       advertisement_release(data);
+       advertisement_free(data);
+}
+
+static void advertisement_remove(void *data)
+{
+       struct advertisement *ad = data;
+
+       g_dbus_client_set_disconnect_watch(ad->client, NULL, NULL);
+
+       /* TODO: mgmt API call to remove advert */
+
+       queue_remove(ad->manager->ads, ad);
+
+       g_idle_add(advertisement_free_idle_cb, ad);
+}
+
+static void client_disconnect_cb(DBusConnection *conn, void *user_data)
+{
+       DBG("Client disconnected");
+
+       advertisement_remove(user_data);
+}
+
+static bool parse_advertising_type(GDBusProxy *proxy, uint8_t *type)
+{
+       DBusMessageIter iter;
+       const char *msg_type;
+
+       if (!g_dbus_proxy_get_property(proxy, "Type", &iter))
+               return false;
+
+       if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
+               return false;
+
+       dbus_message_iter_get_basic(&iter, &msg_type);
+
+       if (!g_strcmp0(msg_type, "broadcast")) {
+               *type = AD_TYPE_BROADCAST;
+               return true;
+       }
+
+       if (!g_strcmp0(msg_type, "peripheral")) {
+               *type = AD_TYPE_PERIPHERAL;
+               return true;
+       }
+
+       return false;
+}
+
+static void refresh_advertisement(struct advertisement *ad)
+{
+       DBG("Refreshing advertisement: %s", ad->path);
+}
+
+static bool parse_advertisement(struct advertisement *ad)
+{
+       if (!parse_advertising_type(ad->proxy, &ad->type)) {
+               error("Failed to read \"Type\" property of advertisement");
+               return false;
+       }
+
+       /* TODO: parse the remaining properties into a shared structure */
+
+       refresh_advertisement(ad);
+
+       return true;
+}
+
+static void advertisement_proxy_added(GDBusProxy *proxy, void *data)
+{
+       struct advertisement *ad = data;
+       DBusMessage *reply;
+
+       if (!parse_advertisement(ad)) {
+               error("Failed to parse advertisement");
+
+               reply = btd_error_failed(ad->reg,
+                                       "Failed to register advertisement");
+               goto done;
+       }
+
+       g_dbus_client_set_disconnect_watch(ad->client, client_disconnect_cb,
+                                                                       ad);
+
+       reply = dbus_message_new_method_return(ad->reg);
+
+       DBG("Advertisement registered: %s", ad->path);
+
+done:
+       g_dbus_send_message(btd_get_dbus_connection(), reply);
+
+       dbus_message_unref(ad->reg);
+       ad->reg = NULL;
+}
+
+static struct advertisement *advertisement_create(DBusConnection *conn,
+                                       DBusMessage *msg, const char *path)
+{
+       struct advertisement *ad;
+       const char *sender = dbus_message_get_sender(msg);
+
+       if (!path || !g_str_has_prefix(path, "/"))
+               return NULL;
+
+       ad = new0(struct advertisement, 1);
+       if (!ad)
+               return NULL;
+
+       ad->client = g_dbus_client_new_full(conn, sender, path, path);
+       if (!ad->client)
+               goto fail;
+
+       ad->owner = g_strdup(sender);
+       if (!ad->owner)
+               goto fail;
+
+       ad->path = g_strdup(path);
+       if (!ad->path)
+               goto fail;
+
+       DBG("Adding proxy for %s", path);
+       ad->proxy = g_dbus_proxy_new(ad->client, path, LE_ADVERTISEMENT_IFACE);
+       if (!ad->proxy)
+               goto fail;
+
+       g_dbus_client_set_proxy_handlers(ad->client, advertisement_proxy_added,
+                                                               NULL, NULL, ad);
+
+       ad->reg = dbus_message_ref(msg);
+
+       return ad;
+
+fail:
+       advertisement_free(ad);
+       return NULL;
+}
+
+static DBusMessage *register_advertisement(DBusConnection *conn,
+                                               DBusMessage *msg,
+                                               void *user_data)
+{
+       struct btd_advertising *manager = user_data;
+       DBusMessageIter args;
+       const char *path;
+       struct advertisement *ad;
+
+       DBG("RegisterAdvertisement");
+
+       if (!dbus_message_iter_init(msg, &args))
+               return btd_error_invalid_args(msg);
+
+       if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_OBJECT_PATH)
+               return btd_error_invalid_args(msg);
+
+       dbus_message_iter_get_basic(&args, &path);
+
+       if (queue_find(manager->ads, match_advertisement_path, path))
+               return btd_error_already_exists(msg);
+
+       /* TODO: support more than one advertisement */
+       if (!queue_isempty(manager->ads))
+               return btd_error_failed(msg, "Already advertising");
+
+       dbus_message_iter_next(&args);
+
+       if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_ARRAY)
+               return btd_error_invalid_args(msg);
+
+       ad = advertisement_create(conn, msg, path);
+       if (!ad)
+               return btd_error_failed(msg,
+                                       "Failed to register advertisement");
+
+       DBG("Registered advertisement at path %s", path);
+
+       ad->manager = manager;
+       queue_push_tail(manager->ads, ad);
+
+       return NULL;
+}
+
+static DBusMessage *unregister_advertisement(DBusConnection *conn,
+                                               DBusMessage *msg,
+                                               void *user_data)
+{
+       struct btd_advertising *manager = user_data;
+       DBusMessageIter args;
+       const char *path;
+       struct advertisement *ad;
+
+       DBG("UnregisterAdvertisement");
+
+       if (!dbus_message_iter_init(msg, &args))
+               return btd_error_invalid_args(msg);
+
+       if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_OBJECT_PATH)
+               return btd_error_invalid_args(msg);
+
+       dbus_message_iter_get_basic(&args, &path);
+
+       ad = queue_find(manager->ads, match_advertisement_path, path);
+       if (!ad)
+               return btd_error_does_not_exist(msg);
+
+       advertisement_remove(ad);
+
+       return dbus_message_new_method_return(msg);
+}
+
+static const GDBusMethodTable methods[] = {
+       { GDBUS_EXPERIMENTAL_ASYNC_METHOD("RegisterAdvertisement",
+                                       GDBUS_ARGS({ "advertisement", "o" },
+                                                       { "options", "a{sv}" }),
+                                       NULL, register_advertisement) },
+       { GDBUS_EXPERIMENTAL_ASYNC_METHOD("UnregisterAdvertisement",
+                                               GDBUS_ARGS({ "service", "o" }),
+                                               NULL,
+                                               unregister_advertisement) },
+       { }
+};
+
+static void advertising_manager_destroy(void *user_data)
+{
+       struct btd_advertising *manager = user_data;
+
+       queue_destroy(manager->ads, advertisement_destroy);
+
+       free(manager);
+}
+
+static struct btd_advertising *
+advertising_manager_create(struct btd_adapter *adapter)
+{
+       struct btd_advertising *manager;
+
+       manager = new0(struct btd_advertising, 1);
+       if (!manager)
+               return NULL;
+
+       manager->adapter = adapter;
+
+       if (!g_dbus_register_interface(btd_get_dbus_connection(),
+                                               adapter_get_path(adapter),
+                                               LE_ADVERTISING_MGR_IFACE,
+                                               methods, NULL, NULL, manager,
+                                               advertising_manager_destroy)) {
+               error("Failed to register " LE_ADVERTISING_MGR_IFACE);
+               free(manager);
+               return NULL;
+       }
+
+       manager->ads = queue_new();
+
+       return manager;
+}
+
+struct btd_advertising *
+btd_advertising_manager_new(struct btd_adapter *adapter)
+{
+       struct btd_advertising *manager;
+
+       if (!adapter)
+               return NULL;
+
+       manager = advertising_manager_create(adapter);
+       if (!manager)
+               return NULL;
+
+       DBG("LE Advertising Manager created for adapter: %s",
+                                               adapter_get_path(adapter));
+
+       return manager;
+}
+
+void btd_advertising_manager_destroy(struct btd_advertising *manager)
+{
+       if (!manager)
+               return;
+
+       g_dbus_unregister_interface(btd_get_dbus_connection(),
+                                       adapter_get_path(manager->adapter),
+                                       LE_ADVERTISING_MGR_IFACE);
+}
diff --git a/src/advertising.h b/src/advertising.h
new file mode 100644 (file)
index 0000000..a4b99ff
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2015  Google Inc.
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ */
+
+struct btd_adapter;
+struct btd_advertising;
+
+struct btd_advertising *btd_advertising_manager_new(
+                                               struct btd_adapter *adapter);
+void btd_advertising_manager_destroy(struct btd_advertising *manager);
index 24d1f9b..d334a36 100644 (file)
@@ -269,7 +269,14 @@ static int attribute_uuid_cmp(gconstpointer a, gconstpointer b)
        const struct attribute *attrib1 = a;
        const bt_uuid_t *uuid = b;
 
-       return bt_uuid_cmp(&attrib1->uuid, uuid);
+       if (attrib1->uuid.value.u16 != GATT_PRIM_SVC_UUID) {
+               return bt_uuid_cmp(&attrib1->uuid, uuid);
+       } else {
+               bt_uuid_t prim_uuid;
+               prim_uuid = att_get_uuid(attrib1->data, attrib1->len);
+
+               return bt_uuid_cmp(&prim_uuid, uuid);
+       }
 }
 
 struct attribute *attribute_find(struct btd_adapter *adapter, const bt_uuid_t *uuid)
@@ -736,7 +743,7 @@ static uint16_t find_info(struct gatt_channel *channel, uint16_t start,
                put_le16(a->handle, value);
 
                /* Attribute Value */
-               put_uuid_le(&a->uuid, &value[2]);
+               bt_uuid_to_le(&a->uuid, &value[2]);
        }
 
        length = enc_find_info_resp(format, adl, pdu, len);
@@ -791,7 +798,6 @@ static uint16_t find_by_type(struct gatt_channel *channel, uint16_t start,
                        if (bt_uuid_cmp(&a->uuid, &prim_uuid) == 0 ||
                                        bt_uuid_cmp(&a->uuid, &snd_uuid) == 0)
                                range = NULL;
-
                        else
                                range->end = a->handle;
                }
@@ -1432,19 +1438,24 @@ static gboolean register_core_services(struct gatt_server *server)
 #ifdef __TIZEN_PATCH__
        /* GATT service: service changed characteristic */
        service_changed_handle = 0x0008;
-       bt_uuid16_create(&uuid, GATT_CLIENT_CHARAC_CFG_UUID);
+       bt_uuid16_create(&uuid, GATT_CHARAC_UUID);
 
-       atval[0] = GATT_CHR_PROP_READ;
+       atval[0] = GATT_CHR_PROP_INDICATE;
        put_le16(service_changed_handle, &atval[1]);
        put_le16(GATT_CHARAC_SERVICE_CHANGED, &atval[3]);
-       put_le16(GATT_CLIENT_CHARAC_CFG_IND_BIT, atval);
+
        attrib_db_add_new(server, 0x0007, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
-                                                               atval, 4);
+                       atval, 5);
 
        /* GATT service: service changed attribute */
        bt_uuid16_create(&uuid, GATT_CHARAC_SERVICE_CHANGED);
-       attrib_db_add_new(server, service_changed_handle, &uuid, ATT_NONE,
+       attrib_db_add_new(server, service_changed_handle, &uuid, ATT_NOT_PERMITTED,
                                                ATT_NOT_PERMITTED, NULL, 0);
+
+       bt_uuid16_create(&uuid, GATT_CLIENT_CHARAC_CFG_UUID);
+       atval[0] = GATT_CHR_PROP_READ | GATT_CHR_PROP_WRITE;
+       atval[1] = 0;
+       attrib_db_add_new(server, 0x0009, &uuid, ATT_NONE, ATT_NONE, atval, 2);
 #endif
 
        server->gatt_sdp_handle = attrib_create_sdp_new(server, 0x0006,
index 00c231a..4fd51d9 100644 (file)
   </policy>
 
 </busconfig>
-
old mode 100644 (file)
new mode 100755 (executable)
index 35e9457..f07b4d7
@@ -5,10 +5,11 @@ Documentation=man:bluetoothd(8)
 [Service]
 Type=dbus
 BusName=org.bluez
-ExecStart=@libexecdir@/bluetoothd
+ExecStart=@libexecdir@/bluetoothd -d -C
 NotifyAccess=main
 #WatchdogSec=10
-#Restart=on-failure
+Restart=always
+RestartSec=1
 CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE
 LimitNPROC=1
 
old mode 100644 (file)
new mode 100755 (executable)
index 6ca505f..93e0305
@@ -310,6 +310,12 @@ struct btd_device {
        uint8_t         last_bdaddr_type;
        gboolean                le_auto_connect;
        guint           auto_id;
+       gboolean        ipsp_connected; /* IPSP Connection state */
+       uint8_t         rpa_res_support; /* RPA Resolution capability of device */
+       uint16_t                max_tx_octets;
+       uint16_t                max_tx_time;
+       uint16_t                max_rx_octets;
+       uint16_t                max_rx_time;
 #endif
 };
 
@@ -499,6 +505,15 @@ static gboolean store_device_info_cb(gpointer user_data)
                g_key_file_remove_key(key_file, "General", "Appearance", NULL);
        }
 
+#ifdef __TIZEN_PATCH__
+       if (device->rpa_res_support) {
+               g_key_file_set_integer(key_file, "General", "RPAResSupport",
+                                       device->rpa_res_support);
+       } else {
+               g_key_file_remove_key(key_file, "General", "RPAResSupport", NULL);
+       }
+#endif
+
        update_technologies(key_file, device);
 
        g_key_file_set_boolean(key_file, "General", "Trusted",
@@ -666,7 +681,7 @@ static void gatt_client_cleanup(struct btd_device *device)
        if (!device->le_state.bonded)
                gatt_db_clear(device->db);
 }
-#ifndef __TIZEN_PATCH__
+
 static void gatt_server_cleanup(struct btd_device *device)
 {
        if (!device->server)
@@ -675,7 +690,7 @@ static void gatt_server_cleanup(struct btd_device *device)
        bt_gatt_server_unref(device->server);
        device->server = NULL;
 }
-#endif
+
 static void attio_cleanup(struct btd_device *device)
 {
 #ifdef __TIZEN_PATCH__
@@ -696,9 +711,7 @@ static void attio_cleanup(struct btd_device *device)
        }
 
        gatt_client_cleanup(device);
-#ifndef __TIZEN_PATCH__
        gatt_server_cleanup(device);
-#endif
 
        if (device->att) {
                bt_att_unref(device->att);
@@ -1227,6 +1240,22 @@ static gboolean dev_property_get_last_addr_type(const GDBusPropertyTable *proper
        return TRUE;
 }
 
+static gboolean dev_property_get_ipsp_conn_state(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct btd_device *dev = data;
+       dbus_bool_t ipsp_connected;
+
+       if (dev->ipsp_connected)
+               ipsp_connected = TRUE;
+       else
+               ipsp_connected = FALSE;
+
+       dbus_message_iter_append_basic(iter,
+                       DBUS_TYPE_BOOLEAN, &ipsp_connected);
+
+       return TRUE;
+}
 #endif
 
 static gboolean dev_property_get_connected(const GDBusPropertyTable *property,
@@ -1331,44 +1360,6 @@ static gboolean dev_property_get_adapter(const GDBusPropertyTable *property,
 }
 
 #ifdef __TIZEN_PATCH__
-static gboolean dev_property_get_prim_services(const GDBusPropertyTable *property,
-                    DBusMessageIter *iter, void *data)
-{
-       struct btd_device *device = data;
-       gchar *attrib_data;
-       DBusMessageIter array;
-       GSList *l;
-       dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
-                               DBUS_TYPE_STRING_AS_STRING,
-                               &array);
-
-       for (l = device->primaries; l != NULL; l = l->next) {
-               struct gatt_primary *primary = l->data;
-
-               DBG("start handle = 0x%04x, end grp handle = 0x%04x "
-                       "uuid: %s\n", primary->range.start, primary->range.end,
-                       primary->uuid);
-
-               /*
-                * attrib_data contains the start_handle followed by '#', end
-                * handle followed by '#' and 128 bit UUID as string. Attribute
-                * data represents one service.
-                */
-
-               attrib_data = g_strdup_printf("%04x""#""%04x""#""%s",
-                       primary->range.start,primary->range.end,primary->uuid);
-
-               DBG("attrib_data string: %s",attrib_data);
-
-               dbus_message_iter_append_basic(&array, DBUS_TYPE_STRING,
-                                       &attrib_data);
-
-       }
-
-       dbus_message_iter_close_container(iter, &array);
-
-       return TRUE;
-}
 
 static gboolean property_get_flag(const GDBusPropertyTable *property,
                                        DBusMessageIter *iter, void *user_data)
@@ -1473,7 +1464,7 @@ int device_block(struct btd_device *device, gboolean update_only)
 
        store_device_info(device);
 
-       btd_device_set_temporary(device, FALSE);
+       btd_device_set_temporary(device, false);
 
        g_dbus_emit_property_changed(dbus_conn, device->path,
                                                DEVICE_INTERFACE, "Blocked");
@@ -1672,7 +1663,7 @@ static void device_profile_connected(struct btd_device *dev,
        DBG("%s %s (%d)", profile->name, strerror(-err), -err);
 
        if (!err)
-               btd_device_set_temporary(dev, FALSE);
+               btd_device_set_temporary(dev, false);
 
        if (dev->pending == NULL)
                return;
@@ -1915,7 +1906,7 @@ static DBusMessage *connect_profiles(struct btd_device *dev, uint8_t bdaddr_type
        if (!btd_adapter_get_powered(dev->adapter))
                return btd_error_not_ready(msg);
 
-       btd_device_set_temporary(dev, FALSE);
+       btd_device_set_temporary(dev, false);
 
        if (!state->svc_resolved)
                goto resolve_services;
@@ -2008,7 +1999,7 @@ static DBusMessage *dev_connect(DBusConnection *conn, DBusMessage *msg,
                if (dev->le_state.connected)
                        return dbus_message_new_method_return(msg);
 
-               btd_device_set_temporary(dev, FALSE);
+               btd_device_set_temporary(dev, false);
 
                if (dev->disable_auto_connect) {
                        dev->disable_auto_connect = FALSE;
@@ -2386,7 +2377,7 @@ static DBusMessage *pair_device(DBusConnection *conn, DBusMessage *msg,
 #endif
        int err;
 
-       btd_device_set_temporary(device, FALSE);
+       btd_device_set_temporary(device, false);
 
 #ifdef __TIZEN_PATCH__
        if (dbus_message_get_args(msg, NULL, DBUS_TYPE_BYTE, &conn_type,
@@ -2472,8 +2463,7 @@ static DBusMessage *pair_device(DBusConnection *conn, DBusMessage *msg,
                err = device_connect_le(device);
        else if (connect_le) /* Send bonding request if LE is already connected*/
                err = adapter_create_bonding(adapter, &device->bdaddr,
-                                                       bdaddr_type,
-                                                       IO_CAPABILITY_NOINPUTNOOUTPUT);
+                                                       bdaddr_type, io_cap);
        else
                err = adapter_create_bonding(adapter, &device->bdaddr,
                                                        BDADDR_BREDR, io_cap);
@@ -2522,6 +2512,10 @@ static DBusMessage *new_authentication_return(DBusMessage *msg, uint8_t status)
                return dbus_message_new_error(msg,
                                ERROR_INTERFACE ".AuthenticationCanceled",
                                "Authentication Canceled");
+       case MGMT_STATUS_ALREADY_PAIRED:
+               return dbus_message_new_error(msg,
+                               ERROR_INTERFACE ".AlreadyExists",
+                               "Already Paired");
        default:
                return dbus_message_new_error(msg,
                                ERROR_INTERFACE ".AuthenticationFailed",
@@ -2650,48 +2644,6 @@ static DBusMessage *read_auth_payload_timeout(DBusConnection *conn,
 }
 #endif
 
-static DBusMessage *get_prim_services(DBusConnection *conn,
-                                       DBusMessage *msg, void *user_data)
-{
-       struct btd_device *device = user_data;
-       DBusMessage *reply;
-       const char *device_path;
-       DBusMessageIter iter, array_iter;
-       GSList *l;
-
-       reply = dbus_message_new_method_return(msg);
-
-       dbus_message_iter_init_append(reply, &iter);
-
-       dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
-                               DBUS_TYPE_OBJECT_PATH_AS_STRING, &array_iter);
-       device_path = device_get_path(device);
-
-       for (l = device->primaries; l != NULL; l = l->next) {
-               struct gatt_primary *primary = l->data;
-               gchar* attrib_data;
-
-               /*
-                * attrib_data contains the start_handle followed by '#', end
-                * handle followed by '#' and 128 bit UUID as string. Attribute
-                * data represents one service.
-                */
-
-               attrib_data = g_strdup_printf("%s/service%04x", device_path,
-                                                               primary->range.start);
-
-               DBG("attrib_data string: %s", attrib_data);
-
-               dbus_message_iter_append_basic(&array_iter,
-                                       DBUS_TYPE_OBJECT_PATH, &attrib_data);
-
-       }
-
-       dbus_message_iter_close_container(&iter, &array_iter);
-
-       return reply;
-}
-
 static DBusMessage *discover_services(DBusConnection *conn,
                                        DBusMessage *msg, void *user_data)
 {
@@ -2936,9 +2888,12 @@ static DBusMessage *connect_le(DBusConnection *conn, DBusMessage *msg,
        if (device->bdaddr_type == BDADDR_BREDR) {
                if(device->le)
                        device->bdaddr_type = BDADDR_LE_PUBLIC;
-               else
+               else {
                        device = btd_adapter_get_device(device->adapter,
                                                &device->bdaddr, BDADDR_LE_PUBLIC);
+                       if (device == NULL)
+                               return btd_error_no_such_adapter(msg);
+               }
        }
 
        if (device->gatt_connected)
@@ -2978,7 +2933,8 @@ static DBusMessage *connect_le(DBusConnection *conn, DBusMessage *msg,
        if (device->auto_id == 0)
                device->auto_id = g_timeout_add(200, att_connect, device);
 
-       return dbus_message_new_method_return(msg);
+       device->connect = dbus_message_ref(msg);
+       return NULL;
 }
 
 static DBusMessage *disconnect_le(DBusConnection *conn, DBusMessage *msg,
@@ -3006,6 +2962,18 @@ static DBusMessage *disconnect_le(DBusConnection *conn, DBusMessage *msg,
        if (!device->le_state.connected)
                return btd_error_not_connected(msg);
 
+       if (device->connect) {
+               DBusMessage *reply = btd_error_failed(device->connect,
+                                               "Cancelled");
+               g_dbus_send_message(dbus_conn, reply);
+               dbus_message_unref(device->connect);
+               device->connect = NULL;
+       }
+
+       if (device->le_state.connected)
+               device->disconnects = g_slist_append(device->disconnects,
+                                               dbus_message_ref(msg));
+
        disconnect_all(device);
 
        /*
@@ -3016,7 +2984,98 @@ static DBusMessage *disconnect_le(DBusConnection *conn, DBusMessage *msg,
        if(device->bredr)
                device->bdaddr_type = BDADDR_BREDR;
 
-       return dbus_message_new_method_return(msg);
+       return NULL;
+}
+
+static DBusMessage *connect_ipsp(DBusConnection *conn, DBusMessage *msg,
+                                                       void *user_data)
+{
+       struct btd_device *device = user_data;
+
+       DBG("bdaddr_type  %d", device->bdaddr_type);
+
+       if (device->bdaddr_type == BDADDR_BREDR) {
+               if(device->le)
+                       device->bdaddr_type = BDADDR_LE_PUBLIC;
+               else {
+                       device = btd_adapter_get_device(device->adapter,
+                                       &device->bdaddr, BDADDR_LE_PUBLIC);
+                       if (device == NULL)
+                               return btd_error_no_such_adapter(msg);
+               }
+       }
+
+       if (device->ipsp_connected)
+               return btd_error_already_connected(msg);
+
+       /* Initiate Connection for 6Lowan*/
+       if (btd_adapter_connect_ipsp(device->adapter, &device->bdaddr,
+                                       device->bdaddr_type) != 0)
+               return btd_error_failed(msg, "ConnectFailed");
+
+       return dbus_message_new_method_return(msg);;
+}
+
+static DBusMessage *disconnect_ipsp(DBusConnection *conn, DBusMessage *msg,
+                                                       void *user_data)
+{
+       struct btd_device *device = user_data;
+       DBG("bdaddr_type  %d", device->bdaddr_type);
+
+       if (device->bdaddr_type == BDADDR_BREDR)
+               return btd_error_not_supported(msg);
+
+       if (!device->ipsp_connected)
+               return btd_error_not_connected(msg);
+
+       /* Disconnect the 6Lowpan connection */
+       if (btd_adapter_disconnect_ipsp(device->adapter, &device->bdaddr,
+                                       device->bdaddr_type) != 0)
+               return btd_error_failed(msg, "DisconnectFailed");
+
+       /* TODO: Handle disconnection of GATT connection, If the connection
+        * is established as part of IPSP connection. */
+
+       return dbus_message_new_method_return(msg);;
+}
+
+static DBusMessage *le_set_data_length(
+                       DBusConnection *conn, DBusMessage *msg,
+                       void *user_data)
+{
+       dbus_uint16_t max_tx_octets;
+       dbus_uint16_t max_tx_time;
+       const gchar *address;
+       bdaddr_t bdaddr;
+       struct btd_device *device = user_data;
+       int status;
+       char addr[BT_ADDRESS_STRING_SIZE];
+
+       if (!dbus_message_get_args(msg, NULL,
+                               DBUS_TYPE_UINT16, &max_tx_octets,
+                               DBUS_TYPE_UINT16, &max_tx_time,
+                               DBUS_TYPE_INVALID)) {
+               DBG("error in retrieving values");
+               return btd_error_invalid_args(msg);
+       }
+
+       if (device->bdaddr_type == BDADDR_BREDR)
+               return btd_error_not_supported(msg);
+
+       ba2str(&device->bdaddr, addr);
+
+       DBG("Remote device address: %s", addr);
+       DBG("Max tx octets: %u, Max tx time: %u",
+                               max_tx_octets, max_tx_time);
+
+       status = btd_adapter_le_set_data_length(device->adapter,
+                               &device->bdaddr, max_tx_octets,
+                               max_tx_time);
+
+       if (status != 0)
+               return btd_error_failed(msg, "Unable to set le data length values");
+       else
+               return dbus_message_new_method_return(msg);
 }
 
 static DBusMessage *is_connected_profile(DBusConnection *conn, DBusMessage *msg,
@@ -3132,10 +3191,10 @@ static const GDBusMethodTable device_methods[] = {
        { GDBUS_METHOD("ReadPayloadTimeout", NULL,
                        NULL, read_auth_payload_timeout)},
 #endif
-       { GDBUS_METHOD("ConnectLE",
+       { GDBUS_ASYNC_METHOD("ConnectLE",
                        GDBUS_ARGS({ "auto_connect", "b"}),
                        NULL, connect_le) },
-       { GDBUS_METHOD("DisconnectLE", NULL, NULL, disconnect_le) },
+       { GDBUS_ASYNC_METHOD("DisconnectLE", NULL, NULL, disconnect_le) },
        { GDBUS_METHOD("IsConnectedProfile", GDBUS_ARGS({ "UUID", "s" }),
                GDBUS_ARGS({ "IsConnected", "b" }), is_connected_profile)},
        { GDBUS_METHOD("LeConnUpdate",
@@ -3143,13 +3202,16 @@ static const GDBusMethodTable device_methods[] = {
                                { "interval_max", "u" }, { "latency", "u" },
                                { "time_out", "u" }), NULL,
                                le_conn_update) },
-       { GDBUS_METHOD("GetPrimServices",
-                               NULL, GDBUS_ARGS({ "Services", "ao" }),
-                               get_prim_services) },
        { GDBUS_ASYNC_METHOD("DiscoverServices",
                        GDBUS_ARGS({ "pattern", "s" }), NULL,
                                discover_services) },
        { GDBUS_METHOD("CancelDiscovery", NULL, NULL, cancel_discover) },
+       { GDBUS_ASYNC_METHOD("ConnectIpsp", NULL, NULL, connect_ipsp) },
+       { GDBUS_ASYNC_METHOD("DisconnectIpsp", NULL, NULL, disconnect_ipsp) },
+       { GDBUS_ASYNC_METHOD("LESetDataLength",
+                       GDBUS_ARGS({"max_tx_octets", "q" },
+                       { "max_tx_time", "q" }), NULL,
+                       le_set_data_length)},
 #endif
        { }
 };
@@ -3186,14 +3248,13 @@ static const GDBusPropertyTable device_properties[] = {
 #ifdef __TIZEN_PATCH__
         /* To handle Failed Legacy Pairing when initiated from Remote device*/
        { "LegacyPaired", "b", dev_property_get_paired },
-       { "Services", "as", dev_property_get_prim_services },
        { "Flag", "q", property_get_flag },
        { "ManufacturerDataLen", "q", property_get_manufacturer_data_len },
        { "ManufacturerData", "ay", property_get_manufacturer_data },
        { "GattConnected", "b", dev_property_get_gatt_connected },
        { "PayloadTimeout", "q", dev_property_get_payload},
        { "LastAddrType", "y", dev_property_get_last_addr_type},
-
+       { "IpspConnected", "b", dev_property_get_ipsp_conn_state },
 #endif
        { }
 };
@@ -3213,6 +3274,11 @@ static const GDBusSignalTable device_signals[] = {
                                        { "RSSI", "i"},
                                        { "AdvDataLen", "i"},
                                        { "AdvData", "ay"})) },
+       { GDBUS_SIGNAL("LEDataLengthChanged",
+                       GDBUS_ARGS({"max_tx_octets","q"},
+                               { "max_tx_time", "q" },
+                               { "max_rx_octets", "q"},
+                               { "max_rx_time", "q"})) },
 };
 #endif
 
@@ -3458,6 +3524,10 @@ static void load_info(struct btd_device *device, const char *local,
        }
 
 #ifdef __TIZEN_PATCH__
+       /* Load RPA Resolution Support value */
+       device->rpa_res_support = g_key_file_get_integer(key_file,
+                                                       "General", "RPAResSupport", NULL);
+
        str = g_key_file_get_string(key_file, "General", "ManufacturerDataLen", NULL);
        if (str) {
                device->manufacturer_data_len = strtol(str, NULL, 10);
@@ -4032,7 +4102,7 @@ static struct btd_device *device_new(struct btd_adapter *adapter,
        }
 
        device->adapter = adapter;
-       device->temporary = TRUE;
+       device->temporary = true;
 
        gatt_db_register(device->db, gatt_service_added, gatt_service_removed,
                                                                device, NULL);
@@ -4444,7 +4514,6 @@ void device_remove(struct btd_device *device, gboolean remove_stored)
        if (device->browse)
                browse_request_cancel(device->browse);
 
-
        while (device->services != NULL) {
                struct btd_service *service = device->services->data;
 
@@ -5091,6 +5160,9 @@ static void att_disconnected_cb(int err, void *user_data)
                adapter_connect_list_add(device->adapter, device);
 
 done:
+#ifdef __TIZEN_PATCH__
+       device_set_gatt_connected(device, FALSE);
+#endif
        attio_cleanup(device);
 }
 
@@ -5108,7 +5180,7 @@ static void register_gatt_services(struct btd_device *device)
         */
        gatt_db_foreach_service(device->db, NULL, add_primary, &services);
 
-       btd_device_set_temporary(device, FALSE);
+       btd_device_set_temporary(device, false);
 
        if (req)
                update_gatt_uuids(req, device->primaries, services);
@@ -5160,17 +5232,10 @@ static void gatt_client_ready_cb(bool success, uint8_t att_ecode,
                return;
        }
 
-       device->att_mtu = bt_att_get_mtu(device->att);
-       g_attrib_set_mtu(device->attrib, device->att_mtu);
-
-       DBG("MTU: %u", device->att_mtu);
-
        register_gatt_services(device);
 
        device_accept_gatt_profiles(device);
 
-       g_slist_foreach(device->attios, attio_connected, device->attrib);
-
        btd_gatt_client_ready(device->client_dbus);
 }
 
@@ -5181,6 +5246,11 @@ static void gatt_client_service_changed(uint16_t start_handle,
        DBG("start 0x%04x, end: 0x%04x", start_handle, end_handle);
 }
 
+static void gatt_debug(const char *str, void *user_data)
+{
+       DBG("%s", str);
+}
+
 static void gatt_client_init(struct btd_device *device)
 {
        gatt_client_cleanup(device);
@@ -5192,12 +5262,17 @@ static void gatt_client_init(struct btd_device *device)
                return;
        }
 
+
 #ifdef __TIZEN_PATCH__
        if (!bt_gatt_client_set_debug(device->client, gatt_client_debug_func,
                                NULL, NULL)) {
                error("Failed to set debug function");
        }
+#else
+       bt_gatt_client_set_debug(device->client, gatt_debug, NULL, NULL);
 #endif
+       /* Notify attio so it can react to notifications */
+       g_slist_foreach(device->attios, attio_connected, device->attrib);
 
        if (!bt_gatt_client_set_ready_handler(device->client,
                                                        gatt_client_ready_cb,
@@ -5216,7 +5291,6 @@ static void gatt_client_init(struct btd_device *device)
        }
 }
 
-#ifndef __TIZEN_PATCH__
 static void gatt_server_init(struct btd_device *device, struct gatt_db *db)
 {
        if (!db) {
@@ -5229,8 +5303,9 @@ static void gatt_server_init(struct btd_device *device, struct gatt_db *db)
        device->server = bt_gatt_server_new(db, device->att, device->att_mtu);
        if (!device->server)
                error("Failed to initialize bt_gatt_server");
+
+       bt_gatt_server_set_debug(device->server, gatt_debug, NULL, NULL);
 }
-#endif
 
 static bool local_counter(uint32_t *sign_cnt, void *user_data)
 {
@@ -5267,9 +5342,7 @@ bool device_attach_att(struct btd_device *dev, GIOChannel *io)
        BtIOSecLevel sec_level;
        uint16_t mtu;
        uint16_t cid;
-#ifndef __TIZEN_PATCH__
        struct btd_gatt_database *database;
-#endif
 
        bt_io_get(io, &gerr, BT_IO_OPT_SEC_LEVEL, &sec_level,
                                                BT_IO_OPT_IMTU, &mtu,
@@ -5304,7 +5377,7 @@ bool device_attach_att(struct btd_device *dev, GIOChannel *io)
                return false;
        }
 
-#ifdef __TIZEN_PATCH__
+#if 0
        dev->attachid = attrib_channel_attach(attrib);
        if (dev->attachid == 0) {
                g_attrib_unref(attrib);
@@ -5330,14 +5403,10 @@ bool device_attach_att(struct btd_device *dev, GIOChannel *io)
                bt_att_set_remote_key(dev->att, dev->remote_csrk->key,
                                                        remote_counter, dev);
 
-#ifndef __TIZEN_PATCH__
        database = btd_adapter_get_database(dev->adapter);
-#endif
 
        gatt_client_init(dev);
-#ifndef __TIZEN_PATCH__
        gatt_server_init(dev, btd_gatt_database_get_db(database));
-#endif
 
        /*
         * Remove the device from the connect_list and give the passive
@@ -5371,11 +5440,6 @@ static void att_connect_cb(GIOChannel *io, GError *gerr, gpointer user_data)
        if (gerr) {
                DBG("%s", gerr->message);
 
-#ifdef __TIZEN_PATCH__
-               /* Send disconnected property changed event */
-               g_dbus_emit_property_changed(dbus_conn, device->path,
-               DEVICE_INTERFACE, "GattConnected");
-#endif
                if (attcb->err)
                        attcb->err(gerr, user_data);
 
@@ -5734,6 +5798,53 @@ void device_set_last_addr_type(struct btd_device *device, uint8_t type)
 
        device->last_bdaddr_type = type;
 }
+
+gboolean device_is_ipsp_connected(struct btd_device * device)
+{
+       return device->ipsp_connected;
+}
+
+void device_set_ipsp_connected(struct btd_device *device, gboolean connected)
+{
+       if (device == NULL) {
+               error("device is NULL");
+               return;
+       }
+
+       if (device->ipsp_connected == connected)
+               return;
+
+       device->ipsp_connected = connected;
+
+       DBG("ipsp_connected %d", connected);
+
+       g_dbus_emit_property_changed(dbus_conn, device->path,
+                       DEVICE_INTERFACE, "IpspConnected");
+}
+void device_le_data_length_changed(struct btd_device *device, uint16_t max_tx_octets,
+               uint16_t max_tx_time, uint16_t max_rx_octets, uint16_t max_rx_time)
+{
+       if (device == NULL) {
+               error("device is NULL");
+               return;
+       }
+
+       device->max_tx_octets = max_tx_octets;
+       device->max_tx_time = max_tx_time;
+       device->max_rx_octets = max_rx_octets;
+       device->max_rx_time = max_rx_time;
+
+       DBG("data length changed values :max_tx_octets: %d  max_tx_time: %d  max_rx_octets: %d  max_rx_time: %d",
+               max_tx_octets, max_tx_time, max_rx_octets, max_rx_time);
+
+       g_dbus_emit_signal(dbus_conn, device->path,
+               DEVICE_INTERFACE, "LEDataLengthChanged",
+               DBUS_TYPE_UINT16, &max_tx_octets,
+               DBUS_TYPE_UINT16, &max_tx_time,
+               DBUS_TYPE_UINT16, &max_rx_octets,
+               DBUS_TYPE_UINT16, &max_rx_time,
+               DBUS_TYPE_INVALID);
+}
 #endif
 
 int device_discover_services(struct btd_device *device)
@@ -5779,7 +5890,7 @@ gboolean device_is_temporary(struct btd_device *device)
        return device->temporary;
 }
 
-void btd_device_set_temporary(struct btd_device *device, gboolean temporary)
+void btd_device_set_temporary(struct btd_device *device, bool temporary)
 {
        if (!device)
                return;
@@ -5789,17 +5900,19 @@ void btd_device_set_temporary(struct btd_device *device, gboolean temporary)
 
        DBG("temporary %d", temporary);
 
+       device->temporary = temporary;
+
        if (temporary) {
                if (device->bredr)
                        adapter_whitelist_remove(device->adapter, device);
                adapter_connect_list_remove(device->adapter, device);
-       } else {
-               if (device->bredr)
-                       adapter_whitelist_add(device->adapter, device);
-               store_device_info(device);
+               return;
        }
 
-       device->temporary = temporary;
+       if (device->bredr)
+               adapter_whitelist_add(device->adapter, device);
+
+       store_device_info(device);
 }
 
 void btd_device_set_trusted(struct btd_device *device, gboolean trusted)
@@ -5831,6 +5944,8 @@ void device_set_bonded(struct btd_device *device, uint8_t bdaddr_type)
                device->bredr_state.bonded = true;
        else
                device->le_state.bonded = true;
+
+       btd_device_set_temporary(device, false);
 }
 
 void device_set_legacy(struct btd_device *device, bool legacy)
@@ -5954,7 +6069,7 @@ void device_set_unpaired(struct btd_device *dev, uint8_t bdaddr_type)
        g_dbus_emit_property_changed(dbus_conn, dev->path,
                                                DEVICE_INTERFACE, "Paired");
 
-       btd_device_set_temporary(dev, TRUE);
+       btd_device_set_temporary(dev, true);
 
        if (btd_device_is_connected(dev))
                device_request_disconnect(dev, NULL);
@@ -6011,8 +6126,18 @@ void device_bonding_complete(struct btd_device *device, uint8_t bdaddr_type,
        device_auth_req_free(device);
 
        /* If we're already paired nothing more is needed */
-       if (state->paired)
+       if (state->paired) {
+#ifdef __TIZEN_PATCH__
+#ifdef TIZEN_WEARABLE
+               DBG("Already paired. Send Paired Signal for Wearble syspopup termn");
+               DBG("state->svc_resolved [%d]", state->svc_resolved);
+               if (state->svc_resolved)
+                       g_dbus_emit_property_changed(dbus_conn, device->path,
+                                       DEVICE_INTERFACE, "Paired");
+#endif /* TIZEN_WEARABLE */
+#endif /* __TIZEN_PATCH__ */
                return;
+       }
 
        device_set_paired(device, bdaddr_type);
 
@@ -6265,9 +6390,9 @@ static void confirm_cb(struct agent *agent, DBusError *err, void *data)
                                                        err ? FALSE : TRUE);
        else
 #endif
-               btd_adapter_confirm_reply(device->adapter, &device->bdaddr,
-                                                       device->bdaddr_type,
-                                                       err ? FALSE : TRUE);
+       btd_adapter_confirm_reply(device->adapter, &device->bdaddr,
+                                               device->bdaddr_type,
+                                               err ? FALSE : TRUE);
 
        agent_unref(device->authr->agent);
        device->authr->agent = NULL;
@@ -6696,6 +6821,18 @@ void device_set_appearance(struct btd_device *device, uint16_t value)
 }
 
 #ifdef __TIZEN_PATCH__
+/* Store the RPA Resolution Characteristic Value of remote device.
+ * This value would be checked before start directed advertising using RPA.
+ */
+void device_set_rpa_res_char_value(struct btd_device *device, uint8_t value)
+{
+       if (device->rpa_res_support == value)
+               return;
+
+       device->rpa_res_support = value;
+       store_device_info(device);
+}
+
 void device_set_manufacturer_info(struct btd_device *device, struct eir_data *eir)
 {
        if (!device)
index e3ee30d..0541aee 100644 (file)
@@ -107,7 +107,7 @@ bool device_is_bonded(struct btd_device *device, uint8_t bdaddr_type);
 gboolean device_is_trusted(struct btd_device *device);
 void device_set_paired(struct btd_device *dev, uint8_t bdaddr_type);
 void device_set_unpaired(struct btd_device *dev, uint8_t bdaddr_type);
-void btd_device_set_temporary(struct btd_device *device, gboolean temporary);
+void btd_device_set_temporary(struct btd_device *device, bool temporary);
 void btd_device_set_trusted(struct btd_device *device, gboolean trusted);
 void device_set_bonded(struct btd_device *device, uint8_t bdaddr_type);
 void device_set_legacy(struct btd_device *device, bool legacy);
@@ -156,6 +156,8 @@ void device_set_adv_report_info(struct btd_device *device, void *data,
 void device_set_payload_timeout(struct btd_device *device,
                        uint16_t payload_timeout);
 void device_set_last_addr_type(struct btd_device *device, uint8_t type);
+gboolean device_is_ipsp_connected(struct btd_device * device);
+void device_set_ipsp_connected(struct btd_device *device, gboolean connected);
 #endif
 
 struct btd_device *btd_device_ref(struct btd_device *device);
index cec119e..1fe7ff7 100644 (file)
--- a/src/eir.c
+++ b/src/eir.c
@@ -294,7 +294,6 @@ void eir_parse(struct eir_data *eir, const uint8_t *eir_data, uint8_t eir_len)
                        eir->manufacturer_data_len = data_len;
 #endif
                        eir_parse_msd(eir, data, data_len);
-
                        break;
                }
 
index ab8081c..0887dc1 100644 (file)
@@ -61,6 +61,9 @@ struct btd_gatt_client {
 
        struct queue *services;
        struct queue *all_notify_clients;
+#ifdef __TIZEN_PATCH__
+       guint wait_charcs_id;
+#endif
 };
 
 struct service {
@@ -381,20 +384,19 @@ static void desc_read_cb(bool success, uint8_t att_ecode,
        struct async_dbus_op *op = user_data;
        struct descriptor *desc = op->data;
        struct service *service = desc->chrc->service;
+       DBusMessage *reply;
 
-       if (!success) {
-               DBusMessage *reply = create_gatt_dbus_error(op->msg, att_ecode);
-
-               desc->read_id = 0;
-               g_dbus_send_message(btd_get_dbus_connection(), reply);
-               return;
-       }
+       if (!success)
+               goto fail;
 
        if (!op->offset)
                gatt_db_attribute_reset(desc->attr);
 
-       gatt_db_attribute_write(desc->attr, op->offset, value, length, 0, NULL,
-                                               write_descriptor_cb, desc);
+       if (!gatt_db_attribute_write(desc->attr, op->offset, value, length, 0,
+                                       NULL, write_descriptor_cb, desc)) {
+               error("Failed to store attribute");
+               goto fail;
+       }
 
        /*
         * If the value length is exactly MTU-1, then we may not have read the
@@ -414,10 +416,21 @@ static void desc_read_cb(bool success, uint8_t att_ecode,
                        return;
        }
 
+       /* Read the stored data from db */
+       if (!gatt_db_attribute_read(desc->attr, 0, 0, NULL, read_op_cb, op)) {
+               error("Failed to read database");
+               goto fail;
+       }
+
        desc->read_id = 0;
 
-       /* Read the stored data from db */
-       gatt_db_attribute_read(desc->attr, 0, 0, NULL, read_op_cb, op);
+       return;
+
+fail:
+       reply = create_gatt_dbus_error(op->msg, att_ecode);
+       desc->read_id = 0;
+       g_dbus_send_message(btd_get_dbus_connection(), reply);
+       return;
 }
 
 static DBusMessage *descriptor_read_value(DBusConnection *conn,
@@ -845,20 +858,19 @@ static void chrc_read_cb(bool success, uint8_t att_ecode, const uint8_t *value,
        struct async_dbus_op *op = user_data;
        struct characteristic *chrc = op->data;
        struct service *service = chrc->service;
+       DBusMessage *reply;
 
-       if (!success) {
-               DBusMessage *reply = create_gatt_dbus_error(op->msg, att_ecode);
-
-               chrc->read_id = 0;
-               g_dbus_send_message(btd_get_dbus_connection(), reply);
-               return ;
-       }
+       if (!success)
+               goto fail;
 
        if (!op->offset)
                gatt_db_attribute_reset(chrc->attr);
 
-       gatt_db_attribute_write(chrc->attr, op->offset, value, length, 0, NULL,
-                                               write_characteristic_cb, chrc);
+       if (!gatt_db_attribute_write(chrc->attr, op->offset, value, length, 0,
+                                       NULL, write_characteristic_cb, chrc)) {
+               error("Failed to store attribute");
+               goto fail;
+       }
 
        /*
         * If the value length is exactly MTU-1, then we may not have read the
@@ -881,7 +893,17 @@ static void chrc_read_cb(bool success, uint8_t att_ecode, const uint8_t *value,
        chrc->read_id = 0;
 
        /* Read the stored data from db */
-       gatt_db_attribute_read(chrc->attr, 0, 0, NULL, read_op_cb, op);
+       if (!gatt_db_attribute_read(chrc->attr, 0, 0, NULL, read_op_cb, op)) {
+               error("Failed to read database");
+               goto fail;
+       }
+
+       return;
+
+fail:
+       reply = create_gatt_dbus_error(op->msg, att_ecode);
+       chrc->read_id = 0;
+       g_dbus_send_message(btd_get_dbus_connection(), reply);
 }
 
 static DBusMessage *characteristic_read_value(DBusConnection *conn,
@@ -1062,7 +1084,18 @@ static DBusMessage *characteristic_write_value_by_type(DBusConnection *conn,
                supported = true;
                chrc->write_id = bt_gatt_client_write_without_response(gatt,
                                        chrc->value_handle,
-                                       chrc->props & BT_GATT_CHRC_PROP_AUTH,
+                                       false,
+                                       value, value_len);
+               if (chrc->write_id) {
+                       chrc->write_id = 0;
+                       return dbus_message_new_method_return(msg);
+               }
+       } else if ((write_type & chrc->props) == BT_GATT_CHRC_PROP_AUTH) {
+               DBG("BT_GATT_CHRC_PROP_AUTH");
+               supported = true;
+               chrc->write_id = bt_gatt_client_write_without_response(gatt,
+                                       chrc->value_handle,
+                                       true,
                                        value, value_len);
                if (chrc->write_id) {
                        chrc->write_id = 0;
@@ -1486,11 +1519,29 @@ static struct characteristic *characteristic_create(
 
        chrc->service = service;
 
+#ifndef __TIZEN_PATCH__
        gatt_db_attribute_get_char_data(attr, &chrc->handle,
                                                        &chrc->value_handle,
                                                        &chrc->props, &uuid);
+#else
+       if (!gatt_db_attribute_get_char_data(attr, &chrc->handle,
+                                                       &chrc->value_handle,
+                                                       &chrc->props, &uuid)) {
+               queue_destroy(chrc->descs, NULL);
+               queue_destroy(chrc->notify_clients, NULL);
+               free(chrc);
+               return NULL;
+       }
+#endif
+
        chrc->attr = gatt_db_get_attribute(service->client->db,
                                                        chrc->value_handle);
+       if (!chrc->attr) {
+               error("Attribute 0x%04x not found", chrc->value_handle);
+               characteristic_free(chrc);
+               return NULL;
+       }
+
        bt_uuid_to_uuid128(&uuid, &chrc->uuid);
 
        chrc->path = g_strdup_printf("%s/char%04x", service->path,
@@ -1848,10 +1899,6 @@ static gboolean set_chrcs_ready(gpointer user_data)
 
        notify_chrcs(service);
 
-#ifdef __TIZEN_PATCH__
-       device_set_gatt_connected(service->client->device, TRUE);
-#endif
-
        return FALSE;
 }
 
@@ -1933,6 +1980,10 @@ void btd_gatt_client_destroy(struct btd_gatt_client *client)
        if (!client)
                return;
 
+#ifdef __TIZEN_PATCH__
+       if (client->wait_charcs_id)
+               g_source_remove(client->wait_charcs_id);
+#endif
        queue_destroy(client->services, unregister_service);
        queue_destroy(client->all_notify_clients, NULL);
        bt_gatt_client_unref(client->gatt);
@@ -1972,6 +2023,50 @@ fail:
        notify_client_free(notify_client);
 }
 
+#ifdef __TIZEN_PATCH__
+static void check_chrcs_ready(void *data, void *user_data)
+{
+       gboolean *chrcs_ready = user_data;
+       struct service *service = data;
+
+       /*
+       * Return FALSE if charcteristics are not ready or if there is
+       * any pending request to read char. extended properties exist.
+       */
+       if (!service->chrcs_ready ||
+               !queue_isempty(service->pending_ext_props))
+               *chrcs_ready = FALSE;
+}
+
+static gboolean check_all_chrcs_ready(gpointer user_data)
+{
+       struct btd_gatt_client *client = user_data;
+       gboolean all_chrcs_ready = TRUE;
+       static int count = 0;
+
+       queue_foreach(client->services, check_chrcs_ready, &all_chrcs_ready);
+
+       /*
+       * By adding below condition, forcing to call check_chrcs_ready()
+       * function to check whether all char./extended properties are ready.
+       * Above function would be called max. for 20 times (Assuming more
+       * no of services). Emit signal only when all characteristics are read.
+       */
+       if (all_chrcs_ready == FALSE && count < 20) {
+               count++;
+               return TRUE;
+       }
+
+       device_set_gatt_connected(client->device, TRUE);
+
+       client->wait_charcs_id = 0;
+
+       count = 0;
+
+       return FALSE;
+}
+#endif
+
 void btd_gatt_client_ready(struct btd_gatt_client *client)
 {
        struct bt_gatt_client *gatt;
@@ -1995,6 +2090,20 @@ void btd_gatt_client_ready(struct btd_gatt_client *client)
        if (queue_isempty(client->services)) {
                DBG("Exporting services");
                create_services(client);
+#ifdef __TIZEN_PATCH__
+       /*
+       * In case of more number of services and services having
+       * characteristics extended properties; GattConnected signal
+       * should be emitted only after all the characteristics are ready.
+       * This piece of code checks all the characteristics periodically and
+       * emit the signal if characteristics are ready.
+       */
+       if (client->wait_charcs_id > 0)
+               g_source_remove(client->wait_charcs_id);
+
+       client->wait_charcs_id = g_timeout_add(100,
+                                       check_all_chrcs_ready, client);
+#endif
                return;
        }
 
index e887bd2..0fa0f58 100644 (file)
@@ -23,6 +23,7 @@
 
 #include <stdint.h>
 #include <stdlib.h>
+#include <errno.h>
 
 #include "lib/bluetooth.h"
 #include "lib/sdp.h"
@@ -41,6 +42,7 @@
 #include "device.h"
 #include "gatt-database.h"
 #include "dbus-common.h"
+#include "profile.h"
 
 #ifndef ATT_CID
 #define ATT_CID 4
@@ -75,6 +77,7 @@ struct btd_gatt_database {
        struct gatt_db_attribute *svc_chngd;
        struct gatt_db_attribute *svc_chngd_ccc;
        struct queue *services;
+       struct queue *profiles;
 };
 
 struct external_service {
@@ -91,6 +94,14 @@ struct external_service {
        struct queue *descs;
 };
 
+struct external_profile {
+       struct btd_gatt_database *database;
+       char *owner;
+       char *path;     /* Path to GattProfile1 */
+       unsigned int id;
+       struct queue *profiles; /* btd_profile list */
+};
+
 struct external_chrc {
        struct external_service *service;
        char *path;
@@ -118,7 +129,11 @@ struct pending_op {
        unsigned int id;
        struct gatt_db_attribute *attrib;
        struct queue *owner_queue;
-       void *setup_data;
+       struct iovec data;
+#ifdef __TIZEN_PATCH__
+       bdaddr_t bdaddr;
+       uint8_t bdaddr_type;
+#endif
 };
 
 struct device_state {
@@ -197,6 +212,31 @@ find_device_state(struct btd_gatt_database *database, bdaddr_t *bdaddr,
        return queue_find(database->device_states, dev_state_match, &dev_info);
 }
 
+#ifdef __TIZEN_PATCH__
+static bool dev_addr_match(const void *a, const void *b)
+{
+       const struct device_state *dev_state = a;
+       const struct device_info *dev_info = b;
+
+       if (bacmp(&dev_state->bdaddr, &dev_info->bdaddr) == 0)
+               return TRUE;
+
+       return FALSE;
+}
+
+static struct device_state *
+find_device_state_from_address(struct btd_gatt_database *database, bdaddr_t *bdaddr)
+{
+       struct device_info dev_info;
+
+       memset(&dev_info, 0, sizeof(dev_info));
+
+       bacpy(&dev_info.bdaddr, bdaddr);
+
+       return queue_find(database->device_states, dev_addr_match, &dev_info);
+}
+#endif
+
 static bool ccc_state_match(const void *a, const void *b)
 {
        const struct ccc_state *ccc = a;
@@ -364,6 +404,52 @@ static void service_free(void *data)
        free(service);
 }
 
+static void profile_remove(void *data)
+{
+       struct btd_profile *p = data;
+
+       DBG("Removed \"%s\"", p->name);
+
+       adapter_foreach(adapter_remove_profile, p);
+
+       g_free((void *) p->name);
+       g_free((void *) p->remote_uuid);
+
+       free(p);
+}
+
+static void profile_release(struct external_profile *profile)
+{
+       DBusMessage *msg;
+
+       if (!profile->id)
+               return;
+
+       DBG("Releasing \"%s\"", profile->owner);
+
+       g_dbus_remove_watch(btd_get_dbus_connection(), profile->id);
+
+       msg = dbus_message_new_method_call(profile->owner, profile->path,
+                                               "org.bluez.GattProfile1",
+                                               "Release");
+       if (msg)
+               g_dbus_send_message(btd_get_dbus_connection(), msg);
+}
+
+static void profile_free(void *data)
+{
+       struct external_profile *profile = data;
+
+       queue_destroy(profile->profiles, profile_remove);
+
+       profile_release(profile);
+
+       g_free(profile->owner);
+       g_free(profile->path);
+
+       free(profile);
+}
+
 static void gatt_database_free(void *data)
 {
        struct btd_gatt_database *database = data;
@@ -390,6 +476,7 @@ static void gatt_database_free(void *data)
 
        queue_destroy(database->device_states, device_state_free);
        queue_destroy(database->services, service_free);
+       queue_destroy(database->profiles, profile_free);
        queue_destroy(database->ccc_callbacks, ccc_cb_free);
        database->device_states = NULL;
        database->ccc_callbacks = NULL;
@@ -494,6 +581,33 @@ done:
        gatt_db_attribute_read_result(attrib, id, error, value, len);
 }
 
+#ifdef __TIZEN_PATCH__
+static void gap_rpa_res_support_read_cb(struct gatt_db_attribute *attrib,
+                                       unsigned int id, uint16_t offset,
+                                       uint8_t opcode, struct bt_att *att,
+                                       void *user_data)
+{
+       struct btd_gatt_database *database = user_data;
+       uint8_t error = 0;
+       size_t len = 1;
+       const uint8_t *value = NULL;
+       uint8_t rpa_res_support = 0x00;
+
+       rpa_res_support = btd_adapter_get_rpa_res_support_value(database->adapter);
+
+       if (offset > 1) {
+               error = BT_ATT_ERROR_INVALID_OFFSET;
+               goto done;
+       }
+
+       len -= offset;
+       value = len ? &rpa_res_support : NULL;
+
+done:
+       gatt_db_attribute_read_result(attrib, id, error, value, len);
+}
+#endif
+
 static sdp_record_t *record_new(uuid_t *uuid, uint16_t start, uint16_t end)
 {
        sdp_list_t *svclass_id, *apseq, *proto[2], *root, *aproto;
@@ -589,7 +703,13 @@ static void populate_gap_service(struct btd_gatt_database *database)
 
        /* Add the GAP service */
        bt_uuid16_create(&uuid, UUID_GAP);
+
+#ifndef __TIZEN_PATCH__
        service = gatt_db_add_service(database->db, &uuid, true, 5);
+#else
+       service = gatt_db_add_service(database->db, &uuid, true, 7);
+#endif
+
        database->gap_handle = database_add_record(database, UUID_GAP, service,
                                                "Generic Access Profile");
 
@@ -611,6 +731,15 @@ static void populate_gap_service(struct btd_gatt_database *database)
                                                        gap_appearance_read_cb,
                                                        NULL, database);
 
+#ifdef __TIZEN_PATCH__
+       /* Central address resolution characteristic */
+       bt_uuid16_create(&uuid, GATT_CHARAC_CENTRAL_RPA_RESOLUTION);
+       gatt_db_service_add_characteristic(service, &uuid, BT_ATT_PERM_READ,
+                                                       BT_GATT_CHRC_PROP_READ,
+                                                       gap_rpa_res_support_read_cb,
+                                                       NULL, database);
+#endif
+
        gatt_db_service_set_active(service, true);
 }
 
@@ -902,6 +1031,32 @@ static void send_notification_to_devices(struct btd_gatt_database *database,
                                                                &notify);
 }
 
+#ifdef __TIZEN_PATCH__
+static void send_unicast_notification_to_device(struct btd_gatt_database *database,
+                                       uint16_t handle, const uint8_t *value,
+                                       uint16_t len, uint16_t ccc_handle,
+                                       bool indicate, bdaddr_t *unicast_addr)
+{
+       struct notify notify;
+       struct device_state *dev_state;
+
+       memset(&notify, 0, sizeof(notify));
+
+       notify.database = database;
+       notify.handle = handle;
+       notify.ccc_handle = ccc_handle;
+       notify.value = value;
+       notify.len = len;
+       notify.indicate = indicate;
+
+        /* Find and return a device state. */
+       dev_state = find_device_state_from_address(database, unicast_addr);
+
+       if (dev_state)
+               send_notification_to_device(dev_state, &notify);
+}
+#endif
+
 static void send_service_changed(struct btd_gatt_database *database,
                                        struct gatt_db_attribute *attrib)
 {
@@ -1366,6 +1521,7 @@ static bool parse_uuid(GDBusProxy *proxy, bt_uuid_t *uuid)
 static bool parse_primary(GDBusProxy *proxy, bool *primary)
 {
        DBusMessageIter iter;
+       dbus_bool_t val;
 
        if (!g_dbus_proxy_get_property(proxy, "Primary", &iter))
                return false;
@@ -1373,7 +1529,10 @@ static bool parse_primary(GDBusProxy *proxy, bool *primary)
        if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN)
                return false;
 
-       dbus_message_iter_get_basic(&iter, primary);
+       dbus_message_iter_get_basic(&iter, &val);
+
+       *primary = val;
+
        return true;
 }
 
@@ -1460,17 +1619,41 @@ static void pending_op_free(void *data)
        free(op);
 }
 
+#ifdef __TIZEN_PATCH__
+static struct pending_op *pending_read_new(struct queue *owner_queue,
+                                       struct gatt_db_attribute *attrib,
+                                       struct bt_att *att,
+                                       unsigned int id)
+#else
 static struct pending_op *pending_read_new(struct queue *owner_queue,
                                        struct gatt_db_attribute *attrib,
                                        unsigned int id)
+#endif
 {
        struct pending_op *op;
+#ifdef __TIZEN_PATCH__
+       bdaddr_t bdaddr;
+       uint8_t bdaddr_type;
+       char address[18];
+#endif
 
        op = new0(struct pending_op, 1);
        if (!op)
                return NULL;
 
+#ifdef __TIZEN_PATCH__
+       if (!get_dst_info(att, &bdaddr, &bdaddr_type)) {
+               free(op);
+               return NULL;
+       }
+#endif
+
        op->owner_queue = owner_queue;
+#ifdef __TIZEN_PATCH__
+       memcpy(&op->bdaddr, &bdaddr, sizeof(bdaddr_t));
+       op->bdaddr_type = bdaddr_type;
+#endif
+
        op->attrib = attrib;
        op->id = id;
        queue_push_tail(owner_queue, op);
@@ -1478,22 +1661,59 @@ static struct pending_op *pending_read_new(struct queue *owner_queue,
        return op;
 }
 
+#ifdef __TIZEN_PATCH__
+static void read_setup_cb(DBusMessageIter *iter, void *user_data)
+{
+       struct pending_op *op = user_data;
+       char dstaddr[18] = { 0 };
+       char *addr_value = NULL;
+       uint16_t offset = 0;
+
+       ba2str(&op->bdaddr, dstaddr);
+       addr_value = g_strdup(dstaddr);
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING,
+                                                       &addr_value);
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_BYTE,
+                                                       &op->id);
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT16,
+                                                       &offset);
+}
+#endif
+
+#ifdef __TIZEN_PATCH__
+static void send_read(struct gatt_db_attribute *attrib, struct bt_att *att,
+                                               GDBusProxy *proxy, struct queue *owner_queue,
+                                               unsigned int id)
+#else
 static void send_read(struct gatt_db_attribute *attrib, GDBusProxy *proxy,
                                                struct queue *owner_queue,
                                                unsigned int id)
+#endif
 {
        struct pending_op *op;
        uint8_t ecode = BT_ATT_ERROR_UNLIKELY;
 
+#ifdef __TIZEN_PATCH__
+       op = pending_read_new(owner_queue, attrib, att, id);
+#else
        op = pending_read_new(owner_queue, attrib, id);
+#endif
        if (!op) {
                error("Failed to allocate memory for pending read call");
                ecode = BT_ATT_ERROR_INSUFFICIENT_RESOURCES;
                goto error;
        }
 
+#ifdef __TIZEN_PATCH__
+       if (g_dbus_proxy_method_call(proxy, "ReadValue", read_setup_cb, read_reply_cb,
+                                               op, pending_op_free) == TRUE)
+#else
        if (g_dbus_proxy_method_call(proxy, "ReadValue", NULL, read_reply_cb,
                                                op, pending_op_free) == TRUE)
+#endif
                return;
 
        pending_op_free(op);
@@ -1505,12 +1725,30 @@ error:
 static void write_setup_cb(DBusMessageIter *iter, void *user_data)
 {
        struct pending_op *op = user_data;
-       struct iovec *iov = op->setup_data;
        DBusMessageIter array;
+#ifdef __TIZEN_PATCH__
+       char dstaddr[18] = { 0 };
+       char *addr_value = NULL;
+       uint16_t offset = 0;
+#endif
+
+#ifdef __TIZEN_PATCH__
+       ba2str(&op->bdaddr, dstaddr);
+       addr_value = g_strdup(dstaddr);
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING,
+                                                       &addr_value);
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_BYTE,
+                                                       &op->id);
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT16,
+                                                       &offset);
+#endif
 
        dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "y", &array);
        dbus_message_iter_append_fixed_array(&array, DBUS_TYPE_BYTE,
-                                               &iov->iov_base, iov->iov_len);
+                                       &op->data.iov_base, op->data.iov_len);
        dbus_message_iter_close_container(iter, &array);
 }
 
@@ -1550,40 +1788,71 @@ done:
        gatt_db_attribute_write_result(op->attrib, op->id, ecode);
 }
 
+#ifdef __TIZEN_PATCH__
+static struct pending_op *pending_write_new(struct queue *owner_queue,
+                                       struct gatt_db_attribute *attrib, struct bt_att *att,
+                                       unsigned int id,
+                                       const uint8_t *value,
+                                       size_t len)
+#else
 static struct pending_op *pending_write_new(struct queue *owner_queue,
                                        struct gatt_db_attribute *attrib,
                                        unsigned int id,
                                        const uint8_t *value,
                                        size_t len)
+#endif
 {
        struct pending_op *op;
-       struct iovec iov;
+#ifdef __TIZEN_PATCH__
+       bdaddr_t bdaddr;
+       uint8_t bdaddr_type;
+       char address[18];
+#endif
 
        op = new0(struct pending_op, 1);
        if (!op)
                return NULL;
+#ifdef __TIZEN_PATCH__
+       if (!get_dst_info(att, &bdaddr, &bdaddr_type)) {
+               free(op);
+               return NULL;
+       }
+#endif
 
-       iov.iov_base = (uint8_t *) value;
-       iov.iov_len = len;
+       op->data.iov_base = (uint8_t *) value;
+       op->data.iov_len = len;
+#ifdef __TIZEN_PATCH__
+       memcpy(&op->bdaddr, &bdaddr, sizeof(bdaddr_t));
+       op->bdaddr_type = bdaddr_type;
+#endif
 
        op->owner_queue = owner_queue;
        op->attrib = attrib;
        op->id = id;
-       op->setup_data = &iov;
        queue_push_tail(owner_queue, op);
 
        return op;
 }
 
+#ifdef __TIZEN_PATCH__
+static void send_write(struct gatt_db_attribute *attrib, struct bt_att *att,
+                                       GDBusProxy *proxy, struct queue *owner_queue,
+                                       unsigned int id, const uint8_t *value, size_t len)
+#else
 static void send_write(struct gatt_db_attribute *attrib, GDBusProxy *proxy,
                                        struct queue *owner_queue,
                                        unsigned int id,
                                        const uint8_t *value, size_t len)
+#endif
 {
        struct pending_op *op;
        uint8_t ecode = BT_ATT_ERROR_UNLIKELY;
 
+#ifdef __TIZEN_PATCH__
+       op = pending_write_new(owner_queue, attrib, att, id, value, len);
+#else
        op = pending_write_new(owner_queue, attrib, id, value, len);
+#endif
        if (!op) {
                error("Failed to allocate memory for pending read call");
                ecode = BT_ATT_ERROR_INSUFFICIENT_RESOURCES;
@@ -1677,7 +1946,63 @@ static void property_changed_cb(GDBusProxy *proxy, const char *name,
        DBusMessageIter array;
        uint8_t *value = NULL;
        int len = 0;
+#ifdef __TIZEN_PATCH__
+       const bdaddr_t *unicast_addr = NULL;
+#endif
+
+#ifdef __TIZEN_PATCH__
+       if (strcmp(name, "Value") == 0) {
+               if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY) {
+                       DBG("Malformed \"Value\" property received");
+                       return;
+               }
+
+               dbus_message_iter_recurse(iter, &array);
+               dbus_message_iter_get_fixed_array(&array, &value, &len);
+
+               if (len < 0) {
+                       DBG("Malformed \"Value\" property received");
+                       return;
+               }
 
+               /* Truncate the value if it's too large */
+               len = MIN(BT_ATT_MAX_VALUE_LEN, len);
+               value = len ? value : NULL;
+       } else if (strcmp(name, "Unicast") == 0) {
+               const char *address = NULL;
+               if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRING) {
+                       DBG("Malformed \"Value\" property received");
+                       return;
+               }
+
+               dbus_message_iter_get_basic(iter, &address);
+
+               if (address) {
+                       /* Set the address for unicast notification/indication */
+                       set_ccc_unicast_address(chrc->ccc, address);
+               }
+               return;
+       } else
+               return;
+
+       unicast_addr = get_ccc_unicast_address(chrc->ccc);
+
+       if (unicast_addr && bacmp(unicast_addr, BDADDR_ANY)) {
+               send_unicast_notification_to_device(chrc->service->database,
+                               gatt_db_attribute_get_handle(chrc->attrib),
+                               value, len,
+                               gatt_db_attribute_get_handle(chrc->ccc),
+                               chrc->props & BT_GATT_CHRC_PROP_INDICATE,
+                               unicast_addr);
+               /* reset the unicast address */
+               set_ccc_unicast_address(chrc->ccc, NULL);
+       } else
+               send_notification_to_devices(chrc->service->database,
+                                       gatt_db_attribute_get_handle(chrc->attrib),
+                                       value, len,
+                                       gatt_db_attribute_get_handle(chrc->ccc),
+                                       chrc->props & BT_GATT_CHRC_PROP_INDICATE);
+#else
        if (strcmp(name, "Value"))
                return;
 
@@ -1703,6 +2028,7 @@ static void property_changed_cb(GDBusProxy *proxy, const char *name,
                                value, len,
                                gatt_db_attribute_get_handle(chrc->ccc),
                                chrc->props & BT_GATT_CHRC_PROP_INDICATE);
+#endif
 }
 
 static bool database_add_ccc(struct external_service *service,
@@ -1783,8 +2109,11 @@ static void desc_read_cb(struct gatt_db_attribute *attrib,
                error("Read callback called with incorrect attribute");
                return;
        }
-
+#ifdef __TIZEN_PATCH__
+       send_read(attrib, att, desc->proxy, desc->pending_reads, id);
+#else
        send_read(attrib, desc->proxy, desc->pending_reads, id);
+#endif
 }
 
 static void desc_write_cb(struct gatt_db_attribute *attrib,
@@ -1800,7 +2129,11 @@ static void desc_write_cb(struct gatt_db_attribute *attrib,
                return;
        }
 
+#ifdef __TIZEN_PATCH__
+       send_write(attrib, att, desc->proxy, desc->pending_writes, id, value, len);
+#else
        send_write(attrib, desc->proxy, desc->pending_writes, id, value, len);
+#endif
 }
 
 static bool database_add_desc(struct external_service *service,
@@ -1842,7 +2175,11 @@ static void chrc_read_cb(struct gatt_db_attribute *attrib,
                return;
        }
 
+#ifdef __TIZEN_PATCH__
+       send_read(attrib, att, chrc->proxy, chrc->pending_reads, id);
+#else
        send_read(attrib, chrc->proxy, chrc->pending_reads, id);
+#endif
 }
 
 static void chrc_write_cb(struct gatt_db_attribute *attrib,
@@ -1858,8 +2195,31 @@ static void chrc_write_cb(struct gatt_db_attribute *attrib,
                return;
        }
 
+#ifdef __TIZEN_PATCH__
+       send_write(attrib, att, chrc->proxy, chrc->pending_writes, id, value, len);
+#else
        send_write(attrib, chrc->proxy, chrc->pending_writes, id, value, len);
+#endif
+}
+
+#ifdef __TIZEN_PATCH__
+static bool database_check_ccc_desc(struct external_desc *desc)
+{
+       bt_uuid_t uuid, uuid_ccc;
+       char uuidstr[MAX_LEN_UUID_STR];
+
+       if (!parse_uuid(desc->proxy, &uuid)) {
+               error("Failed to read \"UUID\" property of descriptor");
+               return false;
+       }
+
+       bt_uuid16_create(&uuid_ccc, GATT_CLIENT_CHARAC_CFG_UUID);
+       if (bt_uuid_cmp(&uuid, &uuid_ccc) == 0)
+               return true;
+       else
+               return false;
 }
+#endif
 
 static bool database_add_chrc(struct external_service *service,
                                                struct external_chrc *chrc)
@@ -1893,8 +2253,13 @@ static bool database_add_chrc(struct external_service *service,
                return false;
        }
 
+#ifndef __TIZEN_PATCH__
+       /* Existing implementation adds CCC descriptor by default
+         * if notification and indication properties are set. But as per the requirment
+         * CCCD shall be added by the application */
        if (!database_add_ccc(service, chrc))
                return false;
+#endif
 
        if (!database_add_cep(service, chrc))
                return false;
@@ -1904,15 +2269,34 @@ static bool database_add_chrc(struct external_service *service,
        while (entry) {
                struct external_desc *desc = entry->data;
 
-               if (desc->handled || g_strcmp0(desc->chrc_path, chrc->path))
+               if (desc->handled || g_strcmp0(desc->chrc_path, chrc->path)) {
+#ifdef __TIZEN_PATCH__
+                       entry = entry->next;
+#endif
                        continue;
-
+               }
+#ifdef __TIZEN_PATCH__
+               /* Check if Application wants to add CCC and use existing
+                * implemenation to add CCC descriptors */
+               if (database_check_ccc_desc(desc)) {
+                       if (!database_add_ccc(service, chrc)) {
+                               chrc->attrib = NULL;
+                               return false;
+                       }
+                       desc->attrib = chrc->ccc;
+                       desc->handled = true;
+               } else if (!database_add_desc(service, desc)) {
+                       chrc->attrib = NULL;
+                       error("Failed to create descriptor entry");
+                               return false;
+               }
+#else
                if (!database_add_desc(service, desc)) {
                        chrc->attrib = NULL;
                        error("Failed to create descriptor entry");
                        return false;
                }
-
+#endif
                entry = entry->next;
        }
 
@@ -2132,14 +2516,226 @@ static DBusMessage *manager_unregister_service(DBusConnection *conn,
        return dbus_message_new_method_return(msg);
 }
 
+static void profile_exited(DBusConnection *conn, void *user_data)
+{
+       struct external_profile *profile = user_data;
+
+       DBG("\"%s\" exited", profile->owner);
+
+       profile->id = 0;
+
+       queue_remove(profile->database->profiles, profile);
+
+       profile_free(profile);
+}
+
+static int profile_add(struct external_profile *profile, const char *uuid)
+{
+       struct btd_profile *p;
+
+       p = new0(struct btd_profile, 1);
+       if (!p)
+               goto fail;
+       /* Assign directly to avoid having extra fields */
+       p->name = (const void *) g_strdup_printf("%s%s/%s", profile->owner,
+                                                       profile->path, uuid);
+       if (!p->name)
+               goto fail;
+
+       p->remote_uuid = (const void *) g_strdup(uuid);
+       if (!p->remote_uuid)
+               goto fail;
+
+       p->auto_connect = true;
+
+       queue_push_tail(profile->profiles, p);
+
+       DBG("Added \"%s\"", p->name);
+
+       return 0;
+fail:
+       error("Fail to add profile");
+
+       if (p) {
+               g_free(p->name);
+               g_free(p->remote_uuid);
+               free(p);
+       }
+
+       return -ENOMEM;
+}
+
+static void add_profile(void *data, void *user_data)
+{
+       struct btd_adapter *adapter = user_data;
+
+       adapter_add_profile(adapter, data);
+}
+
+static int profile_create(DBusConnection *conn,
+                               struct btd_gatt_database *database,
+                               const char *sender, const char *path,
+                               DBusMessageIter *iter)
+{
+       struct external_profile *profile;
+       DBusMessageIter uuids;
+
+       if (!path || !g_str_has_prefix(path, "/"))
+               return -EINVAL;
+
+       profile = new0(struct external_profile, 1);
+       if (!profile)
+               return -ENOMEM;
+
+       profile->owner = g_strdup(sender);
+       if (!profile->owner)
+               goto fail;
+
+       profile->path = g_strdup(path);
+       if (!profile->path)
+               goto fail;
+
+       profile->profiles = queue_new();
+       if (!profile->profiles)
+               goto fail;
+
+       profile->database = database;
+       profile->id = g_dbus_add_disconnect_watch(conn, sender, profile_exited,
+                                                               profile, NULL);
+
+       dbus_message_iter_recurse(iter, &uuids);
+
+       while (dbus_message_iter_get_arg_type(&uuids) == DBUS_TYPE_STRING) {
+               const char *uuid;
+
+               dbus_message_iter_get_basic(&uuids, &uuid);
+
+               if (profile_add(profile, uuid) < 0)
+                       goto fail;
+
+               dbus_message_iter_next(&uuids);
+       }
+
+       if (queue_isempty(profile->profiles))
+               goto fail;
+
+       queue_foreach(profile->profiles, add_profile, database->adapter);
+       queue_push_tail(database->profiles, profile);
+
+       return 0;
+
+fail:
+       profile_free(profile);
+       return -EINVAL;
+}
+
+static bool match_profile(const void *a, const void *b)
+{
+       const struct external_profile *profile = a;
+       const struct svc_match_data *data = b;
+
+       return g_strcmp0(profile->path, data->path) == 0 &&
+                               g_strcmp0(profile->owner, data->sender) == 0;
+}
+
+static DBusMessage *manager_register_profile(DBusConnection *conn,
+                                       DBusMessage *msg, void *user_data)
+{
+       struct btd_gatt_database *database = user_data;
+       const char *sender = dbus_message_get_sender(msg);
+       DBusMessageIter args;
+       const char *path;
+       struct svc_match_data match_data;
+
+       DBG("sender %s", sender);
+
+       if (!dbus_message_iter_init(msg, &args))
+               return btd_error_invalid_args(msg);
+
+       if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_OBJECT_PATH)
+               return btd_error_invalid_args(msg);
+
+       dbus_message_iter_get_basic(&args, &path);
+
+       match_data.path = path;
+       match_data.sender = sender;
+
+       if (queue_find(database->profiles, match_profile, &match_data))
+               return btd_error_already_exists(msg);
+
+       dbus_message_iter_next(&args);
+       if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_ARRAY)
+               return btd_error_invalid_args(msg);
+
+       if (profile_create(conn, database, sender, path, &args) < 0)
+               return btd_error_failed(msg, "Failed to register profile");
+
+       return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *manager_unregister_profile(DBusConnection *conn,
+                                       DBusMessage *msg, void *user_data)
+{
+       struct btd_gatt_database *database = user_data;
+       const char *sender = dbus_message_get_sender(msg);
+       const char *path;
+       DBusMessageIter args;
+       struct external_profile *profile;
+       struct svc_match_data match_data;
+
+       if (!dbus_message_iter_init(msg, &args))
+               return btd_error_invalid_args(msg);
+
+       if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_OBJECT_PATH)
+               return btd_error_invalid_args(msg);
+
+       dbus_message_iter_get_basic(&args, &path);
+
+       match_data.path = path;
+       match_data.sender = sender;
+
+       profile = queue_remove_if(database->profiles, match_profile,
+                                                               &match_data);
+       if (!profile)
+               return btd_error_does_not_exist(msg);
+
+       profile_free(profile);
+
+       return dbus_message_new_method_return(msg);
+}
+
 static const GDBusMethodTable manager_methods[] = {
+#ifdef __TIZEN_PATCH__
+       { GDBUS_ASYNC_METHOD("RegisterService",
+                       GDBUS_ARGS({ "service", "o" }, { "options", "a{sv}" }),
+                       NULL, manager_register_service) },
+       { GDBUS_ASYNC_METHOD("UnregisterService",
+                                       GDBUS_ARGS({ "service", "o" }),
+                                       NULL, manager_unregister_service) },
+       { GDBUS_ASYNC_METHOD("RegisterProfile",
+                       GDBUS_ARGS({ "profile", "o" }, { "UUIDs", "as" },
+                       { "options", "a{sv}" }), NULL,
+                       manager_register_profile) },
+       { GDBUS_ASYNC_METHOD("UnregisterProfile",
+                                       GDBUS_ARGS({ "profile", "o" }),
+                                       NULL, manager_unregister_profile) },
+       { }
+#else
        { GDBUS_EXPERIMENTAL_ASYNC_METHOD("RegisterService",
                        GDBUS_ARGS({ "service", "o" }, { "options", "a{sv}" }),
                        NULL, manager_register_service) },
        { GDBUS_EXPERIMENTAL_ASYNC_METHOD("UnregisterService",
                                        GDBUS_ARGS({ "service", "o" }),
                                        NULL, manager_unregister_service) },
+       { GDBUS_EXPERIMENTAL_ASYNC_METHOD("RegisterProfile",
+                       GDBUS_ARGS({ "profile", "o" }, { "UUIDs", "as" },
+                       { "options", "a{sv}" }), NULL,
+                       manager_register_profile) },
+       { GDBUS_EXPERIMENTAL_ASYNC_METHOD("UnregisterProfile",
+                                       GDBUS_ARGS({ "profile", "o" }),
+                                       NULL, manager_unregister_profile) },
        { }
+#endif
 };
 
 struct btd_gatt_database *btd_gatt_database_new(struct btd_adapter *adapter)
@@ -2168,6 +2764,10 @@ struct btd_gatt_database *btd_gatt_database_new(struct btd_adapter *adapter)
        if (!database->services)
                goto fail;
 
+       database->profiles = queue_new();
+       if (!database->profiles)
+               goto fail;
+
        database->ccc_callbacks = queue_new();
        if (!database->ccc_callbacks)
                goto fail;
index a10566a..3fc2b08 100644 (file)
@@ -551,6 +551,8 @@ bool btd_gatt_update_attr_db(void)
                                } else {
                                        new_service_add = TRUE;
                                }
+                       } else if (local_attr->type.value.u16 == GATT_CHARAC_UUID) {
+                               continue;
                        }
                        /* Fix : RESOURCE_LEAK */
                        if (temp_att) {
index ec421bd..251a200 100644 (file)
@@ -38,6 +38,7 @@ struct main_opts {
        gboolean        reverse_sdp;
        gboolean        name_resolv;
        gboolean        debug_keys;
+       gboolean        fast_conn;
 #ifdef __TIZEN_PATCH__
        gboolean        le_privacy;
 #endif
index 96cbae8..4adf008 100644 (file)
@@ -335,6 +335,13 @@ static void parse_config(GKeyFile *config)
 
                g_free(str);
        }
+
+       boolean = g_key_file_get_boolean(config, "General",
+                                               "FastConnectable", &err);
+       if (err)
+               g_clear_error(&err);
+       else
+               main_opts.fast_conn = boolean;
 #ifdef __TIZEN_PATCH__
        boolean = g_key_file_get_boolean(config, "General",
                                                "EnableLEPrivacy", &err);
@@ -618,7 +625,7 @@ int main(int argc, char *argv[])
 
        g_dbus_set_flags(gdbus_flags);
 
-#ifdef __TIZEN_PATCH__
+#if 0
        gatt_init();
 #endif
 
@@ -687,7 +694,7 @@ int main(int argc, char *argv[])
 
        adapter_cleanup();
 
-#ifdef __TIZEN_PATCH__
+#if 0
        gatt_cleanup();
 #endif
 
diff --git a/src/main.conf b/src/main.conf
new file mode 100644 (file)
index 0000000..884f68d
--- /dev/null
@@ -0,0 +1,76 @@
+[General]
+
+# Default adaper name
+# %h - substituted for hostname
+# %d - substituted for adapter id
+# Defaults to 'BlueZ'
+#Name = %h-%d
+
+# Default device class. Only the major and minor device class bits are
+# considered. Defaults to '0x000000'.
+#Class = 0x000100
+
+# How long to stay in discoverable mode before going back to non-discoverable
+# The value is in seconds. Default is 180, i.e. 3 minutes.
+# 0 = disable timer, i.e. stay discoverable forever
+#DiscoverableTimeout = 0
+
+# How long to stay in pairable mode before going back to non-discoverable
+# The value is in seconds. Default is 0.
+# 0 = disable timer, i.e. stay pairable forever
+#PairableTimeout = 0
+
+# Automatic connection for bonded devices driven by platform/user events.
+# If a platform plugin uses this mechanism, automatic connections will be
+# enabled during the interval defined below. Initially, this feature
+# intends to be used to establish connections to ATT channels. Default is 60.
+#AutoConnectTimeout = 60
+
+# Use vendor id source (assigner), vendor, product and version information for
+# DID profile support. The values are separated by ":" and assigner, VID, PID
+# and version.
+# Possible vendor id source values: bluetooth, usb (defaults to usb)
+#DeviceID = bluetooth:1234:5678:abcd
+
+# Do reverse service discovery for previously unknown devices that connect to
+# us. This option is really only needed for qualification since the BITE tester
+# doesn't like us doing reverse SDP for some test cases (though there could in
+# theory be other useful purposes for this too). Defaults to 'true'.
+#ReverseServiceDiscovery = true
+
+# Enable name resolving after inquiry. Set it to 'false' if you don't need
+# remote devices name and want shorter discovery cycle. Defaults to 'true'.
+#NameResolving = true
+
+# Enable runtime persistency of debug link keys. Default is false which
+# makes debug link keys valid only for the duration of the connection
+# that they were created for.
+#DebugKeys = false
+
+# Restricts all controllers to the specified transport. Default value
+# is "dual", i.e. both BR/EDR and LE enabled (when supported by the HW).
+# Possible values: "dual", "bredr", "le"
+#ControllerMode = dual
+
+# Enables Multi Profile Specification support. This allows to specify if
+# system supports only Multiple Profiles Single Device (MPSD) configuration
+# or both Multiple Profiles Single Device (MPSD) and Multiple Profiles Multiple
+# Devices (MPMD) configurations.
+# Possible values: "off", "single", "multiple"
+#MultiProfile = off
+
+# Permanently enables the Fast Connectable setting for adapters that
+# support it. When enabled other devices can connect faster to us,
+# however the tradeoff is increased power consumptions. This feature
+# will fully work only on kernel version 4.1 and newer. Defaults to
+# 'false'.
+#FastConnectable = false
+
+#[Policy]
+#
+# The ReconnectUUIDs defines the set of remote services that should try
+# to be reconnected to in case of a link loss (link supervision
+# timeout). The policy plugin should contain a sane set of values by
+# default, but this list can be overridden here. By setting the list to
+# empty the reconnection feature gets disabled.
+#ReconnectUUIDs=
old mode 100644 (file)
new mode 100755 (executable)
index 29acad0..c748ed7
@@ -63,6 +63,19 @@ Class = 0x00020C        # Smart phone
 # Possible values: "off", "single", "multiple"
 #MultiProfile = off
 
+# Permanently enables the Fast Connectable setting for adapters that
+# support it. When enabled other devices can connect faster to us,
+# however the tradeoff is increased power consumptions. This feature
+# will fully work only on kernel version 4.1 and newer. Defaults to
+# 'false'.
+#FastConnectable = false
+
+#ifdef __TIZEN_PATCH__
+# Enable the LE Privacy feature. If value is true, i.e. LE Privacy is enabled
+# otherwise the feature is disabled by default for the local device.
+EnableLEPrivacy = false
+#endif
+
 #[Policy]
 #
 # The ReconnectUUIDs defines the set of remote services that should try
@@ -72,8 +85,3 @@ Class = 0x00020C        # Smart phone
 # empty the reconnection feature gets disabled.
 #ReconnectUUIDs=
 
-#ifdef __TIZEN_PATCH__
-# Enable the LE Privacy feature. If value is true, i.e. LE Privacy is enabled
-# otherwise the feature is disabled by default for the local device.
-EnableLEPrivacy = false
-#endif
old mode 100644 (file)
new mode 100755 (executable)
index 17312e9..2709355
@@ -56,17 +56,29 @@ Class = 0x000704        # Wearable, Wrist Watch
 # Possible values: "dual", "bredr", "le"
 #ControllerMode = dual
 
-#[Policy]
+# Permanently enables the Fast Connectable setting for adapters that
+# support it. When enabled other devices can connect faster to us,
+# however the tradeoff is increased power consumptions. This feature
+# will fully work only on kernel version 4.1 and newer. Defaults to
+# 'false'.
+#FastConnectable = false
+
+#ifdef __TIZEN_PATCH__
+# Enable the LE Privacy feature. If value is true, i.e. LE Privacy is enabled
+# otherwise the feature is disabled by default for the local device.
+EnableLEPrivacy = false
+#endif
+
+[Policy]
 #
 # The ReconnectUUIDs defines the set of remote services that should try
 # to be reconnected to in case of a link loss (link supervision
 # timeout). The policy plugin should contain a sane set of values by
 # default, but this list can be overridden here. By setting the list to
 # empty the reconnection feature gets disabled.
-#ReconnectUUIDs=
-
 #ifdef __TIZEN_PATCH__
-# Enable the LE Privacy feature. If value is true, i.e. LE Privacy is enabled
-# otherwise the feature is disabled by default for the local device.
-EnableLEPrivacy = false
+ReconnectUUIDs=
+#else
+#ReconnectUUIDs=
 #endif
+
index 2fbdb53..f174f7e 100644 (file)
 #define BTD_PROFILE_PSM_AUTO   -1
 #define BTD_PROFILE_CHAN_AUTO  -1
 
+#ifdef TIZEN_BT_HID_DEVICE_ENABLE
+#define HID_DEVICE_INTR_PSM 17
+#define HID_DEVICE_CTRL_PSM 19
+#endif
+
 #define HFP_HF_RECORD                                                  \
        "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>                    \
        <record>                                                        \
                </attribute>                                            \
        </record>"
 
+#ifdef TIZEN_BT_HID_DEVICE_ENABLE
+#define HID_DEVICE_RECORD      \
+       "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>    \
+       <record>        \
+       <attribute id=\"0x0001\">       \
+               <sequence>      \
+                       <uuid value=\"0x1124\" />       \
+               </sequence>     \
+       </attribute>    \
+       <attribute id=\"0x0004\">       \
+               <sequence>      \
+                       <sequence>      \
+                               <uuid value=\"0x0100\" />       \
+                               <uint16 value=\"0x0011\" />     \
+                       </sequence>     \
+                       <sequence>      \
+                               <uuid value=\"0x0011\" />       \
+                       </sequence>     \
+               </sequence>     \
+       </attribute>    \
+       <attribute id=\"0x0005\">       \
+               <sequence>      \
+                       <uuid value=\"0x1002\" />       \
+               </sequence>     \
+       </attribute>    \
+       <attribute id=\"0x0006\">       \
+               <sequence>      \
+                       <uint16 value=\"0x656e\" />     \
+                       <uint16 value=\"0x006a\" />     \
+                       <uint16 value=\"0x0100\" />     \
+               </sequence>     \
+       </attribute>    \
+       <attribute id=\"0x0009\">       \
+               <sequence>      \
+                       <sequence>      \
+                               <uuid value=\"0x0011\" />       \
+                               <uint16 value=\"0x0100\" />     \
+                       </sequence>     \
+               </sequence>     \
+       </attribute>    \
+       <attribute id=\"0x000d\">       \
+               <sequence>      \
+                       <sequence>      \
+                               <sequence>      \
+                                       <uuid value=\"0x0100\" />       \
+                                       <uint16 value=\"0x0013\" />     \
+                               </sequence>     \
+                               <sequence>      \
+                                       <uuid value=\"0x0011\" />       \
+                               </sequence>     \
+                       </sequence>     \
+               </sequence>     \
+       </attribute>    \
+       <attribute id=\"0x0100\">       \
+               <text value=\"Bluez Mouse\" />  \
+       </attribute>    \
+       <attribute id=\"0x0101\">       \
+               <text value=\"Mouse\" />        \
+       </attribute>    \
+       <attribute id=\"0x0200\">       \
+               <uint16 value=\"0x0100\" />     \
+       </attribute>    \
+       <attribute id=\"0x0201\">       \
+               <uint16 value=\"0x0111\" />     \
+       </attribute>    \
+       <attribute id=\"0x0202\">       \
+               <uint8 value=\"0x40\" />                \
+       </attribute>    \
+       <attribute id=\"0x0203\">       \
+               <uint8 value=\"0x00\" />                \
+       </attribute>    \
+       <attribute id=\"0x0204\">       \
+               <boolean value=\"true\" />      \
+       </attribute>    \
+       <attribute id=\"0x0205\">       \
+               <boolean value=\"true\" />      \
+       </attribute>    \
+       <attribute id=\"0x0206\">       \
+               <sequence>      \
+                       <sequence>      \
+                               <uint8 value=\"0x22\" />                \
+                               <text encoding=\"hex\" value=\"05010902a10185010901a1000509190129031500250175019503810275059501810105010930093109381581257f750895028106c0c005010906a1018502a100050719e029e71500250175019508810295087508150025650507190029658100c0c0\" />        \
+                       </sequence>     \
+               </sequence>     \
+       </attribute>    \
+       <attribute id=\"0x0207\">       \
+               <sequence>      \
+                       <sequence>      \
+                               <uint16 value=\"0x0409\" />     \
+                               <uint16 value=\"0x0100\" />     \
+                       </sequence>     \
+               </sequence>     \
+       </attribute>    \
+       <attribute id=\"0x020b\">       \
+               <uint16 value=\"0x0100\" />     \
+       </attribute>    \
+       <attribute id=\"0x020e\">       \
+               <boolean value=\"true\" />      \
+       </attribute>    \
+       </record>"
+#endif
+
+
 struct ext_io;
 
 struct ext_profile {
@@ -759,6 +867,9 @@ struct ext_profile {
        char *destination;
        char *app_path;
 #endif
+#ifdef TIZEN_BT_HID_DEVICE_ENABLE
+       bool local_connect;
+#endif
 };
 
 struct ext_io {
@@ -802,6 +913,11 @@ static GSList *custom_props = NULL;
 static GSList *profiles = NULL;
 static GSList *ext_profiles = NULL;
 
+#ifdef TIZEN_BT_HID_DEVICE_ENABLE
+static int connect_io(struct ext_io *conn, const bdaddr_t *src,
+                                                       const bdaddr_t *dst);
+#endif
+
 void btd_profile_foreach(void (*func)(struct btd_profile *p, void *data),
                                                                void *data)
 {
@@ -1114,6 +1230,16 @@ static bool send_new_connection(struct ext_profile *ext, struct ext_io *conn)
        return true;
 }
 
+#ifdef TIZEN_BT_HID_DEVICE_ENABLE
+static int check_connection_psm(gconstpointer a, gconstpointer b)
+{
+       const struct ext_io *conn = a;
+       const int *psm = b;
+       DBG("conn->psm %d, psm %d", conn->psm, *psm);
+       return (conn->psm == *psm ? 0 : -1);
+}
+#endif
+
 static void ext_connect(GIOChannel *io, GError *err, gpointer user_data)
 {
        struct ext_io *conn = user_data;
@@ -1148,7 +1274,31 @@ static void ext_connect(GIOChannel *io, GError *err, gpointer user_data)
                conn->io_id = g_io_add_watch(io, cond, ext_io_disconnected,
                                                                        conn);
        }
-
+#ifdef TIZEN_BT_HID_DEVICE_ENABLE
+       if (g_strcmp0(ext->uuid, HID_UUID) == 0 && ext->local_connect == TRUE) {
+               GSList *l = NULL;
+               int psm = HID_DEVICE_CTRL_PSM;
+               ext->local_connect = FALSE;
+               l = g_slist_find_custom(ext->conns, &psm, check_connection_psm);
+               if (l == NULL) {
+                       struct ext_io *conn1 = g_new0(struct ext_io, 1);
+                       int error = 0;
+                       ext->remote_psm = psm;
+                       conn1->ext = ext;
+                       conn1->psm = ext->remote_psm;
+                       conn1->chan = ext->remote_chan;
+                       error = connect_io(conn1, btd_adapter_get_address(conn->adapter),
+                                                       device_get_address(conn->device));
+                       DBG("error from connect_io %d", error);
+                       conn1->adapter = btd_adapter_ref(conn->adapter);
+                       conn1->device = btd_device_ref(conn->device);
+                       conn1->service = btd_service_ref(conn->service);
+                       ext->conns = g_slist_append(ext->conns, conn1);
+               } else {
+                       DBG("Connection Already there");
+               }
+       }
+#endif
        if (send_new_connection(ext, conn))
                return;
 
@@ -1357,11 +1507,17 @@ static uint32_t ext_start_servers(struct ext_profile *ext,
                                                struct btd_adapter *adapter)
 {
        struct ext_io *l2cap = NULL;
+#ifdef TIZEN_BT_HID_DEVICE_ENABLE
+       struct ext_io *l2cap1 = NULL;
+#endif
        struct ext_io *rfcomm = NULL;
        BtIOConfirm confirm;
        BtIOConnect connect;
        GError *err = NULL;
        GIOChannel *io;
+#ifdef TIZEN_BT_HID_DEVICE_ENABLE
+       GIOChannel *io1;
+#endif
 
        if (ext->authorize) {
                confirm = ext_confirm;
@@ -1407,6 +1563,26 @@ static uint32_t ext_start_servers(struct ext_profile *ext,
                        ext->servers = g_slist_append(ext->servers, l2cap);
                        DBG("%s listening on PSM %u", ext->name, psm);
                }
+#ifdef TIZEN_BT_HID_DEVICE_ENABLE
+               if (g_strcmp0(ext->uuid , HID_UUID) == 0) {
+                       psm = HID_DEVICE_CTRL_PSM;
+                       l2cap1 = g_new0(struct ext_io, 1);
+                       l2cap1->ext = ext;
+                       io1 = bt_io_listen(connect, confirm, l2cap, NULL, &err,
+                                               BT_IO_OPT_SOURCE_BDADDR,
+                                               btd_adapter_get_address(adapter),
+                                               BT_IO_OPT_MODE, ext->mode,
+                                               BT_IO_OPT_PSM, psm,
+                                               BT_IO_OPT_SEC_LEVEL, ext->sec_level,
+                                               BT_IO_OPT_INVALID);
+                       l2cap1->io = io1;
+                       l2cap1->proto = BTPROTO_L2CAP;
+                       l2cap1->psm = psm;
+                       l2cap1->adapter = btd_adapter_ref(adapter);
+                       ext->servers = g_slist_append(ext->servers, l2cap1);
+                       DBG("%s listening on PSM %u", ext->name, psm);
+               }
+#endif
        }
 
        if (ext->local_chan) {
@@ -1807,7 +1983,7 @@ static int ext_connect_dev(struct btd_service *service)
 
        conn = g_new0(struct ext_io, 1);
        conn->ext = ext;
-
+#ifndef TIZEN_BT_HID_DEVICE_ENABLE
        if (ext->remote_psm || ext->remote_chan) {
                conn->psm = ext->remote_psm;
                conn->chan = ext->remote_chan;
@@ -1820,7 +1996,28 @@ static int ext_connect_dev(struct btd_service *service)
 
        if (err < 0)
                goto failed;
-
+#else
+       if (g_strcmp0(ext->uuid, HID_UUID) == 0) {
+               ext->local_connect = TRUE;
+               ext->remote_psm = HID_DEVICE_INTR_PSM;
+               conn->psm = ext->remote_psm;
+               conn->chan = ext->remote_chan;
+               err = connect_io(conn, btd_adapter_get_address(adapter),
+                                               device_get_address(dev));
+       } else {
+               if (ext->remote_psm || ext->remote_chan) {
+                       conn->psm = ext->remote_psm;
+                       conn->chan = ext->remote_chan;
+                       err = connect_io(conn, btd_adapter_get_address(adapter),
+                                                       device_get_address(dev));
+               } else {
+                       err = resolve_service(conn, btd_adapter_get_address(adapter),
+                                                       device_get_address(dev));
+               }
+       }
+       if (err < 0)
+               goto failed;
+#endif
        conn->adapter = btd_adapter_ref(adapter);
        conn->device = btd_device_ref(dev);
        conn->service = btd_service_ref(service);
@@ -1878,6 +2075,7 @@ static int ext_disconnect_dev(struct btd_service *service)
        if (!ext)
                return -ENOENT;
 
+#ifndef TIZEN_BT_HID_DEVICE_ENABLE
        conn = find_connection(ext, dev);
        if (!conn || !conn->connected)
                return -ENOTCONN;
@@ -1888,7 +2086,30 @@ static int ext_disconnect_dev(struct btd_service *service)
        err = send_disconn_req(ext, conn);
        if (err < 0)
                return err;
+#else
+       if (g_strcmp0(ext->uuid, HID_UUID) != 0) {
+               conn = find_connection(ext, dev);
+               if (!conn || !conn->connected)
+                       return -ENOTCONN;
+
+               if (conn->pending)
+                       return -EBUSY;
 
+               err = send_disconn_req(ext, conn);
+               if (err < 0)
+                       return err;
+       } else {
+               GSList *l;
+               /* As HID will be using two psm we need to send disconnect
+                 * request for both the psms */
+               for (l = ext->conns; l != NULL; l = g_slist_next(l)) {
+                       struct ext_io *conn1 = l->data;
+                       if (conn1->device == dev) {
+                               err = send_disconn_req(ext, conn1);
+                       }
+               }
+       }
+#endif
        return 0;
 }
 
@@ -1990,7 +2211,13 @@ static char *get_sync_record(struct ext_profile *ext, struct ext_io *l2cap,
        return g_strdup_printf(SYNC_RECORD, rfcomm->chan, ext->version,
                                                                ext->name);
 }
-
+#ifdef TIZEN_BT_HID_DEVICE_ENABLE
+static char *get_hid_device_record(struct ext_profile *ext, struct ext_io *l2cap,
+                                                       struct ext_io *rfcomm)
+{
+       return g_strdup(HID_DEVICE_RECORD);
+}
+#endif
 static char *get_opp_record(struct ext_profile *ext, struct ext_io *l2cap,
                                                        struct ext_io *rfcomm)
 {
@@ -2210,7 +2437,18 @@ static struct default_settings {
                .authorize      = true,
                .get_record     = get_mns_record,
                .version        = 0x0102
+#ifdef TIZEN_BT_HID_DEVICE_ENABLE
+       }, {
+               .uuid           = HID_UUID,
+               .name           = "HID Device",
+               .psm            = HID_DEVICE_INTR_PSM,
+               .authorize      = TRUE,
+               .get_record     = get_hid_device_record,
+               .version                = 0x0100,
        },
+#else
+       },
+#endif
 };
 
 static void ext_set_defaults(struct ext_profile *ext)
index 7671d67..422cc2c 100644 (file)
@@ -1426,3 +1426,11 @@ bool bt_att_set_remote_key(struct bt_att *att, uint8_t sign_key[16],
 
        return sign_set_key(&att->remote_sign, sign_key, func, user_data);
 }
+
+bool bt_att_has_crypto(struct bt_att *att)
+{
+       if (!att)
+               return false;
+
+       return att->crypto ? true : false;
+}
index a440aaf..fb6247e 100644 (file)
@@ -90,3 +90,4 @@ bool bt_att_set_local_key(struct bt_att *att, uint8_t sign_key[16],
                        bt_att_counter_func_t func, void *user_data);
 bool bt_att_set_remote_key(struct bt_att *att, uint8_t sign_key[16],
                        bt_att_counter_func_t func, void *user_data);
+bool bt_att_has_crypto(struct bt_att *att);
index 3592c2e..d8be5ea 100644 (file)
@@ -25,6 +25,9 @@
 #include <config.h>
 #endif
 
+#ifdef __TIZEN_PATCH__
+#include <stdio.h>
+#endif
 #include <endian.h>
 #include <fcntl.h>
 #include <unistd.h>
@@ -72,6 +75,11 @@ struct btsnoop {
        uint16_t index;
        bool aborted;
        bool pklg_format;
+#ifdef __TIZEN_PATCH__
+       char *path;
+       int16_t rotate_count;
+       ssize_t file_size;
+#endif
 };
 
 struct btsnoop *btsnoop_open(const char *path, unsigned long flags)
@@ -128,7 +136,12 @@ failed:
        return NULL;
 }
 
+#ifdef __TIZEN_PATCH__
+struct btsnoop *btsnoop_create(const char *path, uint32_t type,
+               int16_t rotate_count, ssize_t file_size)
+#else
 struct btsnoop *btsnoop_create(const char *path, uint32_t type)
+#endif
 {
        struct btsnoop *btsnoop;
        struct btsnoop_hdr hdr;
@@ -159,9 +172,99 @@ struct btsnoop *btsnoop_create(const char *path, uint32_t type)
                return NULL;
        }
 
+#ifdef __TIZEN_PATCH__
+       if (rotate_count > 0 && file_size > 0) {
+               btsnoop->path = strdup(path);
+               btsnoop->rotate_count = rotate_count;
+               btsnoop->file_size = file_size;
+       }
+#endif
+
        return btsnoop_ref(btsnoop);
 }
 
+#ifdef __TIZEN_PATCH__
+static int btsnoop_create_2(struct btsnoop *btsnoop)
+{
+       struct btsnoop_hdr hdr;
+       ssize_t written;
+
+       if (btsnoop->fd >= 0)
+               close(btsnoop->fd);
+
+       btsnoop->fd = open(btsnoop->path,
+                       O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC,
+                       S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+       if (btsnoop->fd < 0) {
+               btsnoop_unref(btsnoop);
+               return -1;
+       }
+
+       memcpy(hdr.id, btsnoop_id, sizeof(btsnoop_id));
+       hdr.version = htobe32(btsnoop_version);
+       hdr.type = htobe32(btsnoop->type);
+
+       written = write(btsnoop->fd, &hdr, BTSNOOP_HDR_SIZE);
+       if (written < 0) {
+               btsnoop_unref(btsnoop);
+               return -1;
+       }
+
+       return btsnoop->fd;
+}
+
+static void btsnoop_rotate_files(struct btsnoop *btsnoop)
+{
+       char *filename = NULL;
+       char *new_filename = NULL;
+       int i;
+       int postfix_width = 0;
+       int err;
+
+       if (btsnoop->rotate_count <= 1)
+               return;
+
+       for (i = btsnoop->rotate_count / 10; i; i /= 10)
+               postfix_width++;
+
+       for (i = btsnoop->rotate_count - 2; i >= 0; i--) {
+               if (i == 0) {
+                       filename = strdup(btsnoop->path);
+                       err = (filename == NULL) ? -1 : 0;
+               } else {
+                       err = asprintf(&filename, "%s.%0*d",
+                                       btsnoop->path, postfix_width, i);
+               }
+
+               if (err < 0 || access(filename, F_OK) < 0)
+                       goto done;
+
+               err = asprintf(&new_filename, "%s.%0*d",
+                               btsnoop->path, postfix_width, i + 1);
+               if (err < 0)
+                       goto done;
+
+               err = rename(filename, new_filename);
+
+done:
+               if (new_filename) {
+                       free(new_filename);
+                       new_filename = NULL;
+               }
+
+               if (filename) {
+                       free(filename);
+                       filename = NULL;
+               }
+
+               if (err < 0)
+                       break;
+       }
+
+       return;
+}
+#endif
+
 struct btsnoop *btsnoop_ref(struct btsnoop *btsnoop)
 {
        if (!btsnoop)
@@ -180,6 +283,11 @@ void btsnoop_unref(struct btsnoop *btsnoop)
        if (__sync_sub_and_fetch(&btsnoop->ref_count, 1))
                return;
 
+#ifdef __TIZEN_PATCH__
+       if (btsnoop->path)
+               free(btsnoop->path);
+#endif
+
        if (btsnoop->fd >= 0)
                close(btsnoop->fd);
 
@@ -212,6 +320,16 @@ bool btsnoop_write(struct btsnoop *btsnoop, struct timeval *tv,
        pkt.drops = htobe32(0);
        pkt.ts    = htobe64(ts + 0x00E03AB44A676000ll);
 
+#ifdef __TIZEN_PATCH__
+       if ((btsnoop->rotate_count > 0 && btsnoop->file_size > 0) &&
+                       lseek(btsnoop->fd, 0x00, SEEK_CUR) +
+                       BTSNOOP_PKT_SIZE + size > btsnoop->file_size) {
+               btsnoop_rotate_files(btsnoop);
+               if (btsnoop_create_2(btsnoop) < 0)
+                       return false;
+       }
+#endif
+
        written = write(btsnoop->fd, &pkt, BTSNOOP_PKT_SIZE);
        if (written < 0)
                return false;
index 9675980..e5089a8 100644 (file)
@@ -56,7 +56,12 @@ struct btsnoop_opcode_new_index {
 struct btsnoop;
 
 struct btsnoop *btsnoop_open(const char *path, unsigned long flags);
+#ifdef __TIZEN_PATCH__
+struct btsnoop *btsnoop_create(const char *path, uint32_t type,
+               int16_t rotate_count, ssize_t file_size);
+#else
 struct btsnoop *btsnoop_create(const char *path, uint32_t type);
+#endif
 
 struct btsnoop *btsnoop_ref(struct btsnoop *btsnoop);
 void btsnoop_unref(struct btsnoop *btsnoop);
index d2c5142..8f97f2b 100644 (file)
@@ -81,6 +81,8 @@ struct bt_gatt_client {
        struct queue *long_write_queue;
        bool in_long_write;
 
+       unsigned int reliable_write_session_id;
+
        /* List of registered disconnect/notification/indication callbacks */
        struct queue *notify_list;
        struct queue *notify_chrcs;
@@ -112,6 +114,7 @@ struct bt_gatt_client {
 struct request {
        struct bt_gatt_client *client;
        bool long_write;
+       bool prep_write;
        bool removed;
        int ref_count;
        unsigned int id;
@@ -589,7 +592,8 @@ static bool discover_descs(struct discovery_op *op, bool *discovering)
        *discovering = false;
 
        while ((chrc_data = queue_pop_head(op->pending_chrcs))) {
-               attr = gatt_db_service_add_characteristic(op->cur_svc,
+               attr = gatt_db_service_insert_characteristic(op->cur_svc,
+                                                       chrc_data->value_handle,
                                                        &chrc_data->uuid, 0,
                                                        chrc_data->properties,
                                                        NULL, NULL, NULL);
@@ -601,12 +605,19 @@ static bool discover_descs(struct discovery_op *op, bool *discovering)
                                                        chrc_data->value_handle)
                        goto failed;
 
+#ifdef __TIZEN_PATCH__
+               if (chrc_data->value_handle >= chrc_data->end_handle) {
+                       free(chrc_data);
+                       continue;
+               }
+               desc_start = chrc_data->value_handle + 1;
+#else
                desc_start = chrc_data->value_handle + 1;
-
                if (desc_start > chrc_data->end_handle) {
                        free(chrc_data);
                        continue;
                }
+#endif
 
                client->discovery_req = bt_gatt_discover_descriptors(
                                                        client->att, desc_start,
@@ -680,8 +691,9 @@ static void discover_descs_cb(bool success, uint8_t att_ecode,
                                                "handle: 0x%04x, uuid: %s",
                                                handle, uuid_str);
 
-               attr = gatt_db_service_add_descriptor(op->cur_svc, &uuid, 0,
-                                                       NULL, NULL, NULL);
+               attr = gatt_db_service_insert_descriptor(op->cur_svc, handle,
+                                                       &uuid, 0, NULL, NULL,
+                                                       NULL);
                if (!attr)
                        goto failed;
 
@@ -689,13 +701,13 @@ static void discover_descs_cb(bool success, uint8_t att_ecode,
                        goto failed;
        }
 
+next:
        if (!discover_descs(op, &discovering))
                goto failed;
 
        if (discovering)
                return;
 
-next:
        /* Done with the current service */
        gatt_db_service_set_active(op->cur_svc, true);
 
@@ -1797,69 +1809,78 @@ static bool match_req_id(const void *a, const void *b)
 static void cancel_long_write_cb(uint8_t opcode, const void *pdu, uint16_t len,
                                                                void *user_data)
 {
-       /* Do nothing */
+       struct bt_gatt_client *client = user_data;
+
+       if (queue_isempty(client->long_write_queue))
+               client->in_long_write = false;
 }
 
-bool bt_gatt_client_cancel(struct bt_gatt_client *client, unsigned int id)
+static bool cancel_long_write_req(struct bt_gatt_client *client,
+                                                       struct request *req)
 {
-       struct request *req;
        uint8_t pdu = 0x00;
 
-       if (!client || !id || !client->att)
-               return false;
-
-       req = queue_remove_if(client->pending_requests, match_req_id,
-                                                       UINT_TO_PTR(id));
-       if (!req)
-               return false;
-
-       req->removed = true;
-
-       if (!bt_att_cancel(client->att, req->att_id) && !req->long_write)
-               return false;
-
-       /* If this was a long-write, we need to abort all prepared writes */
-       if (!req->long_write)
-               return true;
-
+       /*
+        * att_id == 0 means that request has been queued and no prepare write
+        * has been sent so far.Let's just remove if from the queue.
+        * Otherwise execute write needs to be send.
+        */
        if (!req->att_id)
-               queue_remove(client->long_write_queue, req);
-       else
-               bt_att_send(client->att, BT_ATT_OP_EXEC_WRITE_REQ,
-                                                       &pdu, sizeof(pdu),
+               return queue_remove(client->long_write_queue, req);
+
+       return !!bt_att_send(client->att, BT_ATT_OP_EXEC_WRITE_REQ, &pdu,
+                                                       sizeof(pdu),
                                                        cancel_long_write_cb,
-                                                       NULL, NULL);
+                                                       client, NULL);
 
-       if (queue_isempty(client->long_write_queue))
-               client->in_long_write = false;
+}
 
-       return true;
+static void cancel_prep_write_cb(uint8_t opcode, const void *pdu, uint16_t len,
+                                                               void *user_data)
+{
+       struct request *req = user_data;
+       struct bt_gatt_client *client = req->client;
+
+       client->reliable_write_session_id = 0;
 }
 
-static void cancel_request(void *data)
+static bool cancel_prep_write_session(struct bt_gatt_client *client,
+                                                       struct request *req)
 {
-       struct request *req = data;
        uint8_t pdu = 0x00;
 
+       return !!bt_att_send(client->att, BT_ATT_OP_EXEC_WRITE_REQ, &pdu,
+                                                       sizeof(pdu),
+                                                       cancel_prep_write_cb,
+                                                       req, request_unref);
+}
+
+static bool cancel_request(struct request *req)
+{
        req->removed = true;
 
-       if (!req->long_write) {
-               bt_att_cancel(req->client->att, req->att_id);
-               return;
-       }
+       if (req->long_write)
+               return cancel_long_write_req(req->client, req);
 
-       if (!req->att_id)
-               queue_remove(req->client->long_write_queue, req);
+       if (req->prep_write)
+               return cancel_prep_write_session(req->client, req);
 
-       if (queue_isempty(req->client->long_write_queue))
-               req->client->in_long_write = false;
+       return bt_att_cancel(req->client->att, req->att_id);
+}
 
-       bt_att_send(req->client->att, BT_ATT_OP_EXEC_WRITE_REQ,
-                                                       &pdu, sizeof(pdu),
-                                                       cancel_long_write_cb,
-                                                       NULL, NULL);
+bool bt_gatt_client_cancel(struct bt_gatt_client *client, unsigned int id)
+{
+       struct request *req;
+
+       if (!client || !id || !client->att)
+               return false;
+
+       req = queue_remove_if(client->pending_requests, match_req_id,
+                                                       UINT_TO_PTR(id));
+       if (!req)
+               return false;
 
-       bt_att_cancel(req->client->att, req->att_id);
+       return cancel_request(req);
 }
 
 bool bt_gatt_client_cancel_all(struct bt_gatt_client *client)
@@ -1867,7 +1888,8 @@ bool bt_gatt_client_cancel_all(struct bt_gatt_client *client)
        if (!client || !client->att)
                return false;
 
-       queue_remove_all(client->pending_requests, NULL, NULL, cancel_request);
+       queue_remove_all(client->pending_requests, NULL, NULL,
+                                       (queue_destroy_func_t) cancel_request);
 
        if (client->discovery_req) {
                bt_gatt_request_cancel(client->discovery_req);
@@ -2245,6 +2267,7 @@ unsigned int bt_gatt_client_write_without_response(
 }
 
 struct write_op {
+       struct bt_gatt_client *client;
        bt_gatt_client_callback_t callback;
        void *user_data;
        bt_gatt_destroy_func_t destroy;
@@ -2597,7 +2620,7 @@ unsigned int bt_gatt_client_write_long_value(struct bt_gatt_client *client,
        req->destroy = long_write_op_free;
        req->long_write = true;
 
-       if (client->in_long_write) {
+       if (client->in_long_write || client->reliable_write_session_id > 0) {
                queue_push_tail(client->long_write_queue, req);
                return req->id;
        }
@@ -2630,6 +2653,264 @@ unsigned int bt_gatt_client_write_long_value(struct bt_gatt_client *client,
        return req->id;
 }
 
+struct prep_write_op {
+       bt_gatt_client_write_long_callback_t callback;
+       void *user_data;
+       bt_gatt_destroy_func_t destroy;
+       uint8_t *pdu;
+       uint16_t pdu_len;
+};
+
+static void destroy_prep_write_op(void *data)
+{
+       struct prep_write_op *op = data;
+
+       if (op->destroy)
+               op->destroy(op->user_data);
+
+       free(op->pdu);
+       free(op);
+}
+
+static void prep_write_cb(uint8_t opcode, const void *pdu, uint16_t length,
+                                                               void *user_data)
+{
+       struct request *req = user_data;
+       struct prep_write_op *op = req->data;
+       bool success;
+       uint8_t att_ecode;
+       bool reliable_error;
+
+       if (opcode == BT_ATT_OP_ERROR_RSP) {
+               success = false;
+               reliable_error = false;
+               att_ecode = process_error(pdu, length);
+               goto done;
+       }
+
+       if (opcode != BT_ATT_OP_PREP_WRITE_RSP) {
+               success = false;
+               reliable_error = false;
+               att_ecode = 0;
+               goto done;
+       }
+
+       if (!pdu || length != op->pdu_len ||
+                                       memcmp(pdu, op->pdu, op->pdu_len)) {
+               success = false;
+               reliable_error = true;
+               att_ecode = 0;
+               goto done;
+       }
+
+       success = true;
+       reliable_error = false;
+       att_ecode = 0;
+
+done:
+       if (op->callback)
+               op->callback(success, reliable_error, att_ecode, op->user_data);
+}
+
+static struct request *get_reliable_request(struct bt_gatt_client *client,
+                                                       unsigned int id)
+{
+       struct request *req;
+       struct prep_write_op *op;
+
+       op = new0(struct prep_write_op, 1);
+       if (!op)
+               return NULL;
+
+       /* Following prepare writes */
+       if (id != 0)
+               req = queue_find(client->pending_requests, match_req_id,
+                                                       UINT_TO_PTR(id));
+       else
+               req = request_create(client);
+
+       if (!req) {
+               free(op);
+               return NULL;
+       }
+
+       req->data = op;
+
+       return req;
+}
+
+unsigned int bt_gatt_client_prepare_write(struct bt_gatt_client *client,
+                               unsigned int id, uint16_t value_handle,
+                               uint16_t offset, const uint8_t *value,
+                               uint16_t length,
+                               bt_gatt_client_write_long_callback_t callback,
+                               void *user_data,
+                               bt_gatt_client_destroy_func_t destroy)
+{
+       struct request *req;
+       struct prep_write_op *op;
+       uint8_t pdu[4 + length];
+
+       if (!client)
+               return 0;
+
+       if (client->in_long_write)
+               return 0;
+
+       /*
+        * Make sure that client who owns reliable session continues with
+        * prepare writes or this is brand new reliable session (id == 0)
+        */
+       if (id != client->reliable_write_session_id) {
+               util_debug(client->debug_callback, client->debug_data,
+                       "There is other reliable write session ongoing %u",
+                       client->reliable_write_session_id);
+
+               return 0;
+       }
+
+       req = get_reliable_request(client, id);
+       if (!req)
+               return 0;
+
+       op = (struct prep_write_op *)req->data;
+
+       op->callback = callback;
+       op->user_data = user_data;
+       op->destroy = destroy;
+
+       req->destroy = destroy_prep_write_op;
+       req->prep_write = true;
+
+       put_le16(value_handle, pdu);
+       put_le16(offset, pdu + 2);
+       memcpy(pdu + 4, value, length);
+
+       /*
+        * Before sending command we need to remember pdu as we need to validate
+        * it in the response. Store handle, offset and value. Therefore
+        * increase length by 4 (handle + offset) as we need it in couple places
+        * below
+        */
+       length += 4;
+
+       op->pdu = malloc(length);
+       if (!op->pdu) {
+               op->destroy = NULL;
+               request_unref(req);
+               return 0;
+       }
+
+       memcpy(op->pdu, pdu, length);
+       op->pdu_len = length;
+
+       /*
+        * Now we are ready to send command
+        * Note that request_unref will be done on write execute
+        */
+       req->att_id = bt_att_send(client->att, BT_ATT_OP_PREP_WRITE_REQ, pdu,
+                                       sizeof(pdu), prep_write_cb, req,
+                                       NULL);
+       if (!req->att_id) {
+               op->destroy = NULL;
+               request_unref(req);
+               return 0;
+       }
+
+       /*
+        * Store first request id for prepare write and treat it as a session id
+        * valid until write execute is done
+        */
+       if (client->reliable_write_session_id == 0)
+               client->reliable_write_session_id = req->id;
+
+       return client->reliable_write_session_id;
+}
+
+static void exec_write_cb(uint8_t opcode, const void *pdu, uint16_t length,
+                                                               void *user_data)
+{
+       struct request *req = user_data;
+       struct write_op *op = req->data;
+       bool success;
+       uint8_t att_ecode;
+
+       if (opcode == BT_ATT_OP_ERROR_RSP) {
+               success = false;
+               att_ecode = process_error(pdu, length);
+               goto done;
+       }
+
+       if (opcode != BT_ATT_OP_EXEC_WRITE_RSP || pdu || length) {
+               success = false;
+               att_ecode = 0;
+               goto done;
+       }
+
+       success = true;
+       att_ecode = 0;
+
+done:
+       if (op->callback)
+               op->callback(success, att_ecode, op->user_data);
+
+       op->client->reliable_write_session_id = 0;
+
+       start_next_long_write(op->client);
+}
+
+unsigned int bt_gatt_client_write_execute(struct bt_gatt_client *client,
+                                       unsigned int id,
+                                       bt_gatt_client_callback_t callback,
+                                       void *user_data,
+                                       bt_gatt_client_destroy_func_t destroy)
+{
+       struct request *req;
+       struct write_op *op;
+       uint8_t pdu;
+
+       if (!client)
+               return 0;
+
+       if (client->in_long_write)
+               return 0;
+
+       if (client->reliable_write_session_id != id)
+               return 0;
+
+       op = new0(struct write_op, 1);
+       if (!op)
+               return 0;
+
+       req = queue_find(client->pending_requests, match_req_id,
+                                                       UINT_TO_PTR(id));
+       if (!req) {
+               free(op);
+               return 0;
+       }
+
+       op->client = client;
+       op->callback = callback;
+       op->user_data = user_data;
+       op->destroy = destroy;
+
+       pdu = 0x01;
+
+       req->data = op;
+       req->destroy = destroy_write_op;
+
+       req->att_id = bt_att_send(client->att, BT_ATT_OP_EXEC_WRITE_REQ, &pdu,
+                                               sizeof(pdu), exec_write_cb,
+                                               req, request_unref);
+       if (!req->att_id) {
+               op->destroy = NULL;
+               request_unref(req);
+               return 0;
+       }
+
+       return id;
+}
+
 static bool match_notify_chrc_value_handle(const void *a, const void *b)
 {
        const struct notify_chrc *chrc = a;
index 819019e..13303c6 100644 (file)
@@ -108,6 +108,18 @@ unsigned int bt_gatt_client_write_long_value(struct bt_gatt_client *client,
                                bt_gatt_client_write_long_callback_t callback,
                                void *user_data,
                                bt_gatt_client_destroy_func_t destroy);
+unsigned int bt_gatt_client_prepare_write(struct bt_gatt_client *client,
+                               unsigned int id,
+                               uint16_t value_handle, uint16_t offset,
+                               const uint8_t *value, uint16_t length,
+                               bt_gatt_client_write_long_callback_t callback,
+                               void *user_data,
+                               bt_gatt_client_destroy_func_t destroy);
+unsigned int bt_gatt_client_write_execute(struct bt_gatt_client *client,
+                                       unsigned int id,
+                                       bt_gatt_client_callback_t callback,
+                                       void *user_data,
+                                       bt_gatt_client_destroy_func_t destroy);
 
 unsigned int bt_gatt_client_register_notify(struct bt_gatt_client *client,
                                uint16_t chrc_value_handle,
index eb81372..3625fda 100644 (file)
@@ -89,6 +89,9 @@ struct gatt_db_attribute {
        uint32_t permissions;
        uint16_t value_len;
        uint8_t *value;
+#ifdef __TIZEN_PATCH__
+       bdaddr_t unicast_addr;
+#endif
 
        gatt_db_read_t read_func;
        gatt_db_write_t write_func;
@@ -158,6 +161,7 @@ static void attribute_destroy(struct gatt_db_attribute *attribute)
 }
 
 static struct gatt_db_attribute *new_attribute(struct gatt_db_service *service,
+                                                       uint16_t handle,
                                                        const bt_uuid_t *type,
                                                        const uint8_t *val,
                                                        uint16_t len)
@@ -169,6 +173,7 @@ static struct gatt_db_attribute *new_attribute(struct gatt_db_service *service,
                return NULL;
 
        attribute->service = service;
+       attribute->handle = handle;
        attribute->uuid = *type;
        attribute->value_len = len;
        if (len) {
@@ -371,6 +376,7 @@ static bool le_to_uuid(const uint8_t *src, size_t len, bt_uuid_t *uuid)
 }
 
 static struct gatt_db_service *gatt_db_service_create(const bt_uuid_t *uuid,
+                                                       uint16_t handle,
                                                        bool primary,
                                                        uint16_t num_handles)
 {
@@ -399,7 +405,8 @@ static struct gatt_db_service *gatt_db_service_create(const bt_uuid_t *uuid,
 
        len = uuid_to_le(uuid, value);
 
-       service->attributes[0] = new_attribute(service, type, value, len);
+       service->attributes[0] = new_attribute(service, handle, type, value,
+                                                                       len);
        if (!service->attributes[0]) {
                gatt_db_service_destroy(service);
                return NULL;
@@ -533,7 +540,7 @@ struct gatt_db_attribute *gatt_db_insert_service(struct gatt_db *db,
        if (!find_insert_loc(db, handle, handle + num_handles - 1, &after))
                return NULL;
 
-       service = gatt_db_service_create(uuid, primary, num_handles);
+       service = gatt_db_service_create(uuid, handle, primary, num_handles);
 
        if (!service)
                return NULL;
@@ -663,8 +670,9 @@ static void set_attribute_data(struct gatt_db_attribute *attribute,
        attribute->user_data = user_data;
 }
 
-struct gatt_db_attribute *
-gatt_db_service_add_characteristic(struct gatt_db_attribute *attrib,
+static struct gatt_db_attribute *
+service_insert_characteristic(struct gatt_db_service *service,
+                                       uint16_t handle,
                                        const bt_uuid_t *uuid,
                                        uint32_t permissions,
                                        uint8_t properties,
@@ -672,35 +680,38 @@ gatt_db_service_add_characteristic(struct gatt_db_attribute *attrib,
                                        gatt_db_write_t write_func,
                                        void *user_data)
 {
-       struct gatt_db_service *service;
        uint8_t value[MAX_CHAR_DECL_VALUE_LEN];
        uint16_t len = 0;
        int i;
 
-       if (!attrib)
+       /* Check if handle is in within service range */
+       if (handle && handle <= service->attributes[0]->handle)
                return NULL;
 
-       service = attrib->service;
-
        i = get_attribute_index(service, 1);
        if (!i)
                return NULL;
 
+       if (!handle)
+               handle = get_handle_at_index(service, i - 1) + 2;
+
        value[0] = properties;
        len += sizeof(properties);
+
        /* We set handle of characteristic value, which will be added next */
-       put_le16(get_handle_at_index(service, i - 1) + 2, &value[1]);
+       put_le16(handle, &value[1]);
        len += sizeof(uint16_t);
        len += uuid_to_le(uuid, &value[3]);
 
-       service->attributes[i] = new_attribute(service, &characteristic_uuid,
-                                                               value, len);
+       service->attributes[i] = new_attribute(service, handle - 1,
+                                                       &characteristic_uuid,
+                                                       value, len);
        if (!service->attributes[i])
                return NULL;
 
-       attribute_update(service, i++);
+       i++;
 
-       service->attributes[i] = new_attribute(service, uuid, NULL, 0);
+       service->attributes[i] = new_attribute(service, handle, uuid, NULL, 0);
        if (!service->attributes[i]) {
                free(service->attributes[i - 1]);
                return NULL;
@@ -709,37 +720,109 @@ gatt_db_service_add_characteristic(struct gatt_db_attribute *attrib,
        set_attribute_data(service->attributes[i], read_func, write_func,
                                                        permissions, user_data);
 
-       return attribute_update(service, i);
+       return service->attributes[i];
 }
 
 struct gatt_db_attribute *
-gatt_db_service_add_descriptor(struct gatt_db_attribute *attrib,
+gatt_db_service_insert_characteristic(struct gatt_db_attribute *attrib,
+                                       uint16_t handle,
                                        const bt_uuid_t *uuid,
                                        uint32_t permissions,
+                                       uint8_t properties,
                                        gatt_db_read_t read_func,
                                        gatt_db_write_t write_func,
                                        void *user_data)
 {
-       struct gatt_db_service *service;
-       int i;
+       if (!attrib || !handle)
+               return NULL;
+
+       return service_insert_characteristic(attrib->service, handle, uuid,
+                                               permissions, properties,
+                                               read_func, write_func,
+                                               user_data);
+}
 
+struct gatt_db_attribute *
+gatt_db_service_add_characteristic(struct gatt_db_attribute *attrib,
+                                       const bt_uuid_t *uuid,
+                                       uint32_t permissions,
+                                       uint8_t properties,
+                                       gatt_db_read_t read_func,
+                                       gatt_db_write_t write_func,
+                                       void *user_data)
+{
        if (!attrib)
                return NULL;
 
-       service = attrib->service;
+       return service_insert_characteristic(attrib->service, 0, uuid,
+                                               permissions, properties,
+                                               read_func, write_func,
+                                               user_data);
+}
+
+static struct gatt_db_attribute *
+service_insert_descriptor(struct gatt_db_service *service,
+                                       uint16_t handle,
+                                       const bt_uuid_t *uuid,
+                                       uint32_t permissions,
+                                       gatt_db_read_t read_func,
+                                       gatt_db_write_t write_func,
+                                       void *user_data)
+{
+       int i;
 
        i = get_attribute_index(service, 0);
        if (!i)
                return NULL;
 
-       service->attributes[i] = new_attribute(service, uuid, NULL, 0);
+       /* Check if handle is in within service range */
+       if (handle && handle <= service->attributes[0]->handle)
+               return NULL;
+
+       if (!handle)
+               handle = get_handle_at_index(service, i - 1) + 1;
+
+       service->attributes[i] = new_attribute(service, handle, uuid, NULL, 0);
        if (!service->attributes[i])
                return NULL;
 
        set_attribute_data(service->attributes[i], read_func, write_func,
                                                        permissions, user_data);
 
-       return attribute_update(service, i);
+       return service->attributes[i];
+}
+
+struct gatt_db_attribute *
+gatt_db_service_insert_descriptor(struct gatt_db_attribute *attrib,
+                                       uint16_t handle,
+                                       const bt_uuid_t *uuid,
+                                       uint32_t permissions,
+                                       gatt_db_read_t read_func,
+                                       gatt_db_write_t write_func,
+                                       void *user_data)
+{
+       if (!attrib || !handle)
+               return NULL;
+
+       return service_insert_descriptor(attrib->service, handle, uuid,
+                                       permissions, read_func, write_func,
+                                       user_data);
+}
+
+struct gatt_db_attribute *
+gatt_db_service_add_descriptor(struct gatt_db_attribute *attrib,
+                                       const bt_uuid_t *uuid,
+                                       uint32_t permissions,
+                                       gatt_db_read_t read_func,
+                                       gatt_db_write_t write_func,
+                                       void *user_data)
+{
+       if (!attrib)
+               return NULL;
+
+       return service_insert_descriptor(attrib->service, 0, uuid,
+                                       permissions, read_func, write_func,
+                                       user_data);
 }
 
 struct gatt_db_attribute *
@@ -781,7 +864,7 @@ gatt_db_service_add_included(struct gatt_db_attribute *attrib,
        if (!index)
                return NULL;
 
-       service->attributes[index] = new_attribute(service,
+       service->attributes[index] = new_attribute(service, 0,
                                                        &included_service_uuid,
                                                        value, len);
        if (!service->attributes[index])
@@ -1184,7 +1267,13 @@ void gatt_db_service_foreach_desc(struct gatt_db_attribute *attrib,
        service = attrib->service;
 
        /* Start from the attribute following the value handle */
-       i = attrib->handle - service->attributes[0]->handle + 2;
+       for (i = 0; i < service->num_handles; i++) {
+               if (service->attributes[i] == attrib) {
+                       i += 2;
+                       break;
+               }
+       }
+
        for (; i < service->num_handles; i++) {
                attr = service->attributes[i];
                if (!attr)
@@ -1222,7 +1311,7 @@ struct gatt_db_attribute *gatt_db_get_attribute(struct gatt_db *db,
                                                        uint16_t handle)
 {
        struct gatt_db_service *service;
-       uint16_t service_handle;
+       int i;
 
        if (!db || !handle)
                return NULL;
@@ -1232,14 +1321,15 @@ struct gatt_db_attribute *gatt_db_get_attribute(struct gatt_db *db,
        if (!service)
                return NULL;
 
-       service_handle = service->attributes[0]->handle;
+       for (i = 0; i < service->num_handles; i++) {
+               if (!service->attributes[i])
+                       continue;
 
-       /*
-        * We can safely get attribute from attributes array with offset,
-        * because find_service_for_handle() check if given handle is
-        * in service range.
-        */
-       return service->attributes[handle - service_handle];
+               if (service->attributes[i]->handle == handle)
+                       return service->attributes[i];
+       }
+
+       return NULL;
 }
 
 static bool find_service_with_uuid(const void *data, const void *user_data)
@@ -1634,3 +1724,19 @@ bool gatt_db_attribute_reset(struct gatt_db_attribute *attrib)
 
        return true;
 }
+
+#ifdef __TIZEN_PATCH__
+void set_ccc_unicast_address(const struct gatt_db_attribute *ccc,
+                                                       const char *address)
+{
+       if (ccc)
+               str2ba(address, &ccc->unicast_addr);
+}
+
+bdaddr_t *get_ccc_unicast_address(const struct gatt_db_attribute *ccc)
+{
+       if (ccc)
+               return &ccc->unicast_addr;
+       return NULL;
+}
+#endif
index 74b37bc..026b024 100644 (file)
@@ -67,6 +67,15 @@ gatt_db_service_add_characteristic(struct gatt_db_attribute *attrib,
                                        gatt_db_read_t read_func,
                                        gatt_db_write_t write_func,
                                        void *user_data);
+struct gatt_db_attribute *
+gatt_db_service_insert_characteristic(struct gatt_db_attribute *attrib,
+                                       uint16_t handle,
+                                       const bt_uuid_t *uuid,
+                                       uint32_t permissions,
+                                       uint8_t properties,
+                                       gatt_db_read_t read_func,
+                                       gatt_db_write_t write_func,
+                                       void *user_data);
 
 struct gatt_db_attribute *
 gatt_db_service_add_descriptor(struct gatt_db_attribute *attrib,
@@ -75,6 +84,14 @@ gatt_db_service_add_descriptor(struct gatt_db_attribute *attrib,
                                        gatt_db_read_t read_func,
                                        gatt_db_write_t write_func,
                                        void *user_data);
+struct gatt_db_attribute *
+gatt_db_service_insert_descriptor(struct gatt_db_attribute *attrib,
+                                       uint16_t handle,
+                                       const bt_uuid_t *uuid,
+                                       uint32_t permissions,
+                                       gatt_db_read_t read_func,
+                                       gatt_db_write_t write_func,
+                                       void *user_data);
 
 struct gatt_db_attribute *
 gatt_db_service_add_included(struct gatt_db_attribute *attrib,
@@ -217,3 +234,10 @@ bool gatt_db_attribute_write_result(struct gatt_db_attribute *attrib,
                                                unsigned int id, int err);
 
 bool gatt_db_attribute_reset(struct gatt_db_attribute *attrib);
+
+#ifdef __TIZEN_PATCH__
+void set_ccc_unicast_address(const struct gatt_db_attribute *ccc,
+                                                       const char *address);
+
+bdaddr_t *get_ccc_unicast_address(const struct gatt_db_attribute *ccc);
+#endif
index 2d6088e..1076a6a 100644 (file)
@@ -212,6 +212,7 @@ static bool convert_uuid_le(const uint8_t *src, size_t len, uint8_t dst[16])
 struct bt_gatt_request {
        struct bt_att *att;
        unsigned int id;
+       uint16_t start_handle;
        uint16_t end_handle;
        int ref_count;
        bt_uuid_t uuid;
@@ -625,6 +626,10 @@ static void async_req_unref(void *data)
 static void discovery_op_complete(struct bt_gatt_request *op, bool success,
                                                                uint8_t ecode)
 {
+       /* Reset success if there is some result to report */
+       if (ecode == BT_ATT_ERROR_ATTRIBUTE_NOT_FOUND && op->result_head)
+               success = true;
+
        if (op->callback)
                op->callback(success, ecode, success ? op->result_head : NULL,
                                                                op->user_data);
@@ -650,11 +655,6 @@ static void read_by_grp_type_cb(uint8_t opcode, const void *pdu,
        if (opcode == BT_ATT_OP_ERROR_RSP) {
                success = false;
                att_ecode = process_error(pdu, length);
-
-               if (att_ecode == BT_ATT_ERROR_ATTRIBUTE_NOT_FOUND &&
-                                                               op->result_head)
-                       goto success;
-
                goto done;
        }
 
@@ -690,10 +690,22 @@ static void read_by_grp_type_cb(uint8_t opcode, const void *pdu,
        }
 
        last_end = get_le16(pdu + length - data_length + 2);
+
+       /*
+        * If last handle is lower from previous start handle then it is smth
+        * wrong. Let's stop search, otherwise we might enter infinite loop.
+        */
+       if (last_end < op->start_handle) {
+               success = false;
+               goto done;
+       }
+
+       op->start_handle = last_end + 1;
+
        if (last_end < op->end_handle) {
                uint8_t pdu[6];
 
-               put_le16(last_end + 1, pdu);
+               put_le16(op->start_handle, pdu);
                put_le16(op->end_handle, pdu + 2);
                put_le16(op->service_type, pdu + 4);
 
@@ -718,7 +730,6 @@ static void read_by_grp_type_cb(uint8_t opcode, const void *pdu,
                put_le16(op->end_handle,
                                cur_result->pdu + length - data_length + 1);
 
-success:
        success = true;
 
 done:
@@ -736,11 +747,6 @@ static void find_by_type_val_cb(uint8_t opcode, const void *pdu,
        if (opcode == BT_ATT_OP_ERROR_RSP) {
                success = false;
                att_ecode = process_error(pdu, length);
-
-               if (att_ecode == BT_ATT_ERROR_ATTRIBUTE_NOT_FOUND &&
-                                                               op->result_head)
-                       goto success;
-
                goto done;
        }
 
@@ -765,10 +771,22 @@ static void find_by_type_val_cb(uint8_t opcode, const void *pdu,
         * last_end is end handle of last data set
         */
        last_end = get_le16(pdu + length - 2);
+
+       /*
+       * If last handle is lower from previous start handle then it is smth
+       * wrong. Let's stop search, otherwise we might enter infinite loop.
+       */
+       if (last_end < op->start_handle) {
+               success = false;
+               goto done;
+       }
+
+       op->start_handle = last_end + 1;
+
        if (last_end < op->end_handle) {
                uint8_t pdu[6 + get_uuid_len(&op->uuid)];
 
-               put_le16(last_end + 1, pdu);
+               put_le16(op->start_handle, pdu);
                put_le16(op->end_handle, pdu + 2);
                put_le16(op->service_type, pdu + 4);
                bt_uuid_to_le(&op->uuid, pdu + 6);
@@ -785,8 +803,7 @@ static void find_by_type_val_cb(uint8_t opcode, const void *pdu,
                goto done;
        }
 
-success:
-       success = true;
+       success = false;
 
 done:
        discovery_op_complete(op, success, att_ecode);
@@ -810,6 +827,7 @@ static struct bt_gatt_request *discover_services(struct bt_att *att,
                return NULL;
 
        op->att = att;
+       op->start_handle = start;
        op->end_handle = end;
        op->callback = callback;
        op->user_data = user_data;
@@ -1047,11 +1065,6 @@ static void discover_included_cb(uint8_t opcode, const void *pdu,
 
        if (opcode == BT_ATT_OP_ERROR_RSP) {
                att_ecode = process_error(pdu, length);
-
-               if (att_ecode == BT_ATT_ERROR_ATTRIBUTE_NOT_FOUND &&
-                                                       op->result_head)
-                       goto done;
-
                success = false;
                goto failed;
        }
@@ -1099,10 +1112,21 @@ static void discover_included_cb(uint8_t opcode, const void *pdu,
        }
 
        last_handle = get_le16(pdu + length - data_length);
+
+       /*
+        * If last handle is lower from previous start handle then it is smth
+        * wrong. Let's stop search, otherwise we might enter infinite loop.
+        */
+       if (last_handle < op->start_handle) {
+               success = false;
+               goto failed;
+       }
+
+       op->start_handle = last_handle + 1;
        if (last_handle != op->end_handle) {
                uint8_t pdu[6];
 
-               put_le16(last_handle + 1, pdu);
+               put_le16(op->start_handle, pdu);
                put_le16(op->end_handle, pdu + 2);
                put_le16(GATT_INCLUDE_UUID, pdu + 4);
 
@@ -1118,7 +1142,6 @@ static void discover_included_cb(uint8_t opcode, const void *pdu,
                goto failed;
        }
 
-done:
        success = true;
 
 failed:
@@ -1145,6 +1168,7 @@ struct bt_gatt_request *bt_gatt_discover_included_services(struct bt_att *att,
        op->callback = callback;
        op->user_data = user_data;
        op->destroy = destroy;
+       op->start_handle = start;
        op->end_handle = end;
 
        put_le16(start, pdu);
@@ -1174,11 +1198,6 @@ static void discover_chrcs_cb(uint8_t opcode, const void *pdu,
        if (opcode == BT_ATT_OP_ERROR_RSP) {
                success = false;
                att_ecode = process_error(pdu, length);
-
-               if (att_ecode == BT_ATT_ERROR_ATTRIBUTE_NOT_FOUND &&
-                                                       op->result_head)
-                       goto success;
-
                goto done;
        }
 
@@ -1209,10 +1228,22 @@ static void discover_chrcs_cb(uint8_t opcode, const void *pdu,
                goto done;
        }
        last_handle = get_le16(pdu + length - data_length);
+
+       /*
+        * If last handle is lower from previous start handle then it is smth
+        * wrong. Let's stop search, otherwise we might enter infinite loop.
+        */
+       if (last_handle < op->start_handle) {
+               success = false;
+               goto done;
+       }
+
+       op->start_handle = last_handle + 1;
+
        if (last_handle != op->end_handle) {
                uint8_t pdu[6];
 
-               put_le16(last_handle + 1, pdu);
+               put_le16(op->start_handle, pdu);
                put_le16(op->end_handle, pdu + 2);
                put_le16(GATT_CHARAC_UUID, pdu + 4);
 
@@ -1228,9 +1259,6 @@ static void discover_chrcs_cb(uint8_t opcode, const void *pdu,
                goto done;
        }
 
-success:
-       success = true;
-
 done:
        discovery_op_complete(op, success, att_ecode);
 }
@@ -1255,6 +1283,7 @@ struct bt_gatt_request *bt_gatt_discover_characteristics(struct bt_att *att,
        op->callback = callback;
        op->user_data = user_data;
        op->destroy = destroy;
+       op->start_handle = start;
        op->end_handle = end;
 
        put_le16(start, pdu);
@@ -1283,13 +1312,7 @@ static void read_by_type_cb(uint8_t opcode, const void *pdu,
 
        if (opcode == BT_ATT_OP_ERROR_RSP) {
                att_ecode = process_error(pdu, length);
-
-               if (att_ecode == BT_ATT_ERROR_ATTRIBUTE_NOT_FOUND &&
-                                                       op->result_head)
-                       success = true;
-               else
-                       success = false;
-
+               success = false;
                goto done;
        }
 
@@ -1313,10 +1336,22 @@ static void read_by_type_cb(uint8_t opcode, const void *pdu,
        }
 
        last_handle = get_le16(pdu + length - data_length);
+
+       /*
+        * If last handle is lower from previous start handle then it is smth
+        * wrong. Let's stop search, otherwise we might enter infinite loop.
+        */
+       if (last_handle < op->start_handle) {
+               success = false;
+               goto done;
+       }
+
+       op->start_handle = last_handle + 1;
+
        if (last_handle != op->end_handle) {
                uint8_t pdu[4 + get_uuid_len(&op->uuid)];
 
-               put_le16(last_handle + 1, pdu);
+               put_le16(op->start_handle, pdu);
                put_le16(op->end_handle, pdu + 2);
                bt_uuid_to_le(&op->uuid, pdu + 4);
 
@@ -1358,6 +1393,7 @@ bool bt_gatt_read_by_type(struct bt_att *att, uint16_t start, uint16_t end,
        op->callback = callback;
        op->user_data = user_data;
        op->destroy = destroy;
+       op->start_handle = start;
        op->end_handle = end;
        op->uuid = *uuid;
 
@@ -1389,11 +1425,6 @@ static void discover_descs_cb(uint8_t opcode, const void *pdu,
        if (opcode == BT_ATT_OP_ERROR_RSP) {
                success = false;
                att_ecode = process_error(pdu, length);
-
-               if (att_ecode == BT_ATT_ERROR_ATTRIBUTE_NOT_FOUND &&
-                                                               op->result_head)
-                       goto success;
-
                goto done;
        }
 
@@ -1430,10 +1461,22 @@ static void discover_descs_cb(uint8_t opcode, const void *pdu,
        }
 
        last_handle = get_le16(pdu + length - data_length);
+
+       /*
+        * If last handle is lower from previous start handle then it is smth
+        * wrong. Let's stop search, otherwise we might enter infinite loop.
+        */
+       if (last_handle < op->start_handle) {
+               success = false;
+               goto done;
+       }
+
+       op->start_handle = last_handle + 1;
+
        if (last_handle != op->end_handle) {
                uint8_t pdu[4];
 
-               put_le16(last_handle + 1, pdu);
+               put_le16(op->start_handle, pdu);
                put_le16(op->end_handle, pdu + 2);
 
                op->id = bt_att_send(op->att, BT_ATT_OP_FIND_INFO_REQ,
@@ -1445,10 +1488,8 @@ static void discover_descs_cb(uint8_t opcode, const void *pdu,
                        return;
 
                success = false;
-               goto done;
        }
 
-success:
        success = true;
 
 done:
@@ -1475,6 +1516,7 @@ struct bt_gatt_request *bt_gatt_discover_descriptors(struct bt_att *att,
        op->callback = callback;
        op->user_data = user_data;
        op->destroy = destroy;
+       op->start_handle = start;
        op->end_handle = end;
 
        put_le16(start, pdu);
index ffcc2ea..3c3089f 100644 (file)
@@ -90,6 +90,7 @@ struct test_case {
        gdouble end_time;
        unsigned int timeout;
        unsigned int timeout_id;
+       unsigned int teardown_id;
        tester_destroy_func_t destroy;
        void *user_data;
 };
@@ -113,6 +114,9 @@ static void test_destroy(gpointer data)
        if (test->timeout_id > 0)
                g_source_remove(test->timeout_id);
 
+       if (test->teardown_id > 0)
+               g_source_remove(test->teardown_id);
+
        if (test->destroy)
                test->destroy(test->user_data);
 
@@ -315,7 +319,8 @@ static int tester_summarize(void)
                COLOR_RED "Failed: %d" COLOR_OFF ", "
                COLOR_YELLOW "Not Run: %d" COLOR_OFF "\n",
                        not_run + passed + failed, passed,
-                       (float) passed * 100 / (not_run + passed + failed),
+                       (not_run + passed + failed) ?
+                       (float) passed * 100 / (not_run + passed + failed) : 0,
                        failed, not_run);
 
        execution_time = g_timer_elapsed(test_timer, NULL);
@@ -328,6 +333,7 @@ static gboolean teardown_callback(gpointer user_data)
 {
        struct test_case *test = user_data;
 
+       test->teardown_id = 0;
        test->stage = TEST_STAGE_TEARDOWN;
 
        print_progress(test->name, COLOR_MAGENTA, "teardown");
@@ -495,7 +501,7 @@ void tester_setup_failed(void)
        test->post_teardown_func(test->test_data);
 }
 
-void tester_test_passed(void)
+static void test_result(enum test_result result)
 {
        struct test_case *test;
 
@@ -512,33 +518,41 @@ void tester_test_passed(void)
                test->timeout_id = 0;
        }
 
-       test->result = TEST_RESULT_PASSED;
-       print_progress(test->name, COLOR_GREEN, "test passed");
-
-       g_idle_add(teardown_callback, test);
-}
-
-void tester_test_failed(void)
-{
-       struct test_case *test;
+       test->result = result;
+       switch (result) {
+       case TEST_RESULT_PASSED:
+               print_progress(test->name, COLOR_GREEN, "test passed");
+               break;
+       case TEST_RESULT_FAILED:
+               print_progress(test->name, COLOR_RED, "test failed");
+               break;
+       case TEST_RESULT_NOT_RUN:
+               print_progress(test->name, COLOR_YELLOW, "test not run");
+               break;
+       case TEST_RESULT_TIMED_OUT:
+               print_progress(test->name, COLOR_RED, "test timed out");
+               break;
+       }
 
-       if (!test_current)
+       if (test->teardown_id > 0)
                return;
 
-       test = test_current->data;
-
-       if (test->stage != TEST_STAGE_RUN)
-               return;
+       test->teardown_id = g_idle_add(teardown_callback, test);
+}
 
-       if (test->timeout_id > 0) {
-               g_source_remove(test->timeout_id);
-               test->timeout_id = 0;
-       }
+void tester_test_passed(void)
+{
+       test_result(TEST_RESULT_PASSED);
+}
 
-       test->result = TEST_RESULT_FAILED;
-       print_progress(test->name, COLOR_RED, "test failed");
+void tester_test_failed(void)
+{
+       test_result(TEST_RESULT_FAILED);
+}
 
-       g_idle_add(teardown_callback, test);
+void tester_test_abort(void)
+{
+       test_result(TEST_RESULT_NOT_RUN);
 }
 
 void tester_teardown_complete(void)
index 0231f19..83ef5de 100644 (file)
@@ -63,6 +63,7 @@ void tester_setup_failed(void);
 
 void tester_test_passed(void);
 void tester_test_failed(void);
+void tester_test_abort(void);
 
 void tester_teardown_complete(void);
 void tester_teardown_failed(void);
diff --git a/test/advertisement-example b/test/advertisement-example
new file mode 100644 (file)
index 0000000..98aeafa
--- /dev/null
@@ -0,0 +1,170 @@
+#!/usr/bin/python
+
+import dbus
+import dbus.exceptions
+import dbus.mainloop.glib
+import dbus.service
+
+import array
+import gobject
+
+from random import randint
+
+mainloop = None
+
+BLUEZ_SERVICE_NAME = 'org.bluez'
+LE_ADVERTISING_MANAGER_IFACE = 'org.bluez.LEAdvertisingManager1'
+DBUS_OM_IFACE = 'org.freedesktop.DBus.ObjectManager'
+DBUS_PROP_IFACE = 'org.freedesktop.DBus.Properties'
+
+LE_ADVERTISEMENT_IFACE = 'org.bluez.LEAdvertisement1'
+
+
+class InvalidArgsException(dbus.exceptions.DBusException):
+    _dbus_error_name = 'org.freedesktop.DBus.Error.InvalidArgs'
+
+
+class NotSupportedException(dbus.exceptions.DBusException):
+    _dbus_error_name = 'org.bluez.Error.NotSupported'
+
+
+class NotPermittedException(dbus.exceptions.DBusException):
+    _dbus_error_name = 'org.bluez.Error.NotPermitted'
+
+
+class InvalidValueLengthException(dbus.exceptions.DBusException):
+    _dbus_error_name = 'org.bluez.Error.InvalidValueLength'
+
+
+class FailedException(dbus.exceptions.DBusException):
+    _dbus_error_name = 'org.bluez.Error.Failed'
+
+
+class Advertisement(dbus.service.Object):
+    PATH_BASE = '/org/bluez/example/advertisement'
+
+    def __init__(self, bus, index, advertising_type):
+        self.path = self.PATH_BASE + str(index)
+        self.bus = bus
+        self.ad_type = advertising_type
+        self.service_uuids = None
+        self.manufacturer_data = None
+        self.solicit_uuids = None
+        self.service_data = None
+        dbus.service.Object.__init__(self, bus, self.path)
+
+    def get_properties(self):
+        properties = dict()
+        properties['Type'] = self.ad_type
+        if self.service_uuids is not None:
+            properties['ServiceUUIDs'] = dbus.Array(self.service_uuids,
+                                                    signature='s')
+        if self.solicit_uuids is not None:
+            properties['SolicitUUIDs'] = dbus.Array(self.solicit_uuids,
+                                                    signature='s')
+        if self.manufacturer_data is not None:
+            properties['ManufacturerData'] = dbus.Dictionary(
+                self.manufacturer_data, signature='qay')
+        if self.service_data is not None:
+            properties['ServiceData'] = dbus.Dictionary(self.service_data,
+                                                        signature='say')
+        return {LE_ADVERTISEMENT_IFACE: properties}
+
+    def get_path(self):
+        return dbus.ObjectPath(self.path)
+
+    def add_service_uuid(self, uuid):
+        if not self.service_uuids:
+            self.service_uuids = []
+        self.service_uuids.append(uuid)
+
+    def add_solicit_uuid(self, uuid):
+        if not self.solicit_uuids:
+            self.solicit_uuids = []
+        self.solicit_uuids.append(uuid)
+
+    def add_manufacturer_data(self, manuf_code, data):
+        if not self.manufacturer_data:
+            self.manufacturer_data = dict()
+        self.manufacturer_data[manuf_code] = data
+
+    def add_service_data(self, uuid, data):
+        if not self.service_data:
+            self.service_data = dict()
+        self.service_data[uuid] = data
+
+    @dbus.service.method(DBUS_PROP_IFACE,
+                         in_signature='s',
+                         out_signature='a{sv}')
+    def GetAll(self, interface):
+        print 'GetAll'
+        if interface != LE_ADVERTISEMENT_IFACE:
+            raise InvalidArgsException()
+        print 'returning props'
+        return self.get_properties()[LE_ADVERTISEMENT_IFACE]
+
+    @dbus.service.method(LE_ADVERTISEMENT_IFACE,
+                         in_signature='',
+                         out_signature='')
+    def Release(self):
+        print '%s: Released!' % self.path
+
+class TestAdvertisement(Advertisement):
+
+    def __init__(self, bus, index):
+        Advertisement.__init__(self, bus, index, 'broadcast')
+        self.add_service_uuid('0000180D-0000-1000-8000-00805F9B34FB')
+        self.add_service_uuid('0000180F-0000-1000-8000-00805F9B34FB')
+        self.add_manufacturer_data(0xffff, [0x00, 0x01, 0x02, 0x03, 0x04])
+        self.add_service_data('00009999-0000-1000-8000-00805F9B34FB',
+                              [0x00, 0x01, 0x02, 0x03, 0x04])
+
+
+def register_ad_cb():
+    print 'Advertisement registered'
+
+
+def register_ad_error_cb(error):
+    print 'Failed to register advertisement: ' + str(error)
+    mainloop.quit()
+
+
+def find_adapter(bus):
+    remote_om = dbus.Interface(bus.get_object(BLUEZ_SERVICE_NAME, '/'),
+                               DBUS_OM_IFACE)
+    objects = remote_om.GetManagedObjects()
+
+    for o, props in objects.iteritems():
+        if LE_ADVERTISING_MANAGER_IFACE in props:
+            return o
+
+    return None
+
+
+def main():
+    global mainloop
+
+    dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
+
+    bus = dbus.SystemBus()
+
+    adapter = find_adapter(bus)
+    if not adapter:
+        print 'LEAdvertisingManager1 interface not found'
+        return
+
+    ad_manager = dbus.Interface(bus.get_object(BLUEZ_SERVICE_NAME, adapter),
+                                LE_ADVERTISING_MANAGER_IFACE)
+
+    test_advertisement = TestAdvertisement(bus, 0)
+
+    mainloop = gobject.MainLoop()
+
+    ad_manager.RegisterAdvertisement(test_advertisement.get_path(), {},
+                                     reply_handler=register_ad_cb,
+                                     error_handler=register_ad_error_cb)
+
+    mainloop.run()
+
+if __name__ == '__main__':
+    main()
diff --git a/tools/bneptest.c b/tools/bneptest.c
new file mode 100644 (file)
index 0000000..84319b9
--- /dev/null
@@ -0,0 +1,710 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2015 Intel Corporation
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <linux/sockios.h>
+#include <netinet/in.h>
+#include <linux/if_bridge.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/hci_lib.h>
+
+#include <glib.h>
+
+#include "src/log.h"
+#include "src/shared/util.h"
+#include "btio/btio.h"
+#include "lib/bnep.h"
+#include "profiles/network/bnep.h"
+
+enum {
+       MODE_LISTEN,
+       MODE_CONNECT,
+};
+
+static GMainLoop *mloop;
+static GIOChannel *bnep_io;
+static struct bnep *session;
+
+static int mode;
+static bool no_close_after_disconn;
+static int send_frame_timeout;
+
+static bdaddr_t src_addr, dst_addr;
+static char iface[16];
+static char bridge[16];
+static bool send_ctrl_msg_type_set = false;
+static uint8_t ctrl_msg_type = 0x00;
+static bool send_bnep_msg_type_set = false;
+static uint8_t bnep_msg_type = 0x00;
+static int ctrl_msg_retransmition_nb = 0;
+static int bnep_msg_retransmission_nb = 0;
+static uint16_t local_role = BNEP_SVC_PANU;
+static uint16_t remote_role = BNEP_SVC_NAP;
+static uint16_t ntw_proto_down_range = 0x0000;
+static uint16_t ntw_proto_up_range = 0xdc05;
+static uint16_t ntw_proto_type = 0x0000;
+static uint8_t mcast_addr_down_range[6];
+static uint8_t mcast_addr_up_range[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+static uint8_t src_hw_addr[6];
+static uint8_t dst_hw_addr[6];
+static uint8_t general_frame_payload[] = "abcdef0123456789_bnep_test_data";
+
+static int set_forward_delay(int sk)
+{
+       unsigned long args[4] = { BRCTL_SET_BRIDGE_FORWARD_DELAY, 0, 0, 0 };
+       struct ifreq ifr;
+
+       memset(&ifr, 0, sizeof(ifr));
+       strncpy(ifr.ifr_name, bridge, IFNAMSIZ);
+       ifr.ifr_data = (char *) args;
+
+       if (ioctl(sk, SIOCDEVPRIVATE, &ifr) < 0) {
+               error("setting forward delay failed: %d (%s)",
+                                                       errno, strerror(errno));
+               return -1;
+       }
+
+       return 0;
+}
+
+static int nap_create_bridge(void)
+{
+       int sk, err;
+
+       sk = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0);
+       if (sk < 0)
+               return -EOPNOTSUPP;
+
+       if (ioctl(sk, SIOCBRADDBR, bridge) < 0) {
+               if (errno != EEXIST) {
+                       close(sk);
+                       return -EOPNOTSUPP;
+               }
+       }
+
+       err = set_forward_delay(sk);
+       if (err < 0) {
+               printf("failed to set forward delay\n");
+               ioctl(sk, SIOCBRDELBR, bridge);
+       }
+
+       close(sk);
+
+       return err;
+}
+
+static int cleanup(void)
+{
+       bnep_cleanup();
+
+       if (mode == MODE_LISTEN)
+               bnep_server_delete(bridge, iface, &dst_addr);
+
+       if (bnep_io) {
+               g_io_channel_shutdown(bnep_io, TRUE, NULL);
+               g_io_channel_unref(bnep_io);
+               bnep_io = NULL;
+       }
+
+       return 0;
+}
+
+static gboolean bnep_watchdog_cb(GIOChannel *chan, GIOCondition cond,
+                                                       gpointer user_data)
+{
+       printf("%s\n", __func__);
+
+       if (no_close_after_disconn)
+               return FALSE;
+
+       /* Cleanup since it's called when disconnected l2cap */
+       if (cleanup() < 0) {
+               printf("cleanup went wrong...\n");
+               return FALSE;
+       }
+
+       g_main_loop_quit(mloop);
+       return FALSE;
+}
+
+static ssize_t send_compressed_frame(int sk, uint8_t type)
+{
+       uint8_t frame[100];
+
+       printf("%s\n", __func__);
+
+       if (send_frame_timeout > 0) {
+               printf("waiting %d seconds before sending msg\n",
+                                                       send_frame_timeout);
+               sleep(send_frame_timeout);
+       }
+
+       frame[0] = type;
+       memcpy(&frame[1], dst_hw_addr, sizeof(dst_hw_addr));
+       memcpy(&frame[7], src_hw_addr, sizeof(src_hw_addr));
+       frame[13] = ntw_proto_type & 0xff;
+       frame[14] = (ntw_proto_type >> 8);
+       memcpy(&frame[15], general_frame_payload,
+                                               sizeof(general_frame_payload));
+
+       /* TODO - set frame payload by user */
+       return send(sk, frame, 15 + sizeof(general_frame_payload), 0);
+}
+
+static ssize_t send_general_frame(int sk)
+{
+       uint8_t frame[100];
+
+       printf("%s\n", __func__);
+
+       if (send_frame_timeout > 0) {
+               printf("waiting %d seconds before sending msg\n",
+                                                       send_frame_timeout);
+               sleep(send_frame_timeout);
+       }
+
+       frame[0] = BNEP_GENERAL;
+       memcpy(&frame[1], dst_hw_addr, sizeof(dst_hw_addr));
+       memcpy(&frame[7], src_hw_addr, sizeof(src_hw_addr));
+       frame[13] = ntw_proto_type & 0xff;
+       frame[14] = (ntw_proto_type >> 8);
+       memcpy(&frame[15], general_frame_payload,
+                                               sizeof(general_frame_payload));
+
+       /* TODO - set frame payload by user */
+       return send(sk, frame, 15 + sizeof(general_frame_payload), 0);
+}
+
+static ssize_t send_ctrl_frame(int sk)
+{
+       /*
+        * Max buff size = type(1byte) + ctrl(1byte) + len(2byte) +
+        * mcast_addr_down(6byte) + mcast_addr_up(6byte)
+        */
+       uint8_t buff[16];
+       struct bnep_set_filter_req *frame = (void *) buff;
+       int err;
+
+       printf("%s\n", __func__);
+
+       if (send_frame_timeout > 0) {
+               printf("waiting %d seconds before sending msg\n",
+                                               send_frame_timeout);
+               sleep(send_frame_timeout);
+       }
+
+       switch (ctrl_msg_type) {
+       case BNEP_FILTER_NET_TYPE_SET:
+               frame->type = BNEP_CONTROL;
+               frame->ctrl = ctrl_msg_type;
+               frame->len = htons(sizeof(ntw_proto_down_range) +
+                                               sizeof(ntw_proto_up_range));
+               memcpy(frame->list, &ntw_proto_down_range,
+                                               sizeof(ntw_proto_down_range));
+               memcpy(frame->list + sizeof(ntw_proto_down_range),
+                       &ntw_proto_up_range, sizeof(ntw_proto_up_range));
+
+               err = send(sk, frame, sizeof(*frame) +
+                                               sizeof(ntw_proto_down_range) +
+                                               sizeof(ntw_proto_up_range), 0);
+               break;
+       case BNEP_FILTER_MULT_ADDR_SET:
+               frame->type = BNEP_CONTROL;
+               frame->ctrl = ctrl_msg_type;
+               frame->len = htons(sizeof(mcast_addr_down_range) +
+                                               sizeof(mcast_addr_up_range));
+               memcpy(frame->list, mcast_addr_down_range,
+                                               sizeof(mcast_addr_down_range));
+               memcpy(frame->list + sizeof(mcast_addr_down_range),
+                       mcast_addr_up_range, sizeof(mcast_addr_up_range));
+
+               err = send(sk, frame, sizeof(*frame) +
+                                       sizeof(mcast_addr_down_range) +
+                                       sizeof(mcast_addr_up_range), 0);
+               break;
+       default:
+               err = -1;
+               break;
+       }
+
+       return err;
+}
+
+static int send_bnep_frame(int sk)
+{
+       int err;
+
+       switch (bnep_msg_type) {
+       case BNEP_GENERAL:
+               err = send_general_frame(sk);
+               break;
+       case BNEP_COMPRESSED:
+               err = send_compressed_frame(sk, BNEP_COMPRESSED);
+               break;
+       case BNEP_COMPRESSED_SRC_ONLY:
+               err = send_compressed_frame(sk,
+                                       BNEP_COMPRESSED_SRC_ONLY);
+               break;
+       case BNEP_COMPRESSED_DST_ONLY:
+               err = send_compressed_frame(sk,
+                                       BNEP_COMPRESSED_DST_ONLY);
+               break;
+       default:
+               printf("wrong bnep_msg_type 0x%02x\n", bnep_msg_type);
+               err = -EINVAL;
+               break;
+       }
+
+       return err;
+}
+
+static void handle_bnep_msg_send(int sk)
+{
+       if (send_ctrl_msg_type_set) {
+               do {
+                       if (send_ctrl_frame(sk) < 0)
+                               printf("sending ctrl frame error: %s (%d)\n",
+                                                       strerror(errno), errno);
+               } while (ctrl_msg_retransmition_nb--);
+       }
+
+       if (send_bnep_msg_type_set) {
+               do {
+                       if (send_bnep_frame(sk) < 0)
+                               printf("sending bnep frame error: %s (%d)\n",
+                                                       strerror(errno), errno);
+               } while (bnep_msg_retransmission_nb--);
+       }
+}
+
+static gboolean setup_bnep_cb(GIOChannel *chan, GIOCondition cond,
+                                                       gpointer user_data)
+{
+       uint8_t packet[BNEP_MTU];
+       int sk, n, err;
+
+       printf("%s\n", __func__);
+
+       if (cond & (G_IO_ERR | G_IO_HUP | G_IO_NVAL)) {
+               error("hangup or error or inval on BNEP socket");
+               return FALSE;
+       }
+
+       sk = g_io_channel_unix_get_fd(chan);
+
+       /* Reading BNEP_SETUP_CONNECTION_REQUEST_MSG */
+#ifdef  __TIZEN_PATCH__
+       n = recv(sk, packet, sizeof(packet), MSG_PEEK);
+#else
+       n = read(sk, packet, sizeof(packet));
+#endif
+       if (n < 0) {
+               error("read(): %s(%d)", strerror(errno), errno);
+               return FALSE;
+       }
+
+       err = nap_create_bridge();
+       if (err < 0) {
+               error("failed to create bridge: %s (%d)", strerror(-err), err);
+               return FALSE;
+       }
+
+       if (bnep_server_add(sk, (err < 0) ? NULL : bridge, iface, &dst_addr,
+                                                       packet, n) < 0) {
+               printf("server_connadd failed\n");
+               cleanup();
+               return FALSE;
+       }
+
+       g_io_add_watch(chan, G_IO_HUP | G_IO_ERR | G_IO_NVAL, bnep_watchdog_cb,
+                                                                       NULL);
+
+       handle_bnep_msg_send(sk);
+
+       g_io_channel_unref(bnep_io);
+       bnep_io = NULL;
+
+       return FALSE;
+}
+
+static void connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
+{
+       printf("%s\n", __func__);
+
+       if (err) {
+               error("%s", err->message);
+               return;
+       }
+
+       g_io_add_watch(chan, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+                                                       setup_bnep_cb, NULL);
+}
+
+static void connected_client_cb(char *iface, int err, void *data)
+{
+       int sk = PTR_TO_INT(data);
+
+       printf("%s\n", __func__);
+
+       handle_bnep_msg_send(sk);
+}
+
+static void disconnected_client_cb(void *data)
+{
+       printf("%s\n", __func__);
+
+       if (no_close_after_disconn)
+               return;
+
+       /* Cleanup since it's called when disconnected l2cap */
+       if (cleanup() < 0) {
+               printf("cleanup went wrong...\n");
+               return;
+       }
+
+       g_main_loop_quit(mloop);
+}
+
+static void connect_client_cb(GIOChannel *chan, GError *err, gpointer user_data)
+{
+       int perr;
+       int sk;
+
+       sk = g_io_channel_unix_get_fd(bnep_io);
+
+       session = bnep_new(sk, local_role, remote_role, bridge);
+       if (!session) {
+               printf("cannot create bnep session\n");
+               return;
+       }
+
+       perr = bnep_connect(session, connected_client_cb,
+                               disconnected_client_cb, INT_TO_PTR(sk), NULL);
+       if (perr < 0)
+               printf("cannot initiate bnep connection\n");
+}
+
+static void confirm_cb(GIOChannel *chan, gpointer data)
+{
+       GError *err = NULL;
+       char address[18];
+
+       printf("%s\n", __func__);
+
+       bt_io_get(chan, &err, BT_IO_OPT_DEST_BDADDR, &dst_addr, BT_IO_OPT_DEST,
+                                               address, BT_IO_OPT_INVALID);
+       if (err) {
+               error("%s", err->message);
+               g_error_free(err);
+               return;
+       }
+
+       printf("incoming connection from: %s\n", address);
+
+       bnep_io = g_io_channel_ref(chan);
+       g_io_channel_set_close_on_unref(bnep_io, TRUE);
+
+       if (!bt_io_accept(bnep_io, connect_cb, NULL, NULL, &err)) {
+               error("bt_io_accept: %s", err->message);
+               g_error_free(err);
+               g_io_channel_unref(bnep_io);
+       }
+}
+
+static int bnep_server_listen(void)
+{
+       GError *gerr = NULL;
+
+       printf("%s\n", __func__);
+
+       bnep_io = bt_io_listen(NULL, confirm_cb, NULL, NULL, &gerr,
+                                       BT_IO_OPT_SOURCE_BDADDR, &src_addr,
+                                       BT_IO_OPT_PSM, BNEP_PSM,
+                                       BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
+                                       BT_IO_OPT_OMTU, BNEP_MTU,
+                                       BT_IO_OPT_IMTU, BNEP_MTU,
+                                       BT_IO_OPT_INVALID);
+       if (!bnep_io) {
+               printf("can't start server listening: err %s\n", gerr->message);
+               g_error_free(gerr);
+               return -1;
+       }
+
+       return 0;
+}
+
+static int bnep_client_connect(void)
+{
+       GError *gerr = NULL;
+       char bdastr[18];
+
+       printf("%s\n", __func__);
+
+       ba2str(&dst_addr, bdastr);
+       printf("connecting %s\n", bdastr);
+
+       bnep_io = bt_io_connect(connect_client_cb, NULL, NULL, &gerr,
+                                       BT_IO_OPT_SOURCE_BDADDR, &src_addr,
+                                       BT_IO_OPT_DEST_BDADDR, &dst_addr,
+                                       BT_IO_OPT_PSM, BNEP_PSM,
+                                       BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM,
+                                       BT_IO_OPT_OMTU, BNEP_MTU,
+                                       BT_IO_OPT_IMTU, BNEP_MTU,
+                                       BT_IO_OPT_INVALID);
+       if (!bnep_io) {
+               printf("cannot connect: err %s\n", gerr->message);
+               g_error_free(gerr);
+               return -1;
+       }
+
+       return 0;
+}
+
+static void exit_handler(int sig)
+{
+       printf("got sig = %d, cleaning up...\n", sig);
+
+       if (cleanup() < 0)
+               printf("cleanup failure...\n");
+       else
+               printf("cleanup successful - exit\n");
+
+       exit(0);
+}
+
+static void usage(void)
+{
+       printf("bneptest - BNEP testing ver %s\n", VERSION);
+       printf("Usage:\n"
+               "\tbneptest [-i] -b <bridge name> -n <iface name>"
+                               " <connection mode> [send_ctrl_cmd] [options]\n"
+               "\t-i hci dev number <hci number>, def. 0\n"
+               "\t-b bridge name <string>\n"
+               "\t-n interface name <string>\n");
+       printf("Connect Mode:\n"
+               "\t-c connect <dst_addr>\n"
+               "\t-r remote role <16 bit svc value>\n"
+               "\t-l local role <16 bit svc valu>\n");
+       printf("Listen Mode:\n"
+               "\t-s start server listening\n");
+       printf("Send control command:\n"
+               "\t-t send message type <control msg type>, def. 0\n"
+               "\t-e start network protocol type range <16 bit val>, def. 0\n"
+               "\t-d end network protocol type range <16 bit val>, def. 1500\n"
+               "\t-g start multicast addr range <xx:xx:xx:xx:xx:xx>, def. 0\n"
+               "\t-j end multicast addr range <xx:xx:xx:xx:xx:xx>, def. f\n"
+               "\t-y number of ctrl frame retransmission <integer>, def. 0\n"
+               "\t-u number of bnep frame retransmission <integer>, def. 0\n");
+       printf("Send bnep generic frame:\n"
+               "\t-w send bnep generic frame <bnep generic type>, def. 0\n"
+               "\t-k set src mac addr <xx:xx:xx:xx:xx:xx>, def. 0\n"
+               "\t-f set dst mac addr <xx:xx:xx:xx:xx:xx>, def. 0\n");
+       printf("Options:\n"
+               "\t-T send message timeout after setup <seconds>\n"
+               "\t-N don't close bneptest after disconnect\n");
+}
+
+static struct option main_options[] = {
+       { "device",                     1, 0, 'i' },
+       { "listen",                     0, 0, 's' },
+       { "connect",                    1, 0, 'c' },
+       { "snd_ctrl_msg_type",          1, 0, 't' },
+       { "snd_bnep_msg_type",          1, 0, 'w' },
+       { "src_hw_addr",                1, 0, 'k' },
+       { "dst_hw_addr",                1, 0, 'f' },
+       { "send_timeout",               1, 0, 'T' },
+       { "ntw_proto_down_range",       1, 0, 'd' },
+       { "ntw_proto_up_range",         1, 0, 'e' },
+       { "mcast_addr_down_range",      1, 0, 'g' },
+       { "mcast_addr_up_range",        1, 0, 'j' },
+       { "local_role",                 1, 0, 'l' },
+       { "remote_role",                1, 0, 'r' },
+       { "bridge name",                1, 0, 'b' },
+       { "iface name",                 1, 0, 'n' },
+       { "no_close",                   0, 0, 'N' },
+       { "retrans_ctrl_nb",            0, 0, 'y' },
+       { "retrans_bnep_nb",            0, 0, 'u' },
+       { "help",                       0, 0, 'h' },
+       { 0, 0, 0, 0 }
+};
+
+int main(int argc, char *argv[])
+{
+       int opt, i;
+       int err;
+       bool is_set_b_name = false, is_set_i_name = false;
+
+       DBG("");
+
+       signal(SIGINT, exit_handler);
+
+       hci_devba(0, &src_addr);
+       bacpy(&src_addr, BDADDR_ANY);
+
+       mloop = g_main_loop_new(NULL, FALSE);
+       if (!mloop) {
+               printf("cannot create main loop\n");
+
+               exit(1);
+       }
+
+       while ((opt = getopt_long(argc, argv,
+                               "+i:c:b:n:t:T:d:e:g:j:k:f:w:l:r:y:u:Nsh",
+                               main_options, NULL)) != EOF) {
+               switch (opt) {
+               case 'i':
+                       if (!strncmp(optarg, "hci", 3))
+                               hci_devba(atoi(optarg + 3), &src_addr);
+                       else
+                               str2ba(optarg, &src_addr);
+                       break;
+               case 's':
+                       mode = MODE_LISTEN;
+                       break;
+               case 'c':
+                       str2ba(optarg, &dst_addr);
+                       mode = MODE_CONNECT;
+                       break;
+               case 't':
+                       send_ctrl_msg_type_set = true;
+                       ctrl_msg_type = atoi(optarg);
+                       break;
+               case 'w':
+                       send_bnep_msg_type_set = true;
+                       bnep_msg_type = atoi(optarg);
+                       break;
+               case 'k':
+                       for (i = 0; i <= 5; i++, optarg += 3)
+                               src_hw_addr[i] = strtol(optarg, NULL, 16);
+                       break;
+               case 'f':
+                       for (i = 0; i <= 5; i++, optarg += 3)
+                               dst_hw_addr[i] = strtol(optarg, NULL, 16);
+                       break;
+               case 'T':
+                       send_frame_timeout = atoi(optarg);
+                       break;
+               case 'd':
+                       ntw_proto_down_range = htons(atoi(optarg));
+                       break;
+               case 'e':
+                       ntw_proto_up_range = htons(atoi(optarg));
+                       break;
+               case 'g':
+                       for (i = 5; i >= 0; i--, optarg += 3)
+                               mcast_addr_down_range[i] =
+                                               strtol(optarg, NULL, 16);
+                       break;
+               case 'j':
+                       for (i = 5; i >= 0; i--, optarg += 3)
+                               mcast_addr_up_range[i] =
+                                               strtol(optarg, NULL, 16);
+                       break;
+               case 'l':
+                       local_role = atoi(optarg);
+                       break;
+               case 'r':
+                       remote_role = atoi(optarg);
+                       break;
+               case 'b':
+                       strncpy(bridge, optarg, 16);
+                       bridge[15] = '\0';
+                       is_set_b_name = true;
+                       break;
+               case 'n':
+                       strncpy(iface, optarg, 14);
+                       strcat(iface, "\%d");
+                       iface[15] = '\0';
+                       is_set_i_name = true;
+                       break;
+               case 'N':
+                       no_close_after_disconn = true;
+                       break;
+               case 'y':
+                       ctrl_msg_retransmition_nb = atoi(optarg);
+                       break;
+               case 'u':
+                       bnep_msg_retransmission_nb = atoi(optarg);
+                       break;
+               case 'h':
+               default:
+                       usage();
+                       exit(0);
+               }
+       }
+
+       if (!is_set_b_name || !is_set_i_name) {
+               printf("bridge, interface name must be set!\n");
+               exit(1);
+       }
+
+       switch (mode) {
+       case MODE_CONNECT:
+               err = bnep_init();
+               if (err < 0) {
+                       printf("cannot initialize bnep\n");
+                       exit(1);
+               }
+               err = bnep_client_connect();
+               if (err < 0)
+                       exit(1);
+
+               break;
+       case MODE_LISTEN:
+               err = bnep_init();
+               if (err < 0) {
+                       printf("cannot initialize bnep\n");
+                       exit(1);
+               }
+               err = bnep_server_listen();
+               if (err < 0)
+                       exit(1);
+
+               break;
+       default:
+               printf("connect/listen mode not set, exit...\n");
+               exit(1);
+       }
+
+       g_main_loop_run(mloop);
+
+       printf("Done\n");
+
+       g_main_loop_unref(mloop);
+
+       return 0;
+}
index c90f265..ee5315d 100644 (file)
@@ -67,6 +67,8 @@ struct client {
        struct bt_att *att;
        struct gatt_db *db;
        struct bt_gatt_client *gatt;
+
+       unsigned int reliable_session_id;
 };
 
 static void print_prompt(void)
@@ -884,6 +886,208 @@ static void cmd_write_long_value(struct client *cli, char *cmd_str)
        free(value);
 }
 
+static void write_prepare_usage(void)
+{
+       printf("Usage: write-prepare [options] <value_handle> <offset> "
+                               "<value>\n"
+                               "Options:\n"
+                               "\t-s, --session-id\tSession id\n"
+                               "e.g.:\n"
+                               "\twrite-prepare -s 1 0x0001 00 01 00\n");
+}
+
+static struct option write_prepare_options[] = {
+       { "session-id",         1, 0, 's' },
+       { }
+};
+
+static void cmd_write_prepare(struct client *cli, char *cmd_str)
+{
+       int opt, i;
+       char *argvbuf[516];
+       char **argv = argvbuf;
+       int argc = 0;
+       unsigned int id = 0;
+       uint16_t handle;
+       uint16_t offset;
+       char *endptr = NULL;
+       unsigned int length;
+       uint8_t *value = NULL;
+
+       if (!bt_gatt_client_is_ready(cli->gatt)) {
+               printf("GATT client not initialized\n");
+               return;
+       }
+
+       if (!parse_args(cmd_str, 514, argv + 1, &argc)) {
+               printf("Too many arguments\n");
+               write_value_usage();
+               return;
+       }
+
+       /* Add command name for getopt_long */
+       argc++;
+       argv[0] = "write-prepare";
+
+       optind = 0;
+       while ((opt = getopt_long(argc, argv , "s:", write_prepare_options,
+                                                               NULL)) != -1) {
+               switch (opt) {
+               case 's':
+                       if (!optarg) {
+                               write_prepare_usage();
+                               return;
+                       }
+
+                       id = atoi(optarg);
+
+                       break;
+               default:
+                       write_prepare_usage();
+                       return;
+               }
+       }
+
+       argc -= optind;
+       argv += optind;
+
+       if (argc < 3) {
+               write_prepare_usage();
+               return;
+       }
+
+       if (cli->reliable_session_id != id) {
+               printf("Session id != Ongoing session id (%u!=%u)\n", id,
+                                               cli->reliable_session_id);
+               return;
+       }
+
+       handle = strtol(argv[0], &endptr, 0);
+       if (!endptr || *endptr != '\0' || !handle) {
+               printf("Invalid handle: %s\n", argv[0]);
+               return;
+       }
+
+       endptr = NULL;
+       offset = strtol(argv[1], &endptr, 0);
+       if (!endptr || *endptr != '\0' || errno == ERANGE) {
+               printf("Invalid offset: %s\n", argv[1]);
+               return;
+       }
+
+       /*
+        * First two arguments are handle and offset. What remains is the value
+        * length
+        */
+       length = argc - 2;
+
+       if (length == 0)
+               goto done;
+
+       if (length > UINT16_MAX) {
+               printf("Write value too long\n");
+               return;
+       }
+
+       value = malloc(length);
+       if (!value) {
+               printf("Failed to allocate memory for value\n");
+               return;
+       }
+
+       for (i = 2; i < argc; i++) {
+               if (strlen(argv[i]) != 2) {
+                       printf("Invalid value byte: %s\n", argv[i]);
+                       free(value);
+                       return;
+               }
+
+               value[i-2] = strtol(argv[i], &endptr, 0);
+               if (endptr == argv[i] || *endptr != '\0' || errno == ERANGE) {
+                       printf("Invalid value byte: %s\n", argv[i]);
+                       free(value);
+                       return;
+               }
+       }
+
+done:
+       cli->reliable_session_id =
+                       bt_gatt_client_prepare_write(cli->gatt, id,
+                                                       handle, offset,
+                                                       value, length,
+                                                       write_long_cb, NULL,
+                                                       NULL);
+       if (!cli->reliable_session_id)
+               printf("Failed to proceed prepare write\n");
+       else
+               printf("Prepare write success.\n"
+                               "Session id: %d to be used on next write\n",
+                                               cli->reliable_session_id);
+
+       free(value);
+}
+
+static void write_execute_usage(void)
+{
+       printf("Usage: write-execute <session_id> <execute>\n"
+                               "e.g.:\n"
+                               "\twrite-execute 1 0\n");
+}
+
+static void cmd_write_execute(struct client *cli, char *cmd_str)
+{
+       char *argvbuf[516];
+       char **argv = argvbuf;
+       int argc = 0;
+       char *endptr = NULL;
+       unsigned int session_id;
+       bool execute;
+
+       if (!bt_gatt_client_is_ready(cli->gatt)) {
+               printf("GATT client not initialized\n");
+               return;
+       }
+
+       if (!parse_args(cmd_str, 514, argv, &argc)) {
+               printf("Too many arguments\n");
+               write_value_usage();
+               return;
+       }
+
+       if (argc < 2) {
+               write_execute_usage();
+               return;
+       }
+
+       session_id = strtol(argv[0], &endptr, 0);
+       if (!endptr || *endptr != '\0') {
+               printf("Invalid session id: %s\n", argv[0]);
+               return;
+       }
+
+       if (session_id != cli->reliable_session_id) {
+               printf("Invalid session id: %u != %u\n", session_id,
+                                               cli->reliable_session_id);
+               return;
+       }
+
+       execute = !!strtol(argv[1], &endptr, 0);
+       if (!endptr || *endptr != '\0') {
+               printf("Invalid execute: %s\n", argv[1]);
+               return;
+       }
+
+       if (execute) {
+               if (!bt_gatt_client_write_execute(cli->gatt, session_id,
+                                                       write_cb, NULL, NULL))
+                       printf("Failed to proceed write execute\n");
+       } else {
+               bt_gatt_client_cancel(cli->gatt, session_id);
+       }
+
+       cli->reliable_session_id = 0;
+}
+
 static void register_notify_usage(void)
 {
        printf("Usage: register-notify <chrc value handle>\n");
@@ -1130,14 +1334,18 @@ static struct {
                        "\tWrite a characteristic or descriptor value" },
        { "write-long-value", cmd_write_long_value,
                        "Write long characteristic or descriptor value" },
+       { "write-prepare", cmd_write_prepare,
+                       "\tWrite prepare characteristic or descriptor value" },
+       { "write-execute", cmd_write_execute,
+                       "\tExecute already prepared write" },
        { "register-notify", cmd_register_notify,
                        "\tSubscribe to not/ind from a characteristic" },
        { "unregister-notify", cmd_unregister_notify,
                                                "Unregister a not/ind session"},
        { "set-sec-level", cmd_set_sec_level,
-                                       "Set security level on le connection"},
+                               "\tSet security level on le connection"},
        { "get-sec-level", cmd_get_sec_level,
-                                       "Get security level on le connection"},
+                               "\tGet security level on le connection"},
        { "set-sign-key", cmd_set_sign_key,
                                "\tSet signing key for signed write command"},
        { }
index b4fbe60..b30a958 100644 (file)
@@ -630,6 +630,7 @@ static void usage(void)
                "\t-m, --mtu <mtu>\t\t\tThe ATT MTU to use\n"
                "\t-s, --security-level <sec>\tSet security level (low|"
                                                                "medium|high)\n"
+               "\t-t, --type [random|public] \t The source address type\n"
                "\t-v, --verbose\t\t\tEnable extra logging\n"
                "\t-r, --heart-rate\t\tEnable Heart Rate service\n"
                "\t-h, --help\t\t\tDisplay help\n");
@@ -639,13 +640,15 @@ static struct option main_options[] = {
        { "index",              1, 0, 'i' },
        { "mtu",                1, 0, 'm' },
        { "security-level",     1, 0, 's' },
+       { "type",               1, 0, 't' },
        { "verbose",            0, 0, 'v' },
        { "heart-rate",         0, 0, 'r' },
        { "help",               0, 0, 'h' },
        { }
 };
 
-static int l2cap_le_att_listen_and_accept(bdaddr_t *src, int sec)
+static int l2cap_le_att_listen_and_accept(bdaddr_t *src, int sec,
+                                                       uint8_t src_type)
 {
        int sk, nsk;
        struct sockaddr_l2 srcaddr, addr;
@@ -663,7 +666,7 @@ static int l2cap_le_att_listen_and_accept(bdaddr_t *src, int sec)
        memset(&srcaddr, 0, sizeof(srcaddr));
        srcaddr.l2_family = AF_BLUETOOTH;
        srcaddr.l2_cid = htobs(ATT_CID);
-       srcaddr.l2_bdaddr_type = 0;
+       srcaddr.l2_bdaddr_type = src_type;
        bacpy(&srcaddr.l2_bdaddr, src);
 
        if (bind(sk, (struct sockaddr *) &srcaddr, sizeof(srcaddr)) < 0) {
@@ -1131,12 +1134,13 @@ int main(int argc, char *argv[])
        int dev_id = -1;
        int fd;
        int sec = BT_SECURITY_LOW;
+       uint8_t src_type = BDADDR_LE_PUBLIC;
        uint16_t mtu = 0;
        sigset_t mask;
        bool hr_visible = false;
        struct server *server;
 
-       while ((opt = getopt_long(argc, argv, "+hvrs:m:i:",
+       while ((opt = getopt_long(argc, argv, "+hvrs:t:m:i:",
                                                main_options, NULL)) != -1) {
                switch (opt) {
                case 'h':
@@ -1160,6 +1164,17 @@ int main(int argc, char *argv[])
                                return EXIT_FAILURE;
                        }
                        break;
+               case 't':
+                       if (strcmp(optarg, "random") == 0)
+                               src_type = BDADDR_LE_RANDOM;
+                       else if (strcmp(optarg, "public") == 0)
+                               src_type = BDADDR_LE_PUBLIC;
+                       else {
+                               fprintf(stderr,
+                                       "Allowed types: random, public\n");
+                               return EXIT_FAILURE;
+                       }
+                       break;
                case 'm': {
                        int arg;
 
@@ -1207,7 +1222,7 @@ int main(int argc, char *argv[])
                return EXIT_FAILURE;
        }
 
-       fd = l2cap_le_att_listen_and_accept(&src_addr, sec);
+       fd = l2cap_le_att_listen_and_accept(&src_addr, sec, src_type);
        if (fd < 0) {
                fprintf(stderr, "Failed to accept L2CAP ATT connection\n");
                return EXIT_FAILURE;
index 8eff56b..d7af7f0 100644 (file)
 #include "src/shared/util.h"
 #include "src/shared/mgmt.h"
 
+#define SCAN_TYPE_BREDR (1 << BDADDR_BREDR)
+#define SCAN_TYPE_LE ((1 << BDADDR_LE_PUBLIC) | (1 << BDADDR_LE_RANDOM))
+#define SCAN_TYPE_DUAL (SCAN_TYPE_BREDR | SCAN_TYPE_LE)
+
 static struct mgmt *mgmt = NULL;
 static uint16_t mgmt_index = MGMT_INDEX_NONE;
 
@@ -153,6 +157,56 @@ static size_t bin2hex(const uint8_t *buf, size_t buflen, char *str,
        return i;
 }
 
+static void print_eir(const uint8_t *eir, uint16_t eir_len)
+{
+       uint16_t parsed = 0;
+       char str[33];
+
+       while (parsed < eir_len - 1) {
+               uint8_t field_len = eir[0];
+
+               if (field_len == 0)
+                       break;
+
+               parsed += field_len + 1;
+
+               if (parsed > eir_len)
+                       break;
+
+               switch (eir[1]) {
+               case 0x01:
+                       print("Flags: 0x%02x", eir[2]);
+                       break;
+               case 0x0d:
+                       print("Class of Device: 0x%02x%02x%02x",
+                                               eir[4], eir[3], eir[2]);
+                       break;
+               case 0x1b:
+                       ba2str((bdaddr_t *) (eir + 2), str);
+                       print("LE Device Address: %s (%s)", str,
+                                       eir[8] ? "random" : "public");
+                       break;
+               case 0x1c:
+                       print("LE Role: 0x%02x", eir[2]);
+                       break;
+               case 0x22:
+                       bin2hex(eir + 2, 16, str, sizeof(str));
+                       print("LE SC Confirmation Value: %s", str);
+                       break;
+               case 0x23:
+                       bin2hex(eir + 2, 16, str, sizeof(str));
+                       print("LE SC Random Value: %s", str);
+                       break;
+               default:
+                       print("Type %u: %u byte%s", eir[1], field_len - 1,
+                                       (field_len - 1) == 1 ? "" : "s");
+                       break;
+               }
+
+               eir += field_len + 1;
+       }
+}
+
 static bool load_identity(uint16_t index, struct mgmt_irk_info *irk)
 {
        char identity_path[PATH_MAX];
@@ -235,6 +289,22 @@ static void unconf_index_removed(uint16_t index, uint16_t len,
        print("hci%u removed (unconfigured)", index);
 }
 
+static void ext_index_added(uint16_t index, uint16_t len,
+                               const void *param, void *user_data)
+{
+       const struct mgmt_ev_ext_index_added *ev = param;
+
+       print("hci%u added (type %u bus %u)", index, ev->type, ev->bus);
+}
+
+static void ext_index_removed(uint16_t index, uint16_t len,
+                               const void *param, void *user_data)
+{
+       const struct mgmt_ev_ext_index_removed *ev = param;
+
+       print("hci%u removed (type %u bus %u)", index, ev->type, ev->bus);
+}
+
 static const char *options_str[] = {
                                "external",
                                "public-address",
@@ -472,6 +542,20 @@ static void auth_failed(uint16_t index, uint16_t len, const void *param,
                        index, addr, ev->status, mgmt_errstr(ev->status));
 }
 
+static void class_of_dev_changed(uint16_t index, uint16_t len,
+                                       const void *param, void *user_data)
+{
+       const struct mgmt_ev_class_of_dev_changed *ev = param;
+
+       if (len != sizeof(*ev)) {
+               error("Invalid class_of_dev_changed length (%u bytes)", len);
+               return;
+       }
+
+       print("hci%u class of device changed: 0x%02x%02x%02x", index,
+                       ev->dev_class[2], ev->dev_class[1], ev->dev_class[0]);
+}
+
 static void local_name_changed(uint16_t index, uint16_t len, const void *param,
                                                        void *user_data)
 {
@@ -962,6 +1046,54 @@ static void passkey_notify(uint16_t index, uint16_t len, const void *param,
                                                                ev->entered);
 }
 
+static void local_oob_data_updated(uint16_t index, uint16_t len,
+                                       const void *param, void *user_data)
+{
+       const struct mgmt_ev_local_oob_data_updated *ev = param;
+       uint16_t eir_len;
+
+       if (len < sizeof(*ev)) {
+               error("Too small (%u bytes) local_oob_updated event", len);
+               return;
+       }
+
+       eir_len = le16_to_cpu(ev->eir_len);
+       if (len != sizeof(*ev) + eir_len) {
+               error("local_oob_updated: expected %zu bytes, got %u bytes",
+                                               sizeof(*ev) + eir_len, len);
+               return;
+       }
+
+       print("hci%u oob data updated: type %u len %u", index,
+                                               ev->type, eir_len);
+}
+
+static void advertising_added(uint16_t index, uint16_t len,
+                                       const void *param, void *user_data)
+{
+       const struct mgmt_ev_advertising_added *ev = param;
+
+       if (len < sizeof(*ev)) {
+               error("Too small (%u bytes) advertising_added event", len);
+               return;
+       }
+
+       print("hci%u advertising_added: instance %u", index, ev->instance);
+}
+
+static void advertising_removed(uint16_t index, uint16_t len,
+                                       const void *param, void *user_data)
+{
+       const struct mgmt_ev_advertising_removed *ev = param;
+
+       if (len < sizeof(*ev)) {
+               error("Too small (%u bytes) advertising_removed event", len);
+               return;
+       }
+
+       print("hci%u advertising_removed: instance %u", index, ev->instance);
+}
+
 static void version_rsp(uint8_t status, uint16_t len, const void *param,
                                                        void *user_data)
 {
@@ -1055,6 +1187,43 @@ static void cmd_commands(struct mgmt *mgmt, uint16_t index, int argc,
        }
 }
 
+static void config_info_rsp(uint8_t status, uint16_t len, const void *param,
+                                                       void *user_data)
+{
+       const struct mgmt_rp_read_config_info *rp = param;
+       uint16_t index = PTR_TO_UINT(user_data);
+       uint32_t supported_options, missing_options;
+
+       if (status != 0) {
+               error("Reading hci%u config failed with status 0x%02x (%s)",
+                                       index, status, mgmt_errstr(status));
+               goto done;
+       }
+
+       if (len < sizeof(*rp)) {
+               error("Too small info reply (%u bytes)", len);
+               goto done;
+       }
+
+       print("hci%u:\tUnconfigured controller", index);
+
+       print("\tmanufacturer %u", le16_to_cpu(rp->manufacturer));
+
+       supported_options = le32_to_cpu(rp->supported_options);
+       print("\tsupported options: %s", options2str(supported_options));
+
+       missing_options = le32_to_cpu(rp->missing_options);
+       print("\tmissing options: %s", options2str(missing_options));
+
+done:
+       pending_index--;
+
+       if (pending_index > 0)
+               return;
+
+       noninteractive_quit(EXIT_SUCCESS);
+}
+
 static void unconf_index_rsp(uint8_t status, uint16_t len, const void *param,
                                                        void *user_data)
 {
@@ -1065,43 +1234,67 @@ static void unconf_index_rsp(uint8_t status, uint16_t len, const void *param,
        if (status != 0) {
                error("Reading index list failed with status 0x%02x (%s)",
                                                status, mgmt_errstr(status));
-               goto done;
+               return noninteractive_quit(EXIT_FAILURE);
        }
 
        if (len < sizeof(*rp)) {
                error("Too small index list reply (%u bytes)", len);
-               goto done;
+               return noninteractive_quit(EXIT_FAILURE);
        }
 
-       count = get_le16(&rp->num_controllers);
+       count = le16_to_cpu(rp->num_controllers);
 
        if (len < sizeof(*rp) + count * sizeof(uint16_t)) {
                error("Index count (%u) doesn't match reply length (%u)",
                                                                count, len);
-               goto done;
+               return noninteractive_quit(EXIT_FAILURE);
        }
 
        print("Unconfigured index list with %u item%s",
-                                               count, count != 1 ? "s" : "");
+                                       count, count != 1 ? "s" : "");
 
        for (i = 0; i < count; i++) {
-               uint16_t index;
+               uint16_t index = le16_to_cpu(rp->index[i]);
 
-               index = get_le16(&rp->index[i]);
+               if (!mgmt_send(mgmt, MGMT_OP_READ_CONFIG_INFO, index, 0, NULL,
+                               config_info_rsp, UINT_TO_PTR(index), NULL)) {
+                       error("Unable to send read_config_info cmd");
+                       return noninteractive_quit(EXIT_FAILURE);
+               }
+
+               pending_index++;
+       }
+
+       if (!count)
+               noninteractive_quit(EXIT_SUCCESS);
+}
 
-               print("\thci%u", index);
+static void cmd_config(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
+{
+       if (index == MGMT_INDEX_NONE) {
+               if (!mgmt_send(mgmt, MGMT_OP_READ_UNCONF_INDEX_LIST,
+                                       MGMT_INDEX_NONE, 0, NULL,
+                                       unconf_index_rsp, mgmt, NULL)) {
+                       error("Unable to send unconf_index_list cmd");
+                       return noninteractive_quit(EXIT_FAILURE);
+               }
 
+               return;
        }
 
-done:
-       noninteractive_quit(EXIT_SUCCESS);
+       if (!mgmt_send(mgmt, MGMT_OP_READ_CONFIG_INFO, index, 0, NULL,
+                               config_info_rsp, UINT_TO_PTR(index), NULL)) {
+               error("Unable to send read_config_info cmd");
+               return noninteractive_quit(EXIT_FAILURE);
+       }
 }
 
-static void config_info_rsp(uint8_t status, uint16_t len, const void *param,
+static void config_options_rsp(uint8_t status, uint16_t len, const void *param,
                                                        void *user_data)
 {
        const struct mgmt_rp_read_config_info *rp = param;
        uint16_t index = PTR_TO_UINT(user_data);
+       uint32_t supported_options, missing_options;
 
        if (status != 0) {
                error("Reading hci%u config failed with status 0x%02x (%s)",
@@ -1114,39 +1307,21 @@ static void config_info_rsp(uint8_t status, uint16_t len, const void *param,
                goto done;
        }
 
-       print("hci%u:\tmanufacturer %u", index, get_le16(&rp->manufacturer));
-
-       print("\tsupported options: %s",
-                       options2str(get_le32(&rp->supported_options)));
-       print("\tmissing options: %s",
-                       options2str(get_le32(&rp->missing_options)));
+       print("hci%u:\tConfiguration options", index);
 
-done:
-       noninteractive_quit(EXIT_SUCCESS);
-}
+       supported_options = le32_to_cpu(rp->supported_options);
+       print("\tsupported options: %s", options2str(supported_options));
 
-static void cmd_config(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
-{
-       void *data;
+       missing_options = le32_to_cpu(rp->missing_options);
+       print("\tmissing options: %s", options2str(missing_options));
 
-       if (index == MGMT_INDEX_NONE) {
-               if (mgmt_send(mgmt, MGMT_OP_READ_UNCONF_INDEX_LIST,
-                                       MGMT_INDEX_NONE, 0, NULL,
-                                       unconf_index_rsp, mgmt, NULL) == 0) {
-                       error("Unable to send unconf_index_list cmd");
-                       return noninteractive_quit(EXIT_FAILURE);
-               }
+done:
+       pending_index--;
 
+       if (pending_index > 0)
                return;
-       }
 
-       data = UINT_TO_PTR(index);
-
-       if (mgmt_send(mgmt, MGMT_OP_READ_CONFIG_INFO, index, 0, NULL,
-                                       config_info_rsp, data, NULL) == 0) {
-               error("Unable to send read_config_info cmd");
-               return noninteractive_quit(EXIT_FAILURE);
-       }
+       noninteractive_quit(EXIT_SUCCESS);
 }
 
 static void info_rsp(uint8_t status, uint16_t len, const void *param,
@@ -1154,10 +1329,9 @@ static void info_rsp(uint8_t status, uint16_t len, const void *param,
 {
        const struct mgmt_rp_read_info *rp = param;
        uint16_t index = PTR_TO_UINT(user_data);
+       uint32_t supported_settings, current_settings;
        char addr[18];
 
-       pending_index--;
-
        if (status != 0) {
                error("Reading hci%u info failed with status 0x%02x (%s)",
                                        index, status, mgmt_errstr(status));
@@ -1169,25 +1343,38 @@ static void info_rsp(uint8_t status, uint16_t len, const void *param,
                goto done;
        }
 
+       print("hci%u:\tPrimary controller", index);
+
        ba2str(&rp->bdaddr, addr);
-       print("hci%u:\taddr %s version %u manufacturer %u"
-                       " class 0x%02x%02x%02x", index,
-                       addr, rp->version, get_le16(&rp->manufacturer),
+       print("\taddr %s version %u manufacturer %u class 0x%02x%02x%02x",
+                       addr, rp->version, le16_to_cpu(rp->manufacturer),
                        rp->dev_class[2], rp->dev_class[1], rp->dev_class[0]);
 
-       print("\tsupported settings: %s",
-                       settings2str(get_le32(&rp->supported_settings)));
+       supported_settings = le32_to_cpu(rp->supported_settings);
+       print("\tsupported settings: %s", settings2str(supported_settings));
 
-       print("\tcurrent settings: %s",
-                       settings2str(get_le32(&rp->current_settings)));
+       current_settings = le32_to_cpu(rp->current_settings);
+       print("\tcurrent settings: %s", settings2str(current_settings));
 
        print("\tname %s", rp->name);
        print("\tshort name %s", rp->short_name);
 
-       if (pending_index > 0)
+       if (supported_settings & MGMT_SETTING_CONFIGURATION) {
+               if (!mgmt_send(mgmt, MGMT_OP_READ_CONFIG_INFO,
+                                       index, 0, NULL, config_options_rsp,
+                                       UINT_TO_PTR(index), NULL)) {
+                       error("Unable to send read_config cmd");
+                       goto done;
+               }
                return;
+       }
 
 done:
+       pending_index--;
+
+       if (pending_index > 0)
+               return;
+
        noninteractive_quit(EXIT_SUCCESS);
 }
 
@@ -1210,7 +1397,7 @@ static void index_rsp(uint8_t status, uint16_t len, const void *param,
                return noninteractive_quit(EXIT_FAILURE);
        }
 
-       count = get_le16(&rp->num_controllers);
+       count = le16_to_cpu(rp->num_controllers);
 
        if (len < sizeof(*rp) + count * sizeof(uint16_t)) {
                error("Index count (%u) doesn't match reply length (%u)",
@@ -1221,15 +1408,10 @@ static void index_rsp(uint8_t status, uint16_t len, const void *param,
        print("Index list with %u item%s", count, count != 1 ? "s" : "");
 
        for (i = 0; i < count; i++) {
-               uint16_t index;
-               void *data;
-
-               index = get_le16(&rp->index[i]);
+               uint16_t index = le16_to_cpu(rp->index[i]);
 
-               data = UINT_TO_PTR(index);
-
-               if (mgmt_send(mgmt, MGMT_OP_READ_INFO, index, 0, NULL,
-                                               info_rsp, data, NULL) == 0) {
+               if (!mgmt_send(mgmt, MGMT_OP_READ_INFO, index, 0, NULL,
+                                       info_rsp, UINT_TO_PTR(index), NULL)) {
                        error("Unable to send read_info cmd");
                        return noninteractive_quit(EXIT_FAILURE);
                }
@@ -1243,12 +1425,10 @@ static void index_rsp(uint8_t status, uint16_t len, const void *param,
 
 static void cmd_info(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
 {
-       void *data;
-
        if (index == MGMT_INDEX_NONE) {
-               if (mgmt_send(mgmt, MGMT_OP_READ_INDEX_LIST,
+               if (!mgmt_send(mgmt, MGMT_OP_READ_INDEX_LIST,
                                        MGMT_INDEX_NONE, 0, NULL,
-                                       index_rsp, mgmt, NULL) == 0) {
+                                       index_rsp, mgmt, NULL)) {
                        error("Unable to send index_list cmd");
                        return noninteractive_quit(EXIT_FAILURE);
                }
@@ -1256,15 +1436,93 @@ static void cmd_info(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
                return;
        }
 
-       data = UINT_TO_PTR(index);
-
-       if (mgmt_send(mgmt, MGMT_OP_READ_INFO, index, 0, NULL, info_rsp,
-                                                       data, NULL) == 0) {
+       if (!mgmt_send(mgmt, MGMT_OP_READ_INFO, index, 0, NULL, info_rsp,
+                                               UINT_TO_PTR(index), NULL)) {
                error("Unable to send read_info cmd");
                return noninteractive_quit(EXIT_FAILURE);
        }
 }
 
+static void ext_index_rsp(uint8_t status, uint16_t len, const void *param,
+                                                       void *user_data)
+{
+       const struct mgmt_rp_read_ext_index_list *rp = param;
+       uint16_t count, index_filter = PTR_TO_UINT(user_data);
+       unsigned int i;
+
+       if (status != 0) {
+               error("Reading ext index list failed with status 0x%02x (%s)",
+                                               status, mgmt_errstr(status));
+               return noninteractive_quit(EXIT_FAILURE);
+       }
+
+       if (len < sizeof(*rp)) {
+               error("Too small ext index list reply (%u bytes)", len);
+               return noninteractive_quit(EXIT_FAILURE);
+       }
+
+       count = get_le16(&rp->num_controllers);
+
+       if (len < sizeof(*rp) + count * (sizeof(uint16_t) + sizeof(uint8_t))) {
+               error("Index count (%u) doesn't match reply length (%u)",
+                                                               count, len);
+               return noninteractive_quit(EXIT_FAILURE);
+       }
+
+       print("Extended index list with %u item%s",
+                                       count, count != 1 ? "s" : "");
+
+       for (i = 0; i < count; i++) {
+               uint16_t index = le16_to_cpu(rp->entry[i].index);
+
+               if (index_filter != MGMT_INDEX_NONE && index_filter != index)
+                       continue;
+
+               switch (rp->entry[i].type) {
+               case 0x00:
+                       if (!mgmt_send(mgmt, MGMT_OP_READ_INFO,
+                                               index, 0, NULL, info_rsp,
+                                               UINT_TO_PTR(index), NULL)) {
+                               error("Unable to send read_info cmd");
+                               return noninteractive_quit(EXIT_FAILURE);
+                       }
+                       pending_index++;
+                       break;
+               case 0x01:
+                       if (!mgmt_send(mgmt, MGMT_OP_READ_CONFIG_INFO,
+                                               index, 0, NULL, config_info_rsp,
+                                               UINT_TO_PTR(index), NULL)) {
+                               error("Unable to send read_config cmd");
+                               return noninteractive_quit(EXIT_FAILURE);
+                       }
+                       pending_index++;
+                       break;
+               case 0x02:
+                       print("hci%u:\tAMP controller (%u)", index,
+                                                       rp->entry[i].bus);
+                       break;
+               default:
+                       print("hci%u:\tType %u controller (%u)", index,
+                                       rp->entry[i].type, rp->entry[i].bus);
+                       break;
+               }
+       }
+
+       if (!count)
+               noninteractive_quit(EXIT_SUCCESS);
+}
+
+static void cmd_extinfo(struct mgmt *mgmt, uint16_t index,
+                                               int argc, char **argv)
+{
+       if (!mgmt_send(mgmt, MGMT_OP_READ_EXT_INDEX_LIST,
+                               MGMT_INDEX_NONE, 0, NULL,
+                               ext_index_rsp, UINT_TO_PTR(index), NULL)) {
+               error("Unable to send ext_index_list cmd");
+               return noninteractive_quit(EXIT_FAILURE);
+       }
+}
+
 /* Wrapper to get the index and opcode to the response callback */
 struct command_data {
        uint16_t id;
@@ -1540,7 +1798,7 @@ static void class_rsp(uint16_t op, uint16_t id, uint8_t status, uint16_t len,
        }
 
        print("%s succeeded. Class 0x%02x%02x%02x", mgmt_opstr(op),
-               rp->class_of_dev[2], rp->class_of_dev[1], rp->class_of_dev[0]);
+               rp->dev_class[2], rp->dev_class[1], rp->dev_class[0]);
 
        noninteractive_quit(EXIT_SUCCESS);
 }
@@ -1621,9 +1879,11 @@ static void cmd_disconnect(struct mgmt *mgmt, uint16_t index, int argc,
                        break;
                case 'h':
                        disconnect_usage();
+                       optind = 0;
                        return noninteractive_quit(EXIT_SUCCESS);
                default:
                        disconnect_usage();
+                       optind = 0;
                        return noninteractive_quit(EXIT_FAILURE);
                }
        }
@@ -1739,7 +1999,7 @@ static void cmd_find_service(struct mgmt *mgmt, uint16_t index, int argc,
        uuid_t uuid;
        uint128_t uint128;
        uuid_t uuid128;
-       uint8_t type;
+       uint8_t type = SCAN_TYPE_DUAL;
        int8_t rssi;
        uint16_t count;
        int opt;
@@ -1747,10 +2007,6 @@ static void cmd_find_service(struct mgmt *mgmt, uint16_t index, int argc,
        if (index == MGMT_INDEX_NONE)
                index = 0;
 
-       type = 0;
-       type |= (1 << BDADDR_BREDR);
-       type |= (1 << BDADDR_LE_PUBLIC);
-       type |= (1 << BDADDR_LE_RANDOM);
        rssi = 127;
        count = 0;
 
@@ -1763,23 +2019,23 @@ static void cmd_find_service(struct mgmt *mgmt, uint16_t index, int argc,
                                        find_service_options, NULL)) != -1) {
                switch (opt) {
                case 'l':
-                       type &= ~(1 << BDADDR_BREDR);
-                       type |= (1 << BDADDR_LE_PUBLIC);
-                       type |= (1 << BDADDR_LE_RANDOM);
+                       type &= ~SCAN_TYPE_BREDR;
+                       type |= SCAN_TYPE_LE;
                        break;
                case 'b':
-                       type |= (1 << BDADDR_BREDR);
-                       type &= ~(1 << BDADDR_LE_PUBLIC);
-                       type &= ~(1 << BDADDR_LE_RANDOM);
+                       type |= SCAN_TYPE_BREDR;
+                       type &= ~SCAN_TYPE_LE;
                        break;
                case 'u':
                        if (count == MAX_UUIDS) {
                                print("Max %u UUIDs supported", MAX_UUIDS);
+                               optind = 0;
                                return noninteractive_quit(EXIT_FAILURE);
                        }
 
                        if (bt_string2uuid(&uuid, optarg) < 0) {
                                print("Invalid UUID: %s", optarg);
+                               optind = 0;
                                return noninteractive_quit(EXIT_FAILURE);
                        }
                        cp = (void *) buf;
@@ -1793,9 +2049,11 @@ static void cmd_find_service(struct mgmt *mgmt, uint16_t index, int argc,
                        break;
                case 'h':
                        find_service_usage();
+                       optind = 0;
                        return noninteractive_quit(EXIT_SUCCESS);
                default:
                        find_service_usage();
+                       optind = 0;
                        return noninteractive_quit(EXIT_FAILURE);
                }
        }
@@ -1850,35 +2108,30 @@ static struct option find_options[] = {
 static void cmd_find(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
 {
        struct mgmt_cp_start_discovery cp;
-       uint8_t type;
+       uint8_t type = SCAN_TYPE_DUAL;
        int opt;
 
        if (index == MGMT_INDEX_NONE)
                index = 0;
 
-       type = 0;
-       type |= (1 << BDADDR_BREDR);
-       type |= (1 << BDADDR_LE_PUBLIC);
-       type |= (1 << BDADDR_LE_RANDOM);
-
        while ((opt = getopt_long(argc, argv, "+lbh", find_options,
                                                                NULL)) != -1) {
                switch (opt) {
                case 'l':
-                       type &= ~(1 << BDADDR_BREDR);
-                       type |= (1 << BDADDR_LE_PUBLIC);
-                       type |= (1 << BDADDR_LE_RANDOM);
+                       type &= ~SCAN_TYPE_BREDR;
+                       type |= SCAN_TYPE_LE;
                        break;
                case 'b':
-                       type |= (1 << BDADDR_BREDR);
-                       type &= ~(1 << BDADDR_LE_PUBLIC);
-                       type &= ~(1 << BDADDR_LE_RANDOM);
+                       type |= SCAN_TYPE_BREDR;
+                       type &= ~SCAN_TYPE_LE;
                        break;
                case 'h':
                        find_usage();
+                       optind = 0;
                        return noninteractive_quit(EXIT_SUCCESS);
                default:
                        find_usage();
+                       optind = 0;
                        return noninteractive_quit(EXIT_FAILURE);
                }
        }
@@ -1897,6 +2150,78 @@ static void cmd_find(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
        }
 }
 
+static void stop_find_rsp(uint8_t status, uint16_t len, const void *param,
+                                                       void *user_data)
+{
+       if (status != 0) {
+               fprintf(stderr,
+                       "Stop Discovery failed: status 0x%02x (%s)\n",
+                                               status, mgmt_errstr(status));
+               mainloop_quit();
+               return;
+       }
+
+       printf("Discovery stopped\n");
+       discovery = false;
+
+       noninteractive_quit(EXIT_SUCCESS);
+}
+
+static void stop_find_usage(void)
+{
+       printf("Usage: btmgmt stop-find [-l|-b]>\n");
+}
+
+static struct option stop_find_options[] = {
+       { "help",       0, 0, 'h' },
+       { "le-only",    1, 0, 'l' },
+       { "bredr-only", 1, 0, 'b' },
+       { 0, 0, 0, 0 }
+};
+
+static void cmd_stop_find(struct mgmt *mgmt, uint16_t index, int argc,
+                         char **argv)
+{
+       struct mgmt_cp_stop_discovery cp;
+       uint8_t type = SCAN_TYPE_DUAL;
+       int opt;
+
+       if (index == MGMT_INDEX_NONE)
+               index = 0;
+
+       while ((opt = getopt_long(argc, argv, "+lbh", stop_find_options,
+                                                               NULL)) != -1) {
+               switch (opt) {
+               case 'l':
+                       type &= ~SCAN_TYPE_BREDR;
+                       type |= SCAN_TYPE_LE;
+                       break;
+               case 'b':
+                       type |= SCAN_TYPE_BREDR;
+                       type &= ~SCAN_TYPE_LE;
+                       break;
+               case 'h':
+               default:
+                       stop_find_usage();
+                       optind = 0;
+                       exit(EXIT_SUCCESS);
+               }
+       }
+
+       argc -= optind;
+       argv += optind;
+       optind = 0;
+
+       memset(&cp, 0, sizeof(cp));
+       cp.type = type;
+
+       if (mgmt_send(mgmt, MGMT_OP_STOP_DISCOVERY, index, sizeof(cp), &cp,
+                                            stop_find_rsp, NULL, NULL) == 0) {
+               fprintf(stderr, "Unable to send stop_discovery cmd\n");
+               exit(EXIT_FAILURE);
+       }
+}
+
 static void name_rsp(uint8_t status, uint16_t len, const void *param,
                                                        void *user_data)
 {
@@ -1995,9 +2320,11 @@ static void cmd_pair(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
                        break;
                case 'h':
                        pair_usage();
+                       optind = 0;
                        return noninteractive_quit(EXIT_SUCCESS);
                default:
                        pair_usage();
+                       optind = 0;
                        return noninteractive_quit(EXIT_FAILURE);
                }
        }
@@ -2084,9 +2411,11 @@ static void cmd_cancel_pair(struct mgmt *mgmt, uint16_t index, int argc,
                        break;
                case 'h':
                        cancel_pair_usage();
+                       optind = 0;
                        return noninteractive_quit(EXIT_SUCCESS);
                default:
                        cancel_pair_usage();
+                       optind = 0;
                        return noninteractive_quit(EXIT_FAILURE);
                }
        }
@@ -2168,9 +2497,11 @@ static void cmd_unpair(struct mgmt *mgmt, uint16_t index, int argc,
                        break;
                case 'h':
                        unpair_usage();
+                       optind = 0;
                        return noninteractive_quit(EXIT_SUCCESS);
                default:
                        unpair_usage();
+                       optind = 0;
                        return noninteractive_quit(EXIT_FAILURE);
                }
        }
@@ -2299,6 +2630,7 @@ static void cmd_irks(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
                case 'l':
                        if (count >= MAX_IRKS) {
                                error("Number of IRKs exceeded");
+                               optind = 0;
                                return noninteractive_quit(EXIT_FAILURE);
                        }
                        if (strlen(optarg) > 3 &&
@@ -2308,15 +2640,18 @@ static void cmd_irks(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
                                local_index = atoi(optarg);
                        if (!load_identity(local_index, &cp->irks[count])) {
                                error("Unable to load identity");
+                               optind = 0;
                                return noninteractive_quit(EXIT_FAILURE);
                        }
                        count++;
                        break;
                case 'h':
                        irks_usage();
+                       optind = 0;
                        return noninteractive_quit(EXIT_SUCCESS);
                default:
                        irks_usage();
+                       optind = 0;
                        return noninteractive_quit(EXIT_FAILURE);
                }
        }
@@ -2394,9 +2729,11 @@ static void cmd_block(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
                        break;
                case 'h':
                        block_usage();
+                       optind = 0;
                        return noninteractive_quit(EXIT_SUCCESS);
                default:
                        block_usage();
+                       optind = 0;
                        return noninteractive_quit(EXIT_FAILURE);
                }
        }
@@ -2444,9 +2781,11 @@ static void cmd_unblock(struct mgmt *mgmt, uint16_t index, int argc,
                        break;
                case 'h':
                        unblock_usage();
+                       optind = 0;
                        return noninteractive_quit(EXIT_SUCCESS);
                default:
                        unblock_usage();
+                       optind = 0;
                        return noninteractive_quit(EXIT_FAILURE);
                }
        }
@@ -2555,7 +2894,6 @@ static void local_oob_rsp(uint8_t status, uint16_t len, const void *param,
                                                        void *user_data)
 {
        const struct mgmt_rp_read_local_oob_data *rp = param;
-       const struct mgmt_rp_read_local_oob_ext_data *rp_ext = param;
        char str[33];
 
        if (status != 0) {
@@ -2569,19 +2907,19 @@ static void local_oob_rsp(uint8_t status, uint16_t len, const void *param,
                return noninteractive_quit(EXIT_FAILURE);
        }
 
-       bin2hex(rp->hash, 16, str, sizeof(str));
+       bin2hex(rp->hash192, 16, str, sizeof(str));
        print("Hash C from P-192: %s", str);
 
-       bin2hex(rp->randomizer, 16, str, sizeof(str));
+       bin2hex(rp->rand192, 16, str, sizeof(str));
        print("Randomizer R with P-192: %s", str);
 
-       if (len < sizeof(*rp_ext))
+       if (len < sizeof(*rp))
                return noninteractive_quit(EXIT_SUCCESS);
 
-       bin2hex(rp_ext->hash256, 16, str, sizeof(str));
+       bin2hex(rp->hash256, 16, str, sizeof(str));
        print("Hash C from P-256: %s", str);
 
-       bin2hex(rp_ext->randomizer256, 16, str, sizeof(str));
+       bin2hex(rp->rand256, 16, str, sizeof(str));
        print("Randomizer R with P-256: %s", str);
 
        noninteractive_quit(EXIT_SUCCESS);
@@ -3236,6 +3574,456 @@ static void cmd_clr_devices(struct mgmt *mgmt, uint16_t index,
        cmd_del_device(mgmt, index, 2, rm_argv);
 }
 
+static void local_oob_ext_rsp(uint8_t status, uint16_t len, const void *param,
+                                                       void *user_data)
+{
+       const struct mgmt_rp_read_local_oob_ext_data *rp = param;
+       uint16_t eir_len;
+
+       if (status != 0) {
+               error("Read Local OOB Ext Data failed with status 0x%02x (%s)",
+                                               status, mgmt_errstr(status));
+               return noninteractive_quit(EXIT_FAILURE);
+       }
+
+       if (len < sizeof(*rp)) {
+               error("Too small (%u bytes) read_local_oob_ext rsp", len);
+               return noninteractive_quit(EXIT_FAILURE);
+       }
+
+       eir_len = le16_to_cpu(rp->eir_len);
+       if (len != sizeof(*rp) + eir_len) {
+               error("local_oob_ext: expected %zu bytes, got %u bytes",
+                                               sizeof(*rp) + eir_len, len);
+               return noninteractive_quit(EXIT_FAILURE);
+       }
+
+       print_eir(rp->eir, eir_len);
+
+       noninteractive_quit(EXIT_SUCCESS);
+}
+
+static void cmd_bredr_oob(struct mgmt *mgmt, uint16_t index,
+                                               int argc, char **argv)
+{
+       struct mgmt_cp_read_local_oob_ext_data cp;
+
+       if (index == MGMT_INDEX_NONE)
+               index = 0;
+
+       cp.type = SCAN_TYPE_BREDR;
+
+       if (!mgmt_send(mgmt, MGMT_OP_READ_LOCAL_OOB_EXT_DATA,
+                                       index, sizeof(cp), &cp,
+                                       local_oob_ext_rsp, NULL, NULL)) {
+               error("Unable to send read_local_oob_ext cmd");
+               return noninteractive_quit(EXIT_FAILURE);
+       }
+}
+
+static void cmd_le_oob(struct mgmt *mgmt, uint16_t index,
+                                               int argc, char **argv)
+{
+       struct mgmt_cp_read_local_oob_ext_data cp;
+
+       if (index == MGMT_INDEX_NONE)
+               index = 0;
+
+       cp.type = SCAN_TYPE_LE;
+
+       if (!mgmt_send(mgmt, MGMT_OP_READ_LOCAL_OOB_EXT_DATA,
+                                       index, sizeof(cp), &cp,
+                                       local_oob_ext_rsp, NULL, NULL)) {
+               error("Unable to send read_local_oob_ext cmd");
+               return noninteractive_quit(EXIT_FAILURE);
+       }
+}
+
+static const char *adv_flags_str[] = {
+                               "connectable",
+                               "general-discoverable",
+                               "limited-discoverable",
+                               "managed-flags",
+                               "tx-power",
+                               "scan-rsp-appearance",
+                               "scan-rsp-local-name",
+};
+
+static const char *adv_flags2str(uint32_t flags)
+{
+       static char str[256];
+       unsigned i;
+       int off;
+
+       off = 0;
+       str[0] = '\0';
+
+       for (i = 0; i < NELEM(adv_flags_str); i++) {
+               if ((flags & (1 << i)) != 0)
+                       off += snprintf(str + off, sizeof(str) - off, "%s ",
+                                                       adv_flags_str[i]);
+       }
+
+       return str;
+}
+
+static void adv_features_rsp(uint8_t status, uint16_t len, const void *param,
+                                                       void *user_data)
+{
+       const struct mgmt_rp_read_adv_features *rp = param;
+       uint32_t supported_flags;
+
+       if (status != 0) {
+               error("Reading adv features failed with status 0x%02x (%s)",
+                                               status, mgmt_errstr(status));
+               return noninteractive_quit(EXIT_FAILURE);
+       }
+
+       if (len < sizeof(*rp)) {
+               error("Too small adv features reply (%u bytes)", len);
+               return noninteractive_quit(EXIT_FAILURE);
+       }
+
+       if (len < sizeof(*rp) + rp->num_instances * sizeof(uint8_t)) {
+               error("Instances count (%u) doesn't match reply length (%u)",
+                                                       rp->num_instances, len);
+               return noninteractive_quit(EXIT_FAILURE);
+       }
+
+       supported_flags = le32_to_cpu(rp->supported_flags);
+       print("Supported flags: %s", adv_flags2str(supported_flags));
+       print("Max advertising data len: %u", rp->max_adv_data_len);
+       print("Max scan response data len: %u", rp->max_scan_rsp_len);
+       print("Max instances: %u", rp->max_instances);
+
+       print("Instances list with %u item%s", rp->num_instances,
+                                       rp->num_instances != 1 ? "s" : "");
+
+       return noninteractive_quit(EXIT_SUCCESS);
+}
+
+static void cmd_advinfo(struct mgmt *mgmt, uint16_t index,
+                                               int argc, char **argv)
+{
+       if (index == MGMT_INDEX_NONE)
+               index = 0;
+
+       if (!mgmt_send(mgmt, MGMT_OP_READ_ADV_FEATURES, index, 0, NULL,
+                                       adv_features_rsp, NULL, NULL)) {
+               error("Unable to send advertising features command");
+               return noninteractive_quit(EXIT_FAILURE);
+       }
+}
+
+static void add_adv_rsp(uint8_t status, uint16_t len, const void *param,
+                                                               void *user_data)
+{
+       const struct mgmt_rp_add_advertising *rp = param;
+
+       if (status != 0) {
+               error("Add Advertising failed with status 0x%02x (%s)",
+                                               status, mgmt_errstr(status));
+               return noninteractive_quit(EXIT_FAILURE);
+       }
+
+       if (len != sizeof(*rp)) {
+               error("Invalid Add Advertising response length (%u)", len);
+               return noninteractive_quit(EXIT_FAILURE);
+       }
+
+       print("Instance added: %u", rp->instance);
+
+       return noninteractive_quit(EXIT_SUCCESS);
+}
+
+static void add_adv_usage(void)
+{
+       print("Usage: add-adv [options] <instance_id>\nOptions:\n"
+               "\t -u, --uuid <uuid>        Service UUID\n"
+               "\t -d, --adv-data <data>    Advertising Data bytes\n"
+               "\t -s, --scan-rsp <data>    Scan Response Data bytes\n"
+               "\t -t, --timeout <timeout>  Timeout in seconds\n"
+               "\t -c, --connectable        \"connectable\" flag\n"
+               "\t -g, --general-discov     \"general-discoverable\" flag\n"
+               "\t -l, --limited-discov     \"limited-discoverable\" flag\n"
+               "\t -m, --managed-flags      \"managed-flags\" flag\n"
+               "\t -p, --tx-power           \"tx-power\" flag\n"
+               "e.g.:\n"
+               "\tadd-adv -u 180d -u 180f -d 080954657374204C45 1");
+}
+
+static struct option add_adv_options[] = {
+       { "help",               0, 0, 'h' },
+       { "uuid",               1, 0, 'u' },
+       { "adv-data",           1, 0, 'd' },
+       { "scan-rsp",           1, 0, 's' },
+       { "timeout",            1, 0, 't' },
+       { "connectable",        0, 0, 'c' },
+       { "general-discov",     0, 0, 'g' },
+       { "limited-discov",     0, 0, 'l' },
+       { "managed-flags",      0, 0, 'm' },
+       { "tx-power",           0, 0, 'p' },
+       { 0, 0, 0, 0}
+};
+
+static bool parse_bytes(char *optarg, uint8_t **bytes, size_t *len)
+{
+       unsigned i;
+
+       if (!optarg) {
+               add_adv_usage();
+               return false;
+       }
+
+       *len = strlen(optarg);
+
+       if (*len % 2) {
+               error("Malformed data");
+               return false;
+       }
+
+       *len /= 2;
+       if (*len > UINT8_MAX) {
+               error("Data too long");
+               return false;
+       }
+
+       *bytes = malloc(*len);
+       if (!*bytes) {
+               error("Failed to allocate memory");
+               return false;
+       }
+
+       for (i = 0; i < *len; i++) {
+               if (sscanf(optarg + (i * 2), "%2hhx", *bytes + i) != 1) {
+                       error("Invalid data");
+                       free(*bytes);
+                       *bytes = NULL;
+                       return false;
+               }
+       }
+
+       return true;
+}
+
+#define MAX_AD_UUID_BYTES 32
+
+static void cmd_add_adv(struct mgmt *mgmt, uint16_t index,
+                                                       int argc, char **argv)
+{
+       struct mgmt_cp_add_advertising *cp = NULL;
+       int opt;
+       uint8_t *adv_data = NULL, *scan_rsp = NULL;
+       size_t adv_len = 0, scan_rsp_len = 0;
+       size_t cp_len;
+       uint8_t uuids[MAX_AD_UUID_BYTES];
+       size_t uuid_bytes = 0;
+       uint8_t uuid_type = 0;
+       uint16_t timeout = 0;
+       uint8_t instance;
+       uuid_t uuid;
+       bool success = false;
+       bool quit = true;
+       uint32_t flags = 0;
+
+       while ((opt = getopt_long(argc, argv, "+u:d:s:t:cglmph",
+                                               add_adv_options, NULL)) != -1) {
+               switch (opt) {
+               case 'u':
+                       if (bt_string2uuid(&uuid, optarg) < 0) {
+                               print("Invalid UUID: %s", optarg);
+                               goto done;
+                       }
+
+                       if (uuid_type && uuid_type != uuid.type) {
+                               print("UUID types must be consistent");
+                               goto done;
+                       }
+
+                       if (uuid.type == SDP_UUID16) {
+                               if (uuid_bytes + 2 >= MAX_AD_UUID_BYTES) {
+                                       print("Too many UUIDs");
+                                       goto done;
+                               }
+
+                               put_le16(uuid.value.uuid16, uuids + uuid_bytes);
+                               uuid_bytes += 2;
+                       } else if (uuid.type == SDP_UUID128) {
+                               if (uuid_bytes + 16 >= MAX_AD_UUID_BYTES) {
+                                       print("Too many UUIDs");
+                                       goto done;
+                               }
+
+                               bswap_128(uuid.value.uuid128.data,
+                                                       uuids + uuid_bytes);
+                               uuid_bytes += 16;
+                       } else {
+                               printf("Unsupported UUID type");
+                               goto done;
+                       }
+
+                       if (!uuid_type)
+                               uuid_type = uuid.type;
+
+                       break;
+               case 'd':
+                       if (adv_len) {
+                               print("Only one adv-data option allowed");
+                               goto done;
+                       }
+
+                       if (!parse_bytes(optarg, &adv_data, &adv_len))
+                               goto done;
+                       break;
+               case 's':
+                       if (scan_rsp_len) {
+                               print("Only one scan-rsp option allowed");
+                               goto done;
+                       }
+
+                       if (!parse_bytes(optarg, &scan_rsp, &scan_rsp_len))
+                               goto done;
+                       break;
+               case 't':
+                       timeout = strtol(optarg, NULL, 0);
+                       break;
+               case 'c':
+                       flags |= MGMT_ADV_FLAG_CONNECTABLE;
+                       break;
+               case 'g':
+                       flags |= MGMT_ADV_FLAG_DISCOV;
+                       break;
+               case 'l':
+                       flags |= MGMT_ADV_FLAG_LIMITED_DISCOV;
+                       break;
+               case 'm':
+                       flags |= MGMT_ADV_FLAG_MANAGED_FLAGS;
+                       break;
+               case 'p':
+                       flags |= MGMT_ADV_FLAG_TX_POWER;
+                       break;
+               case 'h':
+                       success = true;
+               default:
+                       add_adv_usage();
+                       goto done;
+               }
+       }
+
+       argc -= optind;
+       argv += optind;
+       optind = 0;
+
+       if (argc != 1) {
+               add_adv_usage();
+               goto done;
+       }
+
+       if (uuid_bytes)
+               uuid_bytes += 2;
+
+       instance = strtol(argv[0], NULL, 0);
+
+       if (index == MGMT_INDEX_NONE)
+               index = 0;
+
+       cp_len = sizeof(*cp) + uuid_bytes + adv_len + scan_rsp_len;
+       cp = malloc0(cp_len);
+       if (!cp)
+               goto done;
+
+       cp->instance = instance;
+       put_le32(flags, &cp->flags);
+       put_le16(timeout, &cp->timeout);
+       cp->adv_data_len = adv_len + uuid_bytes;
+       cp->scan_rsp_len = scan_rsp_len;
+
+       if (uuid_bytes) {
+               cp->data[0] = uuid_bytes - 1;
+               cp->data[1] = uuid_type == SDP_UUID16 ? 0x03 : 0x07;
+               memcpy(cp->data + 2, uuids, uuid_bytes - 2);
+       }
+
+       memcpy(cp->data + uuid_bytes, adv_data, adv_len);
+       memcpy(cp->data + uuid_bytes + adv_len, scan_rsp, scan_rsp_len);
+
+       if (!mgmt_send(mgmt, MGMT_OP_ADD_ADVERTISING, index, cp_len, cp,
+                                               add_adv_rsp, NULL, NULL)) {
+               error("Unable to send \"Add Advertising\" command");
+               goto done;
+       }
+
+       quit = false;
+
+done:
+       free(adv_data);
+       free(scan_rsp);
+       free(cp);
+
+       if (quit)
+               noninteractive_quit(success ? EXIT_SUCCESS : EXIT_FAILURE);
+}
+
+static void rm_adv_rsp(uint8_t status, uint16_t len, const void *param,
+                                                               void *user_data)
+{
+       const struct mgmt_rp_remove_advertising *rp = param;
+
+       if (status != 0) {
+               error("Remove Advertising failed with status 0x%02x (%s)",
+                                               status, mgmt_errstr(status));
+               return noninteractive_quit(EXIT_FAILURE);
+       }
+
+       if (len != sizeof(*rp)) {
+               error("Invalid Remove Advertising response length (%u)", len);
+               return noninteractive_quit(EXIT_FAILURE);
+       }
+
+       print("Instance removed: %u", rp->instance);
+
+       return noninteractive_quit(EXIT_SUCCESS);
+}
+
+static void rm_adv_usage(void)
+{
+       print("Usage: rm-adv <instance_id>");
+}
+
+static void cmd_rm_adv(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
+{
+       struct mgmt_cp_remove_advertising cp;
+       uint8_t instance;
+
+       if (argc != 2) {
+               rm_adv_usage();
+               return noninteractive_quit(EXIT_FAILURE);
+       }
+
+       instance = strtol(argv[1], NULL, 0);
+
+       if (index == MGMT_INDEX_NONE)
+               index = 0;
+
+       memset(&cp, 0, sizeof(cp));
+
+       cp.instance = instance;
+
+       if (!mgmt_send(mgmt, MGMT_OP_REMOVE_ADVERTISING, index, sizeof(cp), &cp,
+                                               rm_adv_rsp, NULL, NULL)) {
+               error("Unable to send \"Remove Advertising\" command");
+               return noninteractive_quit(EXIT_FAILURE);
+       }
+}
+
+static void cmd_clr_adv(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
+{
+       char *all_instances = "0";
+       char *rm_argv[] = { "rm-adv", all_instances, NULL };
+
+       cmd_rm_adv(mgmt, index, 2, rm_argv);
+}
+
 struct cmd_info {
        char *cmd;
        void (*func)(struct mgmt *mgmt, uint16_t index, int argc, char **argv);
@@ -3249,6 +4037,7 @@ static struct cmd_info all_cmd[] = {
        { "commands",   cmd_commands,   "List supported commands"       },
        { "config",     cmd_config,     "Show configuration info"       },
        { "info",       cmd_info,       "Show controller info"          },
+       { "extinfo",    cmd_extinfo,    "Show extended controller info" },
        { "power",      cmd_power,      "Toggle powered state"          },
        { "discov",     cmd_discov,     "Toggle discoverable state"     },
        { "connectable",cmd_connectable,"Toggle connectable state"      },
@@ -3268,6 +4057,7 @@ static struct cmd_info all_cmd[] = {
        { "con",        cmd_con,        "List connections"              },
        { "find",       cmd_find,       "Discover nearby devices"       },
        { "find-service", cmd_find_service, "Discover nearby service"   },
+       { "stop-find",  cmd_stop_find,  "Stop discovery"                },
        { "name",       cmd_name,       "Set local name"                },
        { "pair",       cmd_pair,       "Pair with a remote device"     },
        { "cancelpair", cmd_cancel_pair,"Cancel pairing"                },
@@ -3294,6 +4084,12 @@ static struct cmd_info all_cmd[] = {
        { "add-device", cmd_add_device, "Add Device"                    },
        { "del-device", cmd_del_device, "Remove Device"                 },
        { "clr-devices",cmd_clr_devices,"Clear Devices"                 },
+       { "bredr-oob",  cmd_bredr_oob,  "Local OOB data (BR/EDR)"       },
+       { "le-oob",     cmd_le_oob,     "Local OOB data (LE)"           },
+       { "advinfo",    cmd_advinfo,    "Show advertising features"     },
+       { "add-adv",    cmd_add_adv,    "Add advertising instance"      },
+       { "rm-adv",     cmd_rm_adv,     "Remove advertising instance"   },
+       { "clr-adv",    cmd_clr_adv,    "Clear advertising instances"   },
 };
 
 static void cmd_quit(struct mgmt *mgmt, uint16_t index,
@@ -3324,6 +4120,8 @@ static void register_mgmt_callbacks(struct mgmt *mgmt, uint16_t index)
                                                                NULL, NULL);
        mgmt_register(mgmt, MGMT_EV_AUTH_FAILED, index, auth_failed,
                                                                NULL, NULL);
+       mgmt_register(mgmt, MGMT_EV_CLASS_OF_DEV_CHANGED, index,
+                                       class_of_dev_changed, NULL, NULL);
        mgmt_register(mgmt, MGMT_EV_LOCAL_NAME_CHANGED, index,
                                        local_name_changed, NULL, NULL);
        mgmt_register(mgmt, MGMT_EV_DEVICE_FOUND, index, device_found,
@@ -3342,7 +4140,16 @@ static void register_mgmt_callbacks(struct mgmt *mgmt, uint16_t index)
                                        unconf_index_removed, NULL, NULL);
        mgmt_register(mgmt, MGMT_EV_NEW_CONFIG_OPTIONS, index,
                                        new_config_options, NULL, NULL);
-
+       mgmt_register(mgmt, MGMT_EV_EXT_INDEX_ADDED, index,
+                                       ext_index_added, NULL, NULL);
+       mgmt_register(mgmt, MGMT_EV_EXT_INDEX_REMOVED, index,
+                                       ext_index_removed, NULL, NULL);
+       mgmt_register(mgmt, MGMT_EV_LOCAL_OOB_DATA_UPDATED, index,
+                                       local_oob_data_updated, NULL, NULL);
+       mgmt_register(mgmt, MGMT_EV_ADVERTISING_ADDED, index,
+                                               advertising_added, NULL, NULL);
+       mgmt_register(mgmt, MGMT_EV_ADVERTISING_REMOVED, index,
+                                       advertising_removed, NULL, NULL);
 }
 
 static void cmd_select(struct mgmt *mgmt, uint16_t index,
index 3eb8082..278e18c 100644 (file)
@@ -34,6 +34,8 @@
 #include <stdint.h>
 #include <stdbool.h>
 #include <string.h>
+#include <time.h>
+#include <sys/time.h>
 #include <getopt.h>
 #include <endian.h>
 #include <arpa/inet.h>
@@ -272,6 +274,86 @@ close_input:
                close(input_fd[i]);
 }
 
+#define BT_SNOOP_TYPE_HCI_PREFIX "btsnoop_type_hci"
+
+static void command_split(const char *input)
+{
+       unsigned char buf[BTSNOOP_MAX_PACKET_SIZE];
+       uint16_t pktlen,opcode;
+       uint32_t type;
+       struct timeval tv;
+       uint16_t index, max_index = 0;
+       char write_file_name[255];
+       struct btsnoop *btsnoop_read_file = NULL;
+       struct btsnoop *btsnoop_write_file[16];
+       time_t t;
+       struct tm tm;
+       unsigned long num_packets = 0;
+
+       btsnoop_read_file = btsnoop_open(input, BTSNOOP_FLAG_PKLG_SUPPORT);
+       if (!btsnoop_read_file)
+               return;
+
+       type = btsnoop_get_type(btsnoop_read_file);
+       if (type != BTSNOOP_TYPE_MONITOR) {
+               fprintf(stderr, "unsupported link data type %u\n", type);
+               btsnoop_unref(btsnoop_read_file);
+               return;
+       }
+
+next_packet:
+       if (!btsnoop_read_hci(btsnoop_read_file, &tv, &index, &opcode, buf,
+                                                               &pktlen))
+               goto close_files;
+
+       if (opcode == 0xffff)
+               goto next_packet;
+
+       switch (opcode) {
+       case BTSNOOP_OPCODE_NEW_INDEX:
+               t = tv.tv_sec;
+               localtime_r(&t, &tm);
+
+               if (max_index < index)
+                       max_index = index;
+
+               sprintf(write_file_name, "%s%d_%02d:%02d:%02d.%06lu.log",
+                       BT_SNOOP_TYPE_HCI_PREFIX, index, tm.tm_hour, tm.tm_min,
+                       tm.tm_sec, tv.tv_usec);
+
+               printf("New Index %d would be saved in %s\n", index,
+                                                       write_file_name);
+
+               btsnoop_write_file[index] = btsnoop_create(write_file_name,
+                                               BTSNOOP_TYPE_HCI, -1, -1);
+               if (!btsnoop_write_file[index])
+                       goto close_files;
+
+               break;
+       case BTSNOOP_OPCODE_DEL_INDEX:
+               printf("Del Index %d\n", index);
+
+               btsnoop_unref(btsnoop_write_file[index]);
+               btsnoop_write_file[index] = NULL;
+               break;
+       default:
+               btsnoop_write_hci(btsnoop_write_file[index], &tv, index,
+                                                       opcode, buf, pktlen);
+       }
+       num_packets++;
+
+       goto next_packet;
+
+close_files:
+       for (index = 0; index < max_index; index++)
+               btsnoop_unref(btsnoop_write_file[index]);
+
+       btsnoop_unref(btsnoop_read_file);
+
+       printf("BT Snoop data link transfer is completed for %lu packets\n",
+                                                               num_packets);
+}
+
 static void command_extract_eir(const char *input)
 {
        struct btsnoop_pkt pkt;
@@ -518,6 +600,7 @@ static void usage(void)
        printf("commands:\n"
                "\t-m, --merge <output>   Merge multiple btsnoop files\n"
                "\t-e, --extract <input>  Extract data from btsnoop file\n"
+               "\t-s, --split <input>    Split btmon file into legacy btsnoop file(s)\n"
                "\t-h, --help             Show help options\n");
 }
 
@@ -525,12 +608,13 @@ static const struct option main_options[] = {
        { "merge",   required_argument, NULL, 'm' },
        { "extract", required_argument, NULL, 'e' },
        { "type",    required_argument, NULL, 't' },
+       { "split",   required_argument, NULL, 's' },
        { "version", no_argument,       NULL, 'v' },
        { "help",    no_argument,       NULL, 'h' },
        { }
 };
 
-enum { INVALID, MERGE, EXTRACT };
+enum { INVALID, MERGE, EXTRACT, SPLIT };
 
 int main(int argc, char *argv[])
 {
@@ -542,7 +626,7 @@ int main(int argc, char *argv[])
        for (;;) {
                int opt;
 
-               opt = getopt_long(argc, argv, "m:e:t:vh", main_options, NULL);
+               opt = getopt_long(argc, argv, "m:e:s:t:vh", main_options, NULL);
                if (opt < 0)
                        break;
 
@@ -555,6 +639,9 @@ int main(int argc, char *argv[])
                        command = EXTRACT;
                        input_path = optarg;
                        break;
+               case 's':
+                       command = SPLIT;
+                       input_path = optarg;
                case 't':
                        type = optarg;
                        break;
@@ -600,6 +687,15 @@ int main(int argc, char *argv[])
                        fprintf(stderr, "extract type not supported\n");
                break;
 
+       case SPLIT:
+               if (argc - optind > 0) {
+                       fprintf(stderr, "extra arguments not allowed\n");
+                       return EXIT_FAILURE;
+               }
+
+               command_split(input_path);
+               break;
+
        default:
                usage();
                return EXIT_FAILURE;
index 150c5d0..b3bb512 100644 (file)
@@ -1099,9 +1099,21 @@ static int bcm2035(int fd, struct uart_t *u, struct termios *ti)
        return 0;
 }
 
+#ifdef __TIZEN_PATCH__ /*SPRD add Start*/
+static int init_sprd_config(int fd, struct uart_t *u, struct termios *ti)
+{
+
+       return sprd_config_init(fd, u->bdaddr, ti);
+}
+#endif
+
 struct uart_t uart[] = {
        { "any",        0x0000, 0x0000, HCI_UART_H4,   115200, 115200,
                                FLOW_CTL, DISABLE_PM, NULL, NULL     },
+#ifdef __TIZEN_PATCH__ /*SPRD*/
+       { "sprd",        0x0000, 0x0000, HCI_UART_H4,   3000000, 3000000,
+                               FLOW_CTL, DISABLE_PM, NULL, init_sprd_config },
+#endif
        { "ericsson",   0x0000, 0x0000, HCI_UART_H4,   57600,  115200,
                                FLOW_CTL, DISABLE_PM, NULL, ericsson },
 
@@ -1409,8 +1421,8 @@ static void usage(void)
 /* This commented code was present before bluez 5.25 upgrade
  * printf("\thciattach [-n] [-p] [-b] [-g device_param] [-r] [-f] [-t timeout] [-s initial_speed] <tty> <type | id> [speed] [flow|noflow] [bdaddr]\n");*/
        printf("\thciattach [-n] [-p] [-b] [-g device_param] [-r] [-f]"
-                       " [-t timeout] [-s initial_speed]"\r
-                       " <tty> <type | id> [speed] [flow|noflow]"\r
+                       " [-t timeout] [-s initial_speed]"
+                       " <tty> <type | id> [speed] [flow|noflow]"
                        " [sleep|nosleep] [bdaddr]\n");
 #else
        printf("\thciattach [-n] [-p] [-b] [-r] [-t timeout] [-s initial_speed]"
index 2aaf075..0b7e02e 100644 (file)
@@ -55,6 +55,9 @@ int stlc2500_init(int fd, bdaddr_t *bdaddr);
 int bgb2xx_init(int dd, bdaddr_t *bdaddr);
 int ath3k_init(int fd, int speed, int init_speed, char *bdaddr,
                                                struct termios *ti);
+#ifdef __TIZEN_PATCH__
+int sprd_config_init(int fd, char *bdaddr, struct termios *ti);
+#endif
 int ath3k_post(int fd, int pm);
 int qualcomm_init(int fd, int speed, struct termios *ti, const char *bdaddr);
 int intel_init(int fd, int init_speed, int *speed, struct termios *ti);
diff --git a/tools/hciattach_sprd.c b/tools/hciattach_sprd.c
new file mode 100644 (file)
index 0000000..410a2cf
--- /dev/null
@@ -0,0 +1,579 @@
+#include <linux/kernel.h>
+#include <assert.h>
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <syslog.h>
+#include <termios.h>
+#include <time.h>
+#include <sys/time.h>
+#include <sys/poll.h>
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+
+#include <sys/types.h>
+#include <dirent.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/hci_lib.h>
+
+#include "hciattach.h"
+#include <sys/stat.h>
+
+#include "hciattach_sprd.h"
+
+//#include <android/log.h>
+//#define DBG
+#ifdef DBG
+#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, "pskey_bt", __VA_ARGS__)
+#else
+#define LOGD(fmt, arg...)  fprintf(stderr, "%s:%d()" fmt "\n", __FILE__,__LINE__, ## arg)
+#endif
+typedef unsigned char   UINT8;
+
+#define UINT32_TO_STREAM(p, u32) {*(p)++ = (UINT8)(u32); *(p)++ = (UINT8)((u32) >> 8); *(p)++ = (UINT8)((u32) >> 16); *(p)++ = (UINT8)((u32) >> 24);}
+#define UINT24_TO_STREAM(p, u24) {*(p)++ = (UINT8)(u24); *(p)++ = (UINT8)((u24) >> 8); *(p)++ = (UINT8)((u24) >> 16);}
+#define UINT16_TO_STREAM(p, u16) {*(p)++ = (UINT8)(u16); *(p)++ = (UINT8)((u16) >> 8);}
+#define UINT8_TO_STREAM(p, u8)   {*(p)++ = (UINT8)(u8);}
+#define INT8_TO_STREAM(p, u8)    {*(p)++ = (INT8)(u8);}
+
+#define PSKEY_PRELOAD_SIZE    0x04
+#define PSKEY_PREAMBLE_SIZE    0xA2
+
+       // for bt mac addr
+#define BT_MAC_FILE_PATH       "/csa/bluetooth/"
+#define DATMISC_MAC_ADDR_PATH  BT_MAC_FILE_PATH".bd_addr"
+#define MAC_ADDR_BUF_LEN    (strlen("FF:FF:FF:FF:FF:FF"))
+#define MAC_ADDR_FILE_LEN    25
+#define MAC_ADDR_LEN    6
+
+#define BD_ADDR_LEN    14
+#define BD_PREFIX      "0002\n"
+
+#if 0
+#ifndef VENDOR_BTWRITE_PROC_NODE
+#define VENDOR_BTWRITE_PROC_NODE "/proc/bluetooth/sleep/btwrite"
+#endif
+#endif
+
+#define MAX_BT_TMP_PSKEY_FILE_LEN 2048
+
+typedef unsigned int   UWORD32;
+typedef unsigned short UWORD16;
+typedef unsigned char  UWORD8;
+
+#define down_bt_is_space(c)    (((c) == '\n') || ((c) == ',') || ((c) == '\r') || ((c) == ' ') || ((c) == '{') || ((c) == '}'))
+#define down_bt_is_comma(c)    (((c) == ','))
+#define down_bt_is_endc(c)     (((c) == '}')) // indicate end of data
+
+/* Macros to swap byte order */
+#define SWAP_BYTE_ORDER_WORD(val) ((((val) & 0x000000FF) << 24) + \
+                                   (((val) & 0x0000FF00) << 8)  + \
+                                   (((val) & 0x00FF0000) >> 8)   + \
+                                   (((val) & 0xFF000000) >> 24))
+#define INLINE static __inline
+
+#ifndef LITTLE_ENDIAN
+#define LITTLE_ENDIAN
+#endif
+
+
+// pskey file structure default value
+static BT_PSKEY_CONFIG_T bt_para_setting={
+       .pskey_cmd = 0x001C0101,
+
+       .g_dbg_source_sink_syn_test_data = 0,
+       .g_sys_sleep_in_standby_supported = 0,
+       .g_sys_sleep_master_supported = 0,
+       .g_sys_sleep_slave_supported = 0,
+
+       .default_ahb_clk = 26000000,
+       .device_class = 0x001F00,
+       .win_ext = 30,
+
+       .g_aGainValue = {0x0000F600, 0x0000D000, 0x0000AA00, 0x00008400, 0x00004400, 0x00000A00},
+       .g_aPowerValue = {0x0FC80000, 0x0FF80000, 0x0FDA0000, 0x0FCC0000, 0x0FFC0000},
+
+       .feature_set = {0xFF, 0xFF, 0x8D, 0xFE, 0x9B, 0x7F, 0x79, 0x83, 0xFF, 0xA7, 0xFF, 0x7F, 0x00, 0xE0, 0xF7, 0x3E},
+       .device_addr = {0x6A, 0x6B, 0x8C, 0x8A, 0x8B, 0x8C},
+
+       .g_sys_sco_transmit_mode = 0, //true tramsmit by uart, otherwise by share memory
+       .g_sys_uart0_communication_supported = 1, //true use uart0, otherwise use uart1 for debug
+       .edr_tx_edr_delay = 5,
+       .edr_rx_edr_delay = 14,
+
+       .g_wbs_nv_117 = 0x0031,
+
+       .is_wdg_supported = 0,
+
+       .share_memo_rx_base_addr = 0,
+       //.share_memo_tx_base_addr = 0,
+       .g_wbs_nv_118 = 0x0066,
+       .g_nbv_nv_117 = 0x1063,
+
+       .share_memo_tx_packet_num_addr = 0,
+       .share_memo_tx_data_base_addr = 0,
+
+       .g_PrintLevel = 0xFFFFFFFF,
+
+       .share_memo_tx_block_length = 0,
+       .share_memo_rx_block_length = 0,
+       .share_memo_tx_water_mark = 0,
+       //.share_memo_tx_timeout_value = 0,
+       .g_nbv_nv_118 = 0x0E45,
+
+       .uart_rx_watermark = 48,
+       .uart_flow_control_thld = 63,
+       .comp_id = 0,
+       .pcm_clk_divd = 0x26,
+
+
+       .reserved = {0}
+};
+
+extern int getPskeyFromFile(void *pData);
+extern int bt_getPskeyFromFile(void *pData);
+
+static int create_mac_folder(void)
+{
+       DIR *dp;
+       int err;
+
+       dp = opendir(BT_MAC_FILE_PATH);
+       if (dp == NULL) {
+               if (mkdir(BT_MAC_FILE_PATH, 0755) < 0) {
+                       err = -errno;
+                       LOGD("%s:  mkdir: %s(%d)",__FUNCTION__, strerror(-err), -err);
+               }
+               return -1;
+       }
+
+       closedir(dp);
+       return 0;
+}
+
+static void mac_rand(char *btmac)
+{
+       int ran;
+       int i;
+       unsigned int seed;
+       struct timeval tv;
+
+       memcpy(btmac, BD_PREFIX, 5);
+       i = gettimeofday(&tv, NULL);
+
+       if (i < 0) {
+               LOGD("Fail to call gettimeofday()");
+               seed = time(NULL);
+       } else
+               seed = (unsigned int)tv.tv_usec;
+
+       for (i = 5; i < BD_ADDR_LEN; i++) {
+               if (i == 7) {
+                       btmac[i] = '\n';
+                       continue;
+               }
+               ran = rand_r(&seed) % 16;
+               if (ran < 10)
+                       ran += 0x30;
+               else
+                       ran += 0x57;
+               btmac[i] = ran;
+       }
+       LOGD("Random number is\r\n");
+       for (i = 0; i < BD_ADDR_LEN; i++) {
+               LOGD("%c", btmac[i]);
+       }
+       LOGD("\r\n");
+}
+
+static void write_btmac2file(char *btmac)
+{
+       int fd;
+       int ret;
+       fd = open(DATMISC_MAC_ADDR_PATH, O_CREAT|O_RDWR|O_TRUNC, S_IRUSR|S_IWUSR);
+       LOGD("write_btmac2file open file, fd=%d", fd);
+       if(fd >= 0) {
+               if(chmod(DATMISC_MAC_ADDR_PATH,0666) != -1){
+                       ret = write(fd, btmac, strlen(btmac));
+                       if (ret < strlen(btmac)) {
+                               LOGD("Fail to write %s", DATMISC_MAC_ADDR_PATH);
+                               close(fd);
+                               return;
+                       }
+               }
+               close(fd);
+       }else{
+               LOGD("write bt mac to file failed!!");
+       }
+}
+
+uint8 ConvertHexToBin(
+               uint8        *hex_ptr,     // in: the hexadecimal format string
+               uint16       length,       // in: the length of hexadecimal string
+               uint8        *bin_ptr      // out: pointer to the binary format string
+               ){
+       uint8        *dest_ptr = bin_ptr;
+       uint32        i = 0;
+       uint8        ch;
+
+       for(i=0; i<length; i+=2){
+               // the bit 8,7,6,5
+               ch = hex_ptr[i];
+               // digital 0 - 9
+               if (ch >= '0' && ch <= '9')
+                       *dest_ptr =(uint8)((ch - '0') << 4);
+               // a - f
+               else if (ch >= 'a' && ch <= 'f')
+                       *dest_ptr = (uint8)((ch - 'a' + 10) << 4);
+               // A - F
+               else if (ch >= 'A' && ch <= 'F')
+                       *dest_ptr = (uint8)((ch -'A' + 10) << 4);
+               else{
+                       return 0;
+               }
+
+               // the bit 1,2,3,4
+               ch = hex_ptr[i+1];
+               // digtial 0 - 9
+               if (ch >= '0' && ch <= '9')
+                       *dest_ptr |= (uint8)(ch - '0');
+               // a - f
+               else if (ch >= 'a' && ch <= 'f')
+                       *dest_ptr |= (uint8)(ch - 'a' + 10);
+               // A - F
+               else if (ch >= 'A' && ch <= 'F')
+                       *dest_ptr |= (uint8)(ch -'A' + 10);
+               else{
+                       return 0;
+               }
+
+               dest_ptr++;
+       }
+
+       return 1;
+}
+
+static int read_mac_address(char *file_name, uint8 *addr) {
+       char buf[MAC_ADDR_FILE_LEN] = {0};
+       uint32 addr_t[MAC_ADDR_LEN] = {0};
+       int i = 0;
+
+
+#if 1
+       int fd = open(file_name, O_RDONLY, 0666);
+       LOGD("%s read file: %s", __func__, file_name);
+       if (fd < 0) {
+               LOGD("%s open %s error reason: %s", __func__, file_name, strerror(errno));
+               return -1;
+       }
+       if (read(fd, buf, BD_ADDR_LEN) < 0) {
+               LOGD("%s read %s error reason: %s", __func__, file_name, strerror(errno));
+               goto done;
+       }
+       if (sscanf(buf, "%02X%02X\n%02X\n%02X%02X%02X", &addr_t[0], &addr_t[1], &addr_t[2], &addr_t[3], &addr_t[4], &addr_t[5]) < 0) {
+               LOGD("%s sscanf %s error reason: %s", __func__, file_name, strerror(errno));
+               goto done;
+       }
+
+       for (i = 0; i < MAC_ADDR_LEN; i++) {
+               addr[i] = addr_t[i] & 0xFF;
+       }
+       LOGD("%s %s addr: [%02X:%02X:%02X:%02X:%02X:%02X]", __func__, file_name, addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
+
+done:
+       close(fd);
+#endif
+       return 0;
+}
+
+static void mac_address_stream_compose(uint8 *addr) {
+       uint8 tmp, i, j;
+       for (i = 0, j = MAC_ADDR_LEN - 1; (i < MAC_ADDR_LEN / 2) && (i != j); i++, j--) {
+               tmp = addr[i];
+               addr[i] = addr[j];
+               addr[j] = tmp;
+       }
+}
+
+#if 0
+/*
+ * random bluetooth mac address
+ */
+static void random_mac_addr(uint8 *addr) {
+       int fd, randseed, ret, mac_rd;
+       uint8 addr_t[MAC_ADDR_LEN] = {0};
+
+       LOGD("%s", __func__);
+       /* urandom seed build */
+       fd = open("/dev/urandom", O_RDONLY);
+       if (fd < 0){
+               LOGD("%s: open urandom fail", __func__);
+       } else {
+               ret = read(fd, &randseed, sizeof(randseed));
+               LOGD("%s urandom:0x%08X", __func__, randseed);
+               close(fd);
+       }
+
+       /* time seed build */
+       if (fd < 0 || ret < 0) {
+               struct timeval tt;
+               if (gettimeofday(&tt, (struct timezone *)0) > 0) {
+                       randseed = (unsigned int) tt.tv_usec;
+               } else {
+                       randseed = (unsigned int) time(NULL);
+               }
+               LOGD("urandom fail, using system time for randseed");
+       }
+
+       LOGD("%s: randseed = %u",__func__, randseed);
+       srand(randseed);
+       mac_rd = rand();
+
+       addr_t[0] = 0x40; /* FOR */
+       addr_t[1] = 0x45; /* SPRD */
+       addr_t[2] = 0xDA; /* ADDR */
+       addr_t[3] = (uint8)(mac_rd & 0xFF);
+       addr_t[4] = (uint8)((mac_rd >> 8) & 0xFF);
+       addr_t[5] = (uint8)((mac_rd >> 16) & 0xFF);
+
+       memcpy(addr, addr_t, MAC_ADDR_LEN);
+       LOGD("%s: MAC ADDR: [%02X:%02X:%02X:%02X:%02X:%02X]",__func__, addr_t[0], addr_t[1], addr_t[2], addr_t[3], addr_t[4], addr_t[5]);
+}
+#endif
+static void get_mac_address(uint8 *addr){
+       int ret = -1;
+       uint8 addr_t[6] = {0};
+       char bt_mac[BD_ADDR_LEN] = {0, };
+
+       LOGD("%s", __func__);
+       /* check misc mac file exist */
+       ret = access(DATMISC_MAC_ADDR_PATH, F_OK);
+       if (ret != 0) {
+               LOGD("%s %s miss", __func__, DATMISC_MAC_ADDR_PATH);
+
+               /* Try to make bt address file */
+               create_mac_folder();
+
+               mac_rand(bt_mac);
+               LOGD("bt random mac=%s",bt_mac);
+               write_btmac2file(bt_mac);
+
+       }
+
+       /* read mac file */
+       read_mac_address(DATMISC_MAC_ADDR_PATH, addr_t);
+
+       /* compose mac stream */
+       mac_address_stream_compose(addr_t);
+
+       memcpy(addr, addr_t, MAC_ADDR_LEN);
+
+}
+
+
+/*
+ * hci command preload stream,  special order
+ */
+static void pskey_stream_compose(uint8 * buf, BT_PSKEY_CONFIG_T *bt_par) {
+       int i = 0;
+       uint8 *p = buf;
+
+       LOGD("%s", __func__);
+
+       UINT24_TO_STREAM(p, bt_par->pskey_cmd);
+       UINT8_TO_STREAM(p, (uint8)(PSKEY_PREAMBLE_SIZE & 0xFF));
+
+       UINT8_TO_STREAM(p, bt_par->g_dbg_source_sink_syn_test_data);
+       UINT8_TO_STREAM(p, bt_par->g_sys_sleep_in_standby_supported);
+       UINT8_TO_STREAM(p, bt_par->g_sys_sleep_master_supported);
+       UINT8_TO_STREAM(p, bt_par->g_sys_sleep_slave_supported);
+
+       UINT32_TO_STREAM(p, bt_par->default_ahb_clk);
+       UINT32_TO_STREAM(p, bt_par->device_class);
+       UINT32_TO_STREAM(p, bt_par->win_ext);
+
+       for (i = 0; i < 6; i++) {
+               UINT32_TO_STREAM(p, bt_par->g_aGainValue[i]);
+       }
+       for (i = 0; i < 5; i++) {
+               UINT32_TO_STREAM(p, bt_par->g_aPowerValue[i]);
+       }
+
+       for (i = 0; i < 16; i++) {
+               UINT8_TO_STREAM(p, bt_par->feature_set[i]);
+       }
+       for (i = 0; i < 6; i++) {
+               UINT8_TO_STREAM(p, bt_par->device_addr[i]);
+       }
+
+       UINT8_TO_STREAM(p, bt_par->g_sys_sco_transmit_mode);
+       UINT8_TO_STREAM(p, bt_par->g_sys_uart0_communication_supported);
+       UINT8_TO_STREAM(p, bt_par->edr_tx_edr_delay);
+       UINT8_TO_STREAM(p, bt_par->edr_rx_edr_delay);
+
+       UINT16_TO_STREAM(p, bt_par->g_wbs_nv_117);
+
+       UINT32_TO_STREAM(p, bt_par->is_wdg_supported);
+
+       UINT32_TO_STREAM(p, bt_par->share_memo_rx_base_addr);
+       //UINT32_TO_STREAM(p, bt_par->share_memo_tx_base_addr);
+       UINT16_TO_STREAM(p, bt_par->g_wbs_nv_118);
+       UINT16_TO_STREAM(p, bt_par->g_nbv_nv_117);
+
+       UINT32_TO_STREAM(p, bt_par->share_memo_tx_packet_num_addr);
+       UINT32_TO_STREAM(p, bt_par->share_memo_tx_data_base_addr);
+
+       UINT32_TO_STREAM(p, bt_par->g_PrintLevel);
+
+       UINT16_TO_STREAM(p, bt_par->share_memo_tx_block_length);
+       UINT16_TO_STREAM(p, bt_par->share_memo_rx_block_length);
+       UINT16_TO_STREAM(p, bt_par->share_memo_tx_water_mark);
+       //UINT16_TO_STREAM(p, bt_par->share_memo_tx_timeout_value);
+       UINT16_TO_STREAM(p, bt_par->g_nbv_nv_118);
+
+       UINT16_TO_STREAM(p, bt_par->uart_rx_watermark);
+       UINT16_TO_STREAM(p, bt_par->uart_flow_control_thld);
+       UINT32_TO_STREAM(p, bt_par->comp_id);
+       UINT16_TO_STREAM(p, bt_par->pcm_clk_divd);
+
+
+       for (i = 0; i < 8; i++) {
+               UINT32_TO_STREAM(p, bt_par->reserved[i]);
+       }
+}
+
+void sprd_get_pskey(BT_PSKEY_CONFIG_T * pskey_t) {
+       BT_PSKEY_CONFIG_T pskey;
+       uint8 buf[180] = {0};
+
+       LOGD("%s", __func__);
+       memset(&pskey, 0 , sizeof(BT_PSKEY_CONFIG_T));
+       if (bt_getPskeyFromFile(&pskey) < 0 ) {
+               LOGD("%s bt_getPskeyFromFile failed", __func__);
+               memcpy(pskey_t, &bt_para_setting, sizeof(BT_PSKEY_CONFIG_T));
+               return;
+       }
+
+       memset(buf, 0, PSKEY_PRELOAD_SIZE + PSKEY_PREAMBLE_SIZE);
+
+       /* get bluetooth mac address */
+       get_mac_address(pskey.device_addr);
+
+       /* compose pskey hci command pkt */
+       pskey_stream_compose(buf, &pskey);
+
+       memcpy(pskey_t, &pskey, sizeof(BT_PSKEY_CONFIG_T));
+}
+
+
+int sprd_config_init(int fd, char *bdaddr, struct termios *ti)
+{
+       int ret = 0,r=0;
+       unsigned char resp[30] = {0};
+       BT_PSKEY_CONFIG_T bt_para_tmp;
+       uint8 data_tmp[5] = {'a'};
+       static int index = 0;
+       uint8 *buf = NULL;
+#if 0
+       char buffer;
+       int btsleep_fd_sprd = -1;
+#endif
+       LOGD("sprd_config_init");
+
+#if 0
+       uart_fd = open(UART_INFO_PATH, O_WRONLY);
+       if(uart_fd > 0)
+       {
+               buffer = '2';
+               if (write(uart_fd, &buffer, 1) < 0)
+               {
+                       LOGD("%s write(%s) failed: %s (%d) 2", __func__,
+                                       UART_INFO_PATH, strerror(errno),errno);
+               }
+
+               close(uart_fd);
+       }
+#endif
+
+#if 0
+       btsleep_fd_sprd = open(VENDOR_BTWRITE_PROC_NODE, O_WRONLY);
+       if (btsleep_fd_sprd < 0)
+       {
+               LOGD("%s open(%s) for write failed: %s (%d)", __func__,
+                               VENDOR_BTWRITE_PROC_NODE, strerror(errno), errno);
+       }
+       else
+       {
+               buffer = '1';
+               if (write(btsleep_fd_sprd, &buffer, 1) < 0)
+               {
+                       LOGD("%s write(%s) failed: %s (%d)", __func__,
+                                       VENDOR_BTWRITE_PROC_NODE, strerror(errno),errno);
+               }
+       }
+#endif
+
+       ret = bt_getPskeyFromFile(&bt_para_tmp);
+       if (ret < 0) {
+               LOGD("init_sprd_config bt_getPskeyFromFile failed\n");
+               memcpy(&bt_para_tmp, &bt_para_setting, sizeof(BT_PSKEY_CONFIG_T));
+       }
+
+       buf = (uint8 *)malloc(PSKEY_PRELOAD_SIZE + PSKEY_PREAMBLE_SIZE);
+       if (buf == NULL) {
+               LOGD("%s alloc stream memory failed", __func__);
+               return -1;
+       }
+       memset(buf, 0, PSKEY_PRELOAD_SIZE + PSKEY_PREAMBLE_SIZE);
+
+       /* get bluetooth mac address */
+       get_mac_address(bt_para_tmp.device_addr);
+
+       /* compose pskey hci command pkt */
+       pskey_stream_compose(buf, &bt_para_tmp);
+
+       ret = write(fd, buf, PSKEY_PRELOAD_SIZE + PSKEY_PREAMBLE_SIZE);
+       LOGD("write pskey ret = %d", ret);
+
+       free(buf);
+       buf = NULL;
+
+       if (ret < 0) {
+               LOGD("%s write pskey stream failed", __func__);
+               return -1;
+       }
+
+       memset(data_tmp, 0xff, sizeof(data_tmp));
+       while (1) {
+               r = read(fd, resp, 1);
+
+               if (r <= 0)
+                       return -1;
+               else{
+                       data_tmp[index] = resp[0];
+                       LOGD("recive from controller 0x%x", data_tmp[index]);
+                       ++index;
+               }
+
+/*             if ((data_tmp[0] == 0x04) && (data_tmp[1] == 0x6f)&& (data_tmp[2] == 0x01) &&(data_tmp[3] == 0x0)){*/
+               if ((data_tmp[0] == 0x04) && (data_tmp[1] == 0xe)&& (data_tmp[2] == 0xa) &&(data_tmp[3] == 0x1)){
+                       fprintf(stderr, "read response ok \n");
+
+                       if (index == 12) {
+                               index = 0;
+                               memset(data_tmp, 0x0, sizeof(data_tmp));
+                               break;
+                       }
+               }
+       }
+
+       return 0;
+}
diff --git a/tools/hciattach_sprd.h b/tools/hciattach_sprd.h
new file mode 100644 (file)
index 0000000..6e59408
--- /dev/null
@@ -0,0 +1,82 @@
+#ifndef HCIATTACH_SPRD_H__
+#define HCIATTACH_SPRD_H__
+
+#define MAC_ERROR              "FF:FF:FF:FF:FF:FF"
+
+#define BT_MAC_FILE            "/productinfo/btmac.txt"
+//#define GET_BTMAC_ATCMD      "AT+SNVM=0,401"
+//#define GET_BTPSKEY_ATCMD    "AT+SNVM=0,415"
+//#define SET_BTMAC_ATCMD      "AT+SNVM=1,401"
+#define BT_RAND_MAC_LENGTH   17
+
+// used to store BT pskey structure and default values
+#define BT_PSKEY_STRUCT_FILE "/system/lib/modules/pskey_bt.txt"
+//#define BT_PSKEY_FILE        "/system/lib/modules/pskey_bt.txt"
+
+
+typedef unsigned char uint8;
+typedef unsigned int uint32;
+typedef unsigned short uint16;
+
+#define BT_ADDRESS_SIZE    6
+
+
+typedef struct SPRD_BT_PSKEY_INFO_T{
+       uint32   pskey_cmd;
+
+       uint8    g_dbg_source_sink_syn_test_data;
+       uint8    g_sys_sleep_in_standby_supported;
+       uint8    g_sys_sleep_master_supported;
+       uint8    g_sys_sleep_slave_supported;
+
+       uint32  default_ahb_clk;
+       uint32  device_class;
+       uint32  win_ext;
+
+       uint32  g_aGainValue[6];
+       uint32  g_aPowerValue[5];
+
+       uint8    feature_set[16];
+       uint8    device_addr[6];
+
+       uint8    g_sys_sco_transmit_mode; //true tramsmit by uart, otherwise by share memory
+       uint8    g_sys_uart0_communication_supported; //true use uart0, otherwise use uart1 for debug
+       uint8    edr_tx_edr_delay;
+       uint8    edr_rx_edr_delay;
+
+       uint16  g_wbs_nv_117;
+
+       uint32  is_wdg_supported;
+
+       uint32  share_memo_rx_base_addr;
+
+       // uint32  share_memo_tx_base_addr;
+       uint16  g_wbs_nv_118;
+       uint16  g_nbv_nv_117;
+
+       uint32  share_memo_tx_packet_num_addr;
+       uint32  share_memo_tx_data_base_addr;
+
+       uint32  g_PrintLevel;
+
+       uint16  share_memo_tx_block_length;
+       uint16  share_memo_rx_block_length;
+       uint16  share_memo_tx_water_mark;
+
+       //uint16  share_memo_tx_timeout_value;
+       uint16  g_nbv_nv_118;
+
+       uint16  uart_rx_watermark;
+       uint16  uart_flow_control_thld;
+       uint32  comp_id;
+       uint16  pcm_clk_divd;
+
+       uint32  reserved[8];
+}BT_PSKEY_CONFIG_T;
+
+
+#endif /* HCIATTACH_SPRD_H__ */
+
+
+
+
index e5fb889..d997010 100644 (file)
@@ -319,6 +319,25 @@ static void test_condition_complete(struct test_data *data)
                                test_post_teardown, 2, user, free); \
        } while (0)
 
+#define test_bredr20(name, data, setup, func) \
+       do { \
+               struct test_data *user; \
+               user = malloc(sizeof(struct test_data)); \
+               if (!user) \
+                       break; \
+               user->hciemu_type = HCIEMU_TYPE_LEGACY; \
+               user->test_setup = setup; \
+               user->test_data = data; \
+               user->expected_version = 0x04; \
+               user->expected_manufacturer = 0x003f; \
+               user->expected_supported_settings = 0x000010bf; \
+               user->initial_settings = 0x00000080; \
+               user->unmet_conditions = 0; \
+               tester_add_full(name, data, \
+                               test_pre_setup, test_setup, func, NULL, \
+                               test_post_teardown, 2, user, free); \
+       } while (0)
+
 #define test_bredr(name, data, setup, func) \
        do { \
                struct test_data *user; \
@@ -378,6 +397,7 @@ struct generic_data {
        uint16_t send_len;
        const void * (*send_func)(uint16_t *len);
        uint8_t expect_status;
+       bool expect_ignore_param;
        const void *expect_param;
        uint16_t expect_len;
        const void * (*expect_func)(uint16_t *len);
@@ -477,6 +497,45 @@ static const struct generic_data read_info_invalid_index_test = {
        .expect_status = MGMT_STATUS_INVALID_INDEX,
 };
 
+static const struct generic_data read_unconf_index_list_invalid_param_test = {
+       .send_index_none = true,
+       .send_opcode = MGMT_OP_READ_UNCONF_INDEX_LIST,
+       .send_param = dummy_data,
+       .send_len = sizeof(dummy_data),
+       .expect_status = MGMT_STATUS_INVALID_PARAMS,
+};
+
+static const struct generic_data read_unconf_index_list_invalid_index_test = {
+       .send_opcode = MGMT_OP_READ_UNCONF_INDEX_LIST,
+       .expect_status = MGMT_STATUS_INVALID_INDEX,
+};
+
+static const struct generic_data read_config_info_invalid_param_test = {
+       .send_opcode = MGMT_OP_READ_CONFIG_INFO,
+       .send_param = dummy_data,
+       .send_len = sizeof(dummy_data),
+       .expect_status = MGMT_STATUS_INVALID_PARAMS,
+};
+
+static const struct generic_data read_config_info_invalid_index_test = {
+       .send_index_none = true,
+       .send_opcode = MGMT_OP_READ_CONFIG_INFO,
+       .expect_status = MGMT_STATUS_INVALID_INDEX,
+};
+
+static const struct generic_data read_ext_index_list_invalid_param_test = {
+       .send_index_none = true,
+       .send_opcode = MGMT_OP_READ_EXT_INDEX_LIST,
+       .send_param = dummy_data,
+       .send_len = sizeof(dummy_data),
+       .expect_status = MGMT_STATUS_INVALID_PARAMS,
+};
+
+static const struct generic_data read_ext_index_list_invalid_index_test = {
+       .send_opcode = MGMT_OP_READ_EXT_INDEX_LIST,
+       .expect_status = MGMT_STATUS_INVALID_INDEX,
+};
+
 static const char set_powered_on_param[] = { 0x01 };
 static const char set_powered_invalid_param[] = { 0x02 };
 static const char set_powered_garbage_param[] = { 0x01, 0x00 };
@@ -797,6 +856,12 @@ static const struct generic_data set_connectable_off_le_test_2 = {
        .expect_hci_len = sizeof(set_connectable_off_adv_param),
 };
 
+static uint16_t settings_powered_le_discoverable[] = {
+                                       MGMT_OP_SET_LE,
+                                       MGMT_OP_SET_CONNECTABLE,
+                                       MGMT_OP_SET_POWERED,
+                                       MGMT_OP_SET_DISCOVERABLE, 0 };
+
 static uint16_t settings_powered_le_discoverable_advertising[] = {
                                        MGMT_OP_SET_LE,
                                        MGMT_OP_SET_CONNECTABLE,
@@ -835,6 +900,8 @@ static const struct generic_data set_connectable_off_le_test_4 = {
 
 static const char set_fast_conn_on_param[] = { 0x01 };
 static const char set_fast_conn_on_settings_1[] = { 0x87, 0x00, 0x00, 0x00 };
+static const char set_fast_conn_on_settings_2[] = { 0x85, 0x00, 0x00, 0x00 };
+static const char set_fast_conn_on_settings_3[] = { 0x84, 0x00, 0x00, 0x00 };
 
 static const struct generic_data set_fast_conn_on_success_test_1 = {
        .setup_settings = settings_powered_connectable,
@@ -847,6 +914,27 @@ static const struct generic_data set_fast_conn_on_success_test_1 = {
        .expect_settings_set = MGMT_SETTING_FAST_CONNECTABLE,
 };
 
+static const struct generic_data set_fast_conn_on_success_test_2 = {
+       .setup_settings = settings_powered,
+       .send_opcode = MGMT_OP_SET_FAST_CONNECTABLE,
+       .send_param = set_fast_conn_on_param,
+       .send_len = sizeof(set_fast_conn_on_param),
+       .expect_status = MGMT_STATUS_SUCCESS,
+       .expect_param = set_fast_conn_on_settings_2,
+       .expect_len = sizeof(set_fast_conn_on_settings_2),
+       .expect_settings_set = MGMT_SETTING_FAST_CONNECTABLE,
+};
+
+static const struct generic_data set_fast_conn_on_success_test_3 = {
+       .send_opcode = MGMT_OP_SET_FAST_CONNECTABLE,
+       .send_param = set_fast_conn_on_param,
+       .send_len = sizeof(set_fast_conn_on_param),
+       .expect_status = MGMT_STATUS_SUCCESS,
+       .expect_param = set_fast_conn_on_settings_3,
+       .expect_len = sizeof(set_fast_conn_on_settings_3),
+       .expect_settings_set = MGMT_SETTING_FAST_CONNECTABLE,
+};
+
 static const struct generic_data set_fast_conn_on_not_supported_test_1 = {
        .setup_settings = settings_powered_connectable,
        .send_opcode = MGMT_OP_SET_FAST_CONNECTABLE,
@@ -855,6 +943,15 @@ static const struct generic_data set_fast_conn_on_not_supported_test_1 = {
        .expect_status = MGMT_STATUS_NOT_SUPPORTED,
 };
 
+static const char set_fast_conn_nval_param[] = { 0xff };
+
+static const struct generic_data set_fast_conn_nval_param_test_1 = {
+       .send_opcode = MGMT_OP_SET_FAST_CONNECTABLE,
+       .send_param = set_fast_conn_nval_param,
+       .send_len = sizeof(set_fast_conn_nval_param),
+       .expect_status = MGMT_STATUS_INVALID_PARAMS,
+};
+
 static const char set_bondable_on_param[] = { 0x01 };
 static const char set_bondable_invalid_param[] = { 0x02 };
 static const char set_bondable_garbage_param[] = { 0x01, 0x00 };
@@ -1286,6 +1383,10 @@ static const struct generic_data set_ssp_on_invalid_index_test = {
 static uint16_t settings_powered_ssp[] = { MGMT_OP_SET_SSP,
                                                MGMT_OP_SET_POWERED, 0 };
 
+static uint16_t settings_powered_sc[] = { MGMT_OP_SET_SSP,
+                                               MGMT_OP_SET_SECURE_CONN,
+                                               MGMT_OP_SET_POWERED, 0 };
+
 static const char set_sc_on_param[] = { 0x01 };
 static const char set_sc_only_on_param[] = { 0x02 };
 static const char set_sc_invalid_param[] = { 0x03 };
@@ -3748,6 +3849,650 @@ static const struct generic_data remove_device_success_5 = {
        .expect_hci_len = sizeof(set_le_scan_off),
 };
 
+static const struct generic_data read_adv_features_invalid_param_test = {
+       .send_opcode = MGMT_OP_READ_ADV_FEATURES,
+       .send_param = dummy_data,
+       .send_len = sizeof(dummy_data),
+       .expect_status = MGMT_STATUS_INVALID_PARAMS,
+};
+
+static const struct generic_data read_adv_features_invalid_index_test = {
+       .send_index_none = true,
+       .send_opcode = MGMT_OP_READ_ADV_FEATURES,
+       .expect_status = MGMT_STATUS_INVALID_INDEX,
+};
+
+static const uint8_t add_advertising_param_1[] = {
+       0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00,
+       0x03, 0x02, 0x0d, 0x18,
+       0x04, 0xff, 0x01, 0x02, 0x03,
+};
+
+static const uint8_t add_advertising_param_2[] = {
+       0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x0a,
+       0x03, 0x02, 0x0d, 0x18,
+       0x04, 0xff, 0x01, 0x02, 0x03,
+       0x03, 0x19, 0x40, 0x03,
+       0x05, 0x03, 0x0d, 0x18, 0x0f, 0x18,
+};
+
+static const uint8_t add_advertising_param_3[] = {
+       0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x09, 0x00,
+       0x03, 0x02, 0x0d, 0x18,
+       0x04, 0xff, 0x01, 0x02, 0x03,
+};
+
+static const uint8_t add_advertising_param_4[] = {
+       0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00,
+       0x03, 0x02, 0x0d, 0x18,
+       0x04, 0xff, 0x01, 0x02, 0x03,
+};
+
+static const uint8_t add_advertising_param_5[] = {
+       0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00,
+       0x03, 0x02, 0x0d, 0x18,
+       0x04, 0xff, 0x01, 0x02, 0x03,
+};
+
+static const uint8_t add_advertising_param_6[] = {
+       0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00,
+       0x03, 0x02, 0x0d, 0x18,
+       0x04, 0xff, 0x01, 0x02, 0x03,
+};
+
+static const uint8_t add_advertising_param_7[] = {
+       0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00,
+       0x03, 0x02, 0x0d, 0x18,
+       0x04, 0xff, 0x01, 0x02, 0x03,
+};
+
+static const uint8_t add_advertising_param_8[] = {
+       0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00,
+       0x03, 0x02, 0x0d, 0x18,
+       0x04, 0xff, 0x01, 0x02, 0x03,
+};
+
+static const uint8_t advertising_instance_param[] = {
+       0x01,
+};
+
+static const uint8_t set_adv_data_1[] = {
+       0x09, 0x03, 0x02, 0x0d, 0x18, 0x04, 0xff, 0x01, 0x02, 0x03,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00,
+};
+
+static const uint8_t set_adv_data_2[] = {
+       0x0c, 0x02, 0x01, 0x04, 0x03, 0x03, 0x0d, 0x18, 0x04, 0xff,
+       0x01, 0x02, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00,
+};
+
+static const uint8_t set_adv_data_3[] = {
+       0x06, 0x05, 0x08, 0x74, 0x65, 0x73, 0x74, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00,
+};
+
+static const uint8_t set_adv_data_4[] = {
+       0x03, 0x02, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00,
+};
+
+static const uint8_t set_adv_data_5[] = {
+       0x0c, 0x02, 0x01, 0x02, 0x03, 0x02, 0x0d, 0x18, 0x04, 0xff,
+       0x01, 0x02, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00,
+};
+
+static const uint8_t set_adv_data_6[] = {
+       0x0c, 0x02, 0x01, 0x01, 0x03, 0x02, 0x0d, 0x18, 0x04, 0xff,
+       0x01, 0x02, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00,
+};
+
+static const uint8_t set_adv_data_7[] = {
+       0x0c, 0x02, 0x01, 0x02, 0x03, 0x02, 0x0d, 0x18, 0x04, 0xff,
+       0x01, 0x02, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00,
+};
+
+static const uint8_t set_adv_data_8[] = {
+       0x0c, 0x02, 0x0a, 0x00, 0x03, 0x02, 0x0d, 0x18, 0x04, 0xff,
+       0x01, 0x02, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00,
+};
+
+static const uint8_t set_scan_rsp_1[] = {
+       0x0a, 0x03, 0x19, 0x40, 0x03, 0x05, 0x03, 0x0d, 0x18, 0x0f,
+       0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00,
+};
+
+static const uint8_t add_advertising_invalid_param_1[] = {
+       0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00,
+       0x03, 0x03, 0x0d, 0x18,
+       0x19, 0xff, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
+       0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14,
+       0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e,
+};
+
+static const uint8_t add_advertising_invalid_param_2[] = {
+       0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00,
+       0x04, 0x03, 0x0d, 0x18,
+       0x04, 0xff, 0x01, 0x02, 0x03,
+};
+
+static const uint8_t add_advertising_invalid_param_3[] = {
+       0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00,
+       0x03, 0x03, 0x0d, 0x18,
+       0x02, 0xff, 0x01, 0x02, 0x03,
+};
+
+static const uint8_t add_advertising_invalid_param_4[] = {
+       0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00,
+       0x03, 0x03, 0x0d, 0x18,
+       0x05, 0xff, 0x01, 0x02, 0x03,
+};
+
+static const uint8_t add_advertising_invalid_param_5[] = {
+       0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1D, 0x00,
+       0x03, 0x03, 0x0d, 0x18,
+       0x19, 0xff, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
+       0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14,
+       0x15, 0x16, 0x17, 0x18,
+};
+
+static const uint8_t add_advertising_invalid_param_6[] = {
+       0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20,
+       0x03, 0x03, 0x0d, 0x18,
+       0x19, 0xff, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
+       0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14,
+       0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e,
+};
+
+static const uint8_t add_advertising_invalid_param_7[] = {
+       0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09,
+       0x04, 0x03, 0x0d, 0x18,
+       0x04, 0xff, 0x01, 0x02, 0x03,
+};
+
+static const uint8_t add_advertising_invalid_param_8[] = {
+       0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09,
+       0x03, 0x03, 0x0d, 0x18,
+       0x02, 0xff, 0x01, 0x02, 0x03,
+};
+
+static const uint8_t add_advertising_invalid_param_9[] = {
+       0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09,
+       0x03, 0x03, 0x0d, 0x18,
+       0x05, 0xff, 0x01, 0x02, 0x03,
+};
+
+static const uint8_t add_advertising_invalid_param_10[] = {
+       0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1D,
+       0x03, 0x03, 0x0d, 0x18,
+       0x19, 0xff, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
+       0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14,
+       0x15, 0x16, 0x17, 0x18,
+};
+
+static const struct generic_data add_advertising_fail_1 = {
+       .setup_settings = settings_powered,
+       .send_opcode = MGMT_OP_ADD_ADVERTISING,
+       .send_param = add_advertising_param_1,
+       .send_len = sizeof(add_advertising_param_1),
+       .expect_status = MGMT_STATUS_REJECTED,
+};
+
+static const struct generic_data add_advertising_fail_2 = {
+       .setup_settings = settings_powered_le,
+       .send_opcode = MGMT_OP_ADD_ADVERTISING,
+       .send_param = add_advertising_invalid_param_1,
+       .send_len = sizeof(add_advertising_invalid_param_1),
+       .expect_status = MGMT_STATUS_INVALID_PARAMS,
+};
+
+static const struct generic_data add_advertising_fail_3 = {
+       .setup_settings = settings_powered_le,
+       .send_opcode = MGMT_OP_ADD_ADVERTISING,
+       .send_param = add_advertising_invalid_param_2,
+       .send_len = sizeof(add_advertising_invalid_param_2),
+       .expect_status = MGMT_STATUS_INVALID_PARAMS,
+};
+
+static const struct generic_data add_advertising_fail_4 = {
+       .setup_settings = settings_powered_le,
+       .send_opcode = MGMT_OP_ADD_ADVERTISING,
+       .send_param = add_advertising_invalid_param_3,
+       .send_len = sizeof(add_advertising_invalid_param_3),
+       .expect_status = MGMT_STATUS_INVALID_PARAMS,
+};
+
+static const struct generic_data add_advertising_fail_5 = {
+       .setup_settings = settings_powered_le,
+       .send_opcode = MGMT_OP_ADD_ADVERTISING,
+       .send_param = add_advertising_invalid_param_4,
+       .send_len = sizeof(add_advertising_invalid_param_4),
+       .expect_status = MGMT_STATUS_INVALID_PARAMS,
+};
+
+static const struct generic_data add_advertising_fail_6 = {
+       .setup_settings = settings_powered_le,
+       .send_opcode = MGMT_OP_ADD_ADVERTISING,
+       .send_param = add_advertising_invalid_param_5,
+       .send_len = sizeof(add_advertising_invalid_param_5),
+       .expect_status = MGMT_STATUS_INVALID_PARAMS,
+};
+
+static const struct generic_data add_advertising_fail_7 = {
+       .setup_settings = settings_powered_le,
+       .send_opcode = MGMT_OP_ADD_ADVERTISING,
+       .send_param = add_advertising_invalid_param_6,
+       .send_len = sizeof(add_advertising_invalid_param_6),
+       .expect_status = MGMT_STATUS_INVALID_PARAMS,
+};
+
+static const struct generic_data add_advertising_fail_8 = {
+       .setup_settings = settings_powered_le,
+       .send_opcode = MGMT_OP_ADD_ADVERTISING,
+       .send_param = add_advertising_invalid_param_7,
+       .send_len = sizeof(add_advertising_invalid_param_7),
+       .expect_status = MGMT_STATUS_INVALID_PARAMS,
+};
+
+static const struct generic_data add_advertising_fail_9 = {
+       .setup_settings = settings_powered_le,
+       .send_opcode = MGMT_OP_ADD_ADVERTISING,
+       .send_param = add_advertising_invalid_param_8,
+       .send_len = sizeof(add_advertising_invalid_param_8),
+       .expect_status = MGMT_STATUS_INVALID_PARAMS,
+};
+
+static const struct generic_data add_advertising_fail_10 = {
+       .setup_settings = settings_powered_le,
+       .send_opcode = MGMT_OP_ADD_ADVERTISING,
+       .send_param = add_advertising_invalid_param_9,
+       .send_len = sizeof(add_advertising_invalid_param_9),
+       .expect_status = MGMT_STATUS_INVALID_PARAMS,
+};
+
+static const struct generic_data add_advertising_fail_11 = {
+       .setup_settings = settings_powered_le,
+       .send_opcode = MGMT_OP_ADD_ADVERTISING,
+       .send_param = add_advertising_invalid_param_10,
+       .send_len = sizeof(add_advertising_invalid_param_10),
+       .expect_status = MGMT_STATUS_INVALID_PARAMS,
+};
+
+static const struct generic_data add_advertising_fail_12 = {
+       .setup_settings = settings_le,
+       .send_opcode = MGMT_OP_ADD_ADVERTISING,
+       .send_param = add_advertising_param_3,
+       .send_len = sizeof(add_advertising_param_3),
+       .expect_status = MGMT_STATUS_REJECTED,
+};
+
+static const struct generic_data add_advertising_success_1 = {
+       .setup_settings = settings_powered_le,
+       .send_opcode = MGMT_OP_ADD_ADVERTISING,
+       .send_param = add_advertising_param_1,
+       .send_len = sizeof(add_advertising_param_1),
+       .expect_param = advertising_instance_param,
+       .expect_len = sizeof(advertising_instance_param),
+       .expect_status = MGMT_STATUS_SUCCESS,
+       .expect_alt_ev = MGMT_EV_ADVERTISING_ADDED,
+       .expect_alt_ev_param = advertising_instance_param,
+       .expect_alt_ev_len = sizeof(advertising_instance_param),
+       .expect_hci_command = BT_HCI_CMD_LE_SET_ADV_DATA,
+       .expect_hci_param = set_adv_data_1,
+       .expect_hci_len = sizeof(set_adv_data_1),
+};
+
+static const char set_powered_adv_instance_settings_param[] = {
+       0x81, 0x02, 0x00, 0x00,
+};
+
+static const struct generic_data add_advertising_success_2 = {
+       .send_opcode = MGMT_OP_SET_POWERED,
+       .send_param = set_powered_on_param,
+       .send_len = sizeof(set_powered_on_param),
+       .expect_status = MGMT_STATUS_SUCCESS,
+       .expect_param = set_powered_adv_instance_settings_param,
+       .expect_len = sizeof(set_powered_adv_instance_settings_param),
+       .expect_hci_command = BT_HCI_CMD_LE_SET_ADV_DATA,
+       .expect_hci_param = set_adv_data_3,
+       .expect_hci_len = sizeof(set_adv_data_3),
+};
+
+static const struct generic_data add_advertising_success_3 = {
+       .send_opcode = MGMT_OP_SET_POWERED,
+       .send_param = set_powered_on_param,
+       .send_len = sizeof(set_powered_on_param),
+       .expect_status = MGMT_STATUS_SUCCESS,
+       .expect_param = set_powered_adv_instance_settings_param,
+       .expect_len = sizeof(set_powered_adv_instance_settings_param),
+       .expect_hci_command = BT_HCI_CMD_LE_SET_ADV_ENABLE,
+       .expect_hci_param = set_adv_on_set_adv_enable_param,
+       .expect_hci_len = sizeof(set_adv_on_set_adv_enable_param),
+};
+
+static const struct generic_data add_advertising_success_4 = {
+       .send_opcode = MGMT_OP_SET_ADVERTISING,
+       .send_param = set_adv_on_param,
+       .send_len = sizeof(set_adv_on_param),
+       .expect_status = MGMT_STATUS_SUCCESS,
+       .expect_param = set_adv_settings_param_2,
+       .expect_len = sizeof(set_adv_settings_param_2),
+       .expect_hci_command = BT_HCI_CMD_LE_SET_ADV_DATA,
+       .expect_hci_param = set_adv_data_4,
+       .expect_hci_len = sizeof(set_adv_data_4),
+};
+
+static const char set_adv_off_param[] = { 0x00 };
+
+static const struct generic_data add_advertising_success_5 = {
+       .send_opcode = MGMT_OP_SET_ADVERTISING,
+       .send_param = set_adv_off_param,
+       .send_len = sizeof(set_adv_off_param),
+       .expect_status = MGMT_STATUS_SUCCESS,
+       .expect_param = set_powered_adv_instance_settings_param,
+       .expect_len = sizeof(set_powered_adv_instance_settings_param),
+       .expect_hci_command = BT_HCI_CMD_LE_SET_ADV_DATA,
+       .expect_hci_param = set_adv_data_3,
+       .expect_hci_len = sizeof(set_adv_data_3),
+};
+
+static const struct generic_data add_advertising_success_6 = {
+       .setup_settings = settings_powered_le,
+       .send_opcode = MGMT_OP_ADD_ADVERTISING,
+       .send_param = add_advertising_param_2,
+       .send_len = sizeof(add_advertising_param_2),
+       .expect_param = advertising_instance_param,
+       .expect_len = sizeof(advertising_instance_param),
+       .expect_status = MGMT_STATUS_SUCCESS,
+       .expect_alt_ev = MGMT_EV_ADVERTISING_ADDED,
+       .expect_alt_ev_param = advertising_instance_param,
+       .expect_alt_ev_len = sizeof(advertising_instance_param),
+       .expect_hci_command = BT_HCI_CMD_LE_SET_ADV_DATA,
+       .expect_hci_param = set_adv_data_1,
+       .expect_hci_len = sizeof(set_adv_data_1),
+};
+
+static const struct generic_data add_advertising_success_7 = {
+       .setup_settings = settings_powered_le,
+       .send_opcode = MGMT_OP_ADD_ADVERTISING,
+       .send_param = add_advertising_param_2,
+       .send_len = sizeof(add_advertising_param_2),
+       .expect_param = advertising_instance_param,
+       .expect_len = sizeof(advertising_instance_param),
+       .expect_status = MGMT_STATUS_SUCCESS,
+       .expect_alt_ev = MGMT_EV_ADVERTISING_ADDED,
+       .expect_alt_ev_param = advertising_instance_param,
+       .expect_alt_ev_len = sizeof(advertising_instance_param),
+       .expect_hci_command = BT_HCI_CMD_LE_SET_SCAN_RSP_DATA,
+       .expect_hci_param = set_scan_rsp_1,
+       .expect_hci_len = sizeof(set_scan_rsp_1),
+};
+
+static const struct generic_data add_advertising_success_8 = {
+       .setup_settings = settings_powered_le,
+       .send_opcode = MGMT_OP_ADD_ADVERTISING,
+       .send_param = add_advertising_param_4,
+       .send_len = sizeof(add_advertising_param_4),
+       .expect_param = advertising_instance_param,
+       .expect_len = sizeof(advertising_instance_param),
+       .expect_status = MGMT_STATUS_SUCCESS,
+       .expect_hci_command = BT_HCI_CMD_LE_SET_ADV_PARAMETERS,
+       .expect_hci_param = set_connectable_on_adv_param,
+       .expect_hci_len = sizeof(set_connectable_on_adv_param),
+};
+
+static const struct generic_data add_advertising_success_9 = {
+       .setup_settings = settings_powered_le,
+       .send_opcode = MGMT_OP_ADD_ADVERTISING,
+       .send_param = add_advertising_param_5,
+       .send_len = sizeof(add_advertising_param_5),
+       .expect_param = advertising_instance_param,
+       .expect_len = sizeof(advertising_instance_param),
+       .expect_status = MGMT_STATUS_SUCCESS,
+       .expect_hci_command = BT_HCI_CMD_LE_SET_ADV_DATA,
+       .expect_hci_param = set_adv_data_5,
+       .expect_hci_len = sizeof(set_adv_data_5),
+};
+
+static const struct generic_data add_advertising_success_10 = {
+       .setup_settings = settings_powered_le,
+       .send_opcode = MGMT_OP_ADD_ADVERTISING,
+       .send_param = add_advertising_param_6,
+       .send_len = sizeof(add_advertising_param_6),
+       .expect_param = advertising_instance_param,
+       .expect_len = sizeof(advertising_instance_param),
+       .expect_status = MGMT_STATUS_SUCCESS,
+       .expect_hci_command = BT_HCI_CMD_LE_SET_ADV_DATA,
+       .expect_hci_param = set_adv_data_6,
+       .expect_hci_len = sizeof(set_adv_data_6),
+};
+
+static const struct generic_data add_advertising_success_11 = {
+       .setup_settings = settings_powered_le_discoverable,
+       .send_opcode = MGMT_OP_ADD_ADVERTISING,
+       .send_param = add_advertising_param_7,
+       .send_len = sizeof(add_advertising_param_7),
+       .expect_param = advertising_instance_param,
+       .expect_len = sizeof(advertising_instance_param),
+       .expect_status = MGMT_STATUS_SUCCESS,
+       .expect_hci_command = BT_HCI_CMD_LE_SET_ADV_DATA,
+       .expect_hci_param = set_adv_data_7,
+       .expect_hci_len = sizeof(set_adv_data_7),
+};
+
+static const struct generic_data add_advertising_success_12 = {
+       .setup_settings = settings_powered_le_discoverable,
+       .send_opcode = MGMT_OP_ADD_ADVERTISING,
+       .send_param = add_advertising_param_8,
+       .send_len = sizeof(add_advertising_param_8),
+       .expect_param = advertising_instance_param,
+       .expect_len = sizeof(advertising_instance_param),
+       .expect_status = MGMT_STATUS_SUCCESS,
+       .expect_hci_command = BT_HCI_CMD_LE_SET_ADV_DATA,
+       .expect_hci_param = set_adv_data_8,
+       .expect_hci_len = sizeof(set_adv_data_8),
+};
+
+static uint16_t settings_powered_le_connectable[] = {
+                                               MGMT_OP_SET_POWERED,
+                                               MGMT_OP_SET_LE,
+                                               MGMT_OP_SET_CONNECTABLE, 0 };
+
+static uint8_t set_connectable_off_scan_adv_param[] = {
+               0x00, 0x08,                             /* min_interval */
+               0x00, 0x08,                             /* max_interval */
+               0x02,                                   /* type */
+               0x01,                                   /* own_addr_type */
+               0x00,                                   /* direct_addr_type */
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00,     /* direct_addr */
+               0x07,                                   /* channel_map */
+               0x00,                                   /* filter_policy */
+};
+
+static const struct generic_data add_advertising_success_13 = {
+       .setup_settings = settings_powered_le,
+       .send_opcode = MGMT_OP_ADD_ADVERTISING,
+       .send_param = add_advertising_param_2,
+       .send_len = sizeof(add_advertising_param_2),
+       .expect_param = advertising_instance_param,
+       .expect_len = sizeof(advertising_instance_param),
+       .expect_status = MGMT_STATUS_SUCCESS,
+       .expect_hci_command = BT_HCI_CMD_LE_SET_ADV_PARAMETERS,
+       .expect_hci_param = set_connectable_off_scan_adv_param,
+       .expect_hci_len = sizeof(set_connectable_off_scan_adv_param),
+};
+
+static const struct generic_data add_advertising_success_14 = {
+       .setup_settings = settings_powered_le,
+       .send_opcode = MGMT_OP_ADD_ADVERTISING,
+       .send_param = add_advertising_param_1,
+       .send_len = sizeof(add_advertising_param_1),
+       .expect_param = advertising_instance_param,
+       .expect_len = sizeof(advertising_instance_param),
+       .expect_status = MGMT_STATUS_SUCCESS,
+       .expect_hci_command = BT_HCI_CMD_LE_SET_ADV_PARAMETERS,
+       .expect_hci_param = set_connectable_off_adv_param,
+       .expect_hci_len = sizeof(set_connectable_off_adv_param),
+};
+
+static const struct generic_data add_advertising_success_15 = {
+       .setup_settings = settings_powered_le_connectable,
+       .send_opcode = MGMT_OP_ADD_ADVERTISING,
+       .send_param = add_advertising_param_1,
+       .send_len = sizeof(add_advertising_param_1),
+       .expect_param = advertising_instance_param,
+       .expect_len = sizeof(advertising_instance_param),
+       .expect_status = MGMT_STATUS_SUCCESS,
+       .expect_hci_command = BT_HCI_CMD_LE_SET_ADV_PARAMETERS,
+       .expect_hci_param = set_connectable_on_adv_param,
+       .expect_hci_len = sizeof(set_connectable_on_adv_param),
+};
+
+static const char set_connectable_settings_param_3[] = {
+                                               0x83, 0x02, 0x00, 0x00 };
+
+static const struct generic_data add_advertising_success_16 = {
+       .send_opcode = MGMT_OP_SET_CONNECTABLE,
+       .send_param = set_connectable_on_param,
+       .send_len = sizeof(set_connectable_on_param),
+       .expect_status = MGMT_STATUS_SUCCESS,
+       .expect_param = set_connectable_settings_param_3,
+       .expect_len = sizeof(set_connectable_settings_param_3),
+       .expect_hci_command = BT_HCI_CMD_LE_SET_ADV_PARAMETERS,
+       .expect_hci_param = set_connectable_on_adv_param,
+       .expect_hci_len = sizeof(set_connectable_on_adv_param),
+};
+
+static const struct generic_data add_advertising_success_17 = {
+       .send_opcode = MGMT_OP_SET_CONNECTABLE,
+       .send_param = set_connectable_off_param,
+       .send_len = sizeof(set_connectable_off_param),
+       .expect_status = MGMT_STATUS_SUCCESS,
+       .expect_param = set_le_settings_param_2,
+       .expect_len = sizeof(set_le_settings_param_2),
+       .expect_hci_command = BT_HCI_CMD_LE_SET_ADV_PARAMETERS,
+       .expect_hci_param = set_connectable_off_adv_param,
+       .expect_hci_len = sizeof(set_connectable_off_adv_param),
+};
+
+static const char set_powered_off_le_settings_param[] = {
+       0x80, 0x02, 0x00, 0x00
+};
+
+static const struct generic_data add_advertising_timeout_power_off = {
+       .send_opcode = MGMT_OP_SET_POWERED,
+       .send_param = set_powered_off_param,
+       .send_len = sizeof(set_powered_off_param),
+       .expect_status = MGMT_STATUS_SUCCESS,
+       .expect_param = set_powered_off_le_settings_param,
+       .expect_len = sizeof(set_powered_off_le_settings_param),
+       .expect_alt_ev = MGMT_EV_ADVERTISING_REMOVED,
+       .expect_alt_ev_param = advertising_instance_param,
+       .expect_alt_ev_len = sizeof(advertising_instance_param),
+};
+
+static const uint8_t remove_advertising_param_1[] = {
+       0x01,
+};
+
+static const uint8_t remove_advertising_param_2[] = {
+       0x00,
+};
+
+static const struct generic_data remove_advertising_fail_1 = {
+       .send_opcode = MGMT_OP_REMOVE_ADVERTISING,
+       .send_param = remove_advertising_param_1,
+       .send_len = sizeof(remove_advertising_param_1),
+       .expect_status = MGMT_STATUS_INVALID_PARAMS,
+};
+
+static const struct generic_data remove_advertising_success_1 = {
+       .send_opcode = MGMT_OP_REMOVE_ADVERTISING,
+       .send_param = remove_advertising_param_1,
+       .send_len = sizeof(remove_advertising_param_1),
+       .expect_status = MGMT_STATUS_SUCCESS,
+       .expect_param = remove_advertising_param_1,
+       .expect_len = sizeof(remove_advertising_param_1),
+       .expect_alt_ev = MGMT_EV_ADVERTISING_REMOVED,
+       .expect_alt_ev_param = advertising_instance_param,
+       .expect_alt_ev_len = sizeof(advertising_instance_param),
+       .expect_hci_command = BT_HCI_CMD_LE_SET_ADV_ENABLE,
+       .expect_hci_param = set_adv_off_param,
+       .expect_hci_len = sizeof(set_adv_off_param),
+};
+
+static const struct generic_data remove_advertising_success_2 = {
+       .send_opcode = MGMT_OP_REMOVE_ADVERTISING,
+       .send_param = remove_advertising_param_2,
+       .send_len = sizeof(remove_advertising_param_2),
+       .expect_status = MGMT_STATUS_SUCCESS,
+       .expect_param = remove_advertising_param_1,
+       .expect_len = sizeof(remove_advertising_param_1),
+       .expect_alt_ev = MGMT_EV_ADVERTISING_REMOVED,
+       .expect_alt_ev_param = advertising_instance_param,
+       .expect_alt_ev_len = sizeof(advertising_instance_param),
+       .expect_hci_command = BT_HCI_CMD_LE_SET_ADV_ENABLE,
+       .expect_hci_param = set_adv_off_param,
+       .expect_hci_len = sizeof(set_adv_off_param),
+};
+
+static const struct generic_data read_local_oob_not_powered_test = {
+       .send_opcode = MGMT_OP_READ_LOCAL_OOB_DATA,
+       .expect_status = MGMT_STATUS_NOT_POWERED,
+};
+
+static const struct generic_data read_local_oob_invalid_param_test = {
+       .send_opcode = MGMT_OP_READ_LOCAL_OOB_DATA,
+       .send_param = dummy_data,
+       .send_len = sizeof(dummy_data),
+       .expect_status = MGMT_STATUS_INVALID_PARAMS,
+};
+
+static const struct generic_data read_local_oob_invalid_index_test = {
+       .send_index_none = true,
+       .send_opcode = MGMT_OP_READ_LOCAL_OOB_DATA,
+       .expect_status = MGMT_STATUS_INVALID_INDEX,
+};
+
+static const struct generic_data read_local_oob_legacy_pairing_test = {
+       .setup_settings = settings_powered,
+       .send_opcode = MGMT_OP_READ_LOCAL_OOB_DATA,
+       .expect_status = MGMT_STATUS_NOT_SUPPORTED,
+};
+
+static const struct generic_data read_local_oob_success_ssp_test = {
+       .setup_settings = settings_powered_ssp,
+       .send_opcode = MGMT_OP_READ_LOCAL_OOB_DATA,
+       .expect_status = MGMT_STATUS_SUCCESS,
+       .expect_ignore_param = true,
+       .expect_hci_command = BT_HCI_CMD_READ_LOCAL_OOB_DATA,
+};
+
+static const struct generic_data read_local_oob_success_sc_test = {
+       .setup_settings = settings_powered_sc,
+       .send_opcode = MGMT_OP_READ_LOCAL_OOB_DATA,
+       .expect_status = MGMT_STATUS_SUCCESS,
+       .expect_ignore_param = true,
+       .expect_hci_command = BT_HCI_CMD_READ_LOCAL_OOB_EXT_DATA,
+};
+
 static void client_cmd_complete(uint16_t opcode, uint8_t status,
                                        const void *param, uint8_t len,
                                        void *user_data)
@@ -4098,6 +4843,199 @@ static void setup_add_device(const void *test_data)
                                        setup_powered_callback, NULL, NULL);
 }
 
+static void setup_add_advertising_callback(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       if (status != MGMT_STATUS_SUCCESS) {
+               tester_setup_failed();
+               return;
+       }
+
+       tester_print("Add Advertising setup complete");
+
+       setup_bthost();
+}
+
+static void setup_add_advertising_not_powered(const void *test_data)
+{
+       struct test_data *data = tester_get_data();
+       struct mgmt_cp_add_advertising *cp;
+       unsigned char adv_param[sizeof(*cp) + 6];
+       unsigned char param[] = { 0x01 };
+
+       tester_print("Adding advertising instance while unpowered");
+
+       cp = (struct mgmt_cp_add_advertising *) adv_param;
+       memset(cp, 0, sizeof(*cp));
+
+       cp->instance = 1;
+       cp->adv_data_len = 6;
+       cp->data[0] = 0x05;
+       cp->data[1] = 0x08;
+       cp->data[2] = 't';
+       cp->data[3] = 'e';
+       cp->data[4] = 's';
+       cp->data[5] = 't';
+
+       mgmt_send(data->mgmt, MGMT_OP_SET_LE, data->mgmt_index,
+                                               sizeof(param), &param,
+                                               NULL, NULL, NULL);
+
+       mgmt_send(data->mgmt, MGMT_OP_ADD_ADVERTISING, data->mgmt_index,
+                                               sizeof(adv_param), adv_param,
+                                               setup_add_advertising_callback,
+                                               NULL, NULL);
+}
+
+static void setup_add_advertising(const void *test_data)
+{
+       struct test_data *data = tester_get_data();
+       struct mgmt_cp_add_advertising *cp;
+       unsigned char adv_param[sizeof(*cp) + 6];
+       unsigned char param[] = { 0x01 };
+
+       tester_print("Adding advertising instance while unpowered");
+
+       cp = (struct mgmt_cp_add_advertising *) adv_param;
+       memset(cp, 0, sizeof(*cp));
+
+       cp->instance = 1;
+       cp->adv_data_len = 6;
+       cp->data[0] = 0x05;
+       cp->data[1] = 0x08;
+       cp->data[2] = 't';
+       cp->data[3] = 'e';
+       cp->data[4] = 's';
+       cp->data[5] = 't';
+
+       mgmt_send(data->mgmt, MGMT_OP_SET_LE, data->mgmt_index,
+                                               sizeof(param), &param,
+                                               NULL, NULL, NULL);
+
+       mgmt_send(data->mgmt, MGMT_OP_SET_POWERED, data->mgmt_index,
+                                               sizeof(param), &param,
+                                               NULL, NULL, NULL);
+
+       mgmt_send(data->mgmt, MGMT_OP_ADD_ADVERTISING, data->mgmt_index,
+                                               sizeof(adv_param), adv_param,
+                                               setup_add_advertising_callback,
+                                               NULL, NULL);
+}
+
+static void setup_add_advertising_connectable(const void *test_data)
+{
+       struct test_data *data = tester_get_data();
+       struct mgmt_cp_add_advertising *cp;
+       unsigned char adv_param[sizeof(*cp) + 6];
+       unsigned char param[] = { 0x01 };
+
+       tester_print("Adding advertising instance while unpowered");
+
+       cp = (struct mgmt_cp_add_advertising *) adv_param;
+       memset(cp, 0, sizeof(*cp));
+
+       cp->instance = 1;
+       cp->adv_data_len = 6;
+       cp->data[0] = 0x05;
+       cp->data[1] = 0x08;
+       cp->data[2] = 't';
+       cp->data[3] = 'e';
+       cp->data[4] = 's';
+       cp->data[5] = 't';
+
+       mgmt_send(data->mgmt, MGMT_OP_SET_LE, data->mgmt_index,
+                                               sizeof(param), &param,
+                                               NULL, NULL, NULL);
+
+       mgmt_send(data->mgmt, MGMT_OP_SET_POWERED, data->mgmt_index,
+                                               sizeof(param), &param,
+                                               NULL, NULL, NULL);
+
+       mgmt_send(data->mgmt, MGMT_OP_SET_CONNECTABLE, data->mgmt_index,
+                                               sizeof(param), &param,
+                                               NULL, NULL, NULL);
+
+       mgmt_send(data->mgmt, MGMT_OP_ADD_ADVERTISING, data->mgmt_index,
+                                               sizeof(adv_param), adv_param,
+                                               setup_add_advertising_callback,
+                                               NULL, NULL);
+}
+
+static void setup_add_advertising_timeout(const void *test_data)
+{
+       struct test_data *data = tester_get_data();
+       struct mgmt_cp_add_advertising *cp;
+       unsigned char adv_param[sizeof(*cp) + 6];
+       unsigned char param[] = { 0x01 };
+
+       tester_print("Adding advertising instance while unpowered");
+
+       cp = (struct mgmt_cp_add_advertising *) adv_param;
+       memset(cp, 0, sizeof(*cp));
+
+       cp->instance = 1;
+       cp->timeout = 5;
+       cp->adv_data_len = 6;
+       cp->data[0] = 0x05;
+       cp->data[1] = 0x08;
+       cp->data[2] = 't';
+       cp->data[3] = 'e';
+       cp->data[4] = 's';
+       cp->data[5] = 't';
+
+       mgmt_send(data->mgmt, MGMT_OP_SET_LE, data->mgmt_index,
+                                               sizeof(param), &param,
+                                               NULL, NULL, NULL);
+
+       mgmt_send(data->mgmt, MGMT_OP_SET_POWERED, data->mgmt_index,
+                                               sizeof(param), &param,
+                                               NULL, NULL, NULL);
+
+       mgmt_send(data->mgmt, MGMT_OP_ADD_ADVERTISING, data->mgmt_index,
+                                               sizeof(adv_param), adv_param,
+                                               setup_add_advertising_callback,
+                                               NULL, NULL);
+}
+
+static void setup_set_and_add_advertising(const void *test_data)
+{
+       struct test_data *data = tester_get_data();
+       struct mgmt_cp_add_advertising *cp;
+       unsigned char adv_param[sizeof(*cp) + 6];
+       unsigned char param[] = { 0x01 };
+
+       tester_print("Adding advertising instance while unpowered");
+
+       cp = (struct mgmt_cp_add_advertising *) adv_param;
+       memset(cp, 0, sizeof(*cp));
+
+       cp->instance = 1;
+       cp->adv_data_len = 6;
+       cp->data[0] = 0x05;
+       cp->data[1] = 0x08;
+       cp->data[2] = 't';
+       cp->data[3] = 'e';
+       cp->data[4] = 's';
+       cp->data[5] = 't';
+
+       mgmt_send(data->mgmt, MGMT_OP_SET_LE, data->mgmt_index,
+                                               sizeof(param), &param,
+                                               NULL, NULL, NULL);
+
+       mgmt_send(data->mgmt, MGMT_OP_SET_POWERED, data->mgmt_index,
+                                               sizeof(param), &param,
+                                               NULL, NULL, NULL);
+
+       mgmt_send(data->mgmt, MGMT_OP_SET_ADVERTISING, data->mgmt_index,
+                                               sizeof(param), &param,
+                                               NULL, NULL, NULL);
+
+       mgmt_send(data->mgmt, MGMT_OP_ADD_ADVERTISING, data->mgmt_index,
+                                               sizeof(adv_param), adv_param,
+                                               setup_add_advertising_callback,
+                                               NULL, NULL);
+}
+
 static void setup_complete(uint8_t status, uint16_t length,
                                        const void *param, void *user_data)
 {
@@ -4402,18 +5340,20 @@ static void command_generic_callback(uint8_t status, uint16_t length,
                return;
        }
 
-       if (test->expect_func)
-               expect_param = test->expect_func(&expect_len);
+       if (!test->expect_ignore_param) {
+               if (test->expect_func)
+                       expect_param = test->expect_func(&expect_len);
 
-       if (length != expect_len) {
-               tester_test_failed();
-               return;
-       }
+               if (length != expect_len) {
+                       tester_test_failed();
+                       return;
+               }
 
-       if (expect_param && expect_len > 0 &&
-                               memcmp(param, expect_param, length)) {
-               tester_test_failed();
-               return;
+               if (expect_param && expect_len > 0 &&
+                                       memcmp(param, expect_param, length)) {
+                       tester_test_failed();
+                       return;
+               }
        }
 
        test_condition_complete(data);
@@ -4679,6 +5619,24 @@ int main(int argc, char *argv[])
        test_bredrle("Read info - Invalid index",
                                &read_info_invalid_index_test,
                                NULL, test_command_generic);
+       test_bredrle("Read unconfigured index list - Invalid parameters",
+                               &read_unconf_index_list_invalid_param_test,
+                               NULL, test_command_generic);
+       test_bredrle("Read unconfigured index list - Invalid index",
+                               &read_unconf_index_list_invalid_index_test,
+                               NULL, test_command_generic);
+       test_bredrle("Read configuration info - Invalid parameters",
+                               &read_config_info_invalid_param_test,
+                               NULL, test_command_generic);
+       test_bredrle("Read configuration info - Invalid index",
+                               &read_config_info_invalid_index_test,
+                               NULL, test_command_generic);
+       test_bredrle("Read extended index list - Invalid parameters",
+                               &read_ext_index_list_invalid_param_test,
+                               NULL, test_command_generic);
+       test_bredrle("Read extended index list - Invalid index",
+                               &read_ext_index_list_invalid_index_test,
+                               NULL, test_command_generic);
 
        test_bredrle("Set powered on - Success",
                                &set_powered_on_success_test,
@@ -4770,6 +5728,15 @@ int main(int argc, char *argv[])
        test_bredrle("Set fast connectable on - Success 1",
                                &set_fast_conn_on_success_test_1,
                                NULL, test_command_generic);
+       test_bredrle("Set fast connectable on - Success 2",
+                               &set_fast_conn_on_success_test_2,
+                               NULL, test_command_generic);
+       test_bredrle("Set fast connectable on - Success 3",
+                               &set_fast_conn_on_success_test_3,
+                               NULL, test_command_generic);
+       test_bredrle("Set fast connectable on - Invalid Params 1",
+                               &set_fast_conn_nval_param_test_1,
+                               NULL, test_command_generic);
        test_le("Set fast connectable on - Not Supported 1",
                                &set_fast_conn_on_not_supported_test_1,
                                NULL, test_command_generic);
@@ -5411,5 +6378,141 @@ int main(int argc, char *argv[])
                                &remove_device_success_5,
                                setup_add_device, test_command_generic);
 
+       test_bredrle("Read Advertising Features - Invalid parameters",
+                               &read_adv_features_invalid_param_test,
+                               NULL, test_command_generic);
+       test_bredrle("Read Advertising Features - Invalid index",
+                               &read_adv_features_invalid_index_test,
+                               NULL, test_command_generic);
+
+       test_bredrle("Add Advertising - Failure: LE off",
+                                       &add_advertising_fail_1,
+                                       NULL, test_command_generic);
+       test_bredrle("Add Advertising - Invalid Params 1 (AD too long)",
+                                       &add_advertising_fail_2,
+                                       NULL, test_command_generic);
+       test_bredrle("Add Advertising - Invalid Params 2 (Malformed len)",
+                                       &add_advertising_fail_3,
+                                       NULL, test_command_generic);
+       test_bredrle("Add Advertising - Invalid Params 3 (Malformed len)",
+                                       &add_advertising_fail_4,
+                                       NULL, test_command_generic);
+       test_bredrle("Add Advertising - Invalid Params 4 (Malformed len)",
+                                       &add_advertising_fail_5,
+                                       NULL, test_command_generic);
+       test_le("Add Advertising - Invalid Params 5 (AD too long)",
+                                       &add_advertising_fail_6,
+                                       NULL, test_command_generic);
+       test_bredrle("Add Advertising - Invalid Params 6 (ScRsp too long)",
+                                       &add_advertising_fail_7,
+                                       NULL, test_command_generic);
+       test_bredrle("Add Advertising - Invalid Params 7 (Malformed len)",
+                                       &add_advertising_fail_8,
+                                       NULL, test_command_generic);
+       test_bredrle("Add Advertising - Invalid Params 8 (Malformed len)",
+                                       &add_advertising_fail_9,
+                                       NULL, test_command_generic);
+       test_bredrle("Add Advertising - Invalid Params 9 (Malformed len)",
+                                       &add_advertising_fail_10,
+                                       NULL, test_command_generic);
+       test_le("Add Advertising - Invalid Params 10 (ScRsp too long)",
+                                       &add_advertising_fail_11,
+                                       NULL, test_command_generic);
+       test_bredrle("Add Advertising - Timeout Not Powered",
+                                       &add_advertising_fail_12,
+                                       NULL, test_command_generic);
+       test_bredrle("Add Advertising - Timeout Power off",
+                                       &add_advertising_timeout_power_off,
+                                       setup_add_advertising_timeout,
+                                       test_command_generic);
+       test_bredrle("Add Advertising - Success 1",
+                                       &add_advertising_success_1,
+                                       NULL, test_command_generic);
+       test_bredrle("Add Advertising - Success 2",
+                                       &add_advertising_success_2,
+                                       setup_add_advertising_not_powered,
+                                       test_command_generic);
+       test_bredrle("Add Advertising - Success 3",
+                                       &add_advertising_success_3,
+                                       setup_add_advertising_not_powered,
+                                       test_command_generic);
+       test_bredrle("Add Advertising - Set Advertising on override 1",
+                                       &add_advertising_success_4,
+                                       setup_add_advertising,
+                                       test_command_generic);
+       test_bredrle("Add Advertising - Set Advertising off override 2",
+                                       &add_advertising_success_5,
+                                       setup_set_and_add_advertising,
+                                       test_command_generic);
+       test_bredrle("Add Advertising - Success 4",
+                                       &add_advertising_success_6,
+                                       NULL, test_command_generic);
+       test_bredrle("Add Advertising - Success 5",
+                                       &add_advertising_success_7,
+                                       NULL, test_command_generic);
+       test_bredrle("Add Advertising - Success 6 - Flag 0",
+                                       &add_advertising_success_8,
+                                       NULL, test_command_generic);
+       test_bredrle("Add Advertising - Success 7 - Flag 1",
+                                       &add_advertising_success_9,
+                                       NULL, test_command_generic);
+       test_bredrle("Add Advertising - Success 8 - Flag 2",
+                                       &add_advertising_success_10,
+                                       NULL, test_command_generic);
+       test_bredrle("Add Advertising - Success 8 - Flag 3",
+                                       &add_advertising_success_11,
+                                       NULL, test_command_generic);
+       test_bredrle("Add Advertising - Success 9 - Flag 4",
+                                       &add_advertising_success_12,
+                                       NULL, test_command_generic);
+       test_bredrle("Add Advertising - Success 10 - ADV_SCAN_IND",
+                                       &add_advertising_success_13,
+                                       NULL, test_command_generic);
+       test_bredrle("Add Advertising - Success 11 - ADV_NONCONN_IND",
+                                       &add_advertising_success_14,
+                                       NULL, test_command_generic);
+       test_bredrle("Add Advertising - Success 12 - ADV_IND",
+                                       &add_advertising_success_15,
+                                       NULL, test_command_generic);
+       test_bredrle("Add Advertising - Success 13 - connectable -> on",
+                                       &add_advertising_success_16,
+                                       setup_add_advertising,
+                                       test_command_generic);
+       test_bredrle("Add Advertising - Success 14 - connectable -> off",
+                                       &add_advertising_success_17,
+                                       setup_add_advertising_connectable,
+                                       test_command_generic);
+
+       test_bredrle("Remove Advertising - Invalid Params 1",
+                                       &remove_advertising_fail_1,
+                                       NULL, test_command_generic);
+       test_bredrle("Remove Advertising - Success 1",
+                                               &remove_advertising_success_1,
+                                               setup_add_advertising,
+                                               test_command_generic);
+       test_bredrle("Remove Advertising - Success 2",
+                                               &remove_advertising_success_2,
+                                               setup_add_advertising,
+                                               test_command_generic);
+
+       test_bredrle("Read Local OOB Data - Not powered",
+                               &read_local_oob_not_powered_test,
+                               NULL, test_command_generic);
+       test_bredrle("Read Local OOB Data - Invalid parameters",
+                               &read_local_oob_invalid_param_test,
+                               NULL, test_command_generic);
+       test_bredrle("Read Local OOB Data - Invalid index",
+                               &read_local_oob_invalid_index_test,
+                               NULL, test_command_generic);
+       test_bredr20("Read Local OOB Data - Legacy pairing",
+                               &read_local_oob_legacy_pairing_test,
+                               NULL, test_command_generic);
+       test_bredrle("Read Local OOB Data - Success SSP",
+                               &read_local_oob_success_ssp_test,
+                               NULL, test_command_generic);
+       test_bredrle("Read Local OOB Data - Success SC",
+                               &read_local_oob_success_sc_test,
+                               NULL, test_command_generic);
+
        return tester_run();
 }
index 9cc6c16..e77320b 100644 (file)
 #include "src/shared/mainloop.h"
 #include "src/shared/util.h"
 #include "src/shared/mgmt.h"
+#include "src/shared/crypto.h"
+
+#define REMOTE_IRK     "\x69\x30\xde\xc3\x8f\x84\x74\x14" \
+                       "\xe1\x23\x99\xc1\xca\x9a\xc3\x31"
 
 static bool use_bredr = false;
 static bool use_le = false;
@@ -41,16 +45,21 @@ static bool use_sc = false;
 static bool use_sconly = false;
 static bool use_legacy = false;
 static bool use_random = false;
+static bool use_privacy = false;
 static bool use_debug = false;
 static bool use_cross = false;
+static bool provide_tk = false;
 static bool provide_p192 = false;
 static bool provide_p256 = false;
+static bool provide_initiator = false;
+static bool provide_acceptor = false;
 
 static struct mgmt *mgmt;
 static uint16_t index1 = MGMT_INDEX_NONE;
 static uint16_t index2 = MGMT_INDEX_NONE;
 static bdaddr_t bdaddr1;
 static bdaddr_t bdaddr2;
+static uint8_t oob_tk[16];
 
 static void pin_code_request_event(uint16_t index, uint16_t len,
                                        const void *param, void *user_data)
@@ -254,9 +263,12 @@ static void add_remote_oob_data(uint16_t index, const bdaddr_t *bdaddr,
                cp.addr.type = BDADDR_LE_RANDOM;
        else
                cp.addr.type = BDADDR_LE_PUBLIC;
-       if (hash192 && rand192) {
+       if (hash192) {
                memcpy(cp.hash192, hash192, 16);
-               memcpy(cp.rand192, rand192, 16);
+               if (rand192)
+                       memcpy(cp.rand192, rand192, 16);
+               else
+                       memset(cp.rand192, 0, 16);
        } else {
                memset(cp.hash192, 0, 16);
                memset(cp.rand192, 0, 16);
@@ -277,7 +289,7 @@ static void add_remote_oob_data(uint16_t index, const bdaddr_t *bdaddr,
 static void read_oob_data_complete(uint8_t status, uint16_t len,
                                        const void *param, void *user_data)
 {
-       const struct mgmt_rp_read_local_oob_ext_data *rp = param;
+       const struct mgmt_rp_read_local_oob_data *rp = param;
        uint16_t index = PTR_TO_UINT(user_data);
        const uint8_t *hash192, *rand192, *hash256, *rand256;
        int i;
@@ -291,12 +303,22 @@ static void read_oob_data_complete(uint8_t status, uint16_t len,
 
        printf("[Index %u]\n", index);
 
+       hash192 = NULL;
+       rand192 = NULL;
+       hash256 = NULL;
+       rand256 = NULL;
+
+       if (index == index1 && !provide_initiator) {
+               printf("  Skipping initiator OOB data\n");
+               goto done;
+       } else if (index == index2 && !provide_acceptor) {
+               printf("  Skipping acceptor OOB data\n");
+               goto done;
+       }
+
        if (provide_p192) {
                hash192 = rp->hash192;
-               rand192 = rp->randomizer192;
-       } else {
-               hash192 = NULL;
-               rand192 = NULL;
+               rand192 = rp->rand192;
        }
 
        printf("  Hash C from P-192: ");
@@ -306,21 +328,15 @@ static void read_oob_data_complete(uint8_t status, uint16_t len,
 
        printf("  Randomizer R with P-192: ");
        for (i = 0; i < 16; i++)
-               printf("%02x", rp->randomizer192[i]);
+               printf("%02x", rp->rand192[i]);
        printf("\n");
 
-       if (len < sizeof(*rp)) {
-               hash256 = NULL;
-               rand256 = NULL;
+       if (len < sizeof(*rp))
                goto done;
-       }
 
        if (provide_p256) {
                hash256 = rp->hash256;
-               rand256 = rp->randomizer256;
-       } else {
-               hash256 = NULL;
-               rand256 = NULL;
+               rand256 = rp->rand256;
        }
 
        printf("  Hash C from P-256: ");
@@ -330,7 +346,7 @@ static void read_oob_data_complete(uint8_t status, uint16_t len,
 
        printf("  Randomizer R with P-256: ");
        for (i = 0; i < 16; i++)
-               printf("%02x", rp->randomizer256[i]);
+               printf("%02x", rp->rand256[i]);
        printf("\n");
 
 done:
@@ -342,6 +358,105 @@ done:
                                        hash192, rand192, hash256, rand256);
 }
 
+static void read_oob_ext_data_complete(uint8_t status, uint16_t len,
+                                       const void *param, void *user_data)
+{
+       const struct mgmt_rp_read_local_oob_ext_data *rp = param;
+       uint16_t index = PTR_TO_UINT(user_data);
+       uint16_t eir_len, parsed;
+       const uint8_t *eir, *tk, *hash256, *rand256;
+       int i;
+
+       if (status) {
+               fprintf(stderr, "Reading OOB data for index %u failed: %s\n",
+                                               index, mgmt_errstr(status));
+               mainloop_quit();
+               return;
+       }
+
+       printf("[Index %u]\n", index);
+
+       eir_len = le16_to_cpu(rp->eir_len);
+       printf("  OOB data len: %u\n", eir_len);
+
+       if (provide_tk)
+               tk = oob_tk;
+       else
+               tk = NULL;
+
+       hash256 = NULL;
+       rand256 = NULL;
+
+       if (index == index1 && !provide_initiator) {
+               printf("  Skipping initiator OOB data\n");
+               goto done;
+       } else if (index == index2 && !provide_acceptor) {
+               printf("  Skipping acceptor OOB data\n");
+               goto done;
+       }
+
+       if (eir_len < 2)
+               goto done;
+
+       eir = rp->eir;
+       parsed = 0;
+
+       while (parsed < eir_len - 1) {
+               uint8_t field_len = eir[0];
+
+               if (field_len == 0)
+                       break;
+
+               parsed += field_len + 1;
+
+               if (parsed > eir_len)
+                       break;
+
+               /* LE Bluetooth Device Address */
+               if (eir[1] == 0x1b) {
+                       char str[18];
+
+                       ba2str((bdaddr_t *) (eir + 2), str);
+                       printf("  Device address: %s (%s)\n", str,
+                                               eir[8] ? "random" : "public");
+               }
+
+               /* LE Role */
+               if (eir[1] == 0x1c)
+                       printf("  Role: 0x%02x\n", eir[2]);
+
+               /* LE Secure Connections Confirmation Value */
+               if (eir[1] == 0x22) {
+                       hash256 = eir + 2;
+
+                       printf("  Hash C from P-256: ");
+                       for (i = 0; i < 16; i++)
+                               printf("%02x", hash256[i]);
+                       printf("\n");
+               }
+
+               /* LE Secure Connections Random Value */
+               if (eir[1] == 0x23) {
+                       rand256 = eir + 2;
+
+                       printf("  Randomizer R with P-256: ");
+                       for (i = 0; i < 16; i++)
+                               printf("%02x", rand256[i]);
+                       printf("\n");
+               }
+
+               eir += field_len + 1;
+       }
+
+done:
+       if (index == index1)
+               add_remote_oob_data(index2, &bdaddr1,
+                                       tk, NULL, hash256, rand256);
+       else if (index == index2)
+               add_remote_oob_data(index1, &bdaddr2,
+                                       tk, NULL, hash256, rand256);
+}
+
 static void set_powered_complete(uint8_t status, uint16_t len,
                                        const void *param, void *user_data)
 {
@@ -380,6 +495,23 @@ static void set_powered_complete(uint8_t status, uint16_t len,
                mgmt_send(mgmt, MGMT_OP_READ_LOCAL_OOB_DATA, index, 0, NULL,
                                                read_oob_data_complete,
                                                UINT_TO_PTR(index), NULL);
+       } else if (use_le && provide_p256) {
+               uint8_t type = (1 << BDADDR_LE_PUBLIC) |
+                                               (1 << BDADDR_LE_RANDOM);
+
+               mgmt_send(mgmt, MGMT_OP_READ_LOCAL_OOB_EXT_DATA, index,
+                                               sizeof(type), &type,
+                                               read_oob_ext_data_complete,
+                                               UINT_TO_PTR(index), NULL);
+       } else if (use_le && provide_tk) {
+               const uint8_t *tk = oob_tk;
+
+               if (index == index1)
+                       add_remote_oob_data(index2, &bdaddr1,
+                                               tk, NULL, NULL, NULL);
+               else if (index == index2)
+                       add_remote_oob_data(index1, &bdaddr2,
+                                               tk, NULL, NULL, NULL);
        } else {
                if (index == index1)
                        add_remote_oob_data(index2, &bdaddr1,
@@ -413,6 +545,17 @@ static void clear_long_term_keys(uint16_t index)
                                        sizeof(cp), &cp, NULL, NULL, NULL);
 }
 
+static void clear_identity_resolving_keys(uint16_t index)
+{
+       struct mgmt_cp_load_irks cp;
+
+       memset(&cp, 0, sizeof(cp));
+       cp.irk_count = cpu_to_le16(0);
+
+       mgmt_send(mgmt, MGMT_OP_LOAD_IRKS, index,
+                                       sizeof(cp), &cp, NULL, NULL, NULL);
+}
+
 static void clear_remote_oob_data(uint16_t index)
 {
        struct mgmt_cp_remove_remote_oob_data cp;
@@ -425,6 +568,123 @@ static void clear_remote_oob_data(uint16_t index)
                                        sizeof(cp), &cp, NULL, NULL, NULL);
 }
 
+static void set_powered_down_complete(uint8_t status, uint16_t len,
+                                       const void *param, void *user_data)
+{
+       uint16_t index = PTR_TO_UINT(user_data);
+
+       if (status) {
+               fprintf(stderr, "Power down for index %u failed: %s\n",
+                                               index, mgmt_errstr(status));
+               mainloop_quit();
+               return;
+       }
+}
+
+static void set_bredr_complete(uint8_t status, uint16_t len,
+                                       const void *param, void *user_data)
+{
+       uint16_t index = PTR_TO_UINT(user_data);
+
+       if (status) {
+               fprintf(stderr, "Setting BR/EDR for index %u failed: %s\n",
+                                               index, mgmt_errstr(status));
+               mainloop_quit();
+               return;
+       }
+}
+
+static void set_le_complete(uint8_t status, uint16_t len,
+                                       const void *param, void *user_data)
+{
+       uint16_t index = PTR_TO_UINT(user_data);
+
+       if (status) {
+               fprintf(stderr, "Setting LE for index %u failed: %s\n",
+                                               index, mgmt_errstr(status));
+               mainloop_quit();
+               return;
+       }
+}
+
+static void set_ssp_complete(uint8_t status, uint16_t len,
+                                       const void *param, void *user_data)
+{
+       uint16_t index = PTR_TO_UINT(user_data);
+
+       if (status) {
+               fprintf(stderr, "Simple Pairing for index %u failed: %s\n",
+                                               index, mgmt_errstr(status));
+               mainloop_quit();
+               return;
+       }
+}
+
+static void set_static_address_complete(uint8_t status, uint16_t len,
+                                       const void *param, void *user_data)
+{
+       uint16_t index = PTR_TO_UINT(user_data);
+
+       if (status) {
+               fprintf(stderr, "Static address for index %u failed: %s\n",
+                                               index, mgmt_errstr(status));
+               mainloop_quit();
+               return;
+       }
+}
+
+static void set_secure_conn_complete(uint8_t status, uint16_t len,
+                                       const void *param, void *user_data)
+{
+       uint16_t index = PTR_TO_UINT(user_data);
+
+       if (status) {
+               fprintf(stderr, "Secure connections for index %u failed: %s\n",
+                                               index, mgmt_errstr(status));
+               mainloop_quit();
+               return;
+       }
+}
+
+static void set_privacy_complete(uint8_t status, uint16_t len,
+                                       const void *param, void *user_data)
+{
+       uint16_t index = PTR_TO_UINT(user_data);
+
+       if (status) {
+               fprintf(stderr, "Setting privacy for index %u failed: %s\n",
+                                               index, mgmt_errstr(status));
+               mainloop_quit();
+               return;
+       }
+}
+
+static void set_debug_keys_complete(uint8_t status, uint16_t len,
+                                       const void *param, void *user_data)
+{
+       uint16_t index = PTR_TO_UINT(user_data);
+
+       if (status) {
+               fprintf(stderr, "Setting debug keys for index %u failed: %s\n",
+                                               index, mgmt_errstr(status));
+               mainloop_quit();
+               return;
+       }
+}
+
+static void set_bondable_complete(uint8_t status, uint16_t len,
+                                       const void *param, void *user_data)
+{
+       uint16_t index = PTR_TO_UINT(user_data);
+
+       if (status) {
+               fprintf(stderr, "Setting bondable for index %u failed: %s\n",
+                                               index, mgmt_errstr(status));
+               mainloop_quit();
+               return;
+       }
+}
+
 static void read_info(uint8_t status, uint16_t len, const void *param,
                                                        void *user_data)
 {
@@ -483,6 +743,12 @@ static void read_info(uint8_t status, uint16_t len, const void *param,
                return;
        }
 
+       if (use_privacy && !(supported_settings & MGMT_SETTING_PRIVACY)) {
+               fprintf(stderr, "Privacy support missing\n");
+               mainloop_quit();
+               return;
+       }
+
        if (use_debug && !(supported_settings & MGMT_SETTING_DEBUG_KEYS)) {
                fprintf(stderr, "Debug keys support missing\n");
                mainloop_quit();
@@ -496,6 +762,16 @@ static void read_info(uint8_t status, uint16_t len, const void *param,
                return;
        }
 
+       if (provide_tk) {
+               const uint8_t *tk = oob_tk;
+               int i;
+
+               printf("  TK Value: ");
+               for (i = 0; i < 16; i++)
+                       printf("%02x", tk[i]);
+               printf("\n");
+       }
+
        mgmt_register(mgmt, MGMT_EV_PIN_CODE_REQUEST, index,
                                                pin_code_request_event,
                                                UINT_TO_PTR(index), NULL);
@@ -510,32 +786,46 @@ static void read_info(uint8_t status, uint16_t len, const void *param,
 
        val = 0x00;
        mgmt_send(mgmt, MGMT_OP_SET_POWERED, index, 1, &val,
-                                               NULL, NULL, NULL);
+                                               set_powered_down_complete,
+                                               UINT_TO_PTR(index), NULL);
 
        clear_link_keys(index);
        clear_long_term_keys(index);
+       clear_identity_resolving_keys(index);
        clear_remote_oob_data(index);
 
        if (use_bredr) {
                val = 0x01;
                mgmt_send(mgmt, MGMT_OP_SET_BREDR, index, 1, &val,
-                                                       NULL, NULL, NULL);
+                                               set_bredr_complete,
+                                               UINT_TO_PTR(index), NULL);
 
                val = use_cross ? 0x01 : 0x00;
                mgmt_send(mgmt, MGMT_OP_SET_LE, index, 1, &val,
-                                                       NULL, NULL, NULL);
+                                               set_le_complete,
+                                               UINT_TO_PTR(index), NULL);
 
                val = use_legacy ? 0x00 : 0x01;
                mgmt_send(mgmt, MGMT_OP_SET_SSP, index, 1, &val,
-                                                       NULL, NULL, NULL);
+                                               set_ssp_complete,
+                                               UINT_TO_PTR(index), NULL);
        } else if (use_le) {
                val = 0x01;
                mgmt_send(mgmt, MGMT_OP_SET_LE, index, 1, &val,
-                                                       NULL, NULL, NULL);
+                                               set_le_complete,
+                                               UINT_TO_PTR(index), NULL);
 
                val = use_cross ? 0x01 : 0x00;
                mgmt_send(mgmt, MGMT_OP_SET_BREDR, index, 1, &val,
-                                                       NULL, NULL, NULL);
+                                               set_bredr_complete,
+                                               UINT_TO_PTR(index), NULL);
+
+               if (use_cross) {
+                       val = use_legacy ? 0x00 : 0x01;
+                       mgmt_send(mgmt, MGMT_OP_SET_SSP, index, 1, &val,
+                                               set_ssp_complete,
+                                               UINT_TO_PTR(index), NULL);
+               }
        } else {
                fprintf(stderr, "Invalid transport for pairing\n");
                mainloop_quit();
@@ -548,8 +838,9 @@ static void read_info(uint8_t status, uint16_t len, const void *param,
                str2ba("c0:00:aa:bb:00:00", &bdaddr);
                bdaddr.b[0] = index;
 
-               mgmt_send(mgmt, MGMT_OP_SET_STATIC_ADDRESS, index,
-                                               6, &bdaddr, NULL, NULL, NULL);
+               mgmt_send(mgmt, MGMT_OP_SET_STATIC_ADDRESS, index, 6, &bdaddr,
+                                               set_static_address_complete,
+                                               UINT_TO_PTR(index), NULL);
 
                if (index == index1)
                        bacpy(&bdaddr1, &bdaddr);
@@ -560,31 +851,62 @@ static void read_info(uint8_t status, uint16_t len, const void *param,
 
                bacpy(&bdaddr, BDADDR_ANY);
 
-               mgmt_send(mgmt, MGMT_OP_SET_STATIC_ADDRESS, index,
-                                               6, &bdaddr, NULL, NULL, NULL);
+               mgmt_send(mgmt, MGMT_OP_SET_STATIC_ADDRESS, index, 6, &bdaddr,
+                                               set_static_address_complete,
+                                               UINT_TO_PTR(index), NULL);
        }
 
        if (use_sc) {
                val = 0x01;
                mgmt_send(mgmt, MGMT_OP_SET_SECURE_CONN, index, 1, &val,
-                                                       NULL, NULL, NULL);
+                                               set_secure_conn_complete,
+                                               UINT_TO_PTR(index), NULL);
        } else if (use_sconly) {
                val = 0x02;
                mgmt_send(mgmt, MGMT_OP_SET_SECURE_CONN, index, 1, &val,
-                                                       NULL, NULL, NULL);
+                                               set_secure_conn_complete,
+                                               UINT_TO_PTR(index), NULL);
        } else {
                val = 0x00;
                mgmt_send(mgmt, MGMT_OP_SET_SECURE_CONN, index, 1, &val,
-                                                       NULL, NULL, NULL);
+                                               set_secure_conn_complete,
+                                               UINT_TO_PTR(index), NULL);
+       }
+
+       if (use_privacy) {
+               struct mgmt_cp_set_privacy cp;
+
+               if (index == index2) {
+                       cp.privacy = 0x01;
+                       memcpy(cp.irk, REMOTE_IRK, sizeof(cp.irk));
+               } else {
+                       cp.privacy = 0x00;
+                       memset(cp.irk, 0, sizeof(cp.irk));
+               }
+
+               mgmt_send(mgmt, MGMT_OP_SET_PRIVACY, index, sizeof(cp), &cp,
+                                               set_privacy_complete,
+                                               UINT_TO_PTR(index), NULL);
+       } else {
+               struct mgmt_cp_set_privacy cp;
+
+               cp.privacy = 0x00;
+               memset(cp.irk, 0, sizeof(cp.irk));
+
+               mgmt_send(mgmt, MGMT_OP_SET_PRIVACY, index, sizeof(cp), &cp,
+                                               set_privacy_complete,
+                                               UINT_TO_PTR(index), NULL);
        }
 
        val = 0x00;
        mgmt_send(mgmt, MGMT_OP_SET_DEBUG_KEYS, index, 1, &val,
-                                               NULL, NULL, NULL);
+                                               set_debug_keys_complete,
+                                               UINT_TO_PTR(index), NULL);
 
        val = 0x01;
        mgmt_send(mgmt, MGMT_OP_SET_BONDABLE, index, 1, &val,
-                                               NULL, NULL, NULL);
+                                               set_bondable_complete,
+                                               UINT_TO_PTR(index), NULL);
 
        val = 0x01;
        mgmt_send(mgmt, MGMT_OP_SET_POWERED, index, 1, &val,
@@ -631,6 +953,16 @@ static void read_index_list(uint8_t status, uint16_t len, const void *param,
        printf("Selecting index %u for initiator\n", index1);
        printf("Selecting index %u for acceptor\n", index2);
 
+       if (provide_tk) {
+               struct bt_crypto *crypto;
+
+               printf("Generating Security Manager TK Value\n");
+
+               crypto = bt_crypto_new();
+               bt_crypto_random_bytes(crypto, oob_tk, 16);
+               bt_crypto_unref(crypto);
+       }
+
        mgmt_send(mgmt, MGMT_OP_READ_INFO, index1, 0, NULL,
                                read_info, UINT_TO_PTR(index1), NULL);
        mgmt_send(mgmt, MGMT_OP_READ_INFO, index2, 0, NULL,
@@ -659,28 +991,36 @@ static void usage(void)
                "\t-O, --sconly           Use Secure Connections Only\n"
                "\t-P, --legacy           Use Legacy Pairing\n"
                "\t-R, --random           Use Static random address\n"
+               "\t-Y, --privacy          Use LE privacy feature\n"
                "\t-D, --debug            Use Pairing debug keys\n"
                "\t-C, --cross            Use cross-transport pairing\n"
+               "\t-0, --tk               Provide LE legacy OOB data\n"
                "\t-1, --p192             Provide P-192 OOB data\n"
                "\t-2, --p256             Provide P-256 OOB data\n"
+               "\t-I, --initiator        Initiator provides OOB data\n"
+               "\t-A, --acceptor         Acceptor provides OOB data\n"
                "\t-h, --help             Show help options\n");
 }
 
 static const struct option main_options[] = {
-       { "bredr",   no_argument,       NULL, 'B' },
-       { "le",      no_argument,       NULL, 'L' },
-       { "sc",      no_argument,       NULL, 'S' },
-       { "sconly",  no_argument,       NULL, 'O' },
-       { "legacy",  no_argument,       NULL, 'P' },
-       { "random",  no_argument,       NULL, 'R' },
-       { "static",  no_argument,       NULL, 'R' },
-       { "debug",   no_argument,       NULL, 'D' },
-       { "cross",   no_argument,       NULL, 'C' },
-       { "dual",    no_argument,       NULL, 'C' },
-       { "p192",    no_argument,       NULL, '1' },
-       { "p256",    no_argument,       NULL, '2' },
-       { "version", no_argument,       NULL, 'v' },
-       { "help",    no_argument,       NULL, 'h' },
+       { "bredr",     no_argument,       NULL, 'B' },
+       { "le",        no_argument,       NULL, 'L' },
+       { "sc",        no_argument,       NULL, 'S' },
+       { "sconly",    no_argument,       NULL, 'O' },
+       { "legacy",    no_argument,       NULL, 'P' },
+       { "random",    no_argument,       NULL, 'R' },
+       { "static",    no_argument,       NULL, 'R' },
+       { "privacy",   no_argument,       NULL, 'Y' },
+       { "debug",     no_argument,       NULL, 'D' },
+       { "cross",     no_argument,       NULL, 'C' },
+       { "dual",      no_argument,       NULL, 'C' },
+       { "tk",        no_argument,       NULL, '0' },
+       { "p192",      no_argument,       NULL, '1' },
+       { "p256",      no_argument,       NULL, '2' },
+       { "initiator", no_argument,       NULL, 'I' },
+       { "acceptor",  no_argument,       NULL, 'A' },
+       { "version",   no_argument,       NULL, 'v' },
+       { "help",      no_argument,       NULL, 'h' },
        { }
 };
 
@@ -692,7 +1032,7 @@ int main(int argc ,char *argv[])
        for (;;) {
                int opt;
 
-               opt = getopt_long(argc, argv, "BLSOPRDC12vh",
+               opt = getopt_long(argc, argv, "BLSOPRYDC012IAvh",
                                                main_options, NULL);
                if (opt < 0)
                        break;
@@ -716,18 +1056,30 @@ int main(int argc ,char *argv[])
                case 'R':
                        use_random = true;
                        break;
+               case 'Y':
+                       use_privacy = true;
+                       break;
                case 'D':
                        use_debug = true;
                        break;
                case 'C':
                        use_cross = true;
                        break;
+               case '0':
+                       provide_tk = true;
+                       break;
                case '1':
                        provide_p192 = true;
                        break;
                case '2':
                        provide_p256 = true;
                        break;
+               case 'I':
+                       provide_initiator = true;
+                       break;
+               case 'A':
+                       provide_acceptor = true;
+                       break;
                case 'v':
                        printf("%s\n", VERSION);
                        return EXIT_SUCCESS;
@@ -754,6 +1106,11 @@ int main(int argc ,char *argv[])
                return EXIT_FAILURE;
        }
 
+       if (use_privacy && !use_le && !use_cross ) {
+               fprintf(stderr, "Specify --privacy with --le or --cross\n");
+               return EXIT_FAILURE;
+       }
+
        if (use_random && !use_le) {
                fprintf(stderr, "Specify --random with --le\n");
                return EXIT_FAILURE;
diff --git a/tools/pskey_get.c b/tools/pskey_get.c
new file mode 100644 (file)
index 0000000..db4d228
--- /dev/null
@@ -0,0 +1,384 @@
+#include <sys/stat.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#define LOG_TAG "pskey"
+// #include "cutils/log.h"
+
+#include "hciattach_sprd.h"
+//#include "bt_vendor_sprd.h"
+#define BT_PSKEY_TRACE_BUF_SIZE 256
+#define MAX_BOARD_TYPE_LEN 32
+
+#define _FILE_PARSE_DEBUG_
+#define  CMD_ITEM_TABLE(ITEM, MEM_OFFSET, TYPE)    { ITEM,   (unsigned int)( &(  ((BT_PSKEY_CONFIG_T *)(0))->MEM_OFFSET )),   TYPE }
+#define ALOGI(fmt, arg...)  fprintf(stderr, "%s:%d()" fmt "\n", __FILE__,__LINE__, ## arg)
+#define ALOGE(fmt, arg...)  fprintf(stderr, "%s:%d()" fmt "\n", __FILE__,__LINE__, ## arg)
+
+#define PSKEY_PATH "/usr/lib/firmware/scx35_pikeavivaltove_3M_MARLIN_connectivity_configure.ini"
+
+typedef struct
+{
+       char item[64];
+       uint32  par[32];
+       int  num;
+}cmd_par;
+
+typedef struct
+{
+       char *item;
+       unsigned int mem_offset;
+       int type;
+}cmd_par_table;
+
+static cmd_par_table g_pskey_table[] =
+{
+       CMD_ITEM_TABLE("pskey_cmd", pskey_cmd, 4),
+
+       CMD_ITEM_TABLE("g_dbg_source_sink_syn_test_data", g_dbg_source_sink_syn_test_data, 1),
+       CMD_ITEM_TABLE("g_sys_sleep_in_standby_supported", g_sys_sleep_in_standby_supported, 1),
+       CMD_ITEM_TABLE("g_sys_sleep_master_supported", g_sys_sleep_master_supported, 1),
+       CMD_ITEM_TABLE("g_sys_sleep_slave_supported", g_sys_sleep_slave_supported, 1),
+
+       CMD_ITEM_TABLE("default_ahb_clk", default_ahb_clk, 4),
+       CMD_ITEM_TABLE("device_class", device_class, 4),
+       CMD_ITEM_TABLE("win_ext", win_ext, 4),
+
+       CMD_ITEM_TABLE("g_aGainValue", g_aGainValue, 4),
+       CMD_ITEM_TABLE("g_aPowerValue", g_aPowerValue, 4),
+
+       CMD_ITEM_TABLE("feature_set", feature_set, 1),
+       CMD_ITEM_TABLE("device_addr", device_addr, 1),
+
+       CMD_ITEM_TABLE("g_sys_sco_transmit_mode", g_sys_sco_transmit_mode, 1), //true tramsmit by uart, otherwise by share memory
+       CMD_ITEM_TABLE("g_sys_uart0_communication_supported", g_sys_uart0_communication_supported, 1), //true use uart0, otherwise use uart1 for debug
+       CMD_ITEM_TABLE("edr_tx_edr_delay", edr_tx_edr_delay, 1),
+       CMD_ITEM_TABLE("edr_rx_edr_delay", edr_rx_edr_delay, 1),
+
+       CMD_ITEM_TABLE("g_wbs_nv_117", g_wbs_nv_117, 2),
+
+
+       CMD_ITEM_TABLE("is_wdg_supported", is_wdg_supported, 4),
+
+       CMD_ITEM_TABLE("share_memo_rx_base_addr", share_memo_rx_base_addr, 4),
+       //CMD_ITEM_TABLE("share_memo_tx_base_addr", share_memo_tx_base_addr, 4),
+
+       CMD_ITEM_TABLE("g_wbs_nv_118", g_wbs_nv_118, 2),
+       CMD_ITEM_TABLE("g_nbv_nv_117", g_nbv_nv_117, 2),
+
+
+       CMD_ITEM_TABLE("share_memo_tx_packet_num_addr", share_memo_tx_packet_num_addr, 4),
+       CMD_ITEM_TABLE("share_memo_tx_data_base_addr", share_memo_tx_data_base_addr, 4),
+
+       CMD_ITEM_TABLE("g_PrintLevel", g_PrintLevel, 4),
+
+       CMD_ITEM_TABLE("share_memo_tx_block_length", share_memo_tx_block_length, 2),
+       CMD_ITEM_TABLE("share_memo_rx_block_length", share_memo_rx_block_length, 2),
+       CMD_ITEM_TABLE("share_memo_tx_water_mark", share_memo_tx_water_mark, 2),
+       //CMD_ITEM_TABLE("share_memo_tx_timeout_value", share_memo_tx_timeout_value, 2),
+       CMD_ITEM_TABLE("g_nbv_nv_118", g_nbv_nv_118, 2),
+
+       CMD_ITEM_TABLE("uart_rx_watermark", uart_rx_watermark, 2),
+       CMD_ITEM_TABLE("uart_flow_control_thld", uart_flow_control_thld, 2),
+       CMD_ITEM_TABLE("comp_id", comp_id, 4),
+       CMD_ITEM_TABLE("pcm_clk_divd", pcm_clk_divd, 2),
+
+
+       CMD_ITEM_TABLE("bt_reserved", reserved, 4)
+};
+
+static int bt_getFileSize(char *file)
+{
+       struct stat temp;
+       stat(file, &temp);
+       return temp.st_size;
+}
+
+static int bt_find_type(char key)
+{
+       if( (key >= 'a' && key <= 'w') || (key >= 'y' && key <= 'z') || (key >= 'A' && key <= 'W') || (key >= 'Y' && key <= 'Z') || ('_' == key) )
+               return 1;
+       if( (key >= '0' && key <= '9') || ('-' == key) )
+               return 2;
+       if( ('x' == key) || ('X' == key) || ('.' == key) )
+               return 3;
+       if( (key == '\0') || ('\r' == key) || ('\n' == key) || ('#' == key) )
+               return 4;
+       return 0;
+}
+
+static void bt_getCmdOneline(unsigned char *str, cmd_par *cmd)
+{
+       int i, j, bufType, cType, flag;
+       char tmp[BT_PSKEY_TRACE_BUF_SIZE];
+       char c;
+       bufType = -1;
+       cType = 0;
+       flag = 0;
+       memset( cmd, 0, sizeof(cmd_par) );
+       for(i = 0, j = 0; ; i++)
+       {
+               c = str[i];
+               cType = bt_find_type(c);
+               if( (1 == cType) || ( 2 == cType) || (3 == cType)  )
+               {
+                       tmp[j] = c;
+                       j++;
+                       if(-1 == bufType)
+                       {
+                               if(2 == cType)
+                                       bufType = 2;
+                               else
+                                       bufType = 1;
+                       }
+                       else if(2 == bufType)
+                       {
+                               if(1 == cType)
+                                       bufType = 1;
+                       }
+                       continue;
+               }
+               if(-1 != bufType)
+               {
+                       tmp[j] = '\0';
+
+                       if((1 == bufType) && (0 == flag) )
+                       {
+                               strcpy(cmd->item, tmp);
+                               flag = 1;
+                       }
+                       else
+                       {
+                               /* compatible with  HEX */
+                               if (tmp[0] == '0' && (tmp[1] == 'x' || tmp[1] == 'X')) {
+                                       cmd->par[cmd->num] = strtoul(tmp, 0, 16) & 0xFFFFFFFF;
+                                       cmd->num++;
+                               } else {
+                                       cmd->par[cmd->num] = strtoul(tmp, 0, 10) & 0xFFFFFFFF;
+                                       cmd->num++;
+                               }
+                       }
+                       bufType = -1;
+                       j = 0;
+               }
+               if(0 == cType )
+                       continue;
+               if(4 == cType)
+                       return;
+       }
+       return;
+}
+
+static int bt_getDataFromCmd(cmd_par_table *pTable, cmd_par *cmd,  void *pData)
+{
+       int i;
+       unsigned char  *p;
+       if( (1 != pTable->type)  && (2 != pTable->type) && (4 != pTable->type) )
+               return -1;
+       p = (unsigned char *)(pData) + pTable->mem_offset;
+#ifdef _FILE_PARSE_DEBUG_
+       char tmp[BT_PSKEY_TRACE_BUF_SIZE] = {0};
+       char string[16] = {0};
+       sprintf(tmp, "###[pskey]%s, offset:%d, num:%d, value:   ", pTable->item, pTable->mem_offset, cmd->num);
+       for(i=0; i<cmd->num; i++)
+       {
+               memset(string, 0, 16);
+               sprintf(string, "0x%x, ", cmd->par[i] );
+               strcat(tmp, string);
+       }
+       ALOGI("%s\n", tmp);
+#endif
+       for(i = 0; i < cmd->num;  i++)
+       {
+               if(1 == pTable->type)
+                       *((unsigned char *)p + i) = (unsigned char)(cmd->par[i]);
+               else if(2 == pTable->type)
+                       *((unsigned short *)p + i) = (unsigned short)(cmd->par[i]);
+               else if(4 == pTable->type)
+                       *( (unsigned int *)p + i) = (unsigned int)(cmd->par[i]);
+               else
+                       ALOGE("%s, type err\n", __func__);
+       }
+       return 0;
+}
+
+static cmd_par_table *bt_cmd_table_match(cmd_par *cmd)
+{
+       int i;
+       cmd_par_table *pTable = NULL;
+       int len = sizeof(g_pskey_table) / sizeof(cmd_par_table);
+       if(NULL == cmd->item)
+               return NULL;
+       for(i = 0; i < len; i++)
+       {
+               if(NULL == g_pskey_table[i].item)
+                       continue;
+               if( 0 != strcmp( g_pskey_table[i].item, cmd->item ) )
+                       continue;
+               pTable = &g_pskey_table[i];
+               break;
+       }
+       return pTable;
+}
+
+
+static int bt_getDataFromBuf(void *pData, unsigned char *pBuf, int file_len)
+{
+       int i, p;
+       cmd_par cmd;
+       cmd_par_table *pTable = NULL;
+       if((NULL == pBuf) || (0 == file_len) || (NULL == pData) )
+               return -1;
+       for(i = 0, p = 0; i < file_len; i++)
+       {
+               if( ('\n' == *(pBuf + i)) || ( '\r' == *(pBuf + i)) || ( '\0' == *(pBuf + i) )   )
+               {
+                       if(5 <= (i - p) )
+                       {
+                               bt_getCmdOneline((pBuf + p), &cmd);
+                               pTable = bt_cmd_table_match(&cmd);
+                               if(NULL != pTable)
+                               {
+                                       bt_getDataFromCmd(pTable, &cmd, pData);
+                               }
+                       }
+                       p = i + 1;
+               }
+
+       }
+       return 0;
+}
+
+static int bt_dumpPskey(BT_PSKEY_CONFIG_T *p)
+{
+       ALOGI("pskey_cmd: 0x%08X", p->pskey_cmd);
+
+       ALOGI("g_dbg_source_sink_syn_test_data: 0x%02X", p->g_dbg_source_sink_syn_test_data);
+       ALOGI("g_sys_sleep_in_standby_supported: 0x%02X", p->g_sys_sleep_in_standby_supported);
+       ALOGI("g_sys_sleep_master_supported: 0x%02X", p->g_sys_sleep_master_supported);
+       ALOGI("g_sys_sleep_slave_supported: 0x%02X", p->g_sys_sleep_slave_supported);
+
+       ALOGI("default_ahb_clk: %d", p->default_ahb_clk);
+       ALOGI("device_class: 0x%08X", p->device_class);
+       ALOGI("win_ext: 0x%08X", p->win_ext);
+
+       ALOGI("g_aGainValue: 0x%08X, 0x%08X, 0x%08X, 0x%08X, 0x%08X, 0x%08X", p->g_aGainValue[0], p->g_aGainValue[1], p->g_aGainValue[2], p->g_aGainValue[3], p->g_aGainValue[4], p->g_aGainValue[5]);
+       ALOGI("g_aPowerValue: 0x%08X, 0x%08X, 0x%08X, 0x%08X, 0x%08X", p->g_aPowerValue[0], p->g_aPowerValue[1], p->g_aPowerValue[2], p->g_aPowerValue[3], p->g_aPowerValue[4]);
+
+
+       ALOGI("feature_set(0~7): 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X", p->feature_set[0], p->feature_set[1], p->feature_set[2], 
+                       p->feature_set[3], p->feature_set[4], p->feature_set[5], p->feature_set[6], p->feature_set[7]);
+       ALOGI("feature_set(8~15): 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X", p->feature_set[8], p->feature_set[9], p->feature_set[10], 
+                       p->feature_set[11], p->feature_set[12], p->feature_set[13], p->feature_set[14], p->feature_set[15]);
+       ALOGI("device_addr: 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X", p->device_addr[0], p->device_addr[1], p->device_addr[2], p->device_addr[3], p->device_addr[4], p->device_addr[5]);
+
+       ALOGI("g_sys_sco_transmit_mode: 0x%02X", p->g_sys_sco_transmit_mode);
+       ALOGI("g_sys_uart0_communication_supported: 0x%02X", p->g_sys_uart0_communication_supported);
+       ALOGI("edr_tx_edr_delay: %d", p->edr_tx_edr_delay);
+       ALOGI("edr_rx_edr_delay: %d", p->edr_rx_edr_delay);
+
+       ALOGI("g_wbs_nv_117 : 0x%04X", p->g_wbs_nv_117 );
+
+       ALOGI("is_wdg_supported: 0x%08X", p->is_wdg_supported);
+
+       ALOGI("share_memo_rx_base_addr: 0x%08X", p->share_memo_rx_base_addr);
+       //ALOGI("share_memo_tx_base_addr: 0x%08X", p->share_memo_tx_base_addr);
+       ALOGI("g_wbs_nv_118 : 0x%04X", p->g_wbs_nv_118 );
+       ALOGI("g_nbv_nv_117 : 0x%04X", p->g_nbv_nv_117 );
+
+
+       ALOGI("share_memo_tx_packet_num_addr: 0x%08X", p->share_memo_tx_packet_num_addr);
+       ALOGI("share_memo_tx_data_base_addr: 0x%08X", p->share_memo_tx_data_base_addr);
+
+       ALOGI("g_PrintLevel: 0x%08X", p->g_PrintLevel);
+
+       ALOGI("share_memo_tx_block_length: 0x%04X", p->share_memo_tx_block_length);
+       ALOGI("share_memo_rx_block_length: 0x%04X", p->share_memo_rx_block_length);
+       ALOGI("share_memo_tx_water_mark: 0x%04X", p->share_memo_tx_water_mark);
+       //ALOGI("share_memo_tx_timeout_value: 0x%04X", p->share_memo_tx_timeout_value);
+       ALOGI("g_nbv_nv_118 : 0x%04X", p->g_nbv_nv_118 );
+
+       ALOGI("uart_rx_watermark: %d", p->uart_rx_watermark);
+       ALOGI("uart_flow_control_thld: %d", p->uart_flow_control_thld);
+       ALOGI("comp_id: 0x%08X", p->comp_id);
+       ALOGI("pcm_clk_divd : 0x%04X", p->pcm_clk_divd );
+
+
+       ALOGI("reserved(0~7): 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X", p->reserved[0], p->reserved[1], p->reserved[2], 
+                       p->reserved[3], p->reserved[4], p->reserved[5], p->reserved[6], p->reserved[7]);
+       return 0;
+}
+#if 0
+static int bt_get_config_ver(unsigned char *pBuf, int len)
+{
+       int i, p;
+       cmd_par cmd;
+       int ret = -1;
+       for(i = 0, p = 0; i < len; i++)
+       {
+               if( ('\n' == *(pBuf + i)) || ( '\r' == *(pBuf + i)) || ( '\0' == *(pBuf + i) )   )
+               {
+                       if(5 <= (i - p) )
+                       {
+                               bt_getCmdOneline((pBuf + p), &cmd);
+                               if( 0 == strcmp(cmd.item, "version") )
+                               {
+                                       ret = cmd.par[0];
+                                       break;
+                               }
+                               memset(&cmd, 0, sizeof(cmd_par) );
+                       }
+                       p = i + 1;
+               }
+
+       }
+       return ret;
+}
+#endif
+int bt_getPskeyFromFile(void *pData)
+{
+       int ret = -1;
+       int fd;
+       unsigned char *pBuf = NULL;
+       int len;
+
+       ALOGI("begin to bt_getPskeyFromFile");
+       fd = open(PSKEY_PATH, O_RDONLY, 0644);
+       if(-1 != fd)
+       {
+               len = bt_getFileSize(PSKEY_PATH);
+               pBuf = (unsigned char *)malloc(len);
+               ret = read(fd, pBuf, len);
+               if(-1 == ret)
+               {
+                       ALOGE("%s read %s ret:%d\n", __FUNCTION__, PSKEY_PATH, ret);
+                       free(pBuf);
+                       close(fd);
+                       return -1;
+               }
+               close(fd);
+       }
+       else
+       {
+               ALOGE("%s open %s ret:%d\n", __FUNCTION__, PSKEY_PATH, fd);
+               return -1;
+       }
+
+       ret = bt_getDataFromBuf(pData, pBuf, len);
+       if(-1 == ret)
+       {
+               free(pBuf);
+               return -1;
+       }
+       ALOGI("begin to dumpPskey");
+       bt_dumpPskey((BT_PSKEY_CONFIG_T *)pData);
+       free(pBuf);
+       return 0;
+}
+
+
index 8f7d5ad..3bc3569 100644 (file)
@@ -36,6 +36,7 @@
 #include <glib.h>
 
 #include "src/shared/util.h"
+#include "src/shared/tester.h"
 #include "src/log.h"
 
 #include "android/avctp.h"
@@ -52,7 +53,6 @@ struct test_data {
 };
 
 struct context {
-       GMainLoop *main_loop;
        struct avctp *session;
        guint source;
        guint process;
@@ -77,16 +77,15 @@ struct context {
                };                                                      \
                static struct test_data data;                           \
                data.test_name = g_strdup(name);                        \
-               data.pdu_list = g_malloc(sizeof(pdus));                 \
-               memcpy(data.pdu_list, pdus, sizeof(pdus));              \
-               g_test_add_data_func(name, &data, function);            \
+               data.pdu_list = g_memdup(pdus, sizeof(pdus));           \
+               tester_add(name, &data, NULL, function, NULL);          \
        } while (0)
 
 static void test_debug(const char *str, void *user_data)
 {
        const char *prefix = user_data;
 
-       g_print("%s%s\n", prefix, str);
+       tester_debug("%s%s", prefix, str);
 }
 
 static void test_free(gconstpointer user_data)
@@ -97,6 +96,17 @@ static void test_free(gconstpointer user_data)
        g_free(data->pdu_list);
 }
 
+static void destroy_context(struct context *context)
+{
+       if (context->source > 0)
+               g_source_remove(context->source);
+
+       avctp_shutdown(context->session);
+
+       test_free(context->data);
+       g_free(context);
+}
+
 static gboolean context_quit(gpointer user_data)
 {
        struct context *context = user_data;
@@ -104,7 +114,9 @@ static gboolean context_quit(gpointer user_data)
        if (context->process > 0)
                g_source_remove(context->process);
 
-       g_main_loop_quit(context->main_loop);
+       destroy_context(context);
+
+       tester_test_passed();
 
        return FALSE;
 }
@@ -119,8 +131,7 @@ static gboolean send_pdu(gpointer user_data)
 
        len = write(context->fd, pdu->data, pdu->size);
 
-       if (g_test_verbose())
-               util_hexdump('<', pdu->data, len, test_debug, "AVCTP: ");
+       util_hexdump('<', pdu->data, len, test_debug, "AVCTP: ");
 
        g_assert_cmpint(len, ==, pdu->size);
 
@@ -161,8 +172,7 @@ static gboolean test_handler(GIOChannel *channel, GIOCondition cond,
 
        g_assert(len > 0);
 
-       if (g_test_verbose())
-               util_hexdump('>', buf, len, test_debug, "AVCTP: ");
+       util_hexdump('>', buf, len, test_debug, "AVCTP: ");
 
        g_assert_cmpint(len, ==, pdu->size);
 
@@ -179,9 +189,6 @@ static struct context *create_context(uint16_t version, gconstpointer data)
        GIOChannel *channel;
        int err, sv[2];
 
-       context->main_loop = g_main_loop_new(NULL, FALSE);
-       g_assert(context->main_loop);
-
        err = socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0, sv);
        g_assert(err == 0);
 
@@ -207,34 +214,11 @@ static struct context *create_context(uint16_t version, gconstpointer data)
        return context;
 }
 
-static void destroy_context(struct context *context)
-{
-       if (context->source > 0)
-               g_source_remove(context->source);
-
-       avctp_shutdown(context->session);
-
-       g_main_loop_unref(context->main_loop);
-
-       test_free(context->data);
-       g_free(context);
-}
-
-static void execute_context(struct context *context)
-{
-       g_main_loop_run(context->main_loop);
-
-       destroy_context(context);
-}
-
 static ssize_t handler(struct avctp *session,
                                        uint8_t transaction, uint8_t *code,
                                        uint8_t *subunit, uint8_t *operands,
                                        size_t operand_count, void *user_data)
 {
-       DBG("transaction %d code %d subunit %d operand_count %zu",
-               transaction, *code, *subunit, operand_count);
-
        g_assert_cmpint(transaction, ==, 0);
        g_assert_cmpint(*code, ==, 0);
        g_assert_cmpint(*subunit, ==, 0);
@@ -250,9 +234,6 @@ static gboolean handler_response(struct avctp *session,
 {
        struct context *context = user_data;
 
-       DBG("code 0x%02x subunit %d operand_count %zu", code, subunit,
-                                                               operand_count);
-
        g_assert_cmpint(code, ==, 0x0a);
        g_assert_cmpint(subunit, ==, 0);
        g_assert_cmpint(operand_count, ==, 0);
@@ -266,8 +247,6 @@ static void test_client(gconstpointer data)
 
        avctp_send_vendor_req(context->session, AVC_CTYPE_CONTROL, 0, NULL,
                                                0, handler_response, context);
-
-       execute_context(context);
 }
 
 static void test_server(gconstpointer data)
@@ -279,28 +258,24 @@ static void test_server(gconstpointer data)
 
                ret = avctp_register_pdu_handler(context->session,
                                        AVC_OP_VENDORDEP, handler, NULL);
-               DBG("ret %d", ret);
                g_assert_cmpint(ret, !=, 0);
        }
 
        g_idle_add(send_pdu, context);
-
-       execute_context(context);
 }
 
 static void test_dummy(gconstpointer data)
 {
        struct context *context = create_context(0x0100, data);
 
-       destroy_context(context);
+       context_quit(context);
 }
 
 int main(int argc, char *argv[])
 {
-       g_test_init(&argc, &argv, NULL);
+       tester_init(&argc, &argv);
 
-       if (g_test_verbose())
-               __btd_log_init("*", 0);
+       __btd_log_init("*", 0);
 
        /* Connection Channel Management tests */
 
@@ -335,5 +310,5 @@ int main(int argc, char *argv[])
                                raw_pdu(0x00, 0xff, 0xff, 0x00, 0x00, 0x00),
                                raw_pdu(0x03, 0xff, 0xff));
 
-       return g_test_run();
+       return tester_run();
 }
index 805f08d..dd8aed7 100644 (file)
@@ -37,7 +37,9 @@
 
 #include "src/shared/util.h"
 #include "src/shared/queue.h"
+#include "src/shared/tester.h"
 #include "src/log.h"
+
 #include "android/avdtp.h"
 
 #define MAX_SEID 0x3E
@@ -78,13 +80,11 @@ struct test_data {
                };                                                      \
                static struct test_data data;                           \
                data.test_name = g_strdup(name);                        \
-               data.pdu_list = g_malloc(sizeof(pdus));                 \
-               memcpy(data.pdu_list, pdus, sizeof(pdus));              \
-               g_test_add_data_func(name, &data, function);            \
+               data.pdu_list = g_memdup(pdus, sizeof(pdus));           \
+               tester_add(name, &data, NULL, function, NULL);          \
        } while (0)
 
 struct context {
-       GMainLoop *main_loop;
        struct avdtp *session;
        struct avdtp_local_sep *sep;
        struct avdtp_stream *stream;
@@ -103,7 +103,7 @@ static void test_debug(const char *str, void *user_data)
 {
        const char *prefix = user_data;
 
-       g_print("%s%s\n", prefix, str);
+       tester_debug("%s%s", prefix, str);
 }
 
 static void test_free(gconstpointer user_data)
@@ -114,6 +114,26 @@ static void test_free(gconstpointer user_data)
        g_free(data->pdu_list);
 }
 
+static void unregister_sep(void *data)
+{
+       struct avdtp_local_sep *sep = data;
+
+       /* Removed from the queue by caller */
+       avdtp_unregister_sep(NULL, sep);
+}
+
+static void destroy_context(struct context *context)
+{
+       if (context->source > 0)
+               g_source_remove(context->source);
+       avdtp_unref(context->session);
+
+       test_free(context->data);
+       queue_destroy(context->lseps, unregister_sep);
+
+       g_free(context);
+}
+
 static gboolean context_quit(gpointer user_data)
 {
        struct context *context = user_data;
@@ -121,7 +141,9 @@ static gboolean context_quit(gpointer user_data)
        if (context->process > 0)
                g_source_remove(context->process);
 
-       g_main_loop_quit(context->main_loop);
+       destroy_context(context);
+
+       tester_test_passed();
 
        return FALSE;
 }
@@ -136,8 +158,7 @@ static gboolean send_pdu(gpointer user_data)
 
        len = write(context->fd, pdu->data, pdu->size);
 
-       if (g_test_verbose())
-               util_hexdump('<', pdu->data, len, test_debug, "AVDTP: ");
+       util_hexdump('<', pdu->data, len, test_debug, "AVDTP: ");
 
        g_assert_cmpint(len, ==, pdu->size);
 
@@ -194,8 +215,7 @@ static gboolean test_handler(GIOChannel *channel, GIOCondition cond,
 
        g_assert(len > 0);
 
-       if (g_test_verbose())
-               util_hexdump('>', buf, len, test_debug, "AVDTP: ");
+       util_hexdump('>', buf, len, test_debug, "AVDTP: ");
 
        g_assert_cmpint(len, ==, pdu->size);
 
@@ -227,9 +247,6 @@ static struct context *context_new(uint16_t version, uint16_t imtu,
        GIOChannel *channel;
        int err, sv[2];
 
-       context->main_loop = g_main_loop_new(NULL, FALSE);
-       g_assert(context->main_loop);
-
        err = socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0, sv);
        g_assert(err == 0);
 
@@ -264,35 +281,6 @@ static struct context *create_context(uint16_t version, gconstpointer data)
        return context_new(version, 672, 672, data);
 }
 
-static void unregister_sep(void *data)
-{
-       struct avdtp_local_sep *sep = data;
-
-       /* Removed from the queue by caller */
-       avdtp_unregister_sep(NULL, sep);
-}
-
-static void destroy_context(struct context *context)
-{
-       if (context->source > 0)
-               g_source_remove(context->source);
-       avdtp_unref(context->session);
-
-       g_main_loop_unref(context->main_loop);
-
-       test_free(context->data);
-       queue_destroy(context->lseps, unregister_sep);
-
-       g_free(context);
-}
-
-static void execute_context(struct context *context)
-{
-       g_main_loop_run(context->main_loop);
-
-       destroy_context(context);
-}
-
 static gboolean sep_getcap_ind(struct avdtp *session,
                                        struct avdtp_local_sep *sep,
                                        GSList **caps, uint8_t *err,
@@ -424,6 +412,11 @@ static void sep_setconf_cfm(struct avdtp *session, struct avdtp_local_sep *sep,
        struct context *context = user_data;
        int ret;
 
+       if (g_str_equal(context->data->test_name, "/TP/SIG/SMG/BV-09-C")) {
+               context_quit(context);
+               return;
+       }
+
        if (g_str_equal(context->data->test_name, "/TP/SIG/SMG/BI-07-C")) {
                g_assert(err != NULL);
                g_assert_cmpint(avdtp_error_error_code(err), ==, 0x13);
@@ -531,8 +524,6 @@ static void test_server(gconstpointer data)
        g_assert(sep);
 
        g_idle_add(send_pdu, context);
-
-       execute_context(context);
 }
 
 static void test_server_1_3(gconstpointer data)
@@ -546,8 +537,6 @@ static void test_server_1_3(gconstpointer data)
        g_assert(sep);
 
        g_idle_add(send_pdu, context);
-
-       execute_context(context);
 }
 
 static void test_server_1_3_sink(gconstpointer data)
@@ -561,8 +550,6 @@ static void test_server_1_3_sink(gconstpointer data)
        g_assert(sep);
 
        g_idle_add(send_pdu, context);
-
-       execute_context(context);
 }
 
 static void test_server_0_sep(gconstpointer data)
@@ -570,8 +557,6 @@ static void test_server_0_sep(gconstpointer data)
        struct context *context = create_context(0x0100, data);
 
        g_idle_add(send_pdu, context);
-
-       execute_context(context);
 }
 
 static void test_server_seid(gconstpointer data)
@@ -595,7 +580,7 @@ static void test_server_seid(gconstpointer data)
                                                context);
        g_assert(!sep);
 
-       destroy_context(context);
+       context_quit(context);
 }
 
 static void test_server_seid_duplicate(gconstpointer data)
@@ -628,8 +613,6 @@ static void test_server_seid_duplicate(gconstpointer data)
        /* Check SEID ids with DISCOVER */
 
        g_idle_add(send_pdu, context);
-
-       execute_context(context);
 }
 
 static gboolean sep_getcap_ind_frg(struct avdtp *session,
@@ -684,8 +667,6 @@ static void test_server_frg(gconstpointer data)
        g_assert(sep);
 
        g_idle_add(send_pdu, context);
-
-       execute_context(context);
 }
 
 static void discover_cb(struct avdtp *session, GSList *seps,
@@ -767,8 +748,6 @@ static void test_client(gconstpointer data)
        context->sep = sep;
 
        avdtp_discover(context->session, discover_cb, context);
-
-       execute_context(context);
 }
 
 static void test_client_1_3(gconstpointer data)
@@ -783,8 +762,6 @@ static void test_client_1_3(gconstpointer data)
        context->sep = sep;
 
        avdtp_discover(context->session, discover_cb, context);
-
-       execute_context(context);
 }
 
 static void test_client_frg(gconstpointer data)
@@ -799,16 +776,13 @@ static void test_client_frg(gconstpointer data)
        context->sep = sep;
 
        avdtp_discover(context->session, discover_cb, context);
-
-       execute_context(context);
 }
 
 int main(int argc, char *argv[])
 {
-       g_test_init(&argc, &argv, NULL);
+       tester_init(&argc, &argv);
 
-       if (g_test_verbose())
-               __btd_log_init("*", 0);
+       __btd_log_init("*", 0);
 
        /*
         * Stream Management Service
@@ -843,7 +817,8 @@ int main(int argc, char *argv[])
                        raw_pdu(0x42, 0x02, 0x01, 0x00, 0x07, 0x06, 0x00, 0x00,
                                0xff, 0xff, 0x02, 0x40),
                        raw_pdu(0x50, 0x03, 0x04, 0x04, 0x01, 0x00, 0x07, 0x06,
-                               0x00, 0x00, 0x21, 0x02, 0x02, 0x20));
+                               0x00, 0x00, 0x21, 0x02, 0x02, 0x20),
+                       raw_pdu(0x52, 0x03));
        define_test("/TP/SIG/SMG/BV-10-C", test_server,
                        raw_pdu(0x00, 0x01),
                        raw_pdu(0x02, 0x01, 0x04, 0x00),
@@ -1413,5 +1388,5 @@ int main(int argc, char *argv[])
                        raw_pdu(0x50, 0x0d, 0x04, 0x00, 0x00),
                        raw_pdu(0x52, 0x0d));
 
-       return g_test_run();
+       return tester_run();
 }
index cffba78..a610ad5 100644 (file)
@@ -37,6 +37,7 @@
 #include <glib.h>
 
 #include "src/shared/util.h"
+#include "src/shared/tester.h"
 #include "src/log.h"
 #include "lib/bluetooth.h"
 
@@ -58,7 +59,6 @@ struct test_data {
 };
 
 struct context {
-       GMainLoop *main_loop;
        struct avrcp *session;
        guint source;
        guint browse_source;
@@ -109,16 +109,15 @@ struct context {
                };                                                      \
                static struct test_data data;                           \
                data.test_name = g_strdup(name);                        \
-               data.pdu_list = g_malloc(sizeof(pdus));                 \
-               memcpy(data.pdu_list, pdus, sizeof(pdus));              \
-               g_test_add_data_func(name, &data, function);            \
+               data.pdu_list = g_memdup(pdus, sizeof(pdus));           \
+               tester_add(name, &data, NULL, function, NULL);          \
        } while (0)
 
 static void test_debug(const char *str, void *user_data)
 {
        const char *prefix = user_data;
 
-       g_print("%s%s\n", prefix, str);
+       tester_debug("%s%s", prefix, str);
 }
 
 static void test_free(gconstpointer user_data)
@@ -129,6 +128,20 @@ static void test_free(gconstpointer user_data)
        g_free(data->pdu_list);
 }
 
+static void destroy_context(struct context *context)
+{
+       if (context->source > 0)
+               g_source_remove(context->source);
+
+       if (context->browse_source > 0)
+               g_source_remove(context->browse_source);
+
+       avrcp_shutdown(context->session);
+
+       test_free(context->data);
+       g_free(context);
+}
+
 static gboolean context_quit(gpointer user_data)
 {
        struct context *context = user_data;
@@ -136,7 +149,9 @@ static gboolean context_quit(gpointer user_data)
        if (context->process > 0)
                g_source_remove(context->process);
 
-       g_main_loop_quit(context->main_loop);
+       destroy_context(context);
+
+       tester_test_passed();
 
        return FALSE;
 }
@@ -154,8 +169,7 @@ static gboolean send_pdu(gpointer user_data)
        else
                len = write(context->fd, pdu->data, pdu->size);
 
-       if (g_test_verbose())
-               util_hexdump('<', pdu->data, len, test_debug, "AVRCP: ");
+       util_hexdump('<', pdu->data, len, test_debug, "AVRCP: ");
 
        g_assert_cmpint(len, ==, pdu->size);
 
@@ -185,15 +199,13 @@ static gboolean test_handler(GIOChannel *channel, GIOCondition cond,
        ssize_t len;
        int fd;
 
-       DBG("");
-
        pdu = &context->data->pdu_list[context->pdu_offset++];
 
        g_assert(!pdu->browse);
 
        if (cond & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
                context->source = 0;
-               g_print("%s: cond %x\n", __func__, cond);
+               tester_debug("%s: cond %x\n", __func__, cond);
                return FALSE;
        }
 
@@ -226,15 +238,13 @@ static gboolean browse_test_handler(GIOChannel *channel, GIOCondition cond,
        ssize_t len;
        int fd;
 
-       DBG("");
-
        pdu = &context->data->pdu_list[context->pdu_offset++];
 
        g_assert(pdu->browse);
 
        if (cond & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
                context->browse_source = 0;
-               g_print("%s: cond %x\n", __func__, cond);
+               tester_debug("%s: cond %x\n", __func__, cond);
                return FALSE;
        }
 
@@ -244,8 +254,7 @@ static gboolean browse_test_handler(GIOChannel *channel, GIOCondition cond,
 
        g_assert(len > 0);
 
-       if (g_test_verbose())
-               util_hexdump('>', buf, len, test_debug, "AVRCP: ");
+       util_hexdump('>', buf, len, test_debug, "AVRCP: ");
 
        g_assert_cmpint(len, ==, pdu->size);
 
@@ -263,11 +272,6 @@ static struct context *create_context(uint16_t version, gconstpointer data)
        GIOChannel *channel;
        int err, sv[2];
 
-       DBG("");
-
-       context->main_loop = g_main_loop_new(NULL, FALSE);
-       g_assert(context->main_loop);
-
        /* Control channel setup */
 
        err = socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0, sv);
@@ -319,71 +323,38 @@ static struct context *create_context(uint16_t version, gconstpointer data)
        return context;
 }
 
-static void destroy_context(struct context *context)
-{
-       if (context->source > 0)
-               g_source_remove(context->source);
-
-       avrcp_shutdown(context->session);
-
-       if (context->browse_source > 0)
-               g_source_remove(context->browse_source);
-
-       g_main_loop_unref(context->main_loop);
-
-       test_free(context->data);
-       g_free(context);
-}
-
 static void test_dummy(gconstpointer data)
 {
        struct context *context =  create_context(0x0100, data);
 
-       destroy_context(context);
-}
-
-static void execute_context(struct context *context)
-{
-       g_main_loop_run(context->main_loop);
-
-       destroy_context(context);
+       context_quit(context);
 }
 
 static bool handle_play(struct avrcp *session, bool pressed, void *user_data)
 {
-       DBG("");
-
        return true;
 }
 
 static bool handle_volume_up(struct avrcp *session, bool pressed,
                                                        void *user_data)
 {
-       DBG("");
-
        return true;
 }
 
 static bool handle_channel_up(struct avrcp *session, bool pressed,
                                                        void *user_data)
 {
-       DBG("");
-
        return true;
 }
 
 static bool handle_select(struct avrcp *session, bool pressed, void *user_data)
 {
-       DBG("");
-
        return true;
 }
 
 static bool handle_vendor_uniq(struct avrcp *session, bool pressed,
                                                                void *user_data)
 {
-       DBG("");
-
        return true;
 }
 
@@ -405,8 +376,6 @@ static int get_capabilities(struct avrcp *session, uint8_t transaction,
 static int list_attributes(struct avrcp *session, uint8_t transaction,
                                                        void *user_data)
 {
-       DBG("");
-
        avrcp_list_player_attributes_rsp(session, transaction, 0, NULL);
 
        return 0;
@@ -418,8 +387,6 @@ static int get_attribute_text(struct avrcp *session, uint8_t transaction,
 {
        const char *text[number];
 
-       DBG("");
-
        if (number) {
                memset(text, 0, number);
                text[0] = "equalizer";
@@ -434,8 +401,6 @@ static int get_attribute_text(struct avrcp *session, uint8_t transaction,
 static int list_values(struct avrcp *session, uint8_t transaction,
                                                uint8_t attr, void *user_data)
 {
-       DBG("");
-
        avrcp_list_player_values_rsp(session, transaction, 0, NULL);
 
        return -EINVAL;
@@ -447,8 +412,6 @@ static int get_value_text(struct avrcp *session, uint8_t transaction,
 {
        const char *text[number];
 
-       DBG("");
-
        if (number) {
                memset(text, 0, number);
                text[0] = "on";
@@ -465,8 +428,6 @@ static int get_value(struct avrcp *session, uint8_t transaction,
 {
        uint8_t values[number];
 
-       DBG("");
-
        memset(values, 0, number);
 
        avrcp_get_current_player_value_rsp(session, transaction, number, attrs,
@@ -479,8 +440,6 @@ static int set_value(struct avrcp *session, uint8_t transaction,
                        uint8_t number, uint8_t *attrs, uint8_t *values,
                        void *user_data)
 {
-       DBG("");
-
        avrcp_set_player_value_rsp(session, transaction);
 
        return 0;
@@ -489,8 +448,6 @@ static int set_value(struct avrcp *session, uint8_t transaction,
 static int get_play_status(struct avrcp *session, uint8_t transaction,
                                                        void *user_data)
 {
-       DBG("");
-
        avrcp_get_play_status_rsp(session, transaction, 0xaaaaaaaa, 0xbbbbbbbb,
                                                                        0x00);
 
@@ -503,8 +460,6 @@ static int get_element_attributes(struct avrcp *session, uint8_t transaction,
 {
        struct context *context = user_data;
 
-       DBG("");
-
        if (g_str_has_prefix(context->data->test_name, "/TP/RCR")) {
                uint8_t params[1024];
 
@@ -525,8 +480,6 @@ static int track_changed(struct avrcp *session, uint8_t transaction,
        struct context *context = user_data;
        uint64_t track;
 
-       DBG("");
-
        if (g_str_equal(context->data->test_name, "/TP/NFY/BV-05-C") ||
                g_str_equal(context->data->test_name, "/TP/NFY/BV-08-C"))
                memset(&track, 0, sizeof(track));
@@ -549,8 +502,6 @@ static int settings_changed(struct avrcp *session, uint8_t transaction,
 {
        uint8_t settings[3];
 
-       DBG("");
-
        settings[0] = 0x01;
        settings[1] = 0x01;
        settings[2] = 0x02;
@@ -569,8 +520,6 @@ static int settings_changed(struct avrcp *session, uint8_t transaction,
 static int available_players_changed(struct avrcp *session, uint8_t transaction,
                                        uint32_t interval, void *user_data)
 {
-       DBG("");
-
        avrcp_register_notification_rsp(session, transaction, AVC_CTYPE_INTERIM,
                                        AVRCP_EVENT_AVAILABLE_PLAYERS_CHANGED,
                                        NULL, 0);
@@ -587,8 +536,6 @@ static int addressed_player_changed(struct avrcp *session, uint8_t transaction,
 {
        uint16_t player[2];
 
-       DBG("");
-
        player[0] = 0x0001;
        player[1] = 0x0001;
 
@@ -612,8 +559,6 @@ static int uids_changed(struct avrcp *session, uint8_t transaction,
        struct context *context = user_data;
        uint16_t counter;
 
-       DBG("");
-
        if (g_str_equal(context->data->test_name, "/TP/MCN/CB/BV-09-C"))
                counter = 0x0000;
        else
@@ -640,8 +585,6 @@ static int now_playing_content_changed(struct avrcp *session,
                                        uint8_t transaction, uint32_t interval,
                                        void *user_data)
 {
-       DBG("");
-
        avrcp_register_notification_rsp(session, transaction, AVC_CTYPE_INTERIM,
                                        AVRCP_EVENT_NOW_PLAYING_CONTENT_CHANGED,
                                        NULL, 0);
@@ -658,8 +601,6 @@ static int volume_changed(struct avrcp *session, uint8_t transaction,
 {
        uint8_t volume = 0x00;
 
-       DBG("");
-
        avrcp_register_notification_rsp(session, transaction, AVC_CTYPE_INTERIM,
                                        AVRCP_EVENT_VOLUME_CHANGED,
                                        &volume, sizeof(volume));
@@ -677,8 +618,6 @@ static int register_notification(struct avrcp *session, uint8_t transaction,
                                        uint8_t event, uint32_t interval,
                                        void *user_data)
 {
-       DBG("");
-
        switch (event) {
        case AVRCP_EVENT_TRACK_CHANGED:
                return track_changed(session, transaction, interval, user_data);
@@ -707,8 +646,6 @@ static int register_notification(struct avrcp *session, uint8_t transaction,
 static int set_volume(struct avrcp *session, uint8_t transaction,
                                        uint8_t volume, void *user_data)
 {
-       DBG("");
-
        avrcp_set_volume_rsp(session, transaction, volume);
 
        return 0;
@@ -720,8 +657,6 @@ static int set_addressed(struct avrcp *session, uint8_t transaction,
        struct context *context = user_data;
        uint8_t status;
 
-       DBG("");
-
        if (g_str_equal(context->data->test_name, "/TP/MPS/BI-01-C"))
                status = AVRCP_STATUS_INVALID_PLAYER_ID;
        else
@@ -738,8 +673,6 @@ static int set_browsed(struct avrcp *session, uint8_t transaction,
        struct context *context = user_data;
        const char *folders[1] = { "Filesystem" };
 
-       DBG("");
-
        if (g_str_equal(context->data->test_name, "/TP/MPS/BI-02-C"))
                avrcp_set_browsed_player_rsp(session, transaction,
                                                AVRCP_STATUS_INVALID_PLAYER_ID,
@@ -759,8 +692,6 @@ static int get_folder_items(struct avrcp *session, uint8_t transaction,
 {
        struct context *context = user_data;
 
-       DBG("");
-
        if (g_str_equal(context->data->test_name, "/TP/MCN/CB/BI-02-C"))
                return -ERANGE;
 
@@ -777,8 +708,6 @@ static int change_path(struct avrcp *session, uint8_t transaction,
                                        uint16_t counter, uint8_t direction,
                                        uint64_t uid, void *user_data)
 {
-       DBG("");
-
        if (!uid)
                return -ENOTDIR;
 
@@ -795,8 +724,6 @@ static int get_item_attributes(struct avrcp *session, uint8_t transaction,
        struct context *context = user_data;
        uint8_t status;
 
-       DBG("");
-
        if (g_str_equal(context->data->test_name, "/TP/MCN/CB/BI-05-C"))
                status = AVRCP_STATUS_UID_CHANGED;
        else
@@ -811,8 +738,6 @@ static int get_item_attributes(struct avrcp *session, uint8_t transaction,
 static int play_item(struct avrcp *session, uint8_t transaction, uint8_t scope,
                        uint64_t uid, uint16_t counter, void *user_data)
 {
-       DBG("");
-
        if (!uid)
                return -ENOENT;
 
@@ -824,8 +749,6 @@ static int play_item(struct avrcp *session, uint8_t transaction, uint8_t scope,
 static int search(struct avrcp *session, uint8_t transaction,
                                        const char *string, void *user_data)
 {
-       DBG("");
-
        avrcp_search_rsp(session, transaction, AVRCP_STATUS_SUCCESS, 0xaabb, 0);
 
        return 0;
@@ -835,8 +758,6 @@ static int add_to_now_playing(struct avrcp *session, uint8_t transaction,
                                uint8_t scope, uint64_t uid, uint16_t counter,
                                void *user_data)
 {
-       DBG("");
-
        if (!uid)
                return -ENOENT;
 
@@ -877,8 +798,6 @@ static void test_server(gconstpointer data)
        avrcp_register_player(context->session, &control_ind, NULL, context);
 
        g_idle_add(send_pdu, context);
-
-       execute_context(context);
 }
 
 static void get_folder_items_rsp(struct avrcp *session, int err,
@@ -887,8 +806,6 @@ static void get_folder_items_rsp(struct avrcp *session, int err,
 {
        struct context *context = user_data;
 
-       DBG("");
-
        g_assert_cmpint(err, ==, 0);
        g_assert_cmpint(counter, ==, 0xabcd);
        g_assert_cmpint(number, ==, 0);
@@ -913,8 +830,6 @@ static bool register_notification_rsp(struct avrcp *session, int err,
 {
        struct context *context = user_data;
 
-       DBG("");
-
        g_assert_cmpint(err, ==, 0);
 
        switch (event) {
@@ -1083,16 +998,13 @@ static void test_client(gconstpointer data)
 
        if (g_str_equal(context->data->test_name, "/TP/PTH/BV-02-C"))
                avrcp_send_passthrough(context->session, 0, AVC_FAST_FORWARD);
-
-       execute_context(context);
 }
 
 int main(int argc, char *argv[])
 {
-       g_test_init(&argc, &argv, NULL);
+       tester_init(&argc, &argv);
 
-       if (g_test_verbose())
-               __btd_log_init("*", 0);
+       __btd_log_init("*", 0);
 
        /* Media Player Selection Commands and Notifications */
 
@@ -2182,5 +2094,5 @@ int main(int argc, char *argv[])
                                0x00, 0x19, 0x58, AVRCP_ABORT_CONTINUING,
                                0x00, 0x00, 0x00));
 
-       return g_test_run();
+       return tester_run();
 }
index 2edcacb..95b42dd 100644 (file)
@@ -102,8 +102,7 @@ struct context {
                data.uuid = bt_uuid;                                    \
                data.step = test_step;                                  \
                data.source_db = db;                                    \
-               data.pdu_list = g_malloc(sizeof(pdus));                 \
-               memcpy(data.pdu_list, pdus, sizeof(pdus));              \
+               data.pdu_list = g_memdup(pdus, sizeof(pdus));           \
                tester_add(name, &data, NULL, function, NULL);          \
        } while (0)
 
@@ -149,6 +148,65 @@ struct context {
                raw_pdu(0x04, 0x08, 0x00, 0x08, 0x00),                  \
                raw_pdu(0x05, 0x01, 0x08, 0x00, 0x01, 0x29)
 
+#define SERVICE_DATA_2_PDUS                                            \
+               MTU_EXCHANGE_CLIENT_PDUS,                               \
+               raw_pdu(0x10, 0x01, 0x00, 0xff, 0xff, 0x00, 0x28),      \
+               raw_pdu(0x11, 0x06, 0x01, 0x00, 0x04, 0x00, 0x01, 0x18),\
+               raw_pdu(0x10, 0x05, 0x00, 0xff, 0xff, 0x00, 0x28),      \
+               raw_pdu(0x11, 0x06, 0x05, 0x00, 0x0a, 0x00, 0x0d, 0x18),\
+               raw_pdu(0x10, 0x0b, 0x00, 0xff, 0xff, 0x00, 0x28),      \
+               raw_pdu(0x01, 0x10, 0x0b, 0x00, 0x0a),                  \
+               raw_pdu(0x10, 0x01, 0x00, 0xff, 0xff, 0x01, 0x28),      \
+               raw_pdu(0x01, 0x10, 0x01, 0x00, 0x0a),                  \
+               raw_pdu(0x08, 0x01, 0x00, 0x04, 0x00, 0x02, 0x28),      \
+               raw_pdu(0x01, 0x08, 0x01, 0x00, 0x0a),                  \
+               raw_pdu(0x08, 0x05, 0x00, 0x0a, 0x00, 0x02, 0x28),      \
+               raw_pdu(0x01, 0x08, 0x05, 0x00, 0x0a),                  \
+               raw_pdu(0x08, 0x01, 0x00, 0x04, 0x00, 0x03, 0x28),      \
+               raw_pdu(0x09, 0x07, 0x02, 0x00, 0x02, 0x03, 0x00, 0x00, \
+                               0x2a),                                  \
+               raw_pdu(0x08, 0x03, 0x00, 0x04, 0x00, 0x03, 0x28),      \
+               raw_pdu(0x01, 0x08, 0x03, 0x00, 0x0a),                  \
+               raw_pdu(0x04, 0x04, 0x00, 0x04, 0x00),                  \
+               raw_pdu(0x05, 0x01, 0x04, 0x00, 0x01, 0x29),            \
+               raw_pdu(0x08, 0x05, 0x00, 0x0a, 0x00, 0x03, 0x28),      \
+               raw_pdu(0x09, 0x07, 0x07, 0x00, 0x0a, 0x08, 0x00, 0x29, \
+                               0x2a),                                  \
+               raw_pdu(0x08, 0x08, 0x00, 0x0a, 0x00, 0x03, 0x28),      \
+               raw_pdu(0x01, 0x08, 0x08, 0x00, 0x0a),                  \
+               raw_pdu(0x04, 0x09, 0x00, 0x0a, 0x00),                  \
+               raw_pdu(0x05, 0x01, 0x0a, 0x00, 0x01, 0x29)
+
+#define SERVICE_DATA_3_PDUS                                            \
+               MTU_EXCHANGE_CLIENT_PDUS,                               \
+               raw_pdu(0x10, 0x01, 0x00, 0xff, 0xff, 0x00, 0x28),      \
+               raw_pdu(0x11, 0x06, 0x00, 0x01, 0x21, 0x01, 0x00, 0x18, \
+                       0x00, 0x02, 0x00, 0x02, 0x01, 0x18),            \
+               raw_pdu(0x10, 0x01, 0x02, 0xff, 0xff, 0x00, 0x28),      \
+               raw_pdu(0x11, 0x06, 0x00, 0x03, 0x20, 0x03, 0x0d, 0x18),\
+               raw_pdu(0x10, 0x21, 0x03, 0xff, 0xff, 0x00, 0x28),      \
+               raw_pdu(0x01, 0x10, 0x21, 0x03, 0x0a),                  \
+               raw_pdu(0x10, 0x01, 0x00, 0xff, 0xff, 0x01, 0x28),      \
+               raw_pdu(0x01, 0x10, 0x01, 0x00, 0x0a),                  \
+               raw_pdu(0x08, 0x00, 0x01, 0x21, 0x01, 0x02, 0x28),      \
+               raw_pdu(0x01, 0x08, 0x00, 0x01, 0x0a),                  \
+               raw_pdu(0x08, 0x00, 0x03, 0x20, 0x03, 0x02, 0x28),      \
+               raw_pdu(0x01, 0x08, 0x00, 0x03, 0x0a),                  \
+               raw_pdu(0x08, 0x00, 0x01, 0x21, 0x01, 0x03, 0x28),      \
+               raw_pdu(0x09, 0x07, 0x10, 0x01, 0x02, 0x11, 0x01, 0x00, \
+                       0x2a, 0x20, 0x01, 0x02, 0x21, 0x01, 0x01, 0x2a),\
+               raw_pdu(0x08, 0x21, 0x01, 0x21, 0x01, 0x03, 0x28),      \
+               raw_pdu(0x01, 0x08, 0x21, 0x01, 0x0a),                  \
+               raw_pdu(0x04, 0x12, 0x01, 0x1f, 0x01),                  \
+               raw_pdu(0x01, 0x04, 0x12, 0x01, 0x0a),                  \
+               raw_pdu(0x08, 0x00, 0x03, 0x20, 0x03, 0x03, 0x28),      \
+               raw_pdu(0x09, 0x07, 0x10, 0x03, 0x0a, 0x11, 0x03, 0x29, \
+                       0x2a),                                          \
+               raw_pdu(0x08, 0x11, 0x03, 0x20, 0x03, 0x03, 0x28),      \
+               raw_pdu(0x01, 0x08, 0x11, 0x03, 0x0a),                  \
+               raw_pdu(0x04, 0x12, 0x03, 0x20, 0x03),                  \
+               raw_pdu(0x05, 0x01, 0x20, 0x03, 0x02, 0x29)
+
 #define PRIMARY_DISC_SMALL_DB                                          \
                raw_pdu(0x10, 0x01, 0x00, 0xff, 0xff, 0x00, 0x28),      \
                raw_pdu(0x11, 0x06, 0x10, 0xF0, 0x17, 0xF0, 0x00, 0x18, \
@@ -304,9 +362,12 @@ static gboolean context_quit(gpointer user_data)
        if (step && step->post_func)
                step->post_func(context);
 
-       destroy_context(context);
+       if (context->data->pdu_list[context->pdu_offset].valid)
+               tester_test_abort();
+       else
+               tester_test_passed();
 
-       tester_test_passed();
+       destroy_context(context);
 
        return FALSE;
 }
@@ -910,6 +971,11 @@ static void test_signed_write(struct context *context)
        uint8_t key[16] = {0xD8, 0x51, 0x59, 0x48, 0x45, 0x1F, 0xEA, 0x32, 0x0D,
                                0xC0, 0x5A, 0x2E, 0x88, 0x30, 0x81, 0x88 };
 
+       if (!bt_att_has_crypto(context->att)) {
+               context_quit(context);
+               return;
+       }
+
        g_assert(bt_att_set_local_key(context->att, key, local_counter,
                                                                context));
 
@@ -952,22 +1018,101 @@ static const struct test_step test_signed_write_seclevel_1 = {
        .length = 0x03
 };
 
+static void test_long_write_cb(bool success, bool reliable_error,
+                                       uint8_t att_ecode, void *user_data)
+{
+       struct context *context = user_data;
+       const struct test_step *step = context->data->step;
+
+       g_assert(att_ecode == step->expected_att_ecode);
+
+       context_quit(context);
+}
+
+static void test_long_write(struct context *context)
+{
+       const struct test_step *step = context->data->step;
+
+       g_assert(bt_gatt_client_write_long_value(context->client, false,
+                               step->handle, 0, step->value,
+                               step->length, test_long_write_cb,
+                               context, NULL));
+}
+
+/* The maximum length of an attribute value shall be 512 octets. */
+static const uint8_t long_data_2[512] = { [0 ... 511] = 0xff };
+
+static const struct test_step test_long_write_1 = {
+       .handle = 0x0007,
+       .func = test_long_write,
+       .expected_att_ecode = 0,
+       .value = long_data_2,
+       .length = sizeof(long_data_2)
+};
+
+static const struct test_step test_long_write_2 = {
+       .handle = 0x0000,
+       .func = test_long_write,
+       .expected_att_ecode = 0x01,
+       .value = write_data_1,
+       .length = 0x03
+};
+
+static const struct test_step test_long_write_3 = {
+       .handle = 0x0003,
+       .func = test_long_write,
+       .expected_att_ecode = 0x03,
+       .value = write_data_1,
+       .length = 0x03
+};
+
+static const struct test_step test_long_write_4 = {
+       .handle = 0x0007,
+       .func = test_long_write,
+       .expected_att_ecode = 0x08,
+       .value = write_data_1,
+       .length = 0x03
+};
+
+static const struct test_step test_long_write_5 = {
+       .handle = 0x0007,
+       .func = test_long_write,
+       .expected_att_ecode = 0x05,
+       .value = write_data_1,
+       .length = 0x03
+};
+
+static const struct test_step test_long_write_6 = {
+       .handle = 0x0007,
+       .func = test_long_write,
+       .expected_att_ecode = 0x0c,
+       .value = write_data_1,
+       .length = 0x03
+};
+
 static void att_write_cb(struct gatt_db_attribute *att, int err,
                                                                void *user_data)
 {
        g_assert(!err);
 }
 
-static struct gatt_db_attribute *add_char_with_value(struct gatt_db *db,
-                                       struct gatt_db_attribute *service_att,
-                                       bt_uuid_t *uuid,
-                                       uint32_t att_permissions,
-                                       uint8_t char_properties,
-                                       const void *value, size_t len)
+static struct gatt_db_attribute *
+add_char_with_value(struct gatt_db_attribute *service_att, uint16_t handle,
+                               bt_uuid_t *uuid, uint32_t att_permissions,
+                               uint8_t char_properties, const void *value,
+                               size_t len)
 {
        struct gatt_db_attribute *attrib;
 
-       attrib = gatt_db_service_add_characteristic(service_att, uuid,
+       if (handle)
+               attrib = gatt_db_service_insert_characteristic(service_att,
+                                                               handle, uuid,
+                                                               att_permissions,
+                                                               char_properties,
+                                                               NULL, NULL,
+                                                               NULL);
+       else
+               attrib = gatt_db_service_add_characteristic(service_att, uuid,
                                                                att_permissions,
                                                                char_properties,
                                                                NULL, NULL,
@@ -982,14 +1127,19 @@ static struct gatt_db_attribute *add_char_with_value(struct gatt_db *db,
 }
 
 static struct gatt_db_attribute *
-add_desc_with_value(struct gatt_db_attribute *att, bt_uuid_t *uuid,
-                               uint32_t att_perms, const uint8_t *value,
-                               size_t len)
+add_desc_with_value(struct gatt_db_attribute *att, uint16_t handle,
+                                       bt_uuid_t *uuid, uint32_t att_perms,
+                                       const uint8_t *value, size_t len)
 {
        struct gatt_db_attribute *desc_att;
 
-       desc_att = gatt_db_service_add_descriptor(att, uuid, att_perms, NULL,
-                                                               NULL, NULL);
+       if (handle)
+               desc_att = gatt_db_service_insert_descriptor(att, handle, uuid,
+                                                       att_perms, NULL, NULL,
+                                                       NULL);
+       else
+               desc_att = gatt_db_service_add_descriptor(att, uuid, att_perms,
+                                                       NULL, NULL, NULL);
 
        gatt_db_attribute_write(desc_att, 0, value, len, 0x00, NULL,
                                                        att_write_cb, NULL);
@@ -1116,7 +1266,7 @@ static struct gatt_db *make_db(const struct att_handle_spec *spec)
                case CHARACTERISTIC:
                        bt_string_to_uuid(&uuid, spec->uuid);
 
-                       add_char_with_value(db, att, &uuid,
+                       add_char_with_value(att, spec->handle, &uuid,
                                                        spec->att_permissions,
                                                        spec->char_properties,
                                                        spec->value, spec->len);
@@ -1126,7 +1276,8 @@ static struct gatt_db *make_db(const struct att_handle_spec *spec)
                case DESCRIPTOR:
                        bt_string_to_uuid(&uuid, spec->uuid);
 
-                       add_desc_with_value(att, &uuid, spec->att_permissions,
+                       add_desc_with_value(att, spec->handle, &uuid,
+                                                       spec->att_permissions,
                                                        spec->value, spec->len);
 
                        break;
@@ -1160,6 +1311,102 @@ static struct gatt_db *make_service_data_1_db(void)
        return make_db(specs);
 }
 
+#define CHARACTERISTIC_STR_AT(chr_handle, chr_uuid, permissions, properties, \
+                                                               string) \
+       {                                                               \
+               .valid = true,                                          \
+               .handle = chr_handle,                                   \
+               .type = CHARACTERISTIC,                                 \
+               .uuid = STR(chr_uuid),                                  \
+               .att_permissions = permissions,                         \
+               .char_properties = properties,                          \
+               .value = (uint8_t *)string,                             \
+               .len = strlen(string),                                  \
+       }
+
+#define DESCRIPTOR_STR_AT(desc_handle, desc_uuid, permissions, string) \
+       {                                                               \
+               .valid = true,                                          \
+               .handle = desc_handle,                                  \
+               .type = DESCRIPTOR,                                     \
+               .uuid = STR(desc_uuid),                                 \
+               .att_permissions = permissions,                         \
+               .value = (uint8_t *)string,                             \
+               .len = strlen(string),                                  \
+       }
+
+static struct gatt_db *make_service_data_2_db(void)
+{
+       const struct att_handle_spec specs[] = {
+               PRIMARY_SERVICE(0x0001, GATT_UUID, 4),
+               CHARACTERISTIC_STR(GATT_CHARAC_DEVICE_NAME, BT_ATT_PERM_READ,
+                                       BT_GATT_CHRC_PROP_READ, "BlueZ"),
+               DESCRIPTOR_STR(GATT_CHARAC_USER_DESC_UUID, BT_ATT_PERM_READ,
+                                                               "Device Name"),
+               PRIMARY_SERVICE(0x0005, HEART_RATE_UUID, 6),
+               CHARACTERISTIC_STR_AT(0x0008,
+                                       GATT_CHARAC_MANUFACTURER_NAME_STRING,
+                                       BT_ATT_PERM_READ,
+                                       BT_GATT_CHRC_PROP_READ |
+                                       BT_GATT_CHRC_PROP_WRITE, ""),
+               DESCRIPTOR_STR_AT(0x000a, GATT_CHARAC_USER_DESC_UUID,
+                                       BT_ATT_PERM_READ, "Manufacturer Name"),
+               { }
+       };
+
+       return make_db(specs);
+}
+
+#define CHARACTERISTIC_AT(chr_handle, chr_uuid, permissions, properties, \
+                                                       bytes...)       \
+       {                                                               \
+               .valid = true,                                          \
+               .handle = chr_handle,                                   \
+               .type = CHARACTERISTIC,                                 \
+               .uuid = STR(chr_uuid),                                  \
+               .att_permissions = permissions,                         \
+               .char_properties = properties,                          \
+               .value = data(bytes),                                   \
+               .len = sizeof(data(bytes)),                             \
+       }
+
+#define DESCRIPTOR_AT(desc_handle, desc_uuid, permissions, bytes...)   \
+       {                                                               \
+               .valid = true,                                          \
+               .handle = desc_handle,                                  \
+               .type = DESCRIPTOR,                                     \
+               .uuid = STR(desc_uuid),                                 \
+               .att_permissions = permissions,                         \
+               .value = data(bytes),                                   \
+               .len = sizeof(data(bytes)),                             \
+       }
+
+static struct gatt_db *make_service_data_3_db(void)
+{
+       const struct att_handle_spec specs[] = {
+               PRIMARY_SERVICE(0x0100, GAP_UUID, 0x0121 - 0x0100 + 1),
+               CHARACTERISTIC_STR_AT(0x0111, GATT_CHARAC_DEVICE_NAME,
+                                       BT_ATT_PERM_READ,
+                                       BT_GATT_CHRC_PROP_READ, "BlueZ"),
+               CHARACTERISTIC_AT(0x0121, GATT_CHARAC_APPEARANCE,
+                                       BT_ATT_PERM_READ,
+                                       BT_GATT_CHRC_PROP_READ, 0x00, 0x00),
+               PRIMARY_SERVICE(0x0200, GATT_UUID, 0x0200 - 0x0200 + 1),
+               PRIMARY_SERVICE(0x0300, HEART_RATE_UUID, 0x0320 - 0x0300 + 1),
+               CHARACTERISTIC_STR_AT(0x0311,
+                                       GATT_CHARAC_MANUFACTURER_NAME_STRING,
+                                       BT_ATT_PERM_READ,
+                                       BT_GATT_CHRC_PROP_READ |
+                                       BT_GATT_CHRC_PROP_WRITE, ""),
+               DESCRIPTOR_AT(0x0320, GATT_CLIENT_CHARAC_CFG_UUID,
+                                       BT_ATT_PERM_READ | BT_ATT_PERM_WRITE,
+                                       0x00, 0x00),
+               { }
+       };
+
+       return make_db(specs);
+}
+
 /*
  * Defined Test database 1:
  * Tiny database fits into a single minimum sized-pdu.
@@ -1196,8 +1443,8 @@ static struct gatt_db *make_test_spec_small_db(void)
                                                        BT_GATT_CHRC_PROP_READ,
                                                        "BlueZ Unit Tester"),
                CHARACTERISTIC(0000B009-0000-0000-0123-456789abcdef,
-                                               BT_ATT_PERM_READ,
-                                               BT_GATT_CHRC_PROP_READ, 0x09),
+                                       BT_ATT_PERM_READ | BT_ATT_PERM_WRITE,
+                                       BT_GATT_CHRC_PROP_READ, 0x09),
                CHARACTERISTIC(GATT_CHARAC_APPEARANCE, BT_ATT_PERM_READ,
                                        BT_GATT_CHRC_PROP_READ, 0x00, 0x00),
                PRIMARY_SERVICE(0xFFFF, DEVICE_INFORMATION_UUID, 1),
@@ -1740,9 +1987,6 @@ static const struct test_step test_long_read_1 = {
        .length = 0x03
 };
 
-/* The maximum length of an attribute value shall be 512 octets. */
-static const uint8_t long_data_2[512] = { [0 ... 511] = 0xff };
-
 static const struct test_step test_long_read_2 = {
        .handle = 0x0003,
        .func = test_long_read,
@@ -1953,11 +2197,14 @@ static const struct test_step test_indication_server_1 = {
 
 int main(int argc, char *argv[])
 {
-       struct gatt_db *service_db_1, *ts_small_db, *ts_large_db_1;
+       struct gatt_db *service_db_1, *service_db_2, *service_db_3;
+       struct gatt_db *ts_small_db, *ts_large_db_1;
 
        tester_init(&argc, &argv);
 
        service_db_1 = make_service_data_1_db();
+       service_db_2 = make_service_data_2_db();
+       service_db_3 = make_service_data_3_db();
        ts_small_db = make_test_spec_small_db();
        ts_large_db_1 = make_test_spec_large_db_1();
 
@@ -2261,6 +2508,18 @@ int main(int argc, char *argv[])
                        raw_pdu(0x05, 0x01, 0x15, 0x00, 0x04, 0x29, 0x16, 0x00,
                                        0x05, 0x29));
 
+       define_test_client("/TP/GAD/CL/BV-06-C/client-1", test_client,
+                       service_db_1, NULL,
+                       SERVICE_DATA_1_PDUS);
+
+       define_test_client("/TP/GAD/CL/BV-06-C/client-2", test_client,
+                       service_db_2, NULL,
+                       SERVICE_DATA_2_PDUS);
+
+       define_test_client("/TP/GAD/CL/BV-06-C/client-3", test_client,
+                       service_db_3, NULL,
+                       SERVICE_DATA_3_PDUS);
+
        define_test_server("/TP/GAD/SR/BV-06-C/small", test_server,
                        ts_small_db, NULL,
                        raw_pdu(0x03, 0x00, 0x02),
@@ -3099,6 +3358,28 @@ int main(int argc, char *argv[])
                        raw_pdu(0x12, 0x07, 0x00, 0x01, 0x02, 0x03),
                        raw_pdu(0x01, 0x12, 0x07, 0x00, 0x0c));
 
+       define_test_server("/TP/GAW/SR/BV-07-C/small", test_server,
+                       ts_small_db, NULL,
+                       raw_pdu(0x03, 0x00, 0x02),
+                       raw_pdu(0x16, 0x03, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03),
+                       raw_pdu(0x17, 0x03, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03),
+                       raw_pdu(0x18, 0x00),
+                       raw_pdu(0x19),
+                       raw_pdu(0x0a, 0x03, 0x00),
+                       raw_pdu(0x0b, 0x42, 0x6c, 0x75, 0x65, 0x5a));
+
+       define_test_server("/TP/GAW/SR/BV-07-C/large-1", test_server,
+                       ts_large_db_1, NULL,
+                       raw_pdu(0x03, 0x00, 0x02),
+                       raw_pdu(0x16, 0xc4, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03),
+                       raw_pdu(0x17, 0xc4, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03),
+                       raw_pdu(0x18, 0x00),
+                       raw_pdu(0x19),
+                       raw_pdu(0x0a, 0xc4, 0x00),
+                       raw_pdu(0x0b, '1', '1', '1', '1', '1', '2', '2', '2',
+                               '2', '2', '3', '3', '3', '3', '3', '4', '4',
+                               '4', '4', '4', '5'));
+
        define_test_server("/TP/GAW/SR/BV-03-C/small", test_server,
                        ts_small_db, NULL,
                        raw_pdu(0x03, 0x00, 0x02),
@@ -3135,6 +3416,390 @@ int main(int argc, char *argv[])
                        raw_pdu(0x12, 0x04, 0x00, 0x01, 0x02, 0x03),
                        raw_pdu(0x01, 0x12, 0x04, 0x00, 0x03));
 
+       define_test_client("/TP/GAW/CL/BV-05-C", test_client, service_db_1,
+                       &test_long_write_1,
+                       SERVICE_DATA_1_PDUS,
+                       raw_pdu(0x16, 0x07, 0x00, 0x00, 0x00,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff),
+                       raw_pdu(0x17, 0x07, 0x00, 0x00, 0x00,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff),
+                       raw_pdu(0x16, 0x07, 0x00, 0xfb, 0x01,
+                               0xff, 0xff, 0xff, 0xff, 0xff),
+                       raw_pdu(0x17, 0x07, 0x00, 0xfb, 0x01,
+                               0xff, 0xff, 0xff, 0xff, 0xff),
+                       raw_pdu(0x18, 0x01),
+                       raw_pdu(0x19));
+
+       define_test_client("/TP/GAW/CL/BI-07-C", test_client, service_db_1,
+                       &test_long_write_2,
+                       SERVICE_DATA_1_PDUS,
+                       raw_pdu(0x16, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03),
+                       raw_pdu(0x01, 0x16, 0x00, 0x00, 0x01),
+                       raw_pdu(0x18, 0x00),
+                       raw_pdu(0x19));
+
+       define_test_client("/TP/GAW/CL/BI-08-C", test_client, service_db_1,
+                       &test_long_write_3,
+                       SERVICE_DATA_1_PDUS,
+                       raw_pdu(0x16, 0x03, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03),
+                       raw_pdu(0x01, 0x16, 0x03, 0x00, 0x03),
+                       raw_pdu(0x18, 0x00),
+                       raw_pdu(0x19));
+
+       define_test_client("/TP/GAW/CL/BI-11-C", test_client, service_db_1,
+                       &test_long_write_4,
+                       SERVICE_DATA_1_PDUS,
+                       raw_pdu(0x16, 0x07, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03),
+                       raw_pdu(0x01, 0x16, 0x07, 0x00, 0x08),
+                       raw_pdu(0x18, 0x00),
+                       raw_pdu(0x19));
+
+       define_test_client("/TP/GAW/CL/BI-12-C", test_client, service_db_1,
+                       &test_long_write_5,
+                       SERVICE_DATA_1_PDUS,
+                       raw_pdu(0x16, 0x07, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03),
+                       raw_pdu(0x01, 0x16, 0x07, 0x00, 0x05),
+                       raw_pdu(0x18, 0x00),
+                       raw_pdu(0x19));
+
+       define_test_client("/TP/GAW/CL/BI-13-C", test_client, service_db_1,
+                       &test_long_write_6,
+                       SERVICE_DATA_1_PDUS,
+                       raw_pdu(0x16, 0x07, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03),
+                       raw_pdu(0x01, 0x16, 0x07, 0x00, 0x0c),
+                       raw_pdu(0x18, 0x00),
+                       raw_pdu(0x19));
+
+       define_test_server("/TP/GAW/SR/BV-05-C/small", test_server,
+                       ts_small_db, NULL,
+                       raw_pdu(0x03, 0x00, 0x02),
+                       raw_pdu(0x16, 0x03, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff),
+                       raw_pdu(0x17, 0x03, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff),
+                       raw_pdu(0x16, 0x03, 0x00, 0x3f, 0x00, 0xff),
+                       raw_pdu(0x17, 0x03, 0x00, 0x3f, 0x00, 0xff),
+                       raw_pdu(0x18, 0x01),
+                       raw_pdu(0x19));
+
+       define_test_server("/TP/GAW/SR/BV-05-C/large-1", test_server,
+                       ts_large_db_1, NULL,
+                       raw_pdu(0x03, 0x00, 0x02),
+                       raw_pdu(0x16, 0x82, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff),
+                       raw_pdu(0x17, 0x82, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff),
+                       raw_pdu(0x16, 0x82, 0x00, 0x3f, 0x00, 0xff),
+                       raw_pdu(0x17, 0x82, 0x00, 0x3f, 0x00, 0xff),
+                       raw_pdu(0x18, 0x01),
+                       raw_pdu(0x19));
+
+       define_test_server("/TP/GAW/SR/BI-07-C/small", test_server,
+                       ts_small_db, NULL,
+                       raw_pdu(0x03, 0x00, 0x02),
+                       raw_pdu(0x16, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff),
+                       raw_pdu(0x01, 0x16, 0x00, 0x00, 0x01));
+
+       define_test_server("/TP/GAW/SR/BI-07-C/large-1", test_server,
+                       ts_large_db_1, NULL,
+                       raw_pdu(0x03, 0x00, 0x02),
+                       raw_pdu(0x16, 0x0f, 0xf0, 0x00, 0x00, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff),
+                       raw_pdu(0x01, 0x16, 0x0f, 0xf0, 0x01));
+
+       define_test_server("/TP/GAW/SR/BI-08-C/small", test_server,
+                       ts_small_db, NULL,
+                       raw_pdu(0x03, 0x00, 0x02),
+                       raw_pdu(0x16, 0x05, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff),
+                       raw_pdu(0x01, 0x16, 0x05, 0x00, 0x03));
+
+       define_test_server("/TP/GAW/SR/BI-08-C/large-1", test_server,
+                       ts_large_db_1, NULL,
+                       raw_pdu(0x03, 0x00, 0x02),
+                       raw_pdu(0x16, 0x73, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff),
+                       raw_pdu(0x01, 0x16, 0x73, 0x00, 0x03));
+
+       define_test_server("/TP/GAW/SR/BV-06-C/small", test_server,
+                       ts_small_db, NULL,
+                       raw_pdu(0x03, 0x00, 0x02),
+                       raw_pdu(0x16, 0x03, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03),
+                       raw_pdu(0x17, 0x03, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03),
+                       raw_pdu(0x18, 0x01),
+                       raw_pdu(0x19));
+
+       define_test_server("/TP/GAW/SR/BV-06-C/large-1", test_server,
+                       ts_large_db_1, NULL,
+                       raw_pdu(0x03, 0x00, 0x02),
+                       raw_pdu(0x16, 0x82, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03),
+                       raw_pdu(0x17, 0x82, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03),
+                       raw_pdu(0x18, 0x01),
+                       raw_pdu(0x19));
+
+       define_test_server("/TP/GAW/SR/BV-10-C/small", test_server,
+                       ts_small_db, NULL,
+                       raw_pdu(0x03, 0x00, 0x02),
+                       raw_pdu(0x16, 0x03, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03),
+                       raw_pdu(0x17, 0x03, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03),
+                       raw_pdu(0x16, 0x15, 0xf0, 0x00, 0x00, 0x01, 0x02, 0x03),
+                       raw_pdu(0x17, 0x15, 0xf0, 0x00, 0x00, 0x01, 0x02, 0x03),
+                       raw_pdu(0x16, 0x03, 0x00, 0x03, 0x00, 0x04, 0x05, 0x06),
+                       raw_pdu(0x17, 0x03, 0x00, 0x03, 0x00, 0x04, 0x05, 0x06),
+                       raw_pdu(0x16, 0x15, 0xf0, 0x03, 0x00, 0x04, 0x05, 0x06),
+                       raw_pdu(0x17, 0x15, 0xf0, 0x03, 0x00, 0x04, 0x05, 0x06),
+                       raw_pdu(0x18, 0x01),
+                       raw_pdu(0x19));
+
+       define_test_server("/TP/GAW/SR/BV-10-C/large-1", test_server,
+                       ts_large_db_1, NULL,
+                       raw_pdu(0x03, 0x00, 0x02),
+                       raw_pdu(0x16, 0x82, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03),
+                       raw_pdu(0x17, 0x82, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03),
+                       raw_pdu(0x16, 0x25, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03),
+                       raw_pdu(0x17, 0x25, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03),
+                       raw_pdu(0x16, 0x82, 0x00, 0x03, 0x00, 0x04, 0x05, 0x06),
+                       raw_pdu(0x17, 0x82, 0x00, 0x03, 0x00, 0x04, 0x05, 0x06),
+                       raw_pdu(0x16, 0x25, 0x00, 0x03, 0x00, 0x04, 0x05, 0x06),
+                       raw_pdu(0x17, 0x25, 0x00, 0x03, 0x00, 0x04, 0x05, 0x06),
+                       raw_pdu(0x18, 0x01),
+                       raw_pdu(0x19));
+
+       define_test_server("/TP/GAW/SR/BI-14-C/small", test_server,
+                       ts_small_db, NULL,
+                       raw_pdu(0x03, 0x00, 0x02),
+                       raw_pdu(0x16, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03),
+                       raw_pdu(0x01, 0x16, 0x00, 0x00, 0x01));
+
+       define_test_server("/TP/GAW/SR/BI-14-C/large-1", test_server,
+                       ts_large_db_1, NULL,
+                       raw_pdu(0x03, 0x00, 0x02),
+                       raw_pdu(0x16, 0x0f, 0xf0, 0x00, 0x00, 0x01, 0x02, 0x03),
+                       raw_pdu(0x01, 0x16, 0x0f, 0xf0, 0x01));
+
+       define_test_server("/TP/GAW/SR/BI-15-C/small", test_server,
+                       ts_small_db, NULL,
+                       raw_pdu(0x03, 0x00, 0x02),
+                       raw_pdu(0x16, 0x05, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03),
+                       raw_pdu(0x01, 0x16, 0x05, 0x00, 0x03));
+
+       define_test_server("/TP/GAW/SR/BI-15-C/large-1", test_server,
+                       ts_large_db_1, NULL,
+                       raw_pdu(0x03, 0x00, 0x02),
+                       raw_pdu(0x16, 0x73, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03),
+                       raw_pdu(0x01, 0x16, 0x73, 0x00, 0x03));
+
        define_test_client("/TP/GAW/CL/BV-08-C", test_client, service_db_1,
                        &test_write_7,
                        SERVICE_DATA_1_PDUS,
@@ -3171,5 +3836,101 @@ int main(int argc, char *argv[])
                        raw_pdu(0x12, 0x08, 0x00, 0x01, 0x02, 0x03),
                        raw_pdu(0x01, 0x12, 0x08, 0x00, 0x0c));
 
+       define_test_server("/TP/GAW/SR/BV-08-C/small", test_server,
+                       ts_small_db, NULL,
+                       raw_pdu(0x03, 0x00, 0x02),
+                       raw_pdu(0x12, 0x04, 0x00, 0x01, 0x02, 0x03),
+                       raw_pdu(0x13));
+
+       define_test_server("/TP/GAW/SR/BV-08-C/large-1", test_server,
+                       ts_large_db_1, NULL,
+                       raw_pdu(0x03, 0x00, 0x02),
+                       raw_pdu(0x12, 0x83, 0x00, 0x01, 0x02, 0x03),
+                       raw_pdu(0x13));
+
+       define_test_server("/TP/GAW/SR/BI-20-C/small", test_server,
+                       ts_small_db, NULL,
+                       raw_pdu(0x03, 0x00, 0x02),
+                       raw_pdu(0x12, 0x00, 0x00, 0x01, 0x02, 0x03),
+                       raw_pdu(0x01, 0x12, 0x00, 0x00, 0x01));
+
+       define_test_server("/TP/GAW/SR/BI-20-C/large-1", test_server,
+                       ts_large_db_1, NULL,
+                       raw_pdu(0x03, 0x00, 0x02),
+                       raw_pdu(0x12, 0x0f, 0xf0, 0x01, 0x02, 0x03),
+                       raw_pdu(0x01, 0x12, 0x0f, 0xf0, 0x01));
+
+       define_test_server("/TP/GAW/SR/BI-21-C/small", test_server,
+                       ts_small_db, NULL,
+                       raw_pdu(0x03, 0x00, 0x02),
+                       raw_pdu(0x12, 0x13, 0xf0, 0x01, 0x02, 0x03),
+                       raw_pdu(0x01, 0x12, 0x13, 0xf0, 0x03));
+
+       define_test_server("/TP/GAW/SR/BI-21-C/large-1", test_server,
+                       ts_large_db_1, NULL,
+                       raw_pdu(0x03, 0x00, 0x02),
+                       raw_pdu(0x12, 0x04, 0x00, 0x01, 0x02, 0x03),
+                       raw_pdu(0x01, 0x12, 0x04, 0x00, 0x03));
+
+       define_test_server("/TP/GAW/SR/BV-09-C/small", test_server,
+                       ts_small_db, NULL,
+                       raw_pdu(0x03, 0x00, 0x02),
+                       raw_pdu(0x16, 0x04, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff),
+                       raw_pdu(0x17, 0x04, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff),
+                       raw_pdu(0x16, 0x04, 0x00, 0x3f, 0x00, 0xff),
+                       raw_pdu(0x17, 0x04, 0x00, 0x3f, 0x00, 0xff),
+                       raw_pdu(0x18, 0x01),
+                       raw_pdu(0x19));
+
+       define_test_server("/TP/GAW/SR/BV-09-C/large-1", test_server,
+                       ts_large_db_1, NULL,
+                       raw_pdu(0x03, 0x00, 0x02),
+                       raw_pdu(0x16, 0x83, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff),
+                       raw_pdu(0x17, 0x83, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff),
+                       raw_pdu(0x16, 0x83, 0x00, 0x3f, 0x00, 0xff),
+                       raw_pdu(0x17, 0x83, 0x00, 0x3f, 0x00, 0xff),
+                       raw_pdu(0x18, 0x01),
+                       raw_pdu(0x19));
+
+       define_test_server("/TP/GAW/SR/BI-25-C/small", test_server,
+                       ts_small_db, NULL,
+                       raw_pdu(0x03, 0x00, 0x02),
+                       raw_pdu(0x16, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff),
+                       raw_pdu(0x01, 0x16, 0x00, 0x00, 0x01));
+
+       define_test_server("/TP/GAW/SR/BI-25-C/large-1", test_server,
+                       ts_large_db_1, NULL,
+                       raw_pdu(0x03, 0x00, 0x02),
+                       raw_pdu(0x16, 0x0f, 0xf0, 0x00, 0x00, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff),
+                       raw_pdu(0x01, 0x16, 0x0f, 0xf0, 0x01));
+
+       define_test_server("/TP/GAW/SR/BI-26-C/small", test_server,
+                       ts_small_db, NULL,
+                       raw_pdu(0x03, 0x00, 0x02),
+                       raw_pdu(0x16, 0x13, 0xf0, 0x00, 0x00, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff),
+                       raw_pdu(0x01, 0x16, 0x13, 0xf0, 0x03));
+
+       define_test_server("/TP/GAW/SR/BI-26-C/large-1", test_server,
+                       ts_large_db_1, NULL,
+                       raw_pdu(0x03, 0x00, 0x02),
+                       raw_pdu(0x16, 0x04, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff),
+                       raw_pdu(0x01, 0x16, 0x04, 0x00, 0x03));
+
        return tester_run();
 }
index 11ad1f7..ad426fe 100644 (file)
@@ -353,7 +353,7 @@ static void proxy_get_string(GDBusProxy *proxy, void *user_data)
        g_assert(dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_STRING);
 
        dbus_message_iter_get_basic(&iter, &string);
-       g_assert(g_strcmp0(string, "value") == 0);
+       g_assert_cmpstr(string, ==, "value");
 
        g_dbus_client_unref(context->dbus_client);
 }
@@ -908,6 +908,56 @@ static void client_proxy_removed(void)
        destroy_context(context);
 }
 
+static void client_no_object_manager(void)
+{
+       struct context *context = create_context();
+       DBusConnection *conn;
+       DBusMessageIter iter;
+       static const GDBusPropertyTable string_properties[] = {
+               { "String", "s", get_string, set_string, string_exists },
+               { },
+       };
+
+       if (context == NULL)
+               return;
+
+       conn = g_dbus_setup_private(DBUS_BUS_SESSION, SERVICE_NAME1, NULL);
+       g_assert(conn != NULL);
+
+       context->data = g_strdup("value");
+
+       g_dbus_register_interface(conn,
+                               SERVICE_PATH, SERVICE_NAME1,
+                               methods, signals, string_properties,
+                               context, NULL);
+
+       context->dbus_client = g_dbus_client_new_full(context->dbus_conn,
+                                               SERVICE_NAME1, SERVICE_PATH,
+                                               NULL);
+
+       g_dbus_client_set_disconnect_watch(context->dbus_client,
+                                               disconnect_handler, context);
+
+       context->proxy = g_dbus_proxy_new(context->dbus_client, SERVICE_PATH,
+                                                               SERVICE_NAME1);
+
+       g_dbus_client_set_proxy_handlers(context->dbus_client, proxy_get_string,
+                                               NULL, NULL, context);
+
+       g_assert(!g_dbus_proxy_get_property(context->proxy, "String", &iter));
+
+       g_main_loop_run(context->main_loop);
+
+       g_dbus_proxy_unref(context->proxy);
+       g_dbus_unregister_interface(conn, SERVICE_PATH, SERVICE_NAME1);
+
+       dbus_connection_flush(conn);
+       dbus_connection_close(conn);
+       dbus_connection_unref(conn);
+
+       destroy_context(context);
+}
+
 static void proxy_force_disconnect(GDBusProxy *proxy, void *user_data)
 {
        struct context *context = user_data;
@@ -1051,6 +1101,9 @@ int main(int argc, char *argv[])
 
        g_test_add_func("/gdbus/client_proxy_removed", client_proxy_removed);
 
+       g_test_add_func("/gdbus/client_no_object_manager",
+                                               client_no_object_manager);
+
        g_test_add_func("/gdbus/client_force_disconnect",
                                                client_force_disconnect);
 
index face9a4..66966ce 100644 (file)
@@ -95,9 +95,8 @@ struct test_data {
                };                                                      \
                static struct test_data data;                           \
                data.test_name = g_strdup(name);                        \
-               data.pdu_list = g_malloc(sizeof(pdus));                 \
+               data.pdu_list = g_memdup(pdus, sizeof(pdus));           \
                data.result_func = result_function;                     \
-               memcpy(data.pdu_list, pdus, sizeof(pdus));              \
                g_test_add_data_func(name, &data, function);            \
                data.test_handler = test_handler;                       \
        } while (0)
@@ -110,10 +109,9 @@ struct test_data {
                };                                                      \
                static struct test_data data;                           \
                data.test_name = g_strdup(name);                        \
-               data.pdu_list = g_malloc(sizeof(pdus));                 \
+               data.pdu_list = g_memdup(pdus, sizeof(pdus));           \
                data.hf_result_func = result_func;                      \
                data.response_func = response_function;                 \
-               memcpy(data.pdu_list, pdus, sizeof(pdus));              \
                g_test_add_data_func(name, &data, function);            \
                data.test_handler = test_hf_handler;                    \
        } while (0)
diff --git a/unit/test-hog.c b/unit/test-hog.c
new file mode 100644 (file)
index 0000000..778f087
--- /dev/null
@@ -0,0 +1,440 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2015  Intel Corporation. All rights reserved.
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <unistd.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <fcntl.h>
+
+#include <glib.h>
+
+#include "src/shared/util.h"
+#include "src/shared/tester.h"
+
+#include "attrib/gattrib.h"
+
+#include "android/hog.h"
+
+struct test_pdu {
+       bool valid;
+       const uint8_t *data;
+       size_t size;
+};
+
+struct test_data {
+       char *test_name;
+       struct test_pdu *pdu_list;
+};
+
+struct context {
+       GAttrib *attrib;
+       struct bt_hog *hog;
+       guint source;
+       guint process;
+       int fd;
+       unsigned int pdu_offset;
+       const struct test_data *data;
+};
+
+#define data(args...) ((const unsigned char[]) { args })
+
+#define raw_pdu(args...)    \
+{      \
+       .valid = true,          \
+       .data = data(args), \
+       .size = sizeof(data(args)),\
+}
+
+#define false_pdu()    \
+{                                              \
+               .valid = false, \
+}
+
+#define define_test(name, function, args...)      \
+       do {    \
+               const struct test_pdu pdus[] = {                        \
+                       args, { }                                       \
+               };              \
+               static struct test_data data;      \
+               data.test_name = g_strdup(name);   \
+               data.pdu_list = g_memdup(pdus, sizeof(pdus));           \
+               tester_add(name, &data, NULL, function, NULL);     \
+       } while (0)
+
+static void test_debug(const char *str, void *user_data)
+{
+       const char *prefix = user_data;
+
+       tester_debug("%s%s", prefix, str);
+}
+
+static gboolean context_quit(gpointer user_data)
+{
+       struct context *context = user_data;
+
+       if (context->process > 0)
+               g_source_remove(context->process);
+
+       if (context->source > 0)
+               g_source_remove(context->source);
+
+       bt_hog_unref(context->hog);
+
+       g_attrib_unref(context->attrib);
+
+       g_free(context);
+
+       tester_test_passed();
+
+       return FALSE;
+}
+
+static gboolean send_pdu(gpointer user_data)
+{
+       struct context *context = user_data;
+       const struct test_pdu *pdu;
+       ssize_t len;
+
+       pdu = &context->data->pdu_list[context->pdu_offset++];
+
+       len = write(context->fd, pdu->data, pdu->size);
+
+       util_hexdump('<', pdu->data, len, test_debug, "hog: ");
+
+       g_assert_cmpint(len, ==, pdu->size);
+
+       context->process = 0;
+
+       if (!context->data->pdu_list[context->pdu_offset].valid)
+               context_quit(context);
+
+       return FALSE;
+}
+
+static gboolean test_handler(GIOChannel *channel, GIOCondition cond,
+                                                       gpointer user_data)
+{
+       struct context *context = user_data;
+       unsigned char buf[512];
+       const struct test_pdu *pdu;
+       ssize_t len;
+       int fd;
+
+       pdu = &context->data->pdu_list[context->pdu_offset++];
+
+       if (cond & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
+               context->source = 0;
+               g_print("%s: cond %x\n", __func__, cond);
+               return FALSE;
+       }
+
+       fd = g_io_channel_unix_get_fd(channel);
+
+       len = read(fd, buf, sizeof(buf));
+
+       g_assert(len > 0);
+
+       util_hexdump('>', buf, len, test_debug, "hog: ");
+
+       g_assert_cmpint(len, ==, pdu->size);
+
+       g_assert(memcmp(buf, pdu->data, pdu->size) == 0);
+
+       context->process = g_idle_add(send_pdu, context);
+
+       return TRUE;
+}
+
+static struct context *create_context(gconstpointer data)
+{
+       struct context *context;
+       GIOChannel *channel, *att_io;
+       int err, sv[2], fd;
+       char name[] = "bluez-hog";
+       uint16_t vendor = 0x0002;
+       uint16_t product = 0x0001;
+       uint16_t version = 0x0001;
+
+       context = g_new0(struct context, 1);
+       err = socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0, sv);
+       g_assert(err == 0);
+
+       att_io = g_io_channel_unix_new(sv[0]);
+
+       g_io_channel_set_close_on_unref(att_io, TRUE);
+
+       context->attrib = g_attrib_new(att_io, 23);
+       g_assert(context->attrib);
+
+       g_io_channel_unref(att_io);
+
+       fd = open("/dev/null", O_WRONLY | O_CLOEXEC);
+       g_assert(fd > 0);
+
+       context->hog = bt_hog_new(fd, name, vendor, product, version, NULL);
+       g_assert(context->hog);
+
+       channel = g_io_channel_unix_new(sv[1]);
+
+       g_io_channel_set_close_on_unref(channel, TRUE);
+       g_io_channel_set_encoding(channel, NULL, NULL);
+       g_io_channel_set_buffered(channel, FALSE);
+
+       context->source = g_io_add_watch(channel,
+                               G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+                               test_handler, context);
+       g_assert(context->source > 0);
+
+       g_io_channel_unref(channel);
+
+       context->fd = sv[1];
+       context->data = data;
+
+       return context;
+}
+
+static void test_hog(gconstpointer data)
+{
+       struct context *context = create_context(data);
+
+       g_assert(bt_hog_attach(context->hog, context->attrib));
+}
+
+int main(int argc, char *argv[])
+{
+       tester_init(&argc, &argv);
+
+       define_test("/TP/HGRF/RH/BV-01-I", test_hog,
+               raw_pdu(0x10, 0x01, 0x00, 0xff, 0xff, 0x00, 0x28),
+               raw_pdu(0x11, 0x06, 0x01, 0x00, 0x04, 0x00, 0x12,
+                       0x18, 0x05, 0x00, 0x08, 0x00, 0x12, 0x18),
+               raw_pdu(0x10, 0x09, 0x00, 0xff, 0xff, 0x00, 0x28),
+               raw_pdu(0x01, 0x10, 0x09, 0x00, 0x0a),
+               raw_pdu(0x08, 0x01, 0x00, 0x04, 0x00, 0x03, 0x28),
+               raw_pdu(0x09, 0x07, 0x03, 0x00, 0x02, 0x04, 0x00,
+                       0x4b, 0x2a),
+               raw_pdu(0x08, 0x01, 0x00, 0x04, 0x00, 0x02, 0x28),
+               raw_pdu(0x01, 0x08, 0x01, 0x00, 0x0a),
+               raw_pdu(0x08, 0x05, 0x00, 0x08, 0x00, 0x02, 0x28),
+               raw_pdu(0x01, 0x08, 0x05, 0x00, 0x0a),
+               raw_pdu(0x08, 0x05, 0x00, 0x08, 0x00, 0x03, 0x28),
+               raw_pdu(0x09, 0x07, 0x07, 0x00, 0x02, 0x08, 0x00,
+                       0x4b, 0x2a),
+               raw_pdu(0x0a, 0x04, 0x00),
+               raw_pdu(0x0b, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
+                       0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,
+                       0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14,
+                       0x15, 0x16),
+               raw_pdu(0x0a, 0x08, 0x00),
+               raw_pdu(0x0b, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
+                       0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,
+                       0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14,
+                       0x15, 0x16),
+               raw_pdu(0x0c, 0x04, 0x00, 0x16, 0x00),
+               raw_pdu(0x0d, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
+                       0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,
+                       0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14,
+                       0x15, 0x16),
+               raw_pdu(0x0c, 0x08, 0x00, 0x16, 0x00),
+               raw_pdu(0x0d, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
+                       0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,
+                       0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14,
+                       0x15, 0x16),
+               raw_pdu(0x0c, 0x04, 0x00, 0x2c, 0x00),
+               raw_pdu(0x0d, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
+                       0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,
+                       0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13),
+               raw_pdu(0x0c, 0x08, 0x00, 0x2c, 0x00),
+               raw_pdu(0x0d, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
+                       0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,
+                       0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13));
+
+       define_test("/TP/HGRF/RH/BV-08-I", test_hog,
+               raw_pdu(0x10, 0x01, 0x00, 0xff, 0xff, 0x00, 0x28),
+               raw_pdu(0x11, 0x06, 0x01, 0x00, 0x05, 0x00, 0x12,
+                       0x18, 0x06, 0x00, 0x0a, 0x00, 0x12, 0x18),
+               raw_pdu(0x10, 0x0b, 0x00, 0xff, 0xff, 0x00, 0x28),
+               raw_pdu(0x01, 0x10, 0x0b, 0x00, 0x0a),
+               raw_pdu(0x08, 0x01, 0x00, 0x05, 0x00, 0x03, 0x28),
+               raw_pdu(0x09, 0x07, 0x03, 0x00, 0x0a, 0x04, 0x00,
+                       0x4d, 0x2a),
+               raw_pdu(0x08, 0x01, 0x00, 0x05, 0x00, 0x02, 0x28),
+               raw_pdu(0x01, 0x08, 0x01, 0x00, 0x0a),
+               raw_pdu(0x08, 0x06, 0x00, 0x0a, 0x00, 0x02, 0x28),
+               raw_pdu(0x01, 0x08, 0x06, 0x00, 0x0a),
+               raw_pdu(0x08, 0x06, 0x00, 0x0a, 0x00, 0x03, 0x28),
+               raw_pdu(0x09, 0x07, 0x08, 0x00, 0x0a, 0x09, 0x00,
+                       0x4d, 0x2a),
+               raw_pdu(0x08, 0x04, 0x00, 0x05, 0x00, 0x03, 0x28),
+               raw_pdu(0x01, 0x08, 0x04, 0x00, 0x0a),
+               raw_pdu(0x08, 0x09, 0x00, 0x0a, 0x00, 0x03, 0x28),
+               raw_pdu(0x01, 0x08, 0x09, 0x00, 0x0a),
+               raw_pdu(0x0a, 0x04, 0x00),
+               raw_pdu(0x0b, 0xee, 0xee, 0xff, 0xff),
+               raw_pdu(0x04, 0x05, 0x00, 0x05, 0x00),
+               raw_pdu(0x05, 0x01, 0x05, 0x00, 0x08, 0x29),
+               raw_pdu(0x0a, 0x09, 0x00),
+               raw_pdu(0x0b, 0xff, 0xff, 0xee, 0xee),
+               raw_pdu(0x04, 0x0a, 0x00, 0x0a, 0x00),
+               raw_pdu(0x05, 0x01, 0x0a, 0x00, 0x08, 0x29),
+               raw_pdu(0x0a, 0x05, 0x00),
+               raw_pdu(0x0b, 0x01, 0x03),
+               raw_pdu(0x0a, 0x0a, 0x00),
+               raw_pdu(0x0b, 0x02, 0x03));
+
+       define_test("/TP/HGRF/RH/BV-09-I", test_hog,
+               raw_pdu(0x10, 0x01, 0x00, 0xff, 0xff, 0x00, 0x28),
+               raw_pdu(0x11, 0x06, 0x01, 0x00, 0x04, 0x00, 0x12,
+                       0x18, 0x05, 0x00, 0x08, 0x00, 0x12, 0x18),
+               raw_pdu(0x10, 0x09, 0x00, 0xff, 0xff, 0x00, 0x28),
+               raw_pdu(0x01, 0x10, 0x09, 0x00, 0x0a),
+               raw_pdu(0x08, 0x01, 0x00, 0x04, 0x00, 0x03, 0x28),
+               raw_pdu(0x09, 0x07, 0x03, 0x00, 0x02, 0x04, 0x00,
+                       0x4a, 0x2a),
+               raw_pdu(0x08, 0x01, 0x00, 0x04, 0x00, 0x02, 0x28),
+               raw_pdu(0x01, 0x08, 0x01, 0x00, 0x0a),
+               raw_pdu(0x08, 0x05, 0x00, 0x08, 0x00, 0x02, 0x28),
+               raw_pdu(0x01, 0x08, 0x05, 0x00, 0x0a),
+               raw_pdu(0x08, 0x05, 0x00, 0x08, 0x00, 0x03, 0x28),
+               raw_pdu(0x09, 0x07, 0x07, 0x00, 0x02, 0x08, 0x00,
+                       0x4a, 0x2a),
+               raw_pdu(0x0a, 0x04, 0x00),
+               raw_pdu(0x0b, 0x01, 0x11, 0x00, 0x01),
+               raw_pdu(0x0a, 0x08, 0x00),
+               raw_pdu(0x0b, 0x01, 0x11, 0x00, 0x01));
+
+       define_test("/TP/HGRF/RH/BV-06-I", test_hog,
+               raw_pdu(0x10, 0x01, 0x00, 0xff, 0xff, 0x00, 0x28),
+               raw_pdu(0x11, 0x06, 0x01, 0x00, 0x05, 0x00, 0x12,
+                       0x18, 0x06, 0x00, 0x0a, 0x00, 0x12, 0x18),
+               raw_pdu(0x10, 0x0b, 0x00, 0xff, 0xff, 0x00, 0x28),
+               raw_pdu(0x01, 0x10, 0x0b, 0x00, 0x0a),
+               raw_pdu(0x08, 0x01, 0x00, 0x05, 0x00, 0x03, 0x28),
+               raw_pdu(0x09, 0x07, 0x03, 0x00, 0x0a, 0x04, 0x00,
+                       0x4d, 0x2a),
+               raw_pdu(0x08, 0x01, 0x00, 0x05, 0x00, 0x02, 0x28),
+               raw_pdu(0x01, 0x08, 0x01, 0x00, 0x0a),
+               raw_pdu(0x08, 0x06, 0x00, 0x0a, 0x00, 0x02, 0x28),
+               raw_pdu(0x01, 0x08, 0x06, 0x00, 0x0a),
+               raw_pdu(0x08, 0x06, 0x00, 0x0a, 0x00, 0x03, 0x28),
+               raw_pdu(0x09, 0x07, 0x08, 0x00, 0x0a, 0x09, 0x00,
+                       0x4d, 0x2a),
+               raw_pdu(0x08, 0x04, 0x00, 0x05, 0x00, 0x03, 0x28),
+               raw_pdu(0x01, 0x08, 0x05, 0x00, 0x0a),
+               raw_pdu(0x08, 0x09, 0x00, 0x0a, 0x00, 0x03, 0x28),
+               raw_pdu(0x01, 0x08, 0x09, 0x00, 0x0a),
+               raw_pdu(0x0a, 0x04, 0x00),
+               raw_pdu(0x0b, 0xee, 0xee, 0xff, 0xff),
+               raw_pdu(0x04, 0x05, 0x00, 0x05, 0x00),
+               raw_pdu(0x05, 0x01, 0x05, 0x00, 0x08, 0x29),
+               raw_pdu(0x0a, 0x09, 0x00),
+               raw_pdu(0x0b, 0xff, 0xff, 0xee, 0xee),
+               raw_pdu(0x04, 0x0a, 0x00, 0x0a, 0x00),
+               raw_pdu(0x05, 0x01, 0x0a, 0x00, 0x08, 0x29),
+               raw_pdu(0x0a, 0x05, 0x00),
+               raw_pdu(0x0b, 0x01, 0x02),
+               raw_pdu(0x0a, 0x0a, 0x00),
+               raw_pdu(0x0b, 0x02, 0x02));
+
+       define_test("/TP/HGCF/RH/BV-01-I", test_hog,
+               raw_pdu(0x10, 0x01, 0x00, 0xff, 0xff, 0x00, 0x28),
+               raw_pdu(0x11, 0x06, 0x01, 0x00, 0x06, 0x00, 0x12,
+                       0x18, 0x07, 0x00, 0x0c, 0x00, 0x12, 0x18),
+               raw_pdu(0x10, 0x0d, 0x00, 0xff, 0xff, 0x00, 0x28),
+               raw_pdu(0x01, 0x10, 0x0d, 0x00, 0x0a),
+               raw_pdu(0x08, 0x01, 0x00, 0x06, 0x00, 0x03, 0x28),
+               raw_pdu(0x09, 0x07, 0x03, 0x00, 0x1a, 0x04, 0x00,
+                       0x4d, 0x2a),
+               raw_pdu(0x08, 0x01, 0x00, 0x06, 0x00, 0x02, 0x28),
+               raw_pdu(0x01, 0x08, 0x01, 0x00, 0x0a),
+               raw_pdu(0x08, 0x07, 0x00, 0x0c, 0x00, 0x02, 0x28),
+               raw_pdu(0x01, 0x08, 0x07, 0x00, 0x0a),
+               raw_pdu(0x08, 0x07, 0x00, 0x0c, 0x00, 0x03, 0x28),
+               raw_pdu(0x09, 0x07, 0x09, 0x00, 0x1a, 0x0a, 0x00,
+                       0x4d, 0x2a),
+               raw_pdu(0x08, 0x04, 0x00, 0x06, 0x00, 0x03, 0x28),
+               raw_pdu(0x01, 0x08, 0x04, 0x00, 0x0a),
+               raw_pdu(0x08, 0x0a, 0x00, 0x0c, 0x00, 0x03, 0x28),
+               raw_pdu(0x01, 0x08, 0x0a, 0x00, 0x0a),
+               raw_pdu(0x0a, 0x04, 0x00),
+               raw_pdu(0x0b, 0xed, 0x00),
+               raw_pdu(0x04, 0x05, 0x00, 0x06, 0x00),
+               raw_pdu(0x05, 0x01, 0x05, 0x00, 0x02, 0x29,
+                       0x06, 0x00, 0x08, 0x29),
+               raw_pdu(0x0a, 0x0a, 0x00),
+               raw_pdu(0x0b, 0xed, 0x00),
+               raw_pdu(0x04, 0x0b, 0x00, 0x0c, 0x00),
+               raw_pdu(0x05, 0x01, 0x0b, 0x00, 0x02, 0x29,
+                       0x0c, 0x00, 0x08, 0x29),
+               raw_pdu(0x0a, 0x06, 0x00),
+               raw_pdu(0x0b, 0x01, 0x01),
+               raw_pdu(0x0a, 0x0c, 0x00),
+               raw_pdu(0x0b, 0x02, 0x01),
+               raw_pdu(0x0a, 0x05, 0x00),
+               raw_pdu(0x0b, 0x00, 0x00),
+               raw_pdu(0x0a, 0x0b, 0x00),
+               raw_pdu(0x0b, 0x00, 0x00),
+               raw_pdu(0x12, 0x05, 0x00, 0x01, 0x00),
+               raw_pdu(0x13),
+               raw_pdu(0x12, 0x0b, 0x00, 0x01, 0x00),
+               raw_pdu(0x13));
+
+       define_test("/TP/HGRF/RH/BV-02-I", test_hog,
+               raw_pdu(0x10, 0x01, 0x00, 0xff, 0xff, 0x00, 0x28),
+               raw_pdu(0x11, 0x06, 0x01, 0x00, 0x05, 0x00, 0x12,
+                       0x18, 0x06, 0x00, 0x0a, 0x00, 0x12, 0x18),
+               raw_pdu(0x10, 0x0b, 0x00, 0xff, 0xff, 0x00, 0x28),
+               raw_pdu(0x01, 0x10, 0x0b, 0x00, 0x0a),
+               raw_pdu(0x08, 0x01, 0x00, 0x05, 0x00, 0x03, 0x28),
+               raw_pdu(0x09, 0x07, 0x03, 0x00, 0x02, 0x04, 0x00,
+                       0x4b, 0x2a),
+               raw_pdu(0x08, 0x01, 0x00, 0x05, 0x00, 0x02, 0x28),
+               raw_pdu(0x01, 0x08, 0x01, 0x00, 0x0a),
+               raw_pdu(0x08, 0x06, 0x00, 0x0a, 0x00, 0x02, 0x28),
+               raw_pdu(0x01, 0x08, 0x06, 0x00, 0x0a),
+               raw_pdu(0x08, 0x06, 0x00, 0x0a, 0x00, 0x03, 0x28),
+               raw_pdu(0x09, 0x07, 0x08, 0x00, 0x02, 0x09, 0x00,
+                       0x4b, 0x2a),
+               raw_pdu(0x08, 0x04, 0x00, 0x05, 0x00, 0x03, 0x28),
+               raw_pdu(0x01, 0x08, 0x04, 0x00, 0x0a),
+               raw_pdu(0x08, 0x09, 0x00, 0x0a, 0x00, 0x03, 0x28),
+               raw_pdu(0x01, 0x08, 0x09, 0x00, 0x0a),
+               raw_pdu(0x0a, 0x04, 0x00),
+               raw_pdu(0x0b, 0x01, 0x02, 0x03),
+               raw_pdu(0x04, 0x05, 0x00, 0x05, 0x00),
+               raw_pdu(0x05, 0x01, 0x05, 0x00, 0x07, 0x29),
+               raw_pdu(0x0a, 0x09, 0x00),
+               raw_pdu(0x0b, 0x01, 0x02, 0x03),
+               raw_pdu(0x04, 0x0a, 0x00, 0x0a, 0x00),
+               raw_pdu(0x05, 0x01, 0x0a, 0x00, 0x07, 0x29),
+               raw_pdu(0x0a, 0x05, 0x00),
+               raw_pdu(0x0b, 0x19, 0x2a),
+               raw_pdu(0x0a, 0x0a, 0x00),
+               raw_pdu(0x0b, 0x19, 0x2a));
+
+       return tester_run();
+}
index a89dbfc..b4ef4d1 100644 (file)
@@ -77,8 +77,7 @@ struct test_data {
                };                                                      \
                static struct test_data data;                           \
                data.mtu = _mtu;                                        \
-               data.pdu_list = g_malloc(sizeof(pdus));                 \
-               memcpy(data.pdu_list, pdus, sizeof(pdus));              \
+               data.pdu_list = g_memdup(pdus, sizeof(pdus));           \
                g_test_add_data_func(name, &data, test_sdp);            \
        } while (0)
 
index 85e1356..b48e0fa 100644 (file)
@@ -73,8 +73,7 @@ struct context {
                };                                                      \
                static struct test_data data;                           \
                data.test_name = g_strdup(name);                        \
-               data.pdu_list = g_malloc(sizeof(pdus));                 \
-               memcpy(data.pdu_list, pdus, sizeof(pdus));              \
+               data.pdu_list = g_memdup(pdus, sizeof(pdus));           \
                g_test_add_data_func(name, &data, function);            \
        } while (0)