Detecting Unwanted Location Trackers (DULT)

The Detecting Unwanted Location Trackers (DULT) library implements a set of functionalities required for Detecting Unwanted Location Trackers (DULT) integration with the nRF Connect SDK. The implementation is based on the official DULT specification, which lists a set of best practices and protocols for products with built-in location tracking capabilities. Following the specification improves the privacy and safety of individuals by preventing the location tracking products from tracking users without their knowledge or consent.

Accessory non-owner service (ANOS)

The DULT library implements the accessory non-owner service (ANOS), which is a GATT service that uses the accessory non-owner characteristic to communicate with other devices. The ANOS uses UUID of 15190001-12F4-C226-88ED-2AC5579F2A85. The accessory non-owner characteristic manages the DULT Accessory Information and the DULT Non-owner controls defined in the DULT specification.

Configuration

Set the CONFIG_DULT Kconfig option to enable the module. This Kconfig option depends on the CONFIG_BT option that enables the Bluetooth® stack.

The following Kconfig options are also available for this module:

See the Kconfig help for details.

Implementation details

The implementation uses BT_GATT_SERVICE_DEFINE to statically define and register the ANOS. Because of that, the ANOS is still present in the GATT database after the DULT subsystem is disabled. In the DULT subsystem disabled state, GATT operations on the ANOS are rejected.

The ANOS handles all requests received from the outer world. In case of an application input needed to handle a GATT operation, the DULT subsystem calls the appropriate registered application callback. For more details, see the Integration steps section of the DULT integration guide.

API documentation

Header file: include/dult.h
Source files: subsys/dult
group dult

API for Detecting Unwanted Location Trackers specification implementation.

