Linux bluetooth development
 help / color / mirror / Atom feed
* Re: [PATCH BlueZ 3/6] audio/A2DP: Add implemention of audio Open Stream command
From: Lukasz Rymanowski @ 2014-01-13  0:10 UTC (permalink / raw)
  To: Luiz Augusto von Dentz; +Cc: linux-bluetooth@vger.kernel.org
In-Reply-To: <1389435216-29040-3-git-send-email-luiz.dentz@gmail.com>

Hi Luiz,

On Sat, Jan 11, 2014 at 11:13 AM, Luiz Augusto von Dentz
<luiz.dentz@gmail.com> wrote:
> From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
>
> ---
>  android/a2dp.c | 199 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 197 insertions(+), 2 deletions(-)
>
> diff --git a/android/a2dp.c b/android/a2dp.c
> index 8649cf3..479cb71 100644
> --- a/android/a2dp.c
> +++ b/android/a2dp.c
> @@ -37,6 +37,7 @@
>  #include "lib/bluetooth.h"
>  #include "lib/sdp.h"
>  #include "lib/sdp_lib.h"
> +#include "profiles/audio/a2dp-codecs.h"

We need to discuss how we gonna use structs from this file in
hal-audio (eg. a2dp_sbc_t). Maybe we should have some special file
with audio structs/defines for IPC only? Then you could copy data to
structs you need.

