* [PATCH 04/10 v2] Bluetooth: Refactor valid LTK data testing into its own function
From: Johan Hedberg @ 2013-01-20 12:27 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1358684842-4441-1-git-send-email-johan.hedberg@gmail.com>
From: Johan Hedberg <johan.hedberg@intel.com>
This patch refactors valid LTK data testing into its own function. This
will help keep the code readable since there are several tests still
missing that need to be done on the LTK data.
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
---
net/bluetooth/mgmt.c | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index c7ec47c..cd75899 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -2701,6 +2701,13 @@ done:
return err;
}
+static bool ltk_is_valid(struct mgmt_ltk_info *key)
+{
+ if (key->master != 0x00 && key->master != 0x01)
+ return false;
+ return true;
+}
+
static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
void *cp_data, u16 len)
{
@@ -2724,7 +2731,7 @@ static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
for (i = 0; i < key_count; i++) {
struct mgmt_ltk_info *key = &cp->keys[i];
- if (key->master != 0x00 && key->master != 0x01)
+ if (!ltk_is_valid(key))
return cmd_status(sk, hdev->id,
MGMT_OP_LOAD_LONG_TERM_KEYS,
MGMT_STATUS_INVALID_PARAMS);
--
1.7.10.4
^ permalink raw reply related
* [PATCH 03/10 v2] Bluetooth: Fix checking for proper key->master value in Load LTKs
From: Johan Hedberg @ 2013-01-20 12:27 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1358684842-4441-1-git-send-email-johan.hedberg@gmail.com>
From: Johan Hedberg <johan.hedberg@intel.com>
The allowed values for the key->master parameter in the Load LTKs
command are 0x00 and 0x01. If there is a key in the list with some other
value the command should fail with a proper invalid params response.
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
---
net/bluetooth/mgmt.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index a050eee..c7ec47c 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -2721,6 +2721,15 @@ static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
BT_DBG("%s key_count %u", hdev->name, key_count);
+ for (i = 0; i < key_count; i++) {
+ struct mgmt_ltk_info *key = &cp->keys[i];
+
+ if (key->master != 0x00 && key->master != 0x01)
+ return cmd_status(sk, hdev->id,
+ MGMT_OP_LOAD_LONG_TERM_KEYS,
+ MGMT_STATUS_INVALID_PARAMS);
+ }
+
hci_dev_lock(hdev);
hci_smp_ltks_clear(hdev);
--
1.7.10.4
^ permalink raw reply related
* [PATCH 02/10 v2] Bluetooth: Fix returning proper mgmt status for Load LTKs
From: Johan Hedberg @ 2013-01-20 12:27 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1358684842-4441-1-git-send-email-johan.hedberg@gmail.com>
From: Johan Hedberg <johan.hedberg@intel.com>
Failures of mgmt commands should be indicated with valid mgmt status
codes, and EINVAL is not one of them. Instead MGMT_STATUS_INVALID_PARAMS
should be returned.
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
Acked-by: Marcel Holtmann <marcel@holtmann.org>
---
net/bluetooth/mgmt.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index d9b042e..a050eee 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -2716,7 +2716,7 @@ static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
BT_ERR("load_keys: expected %u bytes, got %u bytes",
len, expected_len);
return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
- EINVAL);
+ MGMT_STATUS_INVALID_PARAMS);
}
BT_DBG("%s key_count %u", hdev->name, key_count);
--
1.7.10.4
^ permalink raw reply related
* [PATCH 01/10 v2] Bluetooth: Fix checking for correct mgmt_load_link_keys parameters
From: Johan Hedberg @ 2013-01-20 12:27 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1358684842-4441-1-git-send-email-johan.hedberg@gmail.com>
From: Johan Hedberg <johan.hedberg@intel.com>
The debug_keys parameter is only allowed to have the values 0x00 and
0x01. Any other value should result in a proper command status with
MGMT_STATUS_INVALID_PARAMS.
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
Acked-by: Marcel Holtmann <marcel@holtmann.org>
---
net/bluetooth/mgmt.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 36b2310..d9b042e 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -1519,6 +1519,10 @@ static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
MGMT_STATUS_INVALID_PARAMS);
}
+ if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01)
+ return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
+ MGMT_STATUS_INVALID_PARAMS);
+
BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
key_count);
--
1.7.10.4
^ permalink raw reply related
* [PATCH 00/10 v2] Bluetooth: Fix more mgmt parameter checks
From: Johan Hedberg @ 2013-01-20 12:27 UTC (permalink / raw)
To: linux-bluetooth
Hi,
Here's an updated patch set based on feedback from Marcel for the first
one.
This one still needs my patch (acked by Marcel)
"Bluetooth: Fix Class of Device indication when powering off"
and Szymons patch (acked by me)
"Bluetooth: Fix pair device command reply if adapter is powered off"
to be applied first to bluetooth-next.git. At least I've got those two
in my local tree before this set, so no guarantees that there wont be
conflicts if they are not applied first.
Johan
^ permalink raw reply
* multiboot sync bluetooth pair key
From: Ilya Basin @ 2013-01-20 9:24 UTC (permalink / raw)
To: linux-bluetooth
Hi. Is there any software to sync the bluetooth pair key over Linux
and Windows, so one won't need to pair the device again?
Where is the key stored on Linux?
Is it DE-specific?
Where is it stored on Windows?
^ permalink raw reply
* Re: [PATCH] bluetooth: btmrvl_sdio: look for sd8688 firmware in proper location
From: Marcel Holtmann @ 2013-01-19 20:23 UTC (permalink / raw)
To: Lubomir Rintel
Cc: Bing Zhao, Ben Hutchings, David Woodhouse, Gustavo Padovan,
Johan Hedberg, libertas-dev, linux-bluetooth, linux-kernel
In-Reply-To: <1358622064-782-1-git-send-email-lkundrak@v3.sk>
Hi Lubomir,
> The firmware images are shared with libertas_sdio WiFi chip and used to be in
> libertas/ subtree in linux-firmware. As btmrvl_sdio used to look into the
> linux-firmware root, it ended up being unsuccessful. Since the firmware files
> are not specific to the libertas hardware, they're being moved into mrvl/ now.
>
> Signed-off-by: Lubomir Rintel <lkundrak@v3.sk>
> ---
> drivers/bluetooth/btmrvl_sdio.c | 8 ++++----
> 1 files changed, 4 insertions(+), 4 deletions(-)
Acked-by: Marcel Holtmann <marcel@holtmann.org>
Regards
Marcel
^ permalink raw reply
* [PATCH] bluetooth: btmrvl_sdio: look for sd8688 firmware in proper location
From: Lubomir Rintel @ 2013-01-19 19:01 UTC (permalink / raw)
To: Marcel Holtmann
Cc: Lubomir Rintel, Bing Zhao, Ben Hutchings, David Woodhouse,
Gustavo Padovan, Johan Hedberg, libertas-dev, linux-bluetooth,
linux-kernel
In-Reply-To: <1358495893.5510.0.camel@aeonflux>
The firmware images are shared with libertas_sdio WiFi chip and used to be in
libertas/ subtree in linux-firmware. As btmrvl_sdio used to look into the
linux-firmware root, it ended up being unsuccessful. Since the firmware files
are not specific to the libertas hardware, they're being moved into mrvl/ now.
Signed-off-by: Lubomir Rintel <lkundrak@v3.sk>
---
drivers/bluetooth/btmrvl_sdio.c | 8 ++++----
1 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c
index 9959d4c..1cb5183 100644
--- a/drivers/bluetooth/btmrvl_sdio.c
+++ b/drivers/bluetooth/btmrvl_sdio.c
@@ -83,8 +83,8 @@ static const struct btmrvl_sdio_card_reg btmrvl_reg_87xx = {
};
static const struct btmrvl_sdio_device btmrvl_sdio_sd8688 = {
- .helper = "sd8688_helper.bin",
- .firmware = "sd8688.bin",
+ .helper = "mrvl/sd8688_helper.bin",
+ .firmware = "mrvl/sd8688.bin",
.reg = &btmrvl_reg_8688,
.sd_blksz_fw_dl = 64,
};
@@ -1185,7 +1185,7 @@ MODULE_AUTHOR("Marvell International Ltd.");
MODULE_DESCRIPTION("Marvell BT-over-SDIO driver ver " VERSION);
MODULE_VERSION(VERSION);
MODULE_LICENSE("GPL v2");
-MODULE_FIRMWARE("sd8688_helper.bin");
-MODULE_FIRMWARE("sd8688.bin");
+MODULE_FIRMWARE("mrvl/sd8688_helper.bin");
+MODULE_FIRMWARE("mrvl/sd8688.bin");
MODULE_FIRMWARE("mrvl/sd8787_uapsta.bin");
MODULE_FIRMWARE("mrvl/sd8797_uapsta.bin");
--
1.7.1
^ permalink raw reply related
* Re: [PATCH] test: Use proper test data in unblock device test
From: Johan Hedberg @ 2013-01-19 7:56 UTC (permalink / raw)
To: Szymon Janc; +Cc: linux-bluetooth
In-Reply-To: <1358537292-3572-1-git-send-email-szymon@janc.net.pl>
Hi Szymon,
On Fri, Jan 18, 2013, Szymon Janc wrote:
> Copy and paste error. Although both data values are same use proper
> one for clarity.
> ---
> tools/mgmt-tester.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
Applied. Thanks.
Johan
^ permalink raw reply
* [PATCH] test: Use proper test data in unblock device test
From: Szymon Janc @ 2013-01-18 19:28 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Szymon Janc
Copy and paste error. Although both data values are same use proper
one for clarity.
---
tools/mgmt-tester.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tools/mgmt-tester.c b/tools/mgmt-tester.c
index 273401c..bf61f9d 100644
--- a/tools/mgmt-tester.c
+++ b/tools/mgmt-tester.c
@@ -1714,7 +1714,7 @@ int main(int argc, char *argv[])
test_command_generic);
test_bredr("Unblock Device - Invalid Parameters 1",
- &block_device_invalid_param_test_1, NULL,
+ &unblock_device_invalid_param_test_1, NULL,
test_command_generic);
return tester_run();
--
1.8.1
^ permalink raw reply related
* [PATCH BlueZ] avrcp: Ignore MSB of Absolute Volume parameter
From: João Paulo Rechi Vita @ 2013-01-18 19:25 UTC (permalink / raw)
To: linux-bluetooth; +Cc: João Paulo Rechi Vita
According to the Section 6.13.1 of the AVRCP 1.5 specification document,
the most significant bit of the Absolute Volume parameter is reserved
for future additions, so it should be ignored when parsing parameters of
the SetAbsoluteVolume command. This is also necessary to pass PTS test
TC_TG_VLH_BI_02_C.
---
profiles/audio/avrcp.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/profiles/audio/avrcp.c b/profiles/audio/avrcp.c
index 636d3e4..237f176 100644
--- a/profiles/audio/avrcp.c
+++ b/profiles/audio/avrcp.c
@@ -1398,11 +1398,13 @@ static uint8_t avrcp_handle_set_absolute_volume(struct avrcp *session,
{
struct avrcp_player *player = session->player;
uint16_t len = ntohs(pdu->params_len);
+ uint8_t volume;
if (len != 1)
goto err;
- if (pdu->params[0] > 127)
+ volume = pdu->params[0] & 0x7F;
+ if (volume > 127)
goto err;
if (!player)
--
1.7.11.7
^ permalink raw reply related
* Re: [PATCH 02/10] Bluetooth: Fix returning proper mgmt status for Load LTKs
From: Marcel Holtmann @ 2013-01-18 16:55 UTC (permalink / raw)
To: Johan Hedberg; +Cc: linux-bluetooth
In-Reply-To: <1358515558-17861-3-git-send-email-johan.hedberg@gmail.com>
Hi Johan,
> Failures of mgmt commands should be indicated with valid mgmt status
> codes, and EINVAL is not one of them. Instead MGMT_STATUS_INVALID_PARAMS
> should be returned.
>
> Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
> ---
> net/bluetooth/mgmt.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
Acked-by: Marcel Holtmann <marcel@holtmann.org>
Regards
Marcel
^ permalink raw reply
* Re: [PATCH 01/10] Bluetooth: Fix checking for correct mgmt_load_link_keys parameters
From: Marcel Holtmann @ 2013-01-18 16:55 UTC (permalink / raw)
To: Johan Hedberg; +Cc: linux-bluetooth
In-Reply-To: <1358515558-17861-2-git-send-email-johan.hedberg@gmail.com>
Hi Johan,
> The debug_keys parameter is only allowed to have the values 0x00 and
> 0x01. Any other value should result in a proper command status with
> MGMT_STATUS_INVALID_PARAMS.
>
> Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
> ---
> net/bluetooth/mgmt.c | 4 ++++
> 1 file changed, 4 insertions(+)
Acked-by: Marcel Holtmann <marcel@holtmann.org>
Regards
Marcel
^ permalink raw reply
* Re: [PATCH 08/10] Bluetooth: Fix checking for valid disconnect parameters in unpair_device
From: Marcel Holtmann @ 2013-01-18 16:54 UTC (permalink / raw)
To: Johan Hedberg; +Cc: linux-bluetooth
In-Reply-To: <1358515558-17861-9-git-send-email-johan.hedberg@gmail.com>
Hi Johan,
> The valid values for the Disconnect parameter in the Unpair Device
> command are 0x00 and 0x01. If any other value is encountered the command
> should fail with the appropriate invalid params response.
>
> Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
> ---
> net/bluetooth/mgmt.c | 5 +++++
> 1 file changed, 5 insertions(+)
Acked-by: Marcel Holtmann <marcel@holtmann.org>
Regards
Marcel
^ permalink raw reply
* Re: [PATCH 07/10] Bluetooth: Fix checking for valid address type values in mgmt commands
From: Marcel Holtmann @ 2013-01-18 16:53 UTC (permalink / raw)
To: Johan Hedberg; +Cc: linux-bluetooth
In-Reply-To: <1358515558-17861-8-git-send-email-johan.hedberg@gmail.com>
Hi Johan,
> This patch adds checks for valid address type values passed to mgmt
> commands. If an invalid address type is encountered the code will return
> a proper invalid params response.
>
> Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
> ---
> net/bluetooth/mgmt.c | 43 ++++++++++++++++++++++++++++++++++++++-----
> 1 file changed, 38 insertions(+), 5 deletions(-)
>
> diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
> index 76301a3..3de4bc2 100644
> --- a/net/bluetooth/mgmt.c
> +++ b/net/bluetooth/mgmt.c
> @@ -1506,7 +1506,7 @@ static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
> {
> struct mgmt_cp_load_link_keys *cp = data;
> u16 key_count, expected_len;
> - int i;
> + int i, err;
>
> key_count = __le16_to_cpu(cp->key_count);
>
> @@ -1540,15 +1540,24 @@ static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
> for (i = 0; i < key_count; i++) {
> struct mgmt_link_key_info *key = &cp->keys[i];
>
> + if (key->addr.type != BDADDR_BREDR) {
> + clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
> + hci_link_keys_clear(hdev);
> + err = cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
> + MGMT_STATUS_INVALID_PARAMS);
> + goto unlock;
> + }
> +
> hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
> key->type, key->pin_len);
> }
I am not a huge fan of doing it this way (same applies to LTKs). You are
introducing a side effect here. An invalid command will clear the keys.
Please check the validity of the key parameters ahead of time and not in
the middle of applying them. Your rollback is broken since it just
clears all keys.
We could add /sys/kernel/debug/bluetooth/hci0/link_keys as a root-only
entry to allow checking this mgmt-tester.
Regards
Marcel
^ permalink raw reply
* [PATCH BlueZ 2/2] tools: Add volume support for mpris-player
From: Luiz Augusto von Dentz @ 2013-01-18 14:41 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1358520085-4790-1-git-send-email-luiz.dentz@gmail.com>
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This uses MediaTransport1 to track the Volume changes.
---
tools/mpris-player.c | 187 ++++++++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 178 insertions(+), 9 deletions(-)
diff --git a/tools/mpris-player.c b/tools/mpris-player.c
index e3bab1c..80bb76d 100644
--- a/tools/mpris-player.c
+++ b/tools/mpris-player.c
@@ -43,6 +43,7 @@
#define BLUEZ_ADAPTER_INTERFACE "org.bluez.Adapter1"
#define BLUEZ_MEDIA_INTERFACE "org.bluez.Media1"
#define BLUEZ_MEDIA_PLAYER_INTERFACE "org.bluez.MediaPlayer1"
+#define BLUEZ_MEDIA_TRANSPORT_INTERFACE "org.bluez.MediaTransport1"
#define MPRIS_BUS_NAME "org.mpris.MediaPlayer2."
#define MPRIS_INTERFACE "org.mpris.MediaPlayer2"
#define MPRIS_PLAYER_INTERFACE "org.mpris.MediaPlayer2.Player"
@@ -55,6 +56,7 @@ static DBusConnection *sys = NULL;
static DBusConnection *session = NULL;
static GDBusClient *client = NULL;
static GSList *players = NULL;
+static GSList *transports = NULL;
struct player {
char *name;
@@ -62,6 +64,7 @@ struct player {
DBusConnection *conn;
GDBusProxy *proxy;
GDBusProxy *device;
+ GDBusProxy *transport;
};
typedef int (* parse_metadata_func) (DBusMessageIter *iter, const char *key,
@@ -793,6 +796,9 @@ static void player_free(void *data)
g_dbus_proxy_unref(player->device);
g_dbus_proxy_unref(player->proxy);
+ if (player->transport)
+ g_dbus_proxy_unref(player->transport);
+
g_free(player->name);
g_free(player->bus_name);
g_free(player);
@@ -1287,6 +1293,30 @@ static gboolean get_disable(const GDBusPropertyTable *property,
return TRUE;
}
+static gboolean get_volume(const GDBusPropertyTable *property,
+ DBusMessageIter *iter, void *data)
+{
+ struct player *player = data;
+ double value = 0.0;
+ uint16_t volume;
+ DBusMessageIter var;
+
+ if (player->transport == NULL)
+ goto done;
+
+ if (!g_dbus_proxy_get_property(player->transport, "Volume", &var))
+ goto done;
+
+ dbus_message_iter_get_basic(&var, &volume);
+
+ value = (double) volume / 127;
+
+done:
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_DOUBLE, &value);
+
+ return TRUE;
+}
+
static const GDBusMethodTable player_methods[] = {
{ GDBUS_ASYNC_METHOD("PlayPause", NULL, NULL, player_toggle) },
{ GDBUS_ASYNC_METHOD("Play", NULL, NULL, player_play) },
@@ -1311,7 +1341,7 @@ static const GDBusPropertyTable player_properties[] = {
{ "Shuffle", "b", get_shuffle, set_shuffle, shuffle_exists },
{ "Position", "x", get_position, NULL, position_exists },
{ "Metadata", "a{sv}", get_track, NULL, track_exists },
- { "Volume", "d", get_double, NULL, NULL },
+ { "Volume", "d", get_volume, NULL, NULL },
{ "CanGoNext", "b", get_enable, NULL, NULL },
{ "CanGoPrevious", "b", get_enable, NULL, NULL },
{ "CanPlay", "b", get_enable, NULL, NULL },
@@ -1353,12 +1383,33 @@ static char *mpris_busname(const char *name)
return g_strdelimit(bus_name, " ’", '_');
}
+static GDBusProxy *find_transport_by_path(const char *path)
+{
+ GSList *l;
+
+ for (l = transports; l; l = l->next) {
+ GDBusProxy *transport = l->data;
+ DBusMessageIter iter;
+ const char *value;
+
+ if (!g_dbus_proxy_get_property(transport, "Device", &iter))
+ continue;
+
+ dbus_message_iter_get_basic(&iter, &value);
+
+ if (strcmp(path, value) == 0)
+ return transport;
+ }
+
+ return NULL;
+}
+
static void register_player(GDBusProxy *proxy)
{
struct player *player;
DBusMessageIter iter;
const char *path, *name;
- GDBusProxy *device;
+ GDBusProxy *device, *transport;
if (!g_dbus_proxy_get_property(proxy, "Device", &iter))
return;
@@ -1412,6 +1463,10 @@ static void register_player(GDBusProxy *proxy)
goto fail;
}
+ transport = find_transport_by_path(path);
+ if (transport)
+ player->transport = g_dbus_proxy_ref(transport);
+
return;
fail:
@@ -1419,6 +1474,47 @@ fail:
player_free(player);
}
+static struct player *find_player_by_device(const char *device)
+{
+ GSList *l;
+
+ for (l = players; l; l = l->next) {
+ struct player *player = l->data;
+ const char *path = g_dbus_proxy_get_path(player->device);
+
+ if (g_strcmp0(device, path) == 0)
+ return player;
+ }
+
+ return NULL;
+}
+
+static void register_transport(GDBusProxy *proxy)
+{
+ struct player *player;
+ DBusMessageIter iter;
+ const char *path;
+
+ if (g_slist_find(transports, proxy) != NULL)
+ return;
+
+ if (!g_dbus_proxy_get_property(proxy, "Volume", &iter))
+ return;
+
+ if (!g_dbus_proxy_get_property(proxy, "Device", &iter))
+ return;
+
+ dbus_message_iter_get_basic(&iter, &path);
+
+ transports = g_slist_append(transports, proxy);
+
+ player = find_player_by_device(path);
+ if (player == NULL || player->transport != NULL)
+ return;
+
+ player->transport = g_dbus_proxy_ref(proxy);
+}
+
static void proxy_added(GDBusProxy *proxy, void *user_data)
{
const char *interface;
@@ -1437,6 +1533,10 @@ static void proxy_added(GDBusProxy *proxy, void *user_data)
printf("Bluetooth Player %s found\n",
g_dbus_proxy_get_path(proxy));
register_player(proxy);
+ } else if (!strcmp(interface, BLUEZ_MEDIA_TRANSPORT_INTERFACE)) {
+ printf("Bluetooth Transport %s found\n",
+ g_dbus_proxy_get_path(proxy));
+ register_transport(proxy);
}
}
@@ -1462,6 +1562,37 @@ static struct player *find_player(GDBusProxy *proxy)
return NULL;
}
+static struct player *find_player_by_transport(GDBusProxy *proxy)
+{
+ GSList *l;
+
+ for (l = players; l; l = l->next) {
+ struct player *player = l->data;
+
+ if (player->transport == proxy)
+ return player;
+ }
+
+ return NULL;
+}
+
+static void unregister_transport(GDBusProxy *proxy)
+{
+ struct player *player;
+
+ if (g_slist_find(transports, proxy) == NULL)
+ return;
+
+ transports = g_slist_remove(transports, proxy);
+
+ player = find_player_by_transport(proxy);
+ if (player == NULL)
+ return;
+
+ g_dbus_proxy_unref(player->transport);
+ player->transport = NULL;
+}
+
static void proxy_removed(GDBusProxy *proxy, void *user_data)
{
const char *interface;
@@ -1487,6 +1618,10 @@ static void proxy_removed(GDBusProxy *proxy, void *user_data)
printf("Bluetooth Player %s removed\n",
g_dbus_proxy_get_path(proxy));
unregister_player(player);
+ } else if (strcmp(interface, BLUEZ_MEDIA_TRANSPORT_INTERFACE) == 0) {
+ printf("Bluetooth Transport %s removed\n",
+ g_dbus_proxy_get_path(proxy));
+ unregister_transport(proxy);
}
}
@@ -1506,16 +1641,11 @@ static const char *property_to_mpris(const char *property)
return NULL;
}
-static void property_changed(GDBusProxy *proxy, const char *name,
+static void player_property_changed(GDBusProxy *proxy, const char *name,
DBusMessageIter *iter, void *user_data)
{
struct player *player;
- const char *interface, *property;
-
- interface = g_dbus_proxy_get_interface(proxy);
-
- if (strcmp(interface, "org.bluez.MediaPlayer1") != 0)
- return;
+ const char *property;
player = find_player(proxy);
if (player == NULL)
@@ -1530,6 +1660,45 @@ static void property_changed(GDBusProxy *proxy, const char *name,
property);
}
+static void transport_property_changed(GDBusProxy *proxy, const char *name,
+ DBusMessageIter *iter, void *user_data)
+{
+ struct player *player;
+ DBusMessageIter var;
+ const char *path;
+
+ if (strcasecmp(name, "Volume") != 0)
+ return;
+
+ if (!g_dbus_proxy_get_property(proxy, "Device", &var))
+ return;
+
+ dbus_message_iter_get_basic(&var, &path);
+
+ player = find_player_by_device(path);
+ if (player == NULL)
+ return;
+
+ g_dbus_emit_property_changed(player->conn, MPRIS_PLAYER_PATH,
+ MPRIS_PLAYER_INTERFACE,
+ name);
+}
+
+static void property_changed(GDBusProxy *proxy, const char *name,
+ DBusMessageIter *iter, void *user_data)
+{
+ const char *interface;
+
+ interface = g_dbus_proxy_get_interface(proxy);
+
+ if (strcmp(interface, BLUEZ_MEDIA_PLAYER_INTERFACE) == 0)
+ return player_property_changed(proxy, name, iter, user_data);
+
+ if (strcmp(interface, BLUEZ_MEDIA_TRANSPORT_INTERFACE) == 0)
+ return transport_property_changed(proxy, name, iter,
+ user_data);
+}
+
int main(int argc, char *argv[])
{
guint owner_watch, properties_watch;
--
1.8.0.2
^ permalink raw reply related
* [PATCH BlueZ 1/2] tools: Make mpris-player to export players using MPRIS interface
From: Luiz Augusto von Dentz @ 2013-01-18 14:41 UTC (permalink / raw)
To: linux-bluetooth
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
Players found are exported in private connections using
org.mpris.MediaPlayer2.<device name> on the session bus.
---
tools/mpris-player.c | 798 +++++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 779 insertions(+), 19 deletions(-)
diff --git a/tools/mpris-player.c b/tools/mpris-player.c
index 246791a..e3bab1c 100644
--- a/tools/mpris-player.c
+++ b/tools/mpris-player.c
@@ -32,6 +32,7 @@
#include <signal.h>
#include <getopt.h>
#include <string.h>
+#include <inttypes.h>
#include <dbus/dbus.h>
#include <glib.h>
@@ -41,13 +42,30 @@
#define BLUEZ_PATH "/org/bluez"
#define BLUEZ_ADAPTER_INTERFACE "org.bluez.Adapter1"
#define BLUEZ_MEDIA_INTERFACE "org.bluez.Media1"
+#define BLUEZ_MEDIA_PLAYER_INTERFACE "org.bluez.MediaPlayer1"
+#define MPRIS_BUS_NAME "org.mpris.MediaPlayer2."
+#define MPRIS_INTERFACE "org.mpris.MediaPlayer2"
#define MPRIS_PLAYER_INTERFACE "org.mpris.MediaPlayer2.Player"
#define MPRIS_PLAYER_PATH "/org/mpris/MediaPlayer2"
+#define ERROR_INTERFACE "org.mpris.MediaPlayer2.Error"
static GMainLoop *main_loop;
static GDBusProxy *adapter = NULL;
static DBusConnection *sys = NULL;
static DBusConnection *session = NULL;
+static GDBusClient *client = NULL;
+static GSList *players = NULL;
+
+struct player {
+ char *name;
+ char *bus_name;
+ DBusConnection *conn;
+ GDBusProxy *proxy;
+ GDBusProxy *device;
+};
+
+typedef int (* parse_metadata_func) (DBusMessageIter *iter, const char *key,
+ DBusMessageIter *metadata);
static void dict_append_entry(DBusMessageIter *dict, const char *key, int type,
void *val);
@@ -190,7 +208,8 @@ static int parse_metadata_entry(DBusMessageIter *entry, const char *key,
return 0;
}
-static int parse_metadata(DBusMessageIter *args, DBusMessageIter *metadata)
+static int parse_metadata(DBusMessageIter *args, DBusMessageIter *metadata,
+ parse_metadata_func func)
{
DBusMessageIter dict;
int ctype;
@@ -216,7 +235,7 @@ static int parse_metadata(DBusMessageIter *args, DBusMessageIter *metadata)
dbus_message_iter_get_basic(&entry, &key);
dbus_message_iter_next(&entry);
- if (parse_metadata_entry(&entry, key, metadata) < 0)
+ if (func(&entry, key, metadata) < 0)
return -EINVAL;
dbus_message_iter_next(&dict);
@@ -225,7 +244,8 @@ static int parse_metadata(DBusMessageIter *args, DBusMessageIter *metadata)
return 0;
}
-static void append_metadata(DBusMessageIter *iter, DBusMessageIter *dict)
+static void append_metadata(DBusMessageIter *iter, DBusMessageIter *dict,
+ parse_metadata_func func)
{
DBusMessageIter value, metadata;
@@ -237,7 +257,7 @@ static void append_metadata(DBusMessageIter *iter, DBusMessageIter *dict)
DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &metadata);
- parse_metadata(dict, &metadata);
+ parse_metadata(dict, &metadata, func);
dbus_message_iter_close_container(&value, &metadata);
dbus_message_iter_close_container(iter, &value);
@@ -260,7 +280,7 @@ static void dict_append_entry(DBusMessageIter *dict, const char *key, int type,
dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
if (strcasecmp(key, "Metadata") == 0)
- append_metadata(&entry, val);
+ append_metadata(&entry, val, parse_metadata_entry);
else
append_variant(&entry, type, val);
@@ -509,21 +529,29 @@ done:
static void remove_player(DBusConnection *conn, const char *sender)
{
DBusMessage *msg;
- char *path;
+ char *path, *owner;
if (!adapter)
return;
+ path = sender2path(sender);
+ dbus_connection_get_object_path_data(sys, path, (void **) &owner);
+
+ if (owner == NULL) {
+ g_free(path);
+ return;
+ }
+
msg = dbus_message_new_method_call(BLUEZ_BUS_NAME,
g_dbus_proxy_get_path(adapter),
BLUEZ_MEDIA_INTERFACE,
"UnregisterPlayer");
if (!msg) {
fprintf(stderr, "Can't allocate new method call\n");
+ g_free(path);
return;
}
- path = sender2path(sender);
dbus_message_append_args(msg, DBUS_TYPE_OBJECT_PATH, &path,
DBUS_TYPE_INVALID);
@@ -540,10 +568,16 @@ static gboolean properties_changed(DBusConnection *conn,
{
DBusMessageIter iter;
const char *iface;
- char *path;
+ char *path, *owner;
dbus_message_iter_init(msg, &iter);
+ path = sender2path(dbus_message_get_sender(msg));
+ dbus_connection_get_object_path_data(sys, path, (void **) &owner);
+
+ if (owner == NULL)
+ goto done;
+
if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
@@ -553,14 +587,28 @@ static gboolean properties_changed(DBusConnection *conn,
dbus_message_iter_next(&iter);
- path = sender2path(dbus_message_get_sender(msg));
parse_properties(conn, path, &iter, NULL);
+done:
g_free(path);
return TRUE;
}
+static struct player *find_player_by_bus_name(const char *name)
+{
+ GSList *l;
+
+ for (l = players; l; l = l->next) {
+ struct player *player = l->data;
+
+ if (strcmp(player->bus_name, name) == 0)
+ return player;
+ }
+
+ return NULL;
+}
+
static gboolean name_owner_changed(DBusConnection *conn,
DBusMessage *msg, void *data)
{
@@ -581,7 +629,7 @@ static gboolean name_owner_changed(DBusConnection *conn,
if (*new == '\0') {
printf("player %s at %s disappear\n", name, old);
remove_player(conn, old);
- } else {
+ } else if (find_player_by_bus_name(name) == NULL) {
printf("player %s at %s found\n", name, new);
add_player(conn, name, new);
}
@@ -733,21 +781,685 @@ static void disconnect_handler(DBusConnection *connection, void *user_data)
printf("org.bluez disappeared\n");
}
-static void proxy_added(GDBusProxy *proxy, void *user_data)
+static void player_free(void *data)
{
- const char *interface;
+ struct player *player = data;
+
+ if (player->conn) {
+ dbus_connection_close(player->conn);
+ dbus_connection_unref(player->conn);
+ }
+
+ g_dbus_proxy_unref(player->device);
+ g_dbus_proxy_unref(player->proxy);
+
+ g_free(player->name);
+ g_free(player->bus_name);
+ g_free(player);
+}
+
+struct pending_call {
+ struct player *player;
+ DBusMessage *msg;
+};
+
+static void pending_call_free(void *data)
+{
+ struct pending_call *p = data;
+
+ if (p->msg)
+ dbus_message_unref(p->msg);
+
+ g_free(p);
+}
+
+static void player_reply(DBusMessage *message, void *user_data)
+{
+ struct pending_call *p = user_data;
+ struct player *player = p->player;
+ DBusMessage *msg = p->msg;
+ DBusMessage *reply;
+ DBusError err;
+
+ dbus_error_init(&err);
+ if (dbus_set_error_from_message(&err, message)) {
+ fprintf(stderr, "error: %s", err.name);
+ reply = g_dbus_create_error(msg, err.name, err.message);
+ dbus_error_free(&err);
+ } else
+ reply = g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+
+ g_dbus_send_message(player->conn, reply);
+}
+
+static void player_control(struct player *player, DBusMessage *msg,
+ const char *name)
+{
+ struct pending_call *p;
+
+ p = g_new0(struct pending_call, 1);
+ p->player = player;
+ p->msg = dbus_message_ref(msg);
+
+ g_dbus_proxy_method_call(player->proxy, name, NULL, player_reply,
+ p, pending_call_free);
+}
+
+static DBusMessage *player_toggle(DBusConnection *conn, DBusMessage *msg,
+ void *data)
+{
+ struct player *player = data;
+ DBusMessageIter value;
+ const char *status;
+
+ if (!g_dbus_proxy_get_property(player->proxy, "Status", &value))
+ return FALSE;
+
+ dbus_message_iter_get_basic(&value, &status);
+
+ if (strcasecmp(status, "Playing") == 0)
+ player_control(player, msg, "Pause");
+ else
+ player_control(player, msg, "Play");
+
+ return NULL;
+}
+
+static DBusMessage *player_play(DBusConnection *conn, DBusMessage *msg,
+ void *data)
+{
+ struct player *player = data;
+
+ player_control(player, msg, "Play");
+
+ return NULL;
+}
+
+static DBusMessage *player_pause(DBusConnection *conn, DBusMessage *msg,
+ void *data)
+{
+ struct player *player = data;
+
+ player_control(player, msg, "Pause");
+
+ return NULL;
+}
+
+static DBusMessage *player_stop(DBusConnection *conn, DBusMessage *msg,
+ void *data)
+{
+ struct player *player = data;
+
+ player_control(player, msg, "Stop");
+
+ return NULL;
+}
+
+static DBusMessage *player_next(DBusConnection *conn, DBusMessage *msg,
+ void *data)
+{
+ struct player *player = data;
+
+ player_control(player, msg, "Next");
+
+ return NULL;
+}
+
+static DBusMessage *player_previous(DBusConnection *conn, DBusMessage *msg,
+ void *data)
+{
+ struct player *player = data;
+
+ player_control(player, msg, "Previous");
+
+ return NULL;
+}
+
+static gboolean status_exists(const GDBusPropertyTable *property, void *data)
+{
+ DBusMessageIter iter;
+ struct player *player = data;
+
+ return g_dbus_proxy_get_property(player->proxy, "Status", &iter);
+}
+
+static const char *status_to_playback(const char *status)
+{
+ if (strcasecmp(status, "playing") == 0)
+ return "Playing";
+ else if (strcasecmp(status, "paused") == 0)
+ return "Paused";
+ else
+ return "Stopped";
+}
+
+static gboolean get_status(const GDBusPropertyTable *property,
+ DBusMessageIter *iter, void *data)
+{
+
+ struct player *player = data;
+ DBusMessageIter value;
+ const char *status;
+
+ if (!g_dbus_proxy_get_property(player->proxy, "Status", &value))
+ return FALSE;
+
+ dbus_message_iter_get_basic(&value, &status);
+
+ status = status_to_playback(status);
+
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &status);
+
+ return TRUE;
+}
+
+static gboolean repeat_exists(const GDBusPropertyTable *property, void *data)
+{
+ DBusMessageIter iter;
+ struct player *player = data;
+
+ return g_dbus_proxy_get_property(player->proxy, "Repeat", &iter);
+}
+
+static const char *repeat_to_loopstatus(const char *value)
+{
+ if (strcasecmp(value, "off") == 0)
+ return "None";
+ else if (strcasecmp(value, "singletrack") == 0)
+ return "Track";
+ else if (strcasecmp(value, "alltracks") == 0)
+ return "Playlist";
+
+ return NULL;
+}
+
+static gboolean get_repeat(const GDBusPropertyTable *property,
+ DBusMessageIter *iter, void *data)
+{
+ struct player *player = data;
+ DBusMessageIter value;
+ const char *status;
+
+ if (!g_dbus_proxy_get_property(player->proxy, "Repeat", &value))
+ return FALSE;
+
+ dbus_message_iter_get_basic(&value, &status);
+
+ status = repeat_to_loopstatus(status);
+ if (status == NULL)
+ return FALSE;
+
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &status);
+
+ return TRUE;
+}
+
+static const char *loopstatus_to_repeat(const char *value)
+{
+ if (strcasecmp(value, "None") == 0)
+ return "off";
+ else if (strcasecmp(value, "Track") == 0)
+ return "singletrack";
+ else if (strcasecmp(value, "Playlist") == 0)
+ return "alltracks";
+
+ return NULL;
+}
+
+static void property_result(const DBusError *err, void *user_data)
+{
+ GDBusPendingPropertySet id = GPOINTER_TO_UINT(user_data);
+
+ if (!dbus_error_is_set(err))
+ return g_dbus_pending_property_success(id);
+
+ g_dbus_pending_property_error(id, err->name, err->message);
+}
+
+static void set_repeat(const GDBusPropertyTable *property,
+ DBusMessageIter *iter, GDBusPendingPropertySet id,
+ void *data)
+{
+ struct player *player = data;
+ const char *value;
+
+ if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRING) {
+ g_dbus_pending_property_error(id,
+ ERROR_INTERFACE ".InvalidArguments",
+ "Invalid arguments in method call");
+ return;
+ }
+
+ dbus_message_iter_get_basic(iter, &value);
+
+ value = loopstatus_to_repeat(value);
+ if (value == NULL) {
+ g_dbus_pending_property_error(id,
+ ERROR_INTERFACE ".InvalidArguments",
+ "Invalid arguments in method call");
+ return;
+ }
+
+ g_dbus_proxy_set_property_basic(player->proxy, "Repeat",
+ DBUS_TYPE_STRING, value,
+ property_result, GUINT_TO_POINTER(id),
+ NULL);
+}
+
+static gboolean get_double(const GDBusPropertyTable *property,
+ DBusMessageIter *iter, void *data)
+{
+ double value = 1.0;
+
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_DOUBLE, &value);
+
+ return TRUE;
+}
+
+static gboolean shuffle_exists(const GDBusPropertyTable *property, void *data)
+{
+ DBusMessageIter iter;
+ struct player *player = data;
+
+ return g_dbus_proxy_get_property(player->proxy, "Shuffle", &iter);
+}
+
+static gboolean get_shuffle(const GDBusPropertyTable *property,
+ DBusMessageIter *iter, void *data)
+{
+ struct player *player = data;
+ DBusMessageIter value;
+ const char *string;
+ dbus_bool_t shuffle;
+
+ if (!g_dbus_proxy_get_property(player->proxy, "Shuffle", &value))
+ return FALSE;
+
+ dbus_message_iter_get_basic(&value, &string);
+
+ shuffle = strcmp(string, "off") != 0;
+
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &shuffle);
+
+ return TRUE;
+}
+
+static void set_shuffle(const GDBusPropertyTable *property,
+ DBusMessageIter *iter, GDBusPendingPropertySet id,
+ void *data)
+{
+ struct player *player = data;
+ dbus_bool_t shuffle;
+ const char *value;
+
+ if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_BOOLEAN) {
+ g_dbus_pending_property_error(id,
+ ERROR_INTERFACE ".InvalidArguments",
+ "Invalid arguments in method call");
+ return;
+ }
+
+ dbus_message_iter_get_basic(iter, &shuffle);
+ value = shuffle ? "alltracks" : "off";
+
+ g_dbus_proxy_set_property_basic(player->proxy, "Shuffle",
+ DBUS_TYPE_STRING, value,
+ property_result, GUINT_TO_POINTER(id),
+ NULL);
+}
+
+static gboolean position_exists(const GDBusPropertyTable *property, void *data)
+{
+ DBusMessageIter iter;
+ struct player *player = data;
+
+ return g_dbus_proxy_get_property(player->proxy, "Position", &iter);
+}
- if (adapter != NULL)
+static gboolean get_position(const GDBusPropertyTable *property,
+ DBusMessageIter *iter, void *data)
+{
+ struct player *player = data;
+ DBusMessageIter var;
+ uint32_t position;
+ int64_t value;
+
+ if (!g_dbus_proxy_get_property(player->proxy, "Position", &var))
+ return FALSE;
+
+ dbus_message_iter_get_basic(&var, &position);
+
+ value = position * 1000;
+
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_INT64, &value);
+
+ return TRUE;
+}
+
+static gboolean track_exists(const GDBusPropertyTable *property, void *data)
+{
+ DBusMessageIter iter;
+ struct player *player = data;
+
+ return g_dbus_proxy_get_property(player->proxy, "Track", &iter);
+}
+
+static gboolean parse_string_metadata(DBusMessageIter *iter, const char *key,
+ DBusMessageIter *metadata)
+{
+ const char *value;
+
+ if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRING)
+ return FALSE;
+
+ dbus_message_iter_get_basic(iter, &value);
+
+ dict_append_entry(metadata, key, DBUS_TYPE_STRING, &value);
+
+ return TRUE;
+}
+
+static gboolean parse_array_metadata(DBusMessageIter *iter, const char *key,
+ DBusMessageIter *metadata)
+{
+ char **value;
+
+ if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRING)
+ return FALSE;
+
+ value = dbus_malloc0(sizeof(char *));
+
+ dbus_message_iter_get_basic(iter, &(value[0]));
+
+ dict_append_array(metadata, key, DBUS_TYPE_STRING, &value, 1);
+
+ dbus_free(value);
+
+ return TRUE;
+}
+
+static gboolean parse_int64_metadata(DBusMessageIter *iter, const char *key,
+ DBusMessageIter *metadata)
+{
+ uint32_t duration;
+ int64_t value;
+
+ if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_UINT32)
+ return FALSE;
+
+ dbus_message_iter_get_basic(iter, &duration);
+
+ value = duration * 1000;
+
+ dict_append_entry(metadata, key, DBUS_TYPE_INT64, &value);
+
+ return TRUE;
+}
+
+static gboolean parse_int32_metadata(DBusMessageIter *iter, const char *key,
+ DBusMessageIter *metadata)
+{
+ uint32_t value;
+
+ if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_UINT32)
+ return FALSE;
+
+ dbus_message_iter_get_basic(iter, &value);
+
+ dict_append_entry(metadata, key, DBUS_TYPE_INT32, &value);
+
+ return TRUE;
+}
+
+static int parse_track_entry(DBusMessageIter *entry, const char *key,
+ DBusMessageIter *metadata)
+{
+ DBusMessageIter var;
+
+ printf("metadata %s found\n", key);
+
+ if (dbus_message_iter_get_arg_type(entry) != DBUS_TYPE_VARIANT)
+ return -EINVAL;
+
+ dbus_message_iter_recurse(entry, &var);
+
+ if (strcasecmp(key, "Title") == 0) {
+ if (!parse_string_metadata(&var, "xesam:title", metadata))
+ return -EINVAL;
+ } else if (strcasecmp(key, "Artist") == 0) {
+ if (!parse_array_metadata(&var, "xesam:artist", metadata))
+ return -EINVAL;
+ } else if (strcasecmp(key, "Album") == 0) {
+ if (!parse_string_metadata(&var, "xesam:album", metadata))
+ return -EINVAL;
+ } else if (strcasecmp(key, "Genre") == 0) {
+ if (!parse_array_metadata(&var, "xesam:genre", metadata))
+ return -EINVAL;
+ } else if (strcasecmp(key, "Duration") == 0) {
+ if (!parse_int64_metadata(&var, "mpris:length", metadata))
+ return -EINVAL;
+ } else if (strcasecmp(key, "TrackNumber") == 0) {
+ if (!parse_int32_metadata(&var, "xesam:trackNumber", metadata))
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static gboolean get_track(const GDBusPropertyTable *property,
+ DBusMessageIter *iter, void *data)
+{
+ struct player *player = data;
+ DBusMessageIter var, metadata;
+
+ if (!g_dbus_proxy_get_property(player->proxy, "Track", &var))
+ return FALSE;
+
+ dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &metadata);
+
+ parse_metadata(&var, &metadata, parse_track_entry);
+
+ dbus_message_iter_close_container(iter, &metadata);
+
+ return TRUE;
+}
+
+static gboolean get_enable(const GDBusPropertyTable *property,
+ DBusMessageIter *iter, void *data)
+{
+ dbus_bool_t value = TRUE;
+
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &value);
+
+ return TRUE;
+}
+
+static gboolean get_disable(const GDBusPropertyTable *property,
+ DBusMessageIter *iter, void *data)
+{
+ dbus_bool_t value = FALSE;
+
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &value);
+
+ return TRUE;
+}
+
+static const GDBusMethodTable player_methods[] = {
+ { GDBUS_ASYNC_METHOD("PlayPause", NULL, NULL, player_toggle) },
+ { GDBUS_ASYNC_METHOD("Play", NULL, NULL, player_play) },
+ { GDBUS_ASYNC_METHOD("Pause", NULL, NULL, player_pause) },
+ { GDBUS_ASYNC_METHOD("Stop", NULL, NULL, player_stop) },
+ { GDBUS_ASYNC_METHOD("Next", NULL, NULL, player_next) },
+ { GDBUS_ASYNC_METHOD("Previous", NULL, NULL, player_previous) },
+ { }
+};
+
+static const GDBusSignalTable player_signals[] = {
+ { GDBUS_SIGNAL("Seeked", GDBUS_ARGS({"Position", "x"})) },
+ { }
+};
+
+static const GDBusPropertyTable player_properties[] = {
+ { "PlaybackStatus", "s", get_status, NULL, status_exists },
+ { "LoopStatus", "s", get_repeat, set_repeat, repeat_exists },
+ { "Rate", "d", get_double, NULL, NULL },
+ { "MinimumRate", "d", get_double, NULL, NULL },
+ { "MaximumRate", "d", get_double, NULL, NULL },
+ { "Shuffle", "b", get_shuffle, set_shuffle, shuffle_exists },
+ { "Position", "x", get_position, NULL, position_exists },
+ { "Metadata", "a{sv}", get_track, NULL, track_exists },
+ { "Volume", "d", get_double, NULL, NULL },
+ { "CanGoNext", "b", get_enable, NULL, NULL },
+ { "CanGoPrevious", "b", get_enable, NULL, NULL },
+ { "CanPlay", "b", get_enable, NULL, NULL },
+ { "CanPause", "b", get_enable, NULL, NULL },
+ { "CanSeek", "b", get_enable, NULL, NULL },
+ { "CanControl", "b", get_enable, NULL, NULL },
+ { }
+};
+
+static const GDBusMethodTable mpris_methods[] = {
+ { }
+};
+
+static gboolean get_name(const GDBusPropertyTable *property,
+ DBusMessageIter *iter, void *data)
+{
+ struct player *player = data;
+
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &player->name);
+
+ return TRUE;
+}
+
+static const GDBusPropertyTable mpris_properties[] = {
+ { "CanQuit", "b", get_disable, NULL, NULL },
+ { "Fullscreen", "b", get_disable, NULL, NULL },
+ { "CanSetFullscreen", "b", get_disable, NULL, NULL },
+ { "CanRaise", "b", get_disable, NULL, NULL },
+ { "HasTrackList", "b", get_disable, NULL, NULL },
+ { "Identity", "s", get_name, NULL, NULL },
+ { }
+};
+
+static char *mpris_busname(const char *name)
+{
+ char *bus_name;
+
+ bus_name = g_strconcat(MPRIS_BUS_NAME, name, NULL);
+ return g_strdelimit(bus_name, " ’", '_');
+}
+
+static void register_player(GDBusProxy *proxy)
+{
+ struct player *player;
+ DBusMessageIter iter;
+ const char *path, *name;
+ GDBusProxy *device;
+
+ if (!g_dbus_proxy_get_property(proxy, "Device", &iter))
+ return;
+
+ dbus_message_iter_get_basic(&iter, &path);
+
+ device = g_dbus_proxy_new(client, path, "org.bluez.Device1");
+ if (device == NULL)
return;
+ if (!g_dbus_proxy_get_property(device, "Name", &iter))
+ return;
+
+ dbus_message_iter_get_basic(&iter, &name);
+
+ player = g_new0(struct player, 1);
+ player->name = g_strdup(name);
+ player->bus_name = mpris_busname(name);
+ player->proxy = g_dbus_proxy_ref(proxy);
+ player->device = device;
+
+ players = g_slist_prepend(players, player);
+
+ player->conn = g_dbus_setup_private(DBUS_BUS_SESSION, player->bus_name,
+ NULL);
+ if (!session) {
+ fprintf(stderr, "Could not register bus name %s",
+ player->bus_name);
+ goto fail;
+ }
+
+ if (!g_dbus_register_interface(player->conn, MPRIS_PLAYER_PATH,
+ MPRIS_INTERFACE,
+ mpris_methods,
+ NULL,
+ mpris_properties,
+ player, NULL)) {
+ fprintf(stderr, "Could not register interface %s",
+ MPRIS_INTERFACE);
+ goto fail;
+ }
+
+ if (!g_dbus_register_interface(player->conn, MPRIS_PLAYER_PATH,
+ MPRIS_PLAYER_INTERFACE,
+ player_methods,
+ player_signals,
+ player_properties,
+ player, player_free)) {
+ fprintf(stderr, "Could not register interface %s",
+ MPRIS_PLAYER_INTERFACE);
+ goto fail;
+ }
+
+ return;
+
+fail:
+ players = g_slist_remove(players, player);
+ player_free(player);
+}
+
+static void proxy_added(GDBusProxy *proxy, void *user_data)
+{
+ const char *interface;
+
interface = g_dbus_proxy_get_interface(proxy);
if (!strcmp(interface, BLUEZ_ADAPTER_INTERFACE)) {
+ if (adapter != NULL)
+ return;
+
printf("Bluetooth Adapter %s found\n",
g_dbus_proxy_get_path(proxy));
adapter = proxy;
list_names(session);
+ } else if (!strcmp(interface, BLUEZ_MEDIA_PLAYER_INTERFACE)) {
+ printf("Bluetooth Player %s found\n",
+ g_dbus_proxy_get_path(proxy));
+ register_player(proxy);
+ }
+}
+
+static void unregister_player(struct player *player)
+{
+ players = g_slist_remove(players, player);
+
+ g_dbus_unregister_interface(player->conn, MPRIS_PLAYER_PATH,
+ MPRIS_PLAYER_INTERFACE);
+}
+
+static struct player *find_player(GDBusProxy *proxy)
+{
+ GSList *l;
+
+ for (l = players; l; l = l->next) {
+ struct player *player = l->data;
+
+ if (player->proxy == proxy)
+ return player;
}
+
+ return NULL;
}
static void proxy_removed(GDBusProxy *proxy, void *user_data)
@@ -759,19 +1471,67 @@ static void proxy_removed(GDBusProxy *proxy, void *user_data)
interface = g_dbus_proxy_get_interface(proxy);
- if (strcmp(interface, BLUEZ_ADAPTER_INTERFACE))
+ if (strcmp(interface, BLUEZ_ADAPTER_INTERFACE) == 0) {
+ if (adapter != proxy)
+ return;
+ printf("Bluetooth Adapter %s removed\n",
+ g_dbus_proxy_get_path(proxy));
+ adapter = NULL;
+ } else if (strcmp(interface, BLUEZ_MEDIA_PLAYER_INTERFACE) == 0) {
+ struct player *player;
+
+ player = find_player(proxy);
+ if (player == NULL)
+ return;
+
+ printf("Bluetooth Player %s removed\n",
+ g_dbus_proxy_get_path(proxy));
+ unregister_player(player);
+ }
+}
+
+static const char *property_to_mpris(const char *property)
+{
+ if (strcasecmp(property, "Repeat") == 0)
+ return "LoopStatus";
+ else if (strcasecmp(property, "Shuffle") == 0)
+ return "Shuffle";
+ else if (strcasecmp(property, "Status") == 0)
+ return "PlaybackStatus";
+ else if (strcasecmp(property, "Position") == 0)
+ return "Position";
+ else if (strcasecmp(property, "Track") == 0)
+ return "Metadata";
+
+ return NULL;
+}
+
+static void property_changed(GDBusProxy *proxy, const char *name,
+ DBusMessageIter *iter, void *user_data)
+{
+ struct player *player;
+ const char *interface, *property;
+
+ interface = g_dbus_proxy_get_interface(proxy);
+
+ if (strcmp(interface, "org.bluez.MediaPlayer1") != 0)
return;
- if (adapter != proxy)
+ player = find_player(proxy);
+ if (player == NULL)
return;
- printf("Bluetooth Adapter %s removed\n", g_dbus_proxy_get_path(proxy));
- adapter = NULL;
+ property = property_to_mpris(name);
+ if (property == NULL)
+ return;
+
+ g_dbus_emit_property_changed(player->conn, MPRIS_PLAYER_PATH,
+ MPRIS_PLAYER_INTERFACE,
+ property);
}
int main(int argc, char *argv[])
{
- GDBusClient *client;
guint owner_watch, properties_watch;
struct sigaction sa;
int opt;
@@ -825,7 +1585,7 @@ int main(int argc, char *argv[])
g_dbus_client_set_disconnect_watch(client, disconnect_handler, NULL);
g_dbus_client_set_proxy_handlers(client, proxy_added, proxy_removed,
- NULL, NULL);
+ property_changed, NULL);
g_main_loop_run(main_loop);
--
1.8.0.2
^ permalink raw reply related
* Re: [PATCH 1/2] tools: Add mgmt test case for pair device while powered off
From: Johan Hedberg @ 2013-01-18 13:26 UTC (permalink / raw)
To: Szymon Janc; +Cc: linux-bluetooth
In-Reply-To: <1358509895-7460-1-git-send-email-szymon.janc@tieto.com>
Hi Szymon,
On Fri, Jan 18, 2013, Szymon Janc wrote:
> This tests if kernel is responding with proper command complete event.
> ---
> tools/mgmt-tester.c | 17 +++++++++++++++++
> 1 file changed, 17 insertions(+)
Applied. Thanks.
Johan
^ permalink raw reply
* [PATCH 10/10] Bluetooth: Fix returning proper cmd_complete for mgmt_block/unblock
From: Johan Hedberg @ 2013-01-18 13:25 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1358515558-17861-1-git-send-email-johan.hedberg@gmail.com>
From: Johan Hedberg <johan.hedberg@intel.com>
The Block/Unblock Device Management commands should return Command
Complete instead of Command Status whenever possible so that user space
can distinguish exactly which command failed in the case of multiple
commands. This patch does the necessary changes in the command handler
to return the right event to user space.
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
---
net/bluetooth/mgmt.c | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 184673e..50daae8 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -2599,8 +2599,9 @@ static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
BT_DBG("%s", hdev->name);
if (!bdaddr_type_is_valid(cp->addr.type))
- return cmd_status(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
- MGMT_STATUS_INVALID_PARAMS);
+ return cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
+ MGMT_STATUS_INVALID_PARAMS,
+ &cp->addr, sizeof(cp->addr));
hci_dev_lock(hdev);
@@ -2628,8 +2629,9 @@ static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
BT_DBG("%s", hdev->name);
if (!bdaddr_type_is_valid(cp->addr.type))
- return cmd_status(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
- MGMT_STATUS_INVALID_PARAMS);
+ return cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
+ MGMT_STATUS_INVALID_PARAMS,
+ &cp->addr, sizeof(cp->addr));
hci_dev_lock(hdev);
--
1.7.10.4
^ permalink raw reply related
* [PATCH 09/10] Bluetooth: Fix returning proper cmd_complete for mgmt_disconnect
From: Johan Hedberg @ 2013-01-18 13:25 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1358515558-17861-1-git-send-email-johan.hedberg@gmail.com>
From: Johan Hedberg <johan.hedberg@intel.com>
The Disconnect Management command should return Command Complete instead
of Command Status whenever possible so that user space can distinguish
exactly which command failed in the case of multiple commands. This
patch does the necessary changes in the disconnect command handler to
return the right event to user space.
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
---
net/bluetooth/mgmt.c | 22 ++++++++++++++--------
1 file changed, 14 insertions(+), 8 deletions(-)
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 8ec3c4f..184673e 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -1655,6 +1655,7 @@ static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
u16 len)
{
struct mgmt_cp_disconnect *cp = data;
+ struct mgmt_rp_disconnect rp;
struct hci_cp_disconnect dc;
struct pending_cmd *cmd;
struct hci_conn *conn;
@@ -1662,21 +1663,26 @@ static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
BT_DBG("");
+ memset(&rp, 0, sizeof(rp));
+ bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
+ rp.addr.type = cp->addr.type;
+
if (!bdaddr_type_is_valid(cp->addr.type))
- return cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT,
- MGMT_STATUS_INVALID_PARAMS);
+ return cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
+ MGMT_STATUS_INVALID_PARAMS,
+ &rp, sizeof(rp));
hci_dev_lock(hdev);
if (!test_bit(HCI_UP, &hdev->flags)) {
- err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT,
- MGMT_STATUS_NOT_POWERED);
+ err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
+ MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
goto failed;
}
if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
- err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT,
- MGMT_STATUS_BUSY);
+ err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
+ MGMT_STATUS_BUSY, &rp, sizeof(rp));
goto failed;
}
@@ -1687,8 +1693,8 @@ static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
- err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT,
- MGMT_STATUS_NOT_CONNECTED);
+ err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
+ MGMT_STATUS_NOT_CONNECTED, &rp, sizeof(rp));
goto failed;
}
--
1.7.10.4
^ permalink raw reply related
* [PATCH 08/10] Bluetooth: Fix checking for valid disconnect parameters in unpair_device
From: Johan Hedberg @ 2013-01-18 13:25 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1358515558-17861-1-git-send-email-johan.hedberg@gmail.com>
From: Johan Hedberg <johan.hedberg@intel.com>
The valid values for the Disconnect parameter in the Unpair Device
command are 0x00 and 0x01. If any other value is encountered the command
should fail with the appropriate invalid params response.
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
---
net/bluetooth/mgmt.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 3de4bc2..8ec3c4f 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -1591,6 +1591,11 @@ static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
MGMT_STATUS_INVALID_PARAMS,
&rp, sizeof(rp));
+ if (cp->disconnect != 0x00 && cp->disconnect != 0x01)
+ return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
+ MGMT_STATUS_INVALID_PARAMS,
+ &rp, sizeof(rp));
+
hci_dev_lock(hdev);
if (!hdev_is_powered(hdev)) {
--
1.7.10.4
^ permalink raw reply related
* [PATCH 07/10] Bluetooth: Fix checking for valid address type values in mgmt commands
From: Johan Hedberg @ 2013-01-18 13:25 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1358515558-17861-1-git-send-email-johan.hedberg@gmail.com>
From: Johan Hedberg <johan.hedberg@intel.com>
This patch adds checks for valid address type values passed to mgmt
commands. If an invalid address type is encountered the code will return
a proper invalid params response.
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
---
net/bluetooth/mgmt.c | 43 ++++++++++++++++++++++++++++++++++++++-----
1 file changed, 38 insertions(+), 5 deletions(-)
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 76301a3..3de4bc2 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -1506,7 +1506,7 @@ static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
{
struct mgmt_cp_load_link_keys *cp = data;
u16 key_count, expected_len;
- int i;
+ int i, err;
key_count = __le16_to_cpu(cp->key_count);
@@ -1540,15 +1540,24 @@ static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
for (i = 0; i < key_count; i++) {
struct mgmt_link_key_info *key = &cp->keys[i];
+ if (key->addr.type != BDADDR_BREDR) {
+ clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
+ hci_link_keys_clear(hdev);
+ err = cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
+ MGMT_STATUS_INVALID_PARAMS);
+ goto unlock;
+ }
+
hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
key->type, key->pin_len);
}
- cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
+ err = cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
+unlock:
hci_dev_unlock(hdev);
- return 0;
+ return err;
}
static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
@@ -1573,12 +1582,17 @@ static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
struct hci_conn *conn;
int err;
- hci_dev_lock(hdev);
-
memset(&rp, 0, sizeof(rp));
bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
rp.addr.type = cp->addr.type;
+ if (!bdaddr_type_is_valid(cp->addr.type))
+ return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
+ MGMT_STATUS_INVALID_PARAMS,
+ &rp, sizeof(rp));
+
+ hci_dev_lock(hdev);
+
if (!hdev_is_powered(hdev)) {
err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
@@ -1643,6 +1657,10 @@ static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
BT_DBG("");
+ if (!bdaddr_type_is_valid(cp->addr.type))
+ return cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT,
+ MGMT_STATUS_INVALID_PARAMS);
+
hci_dev_lock(hdev);
if (!test_bit(HCI_UP, &hdev->flags)) {
@@ -1947,6 +1965,11 @@ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
rp.addr.type = cp->addr.type;
+ if (!bdaddr_type_is_valid(cp->addr.type))
+ return cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
+ MGMT_STATUS_INVALID_PARAMS,
+ &rp, sizeof(rp));
+
hci_dev_lock(hdev);
if (!hdev_is_powered(hdev)) {
@@ -2564,6 +2587,10 @@ static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
BT_DBG("%s", hdev->name);
+ if (!bdaddr_type_is_valid(cp->addr.type))
+ return cmd_status(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
+ MGMT_STATUS_INVALID_PARAMS);
+
hci_dev_lock(hdev);
err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
@@ -2589,6 +2616,10 @@ static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
BT_DBG("%s", hdev->name);
+ if (!bdaddr_type_is_valid(cp->addr.type))
+ return cmd_status(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
+ MGMT_STATUS_INVALID_PARAMS);
+
hci_dev_lock(hdev);
err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
@@ -2707,6 +2738,8 @@ static bool ltk_is_valid(struct mgmt_ltk_info *key)
return false;
if (key->master != 0x00 && key->master != 0x01)
return false;
+ if (!bdaddr_type_is_le(key->addr.type))
+ return false;
return true;
}
--
1.7.10.4
^ permalink raw reply related
* [PATCH 06/10] Bluetooth: Add helper functions for testing bdaddr types
From: Johan Hedberg @ 2013-01-18 13:25 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1358515558-17861-1-git-send-email-johan.hedberg@gmail.com>
From: Johan Hedberg <johan.hedberg@intel.com>
This patch adds two helper functions to test for valid bdaddr type
values. These will be particularely useful in the mgmt code to check
that user space has passed valid values to the kernel.
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
---
include/net/bluetooth/bluetooth.h | 23 +++++++++++++++++++++++
1 file changed, 23 insertions(+)
diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h
index 2554b3f..9531bee 100644
--- a/include/net/bluetooth/bluetooth.h
+++ b/include/net/bluetooth/bluetooth.h
@@ -166,6 +166,29 @@ typedef struct {
#define BDADDR_LE_PUBLIC 0x01
#define BDADDR_LE_RANDOM 0x02
+static inline bool bdaddr_type_is_valid(__u8 type)
+{
+ switch (type) {
+ case BDADDR_BREDR:
+ case BDADDR_LE_PUBLIC:
+ case BDADDR_LE_RANDOM:
+ return true;
+ }
+
+ return false;
+}
+
+static inline bool bdaddr_type_is_le(__u8 type)
+{
+ switch (type) {
+ case BDADDR_LE_PUBLIC:
+ case BDADDR_LE_RANDOM:
+ return true;
+ }
+
+ return false;
+}
+
#define BDADDR_ANY (&(bdaddr_t) {{0, 0, 0, 0, 0, 0} })
#define BDADDR_LOCAL (&(bdaddr_t) {{0, 0, 0, 0xff, 0xff, 0xff} })
--
1.7.10.4
^ permalink raw reply related
* [PATCH 05/10] Bluetooth: Check for valid key->authenticated value for LTKs
From: Johan Hedberg @ 2013-01-18 13:25 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1358515558-17861-1-git-send-email-johan.hedberg@gmail.com>
From: Johan Hedberg <johan.hedberg@intel.com>
This patch adds necessary checks for the two allowed values of the
authenticated parameter of each Long Term Key, i.e. 0x00 and 0x01. If
any other value is encountered the valid response is to return invalid
params to user space.
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
---
net/bluetooth/mgmt.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 3634907..76301a3 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -2703,6 +2703,8 @@ done:
static bool ltk_is_valid(struct mgmt_ltk_info *key)
{
+ if (key->authenticated != 0x00 && key->authenticated != 0x01)
+ return false;
if (key->master != 0x00 && key->master != 0x01)
return false;
return true;
--
1.7.10.4
^ permalink raw reply related
* [PATCH 04/10] Bluetooth: Refactor valid LTK data testing into its own function
From: Johan Hedberg @ 2013-01-18 13:25 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1358515558-17861-1-git-send-email-johan.hedberg@gmail.com>
From: Johan Hedberg <johan.hedberg@intel.com>
This patch refactors valid LTK data testing into its own function. This
will help keep the code readable since there are several tests still
missing that need to be done on the LTK data.
---
net/bluetooth/mgmt.c | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 5388151..3634907 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -2701,6 +2701,13 @@ done:
return err;
}
+static bool ltk_is_valid(struct mgmt_ltk_info *key)
+{
+ if (key->master != 0x00 && key->master != 0x01)
+ return false;
+ return true;
+}
+
static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
void *cp_data, u16 len)
{
@@ -2729,7 +2736,7 @@ static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
struct mgmt_ltk_info *key = &cp->keys[i];
u8 type;
- if (key->master != 0x00 && key->master != 0x01) {
+ if (!ltk_is_valid(key)) {
hci_smp_ltks_clear(hdev);
err = cmd_status(sk, hdev->id,
MGMT_OP_LOAD_LONG_TERM_KEYS,
--
1.7.10.4
^ permalink raw reply related
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