Linux bluetooth development
 help / color / mirror / Atom feed
* [PATCH 01/13] android/handsfree: Add initial files
From: Szymon Janc @ 2014-02-02 21:09 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Szymon Janc
In-Reply-To: <1391375364-27106-1-git-send-email-szymon.janc@tieto.com>

This adds initial HAL and daemon code for Handsfree profile.
---
 android/Android.mk      |  2 ++
 android/Makefile.am     |  2 ++
 android/hal-bluetooth.c |  3 ++
 android/hal-handsfree.c | 96 +++++++++++++++++++++++++++++++++++++++++++++++++
 android/hal.h           |  2 ++
 android/handsfree.c     | 41 +++++++++++++++++++++
 android/handsfree.h     | 25 +++++++++++++
 android/main.c          | 14 ++++++++
 8 files changed, 185 insertions(+)
 create mode 100644 android/hal-handsfree.c
 create mode 100644 android/handsfree.c
 create mode 100644 android/handsfree.h

diff --git a/android/Android.mk b/android/Android.mk
index 03f2d8b..c16f29a 100644
--- a/android/Android.mk
+++ b/android/Android.mk
@@ -32,6 +32,7 @@ LOCAL_SRC_FILES := \
 	bluez/android/avctp.c \
 	bluez/android/avrcp.c \
 	bluez/android/pan.c \
+	bluez/android/handsfree.c \
 	bluez/src/log.c \
 	bluez/src/shared/mgmt.c \
 	bluez/src/shared/util.c \
@@ -108,6 +109,7 @@ LOCAL_SRC_FILES := \
 	bluez/android/hal-pan.c \
 	bluez/android/hal-a2dp.c \
 	bluez/android/hal-avrcp.c \
+	bluez/android/hal-handsfree.c \
 	bluez/android/hal-utils.c \
 
 LOCAL_C_INCLUDES += \
diff --git a/android/Makefile.am b/android/Makefile.am
index e065c0c..23e30c9 100644
--- a/android/Makefile.am
+++ b/android/Makefile.am
@@ -37,6 +37,7 @@ android_bluetoothd_SOURCES = android/main.c \
 				android/avrcp.h android/avrcp.c \
 				android/socket.h android/socket.c \
 				android/pan.h android/pan.c \
+				android/handsfree.h android/handsfree.c \
 				btio/btio.h btio/btio.c \
 				src/sdp-client.h src/sdp-client.c \
 				profiles/network/bnep.h profiles/network/bnep.c
@@ -51,6 +52,7 @@ android_bluetooth_default_la_SOURCES = android/hal.h android/hal-bluetooth.c \
 					android/hal-pan.c \
 					android/hal-a2dp.c \
 					android/hal-avrcp.c \
+					android/hal-handsfree.c \
 					android/hardware/bluetooth.h \
 					android/hardware/bt_av.h \
 					android/hardware/bt_gatt.h \
diff --git a/android/hal-bluetooth.c b/android/hal-bluetooth.c
index 0dac158..67c91e4 100644
--- a/android/hal-bluetooth.c
+++ b/android/hal-bluetooth.c
@@ -765,6 +765,9 @@ static const void *get_profile_interface(const char *profile_id)
 	if (!strcmp(profile_id, BT_PROFILE_AV_RC_ID))
 		return bt_get_avrcp_interface();
 
+	if (!strcmp(profile_id, BT_PROFILE_HANDSFREE_ID))
+		return bt_get_handsfree_interface();
+
 	return NULL;
 }
 
diff --git a/android/hal-handsfree.c b/android/hal-handsfree.c
new file mode 100644
index 0000000..181e05f
--- /dev/null
+++ b/android/hal-handsfree.c
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2014 Intel Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <string.h>
+
+#include "hal-log.h"
+#include "hal.h"
+#include "hal-msg.h"
+#include "hal-ipc.h"
+
+static const bthf_callbacks_t *cbs = NULL;
+
+static bool interface_ready(void)
+{
+	return cbs != NULL;
+}
+
+/* handlers will be called from notification thread context,
+ * index in table equals to 'opcode - HAL_MINIMUM_EVENT' */
+static const struct hal_ipc_handler ev_handlers[] = {
+
+};
+
+static bt_status_t init(bthf_callbacks_t *callbacks)
+{
+	struct hal_cmd_register_module cmd;
+	int ret;
+
+	DBG("");
+
+	if (interface_ready())
+		return BT_STATUS_DONE;
+
+	cbs = callbacks;
+
+	hal_ipc_register(HAL_SERVICE_ID_HANDSFREE, ev_handlers,
+				sizeof(ev_handlers)/sizeof(ev_handlers[0]));
+
+	cmd.service_id = HAL_SERVICE_ID_HANDSFREE;
+
+	ret = hal_ipc_cmd(HAL_SERVICE_ID_CORE, HAL_OP_REGISTER_MODULE,
+					sizeof(cmd), &cmd, 0, NULL, NULL);
+
+	if (ret != BT_STATUS_SUCCESS) {
+		cbs = NULL;
+		hal_ipc_unregister(HAL_SERVICE_ID_HANDSFREE);
+	}
+
+	return ret;
+}
+
+static void cleanup(void)
+{
+	struct hal_cmd_unregister_module cmd;
+
+	DBG("");
+
+	if (!interface_ready())
+		return;
+
+	cbs = NULL;
+
+	cmd.service_id = HAL_SERVICE_ID_HANDSFREE;
+
+	hal_ipc_cmd(HAL_SERVICE_ID_CORE, HAL_OP_UNREGISTER_MODULE,
+					sizeof(cmd), &cmd, 0, NULL, NULL);
+
+	hal_ipc_unregister(HAL_SERVICE_ID_HANDSFREE);
+}
+
+static bthf_interface_t iface = {
+	.size = sizeof(iface),
+	.init = init,
+	.cleanup = cleanup
+};
+
+bthf_interface_t *bt_get_handsfree_interface(void)
+{
+	return &iface;
+}
diff --git a/android/hal.h b/android/hal.h
index 1ff4fbd..5005b49 100644
--- a/android/hal.h
+++ b/android/hal.h
@@ -21,12 +21,14 @@
 #include <hardware/bt_pan.h>
 #include <hardware/bt_av.h>
 #include <hardware/bt_rc.h>
+#include <hardware/bt_hf.h>
 
 btsock_interface_t *bt_get_sock_interface(void);
 bthh_interface_t *bt_get_hidhost_interface(void);
 btpan_interface_t *bt_get_pan_interface(void);
 btav_interface_t *bt_get_a2dp_interface(void);
 btrc_interface_t *bt_get_avrcp_interface(void);
+bthf_interface_t *bt_get_handsfree_interface(void);
 
 void bt_thread_associate(void);
 void bt_thread_disassociate(void);
diff --git a/android/handsfree.c b/android/handsfree.c
new file mode 100644
index 0000000..fb48ff1
--- /dev/null
+++ b/android/handsfree.c
@@ -0,0 +1,41 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2014  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 <stdbool.h>
+
+#include "lib/bluetooth.h"
+#include "handsfree.h"
+
+bool bt_handsfree_register(const bdaddr_t *addr)
+{
+	return false;
+}
+
+void bt_handsfree_unregister(void)
+{
+
+}
diff --git a/android/handsfree.h b/android/handsfree.h
new file mode 100644
index 0000000..799fcb6
--- /dev/null
+++ b/android/handsfree.h
@@ -0,0 +1,25 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2014  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
+ *
+ */
+
+bool bt_handsfree_register(const bdaddr_t *addr);
+void bt_handsfree_unregister(void);
diff --git a/android/main.c b/android/main.c
index 417dbc3..d9d0572 100644
--- a/android/main.c
+++ b/android/main.c
@@ -56,6 +56,7 @@
 #include "a2dp.h"
 #include "pan.h"
 #include "avrcp.h"
+#include "handsfree.h"
 
 #define STARTUP_GRACE_SECONDS 5
 #define SHUTDOWN_GRACE_SECONDS 10
@@ -115,6 +116,13 @@ static void service_register(const void *buf, uint16_t len)
 		}
 
 		break;
+	case HAL_SERVICE_ID_HANDSFREE:
+		if (!bt_handsfree_register(&adapter_bdaddr)) {
+			status = HAL_STATUS_FAILED;
+			goto failed;
+		}
+
+		break;
 	default:
 		DBG("service %u not supported", m->service_id);
 		status = HAL_STATUS_FAILED;
@@ -160,6 +168,9 @@ static void service_unregister(const void *buf, uint16_t len)
 	case HAL_SERVICE_ID_AVRCP:
 		bt_avrcp_unregister();
 		break;
+	case HAL_SERVICE_ID_HANDSFREE:
+		bt_handsfree_unregister();
+		break;
 	default:
 		/* This would indicate bug in HAL, as unregister should not be
 		 * called in init failed */
@@ -338,6 +349,9 @@ static void cleanup_services(void)
 		case HAL_SERVICE_ID_PAN:
 			bt_pan_unregister();
 			break;
+		case HAL_SERVICE_ID_HANDSFREE:
+			bt_handsfree_unregister();
+			break;
 		}
 
 		services[i] = false;
-- 
1.8.5.3


^ permalink raw reply related

* [PATCH 02/13] android/handsfree: Add commands and events definition to IPC header
From: Szymon Janc @ 2014-02-02 21:09 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Szymon Janc
In-Reply-To: <1391375364-27106-1-git-send-email-szymon.janc@tieto.com>

---
 android/hal-msg.h | 208 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 208 insertions(+)

diff --git a/android/hal-msg.h b/android/hal-msg.h
index d46b428..56e1116 100644
--- a/android/hal-msg.h
+++ b/android/hal-msg.h
@@ -389,6 +389,130 @@ struct hal_cmd_pan_disconnect {
 	uint8_t bdaddr[6];
 } __attribute__((packed));
 
+/* Handsfree HAL API */
+
+#define HAL_OP_HANDSFREE_CONNECT		0x01
+struct hal_cmd_handsfree_connect {
+	uint8_t bdaddr[6];
+} __attribute__((packed));
+
+#define HAL_OP_HANDSFREE_DISCONNECT		0x02
+struct hal_cmd_handsfree_disconnect {
+	uint8_t bdaddr[6];
+} __attribute__((packed));
+
+#define HAL_OP_HANDSFREE_CONNECT_AUDIO		0x03
+struct hal_cmd_handsfree_connect_audio {
+	uint8_t bdaddr[6];
+} __attribute__((packed));
+
+#define HAL_OP_HANDSFREE_DISCONNECT_AUDIO	0x04
+struct hal_cmd_handsfree_disconnect_audio {
+	uint8_t bdaddr[6];
+} __attribute__((packed));
+
+#define HAL_OP_HANDSFREE_START_VR		0x05
+
+#define HAL_OP_HANDSFREE_STOP_VR		0x06
+
+#define HAL_HANDSFREE_VOLUME_TYPE_SPEAKER	0x00
+#define HAL_HANDSFREE_VOLUME_TYPE_MIC		0x01
+
+#define HAL_OP_HANDSFREE_VOLUME_CONTROL		0x07
+struct hal_cmd_handsfree_volume_control {
+	uint8_t type;
+	uint32_t volume;
+} __attribute__((packed));
+
+#define HAL_HANDSFREE_NETWORK_STATE_NOT_AVAILABLE	0x00
+#define HAL_HANDSFREE_NETWORK_STATE_AVAILABLE		0x01
+
+#define HAL_HANDSFREE_SERVICE_TYPE_HOME		0x00
+#define HAL_HANDSFREE_SERVICE_TYPE_ROAMING	0x01
+
+#define HAL_OP_HANDSFREE_DEVICE_STATUS_NOTIF	0x08
+struct hal_cmd_handsfree_device_status_notif {
+	uint8_t state;
+	uint8_t type;
+	uint32_t signal;
+	uint32_t battery;
+} __attribute__((packed));
+
+#define HAL_OP_HANDSFREE_COPS_RESPONSE		0x09
+struct hal_cmd_handsfree_cops_response {
+	uint32_t len;
+	uint8_t buf[0];
+} __attribute__((packed));
+
+#define HAL_HANDSFREE_CALL_STATE_ACTIVE		0x00
+#define HAL_HANDSFREE_CALL_STATE_HELD		0x01
+#define HAL_HANDSFREE_CALL_STATE_DIALING	0x02
+#define HAL_HANDSFREE_CALL_STATE_ALERTING	0x03
+#define HAL_HANDSFREE_CALL_STATE_INCOMING	0x04
+#define HAL_HANDSFREE_CALL_STATE_WAITING	0x05
+#define HAL_HANDSFREE_CALL_STATE_IDLE		0x06
+
+#define HAL_OP_HANDSFREE_CIND_RESPONSE		0x0A
+struct hal_cmd_handsfree_cind_response {
+	uint32_t svc;
+	uint32_t num_active;
+	uint32_t num_held;
+	uint8_t state;
+	uint32_t signal;
+	uint32_t roam;
+	uint32_t batt_chg;
+} __attribute__((packed));
+
+#define HAL_OP_HANDSFREE_FORMATTED_AT_RESPONSE	0x0B
+struct hal_cmd_handsfree_formatted_at_response {
+	uint32_t len;
+	uint8_t buf[0];
+} __attribute__((packed));
+
+#define HAL_HANDSFREE_AT_RESPONSE_ERROR		0x00
+#define HAL_HANDSFREE_AT_RESPONSE_OK		0x01
+
+#define HAL_OP_HANDSFREE_AT_RESPONSE		0x0C
+struct hal_cmd_handsfree_at_response {
+	uint8_t response;
+	uint32_t error;
+} __attribute__((packed));
+
+#define HAL_HANDSFREE_CALL_DIRECTION_OUTGOING	0x00
+#define HAL_HANDSFREE_CALL_DIRECTION_INCOMING	0x01
+
+#define HAL_HANDSFREE_CALL_TYPE_VOICE		0x00
+#define HAL_HANDSFREE_CALL_TYPE_DATA		0x01
+#define HAL_HANDSFREE_CALL_TYPE_FAX		0x02
+
+#define HAL_HANDSFREE_CALL_MPTY_TYPE_SINGLE	0x00
+#define HAL_HANDSFREE_CALL_MPTY_TYPE_MULTI	0x01
+
+#define HAL_HANDSFREE_CALL_ADDRTYPE_UNKNOWN	0x81
+#define HAL_HANDSFREE_CALL_ADDRTYPE_INTERNATIONAL	0x91
+
+#define HAL_OP_HANDSFREE_CLCC_RESPONSE		0x0D
+struct hal_cmd_handsfree_clcc_response {
+	uint32_t index;
+	uint8_t dir;
+	uint8_t state;
+	uint8_t mode;
+	uint8_t mpty;
+	uint8_t type;
+	uint32_t number_len;
+	uint8_t number[0];
+} __attribute__((packed));
+
+#define HAL_OP_HANDSFREE_PHONE_STATE_CHANGE	0x0E
+struct hal_cmd_handsfree_phone_state_change {
+	uint32_t num_active;
+	uint32_t num_held;
+	uint8_t state;
+	uint8_t type;
+	uint32_t number_len;
+	uint8_t number[0];
+} __attribute__((packed));
+
 /* Notifications and confirmations */
 
 #define HAL_POWER_OFF			0x00
