You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@mynewt.apache.org by will sanfilippo <wi...@runtime.io> on 2017/03/31 22:49:05 UTC

Adding platform specific API to get public and/or random static address

Hello:

There has been some discussion of this already on the list but nothing has been done yet so I wanted to resurrect the conversation with some proposals.

What we are trying to do here is the following:
1) Have the controller get a public device address without it being hardcoded.
2) Have the ability to read a chip-specific random static address if the chip has one programmed.

The proposal is the following:

1) Add two new API. These will be platform specific and will be placed in the ble_hw.c file:

/* These API will return -1 if no address available. If available, will return 0 and will place the address in *addr */
int ble_hw_get_public_addr(ble_addr_t *addr)
int ble_hw_get_static_addr(ble_addr_t *addr)

2) Add a syscfg variable to the controller which will allow the developer to set a public address of their choosing. By default this will be all 0 (no public address). More on this below.

3) The ble_hw_get_public_addr function will do the following:
* If the user has overridden the default public address (the syscfg variable) with a non-zero public address, that address will be returned by this function.
* If the default public address in the syscfg is all zero, the code will read FICR and check if the device address type in the FICR is public. If so, it means the nordic chip was factory programmed with a public address and this will be used.
* If both of the above checks fail, the code will read UICR[0] and UICR[1] to see if a public address has been programmed into the UICR. We are doing this to make it easy for folks to program their development kits with public addresses so they do not have to hardcode them. UICR[0] will contain the least significant 4 bytes of the device address. UICR[1] will contain the most significant two bytes. The upper 16 bits of this word should be set to 0. The API will presume that this is a valid public device address as long as the upper 16-bits of this 32-bit word are all zero. We will also check to see if this is a valid public address (see below). If both UICR[0] and UICR[1] are zero, this will not be considered a valid public address.

A note on valid public addresses. Not sure if I got this right, but I think the two least significant bits of the most significant byte of the public address should be zero. I think I will check this to make sure it is valid.

4) The ble_hw_get_static_addr() will do the following:
* Read the FICR to see if there is a random address in the FICR. This is the default programming of the nrf51dk and nrf52dk. Unless you have them program a public device address in the FICR, it will have a random address.
* If the chip does not have a random address the API returns -1.

Some things about writing apps and the BLE spec:
1) I realize that it is the host that tells the controller the random address to use. The controller will NOT automatically use the random address from ble_hw_get_static_addr(). That API will be added as a convenience so that the app developer does not have to generate their own. If the app wants to use this random address it needs to tell the controller to use it using LE_Set_Random_Addr.

2) Regarding the public device address. We have an app called bletiny that can set the public device address I think. If the above gets approved we are going to remove g_dev_addr from the code; it will be kept in the controller and not available globally. The Zephyr project is considering adding vendor specific HCI commands, one of which is “set public device address”. I think if we go with the above approach we should add this vendor specific command and that should be the way an app can set the public device address if it so chooses.

Comments/suggestions?

Re: Adding platform specific API to get public and/or random static address

Posted by will sanfilippo <wi...@runtime.io>.
Yep, except for one typo: ble_hw_get_public_addr() instead of ble_hs_get_public_addr().

I should have mentioned that, assuming we agree to this, the controller code will call that API and the host should not call it. I mentioned this API in case someone wants to modify how it works for them.

Thanks for clarifying that! (and reading that long email)

Will

