Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

nimble/store: Fix nimble store behavior when CCCDs exceed static defined limit #790

Merged

Conversation

prasad-alatkar
Copy link
Contributor

@prasad-alatkar prasad-alatkar commented Mar 31, 2020

Issue reference: #788

Description:
In cases where CCCDs are exceeding MYNEWT_VAL(BLE_STORE_MAX_CCCDS) (overflow event), we can end up in continuous while loop.

Change list:

  1. In ble_gap_unpair_oldest_peer changed return value from 0 to BLE_HS_ENOENT when there is no entry found.
  2. Modified ble_store_util_status_rr to address overflow event of CCCDs.

Previous to this PR, if CCCDs used to exceed the MAX_CCCDs then in ble_store_write call there used to come OVERFLOW event, which used to call ble_store_delete_oldest_peer, now here as we do not have any peer to be deleted, we should have identified that we need to make space for CCCDs and not peer_sec or our_sec. The PR tries to address this issue.

@h2zero
Copy link
Contributor

h2zero commented Mar 31, 2020

Glad you built a proper fix and hope it gets merged.

I still question why we store cccd data for devices that aren’t bonded but that’s a separate issue.

@prasad-alatkar
Copy link
Contributor Author

@h2zero That is a valid point, will update if I find anything. Maybe @rymanluk can explain it to us.

Copy link
Contributor

@rymanluk rymanluk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this fix.

Just as aside note, ble_store_util_status_rr() is just an example code. In most of cases application shall provide its own handling of store events.

Anyway, we should improve it, and it is good catch with CCCD. Please check my comments.

nimble/host/src/ble_gap.c Show resolved Hide resolved
switch (event->event_code) {
case BLE_STORE_EVENT_OVERFLOW:
switch (event->overflow.obj_type) {
case BLE_STORE_OBJ_TYPE_OUR_SEC:
case BLE_STORE_OBJ_TYPE_PEER_SEC:
case BLE_STORE_OBJ_TYPE_CCCD:
return ble_gap_unpair_oldest_peer();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe that for CCCD we should have different handling and if we want to unpair older peer we should not unpair peer for which we store CCCD. If there is nothing to unpair just return the error.

In the CCCD event there is and ble_addr we should use to make sure that one is no unpaired.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rymanluk agreed !! I have made relevant changes. For CCCD, if ble_gap_unpair_oldest_peer is unable to delete any peer, we continue to find other peers occupying CCCDs in storage. I have also modified callback function (ble_store_util_iter_peer_cccd) to skip the current (i.e. for which CCCDs need to be stored) peer entry.

@prasad-alatkar prasad-alatkar force-pushed the fix/ble_store_overflow_handling branch 4 times, most recently from 1f5ad85 to d2012a8 Compare April 3, 2020 16:44
case BLE_STORE_OBJ_TYPE_PEER_SEC:
return ble_gap_unpair_oldest_peer();
case BLE_STORE_OBJ_TYPE_CCCD:
if ((rc = ble_gap_unpair_oldest_peer()) == BLE_HS_ENOENT) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking to call here other version of unpair_oldest which would take as a parameter ble_addr_t of device which we don't want to unpair.
If the only device which could be unpair is the one provided, then unpair is not done and this function returns error.

In such a case we know that we cannot store CCC and there is nothing we can do more here. All the other code is not needed then.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rymanluk That is what I have done actually in ble_store_util_subscribed_cccds !! What I think is ble_gap_unpair_oldest_peer is not anyway going to unpair current peer (the one for which we want to make space), so introducing similar function with ble_addr_t as input won't be really that helpful. Please let me know your thoughts on this.

The issue I believe is only confined to CCCDs, so ble_gap_unpair_oldest_peer()) == BLE_HS_ENOENT will make sure that we do not have any bonded devices and still we are out of storage space, which can be used to conclude that we need to clean old CCCDs (except the current one).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@prasad-alatkar are you sure that ble_gap_unpair_oldest_peer() will not unpair current peer? For me it looks it will.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe @rymanluk is correct, if the current peer exceeds the cccd limit it will likely unpair that peer and disconnect. I like the do nothing if full approach here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rymanluk @h2zero , disregard my earlier comment, yes current peer will be unpaired, and we should simply return error in that case.

I was thinking of adding utility function (ble_store_clean_old_cccd) which will delete CCCDs of all unbonded peers. This can be called first in case of CCCD overflow and if it fails to delete peer then we can continue with modified ble_gap_unpair_oldest_peer(). Please let me know your views on it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe that ble_store_util_delete_peer() deletes all what we need.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @rymanluk I think for some peers CCCD will exist but peer_sec and our_sec won't exist (Ref: subscribe-event ble_gatts_clt_cfg_access). So we need mechanism to clean these stored CCCDs, that is why I have introduced ble_store_clean_old_cccd() function.

@prasad-alatkar prasad-alatkar force-pushed the fix/ble_store_overflow_handling branch 5 times, most recently from 286109e to cd7a848 Compare April 8, 2020 05:51
Copy link
Contributor

@rymanluk rymanluk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are almost there :) Couple of comments.

