diff --git a/pkg/nimble/netif/include/nimble_netif.h b/pkg/nimble/netif/include/nimble_netif.h index fd4b7927fd..b7acbf0fd1 100644 --- a/pkg/nimble/netif/include/nimble_netif.h +++ b/pkg/nimble/netif/include/nimble_netif.h @@ -253,6 +253,22 @@ int nimble_netif_close(int handle); int nimble_netif_accept(const uint8_t *ad, size_t ad_len, const struct ble_gap_adv_params *adv_params); +/** + * @brief Wait for an incoming connection from a specific peer, sending + * directed advertisements (IND_DIR) + * + * @param[in] addr BLE address of the target peer + * @param[in] timeout_ms stop advertising after this time (in ms), set to + * BLE_HS_FOREVER to disable timeout + * @param[in] adv_params advertising (timing) parameters to use + * + * @return NIMBLE_NETIF_OK on success + * @return NIMBLE_NETIF_BUSY if already advertising + * @return NIMBLE_NETIF_NOMEM on insufficient connection memory + */ +int nimble_netif_accept_direct(const ble_addr_t *addr, uint32_t timeout_ms, + const struct ble_gap_adv_params *adv_params); + /** * @brief Stop accepting incoming connections (stop advertising) * * diff --git a/pkg/nimble/netif/nimble_netif.c b/pkg/nimble/netif/nimble_netif.c index 0a2b70a82a..9d4e56959a 100644 --- a/pkg/nimble/netif/nimble_netif.c +++ b/pkg/nimble/netif/nimble_netif.c @@ -531,6 +531,11 @@ static int _on_gap_slave_evt(struct ble_gap_event *event, void *arg) case BLE_GAP_EVENT_CONN_UPDATE_REQ: /* nothing to do here */ break; + case BLE_GAP_EVENT_ADV_COMPLETE: { + uint8_t addr[BLE_ADDR_LEN]; + nimble_netif_conn_free(handle, addr); + _notify(handle, NIMBLE_NETIF_ACCEPT_STOP, addr); + } default: break; } @@ -634,10 +639,10 @@ int nimble_netif_close(int handle) return NIMBLE_NETIF_OK; } -int nimble_netif_accept(const uint8_t *ad, size_t ad_len, - const struct ble_gap_adv_params *adv_params) +static int _accept(const uint8_t *ad, size_t ad_len, const ble_addr_t *addr, + uint32_t timeout, + const struct ble_gap_adv_params *adv_params) { - assert(ad); assert(adv_params); int handle; @@ -651,10 +656,18 @@ int nimble_netif_accept(const uint8_t *ad, size_t ad_len, } /* set advertisement data */ - res = ble_gap_adv_set_data(ad, (int)ad_len); - assert(res == 0); + if (ad != NULL) { + res = ble_gap_adv_set_data(ad, (int)ad_len); + assert(res == 0); + } + /* remember address if applicable */ + if (addr) { + nimble_netif_conn_t *conn = nimble_netif_conn_get(handle); + bluetil_addr_swapped_cp(addr->val, conn->addr); + } + /* remember context and start advertising */ - res = ble_gap_adv_start(nimble_riot_own_addr_type, NULL, BLE_HS_FOREVER, + res = ble_gap_adv_start(nimble_riot_own_addr_type, addr, timeout, adv_params, _on_gap_slave_evt, (void *)handle); assert(res == 0); @@ -663,6 +676,20 @@ int nimble_netif_accept(const uint8_t *ad, size_t ad_len, return NIMBLE_NETIF_OK; } +int nimble_netif_accept(const uint8_t *ad, size_t ad_len, + const struct ble_gap_adv_params *adv_params) +{ + assert(ad != NULL); + assert(ad_len > 0); + return _accept(ad, ad_len, NULL, BLE_HS_FOREVER, adv_params); +} + +int nimble_netif_accept_direct(const ble_addr_t *addr, uint32_t timeout, + const struct ble_gap_adv_params *adv_params) +{ + return _accept(NULL, 0, addr, timeout, adv_params); +} + int nimble_netif_accept_stop(void) { int handle = nimble_netif_conn_get_adv(); diff --git a/sys/shell/commands/sc_nimble_netif.c b/sys/shell/commands/sc_nimble_netif.c index 311879999a..a1c05f5ed1 100644 --- a/sys/shell/commands/sc_nimble_netif.c +++ b/sys/shell/commands/sc_nimble_netif.c @@ -241,6 +241,44 @@ static void _cmd_adv(const char *name) } } +static void _cmd_adv_direct(const char *addr_str) +{ + int res; + (void)res; + uint8_t addrn[BLE_ADDR_LEN]; + ble_addr_t addr; + const struct ble_gap_adv_params _adv_params = { + .conn_mode = BLE_GAP_CONN_MODE_DIR, + .disc_mode = BLE_GAP_DISC_MODE_GEN, + .itvl_min = BLE_GAP_ADV_FAST_INTERVAL2_MIN, + .itvl_max = BLE_GAP_ADV_FAST_INTERVAL2_MAX, + }; + + /* make sure no advertising is in progress */ + if (nimble_netif_conn_is_adv()) { + puts("err: advertising already in progress"); + return; + } + + /* parse and convert address -> RIOT uses big endian notation, NimBLE + * expects little endian... */ + if (bluetil_addr_from_str(addrn, addr_str) == NULL) { + puts("err: unable to parse BLE address"); + return; + } + addr.type = nimble_riot_own_addr_type; + bluetil_addr_swapped_cp(addrn, addr.val); + + /* start advertising directed advertising with the given BLE address */ + res = nimble_netif_accept_direct(&addr, BLE_HS_FOREVER, &_adv_params); + if (res != NIMBLE_NETIF_OK) { + printf("err: unable to start directed advertising (%i)\n", res); + } + else { + puts("success: started to send directed advertisements"); + } +} + static void _cmd_adv_stop(void) { int res = nimble_netif_accept_stop(); @@ -395,13 +433,23 @@ int _nimble_netif_handler(int argc, char **argv) char *name = NULL; if (argc > 2) { if (_ishelp(argv[2])) { - printf("usage: %s adv [help|stop|]\n", argv[0]); + printf("usage: %s adv [help|stop|direct |]\n", + argv[0]); return 0; } if (memcmp(argv[2], "stop", 4) == 0) { _cmd_adv_stop(); return 0; } + if (memcmp(argv[2], "direct", 6) == 0) { + puts("DBG: direct adv"); + if (argc < 4) { + printf("error, no BLE address given\n"); + return 0; + } + _cmd_adv_direct(argv[3]); + return 0; + } name = argv[2]; } _cmd_adv(name);