> On Mar 31, 2017, at 4:28 PM, Christopher Collins <ch...@runtime.io> wrote:
> 
> On Fri, Mar 31, 2017 at 03:49:05PM -0700, will sanfilippo wrote:
>> Hello:
>> 
>> There has been some discussion of this already on the list but nothing has been done yet so I wanted to resurrect the conversation with some proposals.
>> 
>> What we are trying to do here is the following:
>> 1) Have the controller get a public device address without it being hardcoded.
>> 2) Have the ability to read a chip-specific random static address if the chip has one programmed.
>> 
>> The proposal is the following:
> 
>> 1) Add two new API. These will be platform specific and will be placed
>> in the ble_hw.c file:
> 
>> /* These API will return -1 if no address available. If available, will
>> return 0
>> and will place the address in *addr */
>> int ble_hw_get_public_addr(ble_addr_t *addr)
>> int ble_hw_get_static_addr(ble_addr_t *addr)
> 
> [...]
> 
> That sounds good to me.  This covers all the use cases I can think of.
> 
> As you mentioned, Bluetooth is somewhat asymmetric regarding public and
> random addresses.  The controller is in charge of the public address
> while the host is in charge of the static random address.
> 
> With the API you proposed, I think the workflow would look something
> like this:
> 
> 1. At init time, controller calls ble_hs_get_public_addr().  If this
> call yields an address, the controller configures itself to use it.
> 
> 2. If app wants a static random address, it calls
> ble_hw_get_static_addr().  If a random address is available, the
> application configures the host to use it with a call to
> ble_hs_id_set_rnd().
> 
> Does that sound about right?
> 
> In thinking about this, I realized the host interface is missing
> something.  There is currently no way for an application to ask the host
> for its public address.  An application may want to know this to
> determine if it should configure a random address (or just for
> reporting purposes).  The host does know its own public address--it gets
> it from the controller at startup--it just doesn't expose it to the
> application.
> 
> Chris


Re: Adding platform specific API to get public and/or random static address

Posted by Christopher Collins <ch...@runtime.io>.
On Fri, Mar 31, 2017 at 03:49:05PM -0700, will sanfilippo wrote:
> Hello:
> 
> There has been some discussion of this already on the list but nothing has been done yet so I wanted to resurrect the conversation with some proposals.
> 
> What we are trying to do here is the following:
> 1) Have the controller get a public device address without it being hardcoded.
> 2) Have the ability to read a chip-specific random static address if the chip has one programmed.
> 
> The proposal is the following:

> 1) Add two new API. These will be platform specific and will be placed
> in the ble_hw.c file:

> /* These API will return -1 if no address available. If available, will
> return 0
> and will place the address in *addr */
> int ble_hw_get_public_addr(ble_addr_t *addr)
> int ble_hw_get_static_addr(ble_addr_t *addr)

[...]

That sounds good to me.  This covers all the use cases I can think of.

As you mentioned, Bluetooth is somewhat asymmetric regarding public and
random addresses.  The controller is in charge of the public address
while the host is in charge of the static random address.

With the API you proposed, I think the workflow would look something
like this:

1. At init time, controller calls ble_hs_get_public_addr().  If this
call yields an address, the controller configures itself to use it.

2. If app wants a static random address, it calls
ble_hw_get_static_addr().  If a random address is available, the
application configures the host to use it with a call to
ble_hs_id_set_rnd().

Does that sound about right?

In thinking about this, I realized the host interface is missing
something.  There is currently no way for an application to ask the host
for its public address.  An application may want to know this to
determine if it should configure a random address (or just for
reporting purposes).  The host does know its own public address--it gets
it from the controller at startup--it just doesn't expose it to the
application.

Chris

Re: Adding platform specific API to get public and/or random static address

Posted by will sanfilippo <wi...@runtime.io>.
Marcel:

Thanks for the clarification on the public address and that for BLE the two LSbits of the MSbyte do not apply. I do understand the trickiness of changing the public address but it is certainly helpful for debugging/testing.


> On Apr 3, 2017, at 9:38 AM, Marcel Holtmann <ma...@holtmann.org> wrote:
> 
> Hi Will,
> 
>>>> There has been some discussion of this already on the list but nothing has been done yet so I wanted to resurrect the conversation with some proposals.
>>>> 
>>>> What we are trying to do here is the following:
>>>> 1) Have the controller get a public device address without it being hardcoded.
>>>> 2) Have the ability to read a chip-specific random static address if the chip has one programmed.
>>>> 
>>>> The proposal is the following:
>>>> 
>>>> 1) Add two new API. These will be platform specific and will be placed in the ble_hw.c file:
>>>> 
>>>> /* These API will return -1 if no address available. If available, will return 0 and will place the address in *addr */
>>>> int ble_hw_get_public_addr(ble_addr_t *addr)
>>>> int ble_hw_get_static_addr(ble_addr_t *addr)
>>>> 
>>>> 2) Add a syscfg variable to the controller which will allow the developer to set a public address of their choosing. By default this will be all 0 (no public address). More on this below.
>>>> 
>>>> 3) The ble_hw_get_public_addr function will do the following:
>>>> * If the user has overridden the default public address (the syscfg variable) with a non-zero public address, that address will be returned by this function.
>>>> * If the default public address in the syscfg is all zero, the code will read FICR and check if the device address type in the FICR is public. If so, it means the nordic chip was factory programmed with a public address and this will be used.
>>>> * If both of the above checks fail, the code will read UICR[0] and UICR[1] to see if a public address has been programmed into the UICR. We are doing this to make it easy for folks to program their development kits with public addresses so they do not have to hardcode them. UICR[0] will contain the least significant 4 bytes of the device address. UICR[1] will contain the most significant two bytes. The upper 16 bits of this word should be set to 0. The API will presume that this is a valid public device address as long as the upper 16-bits of this 32-bit word are all zero. We will also check to see if this is a valid public address (see below). If both UICR[0] and UICR[1] are zero, this will not be considered a valid public address.
>>>> 
>>>> A note on valid public addresses. Not sure if I got this right, but I think the two least significant bits of the most significant byte of the public address should be zero. I think I will check this to make sure it is valid.
>>> 
>>> you got that wrong. The public address is a BD_ADDR (6 octets) and the random address is that (also 6 octets). If you just get 6 octets, you can not differentiate if it is public or random. That is why I keep that LE addresses are actually 49 bits instead. There is "out-of-band” telling if its public or random.
>>> 
>> The above comment is not based on the BLE specification, it is based on the IEEE standard which says that the two LSbit’s of the MSbyte are the universally/locally administered addres bit and the indiviual/group address bit. I was presuming that both of these bits need to be zero but was not sure. I was only referring to public addresses here.
> 
> the BD_ADDR usage and its relation to IEEE is defined in the standard. The bits and its assignment are irrelevant since it is treated as 6 octets (defined as 3 parts). But that is for BR/EDR only. For LE it is just a 6 octet value marked as public address.
> 
>>> As far I know the FICR is just a 6 octet random value. It is neither a public address or a static random address (you are after the static after all since NRPAs and RPAs are different as well). So you even need to mask the upper 2 bits correctly to make FICR a static address.
>> 
>> Marcel: you are incorrect I Ibelieve. I should have been more specific. There is a DEVICEADDRTYPE register in the FICR which says whether the address is public or random. The code was going to read that register to determine if the address in the FICR was public or random. I do not expect that register being set to public but if it is, the adress in the next two FICR registers should be the public address.
> 
> Good to know. If that is set to public address, then HCI_Read_BD_ADDR should return that value.
> 
>>> 
>>>> 4) The ble_hw_get_static_addr() will do the following:
>>>> * Read the FICR to see if there is a random address in the FICR. This is the default programming of the nrf51dk and nrf52dk. Unless you have them program a public device address in the FICR, it will have a random address.
>>>> * If the chip does not have a random address the API returns -1.
>>> 
>>> See my comment above, the FICR is just 6 octets random data. It is surely not a public address. It can never be since that requires to follow IEEE assignment rules. And it is no static address either. It needs to be masked correctly first. It is just a persistence 6 octets of randomness from manufacturing.
>> I know it is not a public address! Well, it is not a public address if the DEVICEADDRTYPE says it is not. I was merely trying to point out the possibility that there is not a random address here. And yes, I have read the nordic devzone and I know I need to set the upper two bits accordingly.  I skipped that because I already know this and would not have a returned the address with those bits not being set. I even posted on the nordic devzone to get clarification on this. But I should have mentioned it here.
>>> 
>>>> Some things about writing apps and the BLE spec:
>>>> 1) I realize that it is the host that tells the controller the random address to use. The controller will NOT automatically use the random address from ble_hw_get_static_addr(). That API will be added as a convenience so that the app developer does not have to generate their own. If the app wants to use this random address it needs to tell the controller to use it using LE_Set_Random_Addr.
>>>> 
>>>> 2) Regarding the public device address. We have an app called bletiny that can set the public device address I think. If the above gets approved we are going to remove g_dev_addr from the code; it will be kept in the controller and not available globally. The Zephyr project is considering adding vendor specific HCI commands, one of which is “set public device address”. I think if we go with the above approach we should add this vendor specific command and that should be the way an app can set the public device address if it so chooses.
>>> 
>>> The public BD_ADDR needs to be inside the controller before the call of HCI_Reset. Otherwise all sort of assumptions on HCI break. Until then the HCI_Read_BD_ADDR has to return 00:00:00:00:00:00 to indicate the controller has no public address. Switching the BD_ADDR mid-flight with a backdoor is going to fail in the most funny ways left and right.
>>> 
>> Was I wrong about this? I thought that one of the vendor specific additions was to set the public address? If not
> 
> The Bluetooth Core spec does not have any provision for ever changing the BD_ADDR. However certain needs of NVM storage forced us to have the address in the host storage area instead of the controller.
> 
> So changing the address is an option that almost any controller supports. However it comes with certain restrictions. That is why almost every manufacturer binds it actual active change to HCI_Reset happening. Changning it mid flight is dangerous.
> 
> Regards
> 
> Marcel
> 


