/*
|
* Licensed to the Apache Software Foundation (ASF) under one
|
* or more contributor license agreements. See the NOTICE file
|
* distributed with this work for additional information
|
* regarding copyright ownership. The ASF licenses this file
|
* to you under the Apache License, Version 2.0 (the
|
* "License"); you may not use this file except in compliance
|
* with the License. You may obtain a copy of the License at
|
*
|
* http://www.apache.org/licenses/LICENSE-2.0
|
*
|
* Unless required by applicable law or agreed to in writing,
|
* software distributed under the License is distributed on an
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
* KIND, either express or implied. See the License for the
|
* specific language governing permissions and limitations
|
* under the License.
|
*/
|
|
#include <string.h>
|
#include "host/ble_hs_id.h"
|
#include "ble_hs_priv.h"
|
|
static uint8_t ble_hs_id_pub[6];
|
static uint8_t ble_hs_id_rnd[6];
|
|
void
|
ble_hs_id_set_pub(const uint8_t *pub_addr)
|
{
|
ble_hs_lock();
|
memcpy(ble_hs_id_pub, pub_addr, 6);
|
ble_hs_unlock();
|
}
|
|
int
|
ble_hs_id_gen_rnd(int nrpa, ble_addr_t *out_addr)
|
{
|
int rc;
|
|
out_addr->type = BLE_ADDR_RANDOM;
|
|
rc = ble_hs_hci_util_rand(out_addr->val, 6);
|
if (rc != 0) {
|
return rc;
|
}
|
|
if (nrpa) {
|
out_addr->val[5] &= ~0xc0;
|
} else {
|
out_addr->val[5] |= 0xc0;
|
}
|
|
return 0;
|
}
|
|
int
|
ble_hs_id_set_rnd(const uint8_t *rnd_addr)
|
{
|
uint8_t addr_type_byte;
|
int rc;
|
int ones;
|
|
ble_hs_lock();
|
|
/* Make sure random part of rnd_addr is not all ones or zeros. Reference:
|
* Core v5.0, Vol 6, Part B, section 1.3.2.1 */
|
addr_type_byte = rnd_addr[5] & 0xc0;
|
|
/* count bits set to 1 in random part of address */
|
ones = __builtin_popcount(rnd_addr[0]);
|
ones += __builtin_popcount(rnd_addr[1]);
|
ones += __builtin_popcount(rnd_addr[2]);
|
ones += __builtin_popcount(rnd_addr[3]);
|
ones += __builtin_popcount(rnd_addr[4]);
|
ones += __builtin_popcount(rnd_addr[5] & 0x3f);
|
|
if ((addr_type_byte != 0x00 && addr_type_byte != 0xc0) ||
|
(ones == 0 || ones == 46)) {
|
rc = BLE_HS_EINVAL;
|
goto done;
|
}
|
|
rc = ble_hs_hci_util_set_random_addr(rnd_addr);
|
if (rc != 0) {
|
goto done;
|
}
|
|
memcpy(ble_hs_id_rnd, rnd_addr, 6);
|
|
done:
|
ble_hs_unlock();
|
return rc;
|
}
|
|
/**
|
* Retrieves one of the device's identity addresses. The device can have two
|
* identity addresses: one public and one random. The id_addr_type argument
|
* specifies which of these two addresses to retrieve.
|
*
|
* @param id_addr_type The type of identity address to retrieve.
|
* Valid values are:
|
* o BLE_ADDR_PUBLIC
|
* o BLE_ADDR_RANDOM
|
* @param out_id_addr On success, this is reseated to point to the
|
* retrieved 6-byte identity address. Pass
|
* NULL if you do not require this
|
* information.
|
|
* @param out_is_nrpa On success, the pointed-to value indicates
|
* whether the retrieved address is a
|
* non-resolvable private address. Pass NULL
|
* if you do not require this information.
|
*
|
* @return 0 on success;
|
* BLE_HS_EINVAL if an invalid address type was
|
* specified;
|
* BLE_HS_ENOADDR if the device does not have an
|
* identity address of the requested type;
|
* Other BLE host core code on error.
|
*/
|
int
|
ble_hs_id_addr(uint8_t id_addr_type, const uint8_t **out_id_addr,
|
int *out_is_nrpa)
|
{
|
const uint8_t *id_addr;
|
int nrpa;
|
|
BLE_HS_DBG_ASSERT(ble_hs_locked_by_cur_task());
|
|
switch (id_addr_type) {
|
case BLE_ADDR_PUBLIC:
|
id_addr = ble_hs_id_pub;
|
nrpa = 0;
|
break;
|
|
case BLE_ADDR_RANDOM:
|
id_addr = ble_hs_id_rnd;
|
nrpa = (ble_hs_id_rnd[5] & 0xc0) == 0;
|
break;
|
|
default:
|
return BLE_HS_EINVAL;
|
}
|
|
if (memcmp(id_addr, ble_hs_misc_null_addr, 6) == 0) {
|
return BLE_HS_ENOADDR;
|
}
|
|
if (out_id_addr != NULL) {
|
*out_id_addr = id_addr;
|
}
|
if (out_is_nrpa != NULL) {
|
*out_is_nrpa = nrpa;
|
}
|
|
return 0;
|
}
|
|
int
|
ble_hs_id_copy_addr(uint8_t id_addr_type, uint8_t *out_id_addr,
|
int *out_is_nrpa)
|
{
|
const uint8_t *addr;
|
int rc;
|
|
ble_hs_lock();
|
|
rc = ble_hs_id_addr(id_addr_type, &addr, out_is_nrpa);
|
if (rc == 0 && out_id_addr != NULL) {
|
memcpy(out_id_addr, addr, 6);
|
}
|
|
ble_hs_unlock();
|
|
return rc;
|
}
|
|
static int
|
ble_hs_id_addr_type_usable(uint8_t own_addr_type)
|
{
|
uint8_t id_addr_type;
|
int nrpa;
|
int rc;
|
|
switch (own_addr_type) {
|
case BLE_OWN_ADDR_PUBLIC:
|
case BLE_OWN_ADDR_RANDOM:
|
rc = ble_hs_id_addr(own_addr_type, NULL, NULL);
|
if (rc != 0) {
|
return rc;
|
}
|
break;
|
|
case BLE_OWN_ADDR_RPA_PUBLIC_DEFAULT:
|
case BLE_OWN_ADDR_RPA_RANDOM_DEFAULT:
|
id_addr_type = ble_hs_misc_own_addr_type_to_id(own_addr_type);
|
rc = ble_hs_id_addr(id_addr_type, NULL, &nrpa);
|
if (rc != 0) {
|
return rc;
|
}
|
if (nrpa) {
|
return BLE_HS_ENOADDR;
|
}
|
break;
|
|
default:
|
return BLE_HS_EINVAL;
|
}
|
|
return 0;
|
}
|
|
int
|
ble_hs_id_use_addr(uint8_t own_addr_type)
|
{
|
int rc;
|
|
rc = ble_hs_id_addr_type_usable(own_addr_type);
|
if (rc != 0) {
|
return rc;
|
}
|
|
/* If privacy is being used, make sure RPA rotation is in effect. */
|
if (own_addr_type == BLE_OWN_ADDR_RPA_PUBLIC_DEFAULT ||
|
own_addr_type == BLE_OWN_ADDR_RPA_RANDOM_DEFAULT) {
|
|
rc = ble_hs_pvcy_ensure_started();
|
if (rc != 0) {
|
return rc;
|
}
|
}
|
|
return 0;
|
}
|
|
int
|
ble_hs_id_infer_auto(int privacy, uint8_t *out_addr_type)
|
{
|
static const uint8_t pub_addr_types[] = {
|
BLE_OWN_ADDR_RANDOM,
|
BLE_OWN_ADDR_PUBLIC,
|
};
|
static const uint8_t priv_addr_types[] = {
|
BLE_OWN_ADDR_RPA_RANDOM_DEFAULT,
|
BLE_OWN_ADDR_RPA_PUBLIC_DEFAULT,
|
};
|
const uint8_t *addr_types;
|
uint8_t addr_type;
|
int num_addr_types;
|
int rc;
|
int i;
|
|
ble_hs_lock();
|
|
if (privacy) {
|
addr_types = priv_addr_types;
|
num_addr_types = sizeof priv_addr_types / sizeof priv_addr_types[0];
|
} else {
|
addr_types = pub_addr_types;
|
num_addr_types = sizeof pub_addr_types / sizeof pub_addr_types[0];
|
}
|
|
for (i = 0; i < num_addr_types; i++) {
|
addr_type = addr_types[i];
|
|
rc = ble_hs_id_addr_type_usable(addr_type);
|
switch (rc) {
|
case 0:
|
*out_addr_type = addr_type;
|
goto done;
|
|
case BLE_HS_ENOADDR:
|
break;
|
|
default:
|
goto done;
|
}
|
}
|
|
rc = BLE_HS_ENOADDR;
|
|
done:
|
ble_hs_unlock();
|
return rc;
|
}
|
|
/**
|
* Clears both the public and random addresses. This function is necessary
|
* when the controller loses its random address (e.g., on a stack reset).
|
*/
|
void
|
ble_hs_id_reset(void)
|
{
|
memset(ble_hs_id_pub, 0, sizeof ble_hs_id_pub);
|
memset(ble_hs_id_rnd, 0, sizeof ble_hs_id_pub);
|
}
|
|
/**
|
* Clears random address. This function is necessary when the host wants to
|
* clear random address.
|
*/
|
void
|
ble_hs_id_rnd_reset(void)
|
{
|
memset(ble_hs_id_rnd, 0, sizeof ble_hs_id_rnd);
|
}
|