Re: [PATCH BlueZ 3/8] tools/btpclient: Add set io capabilities command

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Szymon,

2018-01-23 14:48 GMT+01:00 Szymon Janc <szymon.janc@xxxxxxxxxxx>:
> 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().
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 *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.
Agree
>
>
> --
> pozdrawiam
> Szymon Janc
>
>

pozdrawiam,
Grzegorz Kołodziejczyk
--
To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Bluez Devel]     [Linux Wireless Networking]     [Linux Wireless Personal Area Networking]     [Linux ATH6KL]     [Linux USB Devel]     [Linux Media Drivers]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Big List of Linux Books]

  Powered by Linux