General comment - please keep commit message title short (up to 70) and then use commit message body if needed.

}

for (i = 0; i < num_peers; i++) {
if (memcmp(curr_peer, &oldest_peer_id_addr[i], sizeof (ble_addr_t)) != 0) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would use here ble_addr_cmp()

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure !!

}
}

if (i < num_peers) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would do it little simpler.

if (i >= num_peers) {
     return BLE_HS_ENOMEM;
}

return ble_gap_unpair(&oldest_peer_id_addr[i]);

int
ble_gap_unpair_oldest_except_curr(const ble_addr_t *curr_peer)
{
ble_addr_t oldest_peer_id_addr[MYNEWT_VAL(BLE_STORE_MAX_BONDS)];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick: please rename to peer_id_addrs

* A BLE host core return code on unexpected
* error.
*/
int ble_gap_unpair_oldest_except_curr(const ble_addr_t *curr_peer);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let us call it ble_gap_unpair_oldest_except () and change the parameter name to peer_addr.
This functionality is not really dedicated only to current device. You might want to have device which you don't want to unpair no matter what :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed !!

return ble_gap_unpair_oldest_peer();
case BLE_STORE_OBJ_TYPE_CCCD:
/* Try to remove unbonded CCCDs first */
if ((rc = ble_store_clean_old_cccds((void *) &event->overflow.value->cccd.peer_addr)) == BLE_HS_ENOENT) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we need to clean unbodend CCCDs as we do not keep such in the storage. Unless I miss something, but CCCDs are stored only for bonded devices, and once unbonded, we do clean CCCDs. If it does not work like this (I believe it does) then we have problem somewhere else.

In this case we just need to call the new function and that is it. Nothing else is needed.

Copy link
Contributor Author

@prasad-alatkar prasad-alatkar Apr 9, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @rymanluk Please let me know if I am missing something. As per my understanding CCCDs for unbonded devices can get stored as ble_gatts_clt_cfg_access --> ble_store_write_cccd --> ble_store_write(BLE_STORE_OBJ_TYPE_CCCD, store_value).

Edit:
Please disregard my earlier comment, missed on cccd_value.flags == 0 check.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we need to clean unbodend CCCDs as we do not keep such in the storage. Unless I miss something, but CCCDs are stored only for bonded devices, and once unbonded, we do clean CCCDs. If it does not work like this (I believe it does) then we have problem somewhere else.

In this case we just need to call the new function and that is it. Nothing else is needed.

@rymanluk CCCD's do get stored if the devices pair but one or both of them does not accept bonding, so cleaning those up makes sense in this case. Although it would be better if that never happened to begin with.

Copy link
Contributor

@rymanluk rymanluk Apr 14, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@h2zero actually CCCD's do get stored when devices are bonded. That happens after pairing is completed and both devices have set bonding flag.

If you do see an issue that CCCDs are stored but device is not actually bonded, please report it as an issue.

@prasad-alatkar prasad-alatkar force-pushed the fix/ble_store_overflow_handling branch from cd7a848 to 4f38ac7 Compare April 16, 2020 11:42
Copy link
Contributor

@rymanluk rymanluk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, one minor comment.

return ble_gap_unpair_oldest_peer();
case BLE_STORE_OBJ_TYPE_CCCD:
/* Try unpairing oldest peer except current peer */
return ble_gap_unpair_oldest_except((void *) &event->overflow.value->cccd.peer_addr);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick: (void *) seems to be not needed here.

- Add supporting API to skip input peer while unpairing oldest peer
@prasad-alatkar prasad-alatkar force-pushed the fix/ble_store_overflow_handling branch from 4f38ac7 to bb9303a Compare April 16, 2020 14:11
@apache-mynewt-bot
Copy link

Style check summary

No suggestions at this time!

Copy link
Contributor

@rymanluk rymanluk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks good to me. Thanks

@rymanluk rymanluk merged commit 6661a51 into apache:master Apr 17, 2020
espressif-bot pushed a commit to espressif/esp-idf that referenced this pull request May 22, 2020
Change list:
- Reduces the size of the compiled binary, PR: espressif/esp-nimble#6
- Null pointer check, PR: apache/mynewt-nimble#701
- Pairing procedure abort on unexpected req: apache/mynewt-nimble#710
- Fix conn flags after pairing: apache/mynewt-nimble#730
- Remove notification for update process timeout (Vol 6, Part B, section 5.2 ):
  apache/mynewt-nimble#782
- CCCD fix : apache/mynewt-nimble#790 and
  apache/mynewt-nimble#804
- Host based Privacy (RPA) fix: espressif/esp-nimble#7

 Closes espressif/esp-nimble#10

 Closes #4413
mahavirj pushed a commit to mahavirj/esp-afr-sdk that referenced this pull request Jun 1, 2020
… (backport v3.3)

Change list:
- Reduces the size of the compiled binary, PR: espressif/esp-nimble#6
- Null pointer check, PR: apache/mynewt-nimble#701
- Pairing procedure abort on unexpected req: apache/mynewt-nimble#710
- Fix conn flags after pairing: apache/mynewt-nimble#730
- Remove notification for update process timeout (Vol 6, Part B, section 5.2 ):
  apache/mynewt-nimble#782
- CCCD fix : apache/mynewt-nimble#790 and
  apache/mynewt-nimble#804
- Host based Privacy (RPA) fix: espressif/esp-nimble#7

 Closes espressif/esp-nimble#10

 Closes espressif/esp-idf#4413
espressif-bot pushed a commit to espressif/esp-idf that referenced this pull request Jun 15, 2020
… (backport v4.0)

Change list:
- Reduces the size of the compiled binary, PR: espressif/esp-nimble#6
- Null pointer check, PR: apache/mynewt-nimble#701
- Pairing procedure abort on unexpected req: apache/mynewt-nimble#710
- Fix conn flags after pairing: apache/mynewt-nimble#730
- Remove notification for update process timeout (Vol 6, Part B, section 5.2 ):
  apache/mynewt-nimble#782
- CCCD fix : apache/mynewt-nimble#790 and
  apache/mynewt-nimble#804
- Host based Privacy (RPA) fix: espressif/esp-nimble#7

 Closes espressif/esp-nimble#10

 Closes #4413
projectgus pushed a commit to espressif/esp-idf that referenced this pull request Jul 22, 2020
… (backport v4.1)

Change list:
- Reduces the size of the compiled binary, PR: espressif/esp-nimble#6
- Null pointer check, PR: apache/mynewt-nimble#701
- Pairing procedure abort on unexpected req: apache/mynewt-nimble#710
- Fix conn flags after pairing: apache/mynewt-nimble#730
- Remove notification for update process timeout (Vol 6, Part B, section 5.2 ):
  apache/mynewt-nimble#782
- CCCD fix : apache/mynewt-nimble#790 and
  apache/mynewt-nimble#804
- Host based Privacy (RPA) fix: espressif/esp-nimble#7

 Closes espressif/esp-nimble#10

 Closes #4413
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants