* [PATCH v2 11/20] unit/AVDTP: Add /TP/SIG/SMG/BV-15-C test
From: Luiz Augusto von Dentz @ 2013-11-25 14:54 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1385391283-10962-1-git-send-email-luiz.dentz@gmail.com>
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
Verify that the IUT (INT) is able to establish a stream connection to a
previously configured remote SEP by establishing one L2CAP channel
(AVDTP_OPEN_CMD), and reports the related confirmation.
---
unit/test-avdtp.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 54 insertions(+), 2 deletions(-)
diff --git a/unit/test-avdtp.c b/unit/test-avdtp.c
index a266819..4e46987 100644
--- a/unit/test-avdtp.c
+++ b/unit/test-avdtp.c
@@ -40,7 +40,7 @@
struct test_pdu {
bool valid;
- const void *data;
+ const uint8_t *data;
size_t size;
};
@@ -234,11 +234,31 @@ static void sep_setconf_cfm(struct avdtp *session, struct avdtp_local_sep *sep,
struct avdtp_stream *stream,
struct avdtp_error *err, void *user_data)
{
+ struct context *context = user_data;
+ const struct test_pdu *pdu;
int ret;
g_assert(err == NULL);
- ret = avdtp_get_configuration(session, stream);
+ if (!context)
+ return;
+
+ pdu = &context->pdu_list[context->pdu_offset];
+
+ if (pdu->size < 2)
+ return;
+
+ switch (pdu->data[1]) {
+ case 0x04:
+ ret = avdtp_get_configuration(session, stream);
+ break;
+ case 0x06:
+ ret = avdtp_open(session, stream);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
g_assert_cmpint(ret, ==, 0);
}
@@ -381,6 +401,28 @@ static void test_get_configuration(gconstpointer data)
g_free(test->pdu_list);
}
+static void test_open(gconstpointer data)
+{
+ const struct test_data *test = data;
+ struct context *context = create_context(0x0100);
+ struct avdtp_local_sep *sep;
+
+ context->pdu_list = test->pdu_list;
+
+ sep = avdtp_register_sep(AVDTP_SEP_TYPE_SINK, AVDTP_MEDIA_TYPE_AUDIO,
+ 0x00, FALSE, NULL, &sep_cfm,
+ context);
+ context->sep = sep;
+
+ avdtp_discover(context->session, discover_cb, context);
+
+ execute_context(context);
+
+ avdtp_unregister_sep(sep);
+
+ g_free(test->pdu_list);
+}
+
int main(int argc, char *argv[])
{
g_test_init(&argc, &argv, NULL);
@@ -448,6 +490,16 @@ int main(int argc, char *argv[])
raw_pdu(0x30, 0x04, 0x04),
raw_pdu(0x32, 0x04, 0x01, 0x00, 0x07, 0x06, 0x00, 0x00,
0x21, 0x02, 0x02, 0x20));
+ define_test("/TP/SIG/SMG/BV-15-C", test_open,
+ raw_pdu(0xa0, 0x01),
+ raw_pdu(0xa2, 0x01, 0x04, 0x00),
+ raw_pdu(0xb0, 0x02, 0x04),
+ raw_pdu(0xb2, 0x02, 0x01, 0x00, 0x07, 0x06, 0x00, 0x00,
+ 0xff, 0xff, 0x02, 0x40),
+ raw_pdu(0xc0, 0x03, 0x04, 0x04, 0x01, 0x00, 0x07, 0x06,
+ 0x00, 0x00, 0x21, 0x02, 0x02, 0x20),
+ raw_pdu(0xc2, 0x03),
+ raw_pdu(0xd0, 0x06, 0x04));
return g_test_run();
}
--
1.8.3.1
^ permalink raw reply related
* [PATCH v2 10/20] unit/AVDTP: Add /TP/SIG/SMG/BV-12-C test
From: Luiz Augusto von Dentz @ 2013-11-25 14:54 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1385391283-10962-1-git-send-email-luiz.dentz@gmail.com>
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
Verify that the IUT (ACP) reports the reception of a valid get
configuration command for remote SEP and replies the returned
configuration.
---
unit/test-avdtp.c | 15 ++++++++++++++-
1 file changed, 14 insertions(+), 1 deletion(-)
diff --git a/unit/test-avdtp.c b/unit/test-avdtp.c
index 1f43c08..a266819 100644
--- a/unit/test-avdtp.c
+++ b/unit/test-avdtp.c
@@ -368,7 +368,8 @@ static void test_get_configuration(gconstpointer data)
context->pdu_list = test->pdu_list;
sep = avdtp_register_sep(AVDTP_SEP_TYPE_SINK, AVDTP_MEDIA_TYPE_AUDIO,
- 0x00, FALSE, &sep_ind, &sep_cfm, NULL);
+ 0x00, FALSE, NULL, &sep_cfm,
+ context);
context->sep = sep;
avdtp_discover(context->session, discover_cb, context);
@@ -435,6 +436,18 @@ int main(int argc, char *argv[])
0x00, 0x00, 0x21, 0x02, 0x02, 0x20),
raw_pdu(0x82, 0x03),
raw_pdu(0x90, 0x04, 0x04));
+ define_test("/TP/SIG/SMG/BV-12-C", test_server,
+ raw_pdu(0x00, 0x01),
+ raw_pdu(0x02, 0x01, 0x04, 0x00),
+ raw_pdu(0x10, 0x02, 0x04),
+ raw_pdu(0x12, 0x02, 0x01, 0x00, 0x07, 0x06, 0x00, 0x00,
+ 0xff, 0xff, 0x02, 0x40),
+ raw_pdu(0x20, 0x03, 0x04, 0x04, 0x01, 0x00, 0x07, 0x06,
+ 0x00, 0x00, 0x21, 0x02, 0x02, 0x20),
+ raw_pdu(0x22, 0x03),
+ raw_pdu(0x30, 0x04, 0x04),
+ raw_pdu(0x32, 0x04, 0x01, 0x00, 0x07, 0x06, 0x00, 0x00,
+ 0x21, 0x02, 0x02, 0x20));
return g_test_run();
}
--
1.8.3.1
^ permalink raw reply related
* [PATCH v2 09/20] unit/AVDTP: Add /TP/SIG/SMG/BV-11-C test
From: Luiz Augusto von Dentz @ 2013-11-25 14:54 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1385391283-10962-1-git-send-email-luiz.dentz@gmail.com>
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
Verify that the IUT (INT) is able to issue a valid get configuration
command for remote SEP and report the replied configuration.
---
unit/test-avdtp.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 47 insertions(+)
diff --git a/unit/test-avdtp.c b/unit/test-avdtp.c
index e39ed24..1f43c08 100644
--- a/unit/test-avdtp.c
+++ b/unit/test-avdtp.c
@@ -230,6 +230,22 @@ static struct avdtp_sep_ind sep_ind = {
.get_capability = sep_getcap_ind,
};
+static void sep_setconf_cfm(struct avdtp *session, struct avdtp_local_sep *sep,
+ struct avdtp_stream *stream,
+ struct avdtp_error *err, void *user_data)
+{
+ int ret;
+
+ g_assert(err == NULL);
+
+ ret = avdtp_get_configuration(session, stream);
+ g_assert_cmpint(ret, ==, 0);
+}
+
+static struct avdtp_sep_cfm sep_cfm = {
+ .set_configuration = sep_setconf_cfm,
+};
+
static void test_server(gconstpointer data)
{
const struct test_data *test = data;
@@ -343,6 +359,27 @@ static void test_set_configuration(gconstpointer data)
g_free(test->pdu_list);
}
+static void test_get_configuration(gconstpointer data)
+{
+ const struct test_data *test = data;
+ struct context *context = create_context(0x0100);
+ struct avdtp_local_sep *sep;
+
+ context->pdu_list = test->pdu_list;
+
+ sep = avdtp_register_sep(AVDTP_SEP_TYPE_SINK, AVDTP_MEDIA_TYPE_AUDIO,
+ 0x00, FALSE, &sep_ind, &sep_cfm, NULL);
+ context->sep = sep;
+
+ avdtp_discover(context->session, discover_cb, context);
+
+ execute_context(context);
+
+ avdtp_unregister_sep(sep);
+
+ g_free(test->pdu_list);
+}
+
int main(int argc, char *argv[])
{
g_test_init(&argc, &argv, NULL);
@@ -388,6 +425,16 @@ int main(int argc, char *argv[])
raw_pdu(0x20, 0x03, 0x04, 0x04, 0x01, 0x00, 0x07, 0x06,
0x00, 0x00, 0x21, 0x02, 0x02, 0x20),
raw_pdu(0x22, 0x03));
+ define_test("/TP/SIG/SMG/BV-11-C", test_get_configuration,
+ raw_pdu(0x60, 0x01),
+ raw_pdu(0x62, 0x01, 0x04, 0x00),
+ raw_pdu(0x70, 0x02, 0x04),
+ raw_pdu(0x72, 0x02, 0x01, 0x00, 0x07, 0x06, 0x00, 0x00,
+ 0xff, 0xff, 0x02, 0x40),
+ raw_pdu(0x80, 0x03, 0x04, 0x04, 0x01, 0x00, 0x07, 0x06,
+ 0x00, 0x00, 0x21, 0x02, 0x02, 0x20),
+ raw_pdu(0x82, 0x03),
+ raw_pdu(0x90, 0x04, 0x04));
return g_test_run();
}
--
1.8.3.1
^ permalink raw reply related
* [PATCH v2 08/20] unit/AVDTP: Add /TP/SIG/SMG/BV-10-C test
From: Luiz Augusto von Dentz @ 2013-11-25 14:54 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1385391283-10962-1-git-send-email-luiz.dentz@gmail.com>
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
Verify that the IUT (ACP) reports the reception of a valid set
configuration command for remote SEP, and configures the SEP as
requested and replies the returned confirmation.
---
unit/test-avdtp.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/unit/test-avdtp.c b/unit/test-avdtp.c
index b0991d9..e39ed24 100644
--- a/unit/test-avdtp.c
+++ b/unit/test-avdtp.c
@@ -379,6 +379,15 @@ int main(int argc, char *argv[])
0xff, 0xff, 0x02, 0x40),
raw_pdu(0x50, 0x03, 0x04, 0x04, 0x01, 0x00, 0x07, 0x06,
0x00, 0x00, 0x21, 0x02, 0x02, 0x20));
+ define_test("/TP/SIG/SMG/BV-10-C", test_server,
+ raw_pdu(0x00, 0x01),
+ raw_pdu(0x02, 0x01, 0x04, 0x00),
+ raw_pdu(0x10, 0x02, 0x04),
+ raw_pdu(0x12, 0x02, 0x01, 0x00, 0x07, 0x06, 0x00, 0x00,
+ 0xff, 0xff, 0x02, 0x40),
+ raw_pdu(0x20, 0x03, 0x04, 0x04, 0x01, 0x00, 0x07, 0x06,
+ 0x00, 0x00, 0x21, 0x02, 0x02, 0x20),
+ raw_pdu(0x22, 0x03));
return g_test_run();
}
--
1.8.3.1
^ permalink raw reply related
* [PATCH v2 07/20] unit/AVDTP: Add /TP/SIG/SMG/BV-09-C test
From: Luiz Augusto von Dentz @ 2013-11-25 14:54 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1385391283-10962-1-git-send-email-luiz.dentz@gmail.com>
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
Verify that the IUT (INT) is able to issue a valid set configuration
command for remote SEP and reports the replied confirmation.
---
unit/test-avdtp.c | 68 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 68 insertions(+)
diff --git a/unit/test-avdtp.c b/unit/test-avdtp.c
index 0b92489..b0991d9 100644
--- a/unit/test-avdtp.c
+++ b/unit/test-avdtp.c
@@ -71,6 +71,7 @@ struct test_data {
struct context {
GMainLoop *main_loop;
struct avdtp *session;
+ struct avdtp_local_sep *sep;
guint source;
int fd;
int mtu;
@@ -252,7 +253,45 @@ static void test_server(gconstpointer data)
static void discover_cb(struct avdtp *session, GSList *seps,
struct avdtp_error *err, void *user_data)
{
+ struct context *context = user_data;
+ struct avdtp_stream *stream;
+ struct avdtp_remote_sep *rsep;
+ struct avdtp_service_capability *media_transport, *media_codec;
+ struct avdtp_media_codec_capability *cap;
+ GSList *caps;
+ uint8_t data[4] = { 0x21, 0x02, 2, 32 };
+ int ret;
+
+ if (!context)
+ return;
+
+ g_assert(err == NULL);
+ g_assert_cmpint(g_slist_length(seps), !=, 0);
+
+ rsep = avdtp_find_remote_sep(session, context->sep);
+ g_assert(rsep != NULL);
+
+ media_transport = avdtp_service_cap_new(AVDTP_MEDIA_TRANSPORT,
+ NULL, 0);
+
+ caps = g_slist_append(NULL, media_transport);
+
+ cap = g_malloc0(sizeof(*cap) + sizeof(data));
+ cap->media_type = AVDTP_MEDIA_TYPE_AUDIO;
+ cap->media_codec_type = 0x00;
+ memcpy(cap->data, data, sizeof(data));
+ media_codec = avdtp_service_cap_new(AVDTP_MEDIA_CODEC, cap,
+ sizeof(*cap) + sizeof(data));
+
+ caps = g_slist_append(caps, media_codec);
+ g_free(cap);
+
+ ret = avdtp_set_configuration(session, rsep, context->sep, caps,
+ &stream);
+ g_assert_cmpint(ret, ==, 0);
+
+ g_slist_free_full(caps, g_free);
}
static void test_discover(gconstpointer data)
@@ -283,6 +322,27 @@ static void test_get_capabilities(gconstpointer data)
g_free(test->pdu_list);
}
+static void test_set_configuration(gconstpointer data)
+{
+ const struct test_data *test = data;
+ struct context *context = create_context(0x0100);
+ struct avdtp_local_sep *sep;
+
+ context->pdu_list = test->pdu_list;
+
+ sep = avdtp_register_sep(AVDTP_SEP_TYPE_SINK, AVDTP_MEDIA_TYPE_AUDIO,
+ 0x00, FALSE, NULL, NULL, NULL);
+ context->sep = sep;
+
+ avdtp_discover(context->session, discover_cb, context);
+
+ execute_context(context);
+
+ avdtp_unregister_sep(sep);
+
+ g_free(test->pdu_list);
+}
+
int main(int argc, char *argv[])
{
g_test_init(&argc, &argv, NULL);
@@ -311,6 +371,14 @@ int main(int argc, char *argv[])
raw_pdu(0x10, 0x02, 0x04),
raw_pdu(0x12, 0x02, 0x01, 0x00, 0x07, 0x06, 0x00, 0x00,
0xff, 0xff, 0x02, 0x40));
+ define_test("/TP/SIG/SMG/BV-09-C", test_set_configuration,
+ raw_pdu(0x30, 0x01),
+ raw_pdu(0x32, 0x01, 0x04, 0x00),
+ raw_pdu(0x40, 0x02, 0x04),
+ 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));
return g_test_run();
}
--
1.8.3.1
^ permalink raw reply related
* [PATCH v2 06/20] unit/AVDTP: Add /TP/SIG/SMG/BV-08-C test
From: Luiz Augusto von Dentz @ 2013-11-25 14:54 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1385391283-10962-1-git-send-email-luiz.dentz@gmail.com>
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
Verify that the IUT (ACP) reports the reception of a valid query for
remote SEP capabilities and replies the returned capabilities.
---
unit/test-avdtp.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 46 insertions(+), 2 deletions(-)
diff --git a/unit/test-avdtp.c b/unit/test-avdtp.c
index 81155a4..0b92489 100644
--- a/unit/test-avdtp.c
+++ b/unit/test-avdtp.c
@@ -195,26 +195,64 @@ static void execute_context(struct context *context)
g_free(context);
}
+static gboolean sep_getcap_ind(struct avdtp *session,
+ struct avdtp_local_sep *sep,
+ gboolean get_all, GSList **caps,
+ uint8_t *err, void *user_data)
+{
+ struct avdtp_service_capability *media_transport, *media_codec;
+ struct avdtp_media_codec_capability *codec_caps;
+ uint8_t cap[4] = { 0xff, 0xff, 2, 64 };
+
+ *caps = NULL;
+
+ media_transport = avdtp_service_cap_new(AVDTP_MEDIA_TRANSPORT,
+ NULL, 0);
+
+ *caps = g_slist_append(*caps, media_transport);
+
+ codec_caps = g_malloc0(sizeof(*codec_caps) + sizeof(cap));
+ codec_caps->media_type = AVDTP_MEDIA_TYPE_AUDIO;
+ codec_caps->media_codec_type = 0x00;
+ memcpy(codec_caps->data, cap, sizeof(cap));
+
+ media_codec = avdtp_service_cap_new(AVDTP_MEDIA_CODEC, codec_caps,
+ sizeof(*codec_caps) + sizeof(cap));
+
+ *caps = g_slist_append(*caps, media_codec);
+ g_free(codec_caps);
+
+ return TRUE;
+}
+
+static struct avdtp_sep_ind sep_ind = {
+ .get_capability = sep_getcap_ind,
+};
+
static void test_server(gconstpointer data)
{
const struct test_data *test = data;
struct context *context = create_context(0x0100);
+ struct avdtp_local_sep *sep;
context->pdu_list = test->pdu_list;
- avdtp_register_sep(AVDTP_SEP_TYPE_SOURCE, AVDTP_MEDIA_TYPE_AUDIO, 0x00,
- TRUE, NULL, NULL, NULL);
+ sep = avdtp_register_sep(AVDTP_SEP_TYPE_SOURCE, AVDTP_MEDIA_TYPE_AUDIO,
+ 0x00, TRUE, &sep_ind, NULL, NULL);
g_idle_add(send_pdu, context);
execute_context(context);
+ avdtp_unregister_sep(sep);
+
g_free(test->pdu_list);
}
static void discover_cb(struct avdtp *session, GSList *seps,
struct avdtp_error *err, void *user_data)
{
+
}
static void test_discover(gconstpointer data)
@@ -267,6 +305,12 @@ int main(int argc, char *argv[])
raw_pdu(0x10, 0x01),
raw_pdu(0x12, 0x01, 0x04, 0x00),
raw_pdu(0x20, 0x02, 0x04));
+ define_test("/TP/SIG/SMG/BV-08-C", test_server,
+ raw_pdu(0x00, 0x01),
+ raw_pdu(0x02, 0x01, 0x04, 0x00),
+ raw_pdu(0x10, 0x02, 0x04),
+ raw_pdu(0x12, 0x02, 0x01, 0x00, 0x07, 0x06, 0x00, 0x00,
+ 0xff, 0xff, 0x02, 0x40));
return g_test_run();
}
--
1.8.3.1
^ permalink raw reply related
* [PATCH v2 05/20] unit/AVDTP: Add /TP/SIG/SMG/BV-07-C test
From: Luiz Augusto von Dentz @ 2013-11-25 14:54 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1385391283-10962-1-git-send-email-luiz.dentz@gmail.com>
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
Verify that the IUT (INT) is able to issue a valid query for remote SEP
capabilities and reports the replied ones.
---
unit/test-avdtp.c | 23 +++++++++++++++++++++--
1 file changed, 21 insertions(+), 2 deletions(-)
diff --git a/unit/test-avdtp.c b/unit/test-avdtp.c
index 5623153..81155a4 100644
--- a/unit/test-avdtp.c
+++ b/unit/test-avdtp.c
@@ -198,11 +198,12 @@ static void execute_context(struct context *context)
static void test_server(gconstpointer data)
{
const struct test_data *test = data;
- struct context *context = create_context();
+ struct context *context = create_context(0x0100);
context->pdu_list = test->pdu_list;
+
avdtp_register_sep(AVDTP_SEP_TYPE_SOURCE, AVDTP_MEDIA_TYPE_AUDIO, 0x00,
- TRUE, NULL, NULL, NULL);
+ TRUE, NULL, NULL, NULL);
g_idle_add(send_pdu, context);
@@ -230,6 +231,20 @@ static void test_discover(gconstpointer data)
g_free(test->pdu_list);
}
+static void test_get_capabilities(gconstpointer data)
+{
+ const struct test_data *test = data;
+ struct context *context = create_context(0x0100);
+
+ context->pdu_list = test->pdu_list;
+
+ avdtp_discover(context->session, discover_cb, NULL);
+
+ execute_context(context);
+
+ g_free(test->pdu_list);
+}
+
int main(int argc, char *argv[])
{
g_test_init(&argc, &argv, NULL);
@@ -248,6 +263,10 @@ int main(int argc, char *argv[])
define_test("/TP/SIG/SMG/BV-06-C", test_server,
raw_pdu(0x00, 0x01),
raw_pdu(0x02, 0x01, 0x04, 0x00));
+ define_test("/TP/SIG/SMG/BV-07-C", test_get_capabilities,
+ raw_pdu(0x10, 0x01),
+ raw_pdu(0x12, 0x01, 0x04, 0x00),
+ raw_pdu(0x20, 0x02, 0x04));
return g_test_run();
}
--
1.8.3.1
^ permalink raw reply related
* [PATCH v2 04/20] unit/AVDTP: Add /TP/SIG/SMG/BV-06-C test
From: Luiz Augusto von Dentz @ 2013-11-25 14:54 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1385391283-10962-1-git-send-email-luiz.dentz@gmail.com>
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
Verify that the IUT (ACP) reports the reception of a valid stream
discover command and replies the returned list of SEPs and media types.
---
unit/test-avdtp.c | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
diff --git a/unit/test-avdtp.c b/unit/test-avdtp.c
index 2dc9424..5623153 100644
--- a/unit/test-avdtp.c
+++ b/unit/test-avdtp.c
@@ -195,6 +195,22 @@ static void execute_context(struct context *context)
g_free(context);
}
+static void test_server(gconstpointer data)
+{
+ const struct test_data *test = data;
+ struct context *context = create_context();
+
+ context->pdu_list = test->pdu_list;
+ avdtp_register_sep(AVDTP_SEP_TYPE_SOURCE, AVDTP_MEDIA_TYPE_AUDIO, 0x00,
+ TRUE, NULL, NULL, NULL);
+
+ g_idle_add(send_pdu, context);
+
+ execute_context(context);
+
+ g_free(test->pdu_list);
+}
+
static void discover_cb(struct avdtp *session, GSList *seps,
struct avdtp_error *err, void *user_data)
{
@@ -229,6 +245,9 @@ int main(int argc, char *argv[])
*/
define_test("/TP/SIG/SMG/BV-05-C", test_discover,
raw_pdu(0x00, 0x01));
+ define_test("/TP/SIG/SMG/BV-06-C", test_server,
+ raw_pdu(0x00, 0x01),
+ raw_pdu(0x02, 0x01, 0x04, 0x00));
return g_test_run();
}
--
1.8.3.1
^ permalink raw reply related
* [PATCH v2 03/20] unit/AVDTP: Add /TP/SIG/SMG/BV-05-C test
From: Luiz Augusto von Dentz @ 2013-11-25 14:54 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1385391283-10962-1-git-send-email-luiz.dentz@gmail.com>
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
Verify that the IUT (INT) is able to issue a valid stream discover command
and report the replied SEPs and media types.
---
Makefile.am | 8 ++
unit/test-avdtp.c | 234 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 242 insertions(+)
create mode 100644 unit/test-avdtp.c
diff --git a/Makefile.am b/Makefile.am
index 328ccdb..2bb2eb5 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -249,6 +249,14 @@ unit_test_sdp_SOURCES = unit/test-sdp.c \
src/sdpd-service.c src/sdpd-request.c
unit_test_sdp_LDADD = lib/libbluetooth-internal.la @GLIB_LIBS@
+unit_tests += unit/test-avdtp
+
+unit_test_avdtp_SOURCES = unit/test-avdtp.c \
+ src/shared/util.h src/shared/util.c \
+ src/log.h src/log.c \
+ android/avdtp.c android/avdtp.h
+unit_test_avdtp_LDADD = @GLIB_LIBS@
+
unit_tests += unit/test-gdbus-client
unit_test_gdbus_client_SOURCES = unit/test-gdbus-client.c
diff --git a/unit/test-avdtp.c b/unit/test-avdtp.c
new file mode 100644
index 0000000..2dc9424
--- /dev/null
+++ b/unit/test-avdtp.c
@@ -0,0 +1,234 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2012 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 <stdlib.h>
+#include <stdbool.h>
+#include <inttypes.h>
+#include <string.h>
+#include <sys/socket.h>
+
+#include <glib.h>
+
+#include "src/shared/util.h"
+#include "src/log.h"
+#include "android/avdtp.h"
+
+struct test_pdu {
+ bool valid;
+ const void *data;
+ size_t size;
+};
+
+struct test_data {
+ struct test_pdu *pdu_list;
+};
+
+#define data(args...) ((const unsigned char[]) { args })
+
+#define raw_pdu(args...) \
+ { \
+ .valid = true, \
+ .data = data(args), \
+ .size = sizeof(data(args)), \
+ }
+
+#define define_test(name, function, args...) \
+ do { \
+ const struct test_pdu pdus[] = { \
+ args, { }, { } \
+ }; \
+ static struct test_data data; \
+ data.pdu_list = g_malloc(sizeof(pdus)); \
+ memcpy(data.pdu_list, pdus, sizeof(pdus)); \
+ g_test_add_data_func(name, &data, function); \
+ } while (0)
+
+struct context {
+ GMainLoop *main_loop;
+ struct avdtp *session;
+ guint source;
+ int fd;
+ int mtu;
+ unsigned int pdu_offset;
+ const struct test_pdu *pdu_list;
+};
+
+static void test_debug(const char *str, void *user_data)
+{
+ const char *prefix = user_data;
+
+ g_print("%s%s\n", prefix, str);
+}
+
+static void context_quit(struct context *context)
+{
+ g_main_loop_quit(context->main_loop);
+}
+
+static gboolean send_pdu(gpointer user_data)
+{
+ struct context *context = user_data;
+ const struct test_pdu *pdu;
+ ssize_t len;
+
+ pdu = &context->pdu_list[context->pdu_offset++];
+
+ len = write(context->fd, pdu->data, pdu->size);
+
+ if (g_test_verbose())
+ util_hexdump('<', pdu->data, len, test_debug, "AVDTP: ");
+
+ g_assert(len == (ssize_t) pdu->size);
+
+ return FALSE;
+}
+
+static void context_process(struct context *context)
+{
+ if (!context->pdu_list[context->pdu_offset].valid) {
+ context_quit(context);
+ return;
+ }
+
+ g_idle_add(send_pdu, context);
+}
+
+static gboolean test_handler(GIOChannel *channel, GIOCondition cond,
+ gpointer user_data)
+{
+ struct context *context = user_data;
+ const struct test_pdu *pdu;
+ unsigned char buf[512];
+ ssize_t len;
+ int fd;
+
+ pdu = &context->pdu_list[context->pdu_offset++];
+
+ if (cond & (G_IO_NVAL | G_IO_ERR | G_IO_HUP))
+ return FALSE;
+
+ fd = g_io_channel_unix_get_fd(channel);
+
+ len = read(fd, buf, sizeof(buf));
+
+ g_assert(len > 0);
+
+ if (g_test_verbose())
+ util_hexdump('>', buf, len, test_debug, "AVDTP: ");
+
+ g_assert((size_t) len == pdu->size);
+
+ g_assert(memcmp(buf, pdu->data, pdu->size) == 0);
+
+ context_process(context);
+
+ return TRUE;
+}
+
+static struct context *create_context(uint16_t version)
+{
+ struct context *context = g_new0(struct context, 1);
+ 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);
+
+ context->session = avdtp_new(sv[0], 672, 672, version);
+ g_assert(context->session != NULL);
+
+ 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];
+
+ return context;
+}
+
+static void execute_context(struct context *context)
+{
+ g_main_loop_run(context->main_loop);
+
+ g_source_remove(context->source);
+ avdtp_unref(context->session);
+
+ g_main_loop_unref(context->main_loop);
+
+ g_free(context);
+}
+
+static void discover_cb(struct avdtp *session, GSList *seps,
+ struct avdtp_error *err, void *user_data)
+{
+}
+
+static void test_discover(gconstpointer data)
+{
+ const struct test_data *test = data;
+ struct context *context = create_context(0x0100);
+
+ context->pdu_list = test->pdu_list;
+
+ avdtp_discover(context->session, discover_cb, NULL);
+
+ execute_context(context);
+
+ g_free(test->pdu_list);
+}
+
+int main(int argc, char *argv[])
+{
+ g_test_init(&argc, &argv, NULL);
+
+ if (g_test_verbose())
+ __btd_log_init("*", 0);
+
+ /*
+ * Stream Management Service
+ *
+ * To verify that the following procedures are implemented according to
+ * their specification in AVDTP.
+ */
+ define_test("/TP/SIG/SMG/BV-05-C", test_discover,
+ raw_pdu(0x00, 0x01));
+
+ return g_test_run();
+}
--
1.8.3.1
^ permalink raw reply related
* [PATCH v2 02/20] android/AVDTP: Strip dependencies
From: Luiz Augusto von Dentz @ 2013-11-25 14:54 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1385391283-10962-1-git-send-email-luiz.dentz@gmail.com>
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This strips AVDTP code of any dependency of core and btio to make it
transport agnostic.
---
android/Android.mk | 1 +
android/Makefile.am | 1 +
android/a2dp.c | 23 ++
android/avdtp.c | 757 +++++-----------------------------------------------
android/avdtp.h | 28 +-
5 files changed, 102 insertions(+), 708 deletions(-)
diff --git a/android/Android.mk b/android/Android.mk
index 616a338..c4d722d 100644
--- a/android/Android.mk
+++ b/android/Android.mk
@@ -25,6 +25,7 @@ LOCAL_SRC_FILES := \
hidhost.c \
socket.c \
ipc.c ipc.h \
+ avdtp.c \
a2dp.c \
pan.c \
../src/log.c \
diff --git a/android/Makefile.am b/android/Makefile.am
index 5f6b1a3..94d231f 100644
--- a/android/Makefile.am
+++ b/android/Makefile.am
@@ -19,6 +19,7 @@ android_bluetoothd_SOURCES = android/main.c \
android/bluetooth.h android/bluetooth.c \
android/hidhost.h android/hidhost.c \
android/ipc.h android/ipc.c \
+ android/avdtp.h android/avdtp.c \
android/a2dp.h android/a2dp.c \
android/socket.h android/socket.c \
android/pan.h android/pan.c \
diff --git a/android/a2dp.c b/android/a2dp.c
index 55a433e..2251001 100644
--- a/android/a2dp.c
+++ b/android/a2dp.c
@@ -43,6 +43,7 @@
#include "ipc.h"
#include "utils.h"
#include "bluetooth.h"
+#include "avdtp.h"
#define L2CAP_PSM_AVDTP 0x19
#define SVC_HINT_CAPTURING 0x08
@@ -58,6 +59,7 @@ struct a2dp_device {
uint8_t state;
GIOChannel *io;
guint watch;
+ struct avdtp *session;
};
static int device_cmp(gconstpointer s, gconstpointer user_data)
@@ -70,6 +72,9 @@ static int device_cmp(gconstpointer s, gconstpointer user_data)
static void a2dp_device_free(struct a2dp_device *dev)
{
+ if (dev->session)
+ avdtp_unref(dev->session);
+
if (dev->watch > 0)
g_source_remove(dev->watch);
@@ -129,6 +134,9 @@ static void signaling_connect_cb(GIOChannel *chan, GError *err,
gpointer user_data)
{
struct a2dp_device *dev = user_data;
+ uint16_t imtu, omtu;
+ GError *gerr = NULL;
+ int fd;
if (err) {
bt_a2dp_notify_state(dev, HAL_A2DP_STATE_DISCONNECTED);
@@ -136,6 +144,21 @@ static void signaling_connect_cb(GIOChannel *chan, GError *err,
return;
}
+ bt_io_get(chan, &gerr,
+ BT_IO_OPT_IMTU, &imtu,
+ BT_IO_OPT_OMTU, &omtu,
+ BT_IO_OPT_INVALID);
+ if (gerr) {
+ bt_a2dp_notify_state(dev, HAL_A2DP_STATE_DISCONNECTED);
+ error("%s", gerr->message);
+ g_error_free(gerr);
+ return;
+ }
+
+ /* FIXME: Add proper version */
+ fd = g_io_channel_unix_get_fd(chan);
+ dev->session = avdtp_new(fd, imtu, omtu, 0x0100);
+
dev->watch = g_io_add_watch(dev->io, G_IO_HUP | G_IO_ERR | G_IO_NVAL,
watch_cb, dev);
diff --git a/android/avdtp.c b/android/avdtp.c
index b7a7d9c..ac08acd 100644
--- a/android/avdtp.c
+++ b/android/avdtp.c
@@ -33,23 +33,14 @@
#include <errno.h>
#include <unistd.h>
#include <assert.h>
-
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/sdp.h>
-#include <bluetooth/sdp_lib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
#include <glib.h>
-#include <btio/btio.h>
#include "log.h"
-
-#include "lib/uuid.h"
-#include "src/adapter.h"
-#include "src/device.h"
-
#include "avdtp.h"
-#include "sink.h"
-#include "source.h"
#define AVDTP_PSM 25
@@ -321,13 +312,6 @@ struct avdtp_remote_sep {
struct avdtp_stream *stream;
};
-struct avdtp_server {
- struct btd_adapter *adapter;
- GIOChannel *io;
- GSList *seps;
- GSList *sessions;
-};
-
struct avdtp_local_sep {
avdtp_state_t state;
struct avdtp_stream *stream;
@@ -338,7 +322,6 @@ struct avdtp_local_sep {
struct avdtp_sep_ind *ind;
struct avdtp_sep_cfm *cfm;
void *user_data;
- struct avdtp_server *server;
};
struct stream_callback {
@@ -347,13 +330,6 @@ struct stream_callback {
unsigned int id;
};
-struct avdtp_state_callback {
- avdtp_session_state_cb cb;
- struct btd_device *dev;
- unsigned int id;
- void *user_data;
-};
-
struct discover_callback {
unsigned int id;
avdtp_discover_cb_t cb;
@@ -390,9 +366,6 @@ struct avdtp {
uint16_t version;
struct avdtp_server *server;
- struct btd_device *device;
-
- avdtp_session_state_t state;
guint auth_id;
@@ -417,16 +390,9 @@ struct avdtp {
struct discover_callback *discover;
struct pending_req *req;
-
- guint dc_timer;
-
- /* Attempt stream setup instead of disconnecting */
- gboolean stream_setup;
};
-static GSList *servers = NULL;
-
-static GSList *state_callbacks = NULL;
+static GSList *lseps = NULL;
static int send_request(struct avdtp *session, gboolean priority,
struct avdtp_stream *stream, uint8_t signal_id,
@@ -444,18 +410,6 @@ static void avdtp_sep_set_state(struct avdtp *session,
struct avdtp_local_sep *sep,
avdtp_state_t state);
-static struct avdtp_server *find_server(GSList *list, struct btd_adapter *a)
-{
- for (; list; list = list->next) {
- struct avdtp_server *server = list->data;
-
- if (server->adapter == a)
- return server;
- }
-
- return NULL;
-}
-
static const char *avdtp_statestr(avdtp_state_t state)
{
switch (state) {
@@ -701,24 +655,6 @@ static struct avdtp_remote_sep *find_remote_sep(GSList *seps, uint8_t seid)
return NULL;
}
-static void avdtp_set_state(struct avdtp *session,
- avdtp_session_state_t new_state)
-{
- GSList *l;
- avdtp_session_state_t old_state = session->state;
-
- session->state = new_state;
-
- for (l = state_callbacks; l != NULL; l = l->next) {
- struct avdtp_state_callback *cb = l->data;
-
- if (session->device != cb->dev)
- continue;
-
- cb->cb(cb->dev, session, old_state, new_state, cb->user_data);
- }
-}
-
static void stream_free(void *data)
{
struct avdtp_stream *stream = data;
@@ -767,47 +703,11 @@ static gboolean transport_cb(GIOChannel *chan, GIOCondition cond,
return FALSE;
}
-static int get_send_buffer_size(int sk)
-{
- int size;
- socklen_t optlen = sizeof(size);
-
- if (getsockopt(sk, SOL_SOCKET, SO_SNDBUF, &size, &optlen) < 0) {
- int err = -errno;
- error("getsockopt(SO_SNDBUF) failed: %s (%d)", strerror(-err),
- -err);
- return err;
- }
-
- /*
- * Doubled value is returned by getsockopt since kernel uses that
- * space for its own purposes (see man 7 socket, bookkeeping overhead
- * for SO_SNDBUF).
- */
- return size / 2;
-}
-
-static int set_send_buffer_size(int sk, int size)
-{
- socklen_t optlen = sizeof(size);
-
- if (setsockopt(sk, SOL_SOCKET, SO_SNDBUF, &size, optlen) < 0) {
- int err = -errno;
- error("setsockopt(SO_SNDBUF) failed: %s (%d)", strerror(-err),
- -err);
- return err;
- }
-
- return 0;
-}
-
static void handle_transport_connect(struct avdtp *session, GIOChannel *io,
uint16_t imtu, uint16_t omtu)
{
struct avdtp_stream *stream = session->pending_open;
struct avdtp_local_sep *sep = stream->lsep;
- int sk, buf_size, min_buf_size;
- GError *err = NULL;
session->pending_open = NULL;
@@ -816,15 +716,8 @@ static void handle_transport_connect(struct avdtp *session, GIOChannel *io,
stream->timer = 0;
}
- if (io == NULL) {
- if (!stream->open_acp && sep->cfm && sep->cfm->open) {
- struct avdtp_error err;
- avdtp_error_init(&err, AVDTP_ERRNO, EIO);
- sep->cfm->open(session, sep, NULL, &err,
- sep->user_data);
- }
+ if (io == NULL)
return;
- }
if (stream->io == NULL)
stream->io = g_io_channel_ref(io);
@@ -832,35 +725,6 @@ static void handle_transport_connect(struct avdtp *session, GIOChannel *io,
stream->omtu = omtu;
stream->imtu = imtu;
- /* Apply special settings only if local SEP is of type SRC */
- if (sep->info.type != AVDTP_SEP_TYPE_SOURCE)
- goto proceed;
-
- bt_io_set(stream->io, &err, BT_IO_OPT_FLUSHABLE, TRUE,
- BT_IO_OPT_INVALID);
- if (err != NULL) {
- error("Enabling flushable packets failed: %s", err->message);
- g_error_free(err);
- } else
- DBG("Flushable packets enabled");
-
- sk = g_io_channel_unix_get_fd(stream->io);
- buf_size = get_send_buffer_size(sk);
- if (buf_size < 0)
- goto proceed;
-
- DBG("sk %d, omtu %d, send buffer size %d", sk, omtu, buf_size);
- min_buf_size = omtu * 2;
- if (buf_size < min_buf_size) {
- DBG("send buffer size to be increassed to %d",
- min_buf_size);
- set_send_buffer_size(sk, min_buf_size);
- }
-
-proceed:
- if (!stream->open_acp && sep->cfm && sep->cfm->open)
- sep->cfm->open(session, sep, stream, NULL, sep->user_data);
-
avdtp_sep_set_state(session, sep, AVDTP_STATE_OPEN);
stream->io_id = g_io_add_watch(io, G_IO_ERR | G_IO_HUP | G_IO_NVAL,
@@ -1071,25 +935,6 @@ static void release_stream(struct avdtp_stream *stream, struct avdtp *session)
avdtp_sep_set_state(session, sep, AVDTP_STATE_IDLE);
}
-static int avdtp_cancel_authorization(struct avdtp *session)
-{
- int err;
-
- if (session->state != AVDTP_SESSION_STATE_CONNECTING)
- return 0;
-
- if (session->auth_id == 0)
- return 0;
-
- err = btd_cancel_authorization(session->auth_id);
- if (err < 0)
- return err;
-
- session->auth_id = 0;
-
- return 0;
-}
-
static void sep_free(gpointer data)
{
struct avdtp_remote_sep *sep = data;
@@ -1098,13 +943,6 @@ static void sep_free(gpointer data)
g_free(sep);
}
-static void remove_disconnect_timer(struct avdtp *session)
-{
- g_source_remove(session->dc_timer);
- session->dc_timer = 0;
- session->stream_setup = FALSE;
-}
-
static void avdtp_free(void *data)
{
struct avdtp *session = data;
@@ -1123,9 +961,6 @@ static void avdtp_free(void *data)
session->io_id = 0;
}
- if (session->dc_timer)
- remove_disconnect_timer(session);
-
if (session->req)
pending_req_free(session->req);
@@ -1140,68 +975,19 @@ static void avdtp_free(void *data)
static void connection_lost(struct avdtp *session, int err)
{
- struct avdtp_server *server = session->server;
- char address[18];
-
- ba2str(device_get_address(session->device), address);
- DBG("Disconnected from %s", address);
-
- if (err != EACCES)
- avdtp_cancel_authorization(session);
+ DBG("Disconnected: %s (%d)", strerror(err), err);
g_slist_foreach(session->streams, (GFunc) release_stream, session);
session->streams = NULL;
finalize_discovery(session, err);
- avdtp_set_state(session, AVDTP_SESSION_STATE_DISCONNECTED);
-
if (session->ref > 0)
return;
- server->sessions = g_slist_remove(server->sessions, session);
- btd_device_unref(session->device);
avdtp_free(session);
}
-static gboolean disconnect_timeout(gpointer user_data)
-{
- struct avdtp *session = user_data;
- struct btd_service *service;
- gboolean stream_setup;
-
- session->dc_timer = 0;
-
- stream_setup = session->stream_setup;
- session->stream_setup = FALSE;
-
- service = btd_device_get_service(session->device, A2DP_SINK_UUID);
- if (service && stream_setup) {
- sink_setup_stream(service, session);
- return FALSE;
- }
-
- service = btd_device_get_service(session->device, A2DP_SOURCE_UUID);
- if (service && stream_setup) {
- source_setup_stream(service, session);
- return FALSE;
- }
-
- connection_lost(session, ETIMEDOUT);
-
- return FALSE;
-}
-
-static void set_disconnect_timer(struct avdtp *session)
-{
- if (session->dc_timer)
- remove_disconnect_timer(session);
-
- session->dc_timer = g_timeout_add_seconds(DISCONNECT_TIMEOUT,
- disconnect_timeout,
- session);
-}
-
void avdtp_unref(struct avdtp *session)
{
if (!session)
@@ -1214,24 +1000,25 @@ void avdtp_unref(struct avdtp *session)
if (session->ref > 0)
return;
- set_disconnect_timer(session);
+ finalize_discovery(session, ECONNABORTED);
+
+ avdtp_free(session);
}
struct avdtp *avdtp_ref(struct avdtp *session)
{
session->ref++;
+
DBG("%p: ref=%d", session, session->ref);
- if (session->dc_timer)
- remove_disconnect_timer(session);
+
return session;
}
-static struct avdtp_local_sep *find_local_sep_by_seid(struct avdtp_server *server,
- uint8_t seid)
+static struct avdtp_local_sep *find_local_sep_by_seid(uint8_t seid)
{
GSList *l;
- for (l = server->seps; l != NULL; l = g_slist_next(l)) {
+ for (l = lseps; l != NULL; l = g_slist_next(l)) {
struct avdtp_local_sep *sep = l->data;
if (sep->info.seid == seid)
@@ -1334,7 +1121,7 @@ static gboolean avdtp_discover_cmd(struct avdtp *session, uint8_t transaction,
struct seid_info *seps;
gboolean ret;
- sep_count = g_slist_length(session->server->seps);
+ sep_count = g_slist_length(lseps);
if (sep_count == 0) {
uint8_t err = AVDTP_NOT_SUPPORTED_COMMAND;
@@ -1346,7 +1133,7 @@ static gboolean avdtp_discover_cmd(struct avdtp *session, uint8_t transaction,
seps = g_new0(struct seid_info, sep_count);
- for (l = session->server->seps, i = 0; l != NULL; l = l->next, i++) {
+ for (l = lseps, i = 0; l != NULL; l = l->next, i++) {
struct avdtp_local_sep *sep = l->data;
memcpy(&seps[i], &sep->info, sizeof(struct seid_info));
@@ -1376,7 +1163,7 @@ static gboolean avdtp_getcap_cmd(struct avdtp *session, uint8_t transaction,
goto failed;
}
- sep = find_local_sep_by_seid(session->server, req->acp_seid);
+ sep = find_local_sep_by_seid(req->acp_seid);
if (!sep) {
err = AVDTP_BAD_ACP_SEID;
goto failed;
@@ -1445,7 +1232,6 @@ static gboolean avdtp_setconf_cmd(struct avdtp *session, uint8_t transaction,
struct avdtp_local_sep *sep;
struct avdtp_stream *stream;
uint8_t err, category = 0x00;
- struct btd_service *service;
GSList *l;
if (size < sizeof(struct setconf_req)) {
@@ -1453,7 +1239,7 @@ static gboolean avdtp_setconf_cmd(struct avdtp *session, uint8_t transaction,
return FALSE;
}
- sep = find_local_sep_by_seid(session->server, req->acp_seid);
+ sep = find_local_sep_by_seid(req->acp_seid);
if (!sep) {
err = AVDTP_BAD_ACP_SEID;
goto failed;
@@ -1464,37 +1250,6 @@ static gboolean avdtp_setconf_cmd(struct avdtp *session, uint8_t transaction,
goto failed;
}
- switch (sep->info.type) {
- case AVDTP_SEP_TYPE_SOURCE:
- service = btd_device_get_service(session->device,
- A2DP_SINK_UUID);
- if (service == NULL) {
- btd_device_add_uuid(session->device, A2DP_SINK_UUID);
- service = btd_device_get_service(session->device,
- A2DP_SINK_UUID);
- if (service == NULL) {
- error("Unable to get a audio sink object");
- err = AVDTP_BAD_STATE;
- goto failed;
- }
- }
- break;
- case AVDTP_SEP_TYPE_SINK:
- service = btd_device_get_service(session->device,
- A2DP_SOURCE_UUID);
- if (service == NULL) {
- btd_device_add_uuid(session->device, A2DP_SOURCE_UUID);
- service = btd_device_get_service(session->device,
- A2DP_SOURCE_UUID);
- if (service == NULL) {
- error("Unable to get a audio source object");
- err = AVDTP_BAD_STATE;
- goto failed;
- }
- }
- break;
- }
-
stream = g_new0(struct avdtp_stream, 1);
stream->session = session;
stream->lsep = sep;
@@ -1568,7 +1323,7 @@ static gboolean avdtp_getconf_cmd(struct avdtp *session, uint8_t transaction,
memset(buf, 0, sizeof(buf));
- sep = find_local_sep_by_seid(session->server, req->acp_seid);
+ sep = find_local_sep_by_seid(req->acp_seid);
if (!sep) {
err = AVDTP_BAD_ACP_SEID;
goto failed;
@@ -1684,7 +1439,7 @@ static gboolean avdtp_open_cmd(struct avdtp *session, uint8_t transaction,
return FALSE;
}
- sep = find_local_sep_by_seid(session->server, req->acp_seid);
+ sep = find_local_sep_by_seid(req->acp_seid);
if (!sep) {
err = AVDTP_BAD_ACP_SEID;
goto failed;
@@ -1744,8 +1499,7 @@ static gboolean avdtp_start_cmd(struct avdtp *session, uint8_t transaction,
for (i = 0; i < seid_count; i++, seid++) {
failed_seid = seid->seid;
- sep = find_local_sep_by_seid(session->server,
- req->first_seid.seid);
+ sep = find_local_sep_by_seid(req->first_seid.seid);
if (!sep || !sep->stream) {
err = AVDTP_BAD_ACP_SEID;
goto failed;
@@ -1795,7 +1549,7 @@ static gboolean avdtp_close_cmd(struct avdtp *session, uint8_t transaction,
return FALSE;
}
- sep = find_local_sep_by_seid(session->server, req->acp_seid);
+ sep = find_local_sep_by_seid(req->acp_seid);
if (!sep || !sep->stream) {
err = AVDTP_BAD_ACP_SEID;
goto failed;
@@ -1856,8 +1610,7 @@ static gboolean avdtp_suspend_cmd(struct avdtp *session, uint8_t transaction,
for (i = 0; i < seid_count; i++, seid++) {
failed_seid = seid->seid;
- sep = find_local_sep_by_seid(session->server,
- req->first_seid.seid);
+ sep = find_local_sep_by_seid(req->first_seid.seid);
if (!sep || !sep->stream) {
err = AVDTP_BAD_ACP_SEID;
goto failed;
@@ -1904,7 +1657,7 @@ static gboolean avdtp_abort_cmd(struct avdtp *session, uint8_t transaction,
return FALSE;
}
- sep = find_local_sep_by_seid(session->server, req->acp_seid);
+ sep = find_local_sep_by_seid(req->acp_seid);
if (!sep || !sep->stream)
return TRUE;
@@ -1942,7 +1695,7 @@ static gboolean avdtp_delayreport_cmd(struct avdtp *session,
return FALSE;
}
- sep = find_local_sep_by_seid(session->server, req->acp_seid);
+ sep = find_local_sep_by_seid(req->acp_seid);
if (!sep || !sep->stream) {
err = AVDTP_BAD_ACP_SEID;
goto failed;
@@ -2265,281 +2018,30 @@ failed:
return FALSE;
}
-static struct avdtp *find_session(GSList *list, struct btd_device *device)
-{
- for (; list != NULL; list = g_slist_next(list)) {
- struct avdtp *s = list->data;
-
- if (s->device == device)
- return s;
- }
-
- return NULL;
-}
-
-static uint16_t get_version(struct avdtp *session)
+struct avdtp *avdtp_new(int fd, size_t imtu, size_t omtu, uint16_t version)
{
- const sdp_record_t *rec;
- sdp_list_t *protos;
- sdp_data_t *proto_desc;
- uint16_t ver = 0x0100;
-
- rec = btd_device_get_record(session->device, A2DP_SINK_UUID);
- if (!rec)
- rec = btd_device_get_record(session->device, A2DP_SOURCE_UUID);
-
- if (!rec)
- return ver;
-
- if (sdp_get_access_protos(rec, &protos) < 0)
- return ver;
-
- proto_desc = sdp_get_proto_desc(protos, AVDTP_UUID);
- if (proto_desc && proto_desc->dtd == SDP_UINT16)
- ver = proto_desc->val.uint16;
-
- sdp_list_foreach(protos, (sdp_list_func_t) sdp_list_free, NULL);
- sdp_list_free(protos, NULL);
-
- return ver;
-}
-
-static struct avdtp *avdtp_get_internal(struct btd_device *device)
-{
- struct avdtp_server *server;
struct avdtp *session;
-
- server = find_server(servers, device_get_adapter(device));
- if (server == NULL)
- return NULL;
-
- session = find_session(server->sessions, device);
- if (session)
- return session;
+ GIOCondition cond = G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL;
session = g_new0(struct avdtp, 1);
-
- session->server = server;
- session->device = btd_device_ref(device);
- /* We don't use avdtp_set_state() here since this isn't a state change
- * but just setting of the initial state */
- session->state = AVDTP_SESSION_STATE_DISCONNECTED;
-
- session->version = get_version(session);
-
- server->sessions = g_slist_append(server->sessions, session);
-
- return session;
-}
-
-struct avdtp *avdtp_get(struct btd_device *device)
-{
- struct avdtp *session;
-
- session = avdtp_get_internal(device);
-
- if (!session)
- return NULL;
-
- return avdtp_ref(session);
-}
-
-static void avdtp_connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
-{
- struct avdtp *session = user_data;
- char address[18];
- int err_no = EIO;
-
- if (err) {
- err_no = err->code;
- error("%s", err->message);
- goto failed;
- }
-
- if (!session->io)
- session->io = g_io_channel_ref(chan);
-
- bt_io_get(chan, &err,
- BT_IO_OPT_OMTU, &session->omtu,
- BT_IO_OPT_IMTU, &session->imtu,
- BT_IO_OPT_INVALID);
- if (err) {
- err_no = err->code;
- error("%s", err->message);
- goto failed;
- }
-
- ba2str(device_get_address(session->device), address);
- DBG("AVDTP: connected %s channel to %s",
- session->pending_open ? "transport" : "signaling",
- address);
-
- if (session->state == AVDTP_SESSION_STATE_CONNECTING) {
- DBG("AVDTP imtu=%u, omtu=%u", session->imtu, session->omtu);
-
- session->buf = g_malloc0(MAX(session->imtu, session->omtu));
- avdtp_set_state(session, AVDTP_SESSION_STATE_CONNECTED);
-
- if (session->io_id)
- g_source_remove(session->io_id);
-
- /* This watch should be low priority since otherwise the
- * connect callback might be dispatched before the session
- * callback if the kernel wakes us up at the same time for
- * them. This could happen if a headset is very quick in
- * sending the Start command after connecting the stream
- * transport channel.
- */
- session->io_id = g_io_add_watch_full(chan,
- G_PRIORITY_LOW,
- G_IO_IN | G_IO_ERR | G_IO_HUP
- | G_IO_NVAL,
+ session->io = g_io_channel_unix_new(fd);
+ session->version = version;
+ session->imtu = imtu;
+ session->omtu = omtu;
+ session->buf = g_malloc0(MAX(session->imtu, session->omtu));
+
+ /* This watch should be low priority since otherwise the
+ * connect callback might be dispatched before the session
+ * callback if the kernel wakes us up at the same time for
+ * them. This could happen if a headset is very quick in
+ * sending the Start command after connecting the stream
+ * transport channel.
+ */
+ session->io_id = g_io_add_watch_full(session->io, G_PRIORITY_LOW, cond,
(GIOFunc) session_cb, session,
NULL);
- if (session->stream_setup)
- set_disconnect_timer(session);
- } else if (session->pending_open)
- handle_transport_connect(session, chan, session->imtu,
- session->omtu);
- else
- goto failed;
-
- process_queue(session);
-
- return;
-
-failed:
- if (session->pending_open) {
- struct avdtp_stream *stream = session->pending_open;
-
- handle_transport_connect(session, NULL, 0, 0);
-
- if (avdtp_abort(session, stream) < 0)
- avdtp_sep_set_state(session, stream->lsep,
- AVDTP_STATE_IDLE);
- } else
- connection_lost(session, err_no);
-}
-
-static void auth_cb(DBusError *derr, void *user_data)
-{
- struct avdtp *session = user_data;
- GError *err = NULL;
-
- if (derr && dbus_error_is_set(derr)) {
- error("Access denied: %s", derr->message);
- connection_lost(session, EACCES);
- return;
- }
-
- if (!bt_io_accept(session->io, avdtp_connect_cb, session, NULL,
- &err)) {
- error("bt_io_accept: %s", err->message);
- connection_lost(session, EACCES);
- g_error_free(err);
- return;
- }
-
- /* This is so that avdtp_connect_cb will know to do the right thing
- * with respect to the disconnect timer */
- session->stream_setup = TRUE;
-}
-
-static void avdtp_confirm_cb(GIOChannel *chan, gpointer data)
-{
- struct avdtp *session;
- char address[18];
- bdaddr_t src, dst;
- GError *err = NULL;
- struct btd_device *device;
-
- bt_io_get(chan, &err,
- BT_IO_OPT_SOURCE_BDADDR, &src,
- BT_IO_OPT_DEST_BDADDR, &dst,
- BT_IO_OPT_DEST, address,
- BT_IO_OPT_INVALID);
- if (err) {
- error("%s", err->message);
- g_error_free(err);
- goto drop;
- }
-
- DBG("AVDTP: incoming connect from %s", address);
-
- device = adapter_find_device(adapter_find(&src), &dst);
- if (!device)
- goto drop;
-
- session = avdtp_get_internal(device);
- if (!session)
- goto drop;
-
- /* This state (ie, session is already *connecting*) happens when the
- * device initiates a connect (really a config'd L2CAP channel) even
- * though there is a connect we initiated in progress. In sink.c &
- * source.c, this state is referred to as XCASE connect:connect.
- * Abort the device's channel in favor of our own.
- */
- if (session->state == AVDTP_SESSION_STATE_CONNECTING) {
- DBG("connect already in progress (XCASE connect:connect)");
- goto drop;
- }
-
- if (session->pending_open && session->pending_open->open_acp) {
- if (!bt_io_accept(chan, avdtp_connect_cb, session, NULL, NULL))
- goto drop;
- return;
- }
-
- if (session->io) {
- error("Refusing unexpected connect from %s", address);
- goto drop;
- }
-
- btd_device_add_uuid(device, ADVANCED_AUDIO_UUID);
-
- session->io = g_io_channel_ref(chan);
- avdtp_set_state(session, AVDTP_SESSION_STATE_CONNECTING);
-
- session->io_id = g_io_add_watch(chan, G_IO_ERR | G_IO_HUP | G_IO_NVAL,
- (GIOFunc) session_cb, session);
-
- session->auth_id = btd_request_authorization(&src, &dst,
- ADVANCED_AUDIO_UUID,
- auth_cb, session);
- if (session->auth_id == 0) {
- avdtp_set_state(session, AVDTP_SESSION_STATE_DISCONNECTED);
- goto drop;
- }
-
- return;
-
-drop:
- g_io_channel_shutdown(chan, TRUE, NULL);
-}
-
-static GIOChannel *l2cap_connect(struct avdtp *session)
-{
- GError *err = NULL;
- GIOChannel *io;
-
- io = bt_io_connect(avdtp_connect_cb, session,
- NULL, &err,
- BT_IO_OPT_SOURCE_BDADDR,
- adapter_get_address(session->server->adapter),
- BT_IO_OPT_DEST_BDADDR,
- device_get_address(session->device),
- BT_IO_OPT_PSM, AVDTP_PSM,
- BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM,
- BT_IO_OPT_INVALID);
- if (!io) {
- error("%s", err->message);
- g_error_free(err);
- return NULL;
- }
-
- return io;
+ return avdtp_ref(session);
}
static void queue_request(struct avdtp *session, struct pending_req *req,
@@ -2676,17 +2178,7 @@ static int send_req(struct avdtp *session, gboolean priority,
static int transaction = 0;
int err;
- if (session->state == AVDTP_SESSION_STATE_DISCONNECTED) {
- session->io = l2cap_connect(session);
- if (!session->io) {
- err = -EIO;
- goto failed;
- }
- avdtp_set_state(session, AVDTP_SESSION_STATE_CONNECTING);
- }
-
- if (session->state < AVDTP_SESSION_STATE_CONNECTED ||
- session->req != NULL) {
+ if (session->req != NULL) {
queue_request(session, req, priority);
return 0;
}
@@ -2859,14 +2351,11 @@ static gboolean avdtp_open_resp(struct avdtp *session, struct avdtp_stream *stre
{
struct avdtp_local_sep *sep = stream->lsep;
- stream->io = l2cap_connect(session);
- if (!stream->io) {
- avdtp_sep_set_state(session, sep, AVDTP_STATE_IDLE);
- return FALSE;
- }
-
session->pending_open = stream;
+ if (!stream->open_acp && sep->cfm && sep->cfm->open)
+ sep->cfm->open(session, sep, stream, NULL, sep->user_data);
+
return TRUE;
}
@@ -2876,14 +2365,14 @@ static gboolean avdtp_start_resp(struct avdtp *session,
{
struct avdtp_local_sep *sep = stream->lsep;
- if (sep->cfm && sep->cfm->start)
- sep->cfm->start(session, sep, stream, NULL, sep->user_data);
-
/* We might be in STREAMING already if both sides send START_CMD at the
* same time and the one in SNK role doesn't reject it as it should */
if (sep->state != AVDTP_STATE_STREAMING)
avdtp_sep_set_state(session, sep, AVDTP_STATE_STREAMING);
+ if (sep->cfm && sep->cfm->start)
+ sep->cfm->start(session, sep, stream, NULL, sep->user_data);
+
return TRUE;
}
@@ -3223,6 +2712,24 @@ struct avdtp_remote_sep *avdtp_stream_get_remote_sep(
return NULL;
}
+gboolean avdtp_stream_set_transport(struct avdtp_stream *stream, int fd,
+ size_t imtu, size_t omtu)
+{
+ GIOChannel *io;
+
+ if (stream != stream->session->pending_open)
+ return FALSE;
+
+ io = g_io_channel_unix_new(fd);
+
+ handle_transport_connect(stream->session, io, imtu, omtu);
+
+ g_io_channel_unref(io);
+
+ return TRUE;
+
+}
+
gboolean avdtp_stream_get_transport(struct avdtp_stream *stream, int *sock,
uint16_t *imtu, uint16_t *omtu,
GSList **caps)
@@ -3375,9 +2882,6 @@ int avdtp_get_configuration(struct avdtp *session, struct avdtp_stream *stream)
{
struct seid_req req;
- if (session->state < AVDTP_SESSION_STATE_CONNECTED)
- return -EINVAL;
-
memset(&req, 0, sizeof(req));
req.acp_seid = stream->rseid;
@@ -3410,9 +2914,6 @@ int avdtp_set_configuration(struct avdtp *session,
struct avdtp_service_capability *cap;
GSList *l;
- if (session->state != AVDTP_SESSION_STATE_CONNECTED)
- return -ENOTCONN;
-
if (!(lsep && rsep))
return -EINVAL;
@@ -3610,7 +3111,8 @@ int avdtp_abort(struct avdtp *session, struct avdtp_stream *stream)
if (stream->lsep->state == AVDTP_STATE_ABORTING)
return -EINVAL;
- if (session->req && stream == session->req->stream)
+ if (session->req && session->req->timeout > 0 &&
+ stream == session->req->stream)
return cancel_request(session, ECANCELED);
memset(&req, 0, sizeof(req));
@@ -3649,108 +3151,43 @@ int avdtp_delay_report(struct avdtp *session, struct avdtp_stream *stream,
&req, sizeof(req));
}
-static GIOChannel *avdtp_server_socket(const bdaddr_t *src, gboolean master)
-{
- GError *err = NULL;
- GIOChannel *io;
-
- io = bt_io_listen(NULL, avdtp_confirm_cb,
- NULL, NULL, &err,
- BT_IO_OPT_SOURCE_BDADDR, src,
- BT_IO_OPT_PSM, AVDTP_PSM,
- BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM,
- BT_IO_OPT_MASTER, master,
- BT_IO_OPT_INVALID);
- if (!io) {
- error("%s", err->message);
- g_error_free(err);
- }
-
- return io;
-}
-
-static struct avdtp_server *avdtp_server_init(struct btd_adapter *adapter)
-{
- struct avdtp_server *server;
-
- server = g_new0(struct avdtp_server, 1);
-
- server->io = avdtp_server_socket(adapter_get_address(adapter), TRUE);
- if (!server->io) {
- g_free(server);
- return NULL;
- }
-
- server->adapter = btd_adapter_ref(adapter);
-
- servers = g_slist_append(servers, server);
-
- return server;
-}
-
-struct avdtp_local_sep *avdtp_register_sep(struct btd_adapter *adapter,
- uint8_t type,
- uint8_t media_type,
+struct avdtp_local_sep *avdtp_register_sep(uint8_t type, uint8_t media_type,
uint8_t codec_type,
gboolean delay_reporting,
struct avdtp_sep_ind *ind,
struct avdtp_sep_cfm *cfm,
void *user_data)
{
- struct avdtp_server *server;
struct avdtp_local_sep *sep;
- server = find_server(servers, adapter);
- if (!server) {
- server = avdtp_server_init(adapter);
- if (!server)
- return NULL;
- }
-
- if (g_slist_length(server->seps) > MAX_SEID)
+ if (g_slist_length(lseps) > MAX_SEID)
return NULL;
sep = g_new0(struct avdtp_local_sep, 1);
sep->state = AVDTP_STATE_IDLE;
- sep->info.seid = g_slist_length(server->seps) + 1;
+ sep->info.seid = g_slist_length(lseps) + 1;
sep->info.type = type;
sep->info.media_type = media_type;
sep->codec = codec_type;
sep->ind = ind;
sep->cfm = cfm;
sep->user_data = user_data;
- sep->server = server;
sep->delay_reporting = TRUE;
DBG("SEP %p registered: type:%d codec:%d seid:%d", sep,
sep->info.type, sep->codec, sep->info.seid);
- server->seps = g_slist_append(server->seps, sep);
+ lseps = g_slist_append(lseps, sep);
return sep;
}
-static void avdtp_server_destroy(struct avdtp_server *server)
-{
- g_slist_free_full(server->sessions, avdtp_free);
-
- servers = g_slist_remove(servers, server);
-
- g_io_channel_shutdown(server->io, TRUE, NULL);
- g_io_channel_unref(server->io);
- btd_adapter_unref(server->adapter);
- g_free(server);
-}
-
int avdtp_unregister_sep(struct avdtp_local_sep *sep)
{
- struct avdtp_server *server;
-
if (!sep)
return -EINVAL;
- server = sep->server;
- server->seps = g_slist_remove(server->seps, sep);
+ lseps = g_slist_remove(lseps, sep);
if (sep->stream)
release_stream(sep->stream, sep->stream->session);
@@ -3760,11 +3197,6 @@ int avdtp_unregister_sep(struct avdtp_local_sep *sep)
g_free(sep);
- if (server->seps)
- return 0;
-
- avdtp_server_destroy(server);
-
return 0;
}
@@ -3818,50 +3250,7 @@ avdtp_state_t avdtp_sep_get_state(struct avdtp_local_sep *sep)
return sep->state;
}
-struct btd_adapter *avdtp_get_adapter(struct avdtp *session)
-{
- return session->server->adapter;
-}
-
-struct btd_device *avdtp_get_device(struct avdtp *session)
-{
- return session->device;
-}
-
gboolean avdtp_has_stream(struct avdtp *session, struct avdtp_stream *stream)
{
return g_slist_find(session->streams, stream) ? TRUE : FALSE;
}
-
-unsigned int avdtp_add_state_cb(struct btd_device *dev,
- avdtp_session_state_cb cb, void *user_data)
-{
- struct avdtp_state_callback *state_cb;
- static unsigned int id = 0;
-
- state_cb = g_new(struct avdtp_state_callback, 1);
- state_cb->cb = cb;
- state_cb->dev = dev;
- state_cb->id = ++id;
- state_cb->user_data = user_data;
-
- state_callbacks = g_slist_append(state_callbacks, state_cb);
-
- return state_cb->id;
-}
-
-gboolean avdtp_remove_state_cb(unsigned int id)
-{
- GSList *l;
-
- for (l = state_callbacks; l != NULL; l = l->next) {
- struct avdtp_state_callback *cb = l->data;
- if (cb && cb->id == id) {
- state_callbacks = g_slist_remove(state_callbacks, cb);
- g_free(cb);
- return TRUE;
- }
- }
-
- return FALSE;
-}
diff --git a/android/avdtp.h b/android/avdtp.h
index 390c154..9760875 100644
--- a/android/avdtp.h
+++ b/android/avdtp.h
@@ -22,12 +22,6 @@
*
*/
-typedef enum {
- AVDTP_SESSION_STATE_DISCONNECTED,
- AVDTP_SESSION_STATE_CONNECTING,
- AVDTP_SESSION_STATE_CONNECTED
-} avdtp_session_state_t;
-
struct avdtp;
struct avdtp_stream;
struct avdtp_local_sep;
@@ -116,12 +110,6 @@ struct avdtp_media_codec_capability {
#error "Unknown byte order"
#endif
-typedef void (*avdtp_session_state_cb) (struct btd_device *dev,
- struct avdtp *session,
- avdtp_session_state_t old_state,
- avdtp_session_state_t new_state,
- void *user_data);
-
typedef void (*avdtp_stream_state_cb) (struct avdtp_stream *stream,
avdtp_state_t old_state,
avdtp_state_t new_state,
@@ -213,7 +201,7 @@ struct avdtp_sep_ind {
typedef void (*avdtp_discover_cb_t) (struct avdtp *session, GSList *seps,
struct avdtp_error *err, void *user_data);
-struct avdtp *avdtp_get(struct btd_device *device);
+struct avdtp *avdtp_new(int fd, size_t imtu, size_t omtu, uint16_t version);
void avdtp_unref(struct avdtp *session);
struct avdtp *avdtp_ref(struct avdtp *session);
@@ -235,6 +223,8 @@ gboolean avdtp_stream_remove_cb(struct avdtp *session,
struct avdtp_stream *stream,
unsigned int id);
+gboolean avdtp_stream_set_transport(struct avdtp_stream *stream, int fd,
+ size_t imtu, size_t omtu);
gboolean avdtp_stream_get_transport(struct avdtp_stream *stream, int *sock,
uint16_t *imtu, uint16_t *omtu,
GSList **caps);
@@ -245,11 +235,6 @@ gboolean avdtp_stream_has_capabilities(struct avdtp_stream *stream,
struct avdtp_remote_sep *avdtp_stream_get_remote_sep(
struct avdtp_stream *stream);
-unsigned int avdtp_add_state_cb(struct btd_device *dev,
- avdtp_session_state_cb cb, void *user_data);
-
-gboolean avdtp_remove_state_cb(unsigned int id);
-
int avdtp_set_configuration(struct avdtp *session,
struct avdtp_remote_sep *rsep,
struct avdtp_local_sep *lsep,
@@ -268,9 +253,7 @@ int avdtp_abort(struct avdtp *session, struct avdtp_stream *stream);
int avdtp_delay_report(struct avdtp *session, struct avdtp_stream *stream,
uint16_t delay);
-struct avdtp_local_sep *avdtp_register_sep(struct btd_adapter *adapter,
- uint8_t type,
- uint8_t media_type,
+struct avdtp_local_sep *avdtp_register_sep(uint8_t type, uint8_t media_type,
uint8_t codec_type,
gboolean delay_reporting,
struct avdtp_sep_ind *ind,
@@ -290,6 +273,3 @@ const char *avdtp_strerror(struct avdtp_error *err);
uint8_t avdtp_error_category(struct avdtp_error *err);
int avdtp_error_error_code(struct avdtp_error *err);
int avdtp_error_posix_errno(struct avdtp_error *err);
-
-struct btd_adapter *avdtp_get_adapter(struct avdtp *session);
-struct btd_device *avdtp_get_device(struct avdtp *session);
--
1.8.3.1
^ permalink raw reply related
* [PATCH v2 00/20] Initial AVDTP for Android
From: Luiz Augusto von Dentz @ 2013-11-25 14:54 UTC (permalink / raw)
To: linux-bluetooth
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
The code is based on the current implementation available in
profiles/audio/avdtp.{c,h} but it is transport agnostic and does not
contain any external dependency except glib for IO handling.
Both the signaling and the transport connection has to be handled by
the upper layer, that is why it is not modified in place to avoid
breaking current implemention until this work is considered stable.
Two new function are added:
- avdtp_new: Creates AVDTP session and attach signaling transport
- avdtp_stream_set_transport: Set stream transport
Both receives a fd as parameter so in future it should be possible to
replace the IO handling.
This set also includes a initial test set based on the current AVDTP
test specification, once merged more tests will be added as well,
then the intent is to make this used by audio plugin.
Note: It is possible to track back to the original code by doing:
git log --follow or git blame -C -C.
v2: Add a separate commit to copy existing AVDTP files
Luiz Augusto von Dentz (20):
android: Add copy of current AVDTP implemention
android/AVDTP: Strip dependencies
unit/AVDTP: Add /TP/SIG/SMG/BV-05-C test
unit/AVDTP: Add /TP/SIG/SMG/BV-06-C test
unit/AVDTP: Add /TP/SIG/SMG/BV-07-C test
unit/AVDTP: Add /TP/SIG/SMG/BV-08-C test
unit/AVDTP: Add /TP/SIG/SMG/BV-09-C test
unit/AVDTP: Add /TP/SIG/SMG/BV-10-C test
unit/AVDTP: Add /TP/SIG/SMG/BV-11-C test
unit/AVDTP: Add /TP/SIG/SMG/BV-12-C test
unit/AVDTP: Add /TP/SIG/SMG/BV-15-C test
unit/AVDTP: Add /TP/SIG/SMG/BV-16-C test
unit/AVDTP: Add /TP/SIG/SMG/BV-17-C test
unit/AVDTP: Add /TP/SIG/SMG/BV-18-C test
unit/AVDTP: Add /TP/SIG/SMG/BV-19-C test
unit/AVDTP: Add /TP/SIG/SMG/BV-20-C test
unit/AVDTP: Add /TP/SIG/SMG/BV-21-C test
unit/AVDTP: Add /TP/SIG/SMG/BV-22-C test
unit/AVDTP: Add /TP/SIG/SMG/BV-23-C test
unit/AVDTP: Add /TP/SIG/SMG/BV-24-C test
Makefile.am | 8 +
android/Makefile.am | 1 +
android/a2dp.c | 23 +
android/avdtp.c | 3256 +++++++++++++++++++++++++++++++++++++++++++++++++++
android/avdtp.h | 275 +++++
unit/test-avdtp.c | 612 ++++++++++
6 files changed, 4175 insertions(+)
create mode 100644 android/avdtp.c
create mode 100644 android/avdtp.h
create mode 100644 unit/test-avdtp.c
--
1.8.3.1
^ permalink raw reply
* Re: [PATCH 1/4] android: Add CAP_NET_RAW capability
From: Johan Hedberg @ 2013-11-25 14:25 UTC (permalink / raw)
To: Ravi kumar Veeramally; +Cc: linux-bluetooth
In-Reply-To: <52935B51.403@linux.intel.com>
Hi Ravi,
On Mon, Nov 25, 2013, Ravi kumar Veeramally wrote:
> On 25.11.2013 16:01, Johan Hedberg wrote:
> >Hi Ravi,
> >
> >On Mon, Nov 25, 2013, Ravi kumar Veeramally wrote:
> >>CAP_NET_RAW capability is required to up the bnep interfaces
> >>in android environment.
> >>---
> >> android/main.c | 1 +
> >> 1 file changed, 1 insertion(+)
> >>
> >>diff --git a/android/main.c b/android/main.c
> >>index c9733f3..bfd2a87 100644
> >>--- a/android/main.c
> >>+++ b/android/main.c
> >>@@ -506,6 +506,7 @@ static bool set_capabilities(void)
> >> header.pid = 0;
> >> cap.effective = cap.permitted =
> >>+ CAP_TO_MASK(CAP_NET_RAW) |
> >> CAP_TO_MASK(CAP_NET_ADMIN) |
> >> CAP_TO_MASK(CAP_NET_BIND_SERVICE);
> >> cap.inheritable = 0;
> >Would you then say that commit 9bda7e8c2130de9a3340ebd0e6cc1dedc2eae338
> >is incorrect? A quick grep doesn't show any instances of checking this
> >capability in the BNEP code of the kernel. Exactly which system call is
> >it that needs it?
> bnep_if_up from profiles/network/common.c
> ---
> ifr.ifr_flags |= IFF_UP;
> ifr.ifr_flags |= IFF_MULTICAST;
>
> err = ioctl(sk, SIOCSIFFLAGS, (caddr_t) &ifr);
> ---
> requires this capability in android environment only.
> this code is under android macro.
So you've verified that under "normal" Linux this ioctl does not require
the NET_RAW capability?
> >If you answered positively to my first question, please send a patch for
> >that as well.
> I didn't understand this, sorry.
My first question was: "Would you then say that
commit 9bda7e8c2130de9a3340ebd0e6cc1dedc2eae338 is incorrect?". Do you
not understand that question or what I asked you to do in case the
answer is "yes"?
Johan
^ permalink raw reply
* Re: [PATCH 1/4] android: Add CAP_NET_RAW capability
From: Ravi kumar Veeramally @ 2013-11-25 14:14 UTC (permalink / raw)
To: linux-bluetooth, johan.hedberg
In-Reply-To: <20131125140154.GA24659@x220.p-661hnu-f1>
Hi Johan,
On 25.11.2013 16:01, Johan Hedberg wrote:
> Hi Ravi,
>
> On Mon, Nov 25, 2013, Ravi kumar Veeramally wrote:
>> CAP_NET_RAW capability is required to up the bnep interfaces
>> in android environment.
>> ---
>> android/main.c | 1 +
>> 1 file changed, 1 insertion(+)
>>
>> diff --git a/android/main.c b/android/main.c
>> index c9733f3..bfd2a87 100644
>> --- a/android/main.c
>> +++ b/android/main.c
>> @@ -506,6 +506,7 @@ static bool set_capabilities(void)
>> header.pid = 0;
>>
>> cap.effective = cap.permitted =
>> + CAP_TO_MASK(CAP_NET_RAW) |
>> CAP_TO_MASK(CAP_NET_ADMIN) |
>> CAP_TO_MASK(CAP_NET_BIND_SERVICE);
>> cap.inheritable = 0;
> Would you then say that commit 9bda7e8c2130de9a3340ebd0e6cc1dedc2eae338
> is incorrect? A quick grep doesn't show any instances of checking this
> capability in the BNEP code of the kernel. Exactly which system call is
> it that needs it?
bnep_if_up from profiles/network/common.c
---
ifr.ifr_flags |= IFF_UP;
ifr.ifr_flags |= IFF_MULTICAST;
err = ioctl(sk, SIOCSIFFLAGS, (caddr_t) &ifr);
---
requires this capability in android environment only.
this code is under android macro.
> If you answered positively to my first question, please send a patch for
> that as well.
I didn't understand this, sorry.
Thanks,
Ravi.
^ permalink raw reply
* [PATCHv10 4/4] android/socket: Check create_rfsock returns valid structure
From: Andrei Emeltchenko @ 2013-11-25 14:10 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1385388625-3156-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>
From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
android/socket.c | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/android/socket.c b/android/socket.c
index 0817b5c..66b240d 100644
--- a/android/socket.c
+++ b/android/socket.c
@@ -647,6 +647,12 @@ static void accept_cb(GIOChannel *io, GError *err, gpointer user_data)
sock_acc = g_io_channel_unix_get_fd(io);
rfsock_acc = create_rfsock(sock_acc, &hal_fd);
+ if (!rfsock_acc) {
+ g_io_channel_shutdown(io, TRUE, NULL);
+ g_io_channel_unref(io);
+ return;
+ }
+
connections = g_list_append(connections, rfsock_acc);
DBG("rfsock: fd %d real_sock %d chan %u sock %d",
@@ -905,8 +911,11 @@ static int handle_connect(void *buf)
DBG("");
- android2bdaddr(cmd->bdaddr, &dst);
rfsock = create_rfsock(-1, &hal_fd);
+ if (!rfsock)
+ return -1;
+
+ android2bdaddr(cmd->bdaddr, &dst);
bacpy(&rfsock->dst, &dst);
memset(&uuid, 0, sizeof(uuid));
--
1.8.3.2
^ permalink raw reply related
* [PATCHv10 3/4] android/socket: Handle Android events for server socket
From: Andrei Emeltchenko @ 2013-11-25 14:10 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1385388625-3156-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>
From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
Add watch for tracking events from Android framework for server socket.
---
android/socket.c | 27 ++++++++++++++++++++++++++-
1 file changed, 26 insertions(+), 1 deletion(-)
diff --git a/android/socket.c b/android/socket.c
index 447e0f1..0817b5c 100644
--- a/android/socket.c
+++ b/android/socket.c
@@ -596,6 +596,24 @@ static bool sock_send_accept(struct rfcomm_sock *rfsock, bdaddr_t *bdaddr,
return true;
}
+static gboolean sock_server_stack_event_cb(GIOChannel *io, GIOCondition cond,
+ gpointer data)
+{
+ struct rfcomm_sock *rfsock = data;
+
+ DBG("");
+
+ if (cond & (G_IO_ERR | G_IO_HUP | G_IO_NVAL)) {
+ error("Socket error: sock %d cond %d",
+ g_io_channel_unix_get_fd(io), cond);
+ cleanup_rfsock(rfsock);
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
static void accept_cb(GIOChannel *io, GError *err, gpointer user_data)
{
struct rfcomm_sock *rfsock = user_data;
@@ -665,7 +683,8 @@ static int handle_listen(void *buf)
struct profile_info *profile;
struct rfcomm_sock *rfsock;
BtIOSecLevel sec_level;
- GIOChannel *io;
+ GIOChannel *io, *io_stack;
+ GIOCondition cond;
GError *err = NULL;
int hal_fd;
int chan;
@@ -708,6 +727,12 @@ static int handle_listen(void *buf)
rfsock->srv_io = io;
+ /* Handle events from Android */
+ cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+ io_stack = g_io_channel_unix_new(rfsock->fd);
+ g_io_add_watch(io_stack, cond, sock_server_stack_event_cb, rfsock);
+ g_io_channel_unref(io_stack);
+
DBG("real_sock %d fd %d hal_fd %d", rfsock->real_sock, rfsock->fd,
hal_fd);
--
1.8.3.2
^ permalink raw reply related
* [PATCHv10 2/4] android/socket: Keep server iochannel reference
From: Andrei Emeltchenko @ 2013-11-25 14:10 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1385388625-3156-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>
From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
server io channel reference will be stored in rfsock structure
and might be deleted when Android end closes connection or when
HAL makes cleanup() call.
---
android/socket.c | 11 ++++++++---
1 file changed, 8 insertions(+), 3 deletions(-)
diff --git a/android/socket.c b/android/socket.c
index e31e391..447e0f1 100644
--- a/android/socket.c
+++ b/android/socket.c
@@ -70,6 +70,8 @@ struct rfcomm_sock {
guint rfcomm_watch;
guint stack_watch;
+ GIOChannel *srv_io;
+
bdaddr_t dst;
uint32_t service_handle;
@@ -121,6 +123,11 @@ static void cleanup_rfsock(struct rfcomm_sock *rfsock)
if (rfsock->service_handle)
bt_adapter_remove_record(rfsock->service_handle);
+ if (rfsock->srv_io) {
+ g_io_channel_shutdown(rfsock->srv_io, TRUE, NULL);
+ g_io_channel_unref(rfsock->srv_io);
+ }
+
g_free(rfsock);
}
@@ -699,9 +706,7 @@ static int handle_listen(void *buf)
rfsock->real_sock = g_io_channel_unix_get_fd(io);
servers = g_list_append(servers, rfsock);
- /* TODO: Add server watch */
- g_io_channel_set_close_on_unref(io, TRUE);
- g_io_channel_unref(io);
+ rfsock->srv_io = io;
DBG("real_sock %d fd %d hal_fd %d", rfsock->real_sock, rfsock->fd,
hal_fd);
--
1.8.3.2
^ permalink raw reply related
* [PATCHv10 1/4] android/socket: Use security level for connect / listen
From: Andrei Emeltchenko @ 2013-11-25 14:10 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <20131125134005.GB19445@x220.p-661hnu-f1>
From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
Use MEDIUM security level for connections without profile and default
sec_level for others. rfsock now has pointer to profile info.
---
android/socket.c | 14 ++++++++++++--
1 file changed, 12 insertions(+), 2 deletions(-)
diff --git a/android/socket.c b/android/socket.c
index 83e6996..e31e391 100644
--- a/android/socket.c
+++ b/android/socket.c
@@ -60,6 +60,8 @@ GList *servers = NULL;
/* Simple list of RFCOMM connected sockets */
GList *connections = NULL;
+struct profile_info;
+
struct rfcomm_sock {
int fd; /* descriptor for communication with Java framework */
int real_sock; /* real RFCOMM socket */
@@ -70,6 +72,8 @@ struct rfcomm_sock {
bdaddr_t dst;
uint32_t service_handle;
+
+ struct profile_info *profile;
};
static struct rfcomm_sock *create_rfsock(int sock, int *hal_fd)
@@ -667,7 +671,7 @@ static int handle_listen(void *buf)
return -1;
else {
chan = cmd->channel;
- sec_level = BT_IO_SEC_LOW;
+ sec_level = BT_IO_SEC_MEDIUM;
}
} else {
chan = profile->channel;
@@ -786,6 +790,7 @@ fail:
static void sdp_search_cb(sdp_list_t *recs, int err, gpointer data)
{
struct rfcomm_sock *rfsock = data;
+ BtIOSecLevel sec_level = BT_IO_SEC_MEDIUM;
GError *gerr = NULL;
sdp_list_t *list;
GIOChannel *io;
@@ -829,11 +834,14 @@ static void sdp_search_cb(sdp_list_t *recs, int err, gpointer data)
DBG("Got RFCOMM channel %d", chan);
+ if (rfsock->profile)
+ sec_level = rfsock->profile->sec_level;
+
io = bt_io_connect(connect_cb, rfsock, NULL, &gerr,
BT_IO_OPT_SOURCE_BDADDR, &adapter_addr,
BT_IO_OPT_DEST_BDADDR, &rfsock->dst,
BT_IO_OPT_CHANNEL, chan,
- BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
+ BT_IO_OPT_SEC_LEVEL, sec_level,
BT_IO_OPT_INVALID);
if (!io) {
error("Failed connect: %s", gerr->message);
@@ -875,6 +883,8 @@ static int handle_connect(void *buf)
uuid.type = SDP_UUID128;
memcpy(&uuid.value.uuid128, cmd->uuid, sizeof(uint128_t));
+ rfsock->profile = get_profile_by_uuid(cmd->uuid);
+
if (bt_search_service(&adapter_addr, &dst, &uuid, sdp_search_cb, rfsock,
NULL) < 0) {
error("Failed to search SDP records");
--
1.8.3.2
^ permalink raw reply related
* Re: [PATCH 1/4] android: Add CAP_NET_RAW capability
From: Johan Hedberg @ 2013-11-25 14:01 UTC (permalink / raw)
To: Ravi kumar Veeramally; +Cc: linux-bluetooth
In-Reply-To: <1385387369-3015-2-git-send-email-ravikumar.veeramally@linux.intel.com>
Hi Ravi,
On Mon, Nov 25, 2013, Ravi kumar Veeramally wrote:
> CAP_NET_RAW capability is required to up the bnep interfaces
> in android environment.
> ---
> android/main.c | 1 +
> 1 file changed, 1 insertion(+)
>
> diff --git a/android/main.c b/android/main.c
> index c9733f3..bfd2a87 100644
> --- a/android/main.c
> +++ b/android/main.c
> @@ -506,6 +506,7 @@ static bool set_capabilities(void)
> header.pid = 0;
>
> cap.effective = cap.permitted =
> + CAP_TO_MASK(CAP_NET_RAW) |
> CAP_TO_MASK(CAP_NET_ADMIN) |
> CAP_TO_MASK(CAP_NET_BIND_SERVICE);
> cap.inheritable = 0;
Would you then say that commit 9bda7e8c2130de9a3340ebd0e6cc1dedc2eae338
is incorrect? A quick grep doesn't show any instances of checking this
capability in the BNEP code of the kernel. Exactly which system call is
it that needs it?
If you answered positively to my first question, please send a patch for
that as well.
Johan
^ permalink raw reply
* [PATCH 4/4] android/pan: Implement the get local role method in daemon
From: Ravi kumar Veeramally @ 2013-11-25 13:49 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Ravi kumar Veeramally
In-Reply-To: <1385387369-3015-1-git-send-email-ravikumar.veeramally@linux.intel.com>
Returns local role of the device (NONE, PANU or NAP).
---
android/pan.c | 14 ++++++++++----
1 file changed, 10 insertions(+), 4 deletions(-)
diff --git a/android/pan.c b/android/pan.c
index 74c27c0..b443b3e 100644
--- a/android/pan.c
+++ b/android/pan.c
@@ -364,11 +364,17 @@ static uint8_t bt_pan_enable(struct hal_cmd_pan_enable *cmd, uint16_t len)
return HAL_STATUS_FAILED;
}
-static uint8_t bt_pan_get_role(void *cmd, uint16_t len)
+static uint8_t bt_pan_get_role(int sk, void *cmd, uint16_t len)
{
- DBG("Not Implemented");
+ struct hal_rsp_pan_get_role rsp;
- return HAL_STATUS_FAILED;
+ DBG("");
+
+ rsp.local_role = local_role;
+ ipc_send(sk, HAL_SERVICE_ID_PAN, HAL_OP_PAN_GET_ROLE, sizeof(rsp),
+ &rsp, -1);
+
+ return HAL_STATUS_SUCCESS;
}
void bt_pan_handle_cmd(int sk, uint8_t opcode, void *buf, uint16_t len)
@@ -380,7 +386,7 @@ void bt_pan_handle_cmd(int sk, uint8_t opcode, void *buf, uint16_t len)
status = bt_pan_enable(buf, len);
break;
case HAL_OP_PAN_GET_ROLE:
- status = bt_pan_get_role(buf, len);
+ status = bt_pan_get_role(sk, buf, len);
break;
case HAL_OP_PAN_CONNECT:
status = bt_pan_connect(buf, len);
--
1.8.3.2
^ permalink raw reply related
* [PATCH 3/4] android/pan: Implement pan disconnect method in daemon
From: Ravi kumar Veeramally @ 2013-11-25 13:49 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Ravi kumar Veeramally
In-Reply-To: <1385387369-3015-1-git-send-email-ravikumar.veeramally@linux.intel.com>
Disconnect ongoing PANU role connection betweek devices, free
the device and notify the connection state.
---
android/pan.c | 59 +++++++++++++++++++++++++++++++++++++++++++++--------------
1 file changed, 45 insertions(+), 14 deletions(-)
diff --git a/android/pan.c b/android/pan.c
index b1d0e15..74c27c0 100644
--- a/android/pan.c
+++ b/android/pan.c
@@ -270,20 +270,6 @@ static void connect_cb(GIOChannel *chan, GError *err, gpointer data)
bnep_setup_cb, np);
}
-static uint8_t bt_pan_enable(struct hal_cmd_pan_enable *cmd, uint16_t len)
-{
- DBG("Not Implemented");
-
- return HAL_STATUS_FAILED;
-}
-
-static uint8_t bt_pan_get_role(void *cmd, uint16_t len)
-{
- DBG("Not Implemented");
-
- return HAL_STATUS_FAILED;
-}
-
static uint8_t bt_pan_connect(struct hal_cmd_pan_connect *cmd, uint16_t len)
{
struct network_peer *np;
@@ -335,6 +321,51 @@ static uint8_t bt_pan_connect(struct hal_cmd_pan_connect *cmd, uint16_t len)
static uint8_t bt_pan_disconnect(struct hal_cmd_pan_disconnect *cmd,
uint16_t len)
{
+ struct network_peer *np;
+ GSList *l;
+ bdaddr_t dst;
+
+ DBG("");
+
+ if (len < sizeof(*cmd))
+ return HAL_STATUS_INVALID;
+
+ android2bdaddr(&cmd->bdaddr, &dst);
+
+ l = g_slist_find_custom(peers, &dst, peer_cmp);
+ if (!l)
+ return HAL_STATUS_FAILED;
+
+ np = l->data;
+
+ if (np->conn_state == HAL_PAN_STATE_CONNECTED) {
+ if (np->watch) {
+ g_source_remove(np->watch);
+ np->watch = 0;
+ }
+
+ bnep_if_down(np->dev);
+ bnep_kill_connection(&dst);
+ bt_pan_notify_conn_state(np, HAL_PAN_STATE_DISCONNECTED);
+ network_peer_free(np);
+
+ } else if (np->io) {
+ bt_pan_notify_conn_state(np, HAL_PAN_STATE_DISCONNECTING);
+ g_io_channel_shutdown(np->io, TRUE, NULL);
+ }
+
+ return HAL_STATUS_SUCCESS;
+}
+
+static uint8_t bt_pan_enable(struct hal_cmd_pan_enable *cmd, uint16_t len)
+{
+ DBG("Not Implemented");
+
+ return HAL_STATUS_FAILED;
+}
+
+static uint8_t bt_pan_get_role(void *cmd, uint16_t len)
+{
DBG("Not Implemented");
return HAL_STATUS_FAILED;
--
1.8.3.2
^ permalink raw reply related
* [PATCH 2/4] android/pan: Implement pan connect method in daemon
From: Ravi kumar Veeramally @ 2013-11-25 13:49 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Ravi kumar Veeramally
In-Reply-To: <1385387369-3015-1-git-send-email-ravikumar.veeramally@linux.intel.com>
Implements the PAN connect method in android daemon with PANU role
only. Setting up the bnep environment, adds connection and makes
bnep interface up. Notifies bnep interface on control state call back
and connection status on connection state call back.
---
android/Android.mk | 2 +
android/Makefile.am | 3 +-
android/pan.c | 289 +++++++++++++++++++++++++++++++++++++++++++++++++++-
3 files changed, 291 insertions(+), 3 deletions(-)
diff --git a/android/Android.mk b/android/Android.mk
index 616a338..4555284 100644
--- a/android/Android.mk
+++ b/android/Android.mk
@@ -41,6 +41,7 @@ LOCAL_SRC_FILES := \
../lib/hci.c \
../btio/btio.c \
../src/sdp-client.c \
+ ../profiles/network/common.c \
LOCAL_C_INCLUDES := \
$(call include-path-for, glib) \
@@ -65,6 +66,7 @@ lib_headers := \
sdp.h \
rfcomm.h \
sco.h \
+ bnep.h \
$(shell mkdir -p $(LOCAL_PATH)/../lib/bluetooth)
diff --git a/android/Makefile.am b/android/Makefile.am
index 5f6b1a3..5d13434 100644
--- a/android/Makefile.am
+++ b/android/Makefile.am
@@ -23,7 +23,8 @@ android_bluetoothd_SOURCES = android/main.c \
android/socket.h android/socket.c \
android/pan.h android/pan.c \
btio/btio.h btio/btio.c \
- src/sdp-client.h src/sdp-client.c
+ src/sdp-client.h src/sdp-client.c \
+ profiles/network/common.c profiles/network/common.h
android_bluetoothd_LDADD = lib/libbluetooth-internal.la @GLIB_LIBS@
diff --git a/android/pan.c b/android/pan.c
index ada458a..b1d0e15 100644
--- a/android/pan.c
+++ b/android/pan.c
@@ -29,13 +29,246 @@
#include <fcntl.h>
#include <glib.h>
+#include "btio/btio.h"
#include "lib/bluetooth.h"
+#include "lib/bnep.h"
+#include "lib/sdp.h"
+#include "lib/sdp_lib.h"
+#include "src/glib-helper.h"
+#include "profiles/network/common.h"
+
#include "log.h"
#include "pan.h"
#include "hal-msg.h"
#include "ipc.h"
+#include "utils.h"
+#include "bluetooth.h"
+static bdaddr_t adapter_addr;
static int notification_sk = -1;
+GSList *peers = NULL;
+uint8_t local_role = HAL_PAN_ROLE_NONE;
+
+struct network_peer {
+ char dev[16];
+ bdaddr_t dst;
+ uint8_t conn_state;
+ uint8_t role;
+ GIOChannel *io;
+ guint watch;
+};
+
+struct __service_16 {
+ uint16_t dst;
+ uint16_t src;
+} __attribute__ ((packed));
+
+static int peer_cmp(gconstpointer s, gconstpointer user_data)
+{
+ const struct network_peer *np = s;
+ const bdaddr_t *dst = user_data;
+
+ return bacmp(&np->dst, dst);
+}
+
+static void network_peer_free(struct network_peer *np)
+{
+ local_role = HAL_PAN_ROLE_NONE;
+
+ if (np->watch > 0) {
+ g_source_remove(np->watch);
+ np->watch = 0;
+ }
+
+ if (np->io) {
+ g_io_channel_unref(np->io);
+ np->io = NULL;
+ }
+
+ peers = g_slist_remove(peers, np);
+ g_free(np);
+}
+
+static void bt_pan_notify_conn_state(struct network_peer *np, uint8_t state)
+{
+ struct hal_ev_pan_conn_state ev;
+ char addr[18];
+
+ if (np->conn_state == state)
+ return;
+
+ np->conn_state = state;
+ ba2str(&np->dst, addr);
+ DBG("device %s state %u", addr, state);
+
+ bdaddr2android(&np->dst, ev.bdaddr);
+ ev.state = state;
+ ev.local_role = local_role;
+ ev.remote_role = np->role;
+ ev.status = HAL_STATUS_SUCCESS;
+
+ ipc_send(notification_sk, HAL_SERVICE_ID_PAN, HAL_EV_PAN_CONN_STATE,
+ sizeof(ev), &ev, -1);
+}
+
+static void bt_pan_notify_ctrl_state(struct network_peer *np, uint8_t state)
+{
+ struct hal_ev_pan_ctrl_state ev;
+
+ DBG("");
+
+ ev.state = state;
+ ev.local_role = local_role;
+ ev.status = HAL_STATUS_SUCCESS;
+ memcpy(ev.name, np->dev, sizeof(np->dev));
+
+ ipc_send(notification_sk, HAL_SERVICE_ID_PAN, HAL_EV_PAN_CTRL_STATE,
+ sizeof(ev), &ev, -1);
+}
+
+static gboolean bnep_watchdog_cb(GIOChannel *chan, GIOCondition cond,
+ gpointer data)
+{
+ struct network_peer *np = data;
+
+ DBG("%s disconnected", np->dev);
+
+ bnep_if_down(np->dev);
+ bt_pan_notify_conn_state(np, HAL_PAN_STATE_DISCONNECTED);
+ network_peer_free(np);
+
+ return FALSE;
+}
+
+static gboolean bnep_setup_cb(GIOChannel *chan, GIOCondition cond,
+ gpointer data)
+{
+ struct network_peer *np = data;
+ struct bnep_control_rsp *rsp;
+ struct timeval timeo;
+ char pkt[BNEP_MTU];
+ uint16_t bnep_role;
+ ssize_t r;
+ int sk;
+
+ DBG("cond %u", cond);
+
+ if (cond & (G_IO_HUP | G_IO_ERR | G_IO_NVAL)) {
+ error("Hangup or error ir invalid on l2cap server socket");
+ goto failed;
+ }
+
+ sk = g_io_channel_unix_get_fd(chan);
+ memset(pkt, 0, BNEP_MTU);
+
+ r = read(sk, pkt, sizeof(pkt) - 1);
+ if (r < 0) {
+ error("IO Channel read error");
+ goto failed;
+ }
+
+ if (r == 0) {
+ error("No packet received on l2cap socket");
+ goto failed;
+ }
+
+ errno = EPROTO;
+
+ if ((size_t) r < sizeof(*rsp)) {
+ error("Packet received is not bnep type");
+ goto failed;
+ }
+
+ rsp = (void *) pkt;
+ if (rsp->type != BNEP_CONTROL) {
+ error("Packet received is not bnep type");
+ goto failed;
+ }
+
+ if (rsp->ctrl != BNEP_SETUP_CONN_RSP) {
+ DBG("rsp->ctrl != BNEP_SETUP_CONN_RSP");
+ return TRUE;
+ }
+
+ r = ntohs(rsp->resp);
+
+ if (r != BNEP_SUCCESS) {
+ error("bnep failed");
+ goto failed;
+ }
+
+ memset(&timeo, 0, sizeof(timeo));
+ timeo.tv_sec = 0;
+
+ setsockopt(sk, SOL_SOCKET, SO_RCVTIMEO, &timeo, sizeof(timeo));
+ bnep_role = (local_role == HAL_PAN_ROLE_PANU) ? BNEP_SVC_PANU :
+ BNEP_SVC_NAP;
+
+ if (bnep_connadd(sk, bnep_role, np->dev))
+ goto failed;
+
+ if (bnep_if_up(np->dev)) {
+ bnep_kill_connection(&np->dst);
+ goto failed;
+ }
+
+ bt_pan_notify_ctrl_state(np, HAL_PAN_CTRL_ENABLED);
+ bt_pan_notify_conn_state(np, HAL_PAN_STATE_CONNECTED);
+
+ DBG("%s connected", np->dev);
+
+ /* Start watchdog */
+ np->watch = g_io_add_watch(chan, G_IO_ERR | G_IO_HUP | G_IO_NVAL,
+ (GIOFunc) bnep_watchdog_cb, np);
+ g_io_channel_unref(np->io);
+ np->io = NULL;
+
+ return FALSE;
+
+failed:
+ bt_pan_notify_conn_state(np, HAL_PAN_STATE_DISCONNECTED);
+ network_peer_free(np);
+ return FALSE;
+}
+
+static void connect_cb(GIOChannel *chan, GError *err, gpointer data)
+{
+ struct network_peer *np = data;
+ struct bnep_setup_conn_req *req;
+ struct __service_16 *s;
+ unsigned char pkt[BNEP_MTU];
+ int fd;
+
+ DBG("");
+
+ if (err) {
+ error("%s", err->message);
+ bt_pan_notify_conn_state(np, HAL_PAN_STATE_DISCONNECTED);
+ network_peer_free(np);
+ }
+
+ /* Send request */
+ req = (void *) pkt;
+ req->type = BNEP_CONTROL;
+ req->ctrl = BNEP_SETUP_CONN_REQ;
+ req->uuid_size = 2; /* 16bit UUID */
+ s = (void *) req->service;
+ s->dst = (np->role == HAL_PAN_ROLE_NAP) ? htons(BNEP_SVC_NAP) :
+ htons(BNEP_SVC_PANU);
+ s->src = (local_role == HAL_PAN_ROLE_NAP) ? htons(BNEP_SVC_NAP) :
+ htons(BNEP_SVC_PANU);
+
+ fd = g_io_channel_unix_get_fd(np->io);
+ if (write(fd, pkt, sizeof(*req) + sizeof(*s)) < 0) {
+ error("bnep connection req send failed: %s", strerror(errno));
+ bt_pan_notify_conn_state(np, HAL_PAN_STATE_DISCONNECTED);
+ network_peer_free(np);
+ return;
+ }
+
+ g_io_add_watch(np->io, G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
+ bnep_setup_cb, np);
+}
static uint8_t bt_pan_enable(struct hal_cmd_pan_enable *cmd, uint16_t len)
{
@@ -53,9 +286,50 @@ static uint8_t bt_pan_get_role(void *cmd, uint16_t len)
static uint8_t bt_pan_connect(struct hal_cmd_pan_connect *cmd, uint16_t len)
{
- DBG("Not Implemented");
+ struct network_peer *np;
+ bdaddr_t dst;
+ char addr[18];
+ GSList *l;
+ GError *gerr = NULL;
- return HAL_STATUS_FAILED;
+ DBG("");
+
+ if (len < sizeof(*cmd))
+ return HAL_STATUS_INVALID;
+
+ android2bdaddr(&cmd->bdaddr, &dst);
+
+ l = g_slist_find_custom(peers, &dst, peer_cmp);
+ if (l)
+ return HAL_STATUS_FAILED;
+
+ np = g_new0(struct network_peer, 1);
+ bacpy(&np->dst, &dst);
+ local_role = cmd->local_role;
+ np->role = cmd->remote_role;
+
+ ba2str(&np->dst, addr);
+ DBG("connecting to %s", addr);
+
+ np->io = bt_io_connect(connect_cb, np, NULL, &gerr,
+ BT_IO_OPT_SOURCE_BDADDR, &adapter_addr,
+ BT_IO_OPT_DEST_BDADDR, &np->dst,
+ 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 (!np->io) {
+ error("%s", gerr->message);
+ g_error_free(gerr);
+ g_free(np);
+ return HAL_STATUS_FAILED;
+ }
+
+ peers = g_slist_append(peers, np);
+ bt_pan_notify_conn_state(np, HAL_PAN_STATE_CONNECTING);
+
+ return HAL_STATUS_SUCCESS;
}
static uint8_t bt_pan_disconnect(struct hal_cmd_pan_disconnect *cmd,
@@ -93,11 +367,21 @@ void bt_pan_handle_cmd(int sk, uint8_t opcode, void *buf, uint16_t len)
bool bt_pan_register(int sk, const bdaddr_t *addr)
{
+ int err;
+
DBG("");
if (notification_sk >= 0)
return false;
+ bacpy(&adapter_addr, addr);
+
+ err = bnep_init();
+ if (err) {
+ error("bnep init failed");
+ return false;
+ }
+
notification_sk = sk;
return true;
@@ -111,4 +395,5 @@ void bt_pan_unregister(void)
return;
notification_sk = -1;
+ bnep_cleanup();
}
--
1.8.3.2
^ permalink raw reply related
* [PATCH 1/4] android: Add CAP_NET_RAW capability
From: Ravi kumar Veeramally @ 2013-11-25 13:49 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Ravi kumar Veeramally
In-Reply-To: <1385387369-3015-1-git-send-email-ravikumar.veeramally@linux.intel.com>
CAP_NET_RAW capability is required to up the bnep interfaces
in android environment.
---
android/main.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/android/main.c b/android/main.c
index c9733f3..bfd2a87 100644
--- a/android/main.c
+++ b/android/main.c
@@ -506,6 +506,7 @@ static bool set_capabilities(void)
header.pid = 0;
cap.effective = cap.permitted =
+ CAP_TO_MASK(CAP_NET_RAW) |
CAP_TO_MASK(CAP_NET_ADMIN) |
CAP_TO_MASK(CAP_NET_BIND_SERVICE);
cap.inheritable = 0;
--
1.8.3.2
^ permalink raw reply related
* [PATCH 0/4] Adds pan connect disconnect and get role methods
From: Ravi kumar Veeramally @ 2013-11-25 13:49 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Ravi kumar Veeramally
This patch set supports PANU role with a minor fix in android. Added
CAP_NET_RAW capability for bnep services. Creates bnep connection and
up the inreface on connect call and free the device on disconnect call.
Interface name(bnepX) will be notified on control state cb. Android
environment will create IP address with dhcp calls.
Ravi kumar Veeramally (4):
android: Add CAP_NET_RAW capability
android/pan: Implement pan connect method in daemon
android/pan: Implement pan disconnect method in daemon
android/pan: Implement the get local role method in daemon
android/Android.mk | 2 +
android/Makefile.am | 3 +-
android/main.c | 1 +
android/pan.c | 340 ++++++++++++++++++++++++++++++++++++++++++++++++++--
4 files changed, 336 insertions(+), 10 deletions(-)
--
1.8.3.2
^ permalink raw reply
* Re: [PATCH 1/3] sdptool: Fix memory leaks creating OPP record
From: Johan Hedberg @ 2013-11-25 13:42 UTC (permalink / raw)
To: Andrei Emeltchenko; +Cc: linux-bluetooth
In-Reply-To: <1385385285-30592-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>
Hi Andrei,
On Mon, Nov 25, 2013, Andrei Emeltchenko wrote:
> From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
>
> ---
> tools/sdptool.c | 3 +++
> 1 file changed, 3 insertions(+)
All three patches have been applied, however don't hesitate to also send
patches to fix using 0 instead of NULL for pointers.
Johan
^ permalink raw reply
* Re: [PATCHv9 18/21] android/socket: Use security level for connect
From: Johan Hedberg @ 2013-11-25 13:40 UTC (permalink / raw)
To: Andrei Emeltchenko; +Cc: linux-bluetooth
In-Reply-To: <1385384937-29858-19-git-send-email-Andrei.Emeltchenko.news@gmail.com>
Hi Andrei,
On Mon, Nov 25, 2013, Andrei Emeltchenko wrote:
> Use low security level for connections without profile and default
> sec_level for others. rfsock now has pointer to profile info for
> outcoming connections.
> ---
> android/socket.c | 12 +++++++++++-
> 1 file changed, 11 insertions(+), 1 deletion(-)
Patches 1-17 have been applied, but I can't apply from this one onwards
since the default security level should be MEDIUM and not LOW. OPP is
the only exception that should have LOW and SAP the only exception that
should have HIGH.
Johan
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox