Skip to content

Commit 97482d4

Browse files
committed
nimble/ll: Add support for Channel Map Update in periodic scanner
1 parent 2971ee5 commit 97482d4

File tree

2 files changed

+126
-20
lines changed

2 files changed

+126
-20
lines changed

nimble/controller/include/controller/ble_ll.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -444,6 +444,14 @@ struct ble_dev_addr
444444
#define BLE_LL_ADDR_SUBTYPE_RPA (1)
445445
#define BLE_LL_ADDR_SUBTYPE_NRPA (2)
446446

447+
/* ACAD data types */
448+
#define BLE_LL_ACAD_CHANNEL_MAP_UPDATE_IND 0x28
449+
450+
struct ble_ll_acad_channel_map_update_ind {
451+
uint8_t map[5];
452+
uint16_t instant;
453+
} __attribute__((packed));
454+
447455
/*--- External API ---*/
448456
/* Initialize the Link Layer */
449457
void ble_ll_init(void);

nimble/controller/src/ble_ll_sync.c

Lines changed: 118 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@
6060
#define BLE_LL_SYNC_SM_FLAG_DISABLED 0x0040
6161
#define BLE_LL_SYNC_SM_FLAG_ADDR_RESOLVED 0x0080
6262
#define BLE_LL_SYNC_SM_FLAG_HCI_TRUNCATED 0x0100
63+
#define BLE_LL_SYNC_SM_FLAG_NEW_CHANMAP 0x0200
6364

6465
#define BLE_LL_SYNC_CHMAP_LEN 5
6566
#define BLE_LL_SYNC_ITVL_USECS 1250
@@ -75,6 +76,9 @@ struct ble_ll_sync_sm {
7576
uint8_t chanmap[BLE_LL_SYNC_CHMAP_LEN];
7677
uint8_t num_used_chans;
7778

79+
uint8_t chanmap_new[BLE_LL_SYNC_CHMAP_LEN];
80+
uint16_t chanmap_new_instant;
81+
7882
uint8_t chan_index;
7983
uint8_t chan_chain;
8084

@@ -525,7 +529,8 @@ ble_ll_sync_rx_isr_start(uint8_t pdu_type, struct ble_mbuf_hdr *rxhdr)
525529
}
526530

527531
static int
528-
ble_ll_sync_parse_ext_hdr(struct os_mbuf *om, uint8_t **aux, int8_t *tx_power)
532+
ble_ll_sync_parse_ext_hdr(struct os_mbuf *om, uint8_t **aux, int8_t *tx_power,
533+
uint8_t **acad, uint8_t *acad_len)
529534
{
530535
uint8_t *rxbuf = om->om_data;
531536
uint8_t ext_hdr_flags;
@@ -585,12 +590,17 @@ ble_ll_sync_parse_ext_hdr(struct os_mbuf *om, uint8_t **aux, int8_t *tx_power)
585590
i += BLE_LL_EXT_ADV_TX_POWER_SIZE;
586591
}
587592

588-
/* TODO Handle ACAD if needed */
589-
590593
/* sanity check */
591594
if (i > ext_hdr_len) {
592595
return -1;
593596
}
597+
598+
/* ACAD */
599+
if (ext_hdr_len > (i + 1)) {
600+
*acad = ext_hdr + i;
601+
*acad_len = ext_hdr_len - i - 1;
602+
}
603+
594604
}
595605

596606
return pdu_len - ext_hdr_len - 1;
@@ -996,14 +1006,81 @@ ble_ll_sync_check_failed(struct ble_ll_sync_sm *sm)
9961006
ble_ll_sync_est_event_failed(BLE_ERR_CONN_ESTABLISHMENT);
9971007
}
9981008

1009+
static bool
1010+
ble_ll_sync_check_acad(struct ble_ll_sync_sm *sm,
1011+
const uint8_t *acad, uint8_t acad_len)
1012+
{
1013+
const struct ble_ll_acad_channel_map_update_ind *chmu;
1014+
unsigned int ad_len;
1015+
uint8_t ad_type;
1016+
1017+
/* assume no empty fields */
1018+
while (acad_len > 2) {
1019+
ad_len = acad[0];
1020+
ad_type = acad[1];
1021+
1022+
/* early termination should not happen in ACAD */
1023+
if (ad_len == 0) {
1024+
return false;
1025+
}
1026+
1027+
/* check if not passing pass acad data */
1028+
if (ad_len + 1 > acad_len) {
1029+
return false;
1030+
}
1031+
1032+
switch (ad_type) {
1033+
case BLE_LL_ACAD_CHANNEL_MAP_UPDATE_IND:
1034+
chmu = (const void *)&acad[2];
1035+
1036+
if (ad_len - 1 != sizeof(*chmu)) {
1037+
return false;
1038+
}
1039+
1040+
/* Channels Mask (37 bits)
1041+
* TODO should we check this?
1042+
*/
1043+
sm->chanmap_new[0] = chmu->map[0];
1044+
sm->chanmap_new[1] = chmu->map[1];
1045+
sm->chanmap_new[2] = chmu->map[2];
1046+
sm->chanmap_new[3] = chmu->map[3];
1047+
sm->chanmap_new[4] = chmu->map[4] & 0x1f;
1048+
1049+
/* drop if channel map is invalid */
1050+
if (ble_ll_utils_calc_num_used_chans(sm->chanmap_new) == 0) {
1051+
return false;
1052+
}
1053+
1054+
sm->chanmap_new_instant = le16toh(chmu->instant);
1055+
sm->flags |= BLE_LL_SYNC_SM_FLAG_NEW_CHANMAP;
1056+
break;
1057+
default:
1058+
break;
1059+
}
1060+
1061+
acad += ad_len + 1;
1062+
acad_len -= ad_len + 1;
1063+
}
1064+
1065+
/* should have no trailing zeros */
1066+
if (acad_len) {
1067+
return false;
1068+
}
1069+
1070+
return true;
1071+
}
1072+
9991073
void
10001074
ble_ll_sync_rx_pkt_in(struct os_mbuf *rxpdu, struct ble_mbuf_hdr *hdr)
10011075
{
10021076
struct ble_ll_sync_sm *sm = hdr->rxinfo.user_data;
10031077
bool aux_scheduled = false;
10041078
int8_t tx_power = 127; /* defaults to not available */
10051079
uint8_t *aux = NULL;
1080+
uint8_t *acad = NULL;
1081+
uint8_t acad_len;
10061082
int datalen;
1083+
bool reports_enabled;
10071084

10081085
BLE_LL_ASSERT(sm);
10091086

@@ -1048,36 +1125,43 @@ ble_ll_sync_rx_pkt_in(struct os_mbuf *rxpdu, struct ble_mbuf_hdr *hdr)
10481125
goto end_event;
10491126
}
10501127

