Loading system/include/bt_target.h +4 −0 Original line number Diff line number Diff line Loading @@ -1407,6 +1407,10 @@ and USER_HW_DISABLE_API macros */ #define LOCAL_BLE_CONTROLLER_ID (1) #endif #ifndef BTM_BLE_PRIVACY_SPT #define BTM_BLE_PRIVACY_SPT TRUE #endif /****************************************************************************** ** ** ATT/GATT Protocol/Profile Settings Loading system/stack/btm/btm_acl.c +57 −0 Original line number Diff line number Diff line Loading @@ -179,6 +179,59 @@ UINT8 btm_handle_to_acl_index (UINT16 hci_handle) /* If here, no BD Addr found */ return(xx); } #if BTM_BLE_PRIVACY_SPT == TRUE /******************************************************************************* ** ** Function btm_ble_get_acl_remote_addr ** ** Description This function reads the active remote address used for the ** connection. ** ** Returns success return TRUE, otherwise FALSE. ** *******************************************************************************/ BOOLEAN btm_ble_get_acl_remote_addr(tBTM_SEC_DEV_REC *p_dev_rec, BD_ADDR conn_addr, tBLE_ADDR_TYPE *p_addr_type) { #if BLE_INCLUDED == TRUE BOOLEAN st = TRUE; if (p_dev_rec == NULL) { BTM_TRACE_ERROR0("btm_ble_get_acl_remote_addr can not find device with matching address"); return FALSE; } switch (p_dev_rec->ble.active_addr_type) { case BTM_BLE_ADDR_PSEUDO: memcpy(conn_addr, p_dev_rec->bd_addr, BD_ADDR_LEN); * p_addr_type = p_dev_rec->ble.ble_addr_type; break; case BTM_BLE_ADDR_RRA: memcpy(conn_addr, p_dev_rec->ble.cur_rand_addr, BD_ADDR_LEN); * p_addr_type = BLE_ADDR_RANDOM; break; case BTM_BLE_ADDR_STATIC: memcpy(conn_addr, p_dev_rec->ble.static_addr, BD_ADDR_LEN); * p_addr_type = p_dev_rec->ble.static_addr_type; break; default: BTM_TRACE_ERROR1("Unknown active address: %d", p_dev_rec->ble.active_addr_type); st = FALSE; break; } return st; #else return FALSE; #endif } #endif /******************************************************************************* ** ** Function btm_acl_created Loading Loading @@ -298,6 +351,10 @@ void btm_acl_created (BD_ADDR bda, DEV_CLASS dc, BD_NAME bdn, /* If here, features are not known yet */ if (p_dev_rec && is_le_link) { #if BTM_BLE_PRIVACY_SPT == TRUE btm_ble_get_acl_remote_addr (p_dev_rec, p->active_remote_addr, &p->active_remote_addr_type); #endif btm_establish_continue(p); #if (!defined(BTA_SKIP_BLE_READ_REMOTE_FEAT) || BTA_SKIP_BLE_READ_REMOTE_FEAT == FALSE) Loading system/stack/btm/btm_ble.c +99 −6 Original line number Diff line number Diff line Loading @@ -35,6 +35,9 @@ #include "btm_ble_api.h" #include "smp_api.h" #include "l2c_int.h" #if (defined BLE_BRCM_INCLUDED && BLE_BRCM_INCLUDED == TRUE) #include "brcm_ble.h" #endif #include "gap_api.h" #include "bt_utils.h" Loading Loading @@ -341,12 +344,24 @@ BOOLEAN BTM_ReadRemoteConnectionAddr(BD_ADDR pseudo_addr, BD_ADDR conn_addr, tBL { BOOLEAN st = TRUE; tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev(pseudo_addr); #if BTM_BLE_PRIVACY_SPT == TRUE tACL_CONN *p = btm_bda_to_acl (pseudo_addr); if (p == NULL) { BTM_TRACE_ERROR0("BTM_ReadRemoteConnectionAddr can not find matching address"); return FALSE; } memcpy(conn_addr, p->active_remote_addr, BD_ADDR_LEN); *p_addr_type = p->active_remote_addr_type; #else memcpy(conn_addr, pseudo_addr, BD_ADDR_LEN); if (p_dev_rec != NULL) { *p_addr_type = p_dev_rec->ble.ble_addr_type; } #endif return st; } /******************************************************************************* Loading Loading @@ -1462,6 +1477,61 @@ UINT8 btm_ble_io_capabilities_req(tBTM_SEC_DEV_REC *p_dev_rec, tBTM_LE_IO_REQ *p return callback_rc; } #if (BTM_BLE_PRIVACY_SPT == TRUE ) /******************************************************************************* ** ** Function btm_ble_resolve_random_addr_on_conn_cmpl ** ** Description resolve random address complete on connection complete event. ** ** Returns void ** *******************************************************************************/ static void btm_ble_resolve_random_addr_on_conn_cmpl(void * p_rec, void *p_data) { UINT8 *p = (UINT8 *)p_data; tBTM_SEC_DEV_REC *match_rec = (tBTM_SEC_DEV_REC *) p_rec; UINT8 role, status, bda_type; UINT16 handle; BD_ADDR bda; UINT16 conn_interval, conn_latency, conn_timeout; BOOLEAN match = FALSE; STREAM_TO_UINT8 (status, p); STREAM_TO_UINT16 (handle, p); STREAM_TO_UINT8 (role, p); STREAM_TO_UINT8 (bda_type, p); STREAM_TO_BDADDR (bda, p); STREAM_TO_UINT16 (conn_interval, p); STREAM_TO_UINT16 (conn_latency, p); STREAM_TO_UINT16 (conn_timeout, p); handle = HCID_GET_HANDLE (handle); BTM_TRACE_EVENT0 ("btm_ble_resolve_random_addr_master_cmpl"); if (match_rec) { BTM_TRACE_ERROR0("Random match"); match = TRUE; match_rec->ble.active_addr_type = BTM_BLE_ADDR_RRA; memcpy(match_rec->ble.cur_rand_addr, bda, BD_ADDR_LEN); memcpy(bda, match_rec->bd_addr, BD_ADDR_LEN); } else { BTM_TRACE_ERROR0("Random unmatch"); } btm_ble_connected(bda, handle, HCI_ENCRYPT_MODE_DISABLED, role, bda_type, match); l2cble_conn_comp (handle, role, bda, bda_type, conn_interval, conn_latency, conn_timeout); return; } #endif /******************************************************************************* ** ** Function btm_ble_connected Loading Loading @@ -1516,9 +1586,18 @@ void btm_ble_connected (UINT8 *bda, UINT16 handle, UINT8 enc_mode, UINT8 role, p_dev_rec->hci_handle = handle; p_dev_rec->ble.ble_addr_type = addr_type; p_dev_rec->role_master = FALSE; if (role == HCI_ROLE_MASTER) p_dev_rec->role_master = TRUE; #if (defined BTM_BLE_PRIVACY_SPT && BTM_BLE_PRIVACY_SPT == TRUE) if (!addr_matched) p_dev_rec->ble.active_addr_type = BTM_BLE_ADDR_PSEUDO; if (p_dev_rec->ble.ble_addr_type == BLE_ADDR_RANDOM && !addr_matched) memcpy(p_dev_rec->ble.cur_rand_addr, bda, BD_ADDR_LEN); #endif if (role == HCI_ROLE_SLAVE) p_cb->inq_var.adv_mode = BTM_BLE_ADV_DISABLE; p_cb->inq_var.directed_conn = FALSE; Loading @@ -1534,6 +1613,9 @@ void btm_ble_connected (UINT8 *bda, UINT16 handle, UINT8 enc_mode, UINT8 role, ******************************************************************************/ void btm_ble_conn_complete(UINT8 *p, UINT16 evt_len) { #if (BTM_BLE_PRIVACY_SPT == TRUE ) UINT8 *p_data = p; #endif UINT8 role, status, bda_type; UINT16 handle; BD_ADDR bda; Loading @@ -1548,6 +1630,16 @@ void btm_ble_conn_complete(UINT8 *p, UINT16 evt_len) STREAM_TO_BDADDR (bda, p); if (status == 0) { #if (BTM_BLE_PRIVACY_SPT == TRUE ) /* possiblly receive connection complete with resolvable random on slave role while the device has been paired */ if (!match && BTM_BLE_IS_RESOLVE_BDA(bda)) { btm_ble_resolve_random_addr(bda, btm_ble_resolve_random_addr_on_conn_cmpl, p_data); } else #endif { STREAM_TO_UINT16 (conn_interval, p); STREAM_TO_UINT16 (conn_latency, p); Loading @@ -1558,6 +1650,7 @@ void btm_ble_conn_complete(UINT8 *p, UINT16 evt_len) l2cble_conn_comp (handle, role, bda, bda_type, conn_interval, conn_latency, conn_timeout); } } else { role = HCI_ROLE_UNKNOWN; Loading system/stack/btm/btm_ble_gap.c +59 −1 Original line number Diff line number Diff line Loading @@ -288,6 +288,49 @@ void BTM_RegisterScanReqEvt(tBTM_BLE_SCAN_REQ_CBACK *p_scan_req_cback) #endif } #if BTM_BLE_PRIVACY_SPT == TRUE /******************************************************************************* ** ** Function btm_ble_resolve_random_addr_on_adv ** ** Description resolve random address complete callback. ** ** Returns void ** *******************************************************************************/ static void btm_ble_resolve_random_addr_on_adv(void * p_rec, void *p) { tBTM_SEC_DEV_REC *match_rec = (tBTM_SEC_DEV_REC *) p_rec; UINT8 addr_type = BLE_ADDR_RANDOM; BD_ADDR bda; UINT8 *pp = (UINT8 *)p + 1; UINT8 evt_type; BTM_TRACE_EVENT0 ("btm_ble_resolve_random_addr_on_adv "); STREAM_TO_UINT8 (evt_type, pp); STREAM_TO_UINT8 (addr_type, pp); STREAM_TO_BDADDR (bda, pp); if (match_rec) { BTM_TRACE_ERROR0("Random match"); match_rec->ble.active_addr_type = BTM_BLE_ADDR_RRA; memcpy(match_rec->ble.cur_rand_addr, bda, BD_ADDR_LEN); memcpy(bda, match_rec->bd_addr, BD_ADDR_LEN); addr_type = match_rec->ble.ble_addr_type; } else { BTM_TRACE_ERROR0("Random unmatch"); } btm_ble_process_adv_pkt_cont(bda, addr_type, evt_type, pp); return; } #endif /******************************************************************************* ** ** Function BTM_BleSetBgConnType Loading Loading @@ -1672,6 +1715,9 @@ void btm_ble_process_adv_pkt (UINT8 *p_data) BD_ADDR bda; UINT8 evt_type = 0, *p = p_data; UINT8 addr_type = 0; #if (defined BTM_BLE_PRIVACY_SPT && BTM_BLE_PRIVACY_SPT == TRUE) BOOLEAN match = FALSE; #endif /* always get one device at a time */ p ++; Loading @@ -1698,8 +1744,20 @@ void btm_ble_process_adv_pkt (UINT8 *p_data) btm_cb.ble_ctr_cb.p_select_cback == NULL)) return; #if (defined BTM_BLE_PRIVACY_SPT && BTM_BLE_PRIVACY_SPT == TRUE) #if SMP_INCLUDED == TRUE /* always do RRA resolution on host */ if (!match && BTM_BLE_IS_RESOLVE_BDA(bda)) { btm_ble_resolve_random_addr(bda, btm_ble_resolve_random_addr_on_adv, p_data); } else #endif #endif { btm_ble_process_adv_pkt_cont(bda, addr_type, evt_type, p); } } /******************************************************************************* ** Loading system/stack/btm/btm_int.h +8 −0 Original line number Diff line number Diff line Loading @@ -493,6 +493,14 @@ typedef struct tBLE_ADDR_TYPE ble_addr_type; /* LE device type: public or random address */ tBLE_ADDR_TYPE static_addr_type; /* static address type */ BD_ADDR static_addr; /* static address */ #if BTM_BLE_PRIVACY_SPT == TRUE BD_ADDR cur_rand_addr; /* current random address */ #define BTM_BLE_ADDR_PSEUDO 0 /* address index device record */ #define BTM_BLE_ADDR_RRA 1 /* cur_rand_addr */ #define BTM_BLE_ADDR_STATIC 2 /* static_addr */ UINT8 active_addr_type; #endif #if SMP_INCLUDED == TRUE tBTM_LE_KEY_TYPE key_type; /* bit mask of valid key types in record */ Loading Loading
system/include/bt_target.h +4 −0 Original line number Diff line number Diff line Loading @@ -1407,6 +1407,10 @@ and USER_HW_DISABLE_API macros */ #define LOCAL_BLE_CONTROLLER_ID (1) #endif #ifndef BTM_BLE_PRIVACY_SPT #define BTM_BLE_PRIVACY_SPT TRUE #endif /****************************************************************************** ** ** ATT/GATT Protocol/Profile Settings Loading
system/stack/btm/btm_acl.c +57 −0 Original line number Diff line number Diff line Loading @@ -179,6 +179,59 @@ UINT8 btm_handle_to_acl_index (UINT16 hci_handle) /* If here, no BD Addr found */ return(xx); } #if BTM_BLE_PRIVACY_SPT == TRUE /******************************************************************************* ** ** Function btm_ble_get_acl_remote_addr ** ** Description This function reads the active remote address used for the ** connection. ** ** Returns success return TRUE, otherwise FALSE. ** *******************************************************************************/ BOOLEAN btm_ble_get_acl_remote_addr(tBTM_SEC_DEV_REC *p_dev_rec, BD_ADDR conn_addr, tBLE_ADDR_TYPE *p_addr_type) { #if BLE_INCLUDED == TRUE BOOLEAN st = TRUE; if (p_dev_rec == NULL) { BTM_TRACE_ERROR0("btm_ble_get_acl_remote_addr can not find device with matching address"); return FALSE; } switch (p_dev_rec->ble.active_addr_type) { case BTM_BLE_ADDR_PSEUDO: memcpy(conn_addr, p_dev_rec->bd_addr, BD_ADDR_LEN); * p_addr_type = p_dev_rec->ble.ble_addr_type; break; case BTM_BLE_ADDR_RRA: memcpy(conn_addr, p_dev_rec->ble.cur_rand_addr, BD_ADDR_LEN); * p_addr_type = BLE_ADDR_RANDOM; break; case BTM_BLE_ADDR_STATIC: memcpy(conn_addr, p_dev_rec->ble.static_addr, BD_ADDR_LEN); * p_addr_type = p_dev_rec->ble.static_addr_type; break; default: BTM_TRACE_ERROR1("Unknown active address: %d", p_dev_rec->ble.active_addr_type); st = FALSE; break; } return st; #else return FALSE; #endif } #endif /******************************************************************************* ** ** Function btm_acl_created Loading Loading @@ -298,6 +351,10 @@ void btm_acl_created (BD_ADDR bda, DEV_CLASS dc, BD_NAME bdn, /* If here, features are not known yet */ if (p_dev_rec && is_le_link) { #if BTM_BLE_PRIVACY_SPT == TRUE btm_ble_get_acl_remote_addr (p_dev_rec, p->active_remote_addr, &p->active_remote_addr_type); #endif btm_establish_continue(p); #if (!defined(BTA_SKIP_BLE_READ_REMOTE_FEAT) || BTA_SKIP_BLE_READ_REMOTE_FEAT == FALSE) Loading
system/stack/btm/btm_ble.c +99 −6 Original line number Diff line number Diff line Loading @@ -35,6 +35,9 @@ #include "btm_ble_api.h" #include "smp_api.h" #include "l2c_int.h" #if (defined BLE_BRCM_INCLUDED && BLE_BRCM_INCLUDED == TRUE) #include "brcm_ble.h" #endif #include "gap_api.h" #include "bt_utils.h" Loading Loading @@ -341,12 +344,24 @@ BOOLEAN BTM_ReadRemoteConnectionAddr(BD_ADDR pseudo_addr, BD_ADDR conn_addr, tBL { BOOLEAN st = TRUE; tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev(pseudo_addr); #if BTM_BLE_PRIVACY_SPT == TRUE tACL_CONN *p = btm_bda_to_acl (pseudo_addr); if (p == NULL) { BTM_TRACE_ERROR0("BTM_ReadRemoteConnectionAddr can not find matching address"); return FALSE; } memcpy(conn_addr, p->active_remote_addr, BD_ADDR_LEN); *p_addr_type = p->active_remote_addr_type; #else memcpy(conn_addr, pseudo_addr, BD_ADDR_LEN); if (p_dev_rec != NULL) { *p_addr_type = p_dev_rec->ble.ble_addr_type; } #endif return st; } /******************************************************************************* Loading Loading @@ -1462,6 +1477,61 @@ UINT8 btm_ble_io_capabilities_req(tBTM_SEC_DEV_REC *p_dev_rec, tBTM_LE_IO_REQ *p return callback_rc; } #if (BTM_BLE_PRIVACY_SPT == TRUE ) /******************************************************************************* ** ** Function btm_ble_resolve_random_addr_on_conn_cmpl ** ** Description resolve random address complete on connection complete event. ** ** Returns void ** *******************************************************************************/ static void btm_ble_resolve_random_addr_on_conn_cmpl(void * p_rec, void *p_data) { UINT8 *p = (UINT8 *)p_data; tBTM_SEC_DEV_REC *match_rec = (tBTM_SEC_DEV_REC *) p_rec; UINT8 role, status, bda_type; UINT16 handle; BD_ADDR bda; UINT16 conn_interval, conn_latency, conn_timeout; BOOLEAN match = FALSE; STREAM_TO_UINT8 (status, p); STREAM_TO_UINT16 (handle, p); STREAM_TO_UINT8 (role, p); STREAM_TO_UINT8 (bda_type, p); STREAM_TO_BDADDR (bda, p); STREAM_TO_UINT16 (conn_interval, p); STREAM_TO_UINT16 (conn_latency, p); STREAM_TO_UINT16 (conn_timeout, p); handle = HCID_GET_HANDLE (handle); BTM_TRACE_EVENT0 ("btm_ble_resolve_random_addr_master_cmpl"); if (match_rec) { BTM_TRACE_ERROR0("Random match"); match = TRUE; match_rec->ble.active_addr_type = BTM_BLE_ADDR_RRA; memcpy(match_rec->ble.cur_rand_addr, bda, BD_ADDR_LEN); memcpy(bda, match_rec->bd_addr, BD_ADDR_LEN); } else { BTM_TRACE_ERROR0("Random unmatch"); } btm_ble_connected(bda, handle, HCI_ENCRYPT_MODE_DISABLED, role, bda_type, match); l2cble_conn_comp (handle, role, bda, bda_type, conn_interval, conn_latency, conn_timeout); return; } #endif /******************************************************************************* ** ** Function btm_ble_connected Loading Loading @@ -1516,9 +1586,18 @@ void btm_ble_connected (UINT8 *bda, UINT16 handle, UINT8 enc_mode, UINT8 role, p_dev_rec->hci_handle = handle; p_dev_rec->ble.ble_addr_type = addr_type; p_dev_rec->role_master = FALSE; if (role == HCI_ROLE_MASTER) p_dev_rec->role_master = TRUE; #if (defined BTM_BLE_PRIVACY_SPT && BTM_BLE_PRIVACY_SPT == TRUE) if (!addr_matched) p_dev_rec->ble.active_addr_type = BTM_BLE_ADDR_PSEUDO; if (p_dev_rec->ble.ble_addr_type == BLE_ADDR_RANDOM && !addr_matched) memcpy(p_dev_rec->ble.cur_rand_addr, bda, BD_ADDR_LEN); #endif if (role == HCI_ROLE_SLAVE) p_cb->inq_var.adv_mode = BTM_BLE_ADV_DISABLE; p_cb->inq_var.directed_conn = FALSE; Loading @@ -1534,6 +1613,9 @@ void btm_ble_connected (UINT8 *bda, UINT16 handle, UINT8 enc_mode, UINT8 role, ******************************************************************************/ void btm_ble_conn_complete(UINT8 *p, UINT16 evt_len) { #if (BTM_BLE_PRIVACY_SPT == TRUE ) UINT8 *p_data = p; #endif UINT8 role, status, bda_type; UINT16 handle; BD_ADDR bda; Loading @@ -1548,6 +1630,16 @@ void btm_ble_conn_complete(UINT8 *p, UINT16 evt_len) STREAM_TO_BDADDR (bda, p); if (status == 0) { #if (BTM_BLE_PRIVACY_SPT == TRUE ) /* possiblly receive connection complete with resolvable random on slave role while the device has been paired */ if (!match && BTM_BLE_IS_RESOLVE_BDA(bda)) { btm_ble_resolve_random_addr(bda, btm_ble_resolve_random_addr_on_conn_cmpl, p_data); } else #endif { STREAM_TO_UINT16 (conn_interval, p); STREAM_TO_UINT16 (conn_latency, p); Loading @@ -1558,6 +1650,7 @@ void btm_ble_conn_complete(UINT8 *p, UINT16 evt_len) l2cble_conn_comp (handle, role, bda, bda_type, conn_interval, conn_latency, conn_timeout); } } else { role = HCI_ROLE_UNKNOWN; Loading
system/stack/btm/btm_ble_gap.c +59 −1 Original line number Diff line number Diff line Loading @@ -288,6 +288,49 @@ void BTM_RegisterScanReqEvt(tBTM_BLE_SCAN_REQ_CBACK *p_scan_req_cback) #endif } #if BTM_BLE_PRIVACY_SPT == TRUE /******************************************************************************* ** ** Function btm_ble_resolve_random_addr_on_adv ** ** Description resolve random address complete callback. ** ** Returns void ** *******************************************************************************/ static void btm_ble_resolve_random_addr_on_adv(void * p_rec, void *p) { tBTM_SEC_DEV_REC *match_rec = (tBTM_SEC_DEV_REC *) p_rec; UINT8 addr_type = BLE_ADDR_RANDOM; BD_ADDR bda; UINT8 *pp = (UINT8 *)p + 1; UINT8 evt_type; BTM_TRACE_EVENT0 ("btm_ble_resolve_random_addr_on_adv "); STREAM_TO_UINT8 (evt_type, pp); STREAM_TO_UINT8 (addr_type, pp); STREAM_TO_BDADDR (bda, pp); if (match_rec) { BTM_TRACE_ERROR0("Random match"); match_rec->ble.active_addr_type = BTM_BLE_ADDR_RRA; memcpy(match_rec->ble.cur_rand_addr, bda, BD_ADDR_LEN); memcpy(bda, match_rec->bd_addr, BD_ADDR_LEN); addr_type = match_rec->ble.ble_addr_type; } else { BTM_TRACE_ERROR0("Random unmatch"); } btm_ble_process_adv_pkt_cont(bda, addr_type, evt_type, pp); return; } #endif /******************************************************************************* ** ** Function BTM_BleSetBgConnType Loading Loading @@ -1672,6 +1715,9 @@ void btm_ble_process_adv_pkt (UINT8 *p_data) BD_ADDR bda; UINT8 evt_type = 0, *p = p_data; UINT8 addr_type = 0; #if (defined BTM_BLE_PRIVACY_SPT && BTM_BLE_PRIVACY_SPT == TRUE) BOOLEAN match = FALSE; #endif /* always get one device at a time */ p ++; Loading @@ -1698,8 +1744,20 @@ void btm_ble_process_adv_pkt (UINT8 *p_data) btm_cb.ble_ctr_cb.p_select_cback == NULL)) return; #if (defined BTM_BLE_PRIVACY_SPT && BTM_BLE_PRIVACY_SPT == TRUE) #if SMP_INCLUDED == TRUE /* always do RRA resolution on host */ if (!match && BTM_BLE_IS_RESOLVE_BDA(bda)) { btm_ble_resolve_random_addr(bda, btm_ble_resolve_random_addr_on_adv, p_data); } else #endif #endif { btm_ble_process_adv_pkt_cont(bda, addr_type, evt_type, p); } } /******************************************************************************* ** Loading
system/stack/btm/btm_int.h +8 −0 Original line number Diff line number Diff line Loading @@ -493,6 +493,14 @@ typedef struct tBLE_ADDR_TYPE ble_addr_type; /* LE device type: public or random address */ tBLE_ADDR_TYPE static_addr_type; /* static address type */ BD_ADDR static_addr; /* static address */ #if BTM_BLE_PRIVACY_SPT == TRUE BD_ADDR cur_rand_addr; /* current random address */ #define BTM_BLE_ADDR_PSEUDO 0 /* address index device record */ #define BTM_BLE_ADDR_RRA 1 /* cur_rand_addr */ #define BTM_BLE_ADDR_STATIC 2 /* static_addr */ UINT8 active_addr_type; #endif #if SMP_INCLUDED == TRUE tBTM_LE_KEY_TYPE key_type; /* bit mask of valid key types in record */ Loading