The Detecting Unwanted Location Trackers module can be used by location trackers devices to comply with the Detecting Unwanted Location Trackers specification (https://datatracker.ietf.org/doc/draft-detecting-unwanted-location-trackers/). The specification can be used with various location tracking networks. The API is not fully thread-safe and should be called from cooperative thread context.

Defines

DULT_PRODUCT_DATA_LEN

Length of DULT product data array (bytes). See the product_data field in the dult_user structure.

DULT_SOUND_DURATION_BT_GATT_MIN_MS

Minimum duration in milliseconds for the DULT sound action originating from the Bluetooth accessory non-owner service (see DULT_SOUND_SRC_BT_GATT).

Enums

enum dult_network_id

DULT Network ID value. Used in the network_id field that is part of the dult_user structure.

Values:

enumerator DULT_NETWORK_ID_APPLE
enumerator DULT_NETWORK_ID_GOOGLE
enum dult_accessory_capability

Bit positions in bitmask that encodes capabilities of the DULT accessory.

Values:

enumerator DULT_ACCESSORY_CAPABILITY_PLAY_SOUND_BIT_POS

Bit position for the play sound capability.

enumerator DULT_ACCESSORY_CAPABILITY_MOTION_DETECTOR_UT_BIT_POS

Bit position for the motion detector unwanted tracking capability.

enumerator DULT_ACCESSORY_CAPABILITY_ID_LOOKUP_NFC_BIT_POS

Bit position for the identifier lookup by NFC capability.

enumerator DULT_ACCESSORY_CAPABILITY_ID_LOOKUP_BLE_BIT_POS

Bit position for the identifier lookup by BLE capability.

enum dult_sound_src

DULT sound source types.

Values:

enumerator DULT_SOUND_SRC_BT_GATT

Sound source type originating from the Bluetooth accessory non-owner service.

enumerator DULT_SOUND_SRC_MOTION_DETECTOR

Sound source type originating from the Motion detector. Used only when the CONFIG_DULT_MOTION_DETECTOR is enabled.

enumerator DULT_SOUND_SRC_EXTERNAL

External source type originating from the unknown location to the DULT module.

enum dult_near_owner_state_mode

Modes of the DULT near-owner state.

Values:

enumerator DULT_NEAR_OWNER_STATE_MODE_SEPARATED

Separated mode of the near-owner state.

enumerator DULT_NEAR_OWNER_STATE_MODE_NEAR_OWNER

Near-owner mode of the near-owner state.

enumerator DULT_NEAR_OWNER_STATE_MODE_COUNT

Mode count for the near-owner state.

Functions

int dult_user_register(const struct dult_user *user)

Register DULT user.

The function must be called before calling any other functions from the DULT user API. Only one DULT user can be registered at a time. Only the registered DULT user is allowed to use other DULT APIs.

Parameters:
  • user – Structure containing user information.

Returns:

0 if the operation was successful. Otherwise, a (negative) error code is returned.

int dult_battery_level_set(const struct dult_user *user, uint8_t percentage_level)

Set the current battery level.

This function sets the current battery level. The battery level is an optional feature in the DULT specification and this API must not be used when the CONFIG_DULT_BATTERY Kconfig is disabled.

If the CONFIG_DULT_BATTERY Kconfig is enabled, this function must be called to initialize the battery level after registering the DULT user with dult_user_register and before enabling DULT with dult_enable function. Subsequent calls to update the battery level are allowed in the enabled mode.

To keep the battery level information accurate, the user should set the battery level to the new value with the help of this API as soon as the device battery level changes.

The exact mapping of the battery percentage to the battery level as defined by the DULT specification in the ANOS is implementation-specific. The mapping configuration is controlled by the following Kconfig options: CONFIG_DULT_BATTERY_LEVEL_CRITICAL_THR , CONFIG_DULT_BATTERY_LEVEL_LOW_THR and CONFIG_DULT_BATTERY_LEVEL_MEDIUM_THR .

Parameters:
  • user – User structure used to authenticate the user.

  • percentage_level – Battery level as a percentage [0-100%]

Returns:

0 if the operation was successful. Otherwise, a (negative) error code is returned.

int dult_id_read_state_cb_register(const struct dult_user *user, const struct dult_id_read_state_cb *cb)

Register DULT identifier read state callback structure.

This function must be called after registering the DULT user with dult_user_register and before enabling DULT with dult_enable function.

Parameters:
  • user – User structure used to authenticate the user.

  • cb – Identifier read state callback structure.

Returns:

0 if the operation was successful. Otherwise, a (negative) error code is returned.

int dult_id_read_state_enter(const struct dult_user *user)

Enter DULT identifier read state.

This function can only be called if DULT was previously enabled with the dult_enable API.

Parameters:
  • user – User structure used to authenticate the user.

Returns:

0 if the operation was successful. Otherwise, a (negative) error code is returned.

int dult_sound_cb_register(const struct dult_user *user, const struct dult_sound_cb *cb)

Register DULT sound callback structure.

This function must be called after registering the DULT user with dult_user_register and before enabling DULT with dult_enable function.

Parameters:
  • user – User structure used to authenticate the user.

  • cb – Sound callback structure.

Returns:

0 if the operation was successful. Otherwise, a (negative) error code is returned.

int dult_sound_state_update(const struct dult_user *user, const struct dult_sound_state_param *param)

Update the sound state.

This function should be called by the upper layer on each sound state change as defined by the dult_sound_state_param structure. All fields defined in the linked structure compose the sound state. The sound state change should be reported as soon as possible with this API, so that the DULT module is able to track the state in the real-time.

This API is typically used to respond to the callbacks defined by the dult_sound_cb structure. Each callback requests a specific action and the upper layer can accept a request by changing the sound state with this API. The upper layer is the ultimate owner of the sound state and only notifies the DULT module about each change.

This function can be used to change the sound state asynchronously as it is often impossible to execute sound playing action on the speaker device in the context of the requesting callbacks (as defined in the dult_sound_cb structure). Asynchronous support is also necessary to report sound state changes triggered by an external source unknown to the DULT module (see DULT_SOUND_SRC_EXTERNAL source type).

Parameters:
  • user – User structure used to authenticate the user.

  • param – Sound state parameters.

Returns:

0 if the operation was successful. Otherwise, a (negative) error code is returned.

int dult_motion_detector_cb_register(const struct dult_user *user, const struct dult_motion_detector_cb *cb)

Register motion detector callbacks.

This function registers callbacks to handle motion detector activities defined in the Motion detector feature from the DULT specification. This API can only be used when the CONFIG_DULT_MOTION_DETECTOR Kconfig option is enabled. If this configuration is active, this function must be called after registering the DULT user with dult_user_register and before enabling DULT with dult_enable function.

Parameters:
  • user – User structure used to authenticate the user.

  • cb – Motion detector callback structure.

Returns:

0 if the operation was successful. Otherwise, a (negative) error code is returned.

int dult_near_owner_state_set(const struct dult_user *user, enum dult_near_owner_state_mode mode)

Set the mode of the DULT near-owner state.

This function can only be called if the DULT user was previously registered with the dult_user_register API. By default, the DULT near-owner state is set to “near-owner” (see DULT_NEAR_OWNER_STATE_MODE_NEAR_OWNER) on boot and when the dult_reset API is called.

Parameters:
  • user – User structure used to authenticate the user.

  • mode – Mode of the DULT near-owner state.

Returns:

0 if the operation was successful. Otherwise, a (negative) error code is returned.

int dult_enable(const struct dult_user *user)

Enable DULT.

This function shall be used only after calling the dult_user_register and registering all of the required callbacks.

Parameters:
  • user – User structure used to authenticate the user.

Returns:

0 if the operation was successful. Otherwise, a (negative) error code is returned.

int dult_reset(const struct dult_user *user)

Reset DULT.

This function can only be called by the DULT user previously registered with the dult_user_register function. After the device boot-up, no DULT user is registered. Calling this function unregisters the registered DULT user structure and callbacks.

Parameters:
  • user – User structure used to authenticate the user.

Returns:

0 if the operation was successful. Otherwise, a (negative) error code is returned.

struct dult_firmware_version
#include <dult.h>

DULT firmware version.

Public Members

uint16_t major

Major firmware version.

uint8_t minor

Minor firmware version.

uint8_t revision

Firmware revision.

struct dult_user
#include <dult.h>

DULT user.

Public Members

const uint8_t *product_data

Pointer to the product data array. The array length must be equal to DULT_PRODUCT_DATA_LEN.

const char *manufacturer_name

Manufacturer name.

const char *model_name

Model name.

uint8_t accessory_category

Accessory category.

uint32_t accessory_capabilities

Accessory capabilities bitmask. See dult_accessory_capability for more details.

enum dult_network_id network_id

Network ID. See dult_network_id for more details.

struct dult_firmware_version firmware_version

Firmware version.

struct dult_id_read_state_cb
#include <dult.h>

DULT identifier read state callback.

Public Members

int (*payload_get)(uint8_t *buf, size_t *len)

Get identifier payload.

This callback is called to get the DULT user-specific identifier payload.

Param buf:

[out] Pointer to the buffer used to store identifier payload.

Param len:

[inout] Pointer to the length (in bytes) of the buffer used to store identifier payload. A negative error code shall be returned if this value is too small. If the operation was successful, the length of the identifier payload shall be written to this pointer.

Return:

0 if the operation was successful. Otherwise, a (negative) error code is returned.

void (*exited)(void)

Identifier read state exited.

This callback is called to indicate that the identifier read state has been exited. Identifier read state can be entered by calling the dult_id_read_state_enter API.

struct dult_sound_cb
#include <dult.h>

DULT sound callback.

Public Members

void (*sound_start)(enum dult_sound_src src)

Request the user to start the sound action.

This callback is triggered to notify the upper layer about the request to start sound action. If the upper layer changes its sound state in response to this request (as described by the dult_sound_state_param structure), it then calls the dult_sound_state_update API.

Param src:

Sound source type. Only the DULT internal sources are used in this callback: DULT_SOUND_SRC_BT_GATT, DULT_SOUND_SRC_MOTION_DETECTOR.

void (*sound_stop)(enum dult_sound_src src)

Request the user to stop the sound action.

This callback is triggered to notify the upper layer about the request to stop sound action. If the upper layer changes its sound state in response to this request (as described by the dult_sound_state_param structure), it then calls the dult_sound_state_update API.

Param src:

Sound source type. Only the DULT internal source originating from the Bluetooth accessory non-owner service (DULT_SOUND_SRC_BT_GATT) is used in this callback.

struct dult_sound_state_param
#include <dult.h>

Sound state parameters

Public Members

bool active

Sound state change flag. True when the sound state is activated. False: when the sound state is deactivated.

enum dult_sound_src src

Sound source type. The source can change during the sound-playing operation. For example, the DULT_SOUND_SRC_EXTERNAL source can override the DULT_SOUND_SRC_BT_GATT source). In the typical flow, the source for sound activation is also the source for sound deactivation.

struct dult_motion_detector_cb
#include <dult.h>

Motion detector callback structure.

Used only when the CONFIG_DULT_MOTION_DETECTOR Kconfig option is enabled.

Public Members

void (*start)(void)

Request the user to start the motion detector.

This callback is called to start the motion detector activity. From now on, the motion detector events are polled periodically with the period_expired API. The motion detector activity stops when the stop is called.

bool (*period_expired)(void)

Notify the user that the motion detector period has expired.

This callback is called at the end of each motion detector period. The start function indicates the beginning of the first motion detector period. The next period is started as soon as the previous period expires. The user should notify the DULT module if motion was detected in the previous period. The return value of this callback is used to pass this information.

Return:

true to indicate detected motion in the last period, otherwise false.

void (*stop)(void)

Notify the user that the motion detector can be stopped.

This callback is called to notify the user that the motion detector is no longer used by the DULT module. It concludes the motion detector activity that was started by the start callback.