Re: Adding platform specific API to get public and/or random static address

Posted by Marcel Holtmann <ma...@holtmann.org>.
Hi Will,

>>> There has been some discussion of this already on the list but nothing has been done yet so I wanted to resurrect the conversation with some proposals.
>>> 
>>> What we are trying to do here is the following:
>>> 1) Have the controller get a public device address without it being hardcoded.
>>> 2) Have the ability to read a chip-specific random static address if the chip has one programmed.
>>> 
>>> The proposal is the following:
>>> 
>>> 1) Add two new API. These will be platform specific and will be placed in the ble_hw.c file:
>>> 
>>> /* These API will return -1 if no address available. If available, will return 0 and will place the address in *addr */
>>> int ble_hw_get_public_addr(ble_addr_t *addr)
>>> int ble_hw_get_static_addr(ble_addr_t *addr)
>>> 
>>> 2) Add a syscfg variable to the controller which will allow the developer to set a public address of their choosing. By default this will be all 0 (no public address). More on this below.
>>> 
>>> 3) The ble_hw_get_public_addr function will do the following:
>>> * If the user has overridden the default public address (the syscfg variable) with a non-zero public address, that address will be returned by this function.
>>> * If the default public address in the syscfg is all zero, the code will read FICR and check if the device address type in the FICR is public. If so, it means the nordic chip was factory programmed with a public address and this will be used.
>>> * If both of the above checks fail, the code will read UICR[0] and UICR[1] to see if a public address has been programmed into the UICR. We are doing this to make it easy for folks to program their development kits with public addresses so they do not have to hardcode them. UICR[0] will contain the least significant 4 bytes of the device address. UICR[1] will contain the most significant two bytes. The upper 16 bits of this word should be set to 0. The API will presume that this is a valid public device address as long as the upper 16-bits of this 32-bit word are all zero. We will also check to see if this is a valid public address (see below). If both UICR[0] and UICR[1] are zero, this will not be considered a valid public address.
>>> 
>>> A note on valid public addresses. Not sure if I got this right, but I think the two least significant bits of the most significant byte of the public address should be zero. I think I will check this to make sure it is valid.
>> 
>> you got that wrong. The public address is a BD_ADDR (6 octets) and the random address is that (also 6 octets). If you just get 6 octets, you can not differentiate if it is public or random. That is why I keep that LE addresses are actually 49 bits instead. There is "out-of-band” telling if its public or random.
>> 
> The above comment is not based on the BLE specification, it is based on the IEEE standard which says that the two LSbit’s of the MSbyte are the universally/locally administered addres bit and the indiviual/group address bit. I was presuming that both of these bits need to be zero but was not sure. I was only referring to public addresses here.

the BD_ADDR usage and its relation to IEEE is defined in the standard. The bits and its assignment are irrelevant since it is treated as 6 octets (defined as 3 parts). But that is for BR/EDR only. For LE it is just a 6 octet value marked as public address.

>> As far I know the FICR is just a 6 octet random value. It is neither a public address or a static random address (you are after the static after all since NRPAs and RPAs are different as well). So you even need to mask the upper 2 bits correctly to make FICR a static address.
> 
> Marcel: you are incorrect I Ibelieve. I should have been more specific. There is a DEVICEADDRTYPE register in the FICR which says whether the address is public or random. The code was going to read that register to determine if the address in the FICR was public or random. I do not expect that register being set to public but if it is, the adress in the next two FICR registers should be the public address.