1051-
if (ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_PERIODIC_ADV_RPT) &&
1052-
!(sm->flags & BLE_LL_SYNC_SM_FLAG_DISABLED)) {
1053-
/* get ext header data */
1054-
datalen = ble_ll_sync_parse_ext_hdr(rxpdu, &aux, &tx_power);
1055-
if (datalen < 0) {
1056-
/* we got bad packet, end event */
1057-
goto end_event;
1058-
}
1128+
/* get ext header data */
1129+
datalen = ble_ll_sync_parse_ext_hdr(rxpdu, &aux, &tx_power, &acad, &acad_len);
1130+
if (datalen < 0) {
1131+
/* we got bad packet, end event */
1132+
goto end_event;
1133+
}
10591134

1135+
reports_enabled = ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_PERIODIC_ADV_RPT) &&
1136+
!(sm->flags & BLE_LL_SYNC_SM_FLAG_DISABLED);
1137+
1138+
/* no need to schedule for chain if reporting is disabled */
1139+
if (reports_enabled) {
10601140
/* if aux is present, we need to schedule ASAP */
10611141
if (aux && (ble_ll_sync_schedule_chain(sm, hdr, aux) == 0)) {
10621142
aux_scheduled = true;
10631143
}
1144+
}
10641145

1065-
/* in case data reporting is enabled we need to send sync established here */
1066-
if (sm->flags & BLE_LL_SYNC_SM_FLAG_ESTABLISHING) {
1067-
ble_ll_sync_established(sm);
1068-
}
1146+
/* check ACAD, needs to be done before rxpdu is adjusted for ADV data */
1147+
if (acad && !ble_ll_sync_check_acad(sm, acad, acad_len)) {
1148+
/* we got bad packet (bad ACAD data), end event */
1149+
goto end_event;
1150+
}
1151+
1152+
/* we need to establish link even if reporting was disabled */
1153+
if (sm->flags & BLE_LL_SYNC_SM_FLAG_ESTABLISHING) {
1154+
ble_ll_sync_established(sm);
1155+
}
10691156

1157+
/* only if reporting is enabled */
1158+
if (reports_enabled) {
10701159
/* Adjust rxpdu to contain advertising data only */
10711160
ble_ll_sync_adjust_ext_hdr(rxpdu);
10721161

10731162
/* send reports from this PDU */
10741163
ble_ll_sync_send_per_adv_rpt(sm, rxpdu, hdr->rxinfo.rssi, tx_power,
10751164
datalen, aux, aux_scheduled);
1076-
} else {
1077-
/* we need to establish link even if reporting was disabled */
1078-
if (sm->flags & BLE_LL_SYNC_SM_FLAG_ESTABLISHING) {
1079-
ble_ll_sync_established(sm);
1080-
}
10811165
}
10821166

10831167
/* if chain was scheduled we don't end event yet */
@@ -1131,6 +1215,20 @@ ble_ll_sync_next_event(struct ble_ll_sync_sm *sm, uint32_t cur_ww_adjust)
11311215
/* Set event counter to the next event */
11321216
sm->event_cntr += 1 + skip;
11331217

1218+
/* update channel map if needed */
1219+
if (sm->flags & BLE_LL_SYNC_SM_FLAG_NEW_CHANMAP) {
1220+
if (((int16_t)(sm->event_cntr - sm->chanmap_new_instant)) >= 0) {
1221+
/* map was verified on reception */
1222+
sm->chanmap[0] = sm->chanmap_new[0];
1223+
sm->chanmap[1] = sm->chanmap_new[1];
1224+
sm->chanmap[2] = sm->chanmap_new[2];
1225+
sm->chanmap[3] = sm->chanmap_new[3];
1226+
sm->chanmap[4] = sm->chanmap_new[4];
1227+
sm->num_used_chans = ble_ll_utils_calc_num_used_chans(sm->chanmap);
1228+
sm->flags &= ~BLE_LL_SYNC_SM_FLAG_NEW_CHANMAP;
1229+
}
1230+
}
1231+
11341232
/* Calculate channel index of next event */
11351233
sm->chan_index = ble_ll_utils_calc_dci_csa2(sm->event_cntr, sm->channel_id,
11361234
sm->num_used_chans, sm->chanmap);

0 commit comments

Comments
 (0)