@@ -572,3 +696,87 @@ struct hal_ev_a2dp_audio_state {
 	uint8_t state;
 	uint8_t bdaddr[6];
 } __attribute__((packed));
+
+#define HAL_EV_HANDSFREE_CONNECTION_STATE_DISCONNECTED	0x00
+#define HAL_EV_HANDSFREE_CONNECTION_STATE_CONNECTING	0x01
+#define HAL_EV_HANDSFREE_CONNECTION_STATE_CONNECTED	0x02
+#define HAL_EV_HANDSFREE_CONNECTION_STATE_SLC_CONNECTED	0x03
+#define HAL_EV_HANDSFREE_CONNECTION_STATE_DISCONNECTING	0x04
+
+#define HAL_EV_HANDSFREE_CONN_STATE		0x81
+struct hal_ev_handsfree_conn_state {
+	uint8_t state;
+	uint8_t bdaddr[6];
+} __attribute__((packed));
+
+#define HAL_EV_HANDSFREE_AUDIO_STATE_DISCONNECTED	0x00
+#define HAL_EV_HANDSFREE_AUDIO_STATE_CONNECTING		0x01
+#define HAL_EV_HANDSFREE_AUDIO_STATE_CONNECTED		0x02
+#define HAL_EV_HANDSFREE_AUDIO_STATE_DISCONNECTING	0x03
+
+#define HAL_EV_HANDSFREE_AUDIO_STATE		0x82
+struct hal_ev_handsfree_audio_state {
+	uint8_t state;
+	uint8_t bdaddr[6];
+} __attribute__((packed));
+
+#define HAL_EV_HANDSFREE_VR		0x83
+struct hal_ev_handsfree_vr_state {
+	uint8_t state;
+} __attribute__((packed));
+
+#define HAL_EV_HANDSFREE_ANSWER		0x84
+
+#define HAL_EV_HANDSFREE_HANGUP		0x85
+
+#define HAL_EV_HANDSFREE_VOLUME		0x86
+struct hal_ev_handsfree_volume {
+	uint8_t type;
+	uint32_t volume;
+} __attribute__((packed));
+
+#define HAL_EV_HANDSFREE_DIAL		0x87
+struct hal_ev_handsfree_dial {
+	uint32_t number_len;
+	uint8_t number[0];
+} __attribute__((packed));
+
+#define HAL_EV_HANDSFREE_DTMF		0x88
+struct hal_ev_handsfree_dtmf {
+	uint8_t tone;
+} __attribute__((packed));
+
+#define HAL_HANDSFREE_NREC_STOP		0x00
+#define HAL_HANDSFREE_NREC_STart	0x01
+
+#define HAL_EV_HANDSFREE_NREC		0x89
+struct hal_ev_handsfree_nrec {
+	uint8_t nrec;
+} __attribute__((packed));
+
+#define HAL_HANDSFREE_CHLD_TYPE_RELEASEHELD			0x00
+#define HAL_HANDSFREE_CHLD_TYPE_RELEASEACTIVE_ACCEPTHELD	0x01
+#define HAL_HANDSFREE_CHLD_TYPE_HOLDACTIVE_ACCEPTHELD		0x02
+#define HAL_HANDSFREE_CHLD_TYPE_ADDHELDTOCONF			0x03
+
+#define HAL_EV_HANDSFREE_CHLD		0x8A
+struct hal_ev_handsfree_chld {
+	uint8_t chld;
+} __attribute__((packed));
+
+
+#define HAL_EV_HANDSFREE_CNUM		0x8B
+
+#define HAL_EV_HANDSFREE_CIND		0x8C
+
+#define HAL_EV_HANDSFREE_COPS		0x8D
+
+#define HAL_EV_HANDSFREE_CLCC		0x8E
+
+#define HAL_EV_HANDSFREE_UNKNOWN_AT	0x8F
+struct hal_ev_handsfree_unknown_at {
+	uint32_t len;
+	uint8_t buf[0];
+} __attribute__((packed));
+
+#define HAL_EV_HANDSFREE_HSP_KEY_PRESS	0x90
-- 
1.8.5.3


^ permalink raw reply related

* [PATCH 03/13] android/handsfree: Add stubs for commands handlers
From: Szymon Janc @ 2014-02-02 21:09 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Szymon Janc
In-Reply-To: <1391375364-27106-1-git-send-email-szymon.janc@tieto.com>

Add empty handlers for all IPC commands.
---
 android/handsfree.c | 170 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 169 insertions(+), 1 deletion(-)

diff --git a/android/handsfree.c b/android/handsfree.c
index fb48ff1..3c0d52b 100644
--- a/android/handsfree.c
+++ b/android/handsfree.c
@@ -26,16 +26,184 @@
 #endif
 
 #include <stdbool.h>
+#include <glib.h>
 
 #include "lib/bluetooth.h"
 #include "handsfree.h"
+#include "src/log.h"
+#include "hal-msg.h"
+#include "ipc.h"
+
+static bdaddr_t adapter_addr;
+
+static void handle_connect(const void *buf, uint16_t len)
+{
+	DBG("");
+
+	ipc_send_rsp(HAL_SERVICE_ID_HANDSFREE, HAL_OP_HANDSFREE_CONNECT,
+							HAL_STATUS_FAILED);
+}
+
+static void handle_disconnect(const void *buf, uint16_t len)
+{
+	DBG("");
+
+	ipc_send_rsp(HAL_SERVICE_ID_HANDSFREE, HAL_OP_HANDSFREE_DISCONNECT,
+							HAL_STATUS_FAILED);
+}
+
+static void handle_connect_audio(const void *buf, uint16_t len)
+{
+	DBG("");
+
+	ipc_send_rsp(HAL_SERVICE_ID_HANDSFREE, HAL_OP_HANDSFREE_CONNECT_AUDIO,
+							HAL_STATUS_FAILED);
+}
+
+static void handle_disconnect_audio(const void *buf, uint16_t len)
+{
+	DBG("");
+
+	ipc_send_rsp(HAL_SERVICE_ID_HANDSFREE,
+			HAL_OP_HANDSFREE_DISCONNECT_AUDIO, HAL_STATUS_FAILED);
+}
+
+static void handle_start_vr(const void *buf, uint16_t len)
+{
+	DBG("");
+
+	ipc_send_rsp(HAL_SERVICE_ID_HANDSFREE, HAL_OP_HANDSFREE_START_VR,
+							HAL_STATUS_FAILED);
+}
+
+static void handle_stop_vr(const void *buf, uint16_t len)
+{
+	DBG("");
+
+	ipc_send_rsp(HAL_SERVICE_ID_HANDSFREE, HAL_OP_HANDSFREE_STOP_VR,
+							HAL_STATUS_FAILED);
+}
+
+static void handle_volume_control(const void *buf, uint16_t len)
+{
+	DBG("");
+
+	ipc_send_rsp(HAL_SERVICE_ID_HANDSFREE, HAL_OP_HANDSFREE_VOLUME_CONTROL,
+							HAL_STATUS_FAILED);
+}
+
+static void handle_device_status_notif(const void *buf, uint16_t len)
+{
+	DBG("");
+
+	ipc_send_rsp(HAL_SERVICE_ID_HANDSFREE,
+					HAL_OP_HANDSFREE_DEVICE_STATUS_NOTIF,
+					HAL_STATUS_FAILED);
+}
+
+static void handle_cops(const void *buf, uint16_t len)
+{
+	DBG("");
+
+	ipc_send_rsp(HAL_SERVICE_ID_HANDSFREE, HAL_OP_HANDSFREE_COPS_RESPONSE,
+							HAL_STATUS_FAILED);
+}
+
+static void handle_cind(const void *buf, uint16_t len)
+{
+	DBG("");
+
+	ipc_send_rsp(HAL_SERVICE_ID_HANDSFREE, HAL_OP_HANDSFREE_CIND_RESPONSE,
+							HAL_STATUS_FAILED);
+}
+
+static void handle_formatted_at_resp(const void *buf, uint16_t len)
+{
+	DBG("");
+
+	ipc_send_rsp(HAL_SERVICE_ID_HANDSFREE,
+					HAL_OP_HANDSFREE_FORMATTED_AT_RESPONSE,
+					HAL_STATUS_FAILED);
+}
+
+static void handle_at_resp(const void *buf, uint16_t len)
+{
+	DBG("");
+
+	ipc_send_rsp(HAL_SERVICE_ID_HANDSFREE, HAL_OP_HANDSFREE_AT_RESPONSE,
+							HAL_STATUS_FAILED);
+}
+
+static void handle_clcc_resp(const void *buf, uint16_t len)
+{
+	DBG("");
+
+	ipc_send_rsp(HAL_SERVICE_ID_HANDSFREE, HAL_OP_HANDSFREE_CLCC_RESPONSE,
+							HAL_STATUS_FAILED);
+}
+
+static void handle_phone_state_change(const void *buf, uint16_t len)
+{
+	DBG("");
+
+	ipc_send_rsp(HAL_SERVICE_ID_HANDSFREE,
+					HAL_OP_HANDSFREE_PHONE_STATE_CHANGE,
+					HAL_STATUS_FAILED);
+}
+
+static const struct ipc_handler cmd_handlers[] = {
+	/* HAL_OP_HANDSFREE_CONNECT */
+	{ handle_connect, false, sizeof(struct hal_cmd_handsfree_connect)},
+	/* HAL_OP_HANDSFREE_DISCONNECT */
+	{handle_disconnect, false, sizeof(struct hal_cmd_handsfree_disconnect)},
+	/*HAL_OP_HANDSFREE_CONNECT_AUDIO*/
+	{handle_connect_audio, false,
+			sizeof(struct hal_cmd_handsfree_connect_audio)},
+	/*HAL_OP_HANDSFREE_DISCONNECT_AUDIO*/
+	{handle_disconnect_audio, false,
+			sizeof(struct hal_cmd_handsfree_disconnect_audio)},
+	/* define HAL_OP_HANDSFREE_START_VR */
+	{handle_start_vr, false, 0 },
+	/* define HAL_OP_HANDSFREE_STOP_VR */
+	{handle_stop_vr, false, 0 },
+	/* HAL_OP_HANDSFREE_VOLUME_CONTROL */
+	{handle_volume_control, false,
+			sizeof(struct hal_cmd_handsfree_volume_control)},
+	/* HAL_OP_HANDSFREE_DEVICE_STATUS_NOTIF */
+	{handle_device_status_notif, false,
+			sizeof(struct hal_cmd_handsfree_device_status_notif)},
+	/* HAL_OP_HANDSFREE_COPS_RESPONSE */
+	{handle_cops, true, sizeof(struct hal_cmd_handsfree_cops_response)},
+	/* HAL_OP_HANDSFREE_CIND_RESPONSE */
+	{ handle_cind, false, sizeof(struct hal_cmd_handsfree_cind_response)},
+	/* HAL_OP_HANDSFREE_FORMATTED_AT_RESPONSE */
+	{handle_formatted_at_resp, true,
+			sizeof(struct hal_cmd_handsfree_formatted_at_response)},
+	/* HAL_OP_HANDSFREE_AT_RESPONSE */
+	{handle_at_resp, false, sizeof(struct hal_cmd_handsfree_at_response)},
+	/* HAL_OP_HANDSFREE_CLCC_RESPONSE */
+	{handle_clcc_resp, true,
+			sizeof(struct hal_cmd_handsfree_clcc_response)},
+	/* HAL_OP_HANDSFREE_PHONE_STATE_CHANGE */
+	{handle_phone_state_change, true,
+			sizeof(struct hal_cmd_handsfree_phone_state_change)},
+};
 
 bool bt_handsfree_register(const bdaddr_t *addr)
 {
-	return false;
+	DBG("");
+
+	bacpy(&adapter_addr, addr);
+
+	ipc_register(HAL_SERVICE_ID_HANDSFREE, cmd_handlers,
+						G_N_ELEMENTS(cmd_handlers));
+
+	return true;
 }
 
 void bt_handsfree_unregister(void)
 {
+	DBG("");
 
+	ipc_unregister(HAL_SERVICE_ID_HANDSFREE);
 }
-- 
1.8.5.3


^ permalink raw reply related

* [PATCH 04/13] android/hal-handsfree: Implement notifications handling
From: Szymon Janc @ 2014-02-02 21:09 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Szymon Janc
In-Reply-To: <1391375364-27106-1-git-send-email-szymon.janc@tieto.com>

This implements all notifications handlers and call proper HAL
callbacks.
---
 android/hal-handsfree.c | 160 +++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 159 insertions(+), 1 deletion(-)