>  #include "log.h"
>  #include "a2dp.h"
>  #include "hal-msg.h"
> @@ -53,6 +54,7 @@
>  static GIOChannel *server = NULL;
>  static GSList *devices = NULL;
>  static GSList *endpoints = NULL;
> +static GSList *setups = NULL;
>  static bdaddr_t adapter_addr;
>  static uint32_t record_id = 0;
>
> @@ -67,6 +69,7 @@ struct a2dp_endpoint {
>         struct avdtp_local_sep *sep;
>         struct a2dp_preset *caps;
>         GSList *presets;
> +       struct a2dp_config *config;
>  };
>
>  struct a2dp_device {
> @@ -76,6 +79,13 @@ struct a2dp_device {
>         struct avdtp    *session;
>  };
>
> +struct a2dp_setup {
> +       struct a2dp_device *dev;
> +       struct a2dp_endpoint *endpoint;
> +       struct a2dp_preset *preset;
> +       struct avdtp_stream *stream;
> +};
> +
>  static int device_cmp(gconstpointer s, gconstpointer user_data)
>  {
>         const struct a2dp_device *dev = s;
> @@ -422,8 +432,160 @@ static gboolean sep_getcap_ind(struct avdtp *session,
>         return TRUE;
>  }
>
> +static int sbc_check_config(struct a2dp_endpoint *endpoint,
> +                                               struct a2dp_preset *conf)
> +{
> +       a2dp_sbc_t *caps, *config;
> +
> +       if (conf->len != sizeof(a2dp_sbc_t)) {
> +               error("SBC: Invalid configuration size (%u)", conf->len);
> +               return -EINVAL;
> +       }
> +
> +       caps = endpoint->caps->data;
> +       config = conf->data;
> +
> +       if (!(caps->frequency & config->frequency)) {
> +               error("SBC: Unsupported frequency (%u) by endpoint",
> +                                                       config->frequency);
> +               return -EINVAL;
> +       }
> +
> +       if (!(caps->channel_mode & config->channel_mode)) {
> +               error("SBC: Unsupported channel mode (%u) by endpoint",
> +                                                       config->channel_mode);
> +               return -EINVAL;
> +       }
> +
> +       if (!(caps->block_length & config->block_length)) {
> +               error("SBC: Unsupported block length (%u) by endpoint",
> +                                                       config->block_length);
> +               return -EINVAL;
> +       }
> +
> +       if (!(caps->allocation_method & config->allocation_method)) {
> +               error("SBC: Unsupported allocation method (%u) by endpoint",
> +                                                       config->block_length);
> +               return -EINVAL;
> +       }
> +
> +       return 0;
> +}
> +
> +static int check_config(struct a2dp_endpoint *endpoint,
> +                                               struct a2dp_preset *config)
> +{
> +       GSList *l;
> +
> +       for (l = endpoint->presets; l; l = g_slist_next(l)) {
> +               struct a2dp_preset *preset = l->data;
> +
> +               if (preset->len != config->len)
> +                       continue;
> +
> +               if (memcmp(preset->data, config->data, preset->len) == 0)
> +                       return 0;
> +       }
> +
> +       /* Codec specific */
> +       switch (endpoint->codec) {
> +       case A2DP_CODEC_SBC:
> +               return sbc_check_config(endpoint, config);
> +       default:
> +               return -EINVAL;
> +       }
> +}
> +
> +static struct a2dp_device *find_device_by_session(struct avdtp *session)
> +{
> +       GSList *l;
> +
> +       for (l = devices; l; l = g_slist_next(l)) {
> +               struct a2dp_device *dev = l->data;
> +
> +               if (dev->session == session)
> +                       return dev;
> +       }
> +
> +       return NULL;
> +}
> +
> +static void setup_free(void *data)
> +{
> +       struct a2dp_setup *setup = data;
> +
> +       preset_free(setup->preset);
> +       g_free(setup);
> +}
> +
> +static void setup_add(struct a2dp_device *dev, struct a2dp_endpoint *endpoint,
> +                       struct a2dp_preset *preset, struct avdtp_stream *stream)
> +{
> +       struct a2dp_setup *setup;
> +
> +       setup = g_new0(struct a2dp_setup, 1);
> +       setup->dev = dev;
> +       setup->endpoint = endpoint;
> +       setup->preset = preset;
> +       setup->stream = stream;
> +       setups = g_slist_append(setups, setup);
> +}
> +
> +static gboolean sep_setconf_ind(struct avdtp *session,
> +                                               struct avdtp_local_sep *sep,
> +                                               struct avdtp_stream *stream,
> +                                               GSList *caps,
> +                                               avdtp_set_configuration_cb cb,
> +                                               void *user_data)
> +{
> +       struct a2dp_endpoint *endpoint = user_data;
> +       struct a2dp_device *dev;
> +       struct a2dp_preset *preset = NULL;
> +
> +       DBG("");
> +
> +       dev = find_device_by_session(session);
> +       if (!dev) {
> +               error("Unable to find device for session %p", session);
> +               return FALSE;
> +       }
> +
> +       for (; caps != NULL; caps = g_slist_next(caps)) {
> +               struct avdtp_service_capability *cap = caps->data;
> +               struct avdtp_media_codec_capability *codec;
> +
> +               if (cap->category == AVDTP_DELAY_REPORTING)
> +                       return FALSE;
> +
> +               if (cap->category != AVDTP_MEDIA_CODEC)
> +                       continue;
> +
> +               codec = (struct avdtp_media_codec_capability *) cap->data;
> +
> +               if (codec->media_codec_type != endpoint->codec)
> +                       return FALSE;
> +
> +               preset = g_new0(struct a2dp_preset, 1);
> +               preset->len = cap->length - sizeof(*codec);
> +               preset->data = g_memdup(codec->data, preset->len);
> +
> +               if (check_config(endpoint, preset) < 0) {
> +                       preset_free(preset);
> +                       return FALSE;
> +               }
> +       }
> +
> +       if (!preset)
> +               return FALSE;
> +
> +       setup_add(dev, endpoint, preset, stream);
> +
> +       return TRUE;
> +}
> +
>  static struct avdtp_sep_ind sep_ind = {
>         .get_capability         = sep_getcap_ind,
> +       .set_configuration      = sep_setconf_ind,
>  };
>
>  static uint8_t register_endpoint(const uint8_t *uuid, uint8_t codec,
> @@ -548,11 +710,41 @@ static void bt_audio_close(const void *buf, uint16_t len)
>         audio_ipc_send_rsp(AUDIO_OP_CLOSE, HAL_STATUS_SUCCESS);
>  }
>
> +static struct a2dp_setup *find_setup(uint8_t id)
> +{
> +       GSList *l;
> +
> +       for (l = setups; l; l = g_slist_next(l)) {
> +               struct a2dp_setup *setup = l->data;
> +
> +               if (setup->endpoint->id == id)
> +                       return setup;
> +       }
> +
> +       return NULL;
> +}
> +
>  static void bt_stream_open(const void *buf, uint16_t len)
>  {
> -       DBG("Not Implemented");
> +       const struct audio_cmd_open_stream *cmd = buf;
> +       struct audio_rsp_open_stream *rsp;
> +       struct a2dp_setup *setup;
> +
> +       DBG("");
>
> -       audio_ipc_send_rsp(AUDIO_OP_OPEN_STREAM, AUDIO_STATUS_FAILED);
> +       setup = find_setup(cmd->id);
> +       if (!setup) {
> +               error("Unable to find stream for endpoint %u", cmd->id);
> +               audio_ipc_send_rsp(AUDIO_OP_OPEN_STREAM, HAL_STATUS_FAILED);

Use AUDIO_STATUS_FAILED

> +               return;
> +       }
> +
> +       len = sizeof(*rsp) + setup->preset->len;
> +       rsp = g_malloc0(sizeof(*rsp) + setup->preset->len);
> +       rsp->preset->len = setup->preset->len;
> +       memcpy(rsp->preset->data, setup->preset->data, setup->preset->len);
> +
> +       audio_ipc_send_rsp_full(AUDIO_OP_OPEN_STREAM, len, rsp, -1);
>  }
>
>  static void bt_stream_close(const void *buf, uint16_t len)
> @@ -651,6 +843,9 @@ void bt_a2dp_unregister(void)
>  {
>         DBG("");
>
> +       g_slist_free_full(setups, setup_free);
> +       setups = NULL;
> +
>         g_slist_free_full(endpoints, unregister_endpoint);
>         endpoints = NULL;
>
> --
> 1.8.4.2
>

BR
Lukasz

> --
> To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH BlueZ 3/6] audio/A2DP: Add implemention of audio Open Stream command
From: Andrzej Kaczmarek @ 2014-01-13  0:02 UTC (permalink / raw)
  To: Luiz Augusto von Dentz; +Cc: linux-bluetooth
In-Reply-To: <1389435216-29040-3-git-send-email-luiz.dentz@gmail.com>

Hi Luiz,

On 11 January 2014 11:13, Luiz Augusto von Dentz <luiz.dentz@gmail.com> wrote:
> From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
>
> ---
>  android/a2dp.c | 199 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 197 insertions(+), 2 deletions(-)
>
> diff --git a/android/a2dp.c b/android/a2dp.c
> index 8649cf3..479cb71 100644
> --- a/android/a2dp.c
> +++ b/android/a2dp.c
> @@ -37,6 +37,7 @@
>  #include "lib/bluetooth.h"
>  #include "lib/sdp.h"
>  #include "lib/sdp_lib.h"
> +#include "profiles/audio/a2dp-codecs.h"
>  #include "log.h"
>  #include "a2dp.h"
>  #include "hal-msg.h"
> @@ -53,6 +54,7 @@
>  static GIOChannel *server = NULL;
>  static GSList *devices = NULL;
>  static GSList *endpoints = NULL;
> +static GSList *setups = NULL;
>  static bdaddr_t adapter_addr;
>  static uint32_t record_id = 0;
>
> @@ -67,6 +69,7 @@ struct a2dp_endpoint {
>         struct avdtp_local_sep *sep;
>         struct a2dp_preset *caps;
>         GSList *presets;
> +       struct a2dp_config *config;
>  };
>
>  struct a2dp_device {
> @@ -76,6 +79,13 @@ struct a2dp_device {
>         struct avdtp    *session;
>  };
>
> +struct a2dp_setup {
> +       struct a2dp_device *dev;
> +       struct a2dp_endpoint *endpoint;
> +       struct a2dp_preset *preset;
> +       struct avdtp_stream *stream;
> +};
> +
>  static int device_cmp(gconstpointer s, gconstpointer user_data)
>  {
>         const struct a2dp_device *dev = s;
> @@ -422,8 +432,160 @@ static gboolean sep_getcap_ind(struct avdtp *session,
>         return TRUE;
>  }
>
> +static int sbc_check_config(struct a2dp_endpoint *endpoint,
> +                                               struct a2dp_preset *conf)
> +{
> +       a2dp_sbc_t *caps, *config;
> +
> +       if (conf->len != sizeof(a2dp_sbc_t)) {
> +               error("SBC: Invalid configuration size (%u)", conf->len);
> +               return -EINVAL;
> +       }
> +
> +       caps = endpoint->caps->data;
> +       config = conf->data;
> +
> +       if (!(caps->frequency & config->frequency)) {
> +               error("SBC: Unsupported frequency (%u) by endpoint",
> +                                                       config->frequency);
> +               return -EINVAL;
> +       }
> +
> +       if (!(caps->channel_mode & config->channel_mode)) {
> +               error("SBC: Unsupported channel mode (%u) by endpoint",
> +                                                       config->channel_mode);
> +               return -EINVAL;
> +       }
> +
> +       if (!(caps->block_length & config->block_length)) {
> +               error("SBC: Unsupported block length (%u) by endpoint",
> +                                                       config->block_length);
> +               return -EINVAL;
> +       }
> +
> +       if (!(caps->allocation_method & config->allocation_method)) {
> +               error("SBC: Unsupported allocation method (%u) by endpoint",
> +                                                       config->block_length);
> +               return -EINVAL;
> +       }
> +
> +       return 0;
> +}
> +
> +static int check_config(struct a2dp_endpoint *endpoint,
> +                                               struct a2dp_preset *config)
> +{
> +       GSList *l;
> +
> +       for (l = endpoint->presets; l; l = g_slist_next(l)) {
> +               struct a2dp_preset *preset = l->data;
> +
> +               if (preset->len != config->len)
> +                       continue;
> +
> +               if (memcmp(preset->data, config->data, preset->len) == 0)
> +                       return 0;
> +       }
> +
> +       /* Codec specific */
> +       switch (endpoint->codec) {
> +       case A2DP_CODEC_SBC:
> +               return sbc_check_config(endpoint, config);
> +       default:
> +               return -EINVAL;
> +       }
> +}
> +
> +static struct a2dp_device *find_device_by_session(struct avdtp *session)
> +{
> +       GSList *l;
> +
> +       for (l = devices; l; l = g_slist_next(l)) {
> +               struct a2dp_device *dev = l->data;
> +
> +               if (dev->session == session)
> +                       return dev;
> +       }
> +
> +       return NULL;
> +}
> +
> +static void setup_free(void *data)
> +{
> +       struct a2dp_setup *setup = data;
> +
> +       preset_free(setup->preset);
> +       g_free(setup);
> +}
> +
> +static void setup_add(struct a2dp_device *dev, struct a2dp_endpoint *endpoint,
> +                       struct a2dp_preset *preset, struct avdtp_stream *stream)
> +{
> +       struct a2dp_setup *setup;
> +
> +       setup = g_new0(struct a2dp_setup, 1);
> +       setup->dev = dev;
> +       setup->endpoint = endpoint;
> +       setup->preset = preset;
> +       setup->stream = stream;
> +       setups = g_slist_append(setups, setup);
> +}
> +
> +static gboolean sep_setconf_ind(struct avdtp *session,
> +                                               struct avdtp_local_sep *sep,
> +                                               struct avdtp_stream *stream,
> +                                               GSList *caps,
> +                                               avdtp_set_configuration_cb cb,
> +                                               void *user_data)
> +{
> +       struct a2dp_endpoint *endpoint = user_data;
> +       struct a2dp_device *dev;
> +       struct a2dp_preset *preset = NULL;
> +
> +       DBG("");
> +
> +       dev = find_device_by_session(session);
> +       if (!dev) {
> +               error("Unable to find device for session %p", session);
> +               return FALSE;
> +       }
> +
> +       for (; caps != NULL; caps = g_slist_next(caps)) {
> +               struct avdtp_service_capability *cap = caps->data;
> +               struct avdtp_media_codec_capability *codec;
> +
> +               if (cap->category == AVDTP_DELAY_REPORTING)
> +                       return FALSE;
> +
> +               if (cap->category != AVDTP_MEDIA_CODEC)
> +                       continue;
> +
> +               codec = (struct avdtp_media_codec_capability *) cap->data;
> +
> +               if (codec->media_codec_type != endpoint->codec)
> +                       return FALSE;
> +
> +               preset = g_new0(struct a2dp_preset, 1);
> +               preset->len = cap->length - sizeof(*codec);
> +               preset->data = g_memdup(codec->data, preset->len);
> +
> +               if (check_config(endpoint, preset) < 0) {
> +                       preset_free(preset);
> +                       return FALSE;
> +               }
> +       }
> +
> +       if (!preset)
> +               return FALSE;
> +
> +       setup_add(dev, endpoint, preset, stream);
> +
> +       return TRUE;

I guess there should be call to avdtp_set_configuration_cb somewhere
in this function?


BR,
Andrzej

^ permalink raw reply

* Re: [PATCH BlueZ 1/6] audio/A2DP: Add implemention of audio Open command
From: Andrzej Kaczmarek @ 2014-01-12 23:58 UTC (permalink / raw)
  To: Luiz Augusto von Dentz; +Cc: linux-bluetooth
In-Reply-To: <1389435216-29040-1-git-send-email-luiz.dentz@gmail.com>

Hi Luiz,

On 11 January 2014 11:13, Luiz Augusto von Dentz <luiz.dentz@gmail.com> wrote:
> From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
>
> ---
>  android/a2dp.c | 159 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 158 insertions(+), 1 deletion(-)
>
> diff --git a/android/a2dp.c b/android/a2dp.c
> index b59c53d..28b7406 100644
> --- a/android/a2dp.c
> +++ b/android/a2dp.c
> @@ -52,9 +52,23 @@
>
>  static GIOChannel *server = NULL;
>  static GSList *devices = NULL;
> +static GSList *endpoints = NULL;
>  static bdaddr_t adapter_addr;
>  static uint32_t record_id = 0;
>
> +struct a2dp_preset {
> +       void *data;
> +       int8_t len;
> +};
> +
> +struct a2dp_endpoint {
> +       uint8_t id;
> +       uint8_t codec;
> +       struct avdtp_local_sep *sep;
> +       struct a2dp_preset *caps;
> +       GSList *presets;
> +};
> +
>  struct a2dp_device {
>         bdaddr_t        dst;
>         uint8_t         state;
> @@ -70,6 +84,29 @@ static int device_cmp(gconstpointer s, gconstpointer user_data)
>         return bacmp(&dev->dst, dst);
>  }
>
> +static void preset_free(void *data)
> +{
> +       struct a2dp_preset *preset = data;
> +
> +       g_free(preset->data);
> +       g_free(preset);
> +}
> +
> +static void unregister_endpoint(void *data)
> +{
> +       struct a2dp_endpoint *endpoint = data;
> +
> +       if (endpoint->sep)
> +               avdtp_unregister_sep(endpoint->sep);
> +
> +       if (endpoint->caps)
> +               preset_free(endpoint->caps);
> +
> +       g_slist_free_full(endpoint->presets, preset_free);
> +
> +       g_free(endpoint);
> +}
> +
>  static void a2dp_device_free(struct a2dp_device *dev)
>  {
>         if (dev->session)
> @@ -354,10 +391,127 @@ static sdp_record_t *a2dp_record(void)
>         return record;
>  }
>
> +static gboolean sep_getcap_ind(struct avdtp *session,
> +                                       struct avdtp_local_sep *sep,
> +                                       GSList **caps, uint8_t *err,
> +                                       void *user_data)
> +{
> +       struct a2dp_endpoint *endpoint = user_data;
> +       struct a2dp_preset *cap = endpoint->presets->data;

endpoint->caps

> +       struct avdtp_service_capability *media_transport, *media_codec;
> +       struct avdtp_media_codec_capability *codec_caps;
> +
> +       *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 = endpoint->codec;
> +       memcpy(codec_caps->data, cap->data, cap->len);
> +
> +       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 uint8_t register_endpoint(const uint8_t *uuid, uint8_t codec,
> +                                                       GSList *presets)
> +{
> +       struct a2dp_endpoint *endpoint;
> +
> +       /* FIXME: Add proper check for uuid */
> +
> +       endpoint = g_new0(struct a2dp_endpoint, 1);
> +       endpoint->id = g_slist_length(endpoints) + 1;
> +       endpoint->codec = codec;
> +       endpoint->sep = avdtp_register_sep(AVDTP_SEP_TYPE_SOURCE,
> +                                               AVDTP_MEDIA_TYPE_AUDIO,
> +                                               codec, FALSE, &sep_ind, NULL,
> +                                               endpoint);
> +       endpoint->caps = g_slist_nth_data(presets->data, 0);

g_slist_nth_data(presets, 0)


BR,
Andrzej

^ permalink raw reply

* Re: [PATCH BlueZ 2/6] audio/A2DP: Add implemention of audio Close command
From: Lukasz Rymanowski @ 2014-01-12 22:36 UTC (permalink / raw)
  To: Luiz Augusto von Dentz; +Cc: linux-bluetooth@vger.kernel.org
In-Reply-To: <1389435216-29040-2-git-send-email-luiz.dentz@gmail.com>

Hi Luiz,

On Sat, Jan 11, 2014 at 11:13 AM, Luiz Augusto von Dentz
<luiz.dentz@gmail.com> wrote:
> From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
>
> ---
>  android/a2dp.c | 30 ++++++++++++++++++++++++++++--
>  1 file changed, 28 insertions(+), 2 deletions(-)
>
> diff --git a/android/a2dp.c b/android/a2dp.c
> index 28b7406..8649cf3 100644
> --- a/android/a2dp.c
> +++ b/android/a2dp.c
> @@ -515,11 +515,37 @@ failed:
>         audio_ipc_send_rsp(AUDIO_OP_OPEN, AUDIO_STATUS_FAILED);
>  }
>
> +static struct a2dp_endpoint *find_endpoint(uint8_t id)
> +{
> +       GSList *l;
> +
> +       for (l = endpoints; l; l = g_slist_next(l)) {
> +               struct a2dp_endpoint *endpoint = l->data;
> +
> +               if (endpoint->id == id)
> +                       return endpoint;
> +       }
> +
> +       return NULL;
> +}
> +
>  static void bt_audio_close(const void *buf, uint16_t len)
>  {
> -       DBG("Not Implemented");
> +       const struct audio_cmd_close *cmd = buf;
> +       struct a2dp_endpoint *endpoint;
> +
> +       DBG("");
> +
> +       endpoint = find_endpoint(cmd->id);
> +       if (!endpoint) {
> +               error("Unable to find endpoint %u", cmd->id);
> +               audio_ipc_send_rsp(AUDIO_OP_CLOSE, HAL_STATUS_FAILED);

I think we should use AUDIO_STATUS_FAILED instead of HAL_STATUS_FAILED

> +               return;
> +       }
> +
> +       unregister_endpoint(endpoint);
>
> -       audio_ipc_send_rsp(AUDIO_OP_CLOSE, HAL_STATUS_FAILED);
> +       audio_ipc_send_rsp(AUDIO_OP_CLOSE, HAL_STATUS_SUCCESS);

Similar here.
>  }
>
>  static void bt_stream_open(const void *buf, uint16_t len)
> --
> 1.8.4.2
>
> --

\Lukasz

> To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* [PATCH] android/ipc: Use proper handlers in ipc_handle_msg
From: Andrzej Kaczmarek @ 2014-01-12 22:22 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Andrzej Kaczmarek

ipc_handle_msg() should use handlers passed as function parameter
instead of static one as otherwise Audio IPC will use incorrect
handlers.
---
 android/ipc.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/android/ipc.c b/android/ipc.c
index a31d315..ed3ef3c 100644
--- a/android/ipc.c
+++ b/android/ipc.c
@@ -82,7 +82,7 @@ int ipc_handle_msg(struct service_handler *handlers, size_t max_index,
 	}
 
 	/* opcode is table offset + 1 */
-	handler = &services[msg->service_id].handler[msg->opcode - 1];
+	handler = &handlers[msg->service_id].handler[msg->opcode - 1];
 
 	/* if payload size is valid */
 	if ((handler->var_len && handler->data_len > msg->len) ||
-- 
1.8.5.2


^ permalink raw reply related

* [PATCH] android/ipc: Fix arguments order in DBG
From: Andrzej Kaczmarek @ 2014-01-12 21:44 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Andrzej Kaczmarek

---
 android/ipc.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/android/ipc.c b/android/ipc.c
index 03bdc35..a31d315 100644
--- a/android/ipc.c
+++ b/android/ipc.c
@@ -88,7 +88,7 @@ int ipc_handle_msg(struct service_handler *handlers, size_t max_index,
 	if ((handler->var_len && handler->data_len > msg->len) ||
 			(!handler->var_len && handler->data_len != msg->len)) {
 		DBG("invalid size for opcode 0x%x service 0x%x",
-						msg->service_id, msg->opcode);
+						msg->opcode, msg->service_id);
 		return -EMSGSIZE;
 	}
 
-- 
1.8.5.2


^ permalink raw reply related

* Re: [PATCH BlueZ 1/6] audio/A2DP: Add implemention of audio Open command
From: Andrzej Kaczmarek @ 2014-01-12 21:21 UTC (permalink / raw)
  To: Luiz Augusto von Dentz; +Cc: linux-bluetooth
In-Reply-To: <1389435216-29040-1-git-send-email-luiz.dentz@gmail.com>

Hi Luiz,

On 11 January 2014 11:13, Luiz Augusto von Dentz <luiz.dentz@gmail.com> wrote:
> From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
>
> ---
>  android/a2dp.c | 159 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 158 insertions(+), 1 deletion(-)
>
> diff --git a/android/a2dp.c b/android/a2dp.c
> index b59c53d..28b7406 100644
> --- a/android/a2dp.c
> +++ b/android/a2dp.c
> @@ -52,9 +52,23 @@
>
>  static GIOChannel *server = NULL;
>  static GSList *devices = NULL;
> +static GSList *endpoints = NULL;
>  static bdaddr_t adapter_addr;
>  static uint32_t record_id = 0;
>
> +struct a2dp_preset {
> +       void *data;
> +       int8_t len;
> +};
> +
> +struct a2dp_endpoint {
> +       uint8_t id;
> +       uint8_t codec;
> +       struct avdtp_local_sep *sep;
> +       struct a2dp_preset *caps;
> +       GSList *presets;
> +};
> +
>  struct a2dp_device {
>         bdaddr_t        dst;
>         uint8_t         state;
> @@ -70,6 +84,29 @@ static int device_cmp(gconstpointer s, gconstpointer user_data)
>         return bacmp(&dev->dst, dst);
>  }
>
> +static void preset_free(void *data)
> +{
> +       struct a2dp_preset *preset = data;
> +
> +       g_free(preset->data);
> +       g_free(preset);
> +}
> +
> +static void unregister_endpoint(void *data)
> +{
> +       struct a2dp_endpoint *endpoint = data;
> +
> +       if (endpoint->sep)
> +               avdtp_unregister_sep(endpoint->sep);
> +
> +       if (endpoint->caps)
> +               preset_free(endpoint->caps);
> +
> +       g_slist_free_full(endpoint->presets, preset_free);
> +
> +       g_free(endpoint);
> +}
> +
>  static void a2dp_device_free(struct a2dp_device *dev)
>  {
>         if (dev->session)
> @@ -354,10 +391,127 @@ static sdp_record_t *a2dp_record(void)
>         return record;
>  }
>
> +static gboolean sep_getcap_ind(struct avdtp *session,
> +                                       struct avdtp_local_sep *sep,
> +                                       GSList **caps, uint8_t *err,
> +                                       void *user_data)
> +{
> +       struct a2dp_endpoint *endpoint = user_data;
> +       struct a2dp_preset *cap = endpoint->presets->data;
> +       struct avdtp_service_capability *media_transport, *media_codec;
> +       struct avdtp_media_codec_capability *codec_caps;
> +
> +       *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 = endpoint->codec;
> +       memcpy(codec_caps->data, cap->data, cap->len);
> +
> +       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 uint8_t register_endpoint(const uint8_t *uuid, uint8_t codec,
> +                                                       GSList *presets)
> +{
> +       struct a2dp_endpoint *endpoint;
> +
> +       /* FIXME: Add proper check for uuid */
> +
> +       endpoint = g_new0(struct a2dp_endpoint, 1);
> +       endpoint->id = g_slist_length(endpoints) + 1;
> +       endpoint->codec = codec;
> +       endpoint->sep = avdtp_register_sep(AVDTP_SEP_TYPE_SOURCE,
> +                                               AVDTP_MEDIA_TYPE_AUDIO,
> +                                               codec, FALSE, &sep_ind, NULL,
> +                                               endpoint);
> +       endpoint->caps = g_slist_nth_data(presets->data, 0);
> +       endpoint->presets = g_slist_copy(g_slist_nth(presets, 1));
> +
> +       endpoints = g_slist_append(endpoints, endpoint);
> +
> +       return endpoint->id;
> +}
> +
> +static GSList *parse_presets(const struct audio_preset *p, uint8_t count,
> +                                                               uint16_t len)
> +{
> +       GSList *l = NULL;
> +       uint8_t i;
> +
> +       for (i = 0; count > i; i++) {
> +               struct a2dp_preset *preset;
> +
> +               if (len < sizeof(struct audio_preset)) {
> +                       DBG("Invalid preset index %u", i);
> +                       break;
> +               }
> +
> +               len -= sizeof(struct audio_preset);
> +               if (len == 0 || len < p->len) {
> +                       DBG("Invalid preset size of %u for index %u", len, i);
> +                       break;
> +               }
> +
> +               preset = g_new0(struct a2dp_preset, 1);
> +               preset->len = p->len;
> +               preset->data = g_memdup(p->data, preset->len);
> +               l = g_slist_append(l, preset);
> +
> +               len -= preset->len;
> +               p += sizeof(struct audio_preset) + preset->len;

It would be better to explicitly use uint8_t pointer for presets
buffer since this will work only as long as sizeof(struct
audio_preset) is 1.


Andrzej

^ permalink raw reply

* [PATCH] Bluetooth: BCSP fails to ACK re-transmitted frames from the peer
From: Dean_Jenkins @ 2014-01-12 16:27 UTC (permalink / raw)
  To: linux-bluetooth, marcel, gustavo; +Cc: Dean_Jenkins

From: Dean Jenkins <djenkins@mentor.com>

Send an ACK frame with the current txack value in response to
every received reliable frame unless a TX reliable frame is being
sent. This modification allows re-transmitted frames from the remote
peer to be acknowledged rather than ignored. It means that the remote
peer knows which frame number to start re-transmitting from.

Without this modification, the recovery time to a missing frame
from the remote peer was unnecessarily being extended because the
headers of the out of order reliable frames were being discarded rather
than being processed. The frame headers of received frames will
indicate whether the local peer's transmissions have been
acknowledged by the remote peer. Therefore, the local peer may
unnecessarily re-transmit despite the remote peer already indicating
that the frame had been acknowledged in out of order reliable frame.

Signed-off-by: Dean Jenkins <djenkins@mentor.com>
---
 drivers/bluetooth/hci_bcsp.c | 94 ++++++++++++++++++++++++++++----------------
 1 file changed, 60 insertions(+), 34 deletions(-)

diff --git a/drivers/bluetooth/hci_bcsp.c b/drivers/bluetooth/hci_bcsp.c
index 0bc87f7..449de29 100644
--- a/drivers/bluetooth/hci_bcsp.c
+++ b/drivers/bluetooth/hci_bcsp.c
@@ -473,13 +473,30 @@ static inline void bcsp_unslip_one_byte(struct bcsp_struct *bcsp, unsigned char
 static void bcsp_complete_rx_pkt(struct hci_uart *hu)
 {
 	struct bcsp_struct *bcsp = hu->priv;
-	int pass_up;
+	int pass_up = 0;
 
 	if (bcsp->rx_skb->data[0] & 0x80) {	/* reliable pkt */
 		BT_DBG("Received seqno %u from card", bcsp->rxseq_txack);
-		bcsp->rxseq_txack++;
-		bcsp->rxseq_txack %= 0x8;
-		bcsp->txack_req    = 1;
+
+		/* check the rx sequence number is as expected */
+		if ((bcsp->rx_skb->data[0] & 0x07) == bcsp->rxseq_txack) {
+			bcsp->rxseq_txack++;
+			bcsp->rxseq_txack %= 0x8;
+		} else {
+			/*
+			 * handle re-transmitted packet or
+			 * when packet was missed
+			 */
+			BT_ERR("Out-of-order packet arrived, got %u expected %u",
+				bcsp->rx_skb->data[0] & 0x07,
+				bcsp->rxseq_txack);
+
+			/* do not process out-of-order packet payload */
+			pass_up = 2;
+		}
+
+		/* send current txack value to all recieved reliable packets */
+		bcsp->txack_req = 1;
 
 		/* If needed, transmit an ack pkt */
 		hci_uart_tx_wakeup(hu);
@@ -488,26 +505,35 @@ static void bcsp_complete_rx_pkt(struct hci_uart *hu)
 	bcsp->rxack = (bcsp->rx_skb->data[0] >> 3) & 0x07;
 	BT_DBG("Request for pkt %u from card", bcsp->rxack);
 
+	/*
+	 * handle recieved ACK indications,
+	 * including those from out-of-order packets
+	 */
 	bcsp_pkt_cull(bcsp);
-	if ((bcsp->rx_skb->data[1] & 0x0f) == 6 &&
-			bcsp->rx_skb->data[0] & 0x80) {
-		bt_cb(bcsp->rx_skb)->pkt_type = HCI_ACLDATA_PKT;
-		pass_up = 1;
-	} else if ((bcsp->rx_skb->data[1] & 0x0f) == 5 &&
-			bcsp->rx_skb->data[0] & 0x80) {
-		bt_cb(bcsp->rx_skb)->pkt_type = HCI_EVENT_PKT;
-		pass_up = 1;
-	} else if ((bcsp->rx_skb->data[1] & 0x0f) == 7) {
-		bt_cb(bcsp->rx_skb)->pkt_type = HCI_SCODATA_PKT;
-		pass_up = 1;
-	} else if ((bcsp->rx_skb->data[1] & 0x0f) == 1 &&
-			!(bcsp->rx_skb->data[0] & 0x80)) {
-		bcsp_handle_le_pkt(hu);
-		pass_up = 0;
-	} else
-		pass_up = 0;
-
-	if (!pass_up) {
+
+	if (pass_up != 2) {
+		if ((bcsp->rx_skb->data[1] & 0x0f) == 6 &&
+				bcsp->rx_skb->data[0] & 0x80) {
+			bt_cb(bcsp->rx_skb)->pkt_type = HCI_ACLDATA_PKT;
+			pass_up = 1;
+		} else if ((bcsp->rx_skb->data[1] & 0x0f) == 5 &&
+				bcsp->rx_skb->data[0] & 0x80) {
+			bt_cb(bcsp->rx_skb)->pkt_type = HCI_EVENT_PKT;
+			pass_up = 1;
+		} else if ((bcsp->rx_skb->data[1] & 0x0f) == 7) {
+			bt_cb(bcsp->rx_skb)->pkt_type = HCI_SCODATA_PKT;
+			pass_up = 1;
+		} else if ((bcsp->rx_skb->data[1] & 0x0f) == 1 &&
+				!(bcsp->rx_skb->data[0] & 0x80)) {
+			bcsp_handle_le_pkt(hu);
+			pass_up = 0;
+		} else
+			pass_up = 0;
+	}
+
+	switch (pass_up) {
+	case 0:
+	{
 		struct hci_event_hdr hdr;
 		u8 desc = (bcsp->rx_skb->data[1] & 0x0f);
 
@@ -532,11 +558,21 @@ static void bcsp_complete_rx_pkt(struct hci_uart *hu)
 			}
 		} else
 			kfree_skb(bcsp->rx_skb);
-	} else {
+		break;
+	}
+	case 1:
 		/* Pull out BCSP hdr */
 		skb_pull(bcsp->rx_skb, 4);
 
 		hci_recv_frame(hu->hdev, bcsp->rx_skb);
+		break;
+	default:
+		/*
+		 * ignore packet payload of already ACKed re-transmitted
+		 * packets or when a packet was missed in the BCSP window
+		 */
+		kfree_skb(bcsp->rx_skb);
+		break;
 	}
 
 	bcsp->rx_state = BCSP_W4_PKT_DELIMITER;
@@ -582,16 +618,6 @@ static int bcsp_recv(struct hci_uart *hu, void *data, int count)
 				bcsp->rx_count = 0;
 				continue;
 			}
-			if (bcsp->rx_skb->data[0] & 0x80	/* reliable pkt */
-			    		&& (bcsp->rx_skb->data[0] & 0x07) != bcsp->rxseq_txack) {
-				BT_ERR ("Out-of-order packet arrived, got %u expected %u",
-					bcsp->rx_skb->data[0] & 0x07, bcsp->rxseq_txack);
-
-				kfree_skb(bcsp->rx_skb);
-				bcsp->rx_state = BCSP_W4_PKT_DELIMITER;
-				bcsp->rx_count = 0;
-				continue;
-			}
 			bcsp->rx_state = BCSP_W4_DATA;
 			bcsp->rx_count = (bcsp->rx_skb->data[1] >> 4) + 
 					(bcsp->rx_skb->data[2] << 4);	/* May be 0 */
-- 
1.8.1.5

^ permalink raw reply related

* [PATCH] Bluetooth: Avoid use of session socket after the session gets freed
From: Dean_Jenkins @ 2014-01-12 13:20 UTC (permalink / raw)
  To: linux-bluetooth, marcel, gustavo; +Cc: Dean_Jenkins, vitaly_kuzmichev

From: Vitaly Kuzmichev <vitaly_kuzmichev@mentor.com>

The commits 08c30aca9e698faddebd34f81e1196295f9dc063 "Bluetooth: Remove
RFCOMM session refcnt" and 8ff52f7d04d9cc31f1e81dcf9a2ba6335ed34905
"Bluetooth: Return RFCOMM session ptrs to avoid freed session"
allow rfcomm_recv_ua and rfcomm_session_close to delete the session
(and free the corresponding socket) and propagate NULL session pointer
to the upper callers.

Additional fix is required to terminate the loop in rfcomm_process_rx
function to avoid use of freed 'sk' memory.

The issue is only reproducible with kernel option CONFIG_PAGE_POISONING
enabled making freed memory being changed and filled up with fixed char
value used to unmask use-after-free issues.

Signed-off-by: Vitaly Kuzmichev <Vitaly_Kuzmichev@mentor.com>
Acked-by: Dean Jenkins <Dean_Jenkins@mentor.com>
---
 net/bluetooth/rfcomm/core.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c
index facd8a7..5632146 100644
--- a/net/bluetooth/rfcomm/core.c
+++ b/net/bluetooth/rfcomm/core.c
@@ -1857,7 +1857,7 @@ static struct rfcomm_session *rfcomm_process_rx(struct rfcomm_session *s)
 	BT_DBG("session %p state %ld qlen %d", s, s->state, skb_queue_len(&sk->sk_receive_queue));
 
 	/* Get data directly from socket receive queue without copying it. */
-	while ((skb = skb_dequeue(&sk->sk_receive_queue))) {
+	while (s && (skb = skb_dequeue(&sk->sk_receive_queue))) {
 		skb_orphan(skb);
 		if (!skb_linearize(skb))
 			s = rfcomm_recv_frame(s, skb);
-- 
1.8.1.5

^ permalink raw reply related

* [PATCH] Bluetooth: Add debugfs entry to show Secure Connections Only mode
From: Marcel Holtmann @ 2014-01-11 22:20 UTC (permalink / raw)
  To: linux-bluetooth

For debugging purposes of Secure Connection Only support a simple
debugfs entry is used to indicate if this mode is active or not.

Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
---
 net/bluetooth/hci_core.c | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 499ec1b1095d..369d30750417 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -461,6 +461,24 @@ static const struct file_operations force_sc_support_fops = {
 	.llseek		= default_llseek,
 };
 
+static ssize_t sc_only_mode_read(struct file *file, char __user *user_buf,
+				 size_t count, loff_t *ppos)
+{
+	struct hci_dev *hdev = file->private_data;
+	char buf[3];
+
+	buf[0] = test_bit(HCI_SC_ONLY, &hdev->dev_flags) ? 'Y': 'N';
+	buf[1] = '\n';
+	buf[2] = '\0';
+	return simple_read_from_buffer(user_buf, count, ppos, buf, 2);
+}
+
+static const struct file_operations sc_only_mode_fops = {
+	.open		= simple_open,
+	.read		= sc_only_mode_read,
+	.llseek		= default_llseek,
+};
+
 static int idle_timeout_set(void *data, u64 val)
 {
 	struct hci_dev *hdev = data;
@@ -1491,6 +1509,8 @@ static int __hci_init(struct hci_dev *hdev)
 				    hdev, &ssp_debug_mode_fops);
 		debugfs_create_file("force_sc_support", 0644, hdev->debugfs,
 				    hdev, &force_sc_support_fops);
+		debugfs_create_file("sc_only_mode", 0444, hdev->debugfs,
+				    hdev, &sc_only_mode_fops);
 	}
 
 	if (lmp_sniff_capable(hdev)) {
-- 
1.8.4.2


^ permalink raw reply related

* [PATCH] Bluetooth: Add management command for Secure Connection Only mode
From: Marcel Holtmann @ 2014-01-11 22:05 UTC (permalink / raw)
  To: linux-bluetooth

With support for Secure Connections it is possible to switch the
controller into a mode that is called Secure Connections Only. In
this mode only security level 4 connections are allowed (with the
exception of security level 0 approved services).

This patch just introduces the management command and setting of the
right internal flags to enable this mode. It does not yet enforce it.

Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
---
 include/net/bluetooth/hci.h |  1 +
 net/bluetooth/mgmt.c        | 36 +++++++++++++++++++++++++-----------
 2 files changed, 26 insertions(+), 11 deletions(-)

diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index 2bc19881e250..aed74d1bd206 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -124,6 +124,7 @@ enum {
 	HCI_LE_SCAN,
 	HCI_SSP_ENABLED,
 	HCI_SC_ENABLED,
+	HCI_SC_ONLY,
 	HCI_HS_ENABLED,
 	HCI_LE_ENABLED,
 	HCI_ADVERTISING,
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 4b6034fcc902..a1d42ae6f8fd 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -4040,7 +4040,7 @@ static int set_secure_conn(struct sock *sk, struct hci_dev *hdev,
 {
 	struct mgmt_mode *cp = data;
 	struct pending_cmd *cmd;
-	u8 status;
+	u8 val, status;
 	int err;
 
 	BT_DBG("request for %s", hdev->name);
@@ -4055,7 +4055,7 @@ static int set_secure_conn(struct sock *sk, struct hci_dev *hdev,
 		return cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
 				  MGMT_STATUS_NOT_SUPPORTED);
 
-	if (cp->val != 0x00 && cp->val != 0x01)
+	if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
 		return cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
 				  MGMT_STATUS_INVALID_PARAMS);
 
@@ -4064,12 +4064,16 @@ static int set_secure_conn(struct sock *sk, struct hci_dev *hdev,
 	if (!hdev_is_powered(hdev)) {
 		bool changed;
 
-		if (cp->val)
+		if (cp->val) {
 			changed = !test_and_set_bit(HCI_SC_ENABLED,
 						    &hdev->dev_flags);
-		else
+			if (cp->val == 0x02)
+				set_bit(HCI_SC_ONLY, &hdev->dev_flags);
+		} else {
 			changed = test_and_clear_bit(HCI_SC_ENABLED,
 						     &hdev->dev_flags);
+			clear_bit(HCI_SC_ONLY, &hdev->dev_flags);
+		}
 
 		err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
 		if (err < 0)
@@ -4087,7 +4091,9 @@ static int set_secure_conn(struct sock *sk, struct hci_dev *hdev,
 		goto failed;
 	}
 
-	if (!!cp->val == test_bit(HCI_SC_ENABLED, &hdev->dev_flags)) {
+	val = !!cp->val;
+
+	if (val == test_bit(HCI_SC_ENABLED, &hdev->dev_flags)) {
 		err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
 		goto failed;
 	}
@@ -4098,12 +4104,15 @@ static int set_secure_conn(struct sock *sk, struct hci_dev *hdev,
 		goto failed;
 	}
 
-	err = hci_send_cmd(hdev, HCI_OP_WRITE_SC_SUPPORT, 1, &cp->val);
+	err = hci_send_cmd(hdev, HCI_OP_WRITE_SC_SUPPORT, 1, &val);
 	if (err < 0) {
 		mgmt_pending_remove(cmd);
 		goto failed;
 	}
 
+	if (cp->val == 0x02)
+		set_bit(HCI_SC_ONLY, &hdev->dev_flags);
+
 failed:
 	hci_dev_unlock(hdev);
 	return err;
@@ -5029,19 +5038,24 @@ void mgmt_sc_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
 	if (status) {
 		u8 mgmt_err = mgmt_status(status);
 
-		if (enable && test_and_clear_bit(HCI_SC_ENABLED,
-						 &hdev->dev_flags))
-			new_settings(hdev, NULL);
+		if (enable) {
+			if (test_and_clear_bit(HCI_SC_ENABLED,
+					       &hdev->dev_flags))
+				new_settings(hdev, NULL);
+			clear_bit(HCI_SC_ONLY, &hdev->dev_flags);
+		}
 
 		mgmt_pending_foreach(MGMT_OP_SET_SECURE_CONN, hdev,
 				     cmd_status_rsp, &mgmt_err);
 		return;
 	}
 
-	if (enable)
+	if (enable) {
 		changed = !test_and_set_bit(HCI_SC_ENABLED, &hdev->dev_flags);
-	else
+	} else {
 		changed = test_and_clear_bit(HCI_SC_ENABLED, &hdev->dev_flags);
+		clear_bit(HCI_SC_ONLY, &hdev->dev_flags);
+	}
 
 	mgmt_pending_foreach(MGMT_OP_SET_SECURE_CONN, hdev,
 			     settings_rsp, &match);
-- 
1.8.4.2


^ permalink raw reply related

* [PATCH 2/2] Bluetooth: Handle security level 4 for RFCOMM connections
From: Marcel Holtmann @ 2014-01-11 21:44 UTC (permalink / raw)
  To: linux-bluetooth

With the introduction of security level 4, the RFCOMM sockets need to
be made aware of this new level. This change ensures that the pairing
requirements are set correctly for these connections.

Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
---
 include/net/bluetooth/rfcomm.h |  1 +
 net/bluetooth/rfcomm/core.c    |  4 +++-
 net/bluetooth/rfcomm/sock.c    | 12 +++++++++++-
 3 files changed, 15 insertions(+), 2 deletions(-)

diff --git a/include/net/bluetooth/rfcomm.h b/include/net/bluetooth/rfcomm.h
index 486213a1aed8..c312cfc4e922 100644
--- a/include/net/bluetooth/rfcomm.h
+++ b/include/net/bluetooth/rfcomm.h
@@ -295,6 +295,7 @@ struct rfcomm_conninfo {
 #define RFCOMM_LM_TRUSTED	0x0008
 #define RFCOMM_LM_RELIABLE	0x0010
 #define RFCOMM_LM_SECURE	0x0020
+#define RFCOMM_LM_FIPS		0x0040
 
 #define rfcomm_pi(sk) ((struct rfcomm_pinfo *) sk)
 
diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c
index facd8a79c038..ba115d472f7b 100644
--- a/net/bluetooth/rfcomm/core.c
+++ b/net/bluetooth/rfcomm/core.c
@@ -216,6 +216,7 @@ static int rfcomm_check_security(struct rfcomm_dlc *d)
 
 	switch (d->sec_level) {
 	case BT_SECURITY_HIGH:
+	case BT_SECURITY_FIPS:
 		auth_type = HCI_AT_GENERAL_BONDING_MITM;
 		break;
 	case BT_SECURITY_MEDIUM:
@@ -2085,7 +2086,8 @@ static void rfcomm_security_cfm(struct hci_conn *conn, u8 status, u8 encrypt)
 				set_bit(RFCOMM_SEC_PENDING, &d->flags);
 				rfcomm_dlc_set_timer(d, RFCOMM_AUTH_TIMEOUT);
 				continue;
-			} else if (d->sec_level == BT_SECURITY_HIGH) {
+			} else if (d->sec_level == BT_SECURITY_HIGH ||
+				   d->sec_level == BT_SECURITY_FIPS) {
 				set_bit(RFCOMM_ENC_DROP, &d->flags);
 				continue;
 			}
diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c
index 3c2d3e4aa2f5..fb8158af1f39 100644
--- a/net/bluetooth/rfcomm/sock.c
+++ b/net/bluetooth/rfcomm/sock.c
@@ -648,6 +648,11 @@ static int rfcomm_sock_setsockopt_old(struct socket *sock, int optname, char __u
 			break;
 		}
 
+		if (opt & RFCOMM_LM_FIPS) {
+			err = -EINVAL;
+			break;
+		}
+
 		if (opt & RFCOMM_LM_AUTH)
 			rfcomm_pi(sk)->sec_level = BT_SECURITY_LOW;
 		if (opt & RFCOMM_LM_ENCRYPT)
@@ -762,7 +767,11 @@ static int rfcomm_sock_getsockopt_old(struct socket *sock, int optname, char __u
 			break;
 		case BT_SECURITY_HIGH:
 			opt = RFCOMM_LM_AUTH | RFCOMM_LM_ENCRYPT |
-							RFCOMM_LM_SECURE;
+			      RFCOMM_LM_SECURE;
+			break;
+		case BT_SECURITY_FIPS:
+			opt = RFCOMM_LM_AUTH | RFCOMM_LM_ENCRYPT |
+			      RFCOMM_LM_SECURE | RFCOMM_LM_FIPS;
 			break;
 		default:
 			opt = 0;
@@ -774,6 +783,7 @@ static int rfcomm_sock_getsockopt_old(struct socket *sock, int optname, char __u
 
 		if (put_user(opt, (u32 __user *) optval))
 			err = -EFAULT;
+
 		break;
 
 	case RFCOMM_CONNINFO:
-- 
1.8.4.2


^ permalink raw reply related

* [PATCH 1/2] Bluetooth: Handle security level 4 for L2CAP connections
From: Marcel Holtmann @ 2014-01-11 21:44 UTC (permalink / raw)
  To: linux-bluetooth

With the introduction of security level 4, the L2CAP sockets need to
be made aware of this new level. This change ensures that the pairing
requirements are set correctly for these connections.

Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
---
 include/net/bluetooth/l2cap.h |  1 +
 net/bluetooth/l2cap_core.c    | 11 ++++++++---
 net/bluetooth/l2cap_sock.c    | 10 ++++++++++
 3 files changed, 19 insertions(+), 3 deletions(-)

diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index dbc4a89984ca..c695083eee2b 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -91,6 +91,7 @@ struct l2cap_conninfo {
 #define L2CAP_LM_TRUSTED	0x0008
 #define L2CAP_LM_RELIABLE	0x0010
 #define L2CAP_LM_SECURE		0x0020
+#define L2CAP_LM_FIPS		0x0040
 
 /* L2CAP command codes */
 #define L2CAP_COMMAND_REJ	0x01
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index b0ad2c752d73..3f0dd552cb2b 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -737,6 +737,7 @@ static inline u8 l2cap_get_auth_type(struct l2cap_chan *chan)
 	case L2CAP_CHAN_RAW:
 		switch (chan->sec_level) {
 		case BT_SECURITY_HIGH:
+		case BT_SECURITY_FIPS:
 			return HCI_AT_DEDICATED_BONDING_MITM;
 		case BT_SECURITY_MEDIUM:
 			return HCI_AT_DEDICATED_BONDING;
@@ -749,7 +750,8 @@ static inline u8 l2cap_get_auth_type(struct l2cap_chan *chan)
 			if (chan->sec_level == BT_SECURITY_LOW)
 				chan->sec_level = BT_SECURITY_SDP;
 		}
-		if (chan->sec_level == BT_SECURITY_HIGH)
+		if (chan->sec_level == BT_SECURITY_HIGH ||
+		    chan->sec_level == BT_SECURITY_FIPS)
 			return HCI_AT_NO_BONDING_MITM;
 		else
 			return HCI_AT_NO_BONDING;
@@ -759,7 +761,8 @@ static inline u8 l2cap_get_auth_type(struct l2cap_chan *chan)
 			if (chan->sec_level == BT_SECURITY_LOW)
 				chan->sec_level = BT_SECURITY_SDP;
 
-			if (chan->sec_level == BT_SECURITY_HIGH)
+			if (chan->sec_level == BT_SECURITY_HIGH ||
+			    chan->sec_level == BT_SECURITY_FIPS)
 				return HCI_AT_NO_BONDING_MITM;
 			else
 				return HCI_AT_NO_BONDING;
@@ -768,6 +771,7 @@ static inline u8 l2cap_get_auth_type(struct l2cap_chan *chan)
 	default:
 		switch (chan->sec_level) {
 		case BT_SECURITY_HIGH:
+		case BT_SECURITY_FIPS:
 			return HCI_AT_GENERAL_BONDING_MITM;
 		case BT_SECURITY_MEDIUM:
 			return HCI_AT_GENERAL_BONDING;
@@ -7206,7 +7210,8 @@ static inline void l2cap_check_encryption(struct l2cap_chan *chan, u8 encrypt)
 	if (encrypt == 0x00) {
 		if (chan->sec_level == BT_SECURITY_MEDIUM) {
 			__set_chan_timer(chan, L2CAP_ENC_TIMEOUT);
-		} else if (chan->sec_level == BT_SECURITY_HIGH)
+		} else if (chan->sec_level == BT_SECURITY_HIGH ||
+			   chan->sec_level == BT_SECURITY_FIPS)
 			l2cap_chan_close(chan, ECONNREFUSED);
 	} else {
 		if (chan->sec_level == BT_SECURITY_MEDIUM)
diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
index 20ef748b2906..4aa6704f0b33 100644
--- a/net/bluetooth/l2cap_sock.c
+++ b/net/bluetooth/l2cap_sock.c
@@ -432,6 +432,10 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname,
 			opt = L2CAP_LM_AUTH | L2CAP_LM_ENCRYPT |
 			      L2CAP_LM_SECURE;
 			break;
+		case BT_SECURITY_FIPS:
+			opt = L2CAP_LM_AUTH | L2CAP_LM_ENCRYPT |
+			      L2CAP_LM_SECURE | L2CAP_LM_FIPS;
+			break;
 		default:
 			opt = 0;
 			break;
@@ -445,6 +449,7 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname,
 
 		if (put_user(opt, (u32 __user *) optval))
 			err = -EFAULT;
+
 		break;
 
 	case L2CAP_CONNINFO:
@@ -699,6 +704,11 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname,
 			break;
 		}
 
+		if (opt & L2CAP_LM_FIPS) {
+			err = -EINVAL;
+			break;
+		}
+
 		if (opt & L2CAP_LM_AUTH)
 			chan->sec_level = BT_SECURITY_LOW;
 		if (opt & L2CAP_LM_ENCRYPT)
-- 
1.8.4.2


^ permalink raw reply related

* [PATCH] Bluetooth: Introduce requirements for security level 4
From: Marcel Holtmann @ 2014-01-11 21:03 UTC (permalink / raw)
  To: linux-bluetooth

The security level 4 is a new strong security requirement that is based
around 128-bit equivalent strength for link and encryption keys required
using FIPS approved algorithms. Which means that E0, SAFER+ and P-192
are not allowed. Only connections created with P-256 resulting from
using Secure Connections support are allowed.

This security level needs to be enforced when Secure Connection Only
mode is enabled for a controller or a service requires FIPS compliant
strong security. Currently it is not possible to enable either of
these two cases. This patch just puts in the foundation for being
able to handle security level 4 in the future.

It should be noted that devices or services with security level 4
requirement can only communicate using Bluetooth 4.1 controllers
with support for Secure Connections. There is no backward compatibilty
if used with older hardware.

Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
---
 include/net/bluetooth/bluetooth.h |  1 +
 net/bluetooth/hci_conn.c          | 18 +++++++++++++-----
 2 files changed, 14 insertions(+), 5 deletions(-)

diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h
index f4f9ee466791..904777c1cd24 100644
--- a/include/net/bluetooth/bluetooth.h
+++ b/include/net/bluetooth/bluetooth.h
@@ -65,6 +65,7 @@ struct bt_security {
 #define BT_SECURITY_LOW		1
 #define BT_SECURITY_MEDIUM	2
 #define BT_SECURITY_HIGH	3
+#define BT_SECURITY_FIPS	4
 
 #define BT_DEFER_SETUP	7
 
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index cf96b3438a91..0266bd8e4913 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -800,10 +800,17 @@ int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type)
 	if (!(conn->link_mode & HCI_LM_AUTH))
 		goto auth;
 
-	/* An authenticated combination key has sufficient security for any
-	   security level. */
-	if (conn->key_type == HCI_LK_AUTH_COMBINATION_P192 ||
-	    conn->key_type == HCI_LK_AUTH_COMBINATION_P256)
+	/* An authenticated FIPS approved combination key has sufficient
+	 * security for security level 4. */
+	if (conn->key_type == HCI_LK_AUTH_COMBINATION_P256 &&
+	    sec_level == BT_SECURITY_FIPS)
+		goto encrypt;
+
+	/* An authenticated combination key has sufficient security for
+	   security level 3. */
+	if ((conn->key_type == HCI_LK_AUTH_COMBINATION_P192 ||
+	     conn->key_type == HCI_LK_AUTH_COMBINATION_P256) &&
+	    sec_level == BT_SECURITY_HIGH)
 		goto encrypt;
 
 	/* An unauthenticated combination key has sufficient security for
@@ -818,7 +825,8 @@ int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type)
 	   is generated using maximum PIN code length (16).
 	   For pre 2.1 units. */
 	if (conn->key_type == HCI_LK_COMBINATION &&
-	    (sec_level != BT_SECURITY_HIGH || conn->pin_length == 16))
+	    (sec_level == BT_SECURITY_MEDIUM || sec_level == BT_SECURITY_LOW ||
+	     conn->pin_length == 16))
 		goto encrypt;
 
 auth:
-- 
1.8.4.2


^ permalink raw reply related

* [PATCH] Bluetooth: Track Secure Connections support of remote devices
From: Marcel Holtmann @ 2014-01-11 20:39 UTC (permalink / raw)
  To: linux-bluetooth

It is important to know if Secure Connections support has been enabled
for a given remote device. The information is provided in the remote
host features page. So track this information and provide a simple
helper function to extract the status.

Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
---
 include/net/bluetooth/hci_core.h | 8 ++++++++
 net/bluetooth/hci_event.c        | 3 +++
 2 files changed, 11 insertions(+)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 66e96ebffe97..8d225e4ea2ce 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -448,6 +448,7 @@ enum {
 	HCI_CONN_LE_SMP_PEND,
 	HCI_CONN_MGMT_CONNECTED,
 	HCI_CONN_SSP_ENABLED,
+	HCI_CONN_SC_ENABLED,
 	HCI_CONN_POWER_SAVE,
 	HCI_CONN_REMOTE_OOB,
 	HCI_CONN_6LOWPAN,
@@ -460,6 +461,13 @@ static inline bool hci_conn_ssp_enabled(struct hci_conn *conn)
 	       test_bit(HCI_CONN_SSP_ENABLED, &conn->flags);
 }
 
+static inline bool hci_conn_sc_enabled(struct hci_conn *conn)
+{
+	struct hci_dev *hdev = conn->hdev;
+	return test_bit(HCI_SC_ENABLED, &hdev->dev_flags) &&
+	       test_bit(HCI_CONN_SC_ENABLED, &conn->flags);
+}
+
 static inline void hci_conn_hash_add(struct hci_dev *hdev, struct hci_conn *c)
 {
 	struct hci_conn_hash *h = &hdev->conn_hash;
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index da1eca1c43db..8c44bbe19add 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -2898,6 +2898,9 @@ static void hci_remote_ext_features_evt(struct hci_dev *hdev,
 			 * features do not indicate SSP support */
 			clear_bit(HCI_CONN_SSP_ENABLED, &conn->flags);
 		}
+
+		if (ev->features[0] & LMP_HOST_SC)
+			set_bit(HCI_CONN_SC_ENABLED, &conn->flags);
 	}
 
 	if (conn->state != BT_CONFIG)
-- 
1.8.4.2


^ permalink raw reply related

* Re: [PATCH BlueZ 1/6] audio/A2DP: Add implemention of audio Open command
From: Szymon Janc @ 2014-01-11 19:14 UTC (permalink / raw)
  To: Luiz Augusto von Dentz; +Cc: linux-bluetooth
In-Reply-To: <1389435216-29040-1-git-send-email-luiz.dentz@gmail.com>

Hi Luiz,

On Saturday 11 January 2014 12:13:31 Luiz Augusto von Dentz wrote:
> From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
> 
> ---
>  android/a2dp.c | 159
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed,
> 158 insertions(+), 1 deletion(-)
> 
> diff --git a/android/a2dp.c b/android/a2dp.c
> index b59c53d..28b7406 100644
> --- a/android/a2dp.c
> +++ b/android/a2dp.c
> @@ -52,9 +52,23 @@
> 
>  static GIOChannel *server = NULL;
>  static GSList *devices = NULL;
> +static GSList *endpoints = NULL;
>  static bdaddr_t adapter_addr;
>  static uint32_t record_id = 0;
> 
> +struct a2dp_preset {
> +	void *data;
> +	int8_t len;
> +};
> +
> +struct a2dp_endpoint {
> +	uint8_t id;
> +	uint8_t codec;
> +	struct avdtp_local_sep *sep;
> +	struct a2dp_preset *caps;
> +	GSList *presets;
> +};
> +
>  struct a2dp_device {
>  	bdaddr_t	dst;
>  	uint8_t		state;
> @@ -70,6 +84,29 @@ static int device_cmp(gconstpointer s, gconstpointer
> user_data) return bacmp(&dev->dst, dst);
>  }
> 
> +static void preset_free(void *data)
> +{
> +	struct a2dp_preset *preset = data;
> +
> +	g_free(preset->data);
> +	g_free(preset);
> +}
> +
> +static void unregister_endpoint(void *data)
> +{
> +	struct a2dp_endpoint *endpoint = data;
> +
> +	if (endpoint->sep)
> +		avdtp_unregister_sep(endpoint->sep);
> +
> +	if (endpoint->caps)
> +		preset_free(endpoint->caps);
> +
> +	g_slist_free_full(endpoint->presets, preset_free);
> +
> +	g_free(endpoint);
> +}
> +
>  static void a2dp_device_free(struct a2dp_device *dev)
>  {
>  	if (dev->session)
> @@ -354,10 +391,127 @@ static sdp_record_t *a2dp_record(void)
>  	return record;
>  }
> 
> +static gboolean sep_getcap_ind(struct avdtp *session,
> +					struct avdtp_local_sep *sep,
> +					GSList **caps, uint8_t *err,
> +					void *user_data)
> +{
> +	struct a2dp_endpoint *endpoint = user_data;
> +	struct a2dp_preset *cap = endpoint->presets->data;
> +	struct avdtp_service_capability *media_transport, *media_codec;
> +	struct avdtp_media_codec_capability *codec_caps;
> +
> +	*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));

Shouldn't this be cap->len instead of sizeof(cap) ?

> +	codec_caps->media_type = AVDTP_MEDIA_TYPE_AUDIO;
> +	codec_caps->media_codec_type = endpoint->codec;
> +	memcpy(codec_caps->data, cap->data, cap->len);
> +
> +	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 uint8_t register_endpoint(const uint8_t *uuid, uint8_t codec,
> +							GSList *presets)
> +{
> +	struct a2dp_endpoint *endpoint;
> +
> +	/* FIXME: Add proper check for uuid */
> +
> +	endpoint = g_new0(struct a2dp_endpoint, 1);
> +	endpoint->id = g_slist_length(endpoints) + 1;
> +	endpoint->codec = codec;
> +	endpoint->sep = avdtp_register_sep(AVDTP_SEP_TYPE_SOURCE,
> +						AVDTP_MEDIA_TYPE_AUDIO,
> +						codec, FALSE, &sep_ind, NULL,
> +						endpoint);
> +	endpoint->caps = g_slist_nth_data(presets->data, 0);
> +	endpoint->presets = g_slist_copy(g_slist_nth(presets, 1));
> +
> +	endpoints = g_slist_append(endpoints, endpoint);
> +
> +	return endpoint->id;
> +}
> +
> +static GSList *parse_presets(const struct audio_preset *p, uint8_t count,
> +								uint16_t len)
> +{
> +	GSList *l = NULL;
> +	uint8_t i;
> +
> +	for (i = 0; count > i; i++) {
> +		struct a2dp_preset *preset;
> +
> +		if (len < sizeof(struct audio_preset)) {

If Audio IPC command is malformed we should discard it, free list and return 
NULL.

(I'm still not sure how daemon should behave if there is Audio IPC error, 
possibly closing IPC socket and reset a2dp service state?)

> +			DBG("Invalid preset index %u", i);
> +			break;
> +		}
> +
> +		len -= sizeof(struct audio_preset);
> +		if (len == 0 || len < p->len) {
> +			DBG("Invalid preset size of %u for index %u", len, i);
> +			break;
> +		}
> +
> +		preset = g_new0(struct a2dp_preset, 1);
> +		preset->len = p->len;
> +		preset->data = g_memdup(p->data, preset->len);
> +		l = g_slist_append(l, preset);
> +
> +		len -= preset->len;
> +		p += sizeof(struct audio_preset) + preset->len;
> +	}
> +
> +	return l;
> +}
> +
>  static void bt_audio_open(const void *buf, uint16_t len)
>  {
> -	DBG("Not Implemented");
> +	const struct audio_cmd_open *cmd = buf;
> +	struct audio_rsp_open rsp;
> +	GSList *presets;
> +
> +	DBG("");
> 
> +	if (cmd->presets == 0) {
> +		error("No audio presets found");
> +		goto failed;
> +	}
> +
> +	presets = parse_presets(cmd->preset, cmd->presets, len - sizeof(*cmd));
> +	if (!presets) {
> +		error("No audio presets found");
> +		goto failed;
> +	}
> +
> +	rsp.id = register_endpoint(cmd->uuid, cmd->codec, presets);
> +	g_slist_free(presets);
> +
> +	if (rsp.id == 0) {
> +		error("Unable to register endpoint");
> +		goto failed;
> +	}
> +
> +	audio_ipc_send_rsp_full(AUDIO_OP_OPEN, sizeof(rsp), &rsp, -1);
> +
> +	return;
> +
> +failed:
>  	audio_ipc_send_rsp(AUDIO_OP_OPEN, AUDIO_STATUS_FAILED);
>  }
> 
> @@ -471,6 +625,9 @@ void bt_a2dp_unregister(void)
>  {
>  	DBG("");
> 
> +	g_slist_free_full(endpoints, unregister_endpoint);
> +	endpoints = NULL;
> +
>  	g_slist_foreach(devices, a2dp_device_disconnected, NULL);
>  	devices = NULL;

-- 
Szymon K. Janc
szymon.janc@gmail.com

^ permalink raw reply

* Re: [PATCH BlueZ 01/11] attrib: Modify gatt_cb_t signature
From: Johan Hedberg @ 2014-01-11 16:56 UTC (permalink / raw)
  To: Anderson Lizardo; +Cc: linux-bluetooth
In-Reply-To: <1389415647-25831-1-git-send-email-anderson.lizardo@openbossa.org>

Hi Lizardo,

On Sat, Jan 11, 2014, Anderson Lizardo wrote:
> Use standard C types instead of GLib ones (which are unnecessary here)
> and move the "status" parameter to the first position, so it is
> consistent with other callbacks.
> ---
>  attrib/gatt.c                        | 10 +++++-----
>  attrib/gatt.h                        |  2 +-
>  attrib/gatttool.c                    |  9 ++++-----
>  attrib/interactive.c                 |  9 ++++-----
>  profiles/cyclingspeed/cyclingspeed.c |  2 +-
>  profiles/deviceinfo/deviceinfo.c     |  4 ++--
>  profiles/gatt/gas.c                  |  4 ++--
>  profiles/heartrate/heartrate.c       |  2 +-
>  profiles/input/hog.c                 |  6 +++---
>  profiles/proximity/monitor.c         | 12 ++++++------
>  profiles/scanparam/scan.c            |  7 +++----
>  profiles/thermometer/thermometer.c   |  4 ++--
>  src/device.c                         |  5 ++---
>  13 files changed, 36 insertions(+), 40 deletions(-)

All patches in this set have been applied. Thanks.

Johan

^ permalink raw reply

* [PATCH BlueZ 6/6] audio/A2DP: Add implemention of audio Suspend Stream command
From: Luiz Augusto von Dentz @ 2014-01-11 10:13 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1389435216-29040-1-git-send-email-luiz.dentz@gmail.com>

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

---
 android/a2dp.c | 23 ++++++++++++++++++++++-
 1 file changed, 22 insertions(+), 1 deletion(-)

diff --git a/android/a2dp.c b/android/a2dp.c
index 2d886e9..8d7d554 100644
--- a/android/a2dp.c
+++ b/android/a2dp.c
@@ -805,8 +805,29 @@ failed:
 
 static void bt_stream_suspend(const void *buf, uint16_t len)
 {
-	DBG("Not Implemented");
+	const struct audio_cmd_suspend_stream *cmd = buf;
+	struct a2dp_setup *setup;
+	int err;
+
+	DBG("");
+
+	setup = find_setup(cmd->id);
+	if (!setup) {
+		error("Unable to find stream for endpoint %u", cmd->id);
+		goto failed;
+	}
+
+	err = avdtp_suspend(setup->dev->session, setup->stream);
+	if (err < 0) {
+		error("avdtp_suspend: %s", strerror(-err));
+		goto failed;
+	}
 
+	audio_ipc_send_rsp(AUDIO_OP_SUSPEND_STREAM, AUDIO_STATUS_SUCCESS);
+
+	return;
+
+failed:
 	audio_ipc_send_rsp(AUDIO_OP_SUSPEND_STREAM, AUDIO_STATUS_FAILED);
 }
 
-- 
1.8.4.2


^ permalink raw reply related

* [PATCH BlueZ 5/6] audio/A2DP: Add implemention of audio Resume Stream command
From: Luiz Augusto von Dentz @ 2014-01-11 10:13 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1389435216-29040-1-git-send-email-luiz.dentz@gmail.com>

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

---
 android/a2dp.c | 23 ++++++++++++++++++++++-
 1 file changed, 22 insertions(+), 1 deletion(-)

diff --git a/android/a2dp.c b/android/a2dp.c
index 4e4f43f..2d886e9 100644
--- a/android/a2dp.c
+++ b/android/a2dp.c
@@ -777,8 +777,29 @@ failed:
 
 static void bt_stream_resume(const void *buf, uint16_t len)
 {
-	DBG("Not Implemented");
+	const struct audio_cmd_resume_stream *cmd = buf;
+	struct a2dp_setup *setup;
+	int err;
+
+	DBG("");
 
+	setup = find_setup(cmd->id);
+	if (!setup) {
+		error("Unable to find stream for endpoint %u", cmd->id);
+		goto failed;
+	}
+
+	err = avdtp_start(setup->dev->session, setup->stream);
+	if (err < 0) {
+		error("avdtp_start: %s", strerror(-err));
+		goto failed;
+	}
+
+	audio_ipc_send_rsp(AUDIO_OP_RESUME_STREAM, AUDIO_STATUS_SUCCESS);
+
+	return;
+
+failed:
 	audio_ipc_send_rsp(AUDIO_OP_RESUME_STREAM, AUDIO_STATUS_FAILED);
 }
 
-- 
1.8.4.2


^ permalink raw reply related

* [PATCH BlueZ 4/6] audio/A2DP: Add implemention of audio Close Stream command
From: Luiz Augusto von Dentz @ 2014-01-11 10:13 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1389435216-29040-1-git-send-email-luiz.dentz@gmail.com>

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

---
 android/a2dp.c | 23 ++++++++++++++++++++++-
 1 file changed, 22 insertions(+), 1 deletion(-)

diff --git a/android/a2dp.c b/android/a2dp.c
index 479cb71..4e4f43f 100644
--- a/android/a2dp.c
+++ b/android/a2dp.c
@@ -749,8 +749,29 @@ static void bt_stream_open(const void *buf, uint16_t len)
 
 static void bt_stream_close(const void *buf, uint16_t len)
 {
-	DBG("Not Implemented");
+	const struct audio_cmd_close_stream *cmd = buf;
+	struct a2dp_setup *setup;
+	int err;
 
+	DBG("");
+
+	setup = find_setup(cmd->id);
+	if (!setup) {
+		error("Unable to find stream for endpoint %u", cmd->id);
+		goto failed;
+	}
+
+	err = avdtp_close(setup->dev->session, setup->stream, FALSE);
+	if (err < 0) {
+		error("avdtp_close: %s", strerror(-err));
+		goto failed;
+	}
+
+	audio_ipc_send_rsp(AUDIO_OP_CLOSE_STREAM, AUDIO_STATUS_SUCCESS);
+
+	return;
+
+failed:
 	audio_ipc_send_rsp(AUDIO_OP_CLOSE_STREAM, AUDIO_STATUS_FAILED);
 }
 
-- 
1.8.4.2


^ permalink raw reply related

* [PATCH BlueZ 3/6] audio/A2DP: Add implemention of audio Open Stream command
From: Luiz Augusto von Dentz @ 2014-01-11 10:13 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1389435216-29040-1-git-send-email-luiz.dentz@gmail.com>

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

---
 android/a2dp.c | 199 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 197 insertions(+), 2 deletions(-)

diff --git a/android/a2dp.c b/android/a2dp.c
index 8649cf3..479cb71 100644
--- a/android/a2dp.c
+++ b/android/a2dp.c
@@ -37,6 +37,7 @@
 #include "lib/bluetooth.h"
 #include "lib/sdp.h"
 #include "lib/sdp_lib.h"
+#include "profiles/audio/a2dp-codecs.h"
 #include "log.h"
 #include "a2dp.h"
 #include "hal-msg.h"
@@ -53,6 +54,7 @@
 static GIOChannel *server = NULL;
 static GSList *devices = NULL;
 static GSList *endpoints = NULL;
+static GSList *setups = NULL;
 static bdaddr_t adapter_addr;
 static uint32_t record_id = 0;
 
@@ -67,6 +69,7 @@ struct a2dp_endpoint {
 	struct avdtp_local_sep *sep;
 	struct a2dp_preset *caps;
 	GSList *presets;
+	struct a2dp_config *config;
 };
 
 struct a2dp_device {
@@ -76,6 +79,13 @@ struct a2dp_device {
 	struct avdtp	*session;
 };
 
+struct a2dp_setup {
+	struct a2dp_device *dev;
+	struct a2dp_endpoint *endpoint;
+	struct a2dp_preset *preset;
+	struct avdtp_stream *stream;
+};
+
 static int device_cmp(gconstpointer s, gconstpointer user_data)
 {
 	const struct a2dp_device *dev = s;
@@ -422,8 +432,160 @@ static gboolean sep_getcap_ind(struct avdtp *session,
 	return TRUE;
 }
 
+static int sbc_check_config(struct a2dp_endpoint *endpoint,
+						struct a2dp_preset *conf)
+{
+	a2dp_sbc_t *caps, *config;
+
+	if (conf->len != sizeof(a2dp_sbc_t)) {
+		error("SBC: Invalid configuration size (%u)", conf->len);
+		return -EINVAL;
+	}
+
+	caps = endpoint->caps->data;
+	config = conf->data;
+
+	if (!(caps->frequency & config->frequency)) {
+		error("SBC: Unsupported frequency (%u) by endpoint",
+							config->frequency);
+		return -EINVAL;
+	}
+
+	if (!(caps->channel_mode & config->channel_mode)) {
+		error("SBC: Unsupported channel mode (%u) by endpoint",
+							config->channel_mode);
+		return -EINVAL;
+	}
+
+	if (!(caps->block_length & config->block_length)) {
+		error("SBC: Unsupported block length (%u) by endpoint",
+							config->block_length);
+		return -EINVAL;
+	}
+
+	if (!(caps->allocation_method & config->allocation_method)) {
+		error("SBC: Unsupported allocation method (%u) by endpoint",
+							config->block_length);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int check_config(struct a2dp_endpoint *endpoint,
+						struct a2dp_preset *config)
+{
+	GSList *l;
+
+	for (l = endpoint->presets; l; l = g_slist_next(l)) {
+		struct a2dp_preset *preset = l->data;
+
+		if (preset->len != config->len)
+			continue;
+
+		if (memcmp(preset->data, config->data, preset->len) == 0)
+			return 0;
+	}
+
+	/* Codec specific */
+	switch (endpoint->codec) {
+	case A2DP_CODEC_SBC:
+		return sbc_check_config(endpoint, config);
+	default:
+		return -EINVAL;
+	}
+}
+
+static struct a2dp_device *find_device_by_session(struct avdtp *session)
+{
+	GSList *l;
+
+	for (l = devices; l; l = g_slist_next(l)) {
+		struct a2dp_device *dev = l->data;
+
+		if (dev->session == session)
+			return dev;
+	}
+
+	return NULL;
+}
+
+static void setup_free(void *data)
+{
+	struct a2dp_setup *setup = data;
+
+	preset_free(setup->preset);
+	g_free(setup);
+}
+
+static void setup_add(struct a2dp_device *dev, struct a2dp_endpoint *endpoint,
+			struct a2dp_preset *preset, struct avdtp_stream *stream)
+{
+	struct a2dp_setup *setup;
+
+	setup = g_new0(struct a2dp_setup, 1);
+	setup->dev = dev;
+	setup->endpoint = endpoint;
+	setup->preset = preset;
+	setup->stream = stream;
+	setups = g_slist_append(setups, setup);
+}
+
+static gboolean sep_setconf_ind(struct avdtp *session,
+						struct avdtp_local_sep *sep,
+						struct avdtp_stream *stream,
+						GSList *caps,
+						avdtp_set_configuration_cb cb,
+						void *user_data)
+{
+	struct a2dp_endpoint *endpoint = user_data;
+	struct a2dp_device *dev;
+	struct a2dp_preset *preset = NULL;
+
+	DBG("");
+
+	dev = find_device_by_session(session);
+	if (!dev) {
+		error("Unable to find device for session %p", session);
+		return FALSE;
+	}
+
+	for (; caps != NULL; caps = g_slist_next(caps)) {
+		struct avdtp_service_capability *cap = caps->data;
+		struct avdtp_media_codec_capability *codec;
+
+		if (cap->category == AVDTP_DELAY_REPORTING)
+			return FALSE;
+
+		if (cap->category != AVDTP_MEDIA_CODEC)
+			continue;
+
+		codec = (struct avdtp_media_codec_capability *) cap->data;
+
+		if (codec->media_codec_type != endpoint->codec)
+			return FALSE;
+
+		preset = g_new0(struct a2dp_preset, 1);
+		preset->len = cap->length - sizeof(*codec);
+		preset->data = g_memdup(codec->data, preset->len);
+
+		if (check_config(endpoint, preset) < 0) {
+			preset_free(preset);
+			return FALSE;
+		}
+	}
+
+	if (!preset)
+		return FALSE;
+
+	setup_add(dev, endpoint, preset, stream);
+
+	return TRUE;
+}
+
 static struct avdtp_sep_ind sep_ind = {
 	.get_capability		= sep_getcap_ind,
+	.set_configuration	= sep_setconf_ind,
 };
 
 static uint8_t register_endpoint(const uint8_t *uuid, uint8_t codec,
@@ -548,11 +710,41 @@ static void bt_audio_close(const void *buf, uint16_t len)
 	audio_ipc_send_rsp(AUDIO_OP_CLOSE, HAL_STATUS_SUCCESS);
 }
 
+static struct a2dp_setup *find_setup(uint8_t id)
+{
+	GSList *l;
+
+	for (l = setups; l; l = g_slist_next(l)) {
+		struct a2dp_setup *setup = l->data;
+
+		if (setup->endpoint->id == id)
+			return setup;
+	}
+
+	return NULL;
+}
+
 static void bt_stream_open(const void *buf, uint16_t len)
 {
-	DBG("Not Implemented");
+	const struct audio_cmd_open_stream *cmd = buf;
+	struct audio_rsp_open_stream *rsp;
+	struct a2dp_setup *setup;
+
+	DBG("");
 
-	audio_ipc_send_rsp(AUDIO_OP_OPEN_STREAM, AUDIO_STATUS_FAILED);
+	setup = find_setup(cmd->id);
+	if (!setup) {
+		error("Unable to find stream for endpoint %u", cmd->id);
+		audio_ipc_send_rsp(AUDIO_OP_OPEN_STREAM, HAL_STATUS_FAILED);
+		return;
+	}
+
+	len = sizeof(*rsp) + setup->preset->len;
+	rsp = g_malloc0(sizeof(*rsp) + setup->preset->len);
+	rsp->preset->len = setup->preset->len;
+	memcpy(rsp->preset->data, setup->preset->data, setup->preset->len);
+
+	audio_ipc_send_rsp_full(AUDIO_OP_OPEN_STREAM, len, rsp, -1);
 }
 
 static void bt_stream_close(const void *buf, uint16_t len)
@@ -651,6 +843,9 @@ void bt_a2dp_unregister(void)
 {
 	DBG("");
 
+	g_slist_free_full(setups, setup_free);
+	setups = NULL;
+
 	g_slist_free_full(endpoints, unregister_endpoint);
 	endpoints = NULL;
 
-- 
1.8.4.2


^ permalink raw reply related

* [PATCH BlueZ 2/6] audio/A2DP: Add implemention of audio Close command
From: Luiz Augusto von Dentz @ 2014-01-11 10:13 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1389435216-29040-1-git-send-email-luiz.dentz@gmail.com>

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

---
 android/a2dp.c | 30 ++++++++++++++++++++++++++++--
 1 file changed, 28 insertions(+), 2 deletions(-)

diff --git a/android/a2dp.c b/android/a2dp.c
index 28b7406..8649cf3 100644
--- a/android/a2dp.c
+++ b/android/a2dp.c
@@ -515,11 +515,37 @@ failed:
 	audio_ipc_send_rsp(AUDIO_OP_OPEN, AUDIO_STATUS_FAILED);
 }
 
+static struct a2dp_endpoint *find_endpoint(uint8_t id)
+{
+	GSList *l;
+
+	for (l = endpoints; l; l = g_slist_next(l)) {
+		struct a2dp_endpoint *endpoint = l->data;
+
+		if (endpoint->id == id)
+			return endpoint;
+	}
+
+	return NULL;
+}
+
 static void bt_audio_close(const void *buf, uint16_t len)
 {
-	DBG("Not Implemented");
+	const struct audio_cmd_close *cmd = buf;
+	struct a2dp_endpoint *endpoint;
+
+	DBG("");
+
+	endpoint = find_endpoint(cmd->id);
+	if (!endpoint) {
+		error("Unable to find endpoint %u", cmd->id);
+		audio_ipc_send_rsp(AUDIO_OP_CLOSE, HAL_STATUS_FAILED);
+		return;
+	}
+
+	unregister_endpoint(endpoint);
 
-	audio_ipc_send_rsp(AUDIO_OP_CLOSE, HAL_STATUS_FAILED);
+	audio_ipc_send_rsp(AUDIO_OP_CLOSE, HAL_STATUS_SUCCESS);
 }
 
 static void bt_stream_open(const void *buf, uint16_t len)
-- 
1.8.4.2


^ permalink raw reply related

* [PATCH BlueZ 1/6] audio/A2DP: Add implemention of audio Open command
From: Luiz Augusto von Dentz @ 2014-01-11 10:13 UTC (permalink / raw)
  To: linux-bluetooth

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

---
 android/a2dp.c | 159 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 158 insertions(+), 1 deletion(-)

diff --git a/android/a2dp.c b/android/a2dp.c
index b59c53d..28b7406 100644
--- a/android/a2dp.c
+++ b/android/a2dp.c
@@ -52,9 +52,23 @@
 
 static GIOChannel *server = NULL;
 static GSList *devices = NULL;
+static GSList *endpoints = NULL;
 static bdaddr_t adapter_addr;
 static uint32_t record_id = 0;
 
+struct a2dp_preset {
+	void *data;
+	int8_t len;
+};
+
+struct a2dp_endpoint {
+	uint8_t id;
+	uint8_t codec;
+	struct avdtp_local_sep *sep;
+	struct a2dp_preset *caps;
+	GSList *presets;
+};
+
 struct a2dp_device {
 	bdaddr_t	dst;
 	uint8_t		state;
@@ -70,6 +84,29 @@ static int device_cmp(gconstpointer s, gconstpointer user_data)
 	return bacmp(&dev->dst, dst);
 }
 
+static void preset_free(void *data)
+{
+	struct a2dp_preset *preset = data;
+
+	g_free(preset->data);
+	g_free(preset);
+}
+
+static void unregister_endpoint(void *data)
+{
+	struct a2dp_endpoint *endpoint = data;
+
+	if (endpoint->sep)
+		avdtp_unregister_sep(endpoint->sep);
+
+	if (endpoint->caps)
+		preset_free(endpoint->caps);
+
+	g_slist_free_full(endpoint->presets, preset_free);
+
+	g_free(endpoint);
+}
+
 static void a2dp_device_free(struct a2dp_device *dev)
 {
 	if (dev->session)
@@ -354,10 +391,127 @@ static sdp_record_t *a2dp_record(void)
 	return record;
 }
 
+static gboolean sep_getcap_ind(struct avdtp *session,
+					struct avdtp_local_sep *sep,
+					GSList **caps, uint8_t *err,
+					void *user_data)
+{
+	struct a2dp_endpoint *endpoint = user_data;
+	struct a2dp_preset *cap = endpoint->presets->data;
+	struct avdtp_service_capability *media_transport, *media_codec;
+	struct avdtp_media_codec_capability *codec_caps;
+
+	*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 = endpoint->codec;
+	memcpy(codec_caps->data, cap->data, cap->len);
+
+	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 uint8_t register_endpoint(const uint8_t *uuid, uint8_t codec,
+							GSList *presets)
+{
+	struct a2dp_endpoint *endpoint;
+
+	/* FIXME: Add proper check for uuid */
+
+	endpoint = g_new0(struct a2dp_endpoint, 1);
+	endpoint->id = g_slist_length(endpoints) + 1;
+	endpoint->codec = codec;
+	endpoint->sep = avdtp_register_sep(AVDTP_SEP_TYPE_SOURCE,
+						AVDTP_MEDIA_TYPE_AUDIO,
+						codec, FALSE, &sep_ind, NULL,
+						endpoint);
+	endpoint->caps = g_slist_nth_data(presets->data, 0);
+	endpoint->presets = g_slist_copy(g_slist_nth(presets, 1));
+
+	endpoints = g_slist_append(endpoints, endpoint);
+
+	return endpoint->id;
+}
+
+static GSList *parse_presets(const struct audio_preset *p, uint8_t count,
+								uint16_t len)
+{
+	GSList *l = NULL;
+	uint8_t i;
+
+	for (i = 0; count > i; i++) {
+		struct a2dp_preset *preset;
+
+		if (len < sizeof(struct audio_preset)) {
+			DBG("Invalid preset index %u", i);
+			break;
+		}
+
+		len -= sizeof(struct audio_preset);
+		if (len == 0 || len < p->len) {
+			DBG("Invalid preset size of %u for index %u", len, i);
+			break;
+		}
+
+		preset = g_new0(struct a2dp_preset, 1);
+		preset->len = p->len;
+		preset->data = g_memdup(p->data, preset->len);
+		l = g_slist_append(l, preset);
+
+		len -= preset->len;
+		p += sizeof(struct audio_preset) + preset->len;
+	}
+
+	return l;
+}
+
 static void bt_audio_open(const void *buf, uint16_t len)
 {
-	DBG("Not Implemented");
+	const struct audio_cmd_open *cmd = buf;
+	struct audio_rsp_open rsp;
+	GSList *presets;
+
+	DBG("");
 
+	if (cmd->presets == 0) {
+		error("No audio presets found");
+		goto failed;
+	}
+
+	presets = parse_presets(cmd->preset, cmd->presets, len - sizeof(*cmd));
+	if (!presets) {
+		error("No audio presets found");
+		goto failed;
+	}
+
+	rsp.id = register_endpoint(cmd->uuid, cmd->codec, presets);
+	g_slist_free(presets);
+
+	if (rsp.id == 0) {
+		error("Unable to register endpoint");
+		goto failed;
+	}
+
+	audio_ipc_send_rsp_full(AUDIO_OP_OPEN, sizeof(rsp), &rsp, -1);
+
+	return;
+
+failed:
 	audio_ipc_send_rsp(AUDIO_OP_OPEN, AUDIO_STATUS_FAILED);
 }
 
@@ -471,6 +625,9 @@ void bt_a2dp_unregister(void)
 {
 	DBG("");
 
+	g_slist_free_full(endpoints, unregister_endpoint);
+	endpoints = NULL;
+
 	g_slist_foreach(devices, a2dp_device_disconnected, NULL);
 	devices = NULL;
 
-- 
1.8.4.2


^ permalink raw reply related

* [PATCH BlueZ 11/11] attrib: Add extra PDU checks when decoding Read by Type Response
From: Anderson Lizardo @ 2014-01-11  4:47 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Anderson Lizardo
In-Reply-To: <1389415647-25831-1-git-send-email-anderson.lizardo@openbossa.org>

These checks are needed to avoid invalid memory access on bogus PDUs.
---
 attrib/att.c | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/attrib/att.c b/attrib/att.c
index 183390b..e28be25 100644
--- a/attrib/att.c
+++ b/attrib/att.c
@@ -454,7 +454,24 @@ struct att_data_list *dec_read_by_type_resp(const uint8_t *pdu, size_t len)
 	if (pdu[0] != ATT_OP_READ_BY_TYPE_RESP)
 		return NULL;
 
+	/* PDU must contain at least:
+	 * - Attribute Opcode (1 octet)
+	 * - Length (1 octet)
+	 * - Attribute Data List (at least one entry):
+	 *   - Attribute Handle (2 octets)
+	 *   - Attribute Value (at least 1 octet) */
+	if (len < 5)
+		return NULL;
+
 	elen = pdu[1];
+	/* Minimum Attribute Data List size */
+	if (elen < 3)
+		return NULL;
+
+	/* Reject incomplete Attribute Data List */
+	if ((len - 2) % elen)
+		return NULL;
+
 	num = (len - 2) / elen;
 	list = att_data_list_alloc(num, elen);
 	if (list == NULL)
-- 
1.8.3.2


^ permalink raw reply related

* [PATCH BlueZ 10/11] attrib: Fix PDU length check for Read by Type Request
From: Anderson Lizardo @ 2014-01-11  4:47 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Anderson Lizardo
In-Reply-To: <1389415647-25831-1-git-send-email-anderson.lizardo@openbossa.org>

PDU length must be either 7 or 21 octets.
---
 attrib/att.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/attrib/att.c b/attrib/att.c
index c279b2c..183390b 100644
--- a/attrib/att.c
+++ b/attrib/att.c
@@ -400,7 +400,7 @@ uint16_t dec_read_by_type_req(const uint8_t *pdu, size_t len, uint16_t *start,
 	if (start == NULL || end == NULL || uuid == NULL)
 		return 0;
 
-	if (len < min_len + 2)
+	if (len != (min_len + 2) && len != (min_len + 16))
 		return 0;
 
 	if (pdu[0] != ATT_OP_READ_BY_TYPE_REQ)
-- 
1.8.3.2


^ permalink raw reply related


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