Good to know. If that is set to public address, then HCI_Read_BD_ADDR should return that value.

>> 
>>> 4) The ble_hw_get_static_addr() will do the following:
>>> * Read the FICR to see if there is a random address in the FICR. This is the default programming of the nrf51dk and nrf52dk. Unless you have them program a public device address in the FICR, it will have a random address.
>>> * If the chip does not have a random address the API returns -1.
>> 
>> See my comment above, the FICR is just 6 octets random data. It is surely not a public address. It can never be since that requires to follow IEEE assignment rules. And it is no static address either. It needs to be masked correctly first. It is just a persistence 6 octets of randomness from manufacturing.
> I know it is not a public address! Well, it is not a public address if the DEVICEADDRTYPE says it is not. I was merely trying to point out the possibility that there is not a random address here. And yes, I have read the nordic devzone and I know I need to set the upper two bits accordingly.  I skipped that because I already know this and would not have a returned the address with those bits not being set. I even posted on the nordic devzone to get clarification on this. But I should have mentioned it here.
>> 
>>> Some things about writing apps and the BLE spec:
>>> 1) I realize that it is the host that tells the controller the random address to use. The controller will NOT automatically use the random address from ble_hw_get_static_addr(). That API will be added as a convenience so that the app developer does not have to generate their own. If the app wants to use this random address it needs to tell the controller to use it using LE_Set_Random_Addr.
>>> 
>>> 2) Regarding the public device address. We have an app called bletiny that can set the public device address I think. If the above gets approved we are going to remove g_dev_addr from the code; it will be kept in the controller and not available globally. The Zephyr project is considering adding vendor specific HCI commands, one of which is “set public device address”. I think if we go with the above approach we should add this vendor specific command and that should be the way an app can set the public device address if it so chooses.
>> 
>> The public BD_ADDR needs to be inside the controller before the call of HCI_Reset. Otherwise all sort of assumptions on HCI break. Until then the HCI_Read_BD_ADDR has to return 00:00:00:00:00:00 to indicate the controller has no public address. Switching the BD_ADDR mid-flight with a backdoor is going to fail in the most funny ways left and right.
>> 
> Was I wrong about this? I thought that one of the vendor specific additions was to set the public address? If not

The Bluetooth Core spec does not have any provision for ever changing the BD_ADDR. However certain needs of NVM storage forced us to have the address in the host storage area instead of the controller.

So changing the address is an option that almost any controller supports. However it comes with certain restrictions. That is why almost every manufacturer binds it actual active change to HCI_Reset happening. Changning it mid flight is dangerous.

Regards

Marcel


Re: Adding platform specific API to get public and/or random static address

Posted by will sanfilippo <wi...@runtime.io>.
Comments inline:

> On Apr 1, 2017, at 12:53 AM, Marcel Holtmann <ma...@holtmann.org> wrote:
> 
> Hi Will,
> 
>> There has been some discussion of this already on the list but nothing has been done yet so I wanted to resurrect the conversation with some proposals.
>> 
>> What we are trying to do here is the following:
>> 1) Have the controller get a public device address without it being hardcoded.
>> 2) Have the ability to read a chip-specific random static address if the chip has one programmed.
>> 
>> The proposal is the following:
>> 
>> 1) Add two new API. These will be platform specific and will be placed in the ble_hw.c file:
>> 
>> /* These API will return -1 if no address available. If available, will return 0 and will place the address in *addr */
>> int ble_hw_get_public_addr(ble_addr_t *addr)
>> int ble_hw_get_static_addr(ble_addr_t *addr)
>> 
>> 2) Add a syscfg variable to the controller which will allow the developer to set a public address of their choosing. By default this will be all 0 (no public address). More on this below.
>> 
>> 3) The ble_hw_get_public_addr function will do the following:
>> * If the user has overridden the default public address (the syscfg variable) with a non-zero public address, that address will be returned by this function.
>> * If the default public address in the syscfg is all zero, the code will read FICR and check if the device address type in the FICR is public. If so, it means the nordic chip was factory programmed with a public address and this will be used.
>> * If both of the above checks fail, the code will read UICR[0] and UICR[1] to see if a public address has been programmed into the UICR. We are doing this to make it easy for folks to program their development kits with public addresses so they do not have to hardcode them. UICR[0] will contain the least significant 4 bytes of the device address. UICR[1] will contain the most significant two bytes. The upper 16 bits of this word should be set to 0. The API will presume that this is a valid public device address as long as the upper 16-bits of this 32-bit word are all zero. We will also check to see if this is a valid public address (see below). If both UICR[0] and UICR[1] are zero, this will not be considered a valid public address.
>> 
>> A note on valid public addresses. Not sure if I got this right, but I think the two least significant bits of the most significant byte of the public address should be zero. I think I will check this to make sure it is valid.
> 
> you got that wrong. The public address is a BD_ADDR (6 octets) and the random address is that (also 6 octets). If you just get 6 octets, you can not differentiate if it is public or random. That is why I keep that LE addresses are actually 49 bits instead. There is "out-of-band” telling if its public or random.
> 
The above comment is not based on the BLE specification, it is based on the IEEE standard which says that the two LSbit’s of the MSbyte are the universally/locally administered addres bit and the indiviual/group address bit. I was presuming that both of these bits need to be zero but was not sure. I was only referring to public addresses here.

