Skip to content

Commit da61af9

Browse files
committed
Add a workaround for subscribe security
apache/mynewt-nimble#1092
1 parent 6ce8026 commit da61af9

File tree

1 file changed

+61
-22
lines changed

1 file changed

+61
-22
lines changed

src/esp32/esp32_bt_gatts.c

Lines changed: 61 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -59,12 +59,6 @@ struct esp32_bt_service_attr_info {
5959
uint16_t handle;
6060
};
6161

62-
struct esp32_bt_gatts_pending_write {
63-
uint16_t handle;
64-
struct mbuf value;
65-
SLIST_ENTRY(esp32_bt_gatts_pending_write) next;
66-
};
67-
6862
struct esp32_bt_gatts_pending_ind {
6963
uint16_t handle;
7064
bool is_ind;
@@ -80,18 +74,25 @@ struct esp32_bt_gatts_session_entry {
8074
struct mgos_bt_gatts_conn gsc;
8175
struct esp32_bt_gatts_service_entry *se;
8276
struct mbuf resp_data;
83-
SLIST_HEAD(pending_writes, esp32_bt_gatts_pending_write) pending_writes;
8477
SLIST_ENTRY(esp32_bt_gatts_session_entry) next;
8578
};
8679

80+
// This notification mode change is awaiting completion of the security
81+
// procedure.
82+
struct esp32_bt_gatts_pending_nm_entry {
83+
struct mgos_bt_gatts_notify_mode_arg nmarg;
84+
SLIST_ENTRY(esp32_bt_gatts_pending_nm_entry) next;
85+
};
86+
8787
struct esp32_bt_gatts_connection_entry {
8888
struct mgos_bt_gatt_conn gc;
8989
enum mgos_bt_gatt_sec_level sec_level;
90-
bool need_auth;
91-
bool ind_in_flight;
90+
bool sec_in_flight;
9291
/* Notifications/indications are finicky, so we keep at most one in flight. */
9392
int ind_queue_len;
93+
bool ind_in_flight;
9494
STAILQ_HEAD(pending_inds, esp32_bt_gatts_pending_ind) pending_inds;
95+
SLIST_HEAD(pending_nm, esp32_bt_gatts_pending_nm_entry) pending_nm;
9596
SLIST_HEAD(sessions, esp32_bt_gatts_session_entry) sessions; // 1 per service
9697
SLIST_ENTRY(esp32_bt_gatts_connection_entry) next;
9798
};
@@ -237,11 +238,10 @@ static enum mgos_bt_gatt_status esp32_bt_gatts_call_handler(
237238
}
238239

239240
void esp32_bt_gatts_close_session(struct esp32_bt_gatts_session_entry *sse) {
240-
struct esp32_bt_gatts_pending_write *pw, *pwt;
241-
SLIST_FOREACH_SAFE(pw, &sse->pending_writes, next, pwt) {
242-
mbuf_free(&pw->value);
243-
memset(pw, 0, sizeof(*pw));
244-
free(pw);
241+
struct esp32_bt_gatts_pending_nm_entry *pnm, *pnmt;
242+
SLIST_FOREACH_SAFE(pnm, &sse->ce->pending_nm, next, pnmt) {
243+
memset(pnm, 0, sizeof(*pnm));
244+
free(pnm);
245245
}
246246
SLIST_REMOVE(&sse->ce->sessions, sse, esp32_bt_gatts_session_entry, next);
247247
esp32_bt_gatts_call_handler(sse, NULL, MGOS_BT_GATTS_EV_DISCONNECT, NULL);
@@ -262,7 +262,6 @@ static void esp32_bt_gatts_create_sessions(
262262
sse->gsc.gc = ce->gc;
263263
sse->gsc.svc_uuid = se->uuid;
264264
mbuf_init(&sse->resp_data, 0);
265-
SLIST_INIT(&sse->pending_writes);
266265
enum mgos_bt_gatt_status st =
267266
esp32_bt_gatts_call_handler(sse, NULL, MGOS_BT_GATTS_EV_CONNECT, NULL);
268267
if (st != MGOS_BT_GATT_STATUS_OK) {
@@ -339,12 +338,10 @@ int esp32_bt_gatts_event(const struct ble_gap_event *ev, void *arg) {
339338
ce->gc.conn_id = conn_id;
340339
ce->gc.mtu = ble_att_mtu(conn_id);
341340
esp32_bt_addr_to_mgos(&cd.peer_ota_addr, &ce->gc.addr);
341+
SLIST_INIT(&ce->pending_nm);
342342
STAILQ_INIT(&ce->pending_inds);
343343
SLIST_INSERT_HEAD(&s_conns, ce, next);
344344
ble_gattc_exchange_mtu(conn_id, NULL, NULL);
345-
if (mgos_sys_config_get_bt_gatts_min_sec_level() > 0) {
346-
// ble_gap_security_initiate(conn_id);
347-
}
348345
break;
349346
}
350347
case BLE_GAP_EVENT_DISCONNECT: {
@@ -370,14 +367,38 @@ int esp32_bt_gatts_event(const struct ble_gap_event *ev, void *arg) {
370367
break;
371368
}
372369
case BLE_GAP_EVENT_ENC_CHANGE: {
373-
uint16_t conn_id = ev->enc_change.conn_handle;
370+
uint16_t ch = ev->enc_change.conn_handle;
374371
struct ble_gap_conn_desc cd = {0};
375-
ble_gap_conn_find(conn_id, &cd);
372+
ble_gap_conn_find(ch, &cd);
376373
struct ble_gap_sec_state *ss = &cd.sec_state;
374+
struct esp32_bt_gatts_connection_entry *ce = find_connection(ch);
375+
if (ce == NULL) break;
376+
ce->sec_in_flight = false;
377377
LOG(LL_DEBUG, ("ENC_CHANGE %s ch %d st %d e %d a %d b %d ks %d",
378-
esp32_bt_addr_to_str(&cd.peer_ota_addr, buf1), conn_id,
378+
esp32_bt_addr_to_str(&cd.peer_ota_addr, buf1), ch,
379379
ev->enc_change.status, ss->encrypted, ss->authenticated,
380380
ss->bonded, ss->key_size));
381+
if (ev->enc_change.status != 0) {
382+
ble_gap_terminate(ch, BLE_ERR_REM_USER_CONN_TERM);
383+
break;
384+
}
385+
while (!SLIST_EMPTY(&ce->pending_nm)) {
386+
struct esp32_bt_gatts_pending_nm_entry *pnm =
387+
SLIST_FIRST(&ce->pending_nm);
388+
SLIST_REMOVE_HEAD(&ce->pending_nm, next);
389+
struct mgos_bt_gatts_notify_mode_arg *narg = &pnm->nmarg;
390+
uint16_t ah = narg->handle;
391+
struct esp32_bt_service_attr_info *ai = NULL;
392+
struct esp32_bt_gatts_session_entry *sse = find_session(ch, ah, &ai);
393+
LOG(LL_DEBUG,
394+
("NOTIFY_MODE ch %d ah %d %s/%s %d", ch, ah,
395+
mgos_bt_uuid_to_str(&narg->svc_uuid, buf1),
396+
mgos_bt_uuid_to_str(&narg->char_uuid, buf2), narg->mode));
397+
esp32_bt_gatts_call_handler(sse, ai, MGOS_BT_GATTS_EV_NOTIFY_MODE,
398+
narg);
399+
memset(pnm, 0, sizeof(*pnm));
400+
free(pnm);
401+
}
381402
break;
382403
}
383404
case BLE_GAP_EVENT_MTU: {
@@ -410,7 +431,25 @@ int esp32_bt_gatts_event(const struct ble_gap_event *ev, void *arg) {
410431
} else if (ev->subscribe.cur_indicate) {
411432
narg.mode = MGOS_BT_GATT_NOTIFY_MODE_INDICATE;
412433
}
413-
LOG(LL_DEBUG, ("NOTIFY_MODE c %d h %d %s/%s %d", ch, ah,
434+
// Work around https://github.com/apache/mynewt-nimble/issues/1092
435+
if (sse->se->sec_level > 0 ||
436+
mgos_sys_config_get_bt_gatts_min_sec_level() > 0) {
437+
struct ble_gap_conn_desc cd = {0};
438+
ble_gap_conn_find(ch, &cd);
439+
struct ble_gap_sec_state *ss = &cd.sec_state;
440+
if (!ss->encrypted) {
441+
struct esp32_bt_gatts_pending_nm_entry *pnm = calloc(1, sizeof(*pnm));
442+
pnm->nmarg = narg;
443+
SLIST_INSERT_HEAD(&sse->ce->pending_nm, pnm, next);
444+
if (!sse->ce->sec_in_flight) {
445+
sse->ce->sec_in_flight = true;
446+
ble_gap_security_initiate(ch);
447+
}
448+
ret = BLE_ATT_ERR_INSUFFICIENT_AUTHOR;
449+
break;
450+
}
451+
}
452+
LOG(LL_DEBUG, ("NOTIFY_MODE ch %d ah %d %s/%s %d", ch, ah,
414453
mgos_bt_uuid_to_str(&narg.svc_uuid, buf1),
415454
mgos_bt_uuid_to_str(&narg.char_uuid, buf2), narg.mode));
416455
esp32_bt_gatts_call_handler(sse, ai, MGOS_BT_GATTS_EV_NOTIFY_MODE, &narg);

0 commit comments

Comments
 (0)