diff --git a/android/hal-handsfree.c b/android/hal-handsfree.c
index 181e05f..6e11367 100644
--- a/android/hal-handsfree.c
+++ b/android/hal-handsfree.c
@@ -18,6 +18,7 @@
 #include <stdbool.h>
 #include <stddef.h>
 #include <string.h>
+#include <stdlib.h>
 
 #include "hal-log.h"
 #include "hal.h"
@@ -31,10 +32,167 @@ static bool interface_ready(void)
 	return cbs != NULL;
 }
 
+static void handle_conn_state(void *buf, uint16_t len)
+{
+	struct hal_ev_handsfree_conn_state *ev = buf;
+
+	if (cbs->connection_state_cb)
+		cbs->connection_state_cb(ev->state,
+						(bt_bdaddr_t *) (ev->bdaddr));
+}
+
+static void handle_audio_state(void *buf, uint16_t len)
+{
+	struct hal_ev_handsfree_audio_state *ev = buf;
+
+	if (cbs->audio_state_cb)
+		cbs->audio_state_cb(ev->state, (bt_bdaddr_t *) (ev->bdaddr));
+}
+
+static void handle_vr_state(void *buf, uint16_t len)
+{
+	struct hal_ev_handsfree_vr_state *ev = buf;
+
+	if (cbs->vr_cmd_cb)
+		cbs->vr_cmd_cb(ev->state);
+}
+
+static void handle_answer(void *buf, uint16_t len)
+{
+	if (cbs->answer_call_cmd_cb)
+		cbs->answer_call_cmd_cb();
+}
+
+static void handle_hangup(void *buf, uint16_t len)
+{
+	if (cbs->hangup_call_cmd_cb)
+		cbs->hangup_call_cmd_cb();
+}
+
+static void handle_volume(void *buf, uint16_t len)
+{
+	struct hal_ev_handsfree_volume *ev = buf;
+
+	if (cbs->volume_cmd_cb)
+		cbs->volume_cmd_cb(ev->type, ev->volume);
+}
+
+static void handle_dial(void *buf, uint16_t len)
+{
+	struct hal_ev_handsfree_dial *ev = buf;
+
+	if (len != sizeof(*ev) + ev->number_len) {
+		error("invalid dial event, aborting");
+		exit(EXIT_FAILURE);
+	}
+
+	if (cbs->dial_call_cmd_cb)
+		cbs->dial_call_cmd_cb((char *) ev->number);
+}
+
+static void handle_dtmf(void *buf, uint16_t len)
+{
+	struct hal_ev_handsfree_dtmf *ev = buf;
+
+	if (cbs->dtmf_cmd_cb)
+		cbs->dtmf_cmd_cb(ev->tone);
+}
+
+static void handle_nrec(void *buf, uint16_t len)
+{
+	struct hal_ev_handsfree_nrec *ev = buf;
+
+	if (cbs->nrec_cmd_cb)
+		cbs->nrec_cmd_cb(ev->nrec);
+}
+
+static void handle_chld(void *buf, uint16_t len)
+{
+	struct hal_ev_handsfree_chld *ev = buf;
+
+	if (cbs->chld_cmd_cb)
+		cbs->chld_cmd_cb(ev->chld);
+}
+
+static void handle_cnum(void *buf, uint16_t len)
+{
+	if (cbs->cnum_cmd_cb)
+		cbs->cnum_cmd_cb();
+}
+
+static void handle_cind(void *buf, uint16_t len)
+{
+	if (cbs->cind_cmd_cb)
+		cbs->cind_cmd_cb();
+}
+
+static void handle_cops(void *buf, uint16_t len)
+{
+	if (cbs->cops_cmd_cb)
+		cbs->cops_cmd_cb();
+}
+
+static void handle_clcc(void *buf, uint16_t len)
+{
+	if (cbs->clcc_cmd_cb)
+		cbs->clcc_cmd_cb();
+}
+
+static void handle_unknown_at(void *buf, uint16_t len)
+{
+	struct hal_ev_handsfree_unknown_at *ev = buf;
+
+	if (len != sizeof(*ev) + ev->len) {
+		error("invalid dial event, aborting");
+		exit(EXIT_FAILURE);
+	}
+
+	if (cbs->unknown_at_cmd_cb)
+		cbs->unknown_at_cmd_cb((char *) ev->buf);
+}
+
+static void handle_hsp_key_press(void *buf, uint16_t len)
+{
+	if (cbs->key_pressed_cmd_cb)
+		cbs->key_pressed_cmd_cb();
+}
+
 /* handlers will be called from notification thread context,
  * index in table equals to 'opcode - HAL_MINIMUM_EVENT' */
 static const struct hal_ipc_handler ev_handlers[] = {
-
+	/* HAL_EV_HANDSFREE_CONN_STATE */
+	{handle_conn_state, false, sizeof(struct hal_ev_handsfree_conn_state)},
+	/* HAL_EV_HANDSFREE_AUDIO_STATE */
+	{handle_audio_state, false,
+				sizeof(struct hal_ev_handsfree_audio_state)},
+	/* HAL_EV_HANDSFREE_VR */
+	{handle_vr_state, false, sizeof(struct hal_ev_handsfree_vr_state)},
+	/*HAL_EV_HANDSFREE_ANSWER */
+	{handle_answer, false, 0},
+	/*HAL_EV_HANDSFREE_HANGUP */
+	{handle_hangup, false, 0},
+	/* HAL_EV_HANDSFREE_VOLUME */
+	{handle_volume, false, sizeof(struct hal_ev_handsfree_volume)},
+	/* HAL_EV_HANDSFREE_DIAL */
+	{handle_dial, true, sizeof(struct hal_ev_handsfree_dial)},
+	/* HAL_EV_HANDSFREE_DTMF */
+	{handle_dtmf, false, sizeof(struct hal_ev_handsfree_dtmf)},
+	/* HAL_EV_HANDSFREE_NREC */
+	{handle_nrec, false, sizeof(struct hal_ev_handsfree_nrec)},
+	/* HAL_EV_HANDSFREE_CHLD */
+	{handle_chld, false, sizeof(struct hal_ev_handsfree_chld)},
+	/* HAL_EV_HANDSFREE_CNUM */
+	{handle_cnum, false, 0},
+	/* HAL_EV_HANDSFREE_CIND */
+	{handle_cind, false, 0},
+	/* HAL_EV_HANDSFREE_COPS */
+	{handle_cops, false, 0},
+	/* HAL_EV_HANDSFREE_CLCC */
+	{handle_clcc, false, 0},
+	/* HAL_EV_HANDSFREE_UNKNOWN_AT */
+	{handle_unknown_at, true, sizeof(struct hal_ev_handsfree_unknown_at)},
+	/* HAL_EV_HANDSFREE_HSP_KEY_PRESS */
+	{handle_hsp_key_press, false, 0},
 };
 
 static bt_status_t init(bthf_callbacks_t *callbacks)
-- 
1.8.5.3


^ permalink raw reply related

* [PATCH 05/13] android/hal-handsfree: Implement sending commands
From: Szymon Janc @ 2014-02-02 21:09 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Szymon Janc
In-Reply-To: <1391375364-27106-1-git-send-email-szymon.janc@tieto.com>

This implements HAL interface methods and pass commands over IPC.
---
 android/hal-handsfree.c | 344 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 344 insertions(+)

diff --git a/android/hal-handsfree.c b/android/hal-handsfree.c
index 6e11367..601c14f 100644
--- a/android/hal-handsfree.c
+++ b/android/hal-handsfree.c
@@ -223,6 +223,336 @@ static bt_status_t init(bthf_callbacks_t *callbacks)
 	return ret;
 }
 