> As far I know the FICR is just a 6 octet random value. It is neither a public address or a static random address (you are after the static after all since NRPAs and RPAs are different as well). So you even need to mask the upper 2 bits correctly to make FICR a static address.

Marcel: you are incorrect I Ibelieve. I should have been more specific. There is a DEVICEADDRTYPE register in the FICR which says whether the address is public or random. The code was going to read that register to determine if the address in the FICR was public or random. I do not expect that register being set to public but if it is, the adress in the next two FICR registers should be the public address.
> 
>> 4) The ble_hw_get_static_addr() will do the following:
>> * Read the FICR to see if there is a random address in the FICR. This is the default programming of the nrf51dk and nrf52dk. Unless you have them program a public device address in the FICR, it will have a random address.
>> * If the chip does not have a random address the API returns -1.
> 
> See my comment above, the FICR is just 6 octets random data. It is surely not a public address. It can never be since that requires to follow IEEE assignment rules. And it is no static address either. It needs to be masked correctly first. It is just a persistence 6 octets of randomness from manufacturing.
I know it is not a public address! Well, it is not a public address if the DEVICEADDRTYPE says it is not. I was merely trying to point out the possibility that there is not a random address here. And yes, I have read the nordic devzone and I know I need to set the upper two bits accordingly.  I skipped that because I already know this and would not have a returned the address with those bits not being set. I even posted on the nordic devzone to get clarification on this. But I should have mentioned it here.
> 
>> Some things about writing apps and the BLE spec:
>> 1) I realize that it is the host that tells the controller the random address to use. The controller will NOT automatically use the random address from ble_hw_get_static_addr(). That API will be added as a convenience so that the app developer does not have to generate their own. If the app wants to use this random address it needs to tell the controller to use it using LE_Set_Random_Addr.
>> 
>> 2) Regarding the public device address. We have an app called bletiny that can set the public device address I think. If the above gets approved we are going to remove g_dev_addr from the code; it will be kept in the controller and not available globally. The Zephyr project is considering adding vendor specific HCI commands, one of which is “set public device address”. I think if we go with the above approach we should add this vendor specific command and that should be the way an app can set the public device address if it so chooses.
> 
> The public BD_ADDR needs to be inside the controller before the call of HCI_Reset. Otherwise all sort of assumptions on HCI break. Until then the HCI_Read_BD_ADDR has to return 00:00:00:00:00:00 to indicate the controller has no public address. Switching the BD_ADDR mid-flight with a backdoor is going to fail in the most funny ways left and right.
> 
Was I wrong about this? I thought that one of the vendor specific additions was to set the public address? If not
> Regards
> 
> Marcel
> 


Re: Adding platform specific API to get public and/or random static address

Posted by will sanfilippo <wi...@runtime.io>.
Setting the public address from the host came from two things: bletiny and also my recollection of one of the vendor specific HCI commands that was discussed at Linaro Connect in Budapest this past March. I am trying to find the document we discussed in Budapest to confirm that this was one of the commands.

Of course I realize the possible issues with setting a public device address “on the fly”. However, it should be quite possible to do this and not all that tricky, assuming the controller is not doing anything at the time.

