diff --git a/apps/bleprph/src/main.c b/apps/bleprph/src/main.c index b9f2d26416..5578db54a0 100644 --- a/apps/bleprph/src/main.c +++ b/apps/bleprph/src/main.c @@ -270,6 +270,14 @@ bleprph_gap_event(struct ble_gap_event *event, void *arg) phy_update(event->phy_updated.tx_phy); return 0; #endif + + case BLE_GAP_EVENT_AUTHORIZE: + MODLOG_DFLT(INFO, + "authorize event: conn_handle=%d attr_handle=," + " is_read=%d\n", + event->authorize.conn_handle, event->authorize.attr_handle, + event->authorize.access_opcode); + return BLE_GAP_AUTHORIZE_REJECT; } return 0; diff --git a/apps/btshell/src/btshell.h b/apps/btshell/src/btshell.h index d8bf83d2ff..933f4c1849 100644 --- a/apps/btshell/src/btshell.h +++ b/apps/btshell/src/btshell.h @@ -97,6 +97,23 @@ struct btshell_scan_opts { extern struct btshell_conn btshell_conns[MYNEWT_VAL(BLE_MAX_CONNECTIONS)]; extern int btshell_num_conns; +/* BLE_GATT_READ_MAX_ATTRS * (1 ATT + 1 EATT chan) */ +#define PENDING_ATTR_MAX MYNEWT_VAL(BLE_GATT_READ_MAX_ATTRS) * 2 + +struct auth_attr { + uint16_t conn_handle; + uint16_t attr_handle; +}; + +extern struct auth_attr authorized_attrs[PENDING_ATTR_MAX]; + +struct pend_attr { + uint16_t attr_handle; + uint16_t cid; +}; + +extern struct pend_attr pending_attr; + int btshell_exchange_mtu(uint16_t conn_handle); int btshell_disc_svcs(uint16_t conn_handle); int btshell_disc_svc_by_uuid(uint16_t conn_handle, const ble_uuid_t *uuid); diff --git a/apps/btshell/src/cmd.c b/apps/btshell/src/cmd.c index 3380de7547..e04b0c17d7 100644 --- a/apps/btshell/src/cmd.c +++ b/apps/btshell/src/cmd.c @@ -176,6 +176,71 @@ cmd_parse_addr(const char *prefix, ble_addr_t *addr) return parse_dev_addr(prefix, cmd_addr_type, addr); } +static int +pending_operation_authorize(int argc, char **argv) +{ + uint16_t conn_handle; + uint16_t attr_handle; + bool auth; + int rc; + + rc = parse_arg_init(argc - 1, argv + 1); + if (rc != 0) { + return rc; + } + + conn_handle = parse_arg_uint16("conn", &rc); + if (rc != 0) { + console_printf("invalid 'conn' parameter\n"); + return rc; + } + + attr_handle = parse_arg_uint16("attr", &rc); + if (rc != 0) { + console_printf("invalid 'attr' parameter\n"); + return rc; + } + + auth = parse_arg_bool_dflt("auth", 1, &rc); + if (rc != 0) { + console_printf("invalid 'auth' parameter\n"); + return rc; + } + + if (auth) { + for (int i = 0; i < PENDING_ATTR_MAX; i++) { + if (authorized_attrs[i].conn_handle == 0 && + authorized_attrs[i].attr_handle == 0) { + authorized_attrs[i].conn_handle = conn_handle; + authorized_attrs[i].attr_handle = attr_handle; + break; + } + } + attr_handle = 0; + } else { + attr_handle = pending_attr.attr_handle; + } + + ble_gatts_pending_req_auth(conn_handle, attr_handle, pending_attr.cid); + + return 0; +} + +#if MYNEWT_VAL(SHELL_CMD_HELP) +static const struct shell_param authorize_params[] = { + {"conn", "connection handle parameter, usage: =" }, + { "attr", "attribute handle parameter to authorize, usage: ="}, + { "auth", "whether to authorize access, usage: =[0-1], default=1" }, + { NULL, NULL } +}; + +static const struct shell_cmd_help authorize_help = { + .summary = "authorize command", + .usage = NULL, + .params = authorize_params, +}; +#endif + /***************************************************************************** * $advertise * *****************************************************************************/ @@ -4374,56 +4439,61 @@ static const struct shell_cmd_help leaudio_broadcast_stop_help = { #endif /* BLE_AUDIO && BLE_ISO_BROADCAST_SOURCE */ static const struct shell_cmd btshell_commands[] = { + { + .sc_cmd = "authorize", + .sc_cmd_func = pending_operation_authorize, + .help = &authorize_help, + }, #if MYNEWT_VAL(BLE_EXT_ADV) { - .sc_cmd = "advertise-configure", - .sc_cmd_func = cmd_advertise_configure, + .sc_cmd = "advertise-configure", + .sc_cmd_func = cmd_advertise_configure, #if MYNEWT_VAL(SHELL_CMD_HELP) - .help = &advertise_configure_help, + .help = &advertise_configure_help, #endif - }, + }, { - .sc_cmd = "advertise-set-addr", - .sc_cmd_func = cmd_advertise_set_addr, + .sc_cmd = "advertise-set-addr", + .sc_cmd_func = cmd_advertise_set_addr, #if MYNEWT_VAL(SHELL_CMD_HELP) - .help = &advertise_set_addr_help, + .help = &advertise_set_addr_help, #endif - }, + }, { - .sc_cmd = "advertise-set-adv-data", - .sc_cmd_func = cmd_set_adv_data, + .sc_cmd = "advertise-set-adv-data", + .sc_cmd_func = cmd_set_adv_data, #if MYNEWT_VAL(SHELL_CMD_HELP) - .help = &set_adv_data_help, + .help = &set_adv_data_help, #endif - }, + }, { - .sc_cmd = "advertise-set-scan-rsp", - .sc_cmd_func = cmd_set_scan_rsp, + .sc_cmd = "advertise-set-scan-rsp", + .sc_cmd_func = cmd_set_scan_rsp, #if MYNEWT_VAL(SHELL_CMD_HELP) - .help = &set_scan_rsp_help, + .help = &set_scan_rsp_help, #endif - }, + }, { - .sc_cmd = "advertise-start", - .sc_cmd_func = cmd_advertise_start, + .sc_cmd = "advertise-start", + .sc_cmd_func = cmd_advertise_start, #if MYNEWT_VAL(SHELL_CMD_HELP) - .help = &advertise_start_help, + .help = &advertise_start_help, #endif - }, + }, { - .sc_cmd = "advertise-stop", - .sc_cmd_func = cmd_advertise_stop, + .sc_cmd = "advertise-stop", + .sc_cmd_func = cmd_advertise_stop, #if MYNEWT_VAL(SHELL_CMD_HELP) - .help = &advertise_stop_help, + .help = &advertise_stop_help, #endif - }, + }, { - .sc_cmd = "advertise-remove", - .sc_cmd_func = cmd_advertise_remove, + .sc_cmd = "advertise-remove", + .sc_cmd_func = cmd_advertise_remove, #if MYNEWT_VAL(SHELL_CMD_HELP) - .help = &advertise_remove_help, + .help = &advertise_remove_help, #endif - }, + }, #else { .sc_cmd = "advertise", @@ -4434,635 +4504,635 @@ static const struct shell_cmd btshell_commands[] = { }, #endif { - .sc_cmd = "connect", - .sc_cmd_func = cmd_connect, + .sc_cmd = "connect", + .sc_cmd_func = cmd_connect, #if MYNEWT_VAL(SHELL_CMD_HELP) - .help = &connect_help, + .help = &connect_help, #endif - }, + }, { - .sc_cmd = "disconnect", - .sc_cmd_func = cmd_disconnect, + .sc_cmd = "disconnect", + .sc_cmd_func = cmd_disconnect, #if MYNEWT_VAL(SHELL_CMD_HELP) - .help = &disconnect_help, + .help = &disconnect_help, #endif - }, + }, { - .sc_cmd = "show-addr", - .sc_cmd_func = cmd_show_addr, + .sc_cmd = "show-addr", + .sc_cmd_func = cmd_show_addr, #if MYNEWT_VAL(SHELL_CMD_HELP) - .help = &gatt_show_addr_help, + .help = &gatt_show_addr_help, #endif - }, + }, { - .sc_cmd = "show-conn", - .sc_cmd_func = cmd_show_conn, + .sc_cmd = "show-conn", + .sc_cmd_func = cmd_show_conn, #if MYNEWT_VAL(SHELL_CMD_HELP) - .help = &gatt_show_conn_help, + .help = &gatt_show_conn_help, #endif - }, + }, { - .sc_cmd = "set-scan-opts", - .sc_cmd_func = cmd_set_scan_opts, + .sc_cmd = "set-scan-opts", + .sc_cmd_func = cmd_set_scan_opts, #if MYNEWT_VAL(SHELL_CMD_HELP) - .help = &set_scan_opts_help, + .help = &set_scan_opts_help, #endif - }, + }, { - .sc_cmd = "scan", - .sc_cmd_func = cmd_scan, + .sc_cmd = "scan", + .sc_cmd_func = cmd_scan, #if MYNEWT_VAL(SHELL_CMD_HELP) - .help = &scan_help, + .help = &scan_help, #endif - }, + }, { - .sc_cmd = "set", - .sc_cmd_func = cmd_set, + .sc_cmd = "set", + .sc_cmd_func = cmd_set, #if MYNEWT_VAL(SHELL_CMD_HELP) - .help = &set_help, + .help = &set_help, #endif - }, + }, #if !MYNEWT_VAL(BLE_EXT_ADV) { - .sc_cmd = "set-adv-data", - .sc_cmd_func = cmd_set_adv_data, + .sc_cmd = "set-adv-data", + .sc_cmd_func = cmd_set_adv_data, #if MYNEWT_VAL(SHELL_CMD_HELP) - .help = &set_adv_data_help, + .help = &set_adv_data_help, #endif - }, + }, { - .sc_cmd = "set-scan-rsp", - .sc_cmd_func = cmd_set_scan_rsp, + .sc_cmd = "set-scan-rsp", + .sc_cmd_func = cmd_set_scan_rsp, #if MYNEWT_VAL(SHELL_CMD_HELP) - .help = &set_scan_rsp_help, + .help = &set_scan_rsp_help, #endif - }, + }, #endif { - .sc_cmd = "set-priv-mode", - .sc_cmd_func = cmd_set_priv_mode, + .sc_cmd = "set-priv-mode", + .sc_cmd_func = cmd_set_priv_mode, #if MYNEWT_VAL(SHELL_CMD_HELP) - .help = &set_priv_mode_help, + .help = &set_priv_mode_help, #endif - }, + }, { - .sc_cmd = "white-list", - .sc_cmd_func = cmd_white_list, + .sc_cmd = "white-list", + .sc_cmd_func = cmd_white_list, #if MYNEWT_VAL(SHELL_CMD_HELP) - .help = &white_list_help, + .help = &white_list_help, #endif - }, + }, { - .sc_cmd = "conn-rssi", - .sc_cmd_func = cmd_conn_rssi, + .sc_cmd = "conn-rssi", + .sc_cmd_func = cmd_conn_rssi, #if MYNEWT_VAL(SHELL_CMD_HELP) - .help = &conn_rssi_help, + .help = &conn_rssi_help, #endif - }, + }, { - .sc_cmd = "conn-update-params", - .sc_cmd_func = cmd_conn_update_params, + .sc_cmd = "conn-update-params", + .sc_cmd_func = cmd_conn_update_params, #if MYNEWT_VAL(SHELL_CMD_HELP) - .help = &conn_update_params_help, + .help = &conn_update_params_help, #endif - }, + }, { - .sc_cmd = "conn-datalen", - .sc_cmd_func = cmd_conn_datalen, + .sc_cmd = "conn-datalen", + .sc_cmd_func = cmd_conn_datalen, #if MYNEWT_VAL(SHELL_CMD_HELP) - .help = &conn_datalen_help, + .help = &conn_datalen_help, #endif - }, + }, { - .sc_cmd = "gatt-discover-characteristic", - .sc_cmd_func = cmd_gatt_discover_characteristic, + .sc_cmd = "gatt-discover-characteristic", + .sc_cmd_func = cmd_gatt_discover_characteristic, #if MYNEWT_VAL(SHELL_CMD_HELP) - .help = &gatt_discover_characteristic_help, + .help = &gatt_discover_characteristic_help, #endif - }, + }, { - .sc_cmd = "gatt-discover-descriptor", - .sc_cmd_func = cmd_gatt_discover_descriptor, + .sc_cmd = "gatt-discover-descriptor", + .sc_cmd_func = cmd_gatt_discover_descriptor, #if MYNEWT_VAL(SHELL_CMD_HELP) - .help = &gatt_discover_descriptor_help, + .help = &gatt_discover_descriptor_help, #endif - }, + }, { - .sc_cmd = "gatt-discover-service", - .sc_cmd_func = cmd_gatt_discover_service, + .sc_cmd = "gatt-discover-service", + .sc_cmd_func = cmd_gatt_discover_service, #if MYNEWT_VAL(SHELL_CMD_HELP) - .help = &gatt_discover_service_help, + .help = &gatt_discover_service_help, #endif - }, + }, { - .sc_cmd = "gatt-discover-full", - .sc_cmd_func = cmd_gatt_discover_full, + .sc_cmd = "gatt-discover-full", + .sc_cmd_func = cmd_gatt_discover_full, #if MYNEWT_VAL(SHELL_CMD_HELP) - .help = &gatt_discover_full_help, + .help = &gatt_discover_full_help, #endif - }, + }, { - .sc_cmd = "gatt-find-included-services", - .sc_cmd_func = cmd_gatt_find_included_services, + .sc_cmd = "gatt-find-included-services", + .sc_cmd_func = cmd_gatt_find_included_services, #if MYNEWT_VAL(SHELL_CMD_HELP) - .help = &gatt_find_included_services_help, + .help = &gatt_find_included_services_help, #endif - }, + }, { - .sc_cmd = "gatt-exchange-mtu", - .sc_cmd_func = cmd_gatt_exchange_mtu, + .sc_cmd = "gatt-exchange-mtu", + .sc_cmd_func = cmd_gatt_exchange_mtu, #if MYNEWT_VAL(SHELL_CMD_HELP) - .help = &gatt_exchange_mtu_help, + .help = &gatt_exchange_mtu_help, #endif - }, + }, { - .sc_cmd = "gatt-read", - .sc_cmd_func = cmd_gatt_read, + .sc_cmd = "gatt-read", + .sc_cmd_func = cmd_gatt_read, #if MYNEWT_VAL(SHELL_CMD_HELP) - .help = &gatt_read_help, + .help = &gatt_read_help, #endif - }, + }, { - .sc_cmd = "gatt-notify", - .sc_cmd_func = cmd_gatt_notify, + .sc_cmd = "gatt-notify", + .sc_cmd_func = cmd_gatt_notify, #if MYNEWT_VAL(SHELL_CMD_HELP) - .help = &gatt_notify_help, + .help = &gatt_notify_help, #endif - }, + }, { - .sc_cmd = "gatt-service-changed", - .sc_cmd_func = cmd_gatt_service_changed, + .sc_cmd = "gatt-service-changed", + .sc_cmd_func = cmd_gatt_service_changed, #if MYNEWT_VAL(SHELL_CMD_HELP) - .help = &gatt_service_changed_help, + .help = &gatt_service_changed_help, #endif - }, + }, { - .sc_cmd = "gatt-service-visibility", - .sc_cmd_func = cmd_gatt_service_visibility, + .sc_cmd = "gatt-service-visibility", + .sc_cmd_func = cmd_gatt_service_visibility, #if MYNEWT_VAL(SHELL_CMD_HELP) - .help = &gatt_service_visibility_help, + .help = &gatt_service_visibility_help, #endif - }, + }, { - .sc_cmd = "gatt-show", - .sc_cmd_func = cmd_gatt_show, + .sc_cmd = "gatt-show", + .sc_cmd_func = cmd_gatt_show, #if MYNEWT_VAL(SHELL_CMD_HELP) - .help = &gatt_show_help, + .help = &gatt_show_help, #endif - }, + }, { - .sc_cmd = "gatt-show-local", - .sc_cmd_func = cmd_gatt_show_local, + .sc_cmd = "gatt-show-local", + .sc_cmd_func = cmd_gatt_show_local, #if MYNEWT_VAL(SHELL_CMD_HELP) - .help = &gatt_show_local_help, + .help = &gatt_show_local_help, #endif - }, + }, { - .sc_cmd = "gatt-write", - .sc_cmd_func = cmd_gatt_write, + .sc_cmd = "gatt-write", + .sc_cmd_func = cmd_gatt_write, #if MYNEWT_VAL(SHELL_CMD_HELP) - .help = &gatt_write_help, + .help = &gatt_write_help, #endif - }, + }, { - .sc_cmd = "gatt-enqueue-notif", - .sc_cmd_func = cmd_gatt_enqueue_notif, + .sc_cmd = "gatt-enqueue-notif", + .sc_cmd_func = cmd_gatt_enqueue_notif, #if MYNEWT_VAL(SHELL_CMD_HELP) - .help = &gatt_enqueue_notif_help, + .help = &gatt_enqueue_notif_help, #endif - }, + }, { - .sc_cmd = "gatt-send-queued-notif", - .sc_cmd_func = cmd_gatt_send_pending_notif, + .sc_cmd = "gatt-send-queued-notif", + .sc_cmd_func = cmd_gatt_send_pending_notif, #if MYNEWT_VAL(SHELL_CMD_HELP) - .help = &gatt_send_pending_notif_help, + .help = &gatt_send_pending_notif_help, #endif - }, + }, { - .sc_cmd = "gatt-clear-queued-notif", - .sc_cmd_func = cmd_gatt_clear_pending_notif, + .sc_cmd = "gatt-clear-queued-notif", + .sc_cmd_func = cmd_gatt_clear_pending_notif, #if MYNEWT_VAL(SHELL_CMD_HELP) - .help = &gatt_clear_pending_notif_help, + .help = &gatt_clear_pending_notif_help, #endif - }, + }, #if MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM) { - .sc_cmd = "l2cap-update", - .sc_cmd_func = cmd_l2cap_update, + .sc_cmd = "l2cap-update", + .sc_cmd_func = cmd_l2cap_update, #if MYNEWT_VAL(SHELL_CMD_HELP) - .help = &l2cap_update_help, + .help = &l2cap_update_help, #endif - }, + }, { - .sc_cmd = "l2cap-create-server", - .sc_cmd_func = cmd_l2cap_create_server, + .sc_cmd = "l2cap-create-server", + .sc_cmd_func = cmd_l2cap_create_server, #if MYNEWT_VAL(SHELL_CMD_HELP) - .help = &l2cap_create_server_help, + .help = &l2cap_create_server_help, #endif - }, + }, { - .sc_cmd = "l2cap-connect", - .sc_cmd_func = cmd_l2cap_connect, + .sc_cmd = "l2cap-connect", + .sc_cmd_func = cmd_l2cap_connect, #if MYNEWT_VAL(SHELL_CMD_HELP) - .help = &l2cap_connect_help, + .help = &l2cap_connect_help, #endif - }, + }, { - .sc_cmd = "l2cap-reconfig", - .sc_cmd_func = cmd_l2cap_reconfig, + .sc_cmd = "l2cap-reconfig", + .sc_cmd_func = cmd_l2cap_reconfig, #if MYNEWT_VAL(SHELL_CMD_HELP) - .help = &l2cap_reconfig_help, + .help = &l2cap_reconfig_help, #endif - }, + }, { - .sc_cmd = "l2cap-disconnect", - .sc_cmd_func = cmd_l2cap_disconnect, + .sc_cmd = "l2cap-disconnect", + .sc_cmd_func = cmd_l2cap_disconnect, #if MYNEWT_VAL(SHELL_CMD_HELP) - .help = &l2cap_disconnect_help, + .help = &l2cap_disconnect_help, #endif - }, + }, { - .sc_cmd = "l2cap-send", - .sc_cmd_func = cmd_l2cap_send, + .sc_cmd = "l2cap-send", + .sc_cmd_func = cmd_l2cap_send, #if MYNEWT_VAL(SHELL_CMD_HELP) - .help = &l2cap_send_help, + .help = &l2cap_send_help, #endif - }, + }, { - .sc_cmd = "l2cap-show-coc", - .sc_cmd_func = cmd_l2cap_show_coc, + .sc_cmd = "l2cap-show-coc", + .sc_cmd_func = cmd_l2cap_show_coc, #if MYNEWT_VAL(SHELL_CMD_HELP) - .help = &l2cap_show_coc_help, + .help = &l2cap_show_coc_help, #endif - }, + }, #endif { - .sc_cmd = "keystore-add", - .sc_cmd_func = cmd_keystore_add, + .sc_cmd = "keystore-add", + .sc_cmd_func = cmd_keystore_add, #if MYNEWT_VAL(SHELL_CMD_HELP) - .help = &keystore_add_help, + .help = &keystore_add_help, #endif - }, + }, { - .sc_cmd = "keystore-del", - .sc_cmd_func = cmd_keystore_del, + .sc_cmd = "keystore-del", + .sc_cmd_func = cmd_keystore_del, #if MYNEWT_VAL(SHELL_CMD_HELP) - .help = &keystore_del_help, + .help = &keystore_del_help, #endif - }, + }, { - .sc_cmd = "keystore-show", - .sc_cmd_func = cmd_keystore_show, + .sc_cmd = "keystore-show", + .sc_cmd_func = cmd_keystore_show, #if MYNEWT_VAL(SHELL_CMD_HELP) - .help = &keystore_show_help, + .help = &keystore_show_help, #endif - }, + }, #if NIMBLE_BLE_SM { - .sc_cmd = "show-oob-sc", - .sc_cmd_func = cmd_show_oob_sc, + .sc_cmd = "show-oob-sc", + .sc_cmd_func = cmd_show_oob_sc, #if MYNEWT_VAL(SHELL_CMD_HELP) - .help = NULL, + .help = NULL, #endif - }, + }, { - .sc_cmd = "auth-passkey", - .sc_cmd_func = cmd_auth_passkey, + .sc_cmd = "auth-passkey", + .sc_cmd_func = cmd_auth_passkey, #if MYNEWT_VAL(SHELL_CMD_HELP) - .help = &auth_passkey_help, + .help = &auth_passkey_help, #endif - }, + }, { - .sc_cmd = "security-pair", - .sc_cmd_func = cmd_security_pair, + .sc_cmd = "security-pair", + .sc_cmd_func = cmd_security_pair, #if MYNEWT_VAL(SHELL_CMD_HELP) - .help = &security_pair_help, + .help = &security_pair_help, #endif - }, + }, { - .sc_cmd = "security-unpair", - .sc_cmd_func = cmd_security_unpair, + .sc_cmd = "security-unpair", + .sc_cmd_func = cmd_security_unpair, #if MYNEWT_VAL(SHELL_CMD_HELP) - .help = &security_unpair_help, + .help = &security_unpair_help, #endif - }, + }, { - .sc_cmd = "security-start", - .sc_cmd_func = cmd_security_start, + .sc_cmd = "security-start", + .sc_cmd_func = cmd_security_start, #if MYNEWT_VAL(SHELL_CMD_HELP) - .help = &security_start_help, + .help = &security_start_help, #endif - }, + }, { - .sc_cmd = "security-encryption", - .sc_cmd_func = cmd_security_encryption, + .sc_cmd = "security-encryption", + .sc_cmd_func = cmd_security_encryption, #if MYNEWT_VAL(SHELL_CMD_HELP) - .help = &security_encryption_help, + .help = &security_encryption_help, #endif - }, + }, { - .sc_cmd = "security-set-data", - .sc_cmd_func = cmd_security_set_data, + .sc_cmd = "security-set-data", + .sc_cmd_func = cmd_security_set_data, #if MYNEWT_VAL(SHELL_CMD_HELP) - .help = &security_set_data_help, + .help = &security_set_data_help, #endif - }, + }, #endif { - .sc_cmd = "test-tx", - .sc_cmd_func = cmd_test_tx, + .sc_cmd = "test-tx", + .sc_cmd_func = cmd_test_tx, #if MYNEWT_VAL(SHELL_CMD_HELP) - .help = &test_tx_help, + .help = &test_tx_help, #endif - }, + }, { - .sc_cmd = "phy-set", - .sc_cmd_func = cmd_phy_set, + .sc_cmd = "phy-set", + .sc_cmd_func = cmd_phy_set, #if MYNEWT_VAL(SHELL_CMD_HELP) - .help = &phy_set_help, + .help = &phy_set_help, #endif - }, + }, { - .sc_cmd = "phy-set-default", - .sc_cmd_func = cmd_phy_set_default, + .sc_cmd = "phy-set-default", + .sc_cmd_func = cmd_phy_set_default, #if MYNEWT_VAL(SHELL_CMD_HELP) - .help = &phy_set_default_help, + .help = &phy_set_default_help, #endif - }, + }, { - .sc_cmd = "phy-read", - .sc_cmd_func = cmd_phy_read, + .sc_cmd = "phy-read", + .sc_cmd_func = cmd_phy_read, #if MYNEWT_VAL(SHELL_CMD_HELP) - .help = &phy_read_help, + .help = &phy_read_help, #endif - }, + }, { - .sc_cmd = "host-enable", - .sc_cmd_func = cmd_host_enable, + .sc_cmd = "host-enable", + .sc_cmd_func = cmd_host_enable, #if MYNEWT_VAL(SHELL_CMD_HELP) - .help = &host_enable_help, + .help = &host_enable_help, #endif - }, + }, { - .sc_cmd = "host-disable", - .sc_cmd_func = cmd_host_disable, + .sc_cmd = "host-disable", + .sc_cmd_func = cmd_host_disable, #if MYNEWT_VAL(SHELL_CMD_HELP) - .help = &host_disable_help, + .help = &host_disable_help, #endif - }, + }, #if MYNEWT_VAL(BLE_PERIODIC_ADV) { - .sc_cmd = "periodic-configure", - .sc_cmd_func = cmd_periodic_configure, + .sc_cmd = "periodic-configure", + .sc_cmd_func = cmd_periodic_configure, #if MYNEWT_VAL(SHELL_CMD_HELP) - .help = &periodic_configure_help, + .help = &periodic_configure_help, #endif - }, + }, { - .sc_cmd = "periodic-set-adv-data", - .sc_cmd_func = cmd_periodic_set_adv_data, + .sc_cmd = "periodic-set-adv-data", + .sc_cmd_func = cmd_periodic_set_adv_data, #if MYNEWT_VAL(SHELL_CMD_HELP) - .help = &set_adv_data_help, + .help = &set_adv_data_help, #endif - }, + }, { - .sc_cmd = "periodic-start", - .sc_cmd_func = cmd_periodic_start, + .sc_cmd = "periodic-start", + .sc_cmd_func = cmd_periodic_start, #if MYNEWT_VAL(SHELL_CMD_HELP) - .help = &periodic_start_help, + .help = &periodic_start_help, #endif - }, + }, { - .sc_cmd = "periodic-stop", - .sc_cmd_func = cmd_periodic_stop, + .sc_cmd = "periodic-stop", + .sc_cmd_func = cmd_periodic_stop, #if MYNEWT_VAL(SHELL_CMD_HELP) - .help = &periodic_stop_help, + .help = &periodic_stop_help, #endif - }, + }, { - .sc_cmd = "sync-create", - .sc_cmd_func = cmd_sync_create, + .sc_cmd = "sync-create", + .sc_cmd_func = cmd_sync_create, #if MYNEWT_VAL(SHELL_CMD_HELP) - .help = &sync_create_help, + .help = &sync_create_help, #endif - }, + }, { - .sc_cmd = "sync-terminate", - .sc_cmd_func = cmd_sync_terminate, + .sc_cmd = "sync-terminate", + .sc_cmd_func = cmd_sync_terminate, #if MYNEWT_VAL(SHELL_CMD_HELP) - .help = &sync_terminate_help, + .help = &sync_terminate_help, #endif - }, + }, { - .sc_cmd = "sync-stats", - .sc_cmd_func = cmd_sync_stats, + .sc_cmd = "sync-stats", + .sc_cmd_func = cmd_sync_stats, #if MYNEWT_VAL(SHELL_CMD_HELP) - .help = &sync_stats_help, + .help = &sync_stats_help, #endif - }, + }, #if MYNEWT_VAL(BLE_PERIODIC_ADV_SYNC_TRANSFER) { - .sc_cmd = "sync-transfer", - .sc_cmd_func = cmd_sync_transfer, + .sc_cmd = "sync-transfer", + .sc_cmd_func = cmd_sync_transfer, #if MYNEWT_VAL(SHELL_CMD_HELP) - .help = &sync_transfer_help, + .help = &sync_transfer_help, #endif - }, + }, { - .sc_cmd = "sync-transfer-set-info", - .sc_cmd_func = cmd_sync_transfer_set_info, + .sc_cmd = "sync-transfer-set-info", + .sc_cmd_func = cmd_sync_transfer_set_info, #if MYNEWT_VAL(SHELL_CMD_HELP) - .help = &sync_transfer_set_info_help, + .help = &sync_transfer_set_info_help, #endif - }, + }, { - .sc_cmd = "sync-transfer-receive", - .sc_cmd_func = cmd_sync_transfer_receive, + .sc_cmd = "sync-transfer-receive", + .sc_cmd_func = cmd_sync_transfer_receive, #if MYNEWT_VAL(SHELL_CMD_HELP) - .help = &sync_transfer_receive_help, + .help = &sync_transfer_receive_help, #endif - }, + }, { - .sc_cmd = "sync-reporting", - .sc_cmd_func = cmd_sync_reporting, + .sc_cmd = "sync-reporting", + .sc_cmd_func = cmd_sync_reporting, #if MYNEWT_VAL(SHELL_CMD_HELP) - .help = &sync_reporting_help, + .help = &sync_reporting_help, #endif - }, + }, #endif #endif #if MYNEWT_VAL(BLE_AUDIO) && MYNEWT_VAL(BLE_ISO_BROADCAST_SOURCE) { - .sc_cmd = "base_add", - .sc_cmd_func = cmd_leaudio_base_add, + .sc_cmd = "base_add", + .sc_cmd_func = cmd_leaudio_base_add, #if MYNEWT_VAL(SHELL_CMD_HELP) - .help = &leaudio_base_add_help, + .help = &leaudio_base_add_help, #endif - }, + }, { - .sc_cmd = "big_sub_add", - .sc_cmd_func = cmd_leaudio_big_sub_add, + .sc_cmd = "big_sub_add", + .sc_cmd_func = cmd_leaudio_big_sub_add, #if MYNEWT_VAL(SHELL_CMD_HELP) - .help = &leaudio_big_sub_add_help, + .help = &leaudio_big_sub_add_help, #endif - }, + }, { - .sc_cmd = "bis_add", - .sc_cmd_func = cmd_leaudio_bis_add, + .sc_cmd = "bis_add", + .sc_cmd_func = cmd_leaudio_bis_add, #if MYNEWT_VAL(SHELL_CMD_HELP) - .help = &leaudio_bis_add_help, + .help = &leaudio_bis_add_help, #endif - }, + }, { - .sc_cmd = "broadcast_create", - .sc_cmd_func = cmd_leaudio_broadcast_create, + .sc_cmd = "broadcast_create", + .sc_cmd_func = cmd_leaudio_broadcast_create, #if MYNEWT_VAL(SHELL_CMD_HELP) - .help = &leaudio_broadcast_create_help, + .help = &leaudio_broadcast_create_help, #endif - }, + }, { - .sc_cmd = "broadcast_destroy", - .sc_cmd_func = cmd_leaudio_broadcast_destroy, + .sc_cmd = "broadcast_destroy", + .sc_cmd_func = cmd_leaudio_broadcast_destroy, #if MYNEWT_VAL(SHELL_CMD_HELP) - .help = &leaudio_broadcast_destroy_help, + .help = &leaudio_broadcast_destroy_help, #endif - }, + }, { - .sc_cmd = "broadcast_update", - .sc_cmd_func = cmd_leaudio_broadcast_update, + .sc_cmd = "broadcast_update", + .sc_cmd_func = cmd_leaudio_broadcast_update, #if MYNEWT_VAL(SHELL_CMD_HELP) - .help = &leaudio_broadcast_update_help, + .help = &leaudio_broadcast_update_help, #endif - }, + }, { - .sc_cmd = "broadcast_start", - .sc_cmd_func = cmd_leaudio_broadcast_start, + .sc_cmd = "broadcast_start", + .sc_cmd_func = cmd_leaudio_broadcast_start, #if MYNEWT_VAL(SHELL_CMD_HELP) - .help = &leaudio_broadcast_start_help, + .help = &leaudio_broadcast_start_help, #endif - }, + }, { - .sc_cmd = "broadcast_stop", - .sc_cmd_func = cmd_leaudio_broadcast_stop, + .sc_cmd = "broadcast_stop", + .sc_cmd_func = cmd_leaudio_broadcast_stop, #if MYNEWT_VAL(SHELL_CMD_HELP) - .help = &leaudio_broadcast_stop_help, + .help = &leaudio_broadcast_stop_help, #endif - }, + }, #endif /* BLE_AUDIO && BLE_ISO_BROADCAST_SOURCE */ #if MYNEWT_VAL(BLE_AUDIO_BROADCAST_SINK) { - .sc_cmd = "broadcast-sink-start", - .sc_cmd_func = cmd_leaudio_broadcast_sink_start, + .sc_cmd = "broadcast-sink-start", + .sc_cmd_func = cmd_leaudio_broadcast_sink_start, #if MYNEWT_VAL(SHELL_CMD_HELP) - .help = &cmd_leaudio_broadcast_sink_start_help, + .help = &cmd_leaudio_broadcast_sink_start_help, #endif - }, + }, { - .sc_cmd = "broadcast-sink-stop", - .sc_cmd_func = cmd_leaudio_broadcast_sink_stop, + .sc_cmd = "broadcast-sink-stop", + .sc_cmd_func = cmd_leaudio_broadcast_sink_stop, #if MYNEWT_VAL(SHELL_CMD_HELP) - .help = &cmd_leaudio_broadcast_sink_stop_help, + .help = &cmd_leaudio_broadcast_sink_stop_help, #endif - }, + }, { - .sc_cmd = "broadcast-sink-metadata", - .sc_cmd_func = cmd_leaudio_broadcast_sink_metadata_update, + .sc_cmd = "broadcast-sink-metadata", + .sc_cmd_func = cmd_leaudio_broadcast_sink_metadata_update, #if MYNEWT_VAL(SHELL_CMD_HELP) - .help = &cmd_leaudio_broadcast_sink_metadata_update_help, + .help = &cmd_leaudio_broadcast_sink_metadata_update_help, #endif - }, + }, { - .sc_cmd = "broadcast-sink-set-sync-params", - .sc_cmd_func = cmd_leaudio_broadcast_sink_sync_params_set, + .sc_cmd = "broadcast-sink-set-sync-params", + .sc_cmd_func = cmd_leaudio_broadcast_sink_sync_params_set, #if MYNEWT_VAL(SHELL_CMD_HELP) - .help = &cmd_leaudio_broadcast_sink_sync_params_set_help, + .help = &cmd_leaudio_broadcast_sink_sync_params_set_help, #endif - }, + }, #endif /* BLE_AUDIO_BROADCAST_SINK */ #if MYNEWT_VAL(BLE_AUDIO_SCAN_DELEGATOR) { - .sc_cmd = "scan-delegator-add", - .sc_cmd_func = cmd_leaudio_scan_delegator_receive_state_add, + .sc_cmd = "scan-delegator-add", + .sc_cmd_func = cmd_leaudio_scan_delegator_receive_state_add, #if MYNEWT_VAL(SHELL_CMD_HELP) - .help = &cmd_leaudio_scan_delegator_receive_state_add_help, + .help = &cmd_leaudio_scan_delegator_receive_state_add_help, #endif - }, + }, { - .sc_cmd = "scan-delegator-remove", - .sc_cmd_func = cmd_leaudio_scan_delegator_receive_state_remove, + .sc_cmd = "scan-delegator-remove", + .sc_cmd_func = cmd_leaudio_scan_delegator_receive_state_remove, #if MYNEWT_VAL(SHELL_CMD_HELP) - .help = &cmd_leaudio_scan_delegator_receive_state_remove_help, + .help = &cmd_leaudio_scan_delegator_receive_state_remove_help, #endif - }, + }, { - .sc_cmd = "scan-delegator-set", - .sc_cmd_func = cmd_leaudio_scan_delegator_receive_state_set, + .sc_cmd = "scan-delegator-set", + .sc_cmd_func = cmd_leaudio_scan_delegator_receive_state_set, #if MYNEWT_VAL(SHELL_CMD_HELP) - .help = &cmd_leaudio_scan_delegator_receive_state_set_help, + .help = &cmd_leaudio_scan_delegator_receive_state_set_help, #endif - }, + }, { - .sc_cmd = "scan-delegator-get", - .sc_cmd_func = cmd_leaudio_scan_delegator_receive_state_get, + .sc_cmd = "scan-delegator-get", + .sc_cmd_func = cmd_leaudio_scan_delegator_receive_state_get, #if MYNEWT_VAL(SHELL_CMD_HELP) - .help = &cmd_leaudio_scan_delegator_receive_state_get_help, + .help = &cmd_leaudio_scan_delegator_receive_state_get_help, #endif - }, + }, { - .sc_cmd = "scan-delegator-show", - .sc_cmd_func = cmd_leaudio_scan_delegator_receive_state_show, + .sc_cmd = "scan-delegator-show", + .sc_cmd_func = cmd_leaudio_scan_delegator_receive_state_show, #if MYNEWT_VAL(SHELL_CMD_HELP) - .help = &cmd_leaudio_scan_delegator_receive_state_show_help, + .help = &cmd_leaudio_scan_delegator_receive_state_show_help, #endif - }, + }, #endif /* BLE_AUDIO_SCAN_DELEGATOR */ #if MYNEWT_VAL(BLE_ISO) #if MYNEWT_VAL(BLE_ISO_BROADCAST_SOURCE) { - .sc_cmd = "big-create", - .sc_cmd_func = cmd_iso_big_create, + .sc_cmd = "big-create", + .sc_cmd_func = cmd_iso_big_create, #if MYNEWT_VAL(SHELL_CMD_HELP) - .help = &cmd_iso_big_create_help, + .help = &cmd_iso_big_create_help, #endif - }, + }, { - .sc_cmd = "big-terminate", - .sc_cmd_func = cmd_iso_big_terminate, + .sc_cmd = "big-terminate", + .sc_cmd_func = cmd_iso_big_terminate, #if MYNEWT_VAL(SHELL_CMD_HELP) - .help = &cmd_iso_big_terminate_help, + .help = &cmd_iso_big_terminate_help, #endif - }, + }, #endif /* BLE_ISO_BROADCAST_SOURCE */ #if MYNEWT_VAL(BLE_ISO_BROADCAST_SINK) { - .sc_cmd = "big-sync-create", - .sc_cmd_func = cmd_iso_big_sync_create, + .sc_cmd = "big-sync-create", + .sc_cmd_func = cmd_iso_big_sync_create, #if MYNEWT_VAL(SHELL_CMD_HELP) - .help = &cmd_iso_big_sync_create_help, + .help = &cmd_iso_big_sync_create_help, #endif - }, + }, { - .sc_cmd = "big-sync-terminate", - .sc_cmd_func = cmd_iso_big_sync_terminate, + .sc_cmd = "big-sync-terminate", + .sc_cmd_func = cmd_iso_big_sync_terminate, #if MYNEWT_VAL(SHELL_CMD_HELP) - .help = &cmd_iso_big_sync_terminate_help, + .help = &cmd_iso_big_sync_terminate_help, #endif - }, + }, #endif /* BLE_ISO_BROADCAST_SINK */ { - .sc_cmd = "iso-data-path-setup", - .sc_cmd_func = cmd_iso_data_path_setup, + .sc_cmd = "iso-data-path-setup", + .sc_cmd_func = cmd_iso_data_path_setup, #if MYNEWT_VAL(SHELL_CMD_HELP) - .help = &cmd_iso_data_path_setup_help, + .help = &cmd_iso_data_path_setup_help, #endif - }, + }, { - .sc_cmd = "iso-data-path-remove", - .sc_cmd_func = cmd_iso_data_path_remove, + .sc_cmd = "iso-data-path-remove", + .sc_cmd_func = cmd_iso_data_path_remove, #if MYNEWT_VAL(SHELL_CMD_HELP) - .help = &cmd_iso_data_path_remove_help, + .help = &cmd_iso_data_path_remove_help, #endif - }, + }, #endif /* BLE_ISO */ { 0 }, }; diff --git a/apps/btshell/src/gatt_svr.c b/apps/btshell/src/gatt_svr.c index dc025ca143..41affa65ce 100644 --- a/apps/btshell/src/gatt_svr.c +++ b/apps/btshell/src/gatt_svr.c @@ -46,6 +46,7 @@ #define PTS_DSC_READ_WRITE 0x000b #define PTS_DSC_READ_WRITE_ENC 0x000c #define PTS_DSC_READ_WRITE_AUTHEN 0x000d +#define PTS_CHR_READ_WRITE_AUTHOR 0x000e #define PTS_LONG_SVC 0x0011 #define PTS_LONG_CHR_READ 0x0012 @@ -60,6 +61,7 @@ #define PTS_LONG_DSC_READ_WRITE 0x001b #define PTS_LONG_DSC_READ_WRITE_ENC 0x001c #define PTS_LONG_DSC_READ_WRITE_AUTHEN 0x001d +#define PTS_LONG_CHR_READ_WRITE_AUTHOR 0x0020 #define PTS_INC_SVC 0x001e #define PTS_CHR_READ_WRITE_ALT 0x001f @@ -178,8 +180,14 @@ static const struct ble_gatt_svc_def gatt_svr_svcs[] = { 0, /* No more descriptors in this characteristic. */ } } }, { - 0, /* No more characteristics in this service. */ - } }, + .uuid = PTS_UUID_DECLARE(PTS_CHR_READ_WRITE_AUTHOR), + .access_cb = gatt_svr_access_test, + .flags = BLE_GATT_CHR_F_READ_AUTHOR | BLE_GATT_CHR_F_READ | + BLE_GATT_CHR_F_WRITE_AUTHOR | BLE_GATT_CHR_F_WRITE + }, { + 0, /* No more characteristics in this service. */ + } + }, }, { @@ -206,6 +214,11 @@ static const struct ble_gatt_svc_def gatt_svr_svcs[] = { .uuid = PTS_UUID_DECLARE(PTS_LONG_CHR_READ_WRITE_ALT), .access_cb = gatt_svr_long_access_test, .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_WRITE, + },{ + .uuid = PTS_UUID_DECLARE(PTS_LONG_CHR_READ_WRITE_AUTHOR), + .access_cb = gatt_svr_long_access_test, + .flags = BLE_GATT_CHR_F_READ_AUTHOR | BLE_GATT_CHR_F_READ | + BLE_GATT_CHR_F_WRITE_AUTHOR | BLE_GATT_CHR_F_WRITE }, { .uuid = PTS_UUID_DECLARE(PTS_LONG_CHR_READ_WRITE_ENC), .access_cb = gatt_svr_long_access_test, @@ -427,6 +440,7 @@ gatt_svr_access_test(uint16_t conn_handle, uint16_t attr_handle, case PTS_CHR_READ_WRITE_ENC: case PTS_CHR_READ_WRITE_AUTHEN: case PTS_CHR_READ_WRITE_ALT: + case PTS_CHR_READ_WRITE_AUTHOR: if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) { rc = gatt_svr_chr_write(ctxt->om,0, sizeof gatt_svr_pts_static_val, @@ -531,6 +545,7 @@ gatt_svr_long_access_test(uint16_t conn_handle, uint16_t attr_handle, case PTS_LONG_CHR_READ_WRITE_ENC: case PTS_LONG_CHR_READ_WRITE_AUTHEN: + case PTS_LONG_CHR_READ_WRITE_AUTHOR: if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) { rc = gatt_svr_chr_write(ctxt->om,0, sizeof gatt_svr_pts_static_long_val, diff --git a/apps/btshell/src/main.c b/apps/btshell/src/main.c index 0db012e98c..1a0d4184e9 100644 --- a/apps/btshell/src/main.c +++ b/apps/btshell/src/main.c @@ -135,6 +135,8 @@ int btshell_full_disc_prev_chr_val; struct ble_sm_sc_oob_data oob_data_local; struct ble_sm_sc_oob_data oob_data_remote; +struct auth_attr authorized_attrs[PENDING_ATTR_MAX]; +struct pend_attr pending_attr; #if MYNEWT_VAL(BLE_AUDIO) && MYNEWT_VAL(BLE_ISO_BROADCAST_SOURCE) static struct {struct ble_audio_base *base; uint8_t adv_instance;} @@ -1292,6 +1294,7 @@ btshell_gap_event(struct ble_gap_event *event, void *arg) struct ble_gap_conn_desc desc; int conn_idx; int rc; + int i; #if MYNEWT_VAL(BLE_PERIODIC_ADV) struct psync *psync; #endif @@ -1318,6 +1321,7 @@ btshell_gap_event(struct ble_gap_event *event, void *arg) if (conn_idx != -1) { btshell_conn_delete_idx(conn_idx); } + memset(&authorized_attrs, 0, sizeof(authorized_attrs)); return btshell_restart_adv(event); #if MYNEWT_VAL(BLE_EXT_ADV) @@ -1555,6 +1559,22 @@ btshell_gap_event(struct ble_gap_event *event, void *arg) return 0; #endif #endif + case BLE_GAP_EVENT_AUTHORIZE: + for (i = 0; i < PENDING_ATTR_MAX; i++) { + if (authorized_attrs[i].conn_handle == event->authorize.conn_handle && + authorized_attrs[i].attr_handle == event->authorize.attr_handle) { + console_printf("Access to attribute %d already authorized\n", + event->authorize.attr_handle); + return BLE_GAP_AUTHORIZE_ACCEPT; + } + } + console_printf("Authorize access to attribute: conn_handle=%d," + "access_opcode=%d, cid=%d, attr=%d\n", + event->authorize.conn_handle, event->authorize.access_opcode, + event->authorize.cid, event->authorize.attr_handle); + pending_attr.cid = event->authorize.cid; + pending_attr.attr_handle = event->authorize.attr_handle; + return BLE_GAP_AUTHORIZE_PENDING; default: return 0; } diff --git a/apps/bttester/src/btp_gap.c b/apps/bttester/src/btp_gap.c index 29fb50a103..f9b9e79d5e 100644 --- a/apps/bttester/src/btp_gap.c +++ b/apps/bttester/src/btp_gap.c @@ -1601,6 +1601,9 @@ gap_event_cb(struct ble_gap_event *event, void *arg) subrate_change_received(event); break; #endif + case BLE_GAP_EVENT_AUTHORIZE: + console_printf("Authorize event: conn_handle=%d", event->authorize.conn_handle); + return BLE_GAP_AUTHORIZE_REJECT; default: break; } diff --git a/nimble/host/include/host/ble_gap.h b/nimble/host/include/host/ble_gap.h index 9a1ead0049..0521982f82 100644 --- a/nimble/host/include/host/ble_gap.h +++ b/nimble/host/include/host/ble_gap.h @@ -261,6 +261,9 @@ struct hci_conn_update; /** GAP event: BIG (Broadcast Isochronous Group) information report */ #define BLE_GAP_EVENT_BIGINFO_REPORT 30 +/** GAP event: Authorization request for GATT operations */ +#define BLE_GAP_EVENT_AUTHORIZE 31 + /** @} */ /** @@ -295,6 +298,22 @@ struct hci_conn_update; /** @} */ +/** + * @defgroup GAP Authorize event possible responses. + * @{ + */ + +/** GAP Authorize event response: reject */ +#define BLE_GAP_AUTHORIZE_REJECT 0 + +/** GAP Authorize event response: accept */ +#define BLE_GAP_AUTHORIZE_ACCEPT 1 + +/** GAP Authorize event response: pending */ +#define BLE_GAP_AUTHORIZE_PENDING 2 + +/** @} */ + /** Connection security state */ struct ble_gap_sec_state { /** If connection is encrypted */ @@ -1308,6 +1327,32 @@ struct ble_gap_event { uint8_t length; } unhandled_hci; #endif + + /** + * GATT Authorization Event. Ask the user to authorize a GATT + * read/write operation. + * + * Valid for the following event types: + * o BLE_GAP_EVENT_AUTHORIZE + * + * Valid responses from user: + * o BLE_GAP_AUTHORIZE_ACCEPT + * o BLE_GAP_AUTHORIZE_REJECT + * o BLE_GAP_AUTHORIZE_PENDING + */ + struct { + /* Connection Handle */ + uint16_t conn_handle; + + /* Attribute handle of the attribute being accessed. */ + uint16_t attr_handle; + + /* ATT access opcode. */ + uint8_t access_opcode; + + /* Channel ID on which request has been received */ + uint16_t cid; + } authorize; }; }; diff --git a/nimble/host/include/host/ble_gatt.h b/nimble/host/include/host/ble_gatt.h index aebfc7ef3d..6d242c1c98 100644 --- a/nimble/host/include/host/ble_gatt.h +++ b/nimble/host/include/host/ble_gatt.h @@ -1245,6 +1245,23 @@ int ble_gatts_peer_cl_sup_feat_get(uint16_t conn_handle, uint8_t *out_supported_ int ble_gatts_read_cccd(uint16_t conn_handle, uint16_t chr_val_handle, uint8_t *cccd_value); +/** + * Prepares and sends a response for pending ATT request. + * + * @param conn_handle The connection over which to authorize a + * pending ATT procedure + * @param attr_handle The Handle of characteristic to perform att + * procedure on. + * @param cid L2CAP channel ID on which request has been + * received + * + * @return 0 on success; + * BLE_HS_EAUTHOR if no matching attribute is + * found on pending_attr_list. + */ +int ble_gatts_pending_req_auth(uint16_t conn_handle, uint16_t attr_handle, + uint16_t cid); + #ifdef __cplusplus } #endif diff --git a/nimble/host/include/host/ble_hs.h b/nimble/host/include/host/ble_hs.h index 5079648fad..52c1d6f05c 100644 --- a/nimble/host/include/host/ble_hs.h +++ b/nimble/host/include/host/ble_hs.h @@ -159,6 +159,9 @@ extern "C" { /** Operation stalled. */ #define BLE_HS_ESTALLED 31 +/** Operation pending. */ +#define BLE_HS_EPENDING 32 + /** Error base for ATT errors */ #define BLE_HS_ERR_ATT_BASE 0x100 diff --git a/nimble/host/src/ble_att_priv.h b/nimble/host/src/ble_att_priv.h index 2bc3da361b..82f3ad0fc9 100644 --- a/nimble/host/src/ble_att_priv.h +++ b/nimble/host/src/ble_att_priv.h @@ -125,6 +125,20 @@ struct ble_att_svr_conn { ble_npl_time_t basc_prep_timeout_at; }; +struct pending_attr { + SLIST_ENTRY(pending_attr) next; + uint16_t conn_handle; + uint16_t attr_handle; + uint8_t offset; + struct os_mbuf *om; + uint16_t access_opcode; + uint8_t att_opcode; + uint16_t cid; +}; + +SLIST_HEAD(pending_attr_list_head, pending_attr); +extern struct pending_attr_list_head pending_attr_list; + /** * Handles a host attribute request. * @@ -226,6 +240,30 @@ void ble_att_svr_restore_range(uint16_t start_handle, uint16_t end_handle); int ble_att_svr_tx_error_rsp(uint16_t conn_handle, uint16_t cid, struct os_mbuf *txom, uint8_t req_op, uint16_t handle, uint8_t error_code); +int ble_att_svr_create_read_rsp(uint16_t conn_handle, uint16_t cid, + struct os_mbuf *om, int hs_status, + uint8_t att_op, uint16_t err_handle, + uint16_t offset, uint8_t *out_att_err); +int ble_att_svr_create_write_rsp(uint16_t conn_handle, uint16_t cid, + struct os_mbuf **om, int hs_status, + struct ble_att_write_req *req, uint16_t offset, + uint16_t handle, uint8_t *out_att_err); +int ble_att_svr_create_read_mult_rsp(uint16_t conn_handle, uint16_t cid, + struct os_mbuf **om, int hs_status, + uint8_t *att_err, uint16_t *err_handle); +int ble_att_svr_create_read_mult_var_len_rsp(uint16_t conn_handle, uint16_t cid, + struct os_mbuf **om, int hs_status, + uint8_t *att_err, uint16_t *err_handle); +int ble_att_svr_create_prep_write_rsp(uint16_t conn_handle, uint16_t cid, + struct os_mbuf **om, + struct ble_att_prep_write_cmd *req, int hs_status, + uint8_t att_err, uint16_t err_handle); +int ble_att_svr_check_author_perm(uint16_t conn_handle, uint16_t attr_handle, + uint8_t *att_err, uint16_t access_opcode, + uint16_t cid); +int ble_att_svr_tx_rsp(uint16_t conn_handle, uint16_t cid, int hs_status, + struct os_mbuf *om, uint8_t att_op, uint8_t err_status, + uint16_t err_handle); /*** $clt */ /** An information-data entry in a find information response. */ diff --git a/nimble/host/src/ble_att_svr.c b/nimble/host/src/ble_att_svr.c index 8fdf0e8457..6e6465cf45 100644 --- a/nimble/host/src/ble_att_svr.c +++ b/nimble/host/src/ble_att_svr.c @@ -20,6 +20,7 @@ #include #include #include +#include #include "os/os.h" #include "host/ble_att.h" #include "nimble/ble.h" @@ -81,6 +82,46 @@ ble_att_svr_entry_free(struct ble_att_svr_entry *entry) os_memblock_put(&ble_att_svr_entry_pool, entry); } +struct pending_attr_list_head pending_attr_list = + SLIST_HEAD_INITIALIZER(pending_attr_list); + +static void +pending_att_prepare(uint16_t conn_handle, uint16_t attr_handle, uint8_t offset, + struct os_mbuf *om, uint8_t access_opcode, + uint8_t att_opcode, uint16_t cid) +{ + struct pending_attr *pending; + struct pending_attr *e; + struct pending_attr *last; + + pending = NULL; + + memset(pending, 0, sizeof(*pending)); + + pending->conn_handle = conn_handle; + pending->attr_handle = attr_handle; + pending->offset = offset; + pending->om = om; + pending->access_opcode = access_opcode; + pending->att_opcode = att_opcode; + pending->cid = cid; + + ble_hs_lock(); + if (SLIST_EMPTY(&pending_attr_list)) { + SLIST_INSERT_HEAD(&pending_attr_list, pending, next); + } else { + last = NULL; + /* find last and insert at tail */ + SLIST_FOREACH(e, &pending_attr_list, next) { + if ((SLIST_NEXT(e, next) = NULL)) { + last = e; + SLIST_INSERT_AFTER(last, pending, next); + } + } + } + ble_hs_unlock(); +} + /** * Allocate the next handle id and return it. * @@ -244,6 +285,59 @@ ble_att_svr_get_sec_state(uint16_t conn_handle, ble_hs_unlock(); } +int +ble_att_svr_check_author_perm(uint16_t conn_handle, uint16_t attr_handle, + uint8_t *att_err, uint16_t access_opcode, uint16_t cid) +{ + struct ble_att_svr_entry *entry; + int author; + int rc; + + entry = ble_att_svr_find_by_handle(attr_handle); + if (entry == NULL) { + if (att_err != NULL) { + *att_err = BLE_ATT_ERR_INVALID_HANDLE; + } + return BLE_HS_ENOENT; + } + + if (access_opcode == BLE_ATT_ACCESS_OP_READ) { + if (!(entry->ha_flags & BLE_ATT_F_READ)) { + *att_err = BLE_ATT_ERR_READ_NOT_PERMITTED; + return BLE_HS_EREJECT; + } + + author = entry->ha_flags & BLE_ATT_F_READ_AUTHOR; + } else { + if (!(entry->ha_flags & BLE_ATT_F_WRITE)) { + *att_err = BLE_ATT_ERR_WRITE_NOT_PERMITTED; + return BLE_HS_EREJECT; + } + + author = entry->ha_flags & BLE_ATT_F_WRITE_AUTHOR; + } + + if (!author) { + return 0; + } + + rc = ble_gap_authorize_event(conn_handle, attr_handle, access_opcode, cid); + + switch (rc) { + case BLE_GAP_AUTHORIZE_ACCEPT: + return 0; + + case BLE_GAP_AUTHORIZE_REJECT: + *att_err = BLE_ATT_ERR_INSUFFICIENT_AUTHOR; + return BLE_HS_ATT_ERR(*att_err); + + case BLE_GAP_AUTHORIZE_PENDING: + return BLE_HS_EPENDING; + } + + return rc; +} + static int ble_att_svr_check_perms(uint16_t conn_handle, int is_read, struct ble_att_svr_entry *entry, @@ -254,7 +348,6 @@ ble_att_svr_check_perms(uint16_t conn_handle, int is_read, struct ble_store_key_sec key_sec; struct ble_hs_conn_addrs addrs; struct ble_hs_conn *conn; - int author; int authen; int enc; int rc; @@ -267,7 +360,6 @@ ble_att_svr_check_perms(uint16_t conn_handle, int is_read, enc = entry->ha_flags & BLE_ATT_F_READ_ENC; authen = entry->ha_flags & BLE_ATT_F_READ_AUTHEN; - author = entry->ha_flags & BLE_ATT_F_READ_AUTHOR; } else { if (!(entry->ha_flags & BLE_ATT_F_WRITE)) { *out_att_err = BLE_ATT_ERR_WRITE_NOT_PERMITTED; @@ -276,11 +368,10 @@ ble_att_svr_check_perms(uint16_t conn_handle, int is_read, enc = entry->ha_flags & BLE_ATT_F_WRITE_ENC; authen = entry->ha_flags & BLE_ATT_F_WRITE_AUTHEN; - author = entry->ha_flags & BLE_ATT_F_WRITE_AUTHOR; } /* Bail early if this operation doesn't require security. */ - if (!enc && !authen && !author) { + if (!enc && !authen) { return 0; } @@ -332,10 +423,6 @@ ble_att_svr_check_perms(uint16_t conn_handle, int is_read, return BLE_HS_ATT_ERR(*out_att_err); } - if (author) { - /* XXX: Prompt user for authorization. */ - } - return 0; } @@ -471,6 +558,25 @@ ble_att_svr_read_flat(uint16_t conn_handle, return rc; } +int +ble_att_svr_create_read_rsp(uint16_t conn_handle, uint16_t cid, struct os_mbuf *om, + int hs_status, uint8_t att_op, uint16_t err_handle, + uint16_t offset, uint8_t *out_att_err) +{ + int rc = 0; + + if (hs_status != 0) { + rc = hs_status; + goto done; + } + + rc = ble_att_svr_read_handle(conn_handle, err_handle, offset, om, out_att_err); + +done: + rc = ble_att_svr_tx_rsp(conn_handle, cid, rc, om, att_op, *out_att_err, err_handle); + return rc; +} + int ble_att_svr_read_handle(uint16_t conn_handle, uint16_t attr_handle, uint16_t offset, struct os_mbuf *om, @@ -621,9 +727,10 @@ ble_att_svr_tx_error_rsp(uint16_t conn_handle, uint16_t cid, struct os_mbuf *txo * of the error message's attribute handle * field. */ -static int -ble_att_svr_tx_rsp(uint16_t conn_handle, uint16_t cid, int hs_status, struct os_mbuf *om, - uint8_t att_op, uint8_t err_status, uint16_t err_handle) +int +ble_att_svr_tx_rsp(uint16_t conn_handle, uint16_t cid, int hs_status, + struct os_mbuf *om, uint8_t att_op, uint8_t err_status, + uint16_t err_handle) { struct ble_l2cap_chan *chan; struct ble_hs_conn *conn; @@ -1501,14 +1608,20 @@ ble_att_svr_rx_read(uint16_t conn_handle, uint16_t cid, struct os_mbuf **rxom) goto done; } - rc = ble_att_svr_read_handle(conn_handle, err_handle, 0, txom, &att_err); - if (rc != 0) { - goto done; + rc = ble_att_svr_check_author_perm(conn_handle, err_handle, &att_err, + BLE_ATT_ACCESS_OP_READ, cid); + + if (rc == BLE_HS_EPENDING) { + pending_att_prepare(conn_handle, err_handle, 0, txom, + BLE_ATT_ACCESS_OP_READ, BLE_ATT_OP_READ_REQ, cid); + txom = NULL; + return rc; } done: - rc = ble_att_svr_tx_rsp(conn_handle, cid, rc, txom, BLE_ATT_OP_READ_REQ, - att_err, err_handle); + rc = ble_att_svr_create_read_rsp(conn_handle, cid, txom, rc, + BLE_ATT_OP_READ_REQ, err_handle, 0, &att_err); + return rc; } @@ -1529,6 +1642,7 @@ ble_att_svr_rx_read_blob(uint16_t conn_handle, uint16_t cid, struct os_mbuf **rx txom = NULL; att_err = 0; err_handle = 0; + offset = 0; rc = ble_att_svr_pullup_req_base(rxom, sizeof(*req), &att_err); if (rc != 0) { @@ -1551,8 +1665,16 @@ ble_att_svr_rx_read_blob(uint16_t conn_handle, uint16_t cid, struct os_mbuf **rx goto done; } - rc = ble_att_svr_read_handle(conn_handle, err_handle, offset, - txom, &att_err); + rc = ble_att_svr_check_author_perm(conn_handle, err_handle, &att_err, + BLE_ATT_ACCESS_OP_READ, cid); + + if (rc == BLE_HS_EPENDING) { + pending_att_prepare(conn_handle, err_handle, 0, txom, + BLE_ATT_ACCESS_OP_READ, BLE_ATT_OP_READ_BLOB_REQ, cid); + txom = NULL; + return rc; + } + if (rc != 0) { goto done; } @@ -1560,8 +1682,9 @@ ble_att_svr_rx_read_blob(uint16_t conn_handle, uint16_t cid, struct os_mbuf **rx rc = 0; done: - rc = ble_att_svr_tx_rsp(conn_handle, cid, rc, txom, BLE_ATT_OP_READ_BLOB_REQ, - att_err, err_handle); + rc = ble_att_svr_create_read_rsp(conn_handle, cid, txom, rc, + BLE_ATT_OP_READ_BLOB_REQ, err_handle, + offset, &att_err); return rc; } @@ -1626,6 +1749,35 @@ ble_att_svr_build_read_mult_rsp(uint16_t conn_handle, uint16_t cid, return rc; } +int +ble_att_svr_create_read_mult_rsp(uint16_t conn_handle, uint16_t cid, + struct os_mbuf **om, int hs_status, + uint8_t *att_err, uint16_t *err_handle) +{ + struct os_mbuf *txom; + + int rc = 0; + txom = NULL; + + if (hs_status != 0) { + rc = ble_att_svr_pkt(om, &txom, att_err); + if (rc != 0) { + *err_handle = 0; + goto done; + } + rc = hs_status; + goto done; + } + + rc = ble_att_svr_build_read_mult_rsp(conn_handle, cid, om, &txom, att_err, + err_handle); + +done: + rc = ble_att_svr_tx_rsp(conn_handle, cid, rc, txom, + BLE_ATT_OP_READ_MULT_REQ, *att_err, *err_handle); + return rc; +} + int ble_att_svr_rx_read_mult(uint16_t conn_handle, uint16_t cid, struct os_mbuf **rxom) { @@ -1633,21 +1785,42 @@ ble_att_svr_rx_read_mult(uint16_t conn_handle, uint16_t cid, struct os_mbuf **rx return BLE_HS_ENOTSUP; #endif - struct os_mbuf *txom; uint16_t err_handle; uint8_t att_err; - int rc; + uint8_t offset; + int rc = 0; /* Initialize some values in case of early error. */ - txom = NULL; err_handle = 0; att_err = 0; + offset = 0; + + /* Iterate through requested handles to check authorization */ + while ((OS_MBUF_PKTLEN(*rxom) - offset) >= 2) { + os_mbuf_copydata(*rxom, offset, 2, &err_handle); + offset += 2; + + rc = ble_att_svr_check_author_perm(conn_handle, err_handle, &att_err, + BLE_ATT_ACCESS_OP_READ, cid); + + if (rc == BLE_HS_EPENDING) { + pending_att_prepare(conn_handle, 0, offset, *rxom, BLE_ATT_ACCESS_OP_READ, + BLE_ATT_OP_READ_MULT_REQ, cid); + /* Always reuse rxom mbuf for response */ + *rxom = NULL; + return rc; + } - rc = ble_att_svr_build_read_mult_rsp(conn_handle, cid, rxom, &txom, &att_err, - &err_handle); + if (rc != 0) { + goto done; + } + } + +done: + rc = ble_att_svr_create_read_mult_rsp(conn_handle, cid, rxom, rc, &att_err, + &err_handle); - return ble_att_svr_tx_rsp(conn_handle, cid, rc, txom, BLE_ATT_OP_READ_MULT_REQ, - att_err, err_handle); + return rc; } static int @@ -1732,6 +1905,31 @@ ble_att_svr_build_read_mult_rsp_var(uint16_t conn_handle, uint16_t cid, return rc; } +int +ble_att_svr_create_read_mult_var_len_rsp(uint16_t conn_handle, uint16_t cid, + struct os_mbuf **om, int hs_status, + uint8_t *att_err, uint16_t *err_handle) +{ + struct os_mbuf *txom; + int rc; + + rc = 0; + txom = NULL; + + if (hs_status != 0) { + rc = hs_status; + goto done; + } + + rc = ble_att_svr_build_read_mult_rsp_var(conn_handle, cid, om, &txom, + att_err, err_handle); + +done: + rc = ble_att_svr_tx_rsp(conn_handle, cid, rc, txom, + BLE_ATT_OP_READ_MULT_VAR_REQ, *att_err, *err_handle); + return rc; +} + int ble_att_svr_rx_read_mult_var(uint16_t conn_handle, uint16_t cid, struct os_mbuf **rxom) { @@ -1739,22 +1937,41 @@ ble_att_svr_rx_read_mult_var(uint16_t conn_handle, uint16_t cid, struct os_mbuf return BLE_HS_ENOTSUP; #endif - struct os_mbuf *txom; uint16_t err_handle; uint8_t att_err; + uint8_t offset; int rc; /* Initialize some values in case of early error. */ - txom = NULL; err_handle = 0; att_err = 0; + offset = 0; + rc = 0; - rc = ble_att_svr_build_read_mult_rsp_var(conn_handle, cid, rxom, &txom, &att_err, - &err_handle); + /* Iterate through requested handles to check authorization */ + while ((OS_MBUF_PKTLEN(*rxom) - offset) >= 2) { + os_mbuf_copydata(*rxom, offset, 2, &err_handle); + offset += 2; + + rc = ble_att_svr_check_author_perm(conn_handle, err_handle, &att_err, + BLE_ATT_ACCESS_OP_READ, cid); + + if (rc == BLE_HS_EPENDING) { + pending_att_prepare(conn_handle, 0, offset, *rxom, BLE_ATT_ACCESS_OP_READ, + BLE_ATT_OP_READ_MULT_REQ, cid); + /* Always reuse rxom mbuf for response */ + *rxom = NULL; + return rc; + } + + if (rc != 0) { + goto done; + } + } - return ble_att_svr_tx_rsp(conn_handle, cid, rc, txom, - BLE_ATT_OP_READ_MULT_VAR_REQ, - att_err, err_handle); +done: + return ble_att_svr_create_read_mult_var_len_rsp(conn_handle, cid, rxom, rc, + &att_err, &err_handle); } static int @@ -2096,6 +2313,47 @@ ble_att_svr_build_write_rsp(struct os_mbuf **rxom, struct os_mbuf **out_txom, return rc; } +int +ble_att_svr_create_write_rsp(uint16_t conn_handle, uint16_t cid, + struct os_mbuf **om, int hs_status, + struct ble_att_write_req *req, uint16_t offset, + uint16_t handle, uint8_t *out_att_err) +{ + struct os_mbuf *txom; + + txom = NULL; + int rc = 0; + + if (hs_status != 0) { + rc = hs_status; + goto done; + } + + /* Allocate the write response. This must be done prior to processing the + * request. See the note at the top of this file for details. + */ + rc = ble_att_svr_build_write_rsp(om, &txom, out_att_err); + if (rc != 0) { + goto done; + } + + /* Strip the request base from the front of the mbuf. */ + os_mbuf_adj(*om, sizeof(*req)); + + rc = ble_att_svr_write_handle(conn_handle, handle, offset, om, out_att_err); + + if (rc != 0) { + goto done; + } + + rc = 0; + +done: + rc = ble_att_svr_tx_rsp(conn_handle, cid, rc, txom, BLE_ATT_OP_WRITE_REQ, + *out_att_err, handle); + return rc; +} + int ble_att_svr_rx_write(uint16_t conn_handle, uint16_t cid, struct os_mbuf **rxom) { @@ -2104,13 +2362,12 @@ ble_att_svr_rx_write(uint16_t conn_handle, uint16_t cid, struct os_mbuf **rxom) #endif struct ble_att_write_req *req; - struct os_mbuf *txom; uint16_t handle; uint8_t att_err; int rc; /* Initialize some values in case of early error. */ - txom = NULL; + req = NULL; att_err = 0; handle = 0; @@ -2123,27 +2380,20 @@ ble_att_svr_rx_write(uint16_t conn_handle, uint16_t cid, struct os_mbuf **rxom) handle = le16toh(req->bawq_handle); - /* Allocate the write response. This must be done prior to processing the - * request. See the note at the top of this file for details. - */ - rc = ble_att_svr_build_write_rsp(rxom, &txom, &att_err); - if (rc != 0) { - goto done; - } - - /* Strip the request base from the front of the mbuf. */ - os_mbuf_adj(*rxom, sizeof(*req)); + rc = ble_att_svr_check_author_perm(conn_handle, handle, &att_err, + BLE_ATT_ACCESS_OP_WRITE, cid); - rc = ble_att_svr_write_handle(conn_handle, handle, 0, rxom, &att_err); - if (rc != 0) { - goto done; + if (rc == BLE_HS_EPENDING) { + pending_att_prepare(conn_handle, handle, 0, *rxom, + BLE_ATT_ACCESS_OP_WRITE, BLE_ATT_OP_WRITE_REQ, cid); + *rxom = NULL; + return rc; } - rc = 0; - done: - rc = ble_att_svr_tx_rsp(conn_handle, cid, rc, txom, BLE_ATT_OP_WRITE_REQ, - att_err, handle); + rc = ble_att_svr_create_write_rsp(conn_handle, cid, rxom, rc, req, 0, + handle, &att_err); + return rc; } @@ -2435,44 +2685,24 @@ ble_att_svr_insert_prep_entry(uint16_t conn_handle, } int -ble_att_svr_rx_prep_write(uint16_t conn_handle, uint16_t cid, struct os_mbuf **rxom) +ble_att_svr_create_prep_write_rsp(uint16_t conn_handle, uint16_t cid, + struct os_mbuf **om, + struct ble_att_prep_write_cmd *req, int hs_status, + uint8_t att_err, uint16_t err_handle) { -#if !MYNEWT_VAL(BLE_ATT_SVR_QUEUED_WRITE) - return BLE_HS_ENOTSUP; -#endif - - struct ble_att_prep_write_cmd *req; struct ble_att_svr_entry *attr_entry; struct os_mbuf *txom; - uint16_t err_handle; - uint8_t att_err; - int rc; - /* Initialize some values in case of early error. */ + int rc = 0; txom = NULL; - att_err = 0; - err_handle = 0; - rc = ble_att_svr_pullup_req_base(rxom, sizeof(*req), &att_err); - if (rc != 0) { + if (hs_status != 0) { + rc = hs_status; goto done; } - req = (struct ble_att_prep_write_cmd *)(*rxom)->om_data; - - err_handle = le16toh(req->bapc_handle); - attr_entry = ble_att_svr_find_by_handle(le16toh(req->bapc_handle)); - /* A prepare write request gets rejected for the following reasons: - * 1. Insufficient authorization. - * 2. Insufficient authentication. - * 3. Insufficient encryption key size (XXX: Not checked). - * 4. Insufficient encryption (XXX: Not checked). - * 5. Invalid handle. - * 6. Write not permitted. - */ - /* <5> */ if (attr_entry == NULL) { rc = BLE_HS_ENOENT; @@ -2480,24 +2710,24 @@ ble_att_svr_rx_prep_write(uint16_t conn_handle, uint16_t cid, struct os_mbuf **r goto done; } - /* <1>, <2>, <4>, <6> */ + /* <2>, <4>, <6> */ rc = ble_att_svr_check_perms(conn_handle, 0, attr_entry, &att_err); + if (rc != 0) { goto done; } ble_hs_lock(); rc = ble_att_svr_insert_prep_entry(conn_handle, le16toh(req->bapc_handle), - le16toh(req->bapc_offset), *rxom, - &att_err); + le16toh(req->bapc_offset), *om, &att_err); ble_hs_unlock(); /* Reuse rxom for response. On success, the response is identical to * request except for op code. On error, the buffer contents will get * cleared before the error gets written. */ - txom = *rxom; - *rxom = NULL; + txom = *om; + *om = NULL; if (rc != 0) { goto done; @@ -2510,8 +2740,62 @@ ble_att_svr_rx_prep_write(uint16_t conn_handle, uint16_t cid, struct os_mbuf **r rc = 0; done: - rc = ble_att_svr_tx_rsp(conn_handle, cid, rc, txom, BLE_ATT_OP_PREP_WRITE_REQ, - att_err, err_handle); + rc = ble_att_svr_tx_rsp(conn_handle, cid, rc, txom, + BLE_ATT_OP_PREP_WRITE_REQ, att_err, err_handle); + + return rc; +} + +int +ble_att_svr_rx_prep_write(uint16_t conn_handle, uint16_t cid, struct os_mbuf **rxom) +{ +#if !MYNEWT_VAL(BLE_ATT_SVR_QUEUED_WRITE) + return BLE_HS_ENOTSUP; +#endif + + struct ble_att_prep_write_cmd *req; + uint16_t err_handle; + uint8_t att_err; + int rc; + + /* Initialize some values in case of early error. */ + req = NULL; + att_err = 0; + err_handle = 0; + + rc = ble_att_svr_pullup_req_base(rxom, sizeof(*req), &att_err); + if (rc != 0) { + goto done; + } + + req = (struct ble_att_prep_write_cmd *)(*rxom)->om_data; + + err_handle = le16toh(req->bapc_handle); + + /* A prepare write request gets rejected for the following reasons: + * 1. Insufficient authorization. + * 2. Insufficient authentication. + * 3. Insufficient encryption key size (XXX: Not checked). + * 4. Insufficient encryption (XXX: Not checked). + * 5. Invalid handle. + * 6. Write not permitted. + */ + + /* <1> */ + rc = ble_att_svr_check_author_perm(conn_handle, err_handle, &att_err, + BLE_ATT_ACCESS_OP_WRITE, cid); + if (rc == BLE_HS_EPENDING) { + pending_att_prepare(conn_handle, err_handle, 0, *rxom, + BLE_ATT_ACCESS_OP_WRITE, BLE_ATT_OP_PREP_WRITE_REQ, cid); + /* Always reuse rxom mbuf for response */ + *rxom = NULL; + return rc; + } + +done: /* <2>, <4>, <6> */ + rc = ble_att_svr_create_prep_write_rsp(conn_handle, cid, rxom, req, rc, + att_err, err_handle); + return rc; } @@ -2943,6 +3227,7 @@ ble_att_svr_init(void) STAILQ_INIT(&ble_att_svr_list); STAILQ_INIT(&ble_att_svr_hidden_list); + SLIST_INIT(&pending_attr_list); ble_att_svr_id = 0; diff --git a/nimble/host/src/ble_gap.c b/nimble/host/src/ble_gap.c index 4928454d4a..6776f6d8d5 100644 --- a/nimble/host/src/ble_gap.c +++ b/nimble/host/src/ble_gap.c @@ -6870,6 +6870,27 @@ ble_gap_unhandled_hci_event(bool is_le_meta, bool is_vs, const void *buf, } #endif +int +ble_gap_authorize_event(uint16_t conn_handle, uint16_t attr_handle, + uint16_t access_opcode, uint16_t cid) +{ +#if MYNEWT_VAL(BLE_ROLE_PERIPHERAL) + struct ble_gap_event event; + int rc; + + memset(&event, 0, sizeof event); + event.type = BLE_GAP_EVENT_AUTHORIZE; + event.authorize.conn_handle = conn_handle; + event.authorize.attr_handle = attr_handle; + event.authorize.access_opcode = access_opcode; + event.authorize.cid = cid; + + rc = ble_gap_call_conn_event_cb(&event, conn_handle); + return rc; +#endif + return BLE_GAP_AUTHORIZE_REJECT; +} + /***************************************************************************** * $preempt * *****************************************************************************/ diff --git a/nimble/host/src/ble_gap_priv.h b/nimble/host/src/ble_gap_priv.h index 2f875ddf0e..5f38dae630 100644 --- a/nimble/host/src/ble_gap_priv.h +++ b/nimble/host/src/ble_gap_priv.h @@ -144,6 +144,8 @@ void ble_gap_pairing_complete_event(uint16_t conn_handle, int status); void ble_gap_unhandled_hci_event(bool is_le_meta, bool is_vs, const void *buf, uint8_t len); int ble_gap_master_in_progress(void); +int ble_gap_authorize_event(uint16_t conn_handle, uint16_t attr_handle, + uint16_t access_opcode, uint16_t cid); void ble_gap_preempt(void); void ble_gap_preempt_done(void); diff --git a/nimble/host/src/ble_gatts.c b/nimble/host/src/ble_gatts.c index 6c3ae19de9..241e1b2c5a 100644 --- a/nimble/host/src/ble_gatts.c +++ b/nimble/host/src/ble_gatts.c @@ -2061,6 +2061,119 @@ ble_gatts_find_dsc(const ble_uuid_t *svc_uuid, const ble_uuid_t *chr_uuid, } } +int +ble_gatts_pending_req_auth(uint16_t conn_handle, uint16_t attr_handle, uint16_t cid) +{ + struct ble_att_prep_write_cmd *prep_req; + struct ble_att_write_req *write_req; + struct pending_attr *pend_attr; + struct pending_attr *attr; + uint8_t att_err; + int rc; + + /* Silence warnings */ + rc = 0; + att_err = 0; + pend_attr = NULL; + + ble_hs_lock(); + SLIST_FOREACH(attr, &pending_attr_list, next) { + if (attr->conn_handle == conn_handle && attr->cid == cid) { + pend_attr = attr; + } + } + ble_hs_unlock(); + + if (!pend_attr) { + /* No matching attribute was found on pending_attr_list */ + return BLE_HS_ENOENT; + } + + if (attr_handle != 0) { + att_err = BLE_ATT_ERR_INSUFFICIENT_AUTHOR; + rc = BLE_HS_EAUTHOR; + ble_att_svr_tx_rsp(conn_handle, cid, rc, pend_attr->om, + pend_attr->att_opcode, att_err, attr_handle); + goto done; + } + + switch (pend_attr->att_opcode) { + case BLE_ATT_OP_READ_REQ: + rc = ble_att_svr_create_read_rsp(conn_handle, cid, pend_attr->om, rc, + BLE_ATT_OP_READ_REQ, pend_attr->attr_handle, + pend_attr->offset, &att_err); + goto done; + + case BLE_ATT_OP_READ_BLOB_REQ: + rc = ble_att_svr_create_read_rsp( + conn_handle, cid, pend_attr->om, rc, BLE_ATT_OP_READ_BLOB_REQ, + pend_attr->attr_handle, pend_attr->offset, &att_err); + goto done; + + case BLE_ATT_OP_WRITE_REQ: + write_req = (struct ble_att_write_req *)(pend_attr)->om->om_data; + rc = ble_att_svr_create_write_rsp(conn_handle, cid, &pend_attr->om, rc, + write_req, pend_attr->offset, + pend_attr->attr_handle, &att_err); + goto done; + + case BLE_ATT_OP_READ_MULT_REQ: + /* iterate through remaining requested handles */ + while ((OS_MBUF_PKTLEN(pend_attr->om) - pend_attr->offset) >= 2) { + os_mbuf_copydata(pend_attr->om, pend_attr->offset, 2, &attr_handle); + pend_attr->offset += 2; + rc = ble_att_svr_check_author_perm(conn_handle, attr_handle, &att_err, + BLE_ATT_ACCESS_OP_WRITE, cid); + if (rc == BLE_HS_EPENDING) { + return rc; + } + if (rc != 0) { + break; + } + } + + rc = ble_att_svr_create_read_mult_rsp(conn_handle, cid, &pend_attr->om, + rc, &att_err, &attr_handle); + goto done; + + case BLE_ATT_OP_READ_MULT_VAR_REQ: + /* iterate through remaining requested handles */ + while ((OS_MBUF_PKTLEN(pend_attr->om) - pend_attr->offset) >= 2) { + os_mbuf_copydata(pend_attr->om, pend_attr->offset, 2, &attr_handle); + pend_attr->offset += 2; + rc = ble_att_svr_check_author_perm(conn_handle, attr_handle, &att_err, + BLE_ATT_ACCESS_OP_WRITE, cid); + if (rc == BLE_HS_EPENDING) { + return rc; + } + if (rc != 0) { + break; + } + } + + rc = ble_att_svr_create_read_mult_var_len_rsp( + conn_handle, cid, &pend_attr->om, rc, &att_err, &attr_handle); + goto done; + + case BLE_ATT_OP_PREP_WRITE_REQ: + prep_req = (struct ble_att_prep_write_cmd *)(pend_attr)->om->om_data; + rc = ble_att_svr_create_prep_write_rsp(conn_handle, cid, &pend_attr->om, + prep_req, rc, att_err, attr_handle); + return rc; + } + +done: + ble_hs_lock(); + SLIST_FOREACH(attr, &pending_attr_list, next) { + if (attr->conn_handle == conn_handle && attr->cid == cid) { + SLIST_REMOVE(&pending_attr_list, attr, pending_attr, next); + } + } + ble_hs_unlock(); + + return rc; +} + int ble_gatts_add_svcs(const struct ble_gatt_svc_def *svcs) {