+static bt_status_t handsfree_connect(bt_bdaddr_t *bd_addr)
+{
+	struct hal_cmd_handsfree_connect cmd;
+
+	DBG("");
+
+	if (!interface_ready())
+		return BT_STATUS_NOT_READY;
+
+	if (!bd_addr)
+		return BT_STATUS_PARM_INVALID;
+
+	memcpy(cmd.bdaddr, bd_addr, sizeof(cmd.bdaddr));
+
+	return hal_ipc_cmd(HAL_SERVICE_ID_HANDSFREE, HAL_OP_HANDSFREE_CONNECT,
+					sizeof(cmd), &cmd, 0, NULL, NULL);
+}
+
+static bt_status_t disconnect(bt_bdaddr_t *bd_addr)
+{
+	struct hal_cmd_handsfree_disconnect cmd;
+
+	DBG("");
+
+	if (!interface_ready())
+		return BT_STATUS_NOT_READY;
+
+	if (!bd_addr)
+		return BT_STATUS_PARM_INVALID;
+
+	memcpy(cmd.bdaddr, bd_addr, sizeof(cmd.bdaddr));
+
+	return hal_ipc_cmd(HAL_SERVICE_ID_HANDSFREE,
+				HAL_OP_HANDSFREE_DISCONNECT, sizeof(cmd), &cmd,
+				0, NULL, NULL);
+}
+
+static bt_status_t connect_audio(bt_bdaddr_t *bd_addr)
+{
+	struct hal_cmd_handsfree_connect_audio cmd;
+
+	DBG("");
+
+	if (!interface_ready())
+		return BT_STATUS_NOT_READY;
+
+	if (!bd_addr)
+		return BT_STATUS_PARM_INVALID;
+
+	memcpy(cmd.bdaddr, bd_addr, sizeof(cmd.bdaddr));
+
+	return hal_ipc_cmd(HAL_SERVICE_ID_HANDSFREE,
+				HAL_OP_HANDSFREE_CONNECT_AUDIO, sizeof(cmd),
+				&cmd, 0, NULL, NULL);
+}
+
+static bt_status_t disconnect_audio(bt_bdaddr_t *bd_addr)
+{
+	struct hal_cmd_handsfree_disconnect_audio cmd;
+
+	DBG("");
+
+	if (!interface_ready())
+		return BT_STATUS_NOT_READY;
+
+	if (!bd_addr)
+		return BT_STATUS_PARM_INVALID;
+
+	memcpy(cmd.bdaddr, bd_addr, sizeof(cmd.bdaddr));
+
+	return hal_ipc_cmd(HAL_SERVICE_ID_HANDSFREE,
+				HAL_OP_HANDSFREE_DISCONNECT_AUDIO, sizeof(cmd),
+				&cmd, 0, NULL, NULL);
+}
+
+static bt_status_t start_voice_recognition(void)
+{
+	DBG("");
+
+	if (!interface_ready())
+		return BT_STATUS_NOT_READY;
+
+	return hal_ipc_cmd(HAL_SERVICE_ID_HANDSFREE, HAL_OP_HANDSFREE_START_VR,
+							0, NULL, 0, NULL, NULL);
+}
+
+static bt_status_t stop_voice_recognition(void)
+{
+	DBG("");
+
+	if (!interface_ready())
+		return BT_STATUS_NOT_READY;
+
+	return hal_ipc_cmd(HAL_SERVICE_ID_HANDSFREE, HAL_OP_HANDSFREE_STOP_VR,
+							0, NULL, 0, NULL, NULL);
+}
+
+static bt_status_t volume_control(bthf_volume_type_t type, int volume)
+{
+	struct hal_cmd_handsfree_volume_control cmd;
+
+	DBG("");
+
+	if (!interface_ready())
+		return BT_STATUS_NOT_READY;
+
+	cmd.type = type;
+	cmd.volume = volume;
+
+	return hal_ipc_cmd(HAL_SERVICE_ID_HANDSFREE,
+				HAL_OP_HANDSFREE_VOLUME_CONTROL, sizeof(cmd),
+				&cmd, 0, NULL, NULL);
+}
+
+static bt_status_t device_status_notification(bthf_network_state_t state,
+						bthf_service_type_t type,
+						int signal, int battery)
+{
+	struct hal_cmd_handsfree_device_status_notif cmd;
+
+	DBG("");
+
+	if (!interface_ready())
+		return BT_STATUS_NOT_READY;
+
+	cmd.state = state;
+	cmd.type = type;
+	cmd.signal = signal;
+	cmd.battery = battery;
+
+	return hal_ipc_cmd(HAL_SERVICE_ID_HANDSFREE,
+					HAL_OP_HANDSFREE_DEVICE_STATUS_NOTIF,
+					sizeof(cmd), &cmd, 0, NULL, NULL);
+}
+
+static bt_status_t cops_response(const char *cops)
+{
+	struct hal_cmd_handsfree_cops_response *cmd;
+	bt_status_t status;
+	int len;
+
+	DBG("");
+
+	if (!interface_ready())
+		return BT_STATUS_NOT_READY;
+
+	if (!cops)
+		return BT_STATUS_PARM_INVALID;
+
+	len = sizeof(*cmd) + strlen(cops);
+
+	cmd = malloc(len);
+	if (!cmd)
+		return BT_STATUS_NOMEM;
+
+	cmd->len = strlen(cops);
+	memcpy(cmd->buf, cops, cmd->len);
+
+	status = hal_ipc_cmd(HAL_SERVICE_ID_HANDSFREE,
+				HAL_OP_HANDSFREE_COPS_RESPONSE, len, cmd, 0,
+				NULL, NULL);
+
+	free(cmd);
+
+	return status;
+}
+
+static bt_status_t cind_response(int svc, int num_active, int num_held,
+					bthf_call_state_t state, int signal,
+					int roam, int batt_chg)
+{
+	struct hal_cmd_handsfree_cind_response cmd;
+
+	DBG("");
+
+	if (!interface_ready())
+		return BT_STATUS_NOT_READY;
+
+	cmd.svc = svc;
+	cmd.num_active = num_active;
+	cmd.num_held = num_held;
+	cmd.state = state;
+	cmd.signal = signal;
+	cmd.roam = roam;
+	cmd.batt_chg = batt_chg;
+
+	return hal_ipc_cmd(HAL_SERVICE_ID_HANDSFREE,
+					HAL_OP_HANDSFREE_CIND_RESPONSE,
+					sizeof(cmd), &cmd, 0, NULL, NULL);
+}
+
+static bt_status_t formatted_at_response(const char *rsp)
+{
+	struct hal_cmd_handsfree_formatted_at_response *cmd;
+	bt_status_t status;
+	int len;
+
+	DBG("");
+
+	if (!interface_ready())
+		return BT_STATUS_NOT_READY;
+
+	if (!rsp)
+		return BT_STATUS_PARM_INVALID;
+
+	len = sizeof(*cmd) + strlen(rsp);
+
+	cmd = malloc(len);
+	if (!cmd)
+		return BT_STATUS_NOMEM;
+
+	cmd->len = strlen(rsp);
+	memcpy(cmd->buf, rsp, cmd->len);
+
+	status = hal_ipc_cmd(HAL_SERVICE_ID_HANDSFREE,
+				HAL_OP_HANDSFREE_FORMATTED_AT_RESPONSE, len,
+				cmd, 0, NULL, NULL);
+
+	free(cmd);
+
+	return status;
+}
+
+static bt_status_t at_response(bthf_at_response_t response, int error)
+{
+	struct hal_cmd_handsfree_at_response cmd;
+
+	DBG("");
+
+	if (!interface_ready())
+		return BT_STATUS_NOT_READY;
+
+	cmd.response = response;
+	cmd.error = error;
+
+	return hal_ipc_cmd(HAL_SERVICE_ID_HANDSFREE,
+					HAL_OP_HANDSFREE_AT_RESPONSE,
+					sizeof(cmd), &cmd, 0, NULL, NULL);
+}
+
+static bt_status_t clcc_response(int index, bthf_call_direction_t dir,
+					bthf_call_state_t state,
+					bthf_call_mode_t mode,
+					bthf_call_mpty_type_t mpty,
+					const char *number,
+					bthf_call_addrtype_t type)
+{
+	struct hal_cmd_handsfree_clcc_response *cmd;
+	bt_status_t status;
+	int len;
+
+	DBG("");
+
+	if (!interface_ready())
+		return BT_STATUS_NOT_READY;
+
+	len = sizeof(*cmd);
+	if (number)
+		len += strlen(number);
+
+	cmd = malloc(len);
+	if (!cmd)
+		return BT_STATUS_NOMEM;
+
+	cmd->index = index;
+	cmd->dir = dir;
+	cmd->state = state;
+	cmd->mode = mode;
+	cmd->mpty = mpty;
+	cmd->type = type;
+
+	if (number) {
+		cmd->number_len = strlen(number);
+		memcpy(cmd->number, number, cmd->number_len);
+	} else {
+		cmd->number_len = 0;
+	}
+
+	status = hal_ipc_cmd(HAL_SERVICE_ID_HANDSFREE,
+					HAL_OP_HANDSFREE_CLCC_RESPONSE, len,
+					cmd, 0, NULL, NULL);
+
+	free(cmd);
+
+	return status;
+}
+
+static bt_status_t phone_state_change(int num_active, int num_held,
+					bthf_call_state_t state,
+					const char *number,
+					bthf_call_addrtype_t type)
+{
+	struct hal_cmd_handsfree_phone_state_change *cmd;
+	bt_status_t status;
+	int len;
+
+	DBG("");
+
+	if (!interface_ready())
+		return BT_STATUS_NOT_READY;
+
+	len = sizeof(*cmd);
+	if (number)
+		len += strlen(number);
+
+	cmd = malloc(len);
+	if (!cmd)
+		return BT_STATUS_NOMEM;
+
+	cmd->num_active = num_active;
+	cmd->num_held = num_held;
+	cmd->state = state;
+	cmd->type = type;
+
+	if (number) {
+		cmd->number_len = strlen(number);
+		memcpy(cmd->number, number, cmd->number_len);
+	} else {
+		cmd->number_len = 0;
+	}
+
+	status = hal_ipc_cmd(HAL_SERVICE_ID_HANDSFREE,
+					HAL_OP_HANDSFREE_PHONE_STATE_CHANGE,
+					len, cmd, 0, NULL, NULL);
+
+	free(cmd);
+
+	return status;
+}
+
 static void cleanup(void)
 {
 	struct hal_cmd_unregister_module cmd;
@@ -245,6 +575,20 @@ static void cleanup(void)
 static bthf_interface_t iface = {
 	.size = sizeof(iface),
 	.init = init,
+	.connect = handsfree_connect,
+	.disconnect = disconnect,
+	.connect_audio = connect_audio,
+	.disconnect_audio = disconnect_audio,
+	.start_voice_recognition = start_voice_recognition,
+	.stop_voice_recognition = stop_voice_recognition,
+	.volume_control = volume_control,
+	.device_status_notification = device_status_notification,
+	.cops_response = cops_response,
+	.cind_response = cind_response,
+	.formatted_at_response = formatted_at_response,
+	.at_response = at_response,
+	.clcc_response = clcc_response,
+	.phone_state_change = phone_state_change,
 	.cleanup = cleanup
 };
 
-- 
1.8.5.3


^ permalink raw reply related

* [PATCH 06/13] android/handsfree: Add SDP record for AG
From: Szymon Janc @ 2014-02-02 21:09 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Szymon Janc
In-Reply-To: <1391375364-27106-1-git-send-email-szymon.janc@tieto.com>

Service Name: Hands-Free Audio GatewayService RecHandle: 0x10001
Service Class ID List:
  "Handsfree Audio Gateway" (0x111f)
  "Generic Audio" (0x1203)
Protocol Descriptor List:
  "L2CAP" (0x0100)
  "RFCOMM" (0x0003)
    Channel: 13
Profile Descriptor List:
  "Handsfree" (0x111e)
    Version: 0x0106
---
 android/handsfree.c | 97 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 97 insertions(+)

diff --git a/android/handsfree.c b/android/handsfree.c
index 3c0d52b..d2dc543 100644
--- a/android/handsfree.c
+++ b/android/handsfree.c
@@ -29,12 +29,19 @@
 #include <glib.h>
 
 #include "lib/bluetooth.h"
+#include "lib/sdp.h"
+#include "lib/sdp_lib.h"
 #include "handsfree.h"
+#include "bluetooth.h"
 #include "src/log.h"
 #include "hal-msg.h"
 #include "ipc.h"
 
+#define HFP_AG_CHANNEL 13
+#define HFP_AG_FEATURES 0
+
 static bdaddr_t adapter_addr;
+static uint32_t record_id = 0;
 
 static void handle_connect(const void *buf, uint16_t len)
 {
@@ -189,12 +196,99 @@ static const struct ipc_handler cmd_handlers[] = {
 			sizeof(struct hal_cmd_handsfree_phone_state_change)},
 };
 
+static sdp_record_t *handsfree_ag_record(void)
+{
+	sdp_list_t *svclass_id, *pfseq, *apseq, *root;
+	uuid_t root_uuid, svclass_uuid, ga_svclass_uuid;
+	uuid_t l2cap_uuid, rfcomm_uuid;
+	sdp_profile_desc_t profile;
+	sdp_list_t *aproto, *proto[2];
+	sdp_record_t *record;
+	sdp_data_t *channel, *features;
+	uint8_t netid = 0x01;
+	uint16_t sdpfeat;
+	sdp_data_t *network;
+	uint8_t ch = HFP_AG_CHANNEL;
+
+	record = sdp_record_alloc();
+	if (!record)
+		return NULL;
+
+	network = sdp_data_alloc(SDP_UINT8, &netid);
+	if (!network) {
+		sdp_record_free(record);
+		return NULL;
+	}
+
+	sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
+	root = sdp_list_append(0, &root_uuid);
+	sdp_set_browse_groups(record, root);
+
+	sdp_uuid16_create(&svclass_uuid, HANDSFREE_AGW_SVCLASS_ID);
+	svclass_id = sdp_list_append(0, &svclass_uuid);
+	sdp_uuid16_create(&ga_svclass_uuid, GENERIC_AUDIO_SVCLASS_ID);
+	svclass_id = sdp_list_append(svclass_id, &ga_svclass_uuid);
+	sdp_set_service_classes(record, svclass_id);
+
+	sdp_uuid16_create(&profile.uuid, HANDSFREE_PROFILE_ID);
+	profile.version = 0x0106;
+	pfseq = sdp_list_append(0, &profile);
+	sdp_set_profile_descs(record, pfseq);
+
+	sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
+	proto[0] = sdp_list_append(0, &l2cap_uuid);
+	apseq = sdp_list_append(0, proto[0]);
+
+	sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
+	proto[1] = sdp_list_append(0, &rfcomm_uuid);
+	channel = sdp_data_alloc(SDP_UINT8, &ch);
+	proto[1] = sdp_list_append(proto[1], channel);
+	apseq = sdp_list_append(apseq, proto[1]);
+
+	sdpfeat = HFP_AG_FEATURES;
+	features = sdp_data_alloc(SDP_UINT16, &sdpfeat);
+	sdp_attr_add(record, SDP_ATTR_SUPPORTED_FEATURES, features);
+
+	aproto = sdp_list_append(0, apseq);
+	sdp_set_access_protos(record, aproto);
+
+	sdp_set_info_attr(record, "Hands-Free Audio Gateway", 0, 0);
+
+	sdp_attr_add(record, SDP_ATTR_EXTERNAL_NETWORK, network);
+
+	sdp_data_free(channel);
+	sdp_list_free(proto[0], 0);
+	sdp_list_free(proto[1], 0);
+	sdp_list_free(apseq, 0);
+	sdp_list_free(pfseq, 0);
+	sdp_list_free(aproto, 0);
+	sdp_list_free(root, 0);
+	sdp_list_free(svclass_id, 0);
+
+	return record;
+}
+
 bool bt_handsfree_register(const bdaddr_t *addr)
 {
+	sdp_record_t *rec;
+
 	DBG("");
 
 	bacpy(&adapter_addr, addr);
 
+	rec = handsfree_ag_record();
+	if (!rec) {
+		error("Failed to allocate Handsfree record");
+		return false;
+	}
+
+	if (bt_adapter_add_record(rec, 0) < 0) {
+		error("Failed to register Handsfree record");
+		sdp_record_free(rec);
+		return false;
+	}
+	record_id = rec->handle;
+
 	ipc_register(HAL_SERVICE_ID_HANDSFREE, cmd_handlers,
 						G_N_ELEMENTS(cmd_handlers));
 
@@ -206,4 +300,7 @@ void bt_handsfree_unregister(void)
 	DBG("");
 
 	ipc_unregister(HAL_SERVICE_ID_HANDSFREE);
+
+	bt_adapter_remove_record(record_id);
+	record_id = 0;
 }
-- 
1.8.5.3


^ permalink raw reply related

* [PATCH 07/13] android/handsfree: Add support for RFCOMM connection handling
From: Szymon Janc @ 2014-02-02 21:09 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Szymon Janc
In-Reply-To: <1391375364-27106-1-git-send-email-szymon.janc@tieto.com>

This adds incoming connection handling and initial connection state
tracking. Only one device is allowed to be connected at the same time.
---
 android/handsfree.c | 167 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 165 insertions(+), 2 deletions(-)

diff --git a/android/handsfree.c b/android/handsfree.c
index d2dc543..ad4c0ff 100644
--- a/android/handsfree.c
+++ b/android/handsfree.c
@@ -25,24 +25,162 @@
 #include <config.h>
 #endif
 
+#include <stdlib.h>
 #include <stdbool.h>
+#include <errno.h>
+#include <unistd.h>
 #include <glib.h>
 
 #include "lib/bluetooth.h"
 #include "lib/sdp.h"
 #include "lib/sdp_lib.h"
+#include "lib/uuid.h"
+#include "src/sdp-client.h"
+#include "src/uuid-helper.h"
+#include "btio/btio.h"
 #include "handsfree.h"
 #include "bluetooth.h"
 #include "src/log.h"
 #include "hal-msg.h"
 #include "ipc.h"
+#include "utils.h"
 
 #define HFP_AG_CHANNEL 13
 #define HFP_AG_FEATURES 0
 
+static struct {
+	bdaddr_t bdaddr;
+	uint8_t state;
+	GIOChannel *io;
+	guint watch;
+} device;
+
 static bdaddr_t adapter_addr;
 static uint32_t record_id = 0;
 
+static GIOChannel *server = NULL;
+
+static void device_set_state(uint8_t state)
+{
+	struct hal_ev_handsfree_conn_state ev;
+	char address[18];
+
+	if (device.state == state)
+		return;
+
+	device.state = state;
+
+	ba2str(&device.bdaddr, address);
+	DBG("device %s state %u", address, state);
+
+	bdaddr2android(&device.bdaddr, ev.bdaddr);
+	ev.state = state;
+
+	ipc_send_notif(HAL_SERVICE_ID_HANDSFREE, HAL_EV_HANDSFREE_CONN_STATE,
+							sizeof(ev), &ev);
+}
+
+static void device_init(const bdaddr_t *bdaddr)
+{
+	bacpy(&device.bdaddr, bdaddr);
+
+	device_set_state(HAL_EV_HANDSFREE_CONNECTION_STATE_CONNECTING);
+}
+
+static void device_cleanup(void)
+{
+	if (device.watch) {
+		g_source_remove(device.watch);
+		device.watch = 0;
+	}
+
+	if (device.io) {
+		g_io_channel_unref(device.io);
+		device.io = NULL;
+	}
+
+	device_set_state(HAL_EV_HANDSFREE_CONNECTION_STATE_DISCONNECTED);
+
+	memset(&device, 0, sizeof(device));
+}
+
+static gboolean watch_cb(GIOChannel *chan, GIOCondition cond,
+							gpointer user_data)
+{
+	DBG("");
+
+	device.watch = 0;
+
+	device_cleanup();
+
+	return FALSE;
+}
+
+static void connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
+{
+	DBG("");
+
+	if (err) {
+		error("handsfree: connect failed (%s)", err->message);
+		goto failed;
+	}
+
+	g_io_channel_set_close_on_unref(chan, TRUE);
+
+	device.watch = g_io_add_watch(chan,
+					G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+					watch_cb, NULL);
+	if (device.watch == 0)
+		goto failed;
+
+	device.io = g_io_channel_ref(chan);
+
+	device_set_state(HAL_EV_HANDSFREE_CONNECTION_STATE_CONNECTED);
+
+	return;
+
+failed:
+	g_io_channel_shutdown(chan, TRUE, NULL);
+	device_cleanup();
+}
+
+static void confirm_cb(GIOChannel *chan, gpointer data)
+{
+	char address[18];
+	bdaddr_t bdaddr;
+	GError *err = NULL;
+
+	bt_io_get(chan, &err,
+			BT_IO_OPT_DEST, address,
+			BT_IO_OPT_DEST_BDADDR, &bdaddr,
+			BT_IO_OPT_INVALID);
+	if (err) {
+		error("handsfree: confirm failed (%s)", err->message);
+		g_error_free(err);
+		goto drop;
+	}
+
+	DBG("incoming connect from %s", address);
+
+	if (device.state != HAL_EV_HANDSFREE_CONNECTION_STATE_DISCONNECTED) {
+		info("handsfree: refusing connection from %s", address);
+		goto drop;
+	}
+
+	device_init(&bdaddr);
+
+	if (!bt_io_accept(chan, connect_cb, NULL, NULL, NULL)) {
+		error("handsfree: failed to accept connection");
+		device_cleanup();
+		goto drop;
+	}
+
+	return;
+
+drop:
+	g_io_channel_shutdown(chan, TRUE, NULL);
+}
+
 static void handle_connect(const void *buf, uint16_t len)
 {
 	DBG("");
@@ -271,21 +409,33 @@ static sdp_record_t *handsfree_ag_record(void)
 bool bt_handsfree_register(const bdaddr_t *addr)
 {
 	sdp_record_t *rec;
+	GError *err = NULL;
 
 	DBG("");
 
 	bacpy(&adapter_addr, addr);
 
+	server =  bt_io_listen( NULL, confirm_cb, NULL, NULL, &err,
+				BT_IO_OPT_SOURCE_BDADDR, &adapter_addr,
+				BT_IO_OPT_CHANNEL, HFP_AG_CHANNEL,
+				BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM,
+				BT_IO_OPT_INVALID);
+	if (!server) {
+		error("Failed to listen on Handsfree rfcomm: %s", err->message);
+		g_error_free(err);
+		return false;
+	}
+
 	rec = handsfree_ag_record();
 	if (!rec) {
 		error("Failed to allocate Handsfree record");
-		return false;
+		goto failed;
 	}
 
 	if (bt_adapter_add_record(rec, 0) < 0) {
 		error("Failed to register Handsfree record");
 		sdp_record_free(rec);
-		return false;
+		goto failed;
 	}
 	record_id = rec->handle;
 
@@ -293,6 +443,13 @@ bool bt_handsfree_register(const bdaddr_t *addr)
 						G_N_ELEMENTS(cmd_handlers));
 
 	return true;
+
+failed:
+	g_io_channel_shutdown(server, TRUE, NULL);
+	g_io_channel_unref(server);
+	server = NULL;
+
+	return false;
 }
 
 void bt_handsfree_unregister(void)
@@ -301,6 +458,12 @@ void bt_handsfree_unregister(void)
 
 	ipc_unregister(HAL_SERVICE_ID_HANDSFREE);
 
+	if (server) {
+		g_io_channel_shutdown(server, TRUE, NULL);
+		g_io_channel_unref(server);
+		server = NULL;
+	}
+
 	bt_adapter_remove_record(record_id);
 	record_id = 0;
 }
