Comment should be aproperiate for advertising command. Device needs to
be powered to advertise.
---
tools/btpclient.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tools/btpclient.c b/tools/btpclient.c
index af0e75290..33116ce1b 100644
--- a/tools/btpclient.c
+++ b/tools/btpclient.c
@@ -1038,7 +1038,7 @@ static void btp_gap_start_advertising(uint8_t index, const void *param,
goto failed;
}
- /* Adapter needs to be powered to be able to remove devices */
+ /* Adapter needs to be powered to be able to advertise */
if (!l_dbus_proxy_get_property(adapter->proxy, "Powered", "b", &prop) ||
!prop || ad.registered)
goto failed;
--
2.13.6
Hi Szymon,
2018-01-23 15:03 GMT+01:00 Szymon Janc <[email protected]>:
> Hi Grzegorz,
>
> On Friday, 19 January 2018 17:41:33 CET Grzegorz Kolodziejczyk wrote:
>> This patch adds passkey confirm command handler and passkey confirm
>> event.
>> ---
>> tools/btpclient.c | 94
>> +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, =
94
>> insertions(+)
>>
>> diff --git a/tools/btpclient.c b/tools/btpclient.c
>> index 55e5170a7..780c2a8db 100644
>> --- a/tools/btpclient.c
>> +++ b/tools/btpclient.c
>> @@ -1703,11 +1703,43 @@ static struct l_dbus_message
>> *ag_request_confirmation_call(struct l_dbus *dbus, struct l_dbus_message
>> *message,
>> void *user_data)
>> {
>> + struct btp_gap_passkey_confirm_ev ev;
>> + struct btp_device *device;
>> + struct btp_adapter *adapter;
>> struct l_dbus_message *reply;
>> + const char *path, *str_addr, *str_addr_type;
>> + uint32_t passkey;
>>
>> reply =3D l_dbus_message_new_method_return(message);
>> l_dbus_message_set_arguments(reply, "");
>>
>> + l_dbus_message_get_arguments(message, "ou", &path, &passkey);
>> +
>> + device =3D find_device_by_path(path);
>> +
>> + if (!l_dbus_proxy_get_property(device->proxy, "Address", "s", &str=
_addr)
>> + || !l_dbus_proxy_get_property(device->proxy, "AddressType"=
, "s",
>> + &str_addr_type)) {
>> + l_info("Cannot get device properties");
>> +
>> + return reply;
>> + }
>> +
>> + ev.passkey =3D L_CPU_TO_LE32(passkey);
>> + ev.address_type =3D strcmp(str_addr_type, "public") ?
>> + BTP_GAP_ADDR_RANDO=
M :
>> + BTP_GAP_ADDR_PUBLI=
C;
>> + if (str2ba(str_addr, &ev.address) < 0) {
>> + l_info("Incorrect device address");
>> +
>> + return reply;
>> + }
>> +
>> + adapter =3D find_adapter_by_device(device);
>> +
>> + btp_send(btp, BTP_GAP_SERVICE, BTP_EV_GAP_PASSKEY_CONFIRM,
>> + adapter->index, sizeof(ev), &ev);
>> +
>> return reply;
>
> So ag.pending request should be stored here. And reply here should be ret=
urned
> only in case of error.
Will fix it
>
>> }
>>
>> @@ -2082,6 +2114,65 @@ failed:
>> btp_send_error(btp, BTP_GAP_SERVICE, index, status);
>> }
>>
>> +static void passkey_confirm_rsp_reply(struct l_dbus_message *result,
>> + void *user=
_data)
>> +{
>> + struct btp_adapter *adapter =3D user_data;
>> +
>> + if (l_dbus_message_is_error(result)) {
>> + const char *name, *desc;
>> +
>> + l_dbus_message_get_error(result, &name, &desc);
>> + l_error("Failed to confirm passkey (%s), %s", name, desc);
>> +
>> + btp_send_error(btp, BTP_GAP_SERVICE, adapter->index,
>> + BTP_ERROR_=
FAIL);
>> + return;
>> + }
>> +
>> + l_dbus_message_unref(ag.pending_req);
>> +
>> + btp_send(btp, BTP_GAP_SERVICE, BTP_OP_GAP_PASSKEY_CONFIRM_RSP,
>> + adapter->index, 0, NULL);
>> +}
>> +
>> +static void btp_gap_confirm_entry_rsp(uint8_t index, const void *param,
>> + uint16_t length, void *user_data)
>> +{
>> + const struct btp_gap_passkey_confirm_rsp_cp *cp =3D param;
>> + struct btp_adapter *adapter =3D find_adapter_by_index(index);
>> + struct l_dbus_message *reply;
>> + uint8_t status =3D BTP_ERROR_FAIL;
>> + bool prop;
>> +
>> + if (!adapter) {
>> + status =3D BTP_ERROR_INVALID_INDEX;
>> + goto failed;
>> + }
>> +
>> + /* Adapter needs to be powered to be able to confirm passkey */
>> + if (!l_dbus_proxy_get_property(adapter->proxy, "Powered", "b", &pr=
op) ||
>> + !prop || !ag.pending_req)
>> + goto failed;
>> +
>> + if (cp->match) {
>> + reply =3D l_dbus_message_new_method_return(ag.pending_req)=
;
>> + l_dbus_message_set_arguments(reply, "");
>> + } else {
>> + reply =3D l_dbus_message_new_error(ag.pending_req,
>> + "org.bluez.Error.Rejected"=
,
>> + "Passkey missmatch");
>> + }
>> +
>> + l_dbus_send_with_reply(dbus, ag.pending_req, passkey_confirm_rsp_r=
eply,
>> + adapter, N=
ULL);
>> +
>> + return;
>> +
>> +failed:
>> + btp_send_error(btp, BTP_GAP_SERVICE, index, status);
>> +}
>> +
>> static void btp_gap_device_found_ev(struct l_dbus_proxy *proxy)
>> {
>> struct btp_device_found_ev ev;
>> @@ -2215,6 +2306,9 @@ static void register_gap_service(void)
>>
>> btp_register(btp, BTP_GAP_SERVICE, BTP_OP_GAP_PASSKEY_ENTRY_RSP,
>> btp_gap_passkey_entry_rsp, NULL, N=
ULL);
>> +
>> + btp_register(btp, BTP_GAP_SERVICE, BTP_OP_GAP_PASSKEY_CONFIRM_RSP,
>> + btp_gap_confirm_entry_rsp, NULL, N=
ULL);
>> }
>>
>> static void btp_core_read_commands(uint8_t index, const void *param,
>
>
> --
> pozdrawiam
> Szymon Janc
>
>
pozdrawiam,
Grzegorz Ko=C5=82odziejczyk
Hi Szymon,
2018-01-23 14:53 GMT+01:00 Szymon Janc <[email protected]>:
> Hi Grzegorz,
>
> On Friday, 19 January 2018 17:41:31 CET Grzegorz Kolodziejczyk wrote:
>> This patch adds pair and unpair commands for btp client.
>> ---
>> tools/btpclient.c | 124
>> ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1=
24
>> insertions(+)
>>
>> diff --git a/tools/btpclient.c b/tools/btpclient.c
>> index 53c0d4c05..9d44fba41 100644
>> --- a/tools/btpclient.c
>> +++ b/tools/btpclient.c
>> @@ -304,6 +304,8 @@ static void btp_gap_read_commands(uint8_t index, con=
st
>> void *param, commands |=3D (1 << BTP_OP_GAP_CONNECT);
>> commands |=3D (1 << BTP_OP_GAP_DISCONNECT);
>> commands |=3D (1 << BTP_OP_GAP_SET_IO_CAPA);
>> + commands |=3D (1 << BTP_OP_GAP_PAIR);
>> + commands |=3D (1 << BTP_OP_GAP_UNPAIR);
>>
>> commands =3D L_CPU_TO_LE16(commands);
>>
>> @@ -1875,6 +1877,122 @@ failed:
>> btp_send_error(btp, BTP_GAP_SERVICE, index, status);
>> }
>>
>> +static void pair_reply(struct l_dbus_proxy *proxy,
>> + struct l_dbus_message *result, void *user_=
data)
>> +{
>> + uint8_t adapter_index =3D L_PTR_TO_UINT(user_data);
>> + struct btp_adapter *adapter =3D find_adapter_by_index(adapter_inde=
x);
>> +
>> + if (!adapter)
>> + return;
>> +
>> + if (l_dbus_message_is_error(result)) {
>> + const char *name, *desc;
>> +
>> + l_dbus_message_get_error(result, &name, &desc);
>> + l_error("Failed to pair (%s), %s", name, desc);
>> +
>> + return;
>> + }
>> +}
>> +
>> +static void btp_gap_pair(uint8_t index, const void *param, uint16_t len=
gth,
>> + void *user=
_data)
>> +{
>> + struct btp_adapter *adapter =3D find_adapter_by_index(index);
>> + const struct btp_gap_pair_cp *cp =3D param;
>> + uint8_t status =3D BTP_ERROR_FAIL;
>> + struct btp_device *device;
>> + bool prop;
>> +
>> + if (!adapter) {
>> + status =3D BTP_ERROR_INVALID_INDEX;
>> + goto failed;
>> + }
>> +
>> + /* Adapter needs to be powered to be able to pair */
>> + if (!l_dbus_proxy_get_property(adapter->proxy, "Powered", "b", &pr=
op) ||
>> + !p=
rop)
>> + goto failed;
>> +
>> + device =3D find_device_by_address(adapter, &cp->address,
>> + cp->address_type);
>> +
>> + if (!device)
>> + goto failed;
>> +
>> + btp_send(btp, BTP_GAP_SERVICE, BTP_OP_GAP_PAIR, adapter->index, 0,
>
> Please comment here that on BTP this command is suppose to initiate pairi=
ng
> only and successful pairing result is reported via event later on.
Ok
>
>> + NU=
LL);
>> +
>> + l_dbus_proxy_method_call(device->proxy, "Pair", NULL, pair_reply,
>> + L_UINT_TO_PTR(adapter->index), NUL=
L);
>> +
>> + return;
>> +
>> +failed:
>> + btp_send_error(btp, BTP_GAP_SERVICE, index, status);
>> +}
>> +
>> +static void unpair_reply(struct l_dbus_proxy *proxy,
>> + struct l_dbus_message *result, void *user_=
data)
>> +{
>> + uint8_t adapter_index =3D L_PTR_TO_UINT(user_data);
>> + struct btp_adapter *adapter =3D find_adapter_by_index(adapter_inde=
x);
>> +
>> + if (!adapter) {
>> + btp_send_error(btp, BTP_GAP_SERVICE, BTP_INDEX_NON_CONTROL=
LER,
>> + BTP_ERROR_=
FAIL);
>> + return;
>> + }
>> +
>> + if (l_dbus_message_is_error(result)) {
>> + const char *name, *desc;
>> +
>> + l_dbus_message_get_error(result, &name, &desc);
>> + l_error("Failed to unpair (%s), %s", name, desc);
>> +
>> + btp_send_error(btp, BTP_GAP_SERVICE, adapter_index,
>> + BTP_ERROR_=
FAIL);
>> + return;
>> + }
>> +
>> + btp_send(btp, BTP_GAP_SERVICE, BTP_OP_GAP_UNPAIR, adapter_index, 0=
, NULL);
>> +}
>> +
>> +static void btp_gap_unpair(uint8_t index, const void *param, uint16_t
>> length, + vo=
id *user_data)
>> +{
>> + struct btp_adapter *adapter =3D find_adapter_by_index(index);
>> + const struct btp_gap_pair_cp *cp =3D param;
>> + uint8_t status =3D BTP_ERROR_FAIL;
>> + struct btp_device *device;
>> + bool prop;
>> +
>> + if (!adapter) {
>> + status =3D BTP_ERROR_INVALID_INDEX;
>> + goto failed;
>> + }
>> +
>> + /* Adapter needs to be powered to be able to unpair */
>> + if (!l_dbus_proxy_get_property(adapter->proxy, "Powered", "b", &pr=
op) ||
>> + !p=
rop)
>> + goto failed;
>> +
>> + device =3D find_device_by_address(adapter, &cp->address,
>> + cp->address_type);
>> +
>> + if (!device)
>> + goto failed;
>> +
>> + l_dbus_proxy_method_call(device->proxy, "Unpair", NULL, unpair_rep=
ly,
>> + L_UINT_TO_PTR(adapter->index), NUL=
L);
>
> There is no "Unpair" command in Device1 interface :) Use RemoveDevice fr=
om
> Adapter1.
Right, that was copy-paste mistake
>
>> + return;
>> +
>> +failed:
>> + btp_send_error(btp, BTP_GAP_SERVICE, index, status);
>> +}
>> +
>> static void btp_gap_device_found_ev(struct l_dbus_proxy *proxy)
>> {
>> struct btp_device_found_ev ev;
>> @@ -1999,6 +2117,12 @@ static void register_gap_service(void)
>>
>> btp_register(btp, BTP_GAP_SERVICE, BTP_OP_GAP_SET_IO_CAPA,
>> btp_gap_set_io_capabilities, NULL, NULL);
>> +
>> + btp_register(btp, BTP_GAP_SERVICE, BTP_OP_GAP_PAIR, btp_gap_pair, =
NULL,
>> + NU=
LL);
>> +
>> + btp_register(btp, BTP_GAP_SERVICE, BTP_OP_GAP_UNPAIR, btp_gap_unpa=
ir,
>> + NULL, NULL=
);
>> }
>>
>> static void btp_core_read_commands(uint8_t index, const void *param,
>
>
> --
> pozdrawiam
> Szymon Janc
>
>
pozdrawiam,
Grzegorz Ko=C5=82odziejczyk
Hi Szymon,
2018-01-23 14:48 GMT+01:00 Szymon Janc <[email protected]>:
> Hi Grzegorz,
>
> On Friday, 19 January 2018 17:41:28 CET Grzegorz Kolodziejczyk wrote:
>> This patch adds support for set io capabilities command.
>> ---
>> tools/btpclient.c | 361
>> ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 3=
61
>> insertions(+)
>>
>> diff --git a/tools/btpclient.c b/tools/btpclient.c
>> index f2c79b3a3..708092937 100644
>> --- a/tools/btpclient.c
>> +++ b/tools/btpclient.c
>> @@ -36,7 +36,9 @@
>> #include "src/shared/btp.h"
>>
>> #define AD_PATH "/org/bluez/advertising"
>> +#define AG_PATH "/org/bluez/agent"
>> #define AD_IFACE "org.bluez.LEAdvertisement1"
>> +#define AG_IFACE "org.bluez.Agent1"
>>
>> /* List of assigned numbers for advetising data and scan response */
>> #define AD_TYPE_FLAGS 0x01
>> @@ -97,6 +99,12 @@ static struct ad {
>> bool appearance;
>> } ad;
>>
>> +static struct btp_agent {
>> + bool registered;
>> + struct l_dbus_proxy *proxy;
>> + struct l_dbus_message *pending_req;
>> +} ag;
>> +
>> static char *dupuuid2str(const uint8_t *uuid, uint8_t len)
>> {
>> switch (len) {
>> @@ -198,6 +206,31 @@ static struct btp_device *find_device_by_address(st=
ruct
>> btp_adapter *adapter, return NULL;
>> }
>>
>> +static bool match_device_paths(const void *device, const void *path)
>> +{
>> + const struct btp_device *dev =3D device;
>> +
>> + return !strcmp(l_dbus_proxy_get_path(dev->proxy), path);
>> +}
>> +
>> +static struct btp_device *find_device_by_path(const char *path)
>> +{
>> + const struct l_queue_entry *entry;
>> + struct btp_device *device;
>> +
>> + for (entry =3D l_queue_get_entries(adapters); entry;
>> + entry =3D entry->n=
ext) {
>> + struct btp_adapter *adapter =3D entry->data;
>> +
>> + device =3D l_queue_find(adapter->devices, match_device_pat=
hs,
>> + pa=
th);
>> + if (device)
>> + return device;
>> + }
>> +
>> + return NULL;
>> +}
>> +
>> static bool match_adapter_dev_proxy(const void *device, const void *pro=
xy)
>> {
>> const struct btp_device *d =3D device;
>> @@ -269,6 +302,7 @@ static void btp_gap_read_commands(uint8_t index, con=
st
>> void *param, commands |=3D (1 << BTP_OP_GAP_STOP_DISCOVERY);
>> commands |=3D (1 << BTP_OP_GAP_CONNECT);
>> commands |=3D (1 << BTP_OP_GAP_DISCONNECT);
>> + commands |=3D (1 << BTP_OP_GAP_SET_IO_CAPA);
>>
>> commands =3D L_CPU_TO_LE16(commands);
>>
>> @@ -418,6 +452,43 @@ static void unreg_advertising_reply(struct l_dbus_p=
roxy
>> *proxy, l_info("Unable to unregister ad interface");
>> }
>>
>> +static void unreg_agent_setup(struct l_dbus_message *message, void
>> *user_data) +{
>> + struct l_dbus_message_builder *builder;
>> +
>> + builder =3D l_dbus_message_builder_new(message);
>> +
>> + l_dbus_message_builder_append_basic(builder, 'o', AG_PATH);
>> +
>> + l_dbus_message_builder_finalize(builder);
>> + l_dbus_message_builder_destroy(builder);
>> +}
>> +
>> +static void unreg_agent_reply(struct l_dbus_proxy *proxy,
>> + struct l_dbus_message *res=
ult,
>> + void *user_data)
>> +{
>> + if (l_dbus_message_is_error(result)) {
>> + const char *name;
>> +
>> + l_dbus_message_get_error(result, &name, NULL);
>> +
>> + l_error("Failed to unregister agent %s (%s)",
>> + l_dbus_proxy_get_path(proxy), name=
);
>> + return;
>> + }
>> +
>> + if (!l_dbus_object_remove_interface(dbus, AG_PATH,
>> + L_DBUS_INTERFACE_PROPERTIE=
S))
>> + l_info("Unable to remove propety instance");
>> + if (!l_dbus_object_remove_interface(dbus, AG_PATH, AG_IFACE))
>> + l_info("Unable to remove agent instance");
>> + if (!l_dbus_unregister_interface(dbus, AG_IFACE))
>> + l_info("Unable to unregister agent interface");
>> +
>> + ag.registered =3D false;
>> +}
>> +
>> static void btp_gap_reset(uint8_t index, const void *param, uint16_t
>> length, void *user_data)
>> {
>> @@ -458,6 +529,15 @@ static void btp_gap_reset(uint8_t index, const void
>> *param, uint16_t length, goto failed;
>> }
>>
>> + if (ag.registered)
>> + if (!l_dbus_proxy_method_call(ag.proxy, "UnregisterAgent",
>> + unreg_agent_setup,
>> + unreg_agent_reply,
>> + NULL, NULL)) {
>> + status =3D BTP_ERROR_FAIL;
>> + goto failed;
>> + }
>> +
>> /* TODO for we assume all went well */
>> btp_send(btp, BTP_GAP_SERVICE, BTP_OP_GAP_RESET, index, 0, NULL);
>> return;
>> @@ -1513,6 +1593,278 @@ failed:
>> btp_send_error(btp, BTP_GAP_SERVICE, index, status);
>> }
>>
>> +static struct l_dbus_message *ag_release_call(struct l_dbus *dbus,
>> + struct l_dbus_message *mes=
sage,
>> + void *user_data)
>> +{
>> + struct l_dbus_message *reply;
>> +
>> + reply =3D l_dbus_message_new_method_return(message);
>> + l_dbus_message_set_arguments(reply, "");
>> +
>> + return reply;
>> +}
>> +
>> +static struct l_dbus_message *ag_request_passkey_call(struct l_dbus *db=
us,
>> + struct l_dbus_message *mes=
sage,
>> + void *user_data)
>> +{
>> + struct btp_gap_passkey_req_ev ev;
>> + struct btp_device *device;
>> + struct btp_adapter *adapter;
>> + const char *path, *str_addr, *str_addr_type;
>> +
>> + l_dbus_message_get_arguments(message, "o", &path);
>> +
>> + device =3D find_device_by_path(path);
>> +
>> + if (!l_dbus_proxy_get_property(device->proxy, "Address", "s", &str=
_addr)
>> + || !l_dbus_proxy_get_property(device->proxy, "AddressType"=
, "s",
>> + &str_addr_type)) {
>> + l_info("Cannot get device properties");
>> +
>> + return NULL;
>> + }
>> +
>> + ev.address_type =3D strcmp(str_addr_type, "public") ?
>> + BTP_GAP_ADDR_RANDO=
M :
>> + BTP_GAP_ADDR_PUBLI=
C;
>> + if (!str2ba(str_addr, &ev.address))
>> + return NULL;
>> +
>> + adapter =3D find_adapter_by_device(device);
>> +
>> + ag.pending_req =3D l_dbus_message_ref(message);
>> +
>> + btp_send(btp, BTP_GAP_SERVICE, BTP_EV_GAP_PASSKEY_REQUEST,
>> + adapter->index, sizeof(ev), &ev);
>> +
>> + return NULL;
>> +}
>> +
>> +static struct l_dbus_message *ag_display_passkey_call(struct l_dbus *db=
us,
>> + struct l_dbus_message *mes=
sage,
>> + void *user_data)
>> +{
>> + struct l_dbus_message *reply;
>> +
>> + reply =3D l_dbus_message_new_method_return(message);
>> + l_dbus_message_set_arguments(reply, "");
>> +
>> + return reply;
>> +}
>> +
>> +static struct l_dbus_message *ag_request_confirmation_call(struct l_dbu=
s
>> *dbus, + struct l_dbus_mess=
age *message,
>> + void *user_data)
>> +{
>> + struct l_dbus_message *reply;
>> +
>> + reply =3D l_dbus_message_new_method_return(message);
>> + l_dbus_message_set_arguments(reply, "");
>> +
>> + return reply;
>> +}
>> +
>> +static struct l_dbus_message *ag_authorize_service_call(struct l_dbus
>> *dbus, + struct l_dbus_mess=
age *message,
>> + void *user_data)
>> +{
>> + struct l_dbus_message *reply;
>> +
>> + reply =3D l_dbus_message_new_method_return(message);
>> + l_dbus_message_set_arguments(reply, "");
>> +
>> + return reply;
>> +}
>> +
>> +static struct l_dbus_message *ag_cancel_call(struct l_dbus *dbus,
>> + struct l_dbus_message *mes=
sage,
>> + void *user_data)
>> +{
>> + struct l_dbus_message *reply;
>> +
>> + reply =3D l_dbus_message_new_method_return(message);
>> + l_dbus_message_set_arguments(reply, "");
>> +
>> + return reply;
>> +}
>> +
>> +static void setup_ag_interface(struct l_dbus_interface *iface)
>> +{
>> + l_dbus_interface_method(iface, "Release", 0, ag_release_call, "", =
"");
>> + l_dbus_interface_method(iface, "RequestPasskey", 0,
>> + ag_request_passkey_call, "u", "o",
>> + "passkey", "device");
>> + l_dbus_interface_method(iface, "DisplayPasskey", 0,
>> + ag_display_passkey_call, "", "ouq"=
,
>> + "device", "passkey", "entered");
>> + l_dbus_interface_method(iface, "RequestConfirmation", 0,
>> + ag_request_confirmation_call, "", =
"ou",
>> + "device", "passkey");
>> + l_dbus_interface_method(iface, "RequestAuthorization", 0,
>> + ag_request_confirmation_call, "", =
"o",
>> + "device");
>> + l_dbus_interface_method(iface, "AuthorizeService", 0,
>> + ag_authorize_service_call, "", "os=
",
>> + "device", "uuid");
>> + l_dbus_interface_method(iface, "Cancel", 0, ag_cancel_call, "", ""=
);
>> +}
>> +
>> +struct set_io_capabilities_data {
>> + uint8_t capa;
>> + struct btp_adapter *adapter;
>> +};
>> +
>> +static void set_io_capabilities_setup(struct l_dbus_message *message,
>> + void *user=
_data)
>> +{
>> + struct set_io_capabilities_data *sicd =3D user_data;
>> + struct l_dbus_message_builder *builder;
>> + char *capa_str;
>> +
>> + builder =3D l_dbus_message_builder_new(message);
>> +
>> + l_dbus_message_builder_append_basic(builder, 'o', AG_PATH);
>> +
>> + switch (sicd->capa) {
>> + case BTP_GAP_IOCAPA_DISPLAY_ONLY:
>> + capa_str =3D "DisplayOnly";
>> + break;
>> + case BTP_GAP_IOCAPA_DISPLAY_YESNO:
>> + capa_str =3D "DisplayYesNo";
>> + break;
>> + case BTP_GAP_IOCAPA_KEYBOARD_ONLY:
>> + capa_str =3D "KeyboardOnly";
>> + break;
>> + case BTP_GAP_IOCAPA_NO_INPUT_NO_OUTPUT:
>> + capa_str =3D "NoInputNoOutput";
>> + break;
>> + case BTP_GAP_IOCAPA_KEYBOARD_DISPLAY:
>> + capa_str =3D "KeyboardDisplay";
>> + break;
>> + default:
>> + l_error("Wrong iocapa given!");
>> + l_dbus_message_builder_finalize(builder);
>> + l_dbus_message_builder_destroy(builder);
>> +
>> + return;
>> + }
>
> setup callback should only build message, not verify parameters as it ret=
urns
> void. Please check those in btp_gap_set_io_capabilities().
Ok.
>
>> +
>> + l_dbus_message_builder_append_basic(builder, 's', capa_str);
>> +
>> + l_dbus_message_builder_finalize(builder);
>> + l_dbus_message_builder_destroy(builder);
>> +}
>> +
>> +static void set_io_capabilities_reply(struct l_dbus_proxy *proxy,
>> + struct l_dbus_message *res=
ult,
>> + void *user_data)
>> +{
>> + struct set_io_capabilities_data *sicd =3D user_data;
>> +
>> + if (!sicd->adapter) {
>> + btp_send_error(btp, BTP_GAP_SERVICE, BTP_INDEX_NON_CONTROL=
LER,
>> + BTP_ERROR_=
FAIL);
>> + return;
>> + }
>> +
>> + if (l_dbus_message_is_error(result)) {
>> + const char *name, *desc;
>> +
>> + if (!l_dbus_object_remove_interface(dbus, AG_PATH, AG_IFAC=
E))
>> + l_info("Unable to remove agent instance");
>> + if (!l_dbus_unregister_interface(dbus, AG_IFACE))
>> + l_info("Unable to unregister agent interface");
>> +
>> + l_dbus_message_get_error(result, &name, &desc);
>> + l_error("Failed to set io capabilities (%s), %s", name, de=
sc);
>> +
>> + btp_send_error(btp, BTP_GAP_SERVICE, sicd->adapter->index,
>> + BTP_ERROR_=
FAIL);
>> + return;
>> + }
>> +
>> + ag.registered =3D true;
>> +
>> + btp_send(btp, BTP_GAP_SERVICE, BTP_OP_GAP_SET_IO_CAPA,
>> + sicd->adapter->index, 0, N=
ULL);
>> +}
>> +
>> +static void set_io_capabilities_destroy(void *user_data)
>> +{
>> + l_free(user_data);
>> +}
>> +
>> +static void btp_gap_set_io_capabilities(uint8_t index, const void *para=
m,
>> + uint16_t length, void *user_data)
>> +{
>> + struct btp_adapter *adapter =3D find_adapter_by_index(index);
>> + const struct btp_gap_set_io_capa_cp *cp =3D param;
>> + uint8_t status =3D BTP_ERROR_FAIL;
>> + struct set_io_capabilities_data *data;
>> + bool prop;
>> +
>> + if (!adapter) {
>> + status =3D BTP_ERROR_INVALID_INDEX;
>> + goto failed;
>> + }
>> +
>> + /* Adapter needs to be powered to be able to set io cap */
>> + if (!l_dbus_proxy_get_property(adapter->proxy, "Powered", "b", &pr=
op) ||
>> + !prop || ag.regist=
ered)
>> + goto failed;
>> +
>> + if (!l_dbus_register_interface(dbus, AG_IFACE, setup_ag_interface,=
NULL,
>> + false)) {
>> + l_info("Unable to register agent interface");
>> + goto failed;
>> + }
>> +
>> + if (!l_dbus_object_add_interface(dbus, AG_PATH, AG_IFACE, NULL)) {
>> + l_info("Unable to instantiate agent interface");
>> +
>> + if (!l_dbus_unregister_interface(dbus, AD_IFACE))
>> + l_info("Unable to unregister agent interface");
>> +
>> + goto failed;
>> + }
>> +
>> + if (!l_dbus_object_add_interface(dbus, AG_PATH,
>> + L_DBUS_INTERFACE_PROPERTIE=
S,
>> + NULL)) {
>> + l_info("Unable to instantiate the ag properties interface"=
);
>> +
>> + if (!l_dbus_object_remove_interface(dbus, AG_PATH, AG_IFAC=
E))
>> + l_info("Unable to remove agent instance");
>> + if (!l_dbus_unregister_interface(dbus, AG_IFACE))
>> + l_info("Unable to unregister agent interface");
>> +
>> + goto failed;
>> + }
>> +
>> + data =3D l_new(struct set_io_capabilities_data, 1);
>> + data->adapter =3D adapter;
>> + data->capa =3D cp->capa;
>> +
>> + if (!l_dbus_proxy_method_call(ag.proxy, "RegisterAgent",
>> + set_io_capabilities_setup,
>> + set_io_capabilities_reply,=
data,
>> + set_io_capabilities_destro=
y)) {
>> + if (!l_dbus_object_remove_interface(dbus, AG_PATH, AG_IFAC=
E))
>> + l_info("Unable to remove agent instance");
>> + if (!l_dbus_unregister_interface(dbus, AG_IFACE))
>> + l_info("Unable to unregister agent interface");
>> +
>> + goto failed;
>> + }
>> +
>> + return;
>> +
>> +failed:
>> + btp_send_error(btp, BTP_GAP_SERVICE, index, status);
>> +}
>> +
>> static void btp_gap_device_found_ev(struct l_dbus_proxy *proxy)
>> {
>> struct btp_device_found_ev ev;
>> @@ -1634,6 +1986,9 @@ static void register_gap_service(void)
>>
>> btp_register(btp, BTP_GAP_SERVICE, BTP_OP_GAP_DISCONNECT,
>> btp_gap_disconnect, NULL, =
NULL);
>> +
>> + btp_register(btp, BTP_GAP_SERVICE, BTP_OP_GAP_SET_IO_CAPA,
>> + btp_gap_set_io_capabilities, NULL, NULL);
>> }
>>
>> static void btp_core_read_commands(uint8_t index, const void *param,
>> @@ -1889,6 +2244,12 @@ static void proxy_added(struct l_dbus_proxy *prox=
y,
>> void *user_data)
>>
>> return;
>> }
>> +
>> + if (!strcmp(interface, "org.bluez.AgentManager1")) {
>> + ag.proxy =3D proxy;
>> +
>> + return;
>> + }
>> }
>>
>> static bool device_match_by_proxy(const void *a, const void *b)
>
> More general comment. We should register default agent on startup so that
> system agent is never used when btpclient is running. When this command i=
s
> called and iocapa is differrent than currently used we should unregister
> current agent and register new default.
Agree
>
>
> --
> pozdrawiam
> Szymon Janc
>
>
pozdrawiam,
Grzegorz Ko=C5=82odziejczyk
Hi Grzegorz,
On Friday, 19 January 2018 17:41:33 CET Grzegorz Kolodziejczyk wrote:
> This patch adds passkey confirm command handler and passkey confirm
> event.
> ---
> tools/btpclient.c | 94
> +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 94
> insertions(+)
>
> diff --git a/tools/btpclient.c b/tools/btpclient.c
> index 55e5170a7..780c2a8db 100644
> --- a/tools/btpclient.c
> +++ b/tools/btpclient.c
> @@ -1703,11 +1703,43 @@ static struct l_dbus_message
> *ag_request_confirmation_call(struct l_dbus *dbus, struct l_dbus_message
> *message,
> void *user_data)
> {
> + struct btp_gap_passkey_confirm_ev ev;
> + struct btp_device *device;
> + struct btp_adapter *adapter;
> struct l_dbus_message *reply;
> + const char *path, *str_addr, *str_addr_type;
> + uint32_t passkey;
>
> reply = l_dbus_message_new_method_return(message);
> l_dbus_message_set_arguments(reply, "");
>
> + l_dbus_message_get_arguments(message, "ou", &path, &passkey);
> +
> + device = find_device_by_path(path);
> +
> + if (!l_dbus_proxy_get_property(device->proxy, "Address", "s", &str_addr)
> + || !l_dbus_proxy_get_property(device->proxy, "AddressType", "s",
> + &str_addr_type)) {
> + l_info("Cannot get device properties");
> +
> + return reply;
> + }
> +
> + ev.passkey = L_CPU_TO_LE32(passkey);
> + ev.address_type = strcmp(str_addr_type, "public") ?
> + BTP_GAP_ADDR_RANDOM :
> + BTP_GAP_ADDR_PUBLIC;
> + if (str2ba(str_addr, &ev.address) < 0) {
> + l_info("Incorrect device address");
> +
> + return reply;
> + }
> +
> + adapter = find_adapter_by_device(device);
> +
> + btp_send(btp, BTP_GAP_SERVICE, BTP_EV_GAP_PASSKEY_CONFIRM,
> + adapter->index, sizeof(ev), &ev);
> +
> return reply;
So ag.pending request should be stored here. And reply here should be returned
only in case of error.
> }
>
> @@ -2082,6 +2114,65 @@ failed:
> btp_send_error(btp, BTP_GAP_SERVICE, index, status);
> }
>
> +static void passkey_confirm_rsp_reply(struct l_dbus_message *result,
> + void *user_data)
> +{
> + struct btp_adapter *adapter = user_data;
> +
> + if (l_dbus_message_is_error(result)) {
> + const char *name, *desc;
> +
> + l_dbus_message_get_error(result, &name, &desc);
> + l_error("Failed to confirm passkey (%s), %s", name, desc);
> +
> + btp_send_error(btp, BTP_GAP_SERVICE, adapter->index,
> + BTP_ERROR_FAIL);
> + return;
> + }
> +
> + l_dbus_message_unref(ag.pending_req);
> +
> + btp_send(btp, BTP_GAP_SERVICE, BTP_OP_GAP_PASSKEY_CONFIRM_RSP,
> + adapter->index, 0, NULL);
> +}
> +
> +static void btp_gap_confirm_entry_rsp(uint8_t index, const void *param,
> + uint16_t length, void *user_data)
> +{
> + const struct btp_gap_passkey_confirm_rsp_cp *cp = param;
> + struct btp_adapter *adapter = find_adapter_by_index(index);
> + struct l_dbus_message *reply;
> + uint8_t status = BTP_ERROR_FAIL;
> + bool prop;
> +
> + if (!adapter) {
> + status = BTP_ERROR_INVALID_INDEX;
> + goto failed;
> + }
> +
> + /* Adapter needs to be powered to be able to confirm passkey */
> + if (!l_dbus_proxy_get_property(adapter->proxy, "Powered", "b", &prop) ||
> + !prop || !ag.pending_req)
> + goto failed;
> +
> + if (cp->match) {
> + reply = l_dbus_message_new_method_return(ag.pending_req);
> + l_dbus_message_set_arguments(reply, "");
> + } else {
> + reply = l_dbus_message_new_error(ag.pending_req,
> + "org.bluez.Error.Rejected",
> + "Passkey missmatch");
> + }
> +
> + l_dbus_send_with_reply(dbus, ag.pending_req, passkey_confirm_rsp_reply,
> + adapter, NULL);
> +
> + return;
> +
> +failed:
> + btp_send_error(btp, BTP_GAP_SERVICE, index, status);
> +}
> +
> static void btp_gap_device_found_ev(struct l_dbus_proxy *proxy)
> {
> struct btp_device_found_ev ev;
> @@ -2215,6 +2306,9 @@ static void register_gap_service(void)
>
> btp_register(btp, BTP_GAP_SERVICE, BTP_OP_GAP_PASSKEY_ENTRY_RSP,
> btp_gap_passkey_entry_rsp, NULL, NULL);
> +
> + btp_register(btp, BTP_GAP_SERVICE, BTP_OP_GAP_PASSKEY_CONFIRM_RSP,
> + btp_gap_confirm_entry_rsp, NULL, NULL);
> }
>
> static void btp_core_read_commands(uint8_t index, const void *param,
--
pozdrawiam
Szymon Janc
Hi Grzegorz,
On Friday, 19 January 2018 17:41:31 CET Grzegorz Kolodziejczyk wrote:
> This patch adds pair and unpair commands for btp client.
> ---
> tools/btpclient.c | 124
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 124
> insertions(+)
>
> diff --git a/tools/btpclient.c b/tools/btpclient.c
> index 53c0d4c05..9d44fba41 100644
> --- a/tools/btpclient.c
> +++ b/tools/btpclient.c
> @@ -304,6 +304,8 @@ static void btp_gap_read_commands(uint8_t index, const
> void *param, commands |= (1 << BTP_OP_GAP_CONNECT);
> commands |= (1 << BTP_OP_GAP_DISCONNECT);
> commands |= (1 << BTP_OP_GAP_SET_IO_CAPA);
> + commands |= (1 << BTP_OP_GAP_PAIR);
> + commands |= (1 << BTP_OP_GAP_UNPAIR);
>
> commands = L_CPU_TO_LE16(commands);
>
> @@ -1875,6 +1877,122 @@ failed:
> btp_send_error(btp, BTP_GAP_SERVICE, index, status);
> }
>
> +static void pair_reply(struct l_dbus_proxy *proxy,
> + struct l_dbus_message *result, void *user_data)
> +{
> + uint8_t adapter_index = L_PTR_TO_UINT(user_data);
> + struct btp_adapter *adapter = find_adapter_by_index(adapter_index);
> +
> + if (!adapter)
> + return;
> +
> + if (l_dbus_message_is_error(result)) {
> + const char *name, *desc;
> +
> + l_dbus_message_get_error(result, &name, &desc);
> + l_error("Failed to pair (%s), %s", name, desc);
> +
> + return;
> + }
> +}
> +
> +static void btp_gap_pair(uint8_t index, const void *param, uint16_t length,
> + void *user_data)
> +{
> + struct btp_adapter *adapter = find_adapter_by_index(index);
> + const struct btp_gap_pair_cp *cp = param;
> + uint8_t status = BTP_ERROR_FAIL;
> + struct btp_device *device;
> + bool prop;
> +
> + if (!adapter) {
> + status = BTP_ERROR_INVALID_INDEX;
> + goto failed;
> + }
> +
> + /* Adapter needs to be powered to be able to pair */
> + if (!l_dbus_proxy_get_property(adapter->proxy, "Powered", "b", &prop) ||
> + !prop)
> + goto failed;
> +
> + device = find_device_by_address(adapter, &cp->address,
> + cp->address_type);
> +
> + if (!device)
> + goto failed;
> +
> + btp_send(btp, BTP_GAP_SERVICE, BTP_OP_GAP_PAIR, adapter->index, 0,
Please comment here that on BTP this command is suppose to initiate pairing
only and successful pairing result is reported via event later on.
> + NULL);
> +
> + l_dbus_proxy_method_call(device->proxy, "Pair", NULL, pair_reply,
> + L_UINT_TO_PTR(adapter->index), NULL);
> +
> + return;
> +
> +failed:
> + btp_send_error(btp, BTP_GAP_SERVICE, index, status);
> +}
> +
> +static void unpair_reply(struct l_dbus_proxy *proxy,
> + struct l_dbus_message *result, void *user_data)
> +{
> + uint8_t adapter_index = L_PTR_TO_UINT(user_data);
> + struct btp_adapter *adapter = find_adapter_by_index(adapter_index);
> +
> + if (!adapter) {
> + btp_send_error(btp, BTP_GAP_SERVICE, BTP_INDEX_NON_CONTROLLER,
> + BTP_ERROR_FAIL);
> + return;
> + }
> +
> + if (l_dbus_message_is_error(result)) {
> + const char *name, *desc;
> +
> + l_dbus_message_get_error(result, &name, &desc);
> + l_error("Failed to unpair (%s), %s", name, desc);
> +
> + btp_send_error(btp, BTP_GAP_SERVICE, adapter_index,
> + BTP_ERROR_FAIL);
> + return;
> + }
> +
> + btp_send(btp, BTP_GAP_SERVICE, BTP_OP_GAP_UNPAIR, adapter_index, 0, NULL);
> +}
> +
> +static void btp_gap_unpair(uint8_t index, const void *param, uint16_t
> length, + void *user_data)
> +{
> + struct btp_adapter *adapter = find_adapter_by_index(index);
> + const struct btp_gap_pair_cp *cp = param;
> + uint8_t status = BTP_ERROR_FAIL;
> + struct btp_device *device;
> + bool prop;
> +
> + if (!adapter) {
> + status = BTP_ERROR_INVALID_INDEX;
> + goto failed;
> + }
> +
> + /* Adapter needs to be powered to be able to unpair */
> + if (!l_dbus_proxy_get_property(adapter->proxy, "Powered", "b", &prop) ||
> + !prop)
> + goto failed;
> +
> + device = find_device_by_address(adapter, &cp->address,
> + cp->address_type);
> +
> + if (!device)
> + goto failed;
> +
> + l_dbus_proxy_method_call(device->proxy, "Unpair", NULL, unpair_reply,
> + L_UINT_TO_PTR(adapter->index), NULL);
There is no "Unpair" command in Device1 interface :) Use RemoveDevice from
Adapter1.
> + return;
> +
> +failed:
> + btp_send_error(btp, BTP_GAP_SERVICE, index, status);
> +}
> +
> static void btp_gap_device_found_ev(struct l_dbus_proxy *proxy)
> {
> struct btp_device_found_ev ev;
> @@ -1999,6 +2117,12 @@ static void register_gap_service(void)
>
> btp_register(btp, BTP_GAP_SERVICE, BTP_OP_GAP_SET_IO_CAPA,
> btp_gap_set_io_capabilities, NULL, NULL);
> +
> + btp_register(btp, BTP_GAP_SERVICE, BTP_OP_GAP_PAIR, btp_gap_pair, NULL,
> + NULL);
> +
> + btp_register(btp, BTP_GAP_SERVICE, BTP_OP_GAP_UNPAIR, btp_gap_unpair,
> + NULL, NULL);
> }
>
> static void btp_core_read_commands(uint8_t index, const void *param,
--
pozdrawiam
Szymon Janc
Hi Grzegorz,
On Friday, 19 January 2018 17:41:29 CET Grzegorz Kolodziejczyk wrote:
> Reset command will restore default settings of adapter.
> ---
> tools/btpclient.c | 5 +++++
> 1 file changed, 5 insertions(+)
>
> diff --git a/tools/btpclient.c b/tools/btpclient.c
> index 708092937..c5f88e673 100644
> --- a/tools/btpclient.c
> +++ b/tools/btpclient.c
> @@ -56,6 +56,7 @@ struct btp_adapter {
> uint8_t index;
> uint32_t supported_settings;
> uint32_t current_settings;
> + uint32_t default_settings;
> struct l_queue *devices;
> };
>
> @@ -538,6 +539,8 @@ static void btp_gap_reset(uint8_t index, const void
> *param, uint16_t length, goto failed;
> }
>
> + adapter->current_settings = adapter->default_settings;
> +
> /* TODO for we assume all went well */
> btp_send(btp, BTP_GAP_SERVICE, BTP_OP_GAP_RESET, index, 0, NULL);
> return;
> @@ -2207,6 +2210,8 @@ static void proxy_added(struct l_dbus_proxy *proxy,
> void *user_data) extract_settings(proxy, &adapter->current_settings,
> &adapter->supported_settings);
>
> + adapter->default_settings = adapter->current_settings;
> +
> l_queue_push_tail(adapters, adapter);
> return;
> }
Patch applied, thanks.
--
pozdrawiam
Szymon Janc
Hi Grzegorz,
On Friday, 19 January 2018 17:41:28 CET Grzegorz Kolodziejczyk wrote:
> This patch adds support for set io capabilities command.
> ---
> tools/btpclient.c | 361
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 361
> insertions(+)
>
> diff --git a/tools/btpclient.c b/tools/btpclient.c
> index f2c79b3a3..708092937 100644
> --- a/tools/btpclient.c
> +++ b/tools/btpclient.c
> @@ -36,7 +36,9 @@
> #include "src/shared/btp.h"
>
> #define AD_PATH "/org/bluez/advertising"
> +#define AG_PATH "/org/bluez/agent"
> #define AD_IFACE "org.bluez.LEAdvertisement1"
> +#define AG_IFACE "org.bluez.Agent1"
>
> /* List of assigned numbers for advetising data and scan response */
> #define AD_TYPE_FLAGS 0x01
> @@ -97,6 +99,12 @@ static struct ad {
> bool appearance;
> } ad;
>
> +static struct btp_agent {
> + bool registered;
> + struct l_dbus_proxy *proxy;
> + struct l_dbus_message *pending_req;
> +} ag;
> +
> static char *dupuuid2str(const uint8_t *uuid, uint8_t len)
> {
> switch (len) {
> @@ -198,6 +206,31 @@ static struct btp_device *find_device_by_address(struct
> btp_adapter *adapter, return NULL;
> }
>
> +static bool match_device_paths(const void *device, const void *path)
> +{
> + const struct btp_device *dev = device;
> +
> + return !strcmp(l_dbus_proxy_get_path(dev->proxy), path);
> +}
> +
> +static struct btp_device *find_device_by_path(const char *path)
> +{
> + const struct l_queue_entry *entry;
> + struct btp_device *device;
> +
> + for (entry = l_queue_get_entries(adapters); entry;
> + entry = entry->next) {
> + struct btp_adapter *adapter = entry->data;
> +
> + device = l_queue_find(adapter->devices, match_device_paths,
> + path);
> + if (device)
> + return device;
> + }
> +
> + return NULL;
> +}
> +
> static bool match_adapter_dev_proxy(const void *device, const void *proxy)
> {
> const struct btp_device *d = device;
> @@ -269,6 +302,7 @@ static void btp_gap_read_commands(uint8_t index, const
> void *param, commands |= (1 << BTP_OP_GAP_STOP_DISCOVERY);
> commands |= (1 << BTP_OP_GAP_CONNECT);
> commands |= (1 << BTP_OP_GAP_DISCONNECT);
> + commands |= (1 << BTP_OP_GAP_SET_IO_CAPA);
>
> commands = L_CPU_TO_LE16(commands);
>
> @@ -418,6 +452,43 @@ static void unreg_advertising_reply(struct l_dbus_proxy
> *proxy, l_info("Unable to unregister ad interface");
> }
>
> +static void unreg_agent_setup(struct l_dbus_message *message, void
> *user_data) +{
> + struct l_dbus_message_builder *builder;
> +
> + builder = l_dbus_message_builder_new(message);
> +
> + l_dbus_message_builder_append_basic(builder, 'o', AG_PATH);
> +
> + l_dbus_message_builder_finalize(builder);
> + l_dbus_message_builder_destroy(builder);
> +}
> +
> +static void unreg_agent_reply(struct l_dbus_proxy *proxy,
> + struct l_dbus_message *result,
> + void *user_data)
> +{
> + if (l_dbus_message_is_error(result)) {
> + const char *name;
> +
> + l_dbus_message_get_error(result, &name, NULL);
> +
> + l_error("Failed to unregister agent %s (%s)",
> + l_dbus_proxy_get_path(proxy), name);
> + return;
> + }
> +
> + if (!l_dbus_object_remove_interface(dbus, AG_PATH,
> + L_DBUS_INTERFACE_PROPERTIES))
> + l_info("Unable to remove propety instance");
> + if (!l_dbus_object_remove_interface(dbus, AG_PATH, AG_IFACE))
> + l_info("Unable to remove agent instance");
> + if (!l_dbus_unregister_interface(dbus, AG_IFACE))
> + l_info("Unable to unregister agent interface");
> +
> + ag.registered = false;
> +}
> +
> static void btp_gap_reset(uint8_t index, const void *param, uint16_t
> length, void *user_data)
> {
> @@ -458,6 +529,15 @@ static void btp_gap_reset(uint8_t index, const void
> *param, uint16_t length, goto failed;
> }
>
> + if (ag.registered)
> + if (!l_dbus_proxy_method_call(ag.proxy, "UnregisterAgent",
> + unreg_agent_setup,
> + unreg_agent_reply,
> + NULL, NULL)) {
> + status = BTP_ERROR_FAIL;
> + goto failed;
> + }
> +
> /* TODO for we assume all went well */
> btp_send(btp, BTP_GAP_SERVICE, BTP_OP_GAP_RESET, index, 0, NULL);
> return;
> @@ -1513,6 +1593,278 @@ failed:
> btp_send_error(btp, BTP_GAP_SERVICE, index, status);
> }
>
> +static struct l_dbus_message *ag_release_call(struct l_dbus *dbus,
> + struct l_dbus_message *message,
> + void *user_data)
> +{
> + struct l_dbus_message *reply;
> +
> + reply = l_dbus_message_new_method_return(message);
> + l_dbus_message_set_arguments(reply, "");
> +
> + return reply;
> +}
> +
> +static struct l_dbus_message *ag_request_passkey_call(struct l_dbus *dbus,
> + struct l_dbus_message *message,
> + void *user_data)
> +{
> + struct btp_gap_passkey_req_ev ev;
> + struct btp_device *device;
> + struct btp_adapter *adapter;
> + const char *path, *str_addr, *str_addr_type;
> +
> + l_dbus_message_get_arguments(message, "o", &path);
> +
> + device = find_device_by_path(path);
> +
> + if (!l_dbus_proxy_get_property(device->proxy, "Address", "s", &str_addr)
> + || !l_dbus_proxy_get_property(device->proxy, "AddressType", "s",
> + &str_addr_type)) {
> + l_info("Cannot get device properties");
> +
> + return NULL;
> + }
> +
> + ev.address_type = strcmp(str_addr_type, "public") ?
> + BTP_GAP_ADDR_RANDOM :
> + BTP_GAP_ADDR_PUBLIC;
> + if (!str2ba(str_addr, &ev.address))
> + return NULL;
> +
> + adapter = find_adapter_by_device(device);
> +
> + ag.pending_req = l_dbus_message_ref(message);
> +
> + btp_send(btp, BTP_GAP_SERVICE, BTP_EV_GAP_PASSKEY_REQUEST,
> + adapter->index, sizeof(ev), &ev);
> +
> + return NULL;
> +}
> +
> +static struct l_dbus_message *ag_display_passkey_call(struct l_dbus *dbus,
> + struct l_dbus_message *message,
> + void *user_data)
> +{
> + struct l_dbus_message *reply;
> +
> + reply = l_dbus_message_new_method_return(message);
> + l_dbus_message_set_arguments(reply, "");
> +
> + return reply;
> +}
> +
> +static struct l_dbus_message *ag_request_confirmation_call(struct l_dbus
> *dbus, + struct l_dbus_message *message,
> + void *user_data)
> +{
> + struct l_dbus_message *reply;
> +
> + reply = l_dbus_message_new_method_return(message);
> + l_dbus_message_set_arguments(reply, "");
> +
> + return reply;
> +}
> +
> +static struct l_dbus_message *ag_authorize_service_call(struct l_dbus
> *dbus, + struct l_dbus_message *message,
> + void *user_data)
> +{
> + struct l_dbus_message *reply;
> +
> + reply = l_dbus_message_new_method_return(message);
> + l_dbus_message_set_arguments(reply, "");
> +
> + return reply;
> +}
> +
> +static struct l_dbus_message *ag_cancel_call(struct l_dbus *dbus,
> + struct l_dbus_message *message,
> + void *user_data)
> +{
> + struct l_dbus_message *reply;
> +
> + reply = l_dbus_message_new_method_return(message);
> + l_dbus_message_set_arguments(reply, "");
> +
> + return reply;
> +}
> +
> +static void setup_ag_interface(struct l_dbus_interface *iface)
> +{
> + l_dbus_interface_method(iface, "Release", 0, ag_release_call, "", "");
> + l_dbus_interface_method(iface, "RequestPasskey", 0,
> + ag_request_passkey_call, "u", "o",
> + "passkey", "device");
> + l_dbus_interface_method(iface, "DisplayPasskey", 0,
> + ag_display_passkey_call, "", "ouq",
> + "device", "passkey", "entered");
> + l_dbus_interface_method(iface, "RequestConfirmation", 0,
> + ag_request_confirmation_call, "", "ou",
> + "device", "passkey");
> + l_dbus_interface_method(iface, "RequestAuthorization", 0,
> + ag_request_confirmation_call, "", "o",
> + "device");
> + l_dbus_interface_method(iface, "AuthorizeService", 0,
> + ag_authorize_service_call, "", "os",
> + "device", "uuid");
> + l_dbus_interface_method(iface, "Cancel", 0, ag_cancel_call, "", "");
> +}
> +
> +struct set_io_capabilities_data {
> + uint8_t capa;
> + struct btp_adapter *adapter;
> +};
> +
> +static void set_io_capabilities_setup(struct l_dbus_message *message,
> + void *user_data)
> +{
> + struct set_io_capabilities_data *sicd = user_data;
> + struct l_dbus_message_builder *builder;
> + char *capa_str;
> +
> + builder = l_dbus_message_builder_new(message);
> +
> + l_dbus_message_builder_append_basic(builder, 'o', AG_PATH);
> +
> + switch (sicd->capa) {
> + case BTP_GAP_IOCAPA_DISPLAY_ONLY:
> + capa_str = "DisplayOnly";
> + break;
> + case BTP_GAP_IOCAPA_DISPLAY_YESNO:
> + capa_str = "DisplayYesNo";
> + break;
> + case BTP_GAP_IOCAPA_KEYBOARD_ONLY:
> + capa_str = "KeyboardOnly";
> + break;
> + case BTP_GAP_IOCAPA_NO_INPUT_NO_OUTPUT:
> + capa_str = "NoInputNoOutput";
> + break;
> + case BTP_GAP_IOCAPA_KEYBOARD_DISPLAY:
> + capa_str = "KeyboardDisplay";
> + break;
> + default:
> + l_error("Wrong iocapa given!");
> + l_dbus_message_builder_finalize(builder);
> + l_dbus_message_builder_destroy(builder);
> +
> + return;
> + }
setup callback should only build message, not verify parameters as it returns
void. Please check those in btp_gap_set_io_capabilities().
> +
> + l_dbus_message_builder_append_basic(builder, 's', capa_str);
> +
> + l_dbus_message_builder_finalize(builder);
> + l_dbus_message_builder_destroy(builder);
> +}
> +
> +static void set_io_capabilities_reply(struct l_dbus_proxy *proxy,
> + struct l_dbus_message *result,
> + void *user_data)
> +{
> + struct set_io_capabilities_data *sicd = user_data;
> +
> + if (!sicd->adapter) {
> + btp_send_error(btp, BTP_GAP_SERVICE, BTP_INDEX_NON_CONTROLLER,
> + BTP_ERROR_FAIL);
> + return;
> + }
> +
> + if (l_dbus_message_is_error(result)) {
> + const char *name, *desc;
> +
> + if (!l_dbus_object_remove_interface(dbus, AG_PATH, AG_IFACE))
> + l_info("Unable to remove agent instance");
> + if (!l_dbus_unregister_interface(dbus, AG_IFACE))
> + l_info("Unable to unregister agent interface");
> +
> + l_dbus_message_get_error(result, &name, &desc);
> + l_error("Failed to set io capabilities (%s), %s", name, desc);
> +
> + btp_send_error(btp, BTP_GAP_SERVICE, sicd->adapter->index,
> + BTP_ERROR_FAIL);
> + return;
> + }
> +
> + ag.registered = true;
> +
> + btp_send(btp, BTP_GAP_SERVICE, BTP_OP_GAP_SET_IO_CAPA,
> + sicd->adapter->index, 0, NULL);
> +}
> +
> +static void set_io_capabilities_destroy(void *user_data)
> +{
> + l_free(user_data);
> +}
> +
> +static void btp_gap_set_io_capabilities(uint8_t index, const void *param,
> + uint16_t length, void *user_data)
> +{
> + struct btp_adapter *adapter = find_adapter_by_index(index);
> + const struct btp_gap_set_io_capa_cp *cp = param;
> + uint8_t status = BTP_ERROR_FAIL;
> + struct set_io_capabilities_data *data;
> + bool prop;
> +
> + if (!adapter) {
> + status = BTP_ERROR_INVALID_INDEX;
> + goto failed;
> + }
> +
> + /* Adapter needs to be powered to be able to set io cap */
> + if (!l_dbus_proxy_get_property(adapter->proxy, "Powered", "b", &prop) ||
> + !prop || ag.registered)
> + goto failed;
> +
> + if (!l_dbus_register_interface(dbus, AG_IFACE, setup_ag_interface, NULL,
> + false)) {
> + l_info("Unable to register agent interface");
> + goto failed;
> + }
> +
> + if (!l_dbus_object_add_interface(dbus, AG_PATH, AG_IFACE, NULL)) {
> + l_info("Unable to instantiate agent interface");
> +
> + if (!l_dbus_unregister_interface(dbus, AD_IFACE))
> + l_info("Unable to unregister agent interface");
> +
> + goto failed;
> + }
> +
> + if (!l_dbus_object_add_interface(dbus, AG_PATH,
> + L_DBUS_INTERFACE_PROPERTIES,
> + NULL)) {
> + l_info("Unable to instantiate the ag properties interface");
> +
> + if (!l_dbus_object_remove_interface(dbus, AG_PATH, AG_IFACE))
> + l_info("Unable to remove agent instance");
> + if (!l_dbus_unregister_interface(dbus, AG_IFACE))
> + l_info("Unable to unregister agent interface");
> +
> + goto failed;
> + }
> +
> + data = l_new(struct set_io_capabilities_data, 1);
> + data->adapter = adapter;
> + data->capa = cp->capa;
> +
> + if (!l_dbus_proxy_method_call(ag.proxy, "RegisterAgent",
> + set_io_capabilities_setup,
> + set_io_capabilities_reply, data,
> + set_io_capabilities_destroy)) {
> + if (!l_dbus_object_remove_interface(dbus, AG_PATH, AG_IFACE))
> + l_info("Unable to remove agent instance");
> + if (!l_dbus_unregister_interface(dbus, AG_IFACE))
> + l_info("Unable to unregister agent interface");
> +
> + goto failed;
> + }
> +
> + return;
> +
> +failed:
> + btp_send_error(btp, BTP_GAP_SERVICE, index, status);
> +}
> +
> static void btp_gap_device_found_ev(struct l_dbus_proxy *proxy)
> {
> struct btp_device_found_ev ev;
> @@ -1634,6 +1986,9 @@ static void register_gap_service(void)
>
> btp_register(btp, BTP_GAP_SERVICE, BTP_OP_GAP_DISCONNECT,
> btp_gap_disconnect, NULL, NULL);
> +
> + btp_register(btp, BTP_GAP_SERVICE, BTP_OP_GAP_SET_IO_CAPA,
> + btp_gap_set_io_capabilities, NULL, NULL);
> }
>
> static void btp_core_read_commands(uint8_t index, const void *param,
> @@ -1889,6 +2244,12 @@ static void proxy_added(struct l_dbus_proxy *proxy,
> void *user_data)
>
> return;
> }
> +
> + if (!strcmp(interface, "org.bluez.AgentManager1")) {
> + ag.proxy = proxy;
> +
> + return;
> + }
> }
>
> static bool device_match_by_proxy(const void *a, const void *b)
More general comment. We should register default agent on startup so that
system agent is never used when btpclient is running. When this command is
called and iocapa is differrent than currently used we should unregister
current agent and register new default.
--
pozdrawiam
Szymon Janc
Hi Grzegorz,
On Friday, 19 January 2018 17:41:26 CET Grzegorz Kolodziejczyk wrote:
> Comment should be aproperiate for advertising command. Device needs to
> be powered to advertise.
> ---
> tools/btpclient.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/tools/btpclient.c b/tools/btpclient.c
> index af0e75290..33116ce1b 100644
> --- a/tools/btpclient.c
> +++ b/tools/btpclient.c
> @@ -1038,7 +1038,7 @@ static void btp_gap_start_advertising(uint8_t index,
> const void *param, goto failed;
> }
>
> - /* Adapter needs to be powered to be able to remove devices */
> + /* Adapter needs to be powered to be able to advertise */
> if (!l_dbus_proxy_get_property(adapter->proxy, "Powered", "b", &prop) ||
> !prop || ad.registered)
> goto failed;
Patches 1 and 2 are now applied. Thanks.
--
pozdrawiam
Szymon Janc
This patch adds passkey confirm command handler and passkey confirm
event.
---
tools/btpclient.c | 94 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 94 insertions(+)
diff --git a/tools/btpclient.c b/tools/btpclient.c
index 55e5170a7..780c2a8db 100644
--- a/tools/btpclient.c
+++ b/tools/btpclient.c
@@ -1703,11 +1703,43 @@ static struct l_dbus_message *ag_request_confirmation_call(struct l_dbus *dbus,
struct l_dbus_message *message,
void *user_data)
{
+ struct btp_gap_passkey_confirm_ev ev;
+ struct btp_device *device;
+ struct btp_adapter *adapter;
struct l_dbus_message *reply;
+ const char *path, *str_addr, *str_addr_type;
+ uint32_t passkey;
reply = l_dbus_message_new_method_return(message);
l_dbus_message_set_arguments(reply, "");
+ l_dbus_message_get_arguments(message, "ou", &path, &passkey);
+
+ device = find_device_by_path(path);
+
+ if (!l_dbus_proxy_get_property(device->proxy, "Address", "s", &str_addr)
+ || !l_dbus_proxy_get_property(device->proxy, "AddressType", "s",
+ &str_addr_type)) {
+ l_info("Cannot get device properties");
+
+ return reply;
+ }
+
+ ev.passkey = L_CPU_TO_LE32(passkey);
+ ev.address_type = strcmp(str_addr_type, "public") ?
+ BTP_GAP_ADDR_RANDOM :
+ BTP_GAP_ADDR_PUBLIC;
+ if (str2ba(str_addr, &ev.address) < 0) {
+ l_info("Incorrect device address");
+
+ return reply;
+ }
+
+ adapter = find_adapter_by_device(device);
+
+ btp_send(btp, BTP_GAP_SERVICE, BTP_EV_GAP_PASSKEY_CONFIRM,
+ adapter->index, sizeof(ev), &ev);
+
return reply;
}
@@ -2082,6 +2114,65 @@ failed:
btp_send_error(btp, BTP_GAP_SERVICE, index, status);
}
+static void passkey_confirm_rsp_reply(struct l_dbus_message *result,
+ void *user_data)
+{
+ struct btp_adapter *adapter = user_data;
+
+ if (l_dbus_message_is_error(result)) {
+ const char *name, *desc;
+
+ l_dbus_message_get_error(result, &name, &desc);
+ l_error("Failed to confirm passkey (%s), %s", name, desc);
+
+ btp_send_error(btp, BTP_GAP_SERVICE, adapter->index,
+ BTP_ERROR_FAIL);
+ return;
+ }
+
+ l_dbus_message_unref(ag.pending_req);
+
+ btp_send(btp, BTP_GAP_SERVICE, BTP_OP_GAP_PASSKEY_CONFIRM_RSP,
+ adapter->index, 0, NULL);
+}
+
+static void btp_gap_confirm_entry_rsp(uint8_t index, const void *param,
+ uint16_t length, void *user_data)
+{
+ const struct btp_gap_passkey_confirm_rsp_cp *cp = param;
+ struct btp_adapter *adapter = find_adapter_by_index(index);
+ struct l_dbus_message *reply;
+ uint8_t status = BTP_ERROR_FAIL;
+ bool prop;
+
+ if (!adapter) {
+ status = BTP_ERROR_INVALID_INDEX;
+ goto failed;
+ }
+
+ /* Adapter needs to be powered to be able to confirm passkey */
+ if (!l_dbus_proxy_get_property(adapter->proxy, "Powered", "b", &prop) ||
+ !prop || !ag.pending_req)
+ goto failed;
+
+ if (cp->match) {
+ reply = l_dbus_message_new_method_return(ag.pending_req);
+ l_dbus_message_set_arguments(reply, "");
+ } else {
+ reply = l_dbus_message_new_error(ag.pending_req,
+ "org.bluez.Error.Rejected",
+ "Passkey missmatch");
+ }
+
+ l_dbus_send_with_reply(dbus, ag.pending_req, passkey_confirm_rsp_reply,
+ adapter, NULL);
+
+ return;
+
+failed:
+ btp_send_error(btp, BTP_GAP_SERVICE, index, status);
+}
+
static void btp_gap_device_found_ev(struct l_dbus_proxy *proxy)
{
struct btp_device_found_ev ev;
@@ -2215,6 +2306,9 @@ static void register_gap_service(void)
btp_register(btp, BTP_GAP_SERVICE, BTP_OP_GAP_PASSKEY_ENTRY_RSP,
btp_gap_passkey_entry_rsp, NULL, NULL);
+
+ btp_register(btp, BTP_GAP_SERVICE, BTP_OP_GAP_PASSKEY_CONFIRM_RSP,
+ btp_gap_confirm_entry_rsp, NULL, NULL);
}
static void btp_core_read_commands(uint8_t index, const void *param,
--
2.13.6
This patch adds passkey entry command handler and passkey display event.
---
tools/btpclient.c | 92 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 92 insertions(+)
diff --git a/tools/btpclient.c b/tools/btpclient.c
index 9d44fba41..55e5170a7 100644
--- a/tools/btpclient.c
+++ b/tools/btpclient.c
@@ -1658,11 +1658,44 @@ static struct l_dbus_message *ag_display_passkey_call(struct l_dbus *dbus,
struct l_dbus_message *message,
void *user_data)
{
+ struct btp_gap_passkey_display_ev ev;
+ struct btp_device *device;
+ struct btp_adapter *adapter;
struct l_dbus_message *reply;
+ const char *path, *str_addr, *str_addr_type;
+ uint32_t passkey;
+ uint16_t entered;
reply = l_dbus_message_new_method_return(message);
l_dbus_message_set_arguments(reply, "");
+ l_dbus_message_get_arguments(message, "ouq", &path, &passkey, &entered);
+
+ device = find_device_by_path(path);
+
+ if (!l_dbus_proxy_get_property(device->proxy, "Address", "s", &str_addr)
+ || !l_dbus_proxy_get_property(device->proxy, "AddressType", "s",
+ &str_addr_type)) {
+ l_info("Cannot get device properties");
+
+ return reply;
+ }
+
+ ev.passkey = L_CPU_TO_LE32(passkey);
+ ev.address_type = strcmp(str_addr_type, "public") ?
+ BTP_GAP_ADDR_RANDOM :
+ BTP_GAP_ADDR_PUBLIC;
+ if (str2ba(str_addr, &ev.address) < 0) {
+ l_info("Incorrect device addres");
+
+ return reply;
+ }
+
+ adapter = find_adapter_by_device(device);
+
+ btp_send(btp, BTP_GAP_SERVICE, BTP_EV_GAP_PASSKEY_DISPLAY,
+ adapter->index, sizeof(ev), &ev);
+
return reply;
}
@@ -1993,6 +2026,62 @@ failed:
btp_send_error(btp, BTP_GAP_SERVICE, index, status);
}
+static void passkey_entry_rsp_reply(struct l_dbus_message *result,
+ void *user_data)
+{
+ struct btp_adapter *adapter = user_data;
+
+ if (l_dbus_message_is_error(result)) {
+ const char *name, *desc;
+
+ l_dbus_message_get_error(result, &name, &desc);
+ l_error("Failed to reply with passkey (%s), %s", name, desc);
+
+ btp_send_error(btp, BTP_GAP_SERVICE, adapter->index,
+ BTP_ERROR_FAIL);
+ return;
+ }
+
+ l_dbus_message_unref(ag.pending_req);
+
+ btp_send(btp, BTP_GAP_SERVICE, BTP_OP_GAP_PASSKEY_ENTRY_RSP,
+ adapter->index, 0, NULL);
+}
+
+static void btp_gap_passkey_entry_rsp(uint8_t index, const void *param,
+ uint16_t length, void *user_data)
+{
+ const struct btp_gap_passkey_entry_rsp_cp *cp = param;
+ struct btp_adapter *adapter = find_adapter_by_index(index);
+ struct l_dbus_message_builder *builder;
+ uint8_t status = BTP_ERROR_FAIL;
+ uint32_t passkey = L_CPU_TO_LE32(cp->passkey);
+ bool prop;
+
+ if (!adapter) {
+ status = BTP_ERROR_INVALID_INDEX;
+ goto failed;
+ }
+
+ /* Adapter needs to be powered to be able to response with passkey */
+ if (!l_dbus_proxy_get_property(adapter->proxy, "Powered", "b", &prop) ||
+ !prop || !ag.pending_req)
+ goto failed;
+
+ builder = l_dbus_message_builder_new(ag.pending_req);
+ l_dbus_message_builder_append_basic(builder, 'u', &passkey);
+ l_dbus_message_builder_finalize(builder);
+ l_dbus_message_builder_destroy(builder);
+
+ l_dbus_send_with_reply(dbus, ag.pending_req, passkey_entry_rsp_reply,
+ adapter, NULL);
+
+ return;
+
+failed:
+ btp_send_error(btp, BTP_GAP_SERVICE, index, status);
+}
+
static void btp_gap_device_found_ev(struct l_dbus_proxy *proxy)
{
struct btp_device_found_ev ev;
@@ -2123,6 +2212,9 @@ static void register_gap_service(void)
btp_register(btp, BTP_GAP_SERVICE, BTP_OP_GAP_UNPAIR, btp_gap_unpair,
NULL, NULL);
+
+ btp_register(btp, BTP_GAP_SERVICE, BTP_OP_GAP_PASSKEY_ENTRY_RSP,
+ btp_gap_passkey_entry_rsp, NULL, NULL);
}
static void btp_core_read_commands(uint8_t index, const void *param,
--
2.13.6
This patch adds pair and unpair commands for btp client.
---
tools/btpclient.c | 124 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 124 insertions(+)
diff --git a/tools/btpclient.c b/tools/btpclient.c
index 53c0d4c05..9d44fba41 100644
--- a/tools/btpclient.c
+++ b/tools/btpclient.c
@@ -304,6 +304,8 @@ static void btp_gap_read_commands(uint8_t index, const void *param,
commands |= (1 << BTP_OP_GAP_CONNECT);
commands |= (1 << BTP_OP_GAP_DISCONNECT);
commands |= (1 << BTP_OP_GAP_SET_IO_CAPA);
+ commands |= (1 << BTP_OP_GAP_PAIR);
+ commands |= (1 << BTP_OP_GAP_UNPAIR);
commands = L_CPU_TO_LE16(commands);
@@ -1875,6 +1877,122 @@ failed:
btp_send_error(btp, BTP_GAP_SERVICE, index, status);
}
+static void pair_reply(struct l_dbus_proxy *proxy,
+ struct l_dbus_message *result, void *user_data)
+{
+ uint8_t adapter_index = L_PTR_TO_UINT(user_data);
+ struct btp_adapter *adapter = find_adapter_by_index(adapter_index);
+
+ if (!adapter)
+ return;
+
+ if (l_dbus_message_is_error(result)) {
+ const char *name, *desc;
+
+ l_dbus_message_get_error(result, &name, &desc);
+ l_error("Failed to pair (%s), %s", name, desc);
+
+ return;
+ }
+}
+
+static void btp_gap_pair(uint8_t index, const void *param, uint16_t length,
+ void *user_data)
+{
+ struct btp_adapter *adapter = find_adapter_by_index(index);
+ const struct btp_gap_pair_cp *cp = param;
+ uint8_t status = BTP_ERROR_FAIL;
+ struct btp_device *device;
+ bool prop;
+
+ if (!adapter) {
+ status = BTP_ERROR_INVALID_INDEX;
+ goto failed;
+ }
+
+ /* Adapter needs to be powered to be able to pair */
+ if (!l_dbus_proxy_get_property(adapter->proxy, "Powered", "b", &prop) ||
+ !prop)
+ goto failed;
+
+ device = find_device_by_address(adapter, &cp->address,
+ cp->address_type);
+
+ if (!device)
+ goto failed;
+
+ btp_send(btp, BTP_GAP_SERVICE, BTP_OP_GAP_PAIR, adapter->index, 0,
+ NULL);
+
+ l_dbus_proxy_method_call(device->proxy, "Pair", NULL, pair_reply,
+ L_UINT_TO_PTR(adapter->index), NULL);
+
+ return;
+
+failed:
+ btp_send_error(btp, BTP_GAP_SERVICE, index, status);
+}
+
+static void unpair_reply(struct l_dbus_proxy *proxy,
+ struct l_dbus_message *result, void *user_data)
+{
+ uint8_t adapter_index = L_PTR_TO_UINT(user_data);
+ struct btp_adapter *adapter = find_adapter_by_index(adapter_index);
+
+ if (!adapter) {
+ btp_send_error(btp, BTP_GAP_SERVICE, BTP_INDEX_NON_CONTROLLER,
+ BTP_ERROR_FAIL);
+ return;
+ }
+
+ if (l_dbus_message_is_error(result)) {
+ const char *name, *desc;
+
+ l_dbus_message_get_error(result, &name, &desc);
+ l_error("Failed to unpair (%s), %s", name, desc);
+
+ btp_send_error(btp, BTP_GAP_SERVICE, adapter_index,
+ BTP_ERROR_FAIL);
+ return;
+ }
+
+ btp_send(btp, BTP_GAP_SERVICE, BTP_OP_GAP_UNPAIR, adapter_index, 0, NULL);
+}
+
+static void btp_gap_unpair(uint8_t index, const void *param, uint16_t length,
+ void *user_data)
+{
+ struct btp_adapter *adapter = find_adapter_by_index(index);
+ const struct btp_gap_pair_cp *cp = param;
+ uint8_t status = BTP_ERROR_FAIL;
+ struct btp_device *device;
+ bool prop;
+
+ if (!adapter) {
+ status = BTP_ERROR_INVALID_INDEX;
+ goto failed;
+ }
+
+ /* Adapter needs to be powered to be able to unpair */
+ if (!l_dbus_proxy_get_property(adapter->proxy, "Powered", "b", &prop) ||
+ !prop)
+ goto failed;
+
+ device = find_device_by_address(adapter, &cp->address,
+ cp->address_type);
+
+ if (!device)
+ goto failed;
+
+ l_dbus_proxy_method_call(device->proxy, "Unpair", NULL, unpair_reply,
+ L_UINT_TO_PTR(adapter->index), NULL);
+
+ return;
+
+failed:
+ btp_send_error(btp, BTP_GAP_SERVICE, index, status);
+}
+
static void btp_gap_device_found_ev(struct l_dbus_proxy *proxy)
{
struct btp_device_found_ev ev;
@@ -1999,6 +2117,12 @@ static void register_gap_service(void)
btp_register(btp, BTP_GAP_SERVICE, BTP_OP_GAP_SET_IO_CAPA,
btp_gap_set_io_capabilities, NULL, NULL);
+
+ btp_register(btp, BTP_GAP_SERVICE, BTP_OP_GAP_PAIR, btp_gap_pair, NULL,
+ NULL);
+
+ btp_register(btp, BTP_GAP_SERVICE, BTP_OP_GAP_UNPAIR, btp_gap_unpair,
+ NULL, NULL);
}
static void btp_core_read_commands(uint8_t index, const void *param,
--
2.13.6
This patch adds advertising data cleanup routine to reset command if
registered.
---
tools/btpclient.c | 71 ++++++++++++++++++++++++++++++-------------------------
1 file changed, 39 insertions(+), 32 deletions(-)
diff --git a/tools/btpclient.c b/tools/btpclient.c
index c5f88e673..53c0d4c05 100644
--- a/tools/btpclient.c
+++ b/tools/btpclient.c
@@ -413,6 +413,37 @@ static void remove_device_reply(struct l_dbus_proxy *proxy,
l_queue_remove(adapter->devices, device);
}
+static void update_current_settings(struct btp_adapter *adapter,
+ uint32_t new_settings)
+{
+ struct btp_new_settings_ev ev;
+
+ adapter->current_settings = new_settings;
+
+ ev.current_settings = L_CPU_TO_LE32(adapter->current_settings);
+
+ btp_send(btp, BTP_GAP_SERVICE, BTP_EV_GAP_NEW_SETTINGS, adapter->index,
+ sizeof(ev), &ev);
+}
+
+static void ad_cleanup_service(void *service)
+{
+ struct service_data *s = service;
+
+ l_free(s->uuid);
+ l_free(s);
+}
+
+static void ad_cleanup(void)
+{
+ l_free(ad.local_name);
+ l_queue_destroy(ad.uuids, l_free);
+ l_queue_destroy(ad.services, ad_cleanup_service);
+ l_queue_destroy(ad.manufacturers, l_free);
+
+ memset(&ad, 0, sizeof(ad));
+}
+
static void unreg_advertising_setup(struct l_dbus_message *message,
void *user_data)
{
@@ -430,6 +461,7 @@ static void unreg_advertising_reply(struct l_dbus_proxy *proxy,
{
const char *path = l_dbus_proxy_get_path(proxy);
struct btp_adapter *adapter = find_adapter_by_path(path);
+ uint32_t new_settings;
if (!adapter)
return;
@@ -451,6 +483,12 @@ static void unreg_advertising_reply(struct l_dbus_proxy *proxy,
l_info("Unable to remove propety instance");
if (!l_dbus_unregister_interface(dbus, AD_IFACE))
l_info("Unable to unregister ad interface");
+
+ new_settings = adapter->current_settings;
+ new_settings &= ~BTP_GAP_SETTING_ADVERTISING;
+ update_current_settings(adapter, new_settings);
+
+ ad_cleanup();
}
static void unreg_agent_setup(struct l_dbus_message *message, void *user_data)
@@ -520,7 +558,7 @@ static void btp_gap_reset(uint8_t index, const void *param, uint16_t length,
NULL);
}
- if (adapter->ad_proxy)
+ if (adapter->ad_proxy && ad.registered)
if (!l_dbus_proxy_method_call(adapter->ad_proxy,
"UnregisterAdvertisement",
unreg_advertising_setup,
@@ -613,19 +651,6 @@ failed:
btp_send_error(btp, BTP_GAP_SERVICE, index, status);
}
-static void update_current_settings(struct btp_adapter *adapter,
- uint32_t new_settings)
-{
- struct btp_new_settings_ev ev;
-
- adapter->current_settings = new_settings;
-
- ev.current_settings = L_CPU_TO_LE32(adapter->current_settings);
-
- btp_send(btp, BTP_GAP_SERVICE, BTP_EV_GAP_NEW_SETTINGS, adapter->index,
- sizeof(ev), &ev);
-}
-
static void btp_gap_set_connectable(uint8_t index, const void *param,
uint16_t length, void *user_data)
{
@@ -726,24 +751,6 @@ failed:
btp_send_error(btp, BTP_GAP_SERVICE, index, status);
}
-static void ad_cleanup_service(void *service)
-{
- struct service_data *s = service;
-
- l_free(s->uuid);
- l_free(s);
-}
-
-static void ad_cleanup(void)
-{
- l_free(ad.local_name);
- l_queue_destroy(ad.uuids, l_free);
- l_queue_destroy(ad.services, ad_cleanup_service);
- l_queue_destroy(ad.manufacturers, l_free);
-
- memset(&ad, 0, sizeof(ad));
-}
-
static void ad_init(void)
{
ad.uuids = l_queue_new();
--
2.13.6
Reset command will restore default settings of adapter.
---
tools/btpclient.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/tools/btpclient.c b/tools/btpclient.c
index 708092937..c5f88e673 100644
--- a/tools/btpclient.c
+++ b/tools/btpclient.c
@@ -56,6 +56,7 @@ struct btp_adapter {
uint8_t index;
uint32_t supported_settings;
uint32_t current_settings;
+ uint32_t default_settings;
struct l_queue *devices;
};
@@ -538,6 +539,8 @@ static void btp_gap_reset(uint8_t index, const void *param, uint16_t length,
goto failed;
}
+ adapter->current_settings = adapter->default_settings;
+
/* TODO for we assume all went well */
btp_send(btp, BTP_GAP_SERVICE, BTP_OP_GAP_RESET, index, 0, NULL);
return;
@@ -2207,6 +2210,8 @@ static void proxy_added(struct l_dbus_proxy *proxy, void *user_data)
extract_settings(proxy, &adapter->current_settings,
&adapter->supported_settings);
+ adapter->default_settings = adapter->current_settings;
+
l_queue_push_tail(adapters, adapter);
return;
}
--
2.13.6
This patch adds support for set io capabilities command.
---
tools/btpclient.c | 361 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 361 insertions(+)
diff --git a/tools/btpclient.c b/tools/btpclient.c
index f2c79b3a3..708092937 100644
--- a/tools/btpclient.c
+++ b/tools/btpclient.c
@@ -36,7 +36,9 @@
#include "src/shared/btp.h"
#define AD_PATH "/org/bluez/advertising"
+#define AG_PATH "/org/bluez/agent"
#define AD_IFACE "org.bluez.LEAdvertisement1"
+#define AG_IFACE "org.bluez.Agent1"
/* List of assigned numbers for advetising data and scan response */
#define AD_TYPE_FLAGS 0x01
@@ -97,6 +99,12 @@ static struct ad {
bool appearance;
} ad;
+static struct btp_agent {
+ bool registered;
+ struct l_dbus_proxy *proxy;
+ struct l_dbus_message *pending_req;
+} ag;
+
static char *dupuuid2str(const uint8_t *uuid, uint8_t len)
{
switch (len) {
@@ -198,6 +206,31 @@ static struct btp_device *find_device_by_address(struct btp_adapter *adapter,
return NULL;
}
+static bool match_device_paths(const void *device, const void *path)
+{
+ const struct btp_device *dev = device;
+
+ return !strcmp(l_dbus_proxy_get_path(dev->proxy), path);
+}
+
+static struct btp_device *find_device_by_path(const char *path)
+{
+ const struct l_queue_entry *entry;
+ struct btp_device *device;
+
+ for (entry = l_queue_get_entries(adapters); entry;
+ entry = entry->next) {
+ struct btp_adapter *adapter = entry->data;
+
+ device = l_queue_find(adapter->devices, match_device_paths,
+ path);
+ if (device)
+ return device;
+ }
+
+ return NULL;
+}
+
static bool match_adapter_dev_proxy(const void *device, const void *proxy)
{
const struct btp_device *d = device;
@@ -269,6 +302,7 @@ static void btp_gap_read_commands(uint8_t index, const void *param,
commands |= (1 << BTP_OP_GAP_STOP_DISCOVERY);
commands |= (1 << BTP_OP_GAP_CONNECT);
commands |= (1 << BTP_OP_GAP_DISCONNECT);
+ commands |= (1 << BTP_OP_GAP_SET_IO_CAPA);
commands = L_CPU_TO_LE16(commands);
@@ -418,6 +452,43 @@ static void unreg_advertising_reply(struct l_dbus_proxy *proxy,
l_info("Unable to unregister ad interface");
}
+static void unreg_agent_setup(struct l_dbus_message *message, void *user_data)
+{
+ struct l_dbus_message_builder *builder;
+
+ builder = l_dbus_message_builder_new(message);
+
+ l_dbus_message_builder_append_basic(builder, 'o', AG_PATH);
+
+ l_dbus_message_builder_finalize(builder);
+ l_dbus_message_builder_destroy(builder);
+}
+
+static void unreg_agent_reply(struct l_dbus_proxy *proxy,
+ struct l_dbus_message *result,
+ void *user_data)
+{
+ if (l_dbus_message_is_error(result)) {
+ const char *name;
+
+ l_dbus_message_get_error(result, &name, NULL);
+
+ l_error("Failed to unregister agent %s (%s)",
+ l_dbus_proxy_get_path(proxy), name);
+ return;
+ }
+
+ if (!l_dbus_object_remove_interface(dbus, AG_PATH,
+ L_DBUS_INTERFACE_PROPERTIES))
+ l_info("Unable to remove propety instance");
+ if (!l_dbus_object_remove_interface(dbus, AG_PATH, AG_IFACE))
+ l_info("Unable to remove agent instance");
+ if (!l_dbus_unregister_interface(dbus, AG_IFACE))
+ l_info("Unable to unregister agent interface");
+
+ ag.registered = false;
+}
+
static void btp_gap_reset(uint8_t index, const void *param, uint16_t length,
void *user_data)
{
@@ -458,6 +529,15 @@ static void btp_gap_reset(uint8_t index, const void *param, uint16_t length,
goto failed;
}
+ if (ag.registered)
+ if (!l_dbus_proxy_method_call(ag.proxy, "UnregisterAgent",
+ unreg_agent_setup,
+ unreg_agent_reply,
+ NULL, NULL)) {
+ status = BTP_ERROR_FAIL;
+ goto failed;
+ }
+
/* TODO for we assume all went well */
btp_send(btp, BTP_GAP_SERVICE, BTP_OP_GAP_RESET, index, 0, NULL);
return;
@@ -1513,6 +1593,278 @@ failed:
btp_send_error(btp, BTP_GAP_SERVICE, index, status);
}
+static struct l_dbus_message *ag_release_call(struct l_dbus *dbus,
+ struct l_dbus_message *message,
+ void *user_data)
+{
+ struct l_dbus_message *reply;
+
+ reply = l_dbus_message_new_method_return(message);
+ l_dbus_message_set_arguments(reply, "");
+
+ return reply;
+}
+
+static struct l_dbus_message *ag_request_passkey_call(struct l_dbus *dbus,
+ struct l_dbus_message *message,
+ void *user_data)
+{
+ struct btp_gap_passkey_req_ev ev;
+ struct btp_device *device;
+ struct btp_adapter *adapter;
+ const char *path, *str_addr, *str_addr_type;
+
+ l_dbus_message_get_arguments(message, "o", &path);
+
+ device = find_device_by_path(path);
+
+ if (!l_dbus_proxy_get_property(device->proxy, "Address", "s", &str_addr)
+ || !l_dbus_proxy_get_property(device->proxy, "AddressType", "s",
+ &str_addr_type)) {
+ l_info("Cannot get device properties");
+
+ return NULL;
+ }
+
+ ev.address_type = strcmp(str_addr_type, "public") ?
+ BTP_GAP_ADDR_RANDOM :
+ BTP_GAP_ADDR_PUBLIC;
+ if (!str2ba(str_addr, &ev.address))
+ return NULL;
+
+ adapter = find_adapter_by_device(device);
+
+ ag.pending_req = l_dbus_message_ref(message);
+
+ btp_send(btp, BTP_GAP_SERVICE, BTP_EV_GAP_PASSKEY_REQUEST,
+ adapter->index, sizeof(ev), &ev);
+
+ return NULL;
+}
+
+static struct l_dbus_message *ag_display_passkey_call(struct l_dbus *dbus,
+ struct l_dbus_message *message,
+ void *user_data)
+{
+ struct l_dbus_message *reply;
+
+ reply = l_dbus_message_new_method_return(message);
+ l_dbus_message_set_arguments(reply, "");
+
+ return reply;
+}
+
+static struct l_dbus_message *ag_request_confirmation_call(struct l_dbus *dbus,
+ struct l_dbus_message *message,
+ void *user_data)
+{
+ struct l_dbus_message *reply;
+
+ reply = l_dbus_message_new_method_return(message);
+ l_dbus_message_set_arguments(reply, "");
+
+ return reply;
+}
+
+static struct l_dbus_message *ag_authorize_service_call(struct l_dbus *dbus,
+ struct l_dbus_message *message,
+ void *user_data)
+{
+ struct l_dbus_message *reply;
+
+ reply = l_dbus_message_new_method_return(message);
+ l_dbus_message_set_arguments(reply, "");
+
+ return reply;
+}
+
+static struct l_dbus_message *ag_cancel_call(struct l_dbus *dbus,
+ struct l_dbus_message *message,
+ void *user_data)
+{
+ struct l_dbus_message *reply;
+
+ reply = l_dbus_message_new_method_return(message);
+ l_dbus_message_set_arguments(reply, "");
+
+ return reply;
+}
+
+static void setup_ag_interface(struct l_dbus_interface *iface)
+{
+ l_dbus_interface_method(iface, "Release", 0, ag_release_call, "", "");
+ l_dbus_interface_method(iface, "RequestPasskey", 0,
+ ag_request_passkey_call, "u", "o",
+ "passkey", "device");
+ l_dbus_interface_method(iface, "DisplayPasskey", 0,
+ ag_display_passkey_call, "", "ouq",
+ "device", "passkey", "entered");
+ l_dbus_interface_method(iface, "RequestConfirmation", 0,
+ ag_request_confirmation_call, "", "ou",
+ "device", "passkey");
+ l_dbus_interface_method(iface, "RequestAuthorization", 0,
+ ag_request_confirmation_call, "", "o",
+ "device");
+ l_dbus_interface_method(iface, "AuthorizeService", 0,
+ ag_authorize_service_call, "", "os",
+ "device", "uuid");
+ l_dbus_interface_method(iface, "Cancel", 0, ag_cancel_call, "", "");
+}
+
+struct set_io_capabilities_data {
+ uint8_t capa;
+ struct btp_adapter *adapter;
+};
+
+static void set_io_capabilities_setup(struct l_dbus_message *message,
+ void *user_data)
+{
+ struct set_io_capabilities_data *sicd = user_data;
+ struct l_dbus_message_builder *builder;
+ char *capa_str;
+
+ builder = l_dbus_message_builder_new(message);
+
+ l_dbus_message_builder_append_basic(builder, 'o', AG_PATH);
+
+ switch (sicd->capa) {
+ case BTP_GAP_IOCAPA_DISPLAY_ONLY:
+ capa_str = "DisplayOnly";
+ break;
+ case BTP_GAP_IOCAPA_DISPLAY_YESNO:
+ capa_str = "DisplayYesNo";
+ break;
+ case BTP_GAP_IOCAPA_KEYBOARD_ONLY:
+ capa_str = "KeyboardOnly";
+ break;
+ case BTP_GAP_IOCAPA_NO_INPUT_NO_OUTPUT:
+ capa_str = "NoInputNoOutput";
+ break;
+ case BTP_GAP_IOCAPA_KEYBOARD_DISPLAY:
+ capa_str = "KeyboardDisplay";
+ break;
+ default:
+ l_error("Wrong iocapa given!");
+ l_dbus_message_builder_finalize(builder);
+ l_dbus_message_builder_destroy(builder);
+
+ return;
+ }
+
+ l_dbus_message_builder_append_basic(builder, 's', capa_str);
+
+ l_dbus_message_builder_finalize(builder);
+ l_dbus_message_builder_destroy(builder);
+}
+
+static void set_io_capabilities_reply(struct l_dbus_proxy *proxy,
+ struct l_dbus_message *result,
+ void *user_data)
+{
+ struct set_io_capabilities_data *sicd = user_data;
+
+ if (!sicd->adapter) {
+ btp_send_error(btp, BTP_GAP_SERVICE, BTP_INDEX_NON_CONTROLLER,
+ BTP_ERROR_FAIL);
+ return;
+ }
+
+ if (l_dbus_message_is_error(result)) {
+ const char *name, *desc;
+
+ if (!l_dbus_object_remove_interface(dbus, AG_PATH, AG_IFACE))
+ l_info("Unable to remove agent instance");
+ if (!l_dbus_unregister_interface(dbus, AG_IFACE))
+ l_info("Unable to unregister agent interface");
+
+ l_dbus_message_get_error(result, &name, &desc);
+ l_error("Failed to set io capabilities (%s), %s", name, desc);
+
+ btp_send_error(btp, BTP_GAP_SERVICE, sicd->adapter->index,
+ BTP_ERROR_FAIL);
+ return;
+ }
+
+ ag.registered = true;
+
+ btp_send(btp, BTP_GAP_SERVICE, BTP_OP_GAP_SET_IO_CAPA,
+ sicd->adapter->index, 0, NULL);
+}
+
+static void set_io_capabilities_destroy(void *user_data)
+{
+ l_free(user_data);
+}
+
+static void btp_gap_set_io_capabilities(uint8_t index, const void *param,
+ uint16_t length, void *user_data)
+{
+ struct btp_adapter *adapter = find_adapter_by_index(index);
+ const struct btp_gap_set_io_capa_cp *cp = param;
+ uint8_t status = BTP_ERROR_FAIL;
+ struct set_io_capabilities_data *data;
+ bool prop;
+
+ if (!adapter) {
+ status = BTP_ERROR_INVALID_INDEX;
+ goto failed;
+ }
+
+ /* Adapter needs to be powered to be able to set io cap */
+ if (!l_dbus_proxy_get_property(adapter->proxy, "Powered", "b", &prop) ||
+ !prop || ag.registered)
+ goto failed;
+
+ if (!l_dbus_register_interface(dbus, AG_IFACE, setup_ag_interface, NULL,
+ false)) {
+ l_info("Unable to register agent interface");
+ goto failed;
+ }
+
+ if (!l_dbus_object_add_interface(dbus, AG_PATH, AG_IFACE, NULL)) {
+ l_info("Unable to instantiate agent interface");
+
+ if (!l_dbus_unregister_interface(dbus, AD_IFACE))
+ l_info("Unable to unregister agent interface");
+
+ goto failed;
+ }
+
+ if (!l_dbus_object_add_interface(dbus, AG_PATH,
+ L_DBUS_INTERFACE_PROPERTIES,
+ NULL)) {
+ l_info("Unable to instantiate the ag properties interface");
+
+ if (!l_dbus_object_remove_interface(dbus, AG_PATH, AG_IFACE))
+ l_info("Unable to remove agent instance");
+ if (!l_dbus_unregister_interface(dbus, AG_IFACE))
+ l_info("Unable to unregister agent interface");
+
+ goto failed;
+ }
+
+ data = l_new(struct set_io_capabilities_data, 1);
+ data->adapter = adapter;
+ data->capa = cp->capa;
+
+ if (!l_dbus_proxy_method_call(ag.proxy, "RegisterAgent",
+ set_io_capabilities_setup,
+ set_io_capabilities_reply, data,
+ set_io_capabilities_destroy)) {
+ if (!l_dbus_object_remove_interface(dbus, AG_PATH, AG_IFACE))
+ l_info("Unable to remove agent instance");
+ if (!l_dbus_unregister_interface(dbus, AG_IFACE))
+ l_info("Unable to unregister agent interface");
+
+ goto failed;
+ }
+
+ return;
+
+failed:
+ btp_send_error(btp, BTP_GAP_SERVICE, index, status);
+}
+
static void btp_gap_device_found_ev(struct l_dbus_proxy *proxy)
{
struct btp_device_found_ev ev;
@@ -1634,6 +1986,9 @@ static void register_gap_service(void)
btp_register(btp, BTP_GAP_SERVICE, BTP_OP_GAP_DISCONNECT,
btp_gap_disconnect, NULL, NULL);
+
+ btp_register(btp, BTP_GAP_SERVICE, BTP_OP_GAP_SET_IO_CAPA,
+ btp_gap_set_io_capabilities, NULL, NULL);
}
static void btp_core_read_commands(uint8_t index, const void *param,
@@ -1889,6 +2244,12 @@ static void proxy_added(struct l_dbus_proxy *proxy, void *user_data)
return;
}
+
+ if (!strcmp(interface, "org.bluez.AgentManager1")) {
+ ag.proxy = proxy;
+
+ return;
+ }
}
static bool device_match_by_proxy(const void *a, const void *b)
--
2.13.6
This patch covers with fail response if no advertising proxy was
registered at command beginning.
---
tools/btpclient.c | 12 ++++--------
1 file changed, 4 insertions(+), 8 deletions(-)
diff --git a/tools/btpclient.c b/tools/btpclient.c
index 33116ce1b..f2c79b3a3 100644
--- a/tools/btpclient.c
+++ b/tools/btpclient.c
@@ -1156,19 +1156,15 @@ static void btp_gap_stop_advertising(uint8_t index, const void *param,
}
if (!l_dbus_proxy_get_property(adapter->proxy, "Powered", "b", &prop) ||
- !prop || !ad.registered)
+ !prop || !adapter->ad_proxy || !ad.registered)
goto failed;
- if (adapter->ad_proxy) {
- if (!l_dbus_proxy_method_call(adapter->ad_proxy,
+ if (!l_dbus_proxy_method_call(adapter->ad_proxy,
"UnregisterAdvertisement",
unreg_advertising_setup,
stop_advertising_reply,
- NULL, NULL)) {
- status = BTP_ERROR_FAIL;
- goto failed;
- }
- }
+ NULL, NULL))
+ goto failed;
return;
--
2.13.6