If no one thinks that having this capability is useful I am fine not including it.

> On Apr 1, 2017, at 8:03 AM, Christopher Collins <ch...@runtime.io> wrote:
> 
> On Sat, Apr 01, 2017 at 09:53:03AM +0200, Marcel Holtmann wrote:
>>> Some things about writing apps and the BLE spec:
>>> 1) I realize that it is the host that tells the controller the
>>> random address to use. The controller will NOT automatically use the
>>> random address from ble_hw_get_static_addr(). That API will be added
>>> as a convenience so that the app developer does not have to generate
>>> their own. If the app wants to use this random address it needs to
>>> tell the controller to use it using LE_Set_Random_Addr.
>>> 
>>> 2) Regarding the public device address. We have an app called
>>> bletiny that can set the public device address I think. If the above
>>> gets approved we are going to remove g_dev_addr from the code; it
>>> will be kept in the controller and not available globally. The
>>> Zephyr project is considering adding vendor specific HCI commands,
>>> one of which is “set public device address”. I think if we go with
>>> the above approach we should add this vendor specific command and
>>> that should be the way an app can set the public device address if
>>> it so chooses.
>> 
>> The public BD_ADDR needs to be inside the controller before the call
>> of HCI_Reset. Otherwise all sort of assumptions on HCI break. Until
>> then the HCI_Read_BD_ADDR has to return 00:00:00:00:00:00 to indicate
>> the controller has no public address. Switching the BD_ADDR mid-flight
>> with a backdoor is going to fail in the most funny ways left and
>> right.
> 
> The bletiny app is a sandbox test tool, and it does some things that a
> more robust application shouldn't do.  One such underhanded thing it
> does is change its own public address whenever the user requests it.  It
> does this by simply overwriting the global public address byte array and
> hoping for the best.  In practice, I've never seen anything funny
> happen, either to the left or the right :), but this is certainly not
> guaranteed to work.  Also, this won't work at all unless bletiny is
> running on a combined host-controller, since that is the only occasion
> in which the host has access to the public address global variable.
> 
> I don't want to speak for Will, but my guess is he just looked at what
> existing code accesses the public address global to determine the scope
> of the proposed API.  My understanding from reading his email is that
> bletiny is doing something sketchy, and that the proposed API won't
> support this particular use case.
> 
> Chris


Re: Adding platform specific API to get public and/or random static address

Posted by Christopher Collins <ch...@runtime.io>.
On Sat, Apr 01, 2017 at 09:53:03AM +0200, Marcel Holtmann wrote:
> > Some things about writing apps and the BLE spec:
> > 1) I realize that it is the host that tells the controller the
> > random address to use. The controller will NOT automatically use the
> > random address from ble_hw_get_static_addr(). That API will be added
> > as a convenience so that the app developer does not have to generate
> > their own. If the app wants to use this random address it needs to
> > tell the controller to use it using LE_Set_Random_Addr.
> > 
> > 2) Regarding the public device address. We have an app called
> > bletiny that can set the public device address I think. If the above
> > gets approved we are going to remove g_dev_addr from the code; it
> > will be kept in the controller and not available globally. The
> > Zephyr project is considering adding vendor specific HCI commands,
> > one of which is \u201cset public device address\u201d. I think if we go with
> > the above approach we should add this vendor specific command and
> > that should be the way an app can set the public device address if
> > it so chooses.
> 
> The public BD_ADDR needs to be inside the controller before the call
> of HCI_Reset. Otherwise all sort of assumptions on HCI break. Until
> then the HCI_Read_BD_ADDR has to return 00:00:00:00:00:00 to indicate
> the controller has no public address. Switching the BD_ADDR mid-flight
> with a backdoor is going to fail in the most funny ways left and
> right.

The bletiny app is a sandbox test tool, and it does some things that a
more robust application shouldn't do.  One such underhanded thing it
does is change its own public address whenever the user requests it.  It
does this by simply overwriting the global public address byte array and
hoping for the best.  In practice, I've never seen anything funny
happen, either to the left or the right :), but this is certainly not
guaranteed to work.  Also, this won't work at all unless bletiny is
running on a combined host-controller, since that is the only occasion
in which the host has access to the public address global variable.