-- 
1.8.5.3


^ permalink raw reply related

* [PATCH 08/13] android/handsfree: Add initial code for AT commands processing
From: Szymon Janc @ 2014-02-02 21:09 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Szymon Janc
In-Reply-To: <1391375364-27106-1-git-send-email-szymon.janc@tieto.com>

Currently always reply with error and disconnect connection.
---
 android/Makefile.am |  2 ++
 android/handsfree.c | 21 +++++++++++++++++++++
 2 files changed, 23 insertions(+)

diff --git a/android/Makefile.am b/android/Makefile.am
index 23e30c9..41bbbcb 100644
--- a/android/Makefile.am
+++ b/android/Makefile.am
@@ -27,6 +27,8 @@ android_bluetoothd_SOURCES = android/main.c \
 				src/shared/queue.h src/shared/queue.c \
 				src/shared/util.h src/shared/util.c \
 				src/shared/mgmt.h src/shared/mgmt.c \
+				src/shared/ringbuf.h src/shared/ringbuf.c \
+				src/shared/hfp.h src/shared/hfp.c \
 				android/bluetooth.h android/bluetooth.c \
 				android/hidhost.h android/hidhost.c \
 				android/ipc.h android/ipc.c \
diff --git a/android/handsfree.c b/android/handsfree.c
index ad4c0ff..a4ce398 100644
--- a/android/handsfree.c
+++ b/android/handsfree.c
@@ -37,6 +37,7 @@
 #include "lib/uuid.h"
 #include "src/sdp-client.h"
 #include "src/uuid-helper.h"
+#include "src/shared/hfp.h"
 #include "btio/btio.h"
 #include "handsfree.h"
 #include "bluetooth.h"
@@ -53,6 +54,7 @@ static struct {
 	uint8_t state;
 	GIOChannel *io;
 	guint watch;
+	struct hfp_gw *gw;
 } device;
 
 static bdaddr_t adapter_addr;
@@ -89,6 +91,11 @@ static void device_init(const bdaddr_t *bdaddr)
 
 static void device_cleanup(void)
 {
+	if (device.gw) {
+		hfp_gw_unref(device.gw);
+		device.gw = NULL;
+	}
+
 	if (device.watch) {
 		g_source_remove(device.watch);
 		device.watch = 0;
@@ -116,6 +123,13 @@ static gboolean watch_cb(GIOChannel *chan, GIOCondition cond,
 	return FALSE;
 }
 
+static void at_command_handler(const char *command, void *user_data)
+{
+	hfp_gw_send_result(device.gw, HFP_RESULT_ERROR);
+
+	g_io_channel_shutdown(device.io, TRUE, NULL);
+}
+
 static void connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
 {
 	DBG("");
@@ -127,6 +141,13 @@ static void connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
 
 	g_io_channel_set_close_on_unref(chan, TRUE);
 
+	device.gw = hfp_gw_new(g_io_channel_unix_get_fd(chan));
+	if (!device.gw)
+		goto failed;
+
+	hfp_gw_set_close_on_unref(device.gw, true);
+	hfp_gw_set_command_handler(device.gw, at_command_handler, NULL, NULL);
+
 	device.watch = g_io_add_watch(chan,
 					G_IO_HUP | G_IO_ERR | G_IO_NVAL,
 					watch_cb, NULL);
-- 
1.8.5.3


^ permalink raw reply related

* [PATCH 09/13] android/handsfree: Add connect command handling
From: Szymon Janc @ 2014-02-02 21:09 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Szymon Janc
In-Reply-To: <1391375364-27106-1-git-send-email-szymon.janc@tieto.com>

This allows to query SDP for RFCOMM channel and connect.
---
 android/handsfree.c | 101 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 100 insertions(+), 1 deletion(-)

diff --git a/android/handsfree.c b/android/handsfree.c
index a4ce398..79e61b4 100644
--- a/android/handsfree.c
+++ b/android/handsfree.c
@@ -202,12 +202,111 @@ drop:
 	g_io_channel_shutdown(chan, TRUE, NULL);
 }
 
+static void sdp_search_cb(sdp_list_t *recs, int err, gpointer data)
+{
+	sdp_list_t *protos, *classes;
+	GError *gerr = NULL;
+	GIOChannel *io;
+	uuid_t uuid;
+	int channel;
+
+	DBG("");
+
+	if (err < 0) {
+		error("handsfree: unable to get SDP record: %s", strerror(-err));
+		goto fail;
+	}
+
+	if (!recs || !recs->data) {
+		error("handsfree: no SDP records found");
+		goto fail;
+	}
+
+	if (sdp_get_service_classes(recs->data, &classes) < 0) {
+		error("handsfree: unable to get service classes from record");
+		goto fail;
+	}
+
+	if (sdp_get_access_protos(recs->data, &protos) < 0) {
+		error("handsfree: unable to get access protocols from record");
+		goto fail;
+	}
+
+	/* TODO read remote version? */
+
+	memcpy(&uuid, classes->data, sizeof(uuid));
+	sdp_list_free(classes, free);
+
+	if (!sdp_uuid128_to_uuid(&uuid) || uuid.type != SDP_UUID16 ||
+			uuid.value.uuid16 != HANDSFREE_SVCLASS_ID) {
+		sdp_list_free(protos, NULL);
+		error("handsfree: invalid service record or not HFP");
+		goto fail;
+	}
+
+	channel = sdp_get_proto_port(protos, RFCOMM_UUID);
+	sdp_list_foreach(protos, (sdp_list_func_t) sdp_list_free, NULL);
+	sdp_list_free(protos, NULL);
+	if (channel <= 0) {
+		error("handsfree: unable to get RFCOMM channel from record");
+		goto fail;
+	}
+
+	io = bt_io_connect(connect_cb, NULL, NULL, &gerr,
+				BT_IO_OPT_SOURCE_BDADDR, &adapter_addr,
+				BT_IO_OPT_DEST_BDADDR, &device.bdaddr,
+				BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM,
+				BT_IO_OPT_CHANNEL, channel,
+				BT_IO_OPT_INVALID);
+	if (!io) {
+		error("handsfree: unable to connect: %s", gerr->message);
+		g_error_free(gerr);
+		goto fail;
+	}
+
+	g_io_channel_unref(io);
+	return;
+
+fail:
+	device_cleanup();
+}
+
 static void handle_connect(const void *buf, uint16_t len)
 {
+	const struct hal_cmd_handsfree_connect *cmd = buf;
+	char addr[18];
+	uint8_t status;
+	uuid_t uuid;
+	bdaddr_t bdaddr;
+
 	DBG("");
 
+	if (device.state != HAL_EV_HANDSFREE_CONNECTION_STATE_DISCONNECTED) {
+		status = HAL_STATUS_FAILED;
+		goto failed;
+	}
+
+	android2bdaddr(&cmd->bdaddr, &bdaddr);
+
+	ba2str(&device.bdaddr, addr);
+	DBG("connecting to %s", addr);
+
+	device_init(&bdaddr);
+
+	bt_string2uuid(&uuid, HFP_HS_UUID);
+	if (bt_search_service(&adapter_addr, &device.bdaddr, &uuid,
+					sdp_search_cb, NULL, NULL, 0) < 0) {
+		error("handsfree: SDP search failed");
+		device_cleanup();
+		status = HAL_STATUS_FAILED;
+		goto failed;
+	}
+
+	status = HAL_STATUS_SUCCESS;
+
+failed:
 	ipc_send_rsp(HAL_SERVICE_ID_HANDSFREE, HAL_OP_HANDSFREE_CONNECT,
-							HAL_STATUS_FAILED);
+									status);
 }
 
 static void handle_disconnect(const void *buf, uint16_t len)
-- 
1.8.5.3


^ permalink raw reply related

* [PATCH 10/13] android/handsfree: Add disconnect command handling
From: Szymon Janc @ 2014-02-02 21:09 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Szymon Janc
In-Reply-To: <1391375364-27106-1-git-send-email-szymon.janc@tieto.com>

---
 android/handsfree.c | 30 +++++++++++++++++++++++++++++-
 1 file changed, 29 insertions(+), 1 deletion(-)

diff --git a/android/handsfree.c b/android/handsfree.c
index 79e61b4..5fe7638 100644
--- a/android/handsfree.c
+++ b/android/handsfree.c
@@ -311,10 +311,38 @@ failed:
 
 static void handle_disconnect(const void *buf, uint16_t len)
 {
+	const struct hal_cmd_handsfree_disconnect *cmd = buf;
+	bdaddr_t bdaddr;
+	uint8_t status;
+
 	DBG("");
 
+	android2bdaddr(cmd->bdaddr, &bdaddr);
+
+	if (device.state == HAL_EV_HANDSFREE_CONNECTION_STATE_DISCONNECTED ||
+			bacmp(&device.bdaddr, &bdaddr)) {
+		status = HAL_STATUS_FAILED;
+		goto failed;
+
+	}
+
+	if (device.state == HAL_EV_HANDSFREE_CONNECTION_STATE_DISCONNECTING) {
+		status = HAL_STATUS_SUCCESS;
+		goto failed;
+	}
+
+	if (device.io) {
+		device_set_state(HAL_EV_HANDSFREE_CONNECTION_STATE_DISCONNECTING);
+		g_io_channel_shutdown(device.io, TRUE, NULL);
+	} else {
+		device_cleanup();
+	}
+
+	status = HAL_STATUS_SUCCESS;
+
+failed:
 	ipc_send_rsp(HAL_SERVICE_ID_HANDSFREE, HAL_OP_HANDSFREE_DISCONNECT,
-							HAL_STATUS_FAILED);
+									status);
 }
 
 static void handle_connect_audio(const void *buf, uint16_t len)
-- 
1.8.5.3


^ permalink raw reply related

* [PATCH 11/13] android/handsfree: Add AT+BRSF command support
From: Szymon Janc @ 2014-02-02 21:09 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Szymon Janc
In-Reply-To: <1391375364-27106-1-git-send-email-szymon.janc@tieto.com>

---
 android/handsfree.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 65 insertions(+), 1 deletion(-)

diff --git a/android/handsfree.c b/android/handsfree.c
index 5fe7638..990ba2f 100644
--- a/android/handsfree.c
+++ b/android/handsfree.c
@@ -49,12 +49,16 @@
 #define HFP_AG_CHANNEL 13
 #define HFP_AG_FEATURES 0
 
