From: Andrei Emeltchenko <andrei.emeltchenko@xxxxxxxxx> Fixes SEID generation for avdtp. Currently SEIDs were assigned assuming that SEID are registered and unregistered in the same order like: seid = g_slist_length(seps) + 1 which makes it possible to reuse similar SEIDs --- android/avdtp.c | 32 +++++++++++++++++++++++++++++--- unit/test-avdtp.c | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+), 3 deletions(-) diff --git a/android/avdtp.c b/android/avdtp.c index 22c492b..20f27d4 100644 --- a/android/avdtp.c +++ b/android/avdtp.c @@ -45,6 +45,7 @@ #include "../profiles/audio/a2dp-codecs.h" #define MAX_SEID 0x3E +static uint64_t seids; #ifndef MAX # define MAX(x, y) ((x) > (y) ? (x) : (y)) @@ -3350,20 +3351,44 @@ int avdtp_delay_report(struct avdtp *session, struct avdtp_stream *stream, &req, sizeof(req)); } +static uint8_t avdtp_get_seid(void) +{ + uint64_t temp = seids; + uint8_t id = 1; + + while (temp >>= 1) + id++; + + if (id > MAX_SEID) + return 0; + + seids |= (uint64_t) (0x01l << id); + + DBG("seids 0x%04lx id %d", seids, id); + + return id; +} + +static void avdtp_clear_seid(uint8_t seid) +{ + seids &= ~(0x1l<<seid); + + DBG("seids 0x%04lx cleared bit %d ", seids, seid); +} + 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, - uint8_t seid) + void *user_data, uint8_t seid) { struct avdtp_local_sep *sep; sep = g_new0(struct avdtp_local_sep, 1); sep->state = AVDTP_STATE_IDLE; - sep->info.seid = seid; + sep->info.seid = avdtp_get_seid(); sep->info.type = type; sep->info.media_type = media_type; sep->codec = codec_type; @@ -3396,6 +3421,7 @@ int avdtp_unregister_sep(struct avdtp_local_sep *sep) DBG("SEP %p unregistered: type:%d codec:%d seid:%d", sep, sep->info.type, sep->codec, sep->info.seid); + avdtp_clear_seid(sep->info.seid); g_free(sep); return 0; diff --git a/unit/test-avdtp.c b/unit/test-avdtp.c index 03fd4b1..00b72f1 100644 --- a/unit/test-avdtp.c +++ b/unit/test-avdtp.c @@ -39,6 +39,8 @@ #include "src/log.h" #include "android/avdtp.h" +#define MAX_SEID 0x3E + GSList *lseps = NULL; struct test_pdu { @@ -567,6 +569,35 @@ static void test_server_0_sep(gconstpointer data) execute_context(context); } +static void unregister_sep(gpointer data, gpointer user_data) +{ + struct avdtp_local_sep *sep = data; + + lseps = g_slist_remove(lseps, sep); + avdtp_unregister_sep(sep); +} + +static void test_server_seid(gconstpointer data) +{ + struct context *context = create_context(0x0103, data); + struct avdtp_local_sep *sep; + int i; + + for (i = 0; i < MAX_SEID; i++) { + sep = avdtp_register_sep(AVDTP_SEP_TYPE_SINK, + AVDTP_MEDIA_TYPE_AUDIO, + 0x00, TRUE, &sep_ind, NULL, + context, + g_slist_length(lseps) + 1); + g_assert(sep); + + lseps = g_slist_append(lseps, sep); + avdtp_set_lseps(context->session, lseps); + } + + g_slist_foreach(lseps, unregister_sep, NULL); +} + static gboolean sep_getcap_ind_frg(struct avdtp *session, struct avdtp_local_sep *sep, GSList **caps, uint8_t *err, @@ -774,6 +805,8 @@ int main(int argc, char *argv[]) * To verify that the following procedures are implemented according to * their specification in AVDTP. */ + define_test("/TP/SIG/SMG/BV-06-C-SEID-1", test_server_seid, + raw_pdu(0x00)); define_test("/TP/SIG/SMG/BV-05-C", test_client, raw_pdu(0x00, 0x01)); define_test("/TP/SIG/SMG/BV-06-C", test_server, -- 2.1.0 -- To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html