I don't want to speak for Will, but my guess is he just looked at what
existing code accesses the public address global to determine the scope
of the proposed API.  My understanding from reading his email is that
bletiny is doing something sketchy, and that the proposed API won't
support this particular use case.

Chris

Re: Adding platform specific API to get public and/or random static address

Posted by Marcel Holtmann <ma...@holtmann.org>.
Hi Will,

> There has been some discussion of this already on the list but nothing has been done yet so I wanted to resurrect the conversation with some proposals.
> 
> What we are trying to do here is the following:
> 1) Have the controller get a public device address without it being hardcoded.
> 2) Have the ability to read a chip-specific random static address if the chip has one programmed.
> 
> The proposal is the following:
> 
> 1) Add two new API. These will be platform specific and will be placed in the ble_hw.c file:
> 
> /* These API will return -1 if no address available. If available, will return 0 and will place the address in *addr */
> int ble_hw_get_public_addr(ble_addr_t *addr)
> int ble_hw_get_static_addr(ble_addr_t *addr)
> 
> 2) Add a syscfg variable to the controller which will allow the developer to set a public address of their choosing. By default this will be all 0 (no public address). More on this below.
> 
> 3) The ble_hw_get_public_addr function will do the following:
> * If the user has overridden the default public address (the syscfg variable) with a non-zero public address, that address will be returned by this function.
> * If the default public address in the syscfg is all zero, the code will read FICR and check if the device address type in the FICR is public. If so, it means the nordic chip was factory programmed with a public address and this will be used.
> * If both of the above checks fail, the code will read UICR[0] and UICR[1] to see if a public address has been programmed into the UICR. We are doing this to make it easy for folks to program their development kits with public addresses so they do not have to hardcode them. UICR[0] will contain the least significant 4 bytes of the device address. UICR[1] will contain the most significant two bytes. The upper 16 bits of this word should be set to 0. The API will presume that this is a valid public device address as long as the upper 16-bits of this 32-bit word are all zero. We will also check to see if this is a valid public address (see below). If both UICR[0] and UICR[1] are zero, this will not be considered a valid public address.
> 
> A note on valid public addresses. Not sure if I got this right, but I think the two least significant bits of the most significant byte of the public address should be zero. I think I will check this to make sure it is valid.

you got that wrong. The public address is a BD_ADDR (6 octets) and the random address is that (also 6 octets). If you just get 6 octets, you can not differentiate if it is public or random. That is why I keep that LE addresses are actually 49 bits instead. There is "out-of-band” telling if its public or random.

As far I know the FICR is just a 6 octet random value. It is neither a public address or a static random address (you are after the static after all since NRPAs and RPAs are different as well). So you even need to mask the upper 2 bits correctly to make FICR a static address.

> 4) The ble_hw_get_static_addr() will do the following:
> * Read the FICR to see if there is a random address in the FICR. This is the default programming of the nrf51dk and nrf52dk. Unless you have them program a public device address in the FICR, it will have a random address.
> * If the chip does not have a random address the API returns -1.

See my comment above, the FICR is just 6 octets random data. It is surely not a public address. It can never be since that requires to follow IEEE assignment rules. And it is no static address either. It needs to be masked correctly first. It is just a persistence 6 octets of randomness from manufacturing.

> Some things about writing apps and the BLE spec:
> 1) I realize that it is the host that tells the controller the random address to use. The controller will NOT automatically use the random address from ble_hw_get_static_addr(). That API will be added as a convenience so that the app developer does not have to generate their own. If the app wants to use this random address it needs to tell the controller to use it using LE_Set_Random_Addr.
> 
> 2) Regarding the public device address. We have an app called bletiny that can set the public device address I think. If the above gets approved we are going to remove g_dev_addr from the code; it will be kept in the controller and not available globally. The Zephyr project is considering adding vendor specific HCI commands, one of which is “set public device address”. I think if we go with the above approach we should add this vendor specific command and that should be the way an app can set the public device address if it so chooses.

The public BD_ADDR needs to be inside the controller before the call of HCI_Reset. Otherwise all sort of assumptions on HCI break. Until then the HCI_Read_BD_ADDR has to return 00:00:00:00:00:00 to indicate the controller has no public address. Switching the BD_ADDR mid-flight with a backdoor is going to fail in the most funny ways left and right.

Regards

Marcel