+#define AG_FEATURES 0
+
 static struct {
 	bdaddr_t bdaddr;
 	uint8_t state;
 	GIOChannel *io;
 	guint watch;
 	struct hfp_gw *gw;
+
+	uint32_t features;
 } device;
 
 static bdaddr_t adapter_addr;
@@ -123,11 +127,69 @@ static gboolean watch_cb(GIOChannel *chan, GIOCondition cond,
 	return FALSE;
 }
 
+static bool at_brsf(const char *at)
+{
+	uint32_t feat;
+
+	if (sscanf(at, " = %u", &feat) != 1) {
+		hfp_gw_send_result(device.gw, HFP_RESULT_ERROR);
+		return false;
+	}
+
+	/* TODO verify features */
+	device.features = feat;
+
+	hfp_gw_send_info(device.gw, "+BRSF=%u", AG_FEATURES);
+
+	hfp_gw_send_result(device.gw, HFP_RESULT_OK);
+
+	return true;
+}
+
+static const struct {
+	const char *prefix;
+	int prefix_len;
+	bool (*func)(const char *at_cmds);
+} at_cmds[] = {
+	{ "+BRSF", sizeof("+BRSF") - 1, at_brsf },
+};
+
 static void at_command_handler(const char *command, void *user_data)
 {
+	unsigned int i;
+
+	if (strlen(command) < 3)
+		goto error;
+
+	if (strncmp(command, "AT", sizeof("AT") - 1))
+		goto error;
+
+	command += sizeof("AT") - 1;
+
+	for (i = 0; i < G_N_ELEMENTS(at_cmds); i++) {
+		if (strncmp(command, at_cmds[i].prefix, at_cmds[i].prefix_len))
+			continue;
+
+		command += at_cmds[i].prefix_len;
+
+		if (at_cmds[i].func(command))
+			return;
+
+		goto check_slc;
+	}
+
+error:
 	hfp_gw_send_result(device.gw, HFP_RESULT_ERROR);
 
-	g_io_channel_shutdown(device.io, TRUE, NULL);
+check_slc:
+	/* Error while establishing SLC */
+	if (device.state != HAL_EV_HANDSFREE_CONNECTION_STATE_SLC_CONNECTED)
+		g_io_channel_shutdown(device.io, TRUE, NULL);
+}
+
+static void hfp_gw_debug(const char *str, void *user_data)
+{
+	DBG("%s", str);
 }
 
 static void connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
@@ -148,6 +210,8 @@ static void connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
 	hfp_gw_set_close_on_unref(device.gw, true);
 	hfp_gw_set_command_handler(device.gw, at_command_handler, NULL, NULL);
 
+	hfp_gw_set_debug(device.gw, hfp_gw_debug, NULL, NULL);
+
 	device.watch = g_io_add_watch(chan,
 					G_IO_HUP | G_IO_ERR | G_IO_NVAL,
 					watch_cb, NULL);
-- 
1.8.5.3


^ permalink raw reply related

* [PATCH 12/13] android/handsfree: Add support for AT+CIND command
From: Szymon Janc @ 2014-02-02 21:09 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Szymon Janc
In-Reply-To: <1391375364-27106-1-git-send-email-szymon.janc@tieto.com>

Android supports only fixed number of indicators so this is all static
for now.
---
 android/handsfree.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 57 insertions(+), 1 deletion(-)

diff --git a/android/handsfree.c b/android/handsfree.c
index 990ba2f..02135cb 100644
--- a/android/handsfree.c
+++ b/android/handsfree.c
@@ -51,6 +51,10 @@
 
 #define AG_FEATURES 0
 
+#define CIND_SUPPORT_STR "+CIND: (\"service\",(0,1)),(\"call\",(0,1)),\
+			(\"callsetup\",(0-3)),(\"callheld\",(0-2)),\
+			(\"signal\",(0-5)),(\"roam\",(0,1)),(\"battchg\",(0,1))"
+
 static struct {
 	bdaddr_t bdaddr;
 	uint8_t state;
@@ -146,12 +150,35 @@ static bool at_brsf(const char *at)
 	return true;
 }
 
+static bool at_cind(const char *at)
+{
+	if (strcmp(at, "?")) {
+		ipc_send_notif(HAL_SERVICE_ID_HANDSFREE, HAL_EV_HANDSFREE_CIND,
+								0, NULL);
+
+		return true;
+	}
+
+	if (strcmp(at, "=?")) {
+		hfp_gw_send_info(device.gw, "%s", CIND_SUPPORT_STR);
+
+		hfp_gw_send_result(device.gw, HFP_RESULT_OK);
+
+		return true;
+	}
+
+	hfp_gw_send_result(device.gw, HFP_RESULT_ERROR);
+
+	return false;
+}
+
 static const struct {
 	const char *prefix;
 	int prefix_len;
 	bool (*func)(const char *at_cmds);
 } at_cmds[] = {
 	{ "+BRSF", sizeof("+BRSF") - 1, at_brsf },
+	{ "+CIND", sizeof("+CIND") - 1, at_cind },
 };
 
 static void at_command_handler(const char *command, void *user_data)
@@ -466,12 +493,41 @@ static void handle_cops(const void *buf, uint16_t len)
 							HAL_STATUS_FAILED);
 }
 
+static unsigned int get_callsetup(uint8_t state)
+{
+	switch (state) {
+	case HAL_HANDSFREE_CALL_STATE_INCOMING:
+		return 1;
+	case HAL_HANDSFREE_CALL_STATE_DIALING:
+		return 2;
+	case HAL_HANDSFREE_CALL_STATE_ALERTING:
+		return 3;
+	default:
+		return 0;
+	}
+}
+
 static void handle_cind(const void *buf, uint16_t len)
 {
+	const struct hal_cmd_handsfree_cind_response *cmd = buf;
+
 	DBG("");
 
+	/* HAL doesn't provide CIND values directly so need to convert here */
+
+	hfp_gw_send_info(device.gw, "+CIND: %u,%u,%u,%u,%u,%u,%u",
+				cmd->svc,
+				!!(cmd->num_active + cmd->num_held),
+				get_callsetup(cmd->state),
+				cmd->num_held ? (cmd->num_active ? 1 : 2) : 0,
+				cmd->signal,
+				cmd->roam,
+				cmd->batt_chg);
+
+	hfp_gw_send_result(device.gw, HFP_RESULT_OK);
+
 	ipc_send_rsp(HAL_SERVICE_ID_HANDSFREE, HAL_OP_HANDSFREE_CIND_RESPONSE,
-							HAL_STATUS_FAILED);
+							HAL_STATUS_SUCCESS);
 }
 
 static void handle_formatted_at_resp(const void *buf, uint16_t len)
-- 
1.8.5.3


^ permalink raw reply related

* [PATCH 13/13] android/handsfree: Add support for AT+CMER command
From: Szymon Janc @ 2014-02-02 21:09 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Szymon Janc
In-Reply-To: <1391375364-27106-1-git-send-email-szymon.janc@tieto.com>

---
 android/handsfree.c | 26 ++++++++++++++++++++++++++
 1 file changed, 26 insertions(+)

diff --git a/android/handsfree.c b/android/handsfree.c
index 02135cb..bf6a575 100644
--- a/android/handsfree.c
+++ b/android/handsfree.c
@@ -63,6 +63,7 @@ static struct {
 	struct hfp_gw *gw;
 
 	uint32_t features;
+	bool ind_notif_active;
 } device;
 
 static bdaddr_t adapter_addr;
@@ -172,6 +173,30 @@ static bool at_cind(const char *at)
 	return false;
 }
 
+static bool at_cmer(const char *at)
+{
+	unsigned int mode, ind;
+	int ret;
+
+	DBG("");
+
+	ret = sscanf(at, " = %u, %*u, %*u, %u", &mode, &ind);
+	if (ret != 2 || mode != 3 || ind > 1) {
+		hfp_gw_send_result(device.gw, HFP_RESULT_ERROR);
+
+		return false;
+	}
+
+	device.ind_notif_active = ind;
+
+	hfp_gw_send_result(device.gw, HFP_RESULT_OK);
+
+	/* TODO Check for 3-way calling support */
+	device_set_state(HAL_EV_HANDSFREE_CONNECTION_STATE_SLC_CONNECTED);
+
+	return true;
+}
+
 static const struct {
 	const char *prefix;
 	int prefix_len;
@@ -179,6 +204,7 @@ static const struct {
 } at_cmds[] = {
 	{ "+BRSF", sizeof("+BRSF") - 1, at_brsf },
 	{ "+CIND", sizeof("+CIND") - 1, at_cind },
+	{ "+CMER", sizeof("+CMER") - 1, at_cmer },
 };
 
 static void at_command_handler(const char *command, void *user_data)
-- 
1.8.5.3


^ permalink raw reply related

* AVRCP profile/plugin in bluez 5
From: Serkan Kaba @ 2014-02-03  6:52 UTC (permalink / raw)
  To: linux-bluetooth@vger.kernel.org

Hi,

I was trying to get my GTK-N1BT hi-fi system. It was constantly bailing "UUIDs has unsupported type" errors and disconnecting after the pairing. All the online examples were referring to bluez 4 config (audio.conf) which even in 4 it was hard to get it working. I added the following in "General" section of audio.conf
<code>
Enable=Media,Sink,Source

</code>
and got it working

I couldn't figure out enabling avrcp profile with bluez 5. Please help

^ permalink raw reply

* [PATCH] pbap: Fix PhonebookSize endianness
From: Hannu Mallat @ 2014-02-03  7:47 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Hannu Mallat

As g_obex_apparam_set_uint16() converts data to big-endian format
internally, do not call htons() prior to it.
---
 obexd/plugins/pbap.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/obexd/plugins/pbap.c b/obexd/plugins/pbap.c
index 4740188..acac3aa 100644
--- a/obexd/plugins/pbap.c
+++ b/obexd/plugins/pbap.c
@@ -188,7 +188,7 @@ static void phonebook_size_result(const char *buffer, size_t bufsize,
 
 	DBG("vcards %d", vcards);
 
-	phonebooksize = htons(vcards);
+	phonebooksize = vcards;
 
 	pbap->obj->apparam = g_obex_apparam_set_uint16(NULL, PHONEBOOKSIZE_TAG,
 								phonebooksize);
@@ -365,7 +365,7 @@ static int generate_response(void *user_data)
 
 	if (max == 0) {
 		/* Ignore all other parameter and return PhoneBookSize */
-		uint16_t size = htons(g_slist_length(pbap->cache.entries));
+		uint16_t size = g_slist_length(pbap->cache.entries);
 
 		pbap->obj->apparam = g_obex_apparam_set_uint16(
 							pbap->obj->apparam,
-- 
1.8.5.3


^ permalink raw reply related

* Re: [PATCH] avrcp: Fix wrong pointer check
From: Andrei Emeltchenko @ 2014-02-03  7:51 UTC (permalink / raw)
  To: Luiz Augusto von Dentz; +Cc: linux-bluetooth@vger.kernel.org
In-Reply-To: <CABBYNZ+-mc_u+ihj_FB5e89TNmBgZvyWxW4vwMCuFDh1_TjCJg@mail.gmail.com>

Hi Luiz,

On Sun, Feb 02, 2014 at 08:03:34AM -0800, Luiz Augusto von Dentz wrote:
> Hi Andrei,
> 
> On Fri, Jan 31, 2014 at 12:33 AM, Andrei Emeltchenko
> <Andrei.Emeltchenko.news@gmail.com> wrote:
> > From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
> >
> > There is wrong assumption that handler might be NULL while it is a
> > pointer to a struct table so check instead for struct members. This
> > fixes accessing wrong memory.
> > ---
> >  profiles/audio/avrcp.c | 4 ++--
> >  1 file changed, 2 insertions(+), 2 deletions(-)
> >
> > diff --git a/profiles/audio/avrcp.c b/profiles/audio/avrcp.c
> > index df88138..5030ce1 100644
> > --- a/profiles/audio/avrcp.c
> > +++ b/profiles/audio/avrcp.c
> > @@ -1673,7 +1673,7 @@ static size_t handle_vendordep_pdu(struct avctp *conn, uint8_t transaction,
> >                         break;
> >         }
> >
> > -       if (!handler || handler->code != *code) {
> > +       if (!handler->code || handler->code != *code) {
> 
> The code checks if  session->control_handlers is initialized and Im
> not sure what is the invalid memory access you are talking about since
> handle->code is no a pointer, I do agree that we should probably drop
> the second check for the handler in the lines bellow.

handler is a pointer, and it points to

static const struct control_pdu_handler control_handlers[] 
table with the last element:

...
		{ },
};
...

So checking for !handler is pointless.

Best regards 
Andrei Emeltchenko 

^ permalink raw reply

* Re: [PATCH 06/13] android/handsfree: Add SDP record for AG
From: Andrei Emeltchenko @ 2014-02-03  7:56 UTC (permalink / raw)
  To: Szymon Janc; +Cc: linux-bluetooth
In-Reply-To: <1391375364-27106-7-git-send-email-szymon.janc@tieto.com>

Hi Szymon,

On Sun, Feb 02, 2014 at 10:09:17PM +0100, Szymon Janc wrote:
> Service Name: Hands-Free Audio GatewayService RecHandle: 0x10001
> Service Class ID List:
>   "Handsfree Audio Gateway" (0x111f)
>   "Generic Audio" (0x1203)
> Protocol Descriptor List:
>   "L2CAP" (0x0100)
>   "RFCOMM" (0x0003)
>     Channel: 13
> Profile Descriptor List:
>   "Handsfree" (0x111e)
>     Version: 0x0106
> ---
>  android/handsfree.c | 97 +++++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 97 insertions(+)
> 
> diff --git a/android/handsfree.c b/android/handsfree.c
> index 3c0d52b..d2dc543 100644
> --- a/android/handsfree.c
> +++ b/android/handsfree.c
> @@ -29,12 +29,19 @@
>  #include <glib.h>
>  
>  #include "lib/bluetooth.h"
> +#include "lib/sdp.h"
> +#include "lib/sdp_lib.h"
>  #include "handsfree.h"
> +#include "bluetooth.h"
>  #include "src/log.h"
>  #include "hal-msg.h"
>  #include "ipc.h"
>  
> +#define HFP_AG_CHANNEL 13
> +#define HFP_AG_FEATURES 0
> +
>  static bdaddr_t adapter_addr;
> +static uint32_t record_id = 0;
>  
>  static void handle_connect(const void *buf, uint16_t len)
>  {
> @@ -189,12 +196,99 @@ static const struct ipc_handler cmd_handlers[] = {
>  			sizeof(struct hal_cmd_handsfree_phone_state_change)},
>  };
>  
> +static sdp_record_t *handsfree_ag_record(void)
> +{
> +	sdp_list_t *svclass_id, *pfseq, *apseq, *root;
> +	uuid_t root_uuid, svclass_uuid, ga_svclass_uuid;
> +	uuid_t l2cap_uuid, rfcomm_uuid;
> +	sdp_profile_desc_t profile;
> +	sdp_list_t *aproto, *proto[2];
> +	sdp_record_t *record;
> +	sdp_data_t *channel, *features;
> +	uint8_t netid = 0x01;
> +	uint16_t sdpfeat;
> +	sdp_data_t *network;
> +	uint8_t ch = HFP_AG_CHANNEL;
> +
> +	record = sdp_record_alloc();
> +	if (!record)
> +		return NULL;
> +
> +	network = sdp_data_alloc(SDP_UINT8, &netid);
> +	if (!network) {
> +		sdp_record_free(record);
> +		return NULL;
> +	}
> +
> +	sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
> +	root = sdp_list_append(0, &root_uuid);
> +	sdp_set_browse_groups(record, root);
> +
> +	sdp_uuid16_create(&svclass_uuid, HANDSFREE_AGW_SVCLASS_ID);
> +	svclass_id = sdp_list_append(0, &svclass_uuid);
> +	sdp_uuid16_create(&ga_svclass_uuid, GENERIC_AUDIO_SVCLASS_ID);
> +	svclass_id = sdp_list_append(svclass_id, &ga_svclass_uuid);
> +	sdp_set_service_classes(record, svclass_id);
> +
> +	sdp_uuid16_create(&profile.uuid, HANDSFREE_PROFILE_ID);
> +	profile.version = 0x0106;
> +	pfseq = sdp_list_append(0, &profile);
> +	sdp_set_profile_descs(record, pfseq);
> +
> +	sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
> +	proto[0] = sdp_list_append(0, &l2cap_uuid);
> +	apseq = sdp_list_append(0, proto[0]);
> +
> +	sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
> +	proto[1] = sdp_list_append(0, &rfcomm_uuid);
> +	channel = sdp_data_alloc(SDP_UINT8, &ch);
> +	proto[1] = sdp_list_append(proto[1], channel);
> +	apseq = sdp_list_append(apseq, proto[1]);
> +
> +	sdpfeat = HFP_AG_FEATURES;
> +	features = sdp_data_alloc(SDP_UINT16, &sdpfeat);
> +	sdp_attr_add(record, SDP_ATTR_SUPPORTED_FEATURES, features);
> +
> +	aproto = sdp_list_append(0, apseq);
> +	sdp_set_access_protos(record, aproto);
> +
> +	sdp_set_info_attr(record, "Hands-Free Audio Gateway", 0, 0);
> +
> +	sdp_attr_add(record, SDP_ATTR_EXTERNAL_NETWORK, network);
> +
> +	sdp_data_free(channel);
> +	sdp_list_free(proto[0], 0);

We have agreed to use NULL for zero pointers.

Best regards 
Andrei Emeltchenko 


^ permalink raw reply

* Re: [PATCH] android/avrcp: Decouple AVRCP logic from btio
From: Andrei Emeltchenko @ 2014-02-03  9:01 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1391092704-24806-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>

On Thu, Jan 30, 2014 at 04:38:24PM +0200, Andrei Emeltchenko wrote:
> From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
> 
> The patch makes AVRCP to be channel-agnostic so that it might be used in
> unit tests. The idea is that all AVRCP logic would come to avrcp-lib and
> channel stuff got to avrcp.
> ---
>  android/Android.mk  |  1 +
>  android/Makefile.am |  1 +
>  android/avrcp-lib.c | 87 +++++++++++++++++++++++++++++++++++++++++++++++++++++
>  android/avrcp-lib.h | 32 ++++++++++++++++++++
>  android/avrcp.c     | 46 ++--------------------------
>  5 files changed, 124 insertions(+), 43 deletions(-)
>  create mode 100644 android/avrcp-lib.c
>  create mode 100644 android/avrcp-lib.h
> 
> diff --git a/android/Android.mk b/android/Android.mk
> index 1d12da5..09b54d6 100644
> --- a/android/Android.mk
> +++ b/android/Android.mk
> @@ -30,6 +30,7 @@ LOCAL_SRC_FILES := \
>  	bluez/android/avdtp.c \
>  	bluez/android/a2dp.c \
>  	bluez/android/avctp.c \
> +	bluez/android/avrcp-lib.c \
>  	bluez/android/avrcp.c \
>  	bluez/android/pan.c \
>  	bluez/src/log.c \
> diff --git a/android/Makefile.am b/android/Makefile.am
> index e065c0c..29cbf79 100644
> --- a/android/Makefile.am
> +++ b/android/Makefile.am
> @@ -34,6 +34,7 @@ android_bluetoothd_SOURCES = android/main.c \
>  				android/avdtp.h android/avdtp.c \
>  				android/a2dp.h android/a2dp.c \
>  				android/avctp.h android/avctp.c \
> +				android/avrcp-lib.h android/avrcp-lib.c \
>  				android/avrcp.h android/avrcp.c \
>  				android/socket.h android/socket.c \
>  				android/pan.h android/pan.c \
> diff --git a/android/avrcp-lib.c b/android/avrcp-lib.c
> new file mode 100644
> index 0000000..33d03d9
> --- /dev/null
> +++ b/android/avrcp-lib.c
> @@ -0,0 +1,87 @@
> +/*
> + *
> + *  BlueZ - Bluetooth protocol stack for Linux
> + *
> + *  Copyright (C) 2014  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 <stdbool.h>
> +#include <glib.h>
> +
> +#include "lib/bluetooth.h"
> +
> +#include "src/log.h"
> +
> +#include "avctp.h"
> +#include "avrcp-lib.h"
> +
> +static GSList *devices = NULL;
> +
> +void avrcp_device_free(void *data)
> +{
> +	struct avrcp_device *dev = data;
> +
> +	if (dev->session)
> +		avctp_shutdown(dev->session);
> +
> +	devices = g_slist_remove(devices, dev);
> +	g_free(dev);
> +}
> +
> +void avrcp_free_all(void)
> +{
> +	g_slist_free_full(devices, avrcp_device_free);
> +	devices = NULL;
> +}
> +
> +struct avrcp_device *avrcp_device_new(const bdaddr_t *dst)
> +{
> +	struct avrcp_device *dev;
> +
> +	dev = g_new0(struct avrcp_device, 1);
> +	bacpy(&dev->dst, dst);
> +	devices = g_slist_prepend(devices, dev);
> +
> +	return dev;
> +}
> +
> +static int device_cmp(gconstpointer s, gconstpointer user_data)
> +{
> +	const struct avrcp_device *dev = s;
> +	const bdaddr_t *dst = user_data;
> +
> +	return bacmp(&dev->dst, dst);
> +}
> +
> +struct avrcp_device *avrcp_find(bdaddr_t *dst)
> +{
> +	GSList *l;
> +
> +	l = g_slist_find_custom(devices, dst, device_cmp);
> +	if (l) {

will fix this to !l

Best regards 
Andrei Emeltchenko 

^ permalink raw reply

* [PATCHv2] android/avrcp: Decouple AVRCP logic from btio
From: Andrei Emeltchenko @ 2014-02-03  9:16 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1391092704-24806-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

The patch makes AVRCP to be channel-agnostic so that it might be used in
unit tests. The idea is that all AVRCP logic would come to avrcp-lib and
channel stuff got to avrcp.
---
 android/Android.mk  |  1 +
 android/Makefile.am |  1 +
 android/avrcp-lib.c | 85 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 android/avrcp-lib.h | 32 ++++++++++++++++++++
 android/avrcp.c     | 44 ++-------------------------
 5 files changed, 122 insertions(+), 41 deletions(-)
 create mode 100644 android/avrcp-lib.c
 create mode 100644 android/avrcp-lib.h

diff --git a/android/Android.mk b/android/Android.mk
index 09ed32d..2772b58 100644
--- a/android/Android.mk
+++ b/android/Android.mk
@@ -30,6 +30,7 @@ LOCAL_SRC_FILES := \
 	bluez/android/avdtp.c \
 	bluez/android/a2dp.c \
 	bluez/android/avctp.c \
+	bluez/android/avrcp-lib.c \
 	bluez/android/avrcp.c \
 	bluez/android/pan.c \
 	bluez/src/log.c \
diff --git a/android/Makefile.am b/android/Makefile.am
index e065c0c..29cbf79 100644
--- a/android/Makefile.am
+++ b/android/Makefile.am
@@ -34,6 +34,7 @@ android_bluetoothd_SOURCES = android/main.c \
 				android/avdtp.h android/avdtp.c \
 				android/a2dp.h android/a2dp.c \
 				android/avctp.h android/avctp.c \
+				android/avrcp-lib.h android/avrcp-lib.c \
 				android/avrcp.h android/avrcp.c \
 				android/socket.h android/socket.c \
 				android/pan.h android/pan.c \
diff --git a/android/avrcp-lib.c b/android/avrcp-lib.c
new file mode 100644
index 0000000..a4bfe6d
--- /dev/null
+++ b/android/avrcp-lib.c
@@ -0,0 +1,85 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2014  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 <stdbool.h>
+#include <glib.h>
+
+#include "lib/bluetooth.h"
+
+#include "src/log.h"
+
+#include "avctp.h"
+#include "avrcp-lib.h"
+
+static GSList *devices = NULL;
+
+void avrcp_device_free(void *data)
+{
+	struct avrcp_device *dev = data;
+
+	if (dev->session)
+		avctp_shutdown(dev->session);
+
+	devices = g_slist_remove(devices, dev);
+	g_free(dev);
+}
+
+void avrcp_free_all(void)
+{
+	g_slist_free_full(devices, avrcp_device_free);
+	devices = NULL;
+}
+
+struct avrcp_device *avrcp_device_new(const bdaddr_t *dst)
+{
+	struct avrcp_device *dev;
+
+	dev = g_new0(struct avrcp_device, 1);
+	bacpy(&dev->dst, dst);
+	devices = g_slist_prepend(devices, dev);
+
+	return dev;
+}
+
+static int device_cmp(gconstpointer s, gconstpointer user_data)
+{
+	const struct avrcp_device *dev = s;
+	const bdaddr_t *dst = user_data;
+
+	return bacmp(&dev->dst, dst);
+}
+
+struct avrcp_device *avrcp_find(bdaddr_t *dst)
+{
+	GSList *l;
+
+	l = g_slist_find_custom(devices, dst, device_cmp);
+	if (!l)
+		return NULL;
+
+	return l->data;
+}
diff --git a/android/avrcp-lib.h b/android/avrcp-lib.h
new file mode 100644
index 0000000..a7213fb
--- /dev/null
+++ b/android/avrcp-lib.h
@@ -0,0 +1,32 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2014  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
+ *
+ */
+
+struct avrcp_device {
+	bdaddr_t	dst;
+	struct avctp	*session;
+};
+
+struct avrcp_device *avrcp_device_new(const bdaddr_t *dst);
+void avrcp_device_free(void *data);
+void avrcp_free_all(void);
+struct avrcp_device *avrcp_find(bdaddr_t *dst);
diff --git a/android/avrcp.c b/android/avrcp.c
index ef833df..ff923cb 100644
--- a/android/avrcp.c
+++ b/android/avrcp.c
@@ -38,6 +38,7 @@
 #include "hal-msg.h"
 #include "ipc.h"
 #include "avctp.h"
+#include "avrcp-lib.h"
 
 #define L2CAP_PSM_AVCTP 0x17
 
@@ -48,14 +49,8 @@
 
 static bdaddr_t adapter_addr;
 static uint32_t record_id = 0;
-static GSList *devices = NULL;
 static GIOChannel *server = NULL;
 
-struct avrcp_device {
-	bdaddr_t	dst;
-	struct avctp	*session;
-};
-
 static const struct ipc_handler cmd_handlers[] = {
 };
 
@@ -127,36 +122,6 @@ static sdp_record_t *avrcp_record(void)
 	return record;
 }
 
-static void avrcp_device_free(void *data)
-{
-	struct avrcp_device *dev = data;
-
-	if (dev->session)
-		avctp_shutdown(dev->session);
-
-	devices = g_slist_remove(devices, dev);
-	g_free(dev);
-}
-
-static struct avrcp_device *avrcp_device_new(const bdaddr_t *dst)
-{
-	struct avrcp_device *dev;
-
-	dev = g_new0(struct avrcp_device, 1);
-	bacpy(&dev->dst, dst);
-	devices = g_slist_prepend(devices, dev);
-
-	return dev;
-}
-
-static int device_cmp(gconstpointer s, gconstpointer user_data)
-{
-	const struct avrcp_device *dev = s;
-	const bdaddr_t *dst = user_data;
-
-	return bacmp(&dev->dst, dst);
-}
-
 static void disconnect_cb(void *data)
 {
 	struct avrcp_device *dev = data;
@@ -175,7 +140,6 @@ static void connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
 	char address[18];
 	uint16_t imtu, omtu;
 	GError *gerr = NULL;
-	GSList *l;
 	int fd;
 
 	if (err) {
@@ -199,8 +163,7 @@ static void connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
 	ba2str(&dst, address);
 	DBG("Incoming connection from %s", address);
 
-	l = g_slist_find_custom(devices, &dst, device_cmp);
-	if (l) {
+	if (avrcp_find(&dst)) {
 		error("Unexpected connection");
 		return;
 	}
@@ -274,8 +237,7 @@ void bt_avrcp_unregister(void)
 {
 	DBG("");
 
-	g_slist_free_full(devices, avrcp_device_free);
-	devices = NULL;
+	avrcp_free_all();
 
 	ipc_unregister(HAL_SERVICE_ID_AVRCP);
 
-- 
1.8.3.2


^ permalink raw reply related

* Re: [PATCH] avrcp: Fix wrong pointer check
From: Luiz Augusto von Dentz @ 2014-02-03  9:20 UTC (permalink / raw)
  To: Andrei Emeltchenko, Luiz Augusto von Dentz,
	linux-bluetooth@vger.kernel.org
In-Reply-To: <20140203074920.GA2930@aemeltch-MOBL1>

Hi Andrei,

On Sun, Feb 2, 2014 at 11:51 PM, Andrei Emeltchenko
<Andrei.Emeltchenko.news@gmail.com> wrote:
> Hi Luiz,
>
> On Sun, Feb 02, 2014 at 08:03:34AM -0800, Luiz Augusto von Dentz wrote:
>> Hi Andrei,
>>
>> On Fri, Jan 31, 2014 at 12:33 AM, Andrei Emeltchenko
>> <Andrei.Emeltchenko.news@gmail.com> wrote:
>> > From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
>> >
>> > There is wrong assumption that handler might be NULL while it is a
>> > pointer to a struct table so check instead for struct members. This
>> > fixes accessing wrong memory.
>> > ---
>> >  profiles/audio/avrcp.c | 4 ++--
>> >  1 file changed, 2 insertions(+), 2 deletions(-)
>> >
>> > diff --git a/profiles/audio/avrcp.c b/profiles/audio/avrcp.c
>> > index df88138..5030ce1 100644
>> > --- a/profiles/audio/avrcp.c
>> > +++ b/profiles/audio/avrcp.c
>> > @@ -1673,7 +1673,7 @@ static size_t handle_vendordep_pdu(struct avctp *conn, uint8_t transaction,
>> >                         break;
>> >         }
>> >
>> > -       if (!handler || handler->code != *code) {
>> > +       if (!handler->code || handler->code != *code) {
>>
>> The code checks if  session->control_handlers is initialized and Im
>> not sure what is the invalid memory access you are talking about since
>> handle->code is no a pointer, I do agree that we should probably drop
>> the second check for the handler in the lines bellow.
>
> handler is a pointer, and it points to
>
> static const struct control_pdu_handler control_handlers[]
> table with the last element:
>
> ...
>                 { },
> };
> ...
>
> So checking for !handler is pointless.

Right, because checking for pointer is pointless, yes Im being
sarcastic here... Now lets be clear, you are changing a check of a
pointer to a value and claiming it fixes invalid accesses which does
not make any sense, what could make sense is to check if
handler->pdu_id == pdu->pdu_id since that what we check when we lookup
for a handle.



-- 
Luiz Augusto von Dentz

^ permalink raw reply

* Re: [PATCH] avrcp: Fix wrong pointer check
From: Andrei Emeltchenko @ 2014-02-03  9:36 UTC (permalink / raw)
  To: Luiz Augusto von Dentz; +Cc: linux-bluetooth@vger.kernel.org
In-Reply-To: <CABBYNZ+VPAkfgUNRu6GC9DhkP=KXpTzBC03OVW8nNC_55uaMfg@mail.gmail.com>

On Mon, Feb 03, 2014 at 01:20:11AM -0800, Luiz Augusto von Dentz wrote:
> Hi Andrei,
> 
> On Sun, Feb 2, 2014 at 11:51 PM, Andrei Emeltchenko
> <Andrei.Emeltchenko.news@gmail.com> wrote:
> > Hi Luiz,
> >
> > On Sun, Feb 02, 2014 at 08:03:34AM -0800, Luiz Augusto von Dentz wrote:
> >> Hi Andrei,
> >>
> >> On Fri, Jan 31, 2014 at 12:33 AM, Andrei Emeltchenko
> >> <Andrei.Emeltchenko.news@gmail.com> wrote:
> >> > From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
> >> >
> >> > There is wrong assumption that handler might be NULL while it is a
> >> > pointer to a struct table so check instead for struct members. This
> >> > fixes accessing wrong memory.
> >> > ---
> >> >  profiles/audio/avrcp.c | 4 ++--
> >> >  1 file changed, 2 insertions(+), 2 deletions(-)
> >> >
> >> > diff --git a/profiles/audio/avrcp.c b/profiles/audio/avrcp.c
> >> > index df88138..5030ce1 100644
> >> > --- a/profiles/audio/avrcp.c
> >> > +++ b/profiles/audio/avrcp.c
> >> > @@ -1673,7 +1673,7 @@ static size_t handle_vendordep_pdu(struct avctp *conn, uint8_t transaction,
> >> >                         break;
> >> >         }
> >> >
> >> > -       if (!handler || handler->code != *code) {
> >> > +       if (!handler->code || handler->code != *code) {
> >>
> >> The code checks if  session->control_handlers is initialized and Im
> >> not sure what is the invalid memory access you are talking about since
> >> handle->code is no a pointer, I do agree that we should probably drop
> >> the second check for the handler in the lines bellow.
> >
> > handler is a pointer, and it points to
> >
> > static const struct control_pdu_handler control_handlers[]
> > table with the last element:
> >
> > ...
> >                 { },
> > };
> > ...
> >
> > So checking for !handler is pointless.
> 
> Right, because checking for pointer is pointless, yes Im being
> sarcastic here... Now lets be clear, you are changing a check of a
> pointer to a value and claiming it fixes invalid accesses which does
> not make any sense, what could make sense is to check if
> handler->pdu_id == pdu->pdu_id since that what we check when we lookup
> for a handle.

No, we break if handler->pdu_id == pdu->pdu_id one line above ;)

Best regards 
Andrei Emeltchenko 

> 
> 
> 
> -- 
> Luiz Augusto von Dentz

^ permalink raw reply

* [PATCH BlueZ] audio/AVRCP: Fix checking for handler pointer instead of pdu_id
From: Luiz Augusto von Dentz @ 2014-02-03  9:40 UTC (permalink / raw)
  To: linux-bluetooth

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

The code may not find a valid handler for the pdu_id, in that case the
handler would not be NULL because the handlers table is not NULL
terminated, instead the code should check if pdu_id really matches.
---
 profiles/audio/avrcp.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/profiles/audio/avrcp.c b/profiles/audio/avrcp.c
index 12f7faa..4532d85 100644
--- a/profiles/audio/avrcp.c
+++ b/profiles/audio/avrcp.c
@@ -1673,7 +1673,7 @@ static size_t handle_vendordep_pdu(struct avctp *conn, uint8_t transaction,
 			break;
 	}
 
-	if (!handler || handler->code != *code) {
+	if (handler->pdu_id != pdu->pdu_id || handler->code != *code) {
 		pdu->params[0] = AVRCP_STATUS_INVALID_COMMAND;
 		goto err_metadata;
 	}
@@ -1734,12 +1734,12 @@ static size_t handle_browsing_pdu(struct avctp *conn,
 
 	for (handler = browsing_handlers; handler->pdu_id; handler++) {
 		if (handler->pdu_id == pdu->pdu_id)
-			break;
+			goto done;
 	}
 
-	if (handler == NULL || handler->func == NULL)
-		return avrcp_browsing_general_reject(operands);
+	return avrcp_browsing_general_reject(operands);
 
+done:
 	session->transaction = transaction;
 	handler->func(session, pdu, transaction);
 	return AVRCP_BROWSING_HEADER_LENGTH + ntohs(pdu->param_len);
-- 
1.8.4.2


^ permalink raw reply related

* Re: [PATCH] avrcp: Fix wrong pointer check
From: Andrei Emeltchenko @ 2014-02-03  9:42 UTC (permalink / raw)
  To: Luiz Augusto von Dentz, linux-bluetooth@vger.kernel.org
In-Reply-To: <20140203093651.GE2930@aemeltch-MOBL1>

On Mon, Feb 03, 2014 at 11:36:52AM +0200, Andrei Emeltchenko wrote:
> On Mon, Feb 03, 2014 at 01:20:11AM -0800, Luiz Augusto von Dentz wrote:
> > Hi Andrei,
> > 
> > On Sun, Feb 2, 2014 at 11:51 PM, Andrei Emeltchenko
> > <Andrei.Emeltchenko.news@gmail.com> wrote:
> > > Hi Luiz,
> > >
> > > On Sun, Feb 02, 2014 at 08:03:34AM -0800, Luiz Augusto von Dentz wrote:
> > >> Hi Andrei,
> > >>
> > >> On Fri, Jan 31, 2014 at 12:33 AM, Andrei Emeltchenko
> > >> <Andrei.Emeltchenko.news@gmail.com> wrote:
> > >> > From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
> > >> >
> > >> > There is wrong assumption that handler might be NULL while it is a
> > >> > pointer to a struct table so check instead for struct members. This
> > >> > fixes accessing wrong memory.
> > >> > ---
> > >> >  profiles/audio/avrcp.c | 4 ++--
> > >> >  1 file changed, 2 insertions(+), 2 deletions(-)
> > >> >
> > >> > diff --git a/profiles/audio/avrcp.c b/profiles/audio/avrcp.c
> > >> > index df88138..5030ce1 100644
> > >> > --- a/profiles/audio/avrcp.c
> > >> > +++ b/profiles/audio/avrcp.c
> > >> > @@ -1673,7 +1673,7 @@ static size_t handle_vendordep_pdu(struct avctp *conn, uint8_t transaction,
> > >> >                         break;
> > >> >         }
> > >> >
> > >> > -       if (!handler || handler->code != *code) {
> > >> > +       if (!handler->code || handler->code != *code) {
> > >>
> > >> The code checks if  session->control_handlers is initialized and Im
> > >> not sure what is the invalid memory access you are talking about since
> > >> handle->code is no a pointer, I do agree that we should probably drop
> > >> the second check for the handler in the lines bellow.
> > >
> > > handler is a pointer, and it points to
> > >
> > > static const struct control_pdu_handler control_handlers[]
> > > table with the last element:
> > >
> > > ...
> > >                 { },
> > > };
> > > ...
> > >
> > > So checking for !handler is pointless.
> > 
> > Right, because checking for pointer is pointless, yes Im being
> > sarcastic here... Now lets be clear, you are changing a check of a
> > pointer to a value and claiming it fixes invalid accesses which does
> > not make any sense, what could make sense is to check if
> > handler->pdu_id == pdu->pdu_id since that what we check when we lookup
> > for a handle.
> 
> No, we break if handler->pdu_id == pdu->pdu_id one line above ;)

Sorry this was wrong. So my idea is to check that we are not at the end of
the table. In this case every element of a struct is zero, so it does not
matter which one to check.

Best regards 
Andrei Emeltchenko 


^ permalink raw reply

* Re: [PATCH] Bluetooth: hidp: make sure input buffers are big enough
From: Jiri Kosina @ 2014-02-03 10:08 UTC (permalink / raw)
  To: David Herrmann
  Cc: Marcel Holtmann, open list:HID CORE LAYER,
	linux-bluetooth@vger.kernel.org development, Gustavo F. Padovan
In-Reply-To: <CANq1E4TW+GU=oaW0tXb=Tun9HMtr26u-PC3H6BsLot560ANgog@mail.gmail.com>

On Wed, 29 Jan 2014, David Herrmann wrote:

> >> Due to various reasons I will not have access to any testing HW for the
> >> upcoming 2-3 days, so if you can cook something up in that timeframe, it'd
> >> be appreciated.
> >>
> >> Otherwise I'll be working on it by the end of this week.
> >
> > David,
> >
> > just got back to this, finally ... did you have time to work on this at
> > all, or should I just start from scratch?
> 
> Sorry, no. Fosdem is this weekend and I needed to get my code ready
> for that. But I'll finally have time again next week.

Okay, thanks. I then guess we should proceed with this bandaid (double 
allocation) for 3.14

-- 
Jiri Kosina
SUSE Labs

^ permalink raw reply

* Re: [PATCH] Bluetooth: hidp: make sure input buffers are big enough
From: David Herrmann @ 2014-02-03 11:27 UTC (permalink / raw)
  To: Jiri Kosina
  Cc: Marcel Holtmann, open list:HID CORE LAYER,
	linux-bluetooth@vger.kernel.org development, Gustavo F. Padovan
In-Reply-To: <alpine.LNX.2.00.1402031107310.14066@pobox.suse.cz>

Hi Jiri

On Mon, Feb 3, 2014 at 11:08 AM, Jiri Kosina <jkosina@suse.cz> wrote:
> On Wed, 29 Jan 2014, David Herrmann wrote:
>
>> >> Due to various reasons I will not have access to any testing HW for the
>> >> upcoming 2-3 days, so if you can cook something up in that timeframe, it'd
>> >> be appreciated.
>> >>
>> >> Otherwise I'll be working on it by the end of this week.
>> >
>> > David,
>> >
>> > just got back to this, finally ... did you have time to work on this at
>> > all, or should I just start from scratch?
>>
>> Sorry, no. Fosdem is this weekend and I needed to get my code ready
>> for that. But I'll finally have time again next week.
>
> Okay, thanks. I then guess we should proceed with this bandaid (double
> allocation) for 3.14

It would be really nice if we could get the HIDP patch into 3.14-rc2
and backported to stable. There have been quite a bunch of reports now
and I dislike adding a GFP_ATOMIC allocation in HID core. I am back
home now and will try to make HID core honor the length, but that's
quite invasive and shouldn't be used for stable.

Sorry for the delay,
David

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox