mirror of
https://github.com/kidfromjupiter/nearby.git
synced 2026-09-14 14:46:12 -04:00
Remove Embedded SDK related code
This commit is contained in:
@@ -14,10 +14,6 @@ A peer-to-peer networking API that allows apps to easily discover, connect to, a
|
||||
|
||||
An extension to Nearby Connections that features an extensible identity model for authentication and restricted visibility, resource management for system health, and proximity detection through sensor fusion.
|
||||
|
||||
### [Nearby for Embedded Systems](embedded/)
|
||||
|
||||
A lightweight implementation of Fast Pair intended for embedded systems.
|
||||
|
||||
## Contributing
|
||||
|
||||
We encourage you to contribute to Nearby! Please check out the [Contributing to Nearby guide](CONTRIBUTING.md) for guidelines about how to proceed.
|
||||
|
||||
@@ -1,213 +0,0 @@
|
||||
# Makefile arguments
|
||||
#
|
||||
#
|
||||
# Delete the default suffix rules.
|
||||
.SUFFIXES:
|
||||
.SECONDARY:
|
||||
|
||||
GTEST_DIR = ../third_party/gtest/googletest/
|
||||
GMOCK_DIR = ../third_party/gtest/googlemock/
|
||||
MBEDTLS_DIR = ../third_party/mbedtls/
|
||||
|
||||
|
||||
ARCH ?= host
|
||||
OUT_DIR_NAME ?= $(ARCH)
|
||||
OUT_DIR = out/$(OUT_DIR_NAME)
|
||||
DIST_DIR = dist/$(OUT_DIR_NAME)
|
||||
|
||||
CFLAGS := -Wall
|
||||
COMMON_INCLUDE_DIRS :=
|
||||
CLIENT_INCLUDES :=
|
||||
# For ARCH variants like gLinux_hw set to gLinux.
|
||||
ARCH_COMMON_NAME := $(ARCH)
|
||||
ARCH_COMMON_DIR = common/source/$(ARCH_COMMON_NAME)
|
||||
CLIENT_DIR = client/source
|
||||
CLIENT_SRCS :=
|
||||
|
||||
NEARBY_LIB_NAME = libnearby.a
|
||||
|
||||
NAME = $(OUT_DIR)/$(NEARBY_LIB_NAME)
|
||||
|
||||
all : $(NAME)
|
||||
|
||||
COMMON_DIR = common/source
|
||||
COMMON_C_FILES :=
|
||||
|
||||
# All output objects for the build system should be added to ALL_OBJS.
|
||||
ALL_OBJS :=
|
||||
# Extra dependencies of the dist target.
|
||||
DIST_LIST :=
|
||||
|
||||
# Name of the libnearby static library that we distribute.
|
||||
DIST_NEARBY_LIB_NAME ?= $(DIST_DIR)/$(NEARBY_LIB_NAME)
|
||||
|
||||
# Kokoro on Windows is wonky. We can't shell out to git because we are in
|
||||
# cygwin, so this is pre-computed by continuous.bat
|
||||
ifneq ($(FIRMWARE_VERSION_FILENAME),)
|
||||
FIRMWARE_VERSION := $(shell cat $(FIRMWARE_VERSION_FILENAME))
|
||||
else
|
||||
FIRMWARE_VERSION_FILENAME = $(OUT_DIR)/FIRMWARE_VERSION
|
||||
PHONY_VERSION_FILENAME = $(OUT_DIR)/PHONY_FIRMWARE_VERSION
|
||||
FIRMWARE_VERSION := $(shell git -c core.fileMode=false describe --always --dirty --exclude="*")
|
||||
FIRMWARE_VERSION_FILENAME: $(PHONY_VERSION_FILENAME)
|
||||
|
||||
ifneq ($(KOKORO_RELEASE_BUILD),1)
|
||||
FIRMWARE_VERSION := $(FIRMWARE_VERSION)ENG
|
||||
endif
|
||||
|
||||
# Update the phony version on every build.
|
||||
.PHONY: $(PHONY_VERSION_FILENAME)
|
||||
$(PHONY_VERSION_FILENAME):
|
||||
@mkdir -p $(dir $@) ;\
|
||||
echo $(FIRMWARE_VERSION) > $@ ;\
|
||||
|
||||
# Only update this version if necessary (if it's different from the phony). This
|
||||
# tricks make into not updating dependencies of FIRMWARE_VERSION_FILENAME unless
|
||||
# the file is updated. .PHONY is not transitive.
|
||||
$(FIRMWARE_VERSION_FILENAME): $(PHONY_VERSION_FILENAME)
|
||||
@cmp $@ $< 2>> /dev/null || cp -v $< $@
|
||||
|
||||
endif
|
||||
|
||||
# Note $(notdir) below converts a path to just the base file name
|
||||
define compile_c
|
||||
mkdir -p $(dir $@)
|
||||
$(CC) -c $(1) -o $@ -D__NEARBY_SHORT_FILE__='"$(notdir $<)"' $<
|
||||
endef
|
||||
|
||||
# Include all of the target specific variables and rules.
|
||||
# The $(ARCH).mk files should only depend on the variables listed above.
|
||||
include target/$(ARCH)/config.mk
|
||||
|
||||
# Set trace verbosity from target specific variable
|
||||
CFLAGS += -DNEARBY_TRACE_LEVEL=NEARBY_TRACE_LEVEL_$(NEARBY_TRACE_LEVEL)
|
||||
# if directory doesn't exist, raise an error so we don't fail later with more cryptic warnings
|
||||
ifeq ($(wildcard common/target/$(ARCH_COMMON_NAME)),)
|
||||
$(error need to create directory common/target/$(ARCH_COMMON_NAME) )
|
||||
endif
|
||||
|
||||
ifdef NEARBY_FP_ENABLE_BATTERY_NOTIFICATION
|
||||
CFLAGS += -DNEARBY_FP_ENABLE_BATTERY_NOTIFICATION=$(NEARBY_FP_ENABLE_BATTERY_NOTIFICATION)
|
||||
endif
|
||||
|
||||
ifdef NEARBY_FP_ENABLE_ADDITIONAL_DATA
|
||||
CFLAGS += -DNEARBY_FP_ENABLE_ADDITIONAL_DATA=$(NEARBY_FP_ENABLE_ADDITIONAL_DATA)
|
||||
endif
|
||||
|
||||
ifdef NEARBY_FP_MESSAGE_STREAM
|
||||
CFLAGS += -DNEARBY_FP_MESSAGE_STREAM=$(NEARBY_FP_MESSAGE_STREAM)
|
||||
endif
|
||||
|
||||
ifdef NEARBY_FP_RETROACTIVE_PAIRING
|
||||
CFLAGS += -DNEARBY_FP_RETROACTIVE_PAIRING=$(NEARBY_FP_RETROACTIVE_PAIRING)
|
||||
endif
|
||||
|
||||
ifdef NEARBY_FP_BLE_ONLY
|
||||
CFLAGS += -DNEARBY_FP_BLE_ONLY=$(NEARBY_FP_BLE_ONLY)
|
||||
endif
|
||||
|
||||
ifdef NEARBY_FP_PREFER_BLE_BONDING
|
||||
CFLAGS += -DNEARBY_FP_PREFER_BLE_BONDING=$(NEARBY_FP_PREFER_BLE_BONDING)
|
||||
endif
|
||||
|
||||
ifdef NEARBY_FP_PREFER_LE_TRANSPORT
|
||||
CFLAGS += -DNEARBY_FP_PREFER_LE_TRANSPORT=$(NEARBY_FP_PREFER_LE_TRANSPORT)
|
||||
endif
|
||||
COMMON_INCLUDE_DIRS += \
|
||||
-I. \
|
||||
-I$(ARCH_COMMON_DIR) \
|
||||
-Icommon/target \
|
||||
-Icommon/target/$(ARCH_COMMON_NAME) \
|
||||
-I$(COMMON_DIR)
|
||||
ifeq ($(NEARBY_PLATFORM_USE_MBEDTLS),1)
|
||||
COMMON_INCLUDE_DIRS += -I$(MBEDTLS_DIR)/include
|
||||
endif
|
||||
|
||||
CLIENT_INCLUDES += \
|
||||
-I$(CLIENT_DIR) \
|
||||
-Iclient/target
|
||||
|
||||
COMMON_C_FILES += \
|
||||
$(wildcard $(COMMON_DIR)/*.c)
|
||||
|
||||
CLIENT_SRCS += \
|
||||
$(wildcard $(CLIENT_DIR)/*.c)
|
||||
|
||||
CFLAGS += $(COMMON_INCLUDE_DIRS)
|
||||
|
||||
CROSS_COMPILE ?= arm-none-eabi-
|
||||
CC ?= $(CROSS_COMPILE)gcc
|
||||
AR ?= $(CROSS_COMPILE)ar
|
||||
ALL_C_FILES = $(COMMON_C_FILES)
|
||||
COMMON_OBJS = $(patsubst %.c,$(OUT_DIR)/%.o,$(ALL_C_FILES))
|
||||
CLIENT_OBJS = $(patsubst %.c,$(OUT_DIR)/%.o,$(CLIENT_SRCS))
|
||||
NEARBY_LIB_OBJS = $(COMMON_OBJS) $(CLIENT_OBJS)
|
||||
|
||||
NEARBY_HEADERS += $(patsubst common/target/%.h,$(DIST_DIR)/%.h,$(wildcard common/target/*.h))
|
||||
NEARBY_HEADERS += $(patsubst common/target/$(ARCH_COMMON_NAME)/%.h,$(DIST_DIR)/%.h,$(wildcard common/target/$(ARCH_COMMON_NAME)/*.h))
|
||||
NEARBY_HEADERS += $(patsubst client/target/%,$(DIST_DIR)/%,$(wildcard client/target/*.h))
|
||||
|
||||
NEARBY_DIST_HEADERS := $(NEARBY_HEADERS)
|
||||
|
||||
DIST_LIST += $(NEARBY_DIST_HEADERS)
|
||||
DIST_LIST += $(DIST_NEARBY_LIB_NAME)
|
||||
|
||||
$(DIST_DIR)/nearby.h: $(FIRMWARE_VERSION_FILENAME)
|
||||
$(DIST_DIR)/nearby.h: common/target/nearby.h
|
||||
@mkdir -p $(dir $@)
|
||||
$(call copy_dist_header)
|
||||
sed -i -e "s/\(define\s*NEARBY_BUILD_ID\).*/\1 \"$(FIRMWARE_VERSION)\"/" $@
|
||||
|
||||
define copy_dist_header
|
||||
@mkdir -p $(dir $@)
|
||||
@test "$$(head -n 2 $< | grep 'Copyright [0-9]\{4\} Google LLC.')" != "" || \
|
||||
(echo ; echo "=====ERROR=====" ; echo "Missing copyright in $<" ; exit 1)
|
||||
unifdef -t -b -x2 $(UNIFDEF_ARG) -o - $< | cat - >$@
|
||||
@# (mkartoz) Should be able to specify $@ as the output directly from
|
||||
@# unifdef but, if you do that, the file never shows up on kokoro. Piping to
|
||||
@# cat is a workaround.
|
||||
endef
|
||||
|
||||
# Do not bypass the whole build process if the dist directory exists
|
||||
.PHONY: dist
|
||||
dist : all \
|
||||
$(DIST_LIST)
|
||||
|
||||
$(DIST_DIR)/$(NEARBY_LIB_NAME) : $(NAME)
|
||||
mkdir -p $(dir $@)
|
||||
cp -uv $< $@
|
||||
|
||||
$(DIST_DIR)/%.h : common/target/%.h
|
||||
$(call copy_dist_header)
|
||||
|
||||
$(DIST_DIR)/%.h : common/target/$(ARCH_COMMON_NAME)/%.h
|
||||
$(call copy_dist_header)
|
||||
|
||||
$(NAME): $(NEARBY_LIB_OBJS)
|
||||
mkdir -p $(dir $@)
|
||||
$(AR) rcs $@ $(NEARBY_LIB_OBJS)
|
||||
|
||||
# If the hash has changed then we need to rebuild nearby.o and nearby_client.o
|
||||
$(filter %/nearby_client.o, $(NEARBY_LIB_OBJS)): $(FIRMWARE_VERSION_FILENAME)
|
||||
$(filter %/nearby.o, $(NEARBY_LIB_OBJS)): $(FIRMWARE_VERSION_FILENAME)
|
||||
|
||||
$(CLIENT_OBJS) : $(OUT_DIR)/%.o : %.c
|
||||
$(call compile_c, $(CFLAGS) -Icommon/target $(CLIENT_INCLUDES))
|
||||
|
||||
$(COMMON_OBJS) : $(OUT_DIR)/%.o: %.c
|
||||
$(call compile_c,$(CFLAGS))
|
||||
|
||||
ALL_OBJS += $(NEARBY_LIB_OBJS) $(CLIENT_OBJS)
|
||||
|
||||
DEPFILES = $(ALL_OBJS:.o=.d)
|
||||
|
||||
-include $(DEPFILES)
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -f $(NAME)
|
||||
rm -f $(ALL_OBJS) $(DEPFILES)
|
||||
rm -f $(FIRMWARE_VERSION_FILENAME) $(PHONY_VERSION_FILENAME)
|
||||
rm -f $(DIST_LIST) $(TEST_BINARIES)
|
||||
|
||||
-include target/$(ARCH)/rules.mk
|
||||
@@ -1,43 +0,0 @@
|
||||
# Nearby embedded SDK library
|
||||
|
||||
This repository contains Nearby SDK library for embedded systems. Nearby SDK
|
||||
implements the Fast Pair protocol and its future versions per
|
||||
https://developers.google.com/nearby/fast-pair/spec
|
||||
|
||||
|
||||
## Threading model
|
||||
|
||||
Nearby SDK assumes a single-threading model. All calls to the SDK must be on the same thread, or protected with a mutex. That includes:
|
||||
- client API, for example `nearby_fp_client_SetAdvertisement()`
|
||||
- ble and other event callbacks
|
||||
- timers
|
||||
|
||||
## Porting guidelines
|
||||
|
||||
1. Follow the steps at [Fast Pair Help](https://developers.google.com/nearby/fast-pair/help) to
|
||||
register a Model Id for your device.
|
||||
1. Review `nearby_config.h` and disable features, if any, that you don't
|
||||
wish to support.
|
||||
1. Implement the HAL defined in `nearby_platform_*.h` headers.
|
||||
1. Set platform specific compile flags in `config.mk` - see
|
||||
`target/gLinux/config.mk` for inspiration, and add your platform in
|
||||
`build.sh`, or use your own build system.
|
||||
1. Compile with `./build.sh <your platform>`
|
||||
1. Start advertising in your application. For example
|
||||
```
|
||||
nearby_fp_client_Init(NULL);
|
||||
nearby_fp_client_SetAdvertisement(NEARBY_FP_ADVERTISEMENT_DISCOVERABLE);
|
||||
```
|
||||
1. Use [Fast Pair Validator](https://play.google.com/store/apps/details?id=com.google.location.nearby.apps.fastpair.validator) to verify that your device is behaving correctly.
|
||||
|
||||
## Optional modules
|
||||
The optional modules provide partial implementation of HAL interfaces using common libraries, mbedtls in particular.
|
||||
|
||||
1. *mbedtls* located in `common/source/mbedtls/mbedtls.c` implements `nearby_platform_Sha256Start()`, `nearby_platform_Sha256Update()`, `nearby_platform_Sha256Finish()`, `nearby_platform_Aes128Encrypt()`, `nearby_platform_Aes128Decrypt()`.
|
||||
|
||||
Nearby SDK can be configured to use the MBEDTLS package, commonly available on ARM
|
||||
implementations, with the config.mk flag `NEARBY_PLATFORM_USE_MBEDTLS`.
|
||||
|
||||
2. *gen_secret* located in `common/source/mbedtls/gen_secret.c` implements `nearby_platform_GenSec256r1Secret()`.
|
||||
|
||||
*gen_secret* generates a shared secret based on a given private key on platforms that don't support hardware SE. *gen_secret* module is enabled `NEARBY_PLATFORM_USE_MBEDTLS` is set and `NEARBY_PLATFORM_HAS_SE` is *not* set. When `NEARBY_PLATFORM_HAS_SE` is set, the platform needs to provide their own `nearby_platform_GenSec256r1Secret()` routine.
|
||||
@@ -1,97 +0,0 @@
|
||||
#!/bin/sh
|
||||
# Copyright 2022 Google LLC
|
||||
#
|
||||
# Licensed 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
|
||||
#
|
||||
# https://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.
|
||||
|
||||
#
|
||||
# Parameters:
|
||||
# ${1} architecture (default: gLinux)
|
||||
# ${2} make target (e.g. "dist")
|
||||
# (remaining params are also passed to make)
|
||||
#
|
||||
# Checks for environment variables:
|
||||
# NEARBY_MAKEFILE_DEBUG: if set, passes -d argument to make
|
||||
# many others, not fully documented here yet
|
||||
#
|
||||
# e.g.
|
||||
# ./build.sh gLinux dist DEBUG=1
|
||||
|
||||
if [ "${1}" == "help" ] ; then
|
||||
echo "Usage:"
|
||||
echo " ./build.sh <target> [dist] [args]"
|
||||
echo ""
|
||||
echo "Optional arguments:"
|
||||
echo " DEBUG=1"
|
||||
echo " -j72 # parallelizes build using 72 cores"
|
||||
exit -1;
|
||||
fi
|
||||
|
||||
if [ "${1}" != "" ] ; then
|
||||
ARCH="${1}"
|
||||
shift 1
|
||||
else
|
||||
ARCH=gLinux
|
||||
fi
|
||||
|
||||
CC=arm-none-eabi-gcc
|
||||
AR=arm-none-eabi-ar
|
||||
|
||||
UNAME_OUT="$(uname -s)"
|
||||
case "${UNAME_OUT}" in
|
||||
Linux*) MACHINE=linux;;
|
||||
Darwin*) MACHINE=mac;;
|
||||
CYGWIN*) MACHINE=cygwin;;
|
||||
MINGW*) MACHINE=mingw;;
|
||||
*) MACHINE=windows;;
|
||||
esac
|
||||
|
||||
if [ "${ARCH}" = "gLinux" ] ; then
|
||||
if [ -x /usr/bin/clang ] ; then
|
||||
CC=clang
|
||||
else
|
||||
CC=clang-3.8
|
||||
fi
|
||||
AR=ar
|
||||
else
|
||||
echo "Invalid target specified on command line ${ARCH}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
export NEARBY=$(cd `dirname ${0}` && pwd)
|
||||
|
||||
PLATFORM=$(uname -s | grep -i '\(mingw\|cygwin\)')
|
||||
echo $PLATFORM
|
||||
|
||||
make_args=
|
||||
if [ ! -z "$NEARBY_MAKEFILE_DEBUG" ]; then
|
||||
echo "NEARBY_MAKEFILE_DEBUG is set, passing -d to make"
|
||||
make_args+=" -d"
|
||||
fi
|
||||
|
||||
make \
|
||||
$make_args \
|
||||
-C "${NEARBY}" \
|
||||
CC="${CC}" \
|
||||
AR="${AR}" \
|
||||
ARCH="${ARCH}" \
|
||||
$@
|
||||
|
||||
make_rc=$?
|
||||
|
||||
# NOTE: if make fails, it is important that the bad return code is bubbled up
|
||||
# to the caller of this script.
|
||||
# We don't want automated processes to keep going if there was a build error.
|
||||
|
||||
if [ $make_rc -ne 0 ]; then
|
||||
exit $make_rc
|
||||
fi
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,114 +0,0 @@
|
||||
// Copyright 2022 Google LLC
|
||||
//
|
||||
// Licensed 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
|
||||
//
|
||||
// https://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.
|
||||
|
||||
#ifndef NEARBY_FP_CLIENT_H
|
||||
#define NEARBY_FP_CLIENT_H
|
||||
|
||||
// clang-format off
|
||||
#include "nearby_config.h"
|
||||
// clang-format on
|
||||
|
||||
#include "nearby.h"
|
||||
#include "nearby_event.h"
|
||||
#include "nearby_message_stream.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
typedef struct {
|
||||
// Optional event callback
|
||||
void (*on_event)(nearby_event_Event* event);
|
||||
} nearby_fp_client_Callbacks;
|
||||
|
||||
// Seeker information structure
|
||||
// Returns current information on a given seeker.
|
||||
typedef struct {
|
||||
uint64_t peer_address; // address of peer/seeker
|
||||
uint8_t capabilities; // Capability bits
|
||||
// Bit 0: Companion app is installed/not installed.
|
||||
// Bit 1: Silence mode is supported/not supported.
|
||||
uint8_t platform_type; // platform type code (Android = 0x01)
|
||||
uint8_t platform_build; // Platform build number (Android Pie=0x1c)
|
||||
} nearby_fp_client_SeekerInfo;
|
||||
|
||||
// No advertisement, default state
|
||||
#define NEARBY_FP_ADVERTISEMENT_NONE 0x00
|
||||
// The device is discoverable and can be paired with
|
||||
#define NEARBY_FP_ADVERTISEMENT_DISCOVERABLE 0x01
|
||||
// The device is not discoverable
|
||||
#define NEARBY_FP_ADVERTISEMENT_NON_DISCOVERABLE 0x02
|
||||
// Ask the Seeker to show pairing UI indication. This flag can be combined with
|
||||
// NEARBY_FP_ADVERTISEMENT_NON_DISCOVERABLE
|
||||
#define NEARBY_FP_ADVERTISEMENT_PAIRING_UI_INDICATOR 0x04
|
||||
#if NEARBY_FP_ENABLE_BATTERY_NOTIFICATION
|
||||
// Include battery and charging info in the advertisement. This flag can be
|
||||
// combined with NEARBY_FP_ADVERTISEMENT_NON_DISCOVERABLE
|
||||
#define NEARBY_FP_ADVERTISEMENT_INCLUDE_BATTERY_INFO 0x08
|
||||
// Ask the Seeker to show Battery UI indication. This flag can be combined with
|
||||
// NEARBY_FP_ADVERTISEMENT_INCLUDE_BATTERY_INFO
|
||||
#define NEARBY_FP_ADVERTISEMENT_BATTERY_UI_INDICATOR 0x10
|
||||
#endif /* NEARBY_FP_ENABLE_BATTERY_NOTIFICATION */
|
||||
#ifdef NEARBY_FP_ENABLE_SASS
|
||||
// Include SASS advertisement. This flag can be
|
||||
// combined with NEARBY_FP_ADVERTISEMENT_NON_DISCOVERABLE
|
||||
#define NEARBY_FP_ADVERTISEMENT_SASS 0x20
|
||||
#endif /* NEARBY_FP_ENABLE_SASS */
|
||||
|
||||
// Sets Fast Pair advertisement type
|
||||
nearby_platform_status nearby_fp_client_SetAdvertisement(int mode);
|
||||
|
||||
// Initalizes Fast Pair provider. The |callbacks| are optional - can be NULL.
|
||||
nearby_platform_status nearby_fp_client_Init(
|
||||
const nearby_fp_client_Callbacks* callbacks);
|
||||
|
||||
#if NEARBY_FP_MESSAGE_STREAM
|
||||
// Serializes and sends |message| over Message Stream
|
||||
nearby_platform_status nearby_fp_client_SendMessage(
|
||||
uint64_t peer_address, const nearby_message_stream_Message* message);
|
||||
|
||||
// Sends out an ACK message for a received |message|. Note that not all messages
|
||||
// require an ACK
|
||||
nearby_platform_status nearby_fp_client_SendAck(
|
||||
const nearby_event_MessageStreamReceived* message);
|
||||
|
||||
// Sends out a NACK message for a received |message| with |fail_reason| reason.
|
||||
nearby_platform_status nearby_fp_client_SendNack(
|
||||
const nearby_event_MessageStreamReceived* message, uint8_t fail_reason);
|
||||
|
||||
// Sends out a enable or disable silence mode, which stops audio from being
|
||||
// routed to the provider.
|
||||
nearby_platform_status nearby_fp_client_SetSilenceMode(uint64_t peer_address,
|
||||
bool enable);
|
||||
|
||||
// Sends log buffer full message to seeker, which passes it on to the companion
|
||||
// app to manage log collection.
|
||||
nearby_platform_status nearby_fp_client_SignalLogBufferFull(
|
||||
uint64_t peer_address);
|
||||
|
||||
// Gets information on currently connected seekers.
|
||||
// An array of `SeekerInfo` structures is passed in, along with the length.
|
||||
// On output, `seeker_info_length` is the actual number of structures read.
|
||||
// Returns an error if input array is too small to hold information about
|
||||
// all connected seekers.
|
||||
nearby_platform_status nearby_fp_client_GetSeekerInfo(
|
||||
nearby_fp_client_SeekerInfo* seeker_info, size_t* seeker_info_length);
|
||||
|
||||
#endif /* NEARBY_FP_MESSAGE_STREAM */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* NEARBY_FP_CLIENT_H */
|
||||
@@ -1,188 +0,0 @@
|
||||
// Copyright 2022 Google LLC
|
||||
//
|
||||
// Licensed 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
|
||||
//
|
||||
// https://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 "fakes.h"
|
||||
#include "nearby.h"
|
||||
#include "nearby_fp_client.h"
|
||||
#include "nearby_platform_audio.h"
|
||||
|
||||
static const nearby_platform_AudioCallbacks* callbacks;
|
||||
|
||||
static bool multipoint = false;
|
||||
static uint8_t switching_preference_flags = 0;
|
||||
static uint64_t switch_active_peer_address = 0;
|
||||
static uint8_t switch_active_flags = 0;
|
||||
static uint64_t switch_active_preferred_audio_source = 0;
|
||||
static uint64_t switch_back_peer_address = 0;
|
||||
static uint8_t switch_back_flags = 0;
|
||||
static uint64_t notify_peer_address = 0;
|
||||
static uint8_t notify_flags = 0;
|
||||
static uint64_t drop_peer_address = 0;
|
||||
static uint8_t drop_flags = 0;
|
||||
static uint64_t active_peer_address = 0;
|
||||
|
||||
bool nearby_platform_GetEarbudRightStatus() { return false; }
|
||||
|
||||
bool nearby_platform_GetEarbudLeftStatus() { return false; }
|
||||
|
||||
unsigned int nearby_platform_GetAudioConnectionState() {
|
||||
return NEARBY_PLATFORM_CONNECTION_STATE_A2DP_WITH_AVRCP;
|
||||
}
|
||||
|
||||
bool nearby_platform_OnHead() { return true; }
|
||||
|
||||
// Returns true if the device can accept another audio connection without
|
||||
// dropping any of the existing connections.
|
||||
bool nearby_platform_CanAcceptConnection() { return false; }
|
||||
|
||||
// When the device is in focus mode, connection switching is not allowed
|
||||
bool nearby_platform_InFocusMode() { return false; }
|
||||
|
||||
// Returns true if the current connection is auto-recconnected, meaning it is
|
||||
// not connected by the user. For multi-point connections, returns true if any
|
||||
// of the existing connections is auto-reconnected.
|
||||
bool nearby_platform_AutoReconnected() { return false; }
|
||||
|
||||
// Sets a bit in the |bitmap| for every connected peer. The bit stays cleared
|
||||
// for bonded but not connected peers. The order change is acceptable if it is
|
||||
// unavoidable, e.g. when users factory reset the headset or when the bonded
|
||||
// device count reaches the upper limit.
|
||||
// |length| is the |bitmap| length on input in bytes and used space on output.
|
||||
// For example, if there are 5 bonded devices, then |length| should be set to 1.
|
||||
void nearby_platform_GetConnectionBitmap(uint8_t* bitmap, size_t* length) {
|
||||
if (*length > 0) {
|
||||
bitmap[0] = 0x09;
|
||||
*length = 1;
|
||||
}
|
||||
}
|
||||
|
||||
bool nearby_platform_IsSassOn() { return true; }
|
||||
|
||||
bool nearby_platform_IsMultipointConfigurable() { return true; }
|
||||
|
||||
bool nearby_platform_IsMultipointOn() { return multipoint; }
|
||||
|
||||
bool nearby_platform_IsOnHeadDetectionSupported() { return true; }
|
||||
|
||||
bool nearby_platform_IsOnHeadDetectionEnabled() { return false; }
|
||||
|
||||
nearby_platform_status nearby_platform_SetMultipoint(uint64_t peer_address,
|
||||
bool enable) {
|
||||
multipoint = enable;
|
||||
return kNearbyStatusOK;
|
||||
}
|
||||
|
||||
nearby_platform_status nearby_platform_SetSwitchingPreference(uint8_t flags) {
|
||||
switching_preference_flags = flags;
|
||||
return kNearbyStatusOK;
|
||||
}
|
||||
|
||||
// Gets switching preference flags
|
||||
uint8_t nearby_platform_GetSwitchingPreference() {
|
||||
return switching_preference_flags;
|
||||
}
|
||||
|
||||
nearby_platform_status nearby_platform_SwitchActiveAudioSource(
|
||||
uint64_t peer_address, uint8_t flags, uint64_t preferred_audio_source) {
|
||||
switch_active_peer_address = peer_address;
|
||||
switch_active_flags = flags;
|
||||
switch_active_preferred_audio_source = preferred_audio_source;
|
||||
return kNearbyStatusOK;
|
||||
}
|
||||
|
||||
nearby_platform_status nearby_platform_SwitchBackAudioSource(
|
||||
uint64_t peer_address, uint8_t flags) {
|
||||
switch_back_peer_address = peer_address;
|
||||
switch_back_flags = flags;
|
||||
return kNearbyStatusOK;
|
||||
}
|
||||
|
||||
nearby_platform_status nearby_platform_NotifySassInitiatedConnection(
|
||||
uint64_t peer_address, uint8_t flags) {
|
||||
notify_peer_address = peer_address;
|
||||
notify_flags = flags;
|
||||
return kNearbyStatusOK;
|
||||
}
|
||||
|
||||
nearby_platform_status nearby_platform_SetDropConnectionTarget(
|
||||
uint64_t peer_address, uint8_t flags) {
|
||||
drop_peer_address = peer_address;
|
||||
drop_flags = flags;
|
||||
return kNearbyStatusOK;
|
||||
}
|
||||
|
||||
uint64_t nearby_platform_GetActiveAudioSource() { return active_peer_address; }
|
||||
|
||||
void nearby_test_fakes_SetActiveAudioSource(uint64_t peer_address) {
|
||||
active_peer_address = peer_address;
|
||||
}
|
||||
|
||||
// Initializes Audio module
|
||||
nearby_platform_status nearby_platform_AudioInit(
|
||||
const nearby_platform_AudioCallbacks* audio_interface) {
|
||||
multipoint = false;
|
||||
switching_preference_flags = 0;
|
||||
switch_active_peer_address = 0;
|
||||
switch_active_flags = 0;
|
||||
switch_active_preferred_audio_source = 0;
|
||||
switch_back_peer_address = 0;
|
||||
switch_back_flags = 0;
|
||||
notify_peer_address = 0;
|
||||
notify_flags = 0;
|
||||
drop_peer_address = 0;
|
||||
drop_flags = 0;
|
||||
|
||||
callbacks = audio_interface;
|
||||
return kNearbyStatusOK;
|
||||
}
|
||||
|
||||
uint64_t nearby_test_fakes_GetSassSwitchActiveSourcePeerAddress() {
|
||||
return switch_active_peer_address;
|
||||
}
|
||||
|
||||
uint8_t nearby_test_fakes_GetSassSwitchActiveSourceFlags() {
|
||||
return switch_active_flags;
|
||||
}
|
||||
|
||||
uint64_t nearby_test_fakes_GetSassSwitchActiveSourcePreferredAudioSource() {
|
||||
return switch_active_preferred_audio_source;
|
||||
}
|
||||
|
||||
uint64_t nearby_test_fakes_GetSassSwitchBackPeerAddress() {
|
||||
return switch_back_peer_address;
|
||||
}
|
||||
|
||||
uint8_t nearby_test_fakes_GetSassSwitchBackFlags() { return switch_back_flags; }
|
||||
|
||||
uint64_t nearby_test_fakes_GetSassNotifyInitiatedConnectionPeerAddress() {
|
||||
return notify_peer_address;
|
||||
}
|
||||
|
||||
uint8_t nearby_test_fakes_GetSassNotifyInitiatedConnectionFlags() {
|
||||
return notify_flags;
|
||||
}
|
||||
|
||||
uint64_t nearby_test_fakes_GetSassDropConnectionTargetPeerAddress() {
|
||||
return drop_peer_address;
|
||||
}
|
||||
|
||||
uint8_t nearby_test_fakes_GetSassDropConnectionTargetFlags() {
|
||||
return drop_flags;
|
||||
}
|
||||
|
||||
void nearby_test_fakes_SassMultipointSwitch(uint8_t reason,
|
||||
uint64_t peer_address,
|
||||
const char* name) {
|
||||
callbacks->on_multipoint_switch_event(reason, peer_address, name);
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
// Copyright 2022 Google LLC
|
||||
//
|
||||
// Licensed 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
|
||||
//
|
||||
// https://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 "fakes.h"
|
||||
#include "nearby.h"
|
||||
#include "nearby_platform_battery.h"
|
||||
|
||||
constexpr nearby_platform_BatteryInfo kDefaultBatteryInfo = {
|
||||
.is_charging = true,
|
||||
.right_bud_battery_level = 80,
|
||||
.left_bud_battery_level = 85,
|
||||
.charging_case_battery_level = 90,
|
||||
.remaining_time_minutes = 100};
|
||||
static nearby_platform_BatteryInfo test_battery_info = kDefaultBatteryInfo;
|
||||
static nearby_platform_status get_battery_info_result = kNearbyStatusOK;
|
||||
|
||||
static const nearby_platform_BatteryInterface* battery_interface;
|
||||
nearby_platform_status nearby_platform_GetBatteryInfo(
|
||||
nearby_platform_BatteryInfo* battery_info) {
|
||||
(*battery_info) = test_battery_info;
|
||||
return get_battery_info_result;
|
||||
}
|
||||
|
||||
void nearby_test_fakes_SetIsCharging(bool charging) {
|
||||
test_battery_info.is_charging = charging;
|
||||
}
|
||||
|
||||
void nearby_test_fakes_SetRightBudBatteryLevel(unsigned battery_level) {
|
||||
test_battery_info.right_bud_battery_level = battery_level;
|
||||
}
|
||||
|
||||
void nearby_test_fakes_SetLeftBudBatteryLevel(unsigned battery_level) {
|
||||
test_battery_info.left_bud_battery_level = battery_level;
|
||||
}
|
||||
|
||||
void nearby_test_fakes_SetChargingCaseBatteryLevel(unsigned battery_level) {
|
||||
test_battery_info.charging_case_battery_level = battery_level;
|
||||
}
|
||||
|
||||
void nearby_test_fakes_BatteryTime(uint16_t battery_time) {
|
||||
test_battery_info.remaining_time_minutes = battery_time;
|
||||
}
|
||||
|
||||
void nearby_test_fakes_SetGetBatteryInfoResult(nearby_platform_status status) {
|
||||
get_battery_info_result = status;
|
||||
}
|
||||
|
||||
nearby_platform_status nearby_platform_BatteryInit(
|
||||
nearby_platform_BatteryInterface* callbacks) {
|
||||
battery_interface = callbacks;
|
||||
test_battery_info = kDefaultBatteryInfo;
|
||||
get_battery_info_result = kNearbyStatusOK;
|
||||
return kNearbyStatusOK;
|
||||
}
|
||||
@@ -1,140 +0,0 @@
|
||||
// Copyright 2022 Google LLC
|
||||
//
|
||||
// Licensed 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
|
||||
//
|
||||
// https://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 <map>
|
||||
#include <vector>
|
||||
|
||||
// clang-format off
|
||||
#include "nearby_config.h"
|
||||
// clang-format on
|
||||
|
||||
#include "fakes.h"
|
||||
#include "nearby_platform_ble.h"
|
||||
#include "nearby_platform_se.h"
|
||||
|
||||
constexpr uint64_t kDefaultBleAddress = 0xbabababa;
|
||||
static uint64_t ble_address = kDefaultBleAddress;
|
||||
static uint64_t peer_address = 0x345678ab;
|
||||
static const nearby_platform_BleInterface* ble_interface;
|
||||
static std::map<nearby_fp_Characteristic, std::vector<uint8_t>> notifications;
|
||||
static std::vector<uint8_t> advertisement;
|
||||
static nearby_fp_AvertisementInterval interval;
|
||||
constexpr int32_t kDefaultPsm = -1;
|
||||
static int32_t psm = kDefaultPsm;
|
||||
|
||||
std::map<nearby_fp_Characteristic, std::vector<uint8_t>>&
|
||||
nearby_test_fakes_GetGattNotifications() {
|
||||
return notifications;
|
||||
}
|
||||
|
||||
// Gets BLE address.
|
||||
uint64_t nearby_platform_GetBleAddress() { return ble_address; }
|
||||
|
||||
// Sets BLE address. Returns address after change, which may be different than
|
||||
// requested address.
|
||||
uint64_t nearby_platform_SetBleAddress(uint64_t address) {
|
||||
ble_address = address;
|
||||
return ble_address;
|
||||
}
|
||||
|
||||
#ifdef NEARBY_FP_HAVE_BLE_ADDRESS_ROTATION
|
||||
// Rotates BLE address to a random resolvable private address (RPA). Returns
|
||||
// address after change.
|
||||
uint64_t nearby_platform_RotateBleAddress() {
|
||||
unsigned i;
|
||||
uint64_t address = 0;
|
||||
for (i = 0; i < sizeof(address); i++) {
|
||||
address = (address << 8) ^ nearby_platform_Rand();
|
||||
}
|
||||
address |= (uint64_t)1 << 46;
|
||||
address &= ~((uint64_t)1 << 47);
|
||||
nearby_platform_SetBleAddress(address);
|
||||
return address;
|
||||
}
|
||||
#endif /* NEARBY_FP_HAVE_BLE_ADDRESS_ROTATION */
|
||||
|
||||
// Sends a notification to the connected GATT client.
|
||||
nearby_platform_status nearby_platform_GattNotify(
|
||||
uint64_t peer_address, nearby_fp_Characteristic characteristic,
|
||||
const uint8_t* message, size_t length) {
|
||||
notifications.emplace(characteristic,
|
||||
std::vector<uint8_t>(message, message + length));
|
||||
return kNearbyStatusOK;
|
||||
}
|
||||
|
||||
nearby_platform_status nearby_platform_SetAdvertisement(
|
||||
const uint8_t* payload, size_t length,
|
||||
nearby_fp_AvertisementInterval interval) {
|
||||
if (payload == NULL || length == 0) {
|
||||
advertisement.clear();
|
||||
} else {
|
||||
advertisement.assign(payload, payload + length);
|
||||
}
|
||||
::interval = interval;
|
||||
return kNearbyStatusOK;
|
||||
}
|
||||
|
||||
int32_t nearby_platform_GetMessageStreamPsm() { return psm; }
|
||||
|
||||
// Initializes BLE
|
||||
nearby_platform_status nearby_platform_BleInit(
|
||||
const nearby_platform_BleInterface* callbacks) {
|
||||
ble_interface = callbacks;
|
||||
notifications.clear();
|
||||
advertisement.clear();
|
||||
interval = kDisabled;
|
||||
ble_address = kDefaultBleAddress;
|
||||
psm = kDefaultPsm;
|
||||
return kNearbyStatusOK;
|
||||
}
|
||||
|
||||
void nearby_test_fakes_SetPsm(int32_t value) { psm = value; }
|
||||
|
||||
std::vector<uint8_t>& nearby_test_fakes_GetAdvertisement() {
|
||||
return advertisement;
|
||||
}
|
||||
|
||||
nearby_platform_status nearby_test_fakes_GattReadModelId(uint8_t* output,
|
||||
size_t* length) {
|
||||
return ble_interface->on_gatt_read(peer_address, kModelId, output, length);
|
||||
}
|
||||
|
||||
nearby_platform_status nearby_fp_fakes_ReceiveKeyBasedPairingRequest(
|
||||
const uint8_t* request, size_t length) {
|
||||
return ble_interface->on_gatt_write(peer_address, kKeyBasedPairing, request,
|
||||
length);
|
||||
}
|
||||
|
||||
nearby_platform_status nearby_fp_fakes_ReceivePasskey(const uint8_t* request,
|
||||
size_t length) {
|
||||
return ble_interface->on_gatt_write(peer_address, kPasskey, request, length);
|
||||
}
|
||||
|
||||
nearby_platform_status nearby_fp_fakes_ReceiveAccountKeyWrite(
|
||||
const uint8_t* request, size_t length) {
|
||||
return ble_interface->on_gatt_write(peer_address, kAccountKey, request,
|
||||
length);
|
||||
}
|
||||
|
||||
nearby_platform_status nearby_fp_fakes_ReceiveAdditionalData(
|
||||
const uint8_t* request, size_t length) {
|
||||
return ble_interface->on_gatt_write(peer_address, kAdditionalData, request,
|
||||
length);
|
||||
}
|
||||
|
||||
nearby_platform_status nearby_fp_fakes_GattReadMessageStreamPsm(
|
||||
uint8_t* output, size_t* length) {
|
||||
return ble_interface->on_gatt_read(peer_address, kMessageStreamPsm, output,
|
||||
length);
|
||||
}
|
||||
@@ -1,165 +0,0 @@
|
||||
// Copyright 2022 Google LLC
|
||||
//
|
||||
// Licensed 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
|
||||
//
|
||||
// https://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 <cstring>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#include "nearby_platform_bt.h"
|
||||
|
||||
static const uint32_t kFastPairId = 0x101112;
|
||||
static const int8_t kTxLevel = 33;
|
||||
static const uint64_t kPublicAddress = 0xA0A1A2A3A4A5;
|
||||
// No secondary identity address by default.
|
||||
static const uint64_t kSecondaryPublicAddress = 0;
|
||||
static const uint32_t kLocalPasskey = 123456;
|
||||
static uint32_t remote_passkey;
|
||||
static uint64_t remote_address;
|
||||
static uint64_t paired_peer_address;
|
||||
static std::map<uint64_t, std::vector<uint8_t>> rfcomm_outputs;
|
||||
static std::vector<char> device_name;
|
||||
static bool pairing_mode = false;
|
||||
static uint64_t secondary_public_address = kSecondaryPublicAddress;
|
||||
|
||||
static const nearby_platform_BtInterface* bt_interface;
|
||||
// Returns Fast Pair Model Id.
|
||||
uint32_t nearby_platform_GetModelId() { return kFastPairId; }
|
||||
|
||||
int8_t nearby_platform_GetTxLevel() { return kTxLevel; }
|
||||
|
||||
// Returns public BR/EDR address
|
||||
uint64_t nearby_platform_GetPublicAddress() { return kPublicAddress; }
|
||||
|
||||
uint64_t nearby_platform_GetSecondaryPublicAddress() {
|
||||
return secondary_public_address;
|
||||
}
|
||||
|
||||
// Returns passkey used during pairing
|
||||
uint32_t nearby_platfrom_GetPairingPassKey() { return kLocalPasskey; }
|
||||
|
||||
void nearby_platform_SetRemotePasskey(uint32_t passkey) {
|
||||
remote_passkey = passkey;
|
||||
if (remote_passkey == kLocalPasskey &&
|
||||
remote_address != 0 & bt_interface != NULL) {
|
||||
paired_peer_address = remote_address;
|
||||
bt_interface->on_paired(remote_address);
|
||||
}
|
||||
}
|
||||
|
||||
nearby_platform_status nearby_platform_SendPairingRequest(
|
||||
uint64_t remote_party_br_edr_address) {
|
||||
remote_address = remote_party_br_edr_address;
|
||||
return kNearbyStatusOK;
|
||||
}
|
||||
|
||||
nearby_platform_status nearby_platform_SetFastPairCapabilities() {
|
||||
return kNearbyStatusOK;
|
||||
}
|
||||
|
||||
nearby_platform_status nearby_platform_SetDefaultCapabilities() {
|
||||
remote_address = 0;
|
||||
return kNearbyStatusOK;
|
||||
}
|
||||
|
||||
nearby_platform_status nearby_platform_BtInit(
|
||||
const nearby_platform_BtInterface* callbacks) {
|
||||
bt_interface = callbacks;
|
||||
remote_address = 0;
|
||||
remote_passkey = 0;
|
||||
paired_peer_address = 0;
|
||||
pairing_mode = false;
|
||||
secondary_public_address = kSecondaryPublicAddress;
|
||||
rfcomm_outputs.clear();
|
||||
return kNearbyStatusOK;
|
||||
}
|
||||
|
||||
uint64_t nearby_test_fakes_GetPairingRequestAddress() { return remote_address; }
|
||||
|
||||
uint32_t nearby_test_fakes_GetRemotePasskey() { return remote_passkey; }
|
||||
|
||||
void nearby_test_fakes_SimulatePairing(uint64_t peer_address) {
|
||||
remote_address = peer_address;
|
||||
if (bt_interface != NULL) {
|
||||
bt_interface->on_pairing_request(peer_address);
|
||||
}
|
||||
}
|
||||
|
||||
void nearby_test_fakes_SetSecondaryPublicAddress(uint64_t address) {
|
||||
secondary_public_address = address;
|
||||
}
|
||||
|
||||
uint64_t nearby_test_fakes_GetPairedDevice() { return paired_peer_address; }
|
||||
|
||||
void nearby_test_fakes_DevicePaired(uint64_t peer_address) {
|
||||
bt_interface->on_paired(peer_address);
|
||||
}
|
||||
|
||||
nearby_platform_status nearby_platform_SendMessageStream(uint64_t peer_address,
|
||||
const uint8_t* message,
|
||||
size_t length) {
|
||||
rfcomm_outputs.emplace(peer_address, std::vector<uint8_t>());
|
||||
auto rfcomm_output = rfcomm_outputs.find(peer_address);
|
||||
for (int i = 0; i < length; i++) {
|
||||
rfcomm_output->second.push_back(message[i]);
|
||||
}
|
||||
return kNearbyStatusOK;
|
||||
}
|
||||
|
||||
std::vector<uint8_t>& nearby_test_fakes_GetRfcommOutput(uint64_t peer_address) {
|
||||
return rfcomm_outputs[peer_address];
|
||||
}
|
||||
|
||||
std::vector<uint8_t>& nearby_test_fakes_GetRfcommOutput() {
|
||||
return nearby_test_fakes_GetRfcommOutput(paired_peer_address);
|
||||
}
|
||||
|
||||
nearby_platform_status nearby_platform_SetDeviceName(const char* name) {
|
||||
// + 1 for null terminator
|
||||
device_name = std::vector<char>(name, name + std::strlen(name) + 1);
|
||||
return kNearbyStatusOK;
|
||||
}
|
||||
|
||||
// Gets null-terminated device name string in UTF-8 encoding
|
||||
// pass buffer size in char, and get string length in char.
|
||||
nearby_platform_status nearby_platform_GetDeviceName(char* name,
|
||||
size_t* length) {
|
||||
if (*length < device_name.size()) {
|
||||
return kNearbyStatusResourceExhausted;
|
||||
}
|
||||
*length = device_name.size();
|
||||
std::memcpy(name, device_name.data(), device_name.size());
|
||||
return kNearbyStatusOK;
|
||||
}
|
||||
|
||||
bool nearby_platform_IsInPairingMode() { return pairing_mode; }
|
||||
|
||||
void nearby_test_fakes_SetInPairingMode(bool in_pairing_mode) {
|
||||
pairing_mode = in_pairing_mode;
|
||||
}
|
||||
|
||||
#if NEARBY_FP_MESSAGE_STREAM
|
||||
void nearby_test_fakes_MessageStreamConnected(uint64_t peer_address) {
|
||||
bt_interface->on_message_stream_connected(peer_address);
|
||||
}
|
||||
|
||||
void nearby_test_fakes_MessageStreamDisconnected(uint64_t peer_address) {
|
||||
bt_interface->on_message_stream_disconnected(peer_address);
|
||||
}
|
||||
|
||||
void nearby_test_fakes_MessageStreamReceived(uint64_t peer_address,
|
||||
const uint8_t* message,
|
||||
size_t length) {
|
||||
bt_interface->on_message_stream_received(peer_address, message, length);
|
||||
}
|
||||
#endif /* NEARBY_FP_MESSAGE_STREAM */
|
||||
@@ -1,198 +0,0 @@
|
||||
// Copyright 2022 Google LLC
|
||||
//
|
||||
// Licensed 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
|
||||
//
|
||||
// https://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.
|
||||
|
||||
// Copyright 2021 Google LLC.
|
||||
#ifndef NEARBY_TEST_FAKES_H
|
||||
#define NEARBY_TEST_FAKES_H
|
||||
#include <map>
|
||||
#include <queue>
|
||||
#include <vector>
|
||||
|
||||
#include "nearby.h"
|
||||
#include "nearby_platform_ble.h"
|
||||
|
||||
void nearby_test_fakes_SetRandomNumber(unsigned int value);
|
||||
void nearby_test_fakes_SetRandomNumberSequence(std::vector<uint8_t>& value);
|
||||
|
||||
std::vector<uint8_t> nearby_test_fakes_GetRawAccountKeys();
|
||||
|
||||
nearby_platform_status nearby_test_fakes_GattReadModelId(uint8_t* output,
|
||||
size_t* length);
|
||||
|
||||
#ifdef MBEDTLS_FOR_SSL
|
||||
extern "C" {
|
||||
#endif
|
||||
nearby_platform_status nearby_test_fakes_SetAntiSpoofingKey(
|
||||
const uint8_t private_key[32], const uint8_t public_key[64]);
|
||||
#ifdef MBEDTLS_FOR_SSL
|
||||
}
|
||||
#endif
|
||||
|
||||
nearby_platform_status nearby_test_fakes_GenSec256r1Secret(
|
||||
const uint8_t remote_party_public_key[64], uint8_t secret[32]);
|
||||
|
||||
nearby_platform_status nearby_test_fakes_Aes128Decrypt(
|
||||
const uint8_t input[AES_MESSAGE_SIZE_BYTES],
|
||||
uint8_t output[AES_MESSAGE_SIZE_BYTES],
|
||||
const uint8_t key[AES_MESSAGE_SIZE_BYTES]);
|
||||
nearby_platform_status nearby_test_fakes_Aes128Encrypt(
|
||||
const uint8_t input[AES_MESSAGE_SIZE_BYTES],
|
||||
uint8_t output[AES_MESSAGE_SIZE_BYTES],
|
||||
const uint8_t key[AES_MESSAGE_SIZE_BYTES]);
|
||||
|
||||
std::vector<uint8_t>& nearby_test_fakes_GetAdvertisement();
|
||||
|
||||
std::map<nearby_fp_Characteristic, std::vector<uint8_t>>&
|
||||
nearby_test_fakes_GetGattNotifications();
|
||||
|
||||
void nearby_test_fakes_SimulatePairing(uint64_t peer_address);
|
||||
nearby_platform_status nearby_fp_fakes_ReceiveKeyBasedPairingRequest(
|
||||
const uint8_t* request, size_t length);
|
||||
nearby_platform_status nearby_fp_fakes_ReceivePasskey(const uint8_t* request,
|
||||
size_t length);
|
||||
nearby_platform_status nearby_fp_fakes_ReceiveAccountKeyWrite(
|
||||
const uint8_t* request, size_t length);
|
||||
nearby_platform_status nearby_fp_fakes_ReceiveAdditionalData(
|
||||
const uint8_t* request, size_t length);
|
||||
nearby_platform_status nearby_fp_fakes_GattReadMessageStreamPsm(uint8_t* output,
|
||||
size_t* length);
|
||||
uint64_t nearby_test_fakes_GetPairingRequestAddress();
|
||||
uint32_t nearby_test_fakes_GetRemotePasskey();
|
||||
uint64_t nearby_test_fakes_GetPairedDevice();
|
||||
void nearby_test_fakes_DevicePaired(uint64_t peer_address);
|
||||
|
||||
class AccountKeyPair {
|
||||
public:
|
||||
AccountKeyPair(uint64_t bt_address, const std::vector<uint8_t>& account_key)
|
||||
: address_(bt_address), account_key_(account_key) {}
|
||||
AccountKeyPair(uint64_t bt_address, const uint8_t* account_key)
|
||||
: address_(bt_address),
|
||||
account_key_(account_key, account_key + ACCOUNT_KEY_SIZE_BYTES) {}
|
||||
|
||||
uint64_t address_;
|
||||
std::vector<uint8_t> account_key_;
|
||||
};
|
||||
|
||||
struct RawAccountKeyList {
|
||||
uint8_t num_keys;
|
||||
nearby_platform_AccountKeyInfo key[NEARBY_MAX_ACCOUNT_KEYS];
|
||||
};
|
||||
|
||||
class AccountKeyList {
|
||||
public:
|
||||
explicit AccountKeyList(const std::vector<uint8_t>& raw_values) {
|
||||
const RawAccountKeyList* list =
|
||||
reinterpret_cast<const RawAccountKeyList*>(raw_values.data());
|
||||
if (!list) return;
|
||||
|
||||
for (size_t i = 0; i < list->num_keys; i++) {
|
||||
uint64_t address = 0;
|
||||
#ifdef NEARBY_FP_ENABLE_SASS
|
||||
address = list->key[i].peer_address;
|
||||
#endif /* NEARBY_FP_ENABLE_SASS */
|
||||
key_pairs_.emplace_back(
|
||||
address, std::vector<uint8_t>(
|
||||
list->key[i].account_key,
|
||||
list->key[i].account_key + ACCOUNT_KEY_SIZE_BYTES));
|
||||
}
|
||||
}
|
||||
explicit AccountKeyList(const std::vector<AccountKeyPair>& key_pairs)
|
||||
: key_pairs_(key_pairs) {}
|
||||
|
||||
size_t size() { return key_pairs_.size(); }
|
||||
|
||||
std::vector<uint8_t> GetKey(int index) {
|
||||
return key_pairs_[index].account_key_;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> GetRawFormat() {
|
||||
RawAccountKeyList account_keys;
|
||||
account_keys.num_keys = size();
|
||||
for (size_t i = 0; i < size(); i++) {
|
||||
#ifdef NEARBY_FP_ENABLE_SASS
|
||||
account_keys.key[i].peer_address = key_pairs_[i].address_;
|
||||
#endif /* NEARBY_FP_ENABLE_SASS */
|
||||
for (size_t j = 0; j < key_pairs_[i].account_key_.size(); j++) {
|
||||
account_keys.key[i].account_key[j] = key_pairs_[i].account_key_[j];
|
||||
}
|
||||
}
|
||||
uint8_t* p = reinterpret_cast<uint8_t*>(&account_keys);
|
||||
return std::vector<uint8_t>(p, p + sizeof(account_keys));
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<AccountKeyPair> key_pairs_;
|
||||
};
|
||||
|
||||
void nearby_test_fakes_SetAccountKeys(const uint8_t* input, size_t length);
|
||||
void nearby_test_fakes_SetAccountKeys(
|
||||
std::vector<AccountKeyPair>& account_key_pairs);
|
||||
void nearby_test_fakes_SetAccountKeys(AccountKeyList& keys);
|
||||
|
||||
AccountKeyList nearby_test_fakes_GetAccountKeys();
|
||||
|
||||
void nearby_test_fakes_SetIsCharging(bool charging);
|
||||
|
||||
void nearby_test_fakes_SetRightBudBatteryLevel(unsigned battery_level);
|
||||
|
||||
void nearby_test_fakes_SetLeftBudBatteryLevel(unsigned battery_level);
|
||||
|
||||
void nearby_test_fakes_SetChargingCaseBatteryLevel(unsigned battery_level);
|
||||
|
||||
void nearby_test_fakes_BatteryTime(uint16_t battery_time);
|
||||
|
||||
void nearby_test_fakes_SetGetBatteryInfoResult(nearby_platform_status status);
|
||||
|
||||
std::vector<uint8_t>& nearby_test_fakes_GetRfcommOutput();
|
||||
std::vector<uint8_t>& nearby_test_fakes_GetRfcommOutput(uint64_t peer_address);
|
||||
|
||||
void nearby_test_fakes_MessageStreamConnected(uint64_t peer_address);
|
||||
|
||||
void nearby_test_fakes_MessageStreamDisconnected(uint64_t peer_address);
|
||||
|
||||
void nearby_test_fakes_MessageStreamReceived(uint64_t peer_address,
|
||||
const uint8_t* message,
|
||||
size_t length);
|
||||
|
||||
uint32_t nearby_test_fakes_GetNextTimerMs();
|
||||
// Sets current time and triggers the timer callback if it expired
|
||||
void nearby_test_fakes_SetCurrentTimeMs(uint32_t ms);
|
||||
|
||||
void nearby_test_fakes_SetInPairingMode(bool in_pairing_mode);
|
||||
|
||||
uint8_t nearby_test_fakes_GetRingCommand(void);
|
||||
|
||||
uint16_t nearby_test_fakes_GetRingTimeout(void);
|
||||
uint64_t nearby_test_fakes_GetSassSwitchActiveSourcePeerAddress();
|
||||
uint8_t nearby_test_fakes_GetSassSwitchActiveSourceFlags();
|
||||
uint64_t nearby_test_fakes_GetSassSwitchActiveSourcePreferredAudioSource();
|
||||
uint64_t nearby_test_fakes_GetSassSwitchBackPeerAddress();
|
||||
uint8_t nearby_test_fakes_GetSassSwitchBackFlags();
|
||||
uint64_t nearby_test_fakes_GetSassNotifyInitiatedConnectionPeerAddress();
|
||||
uint8_t nearby_test_fakes_GetSassNotifyInitiatedConnectionFlags();
|
||||
uint64_t nearby_test_fakes_GetSassDropConnectionTargetPeerAddress();
|
||||
uint8_t nearby_test_fakes_GetSassDropConnectionTargetFlags();
|
||||
void nearby_test_fakes_SassMultipointSwitch(uint8_t reason,
|
||||
uint64_t peer_address,
|
||||
const char* name);
|
||||
|
||||
#ifdef NEARBY_FP_ENABLE_SASS
|
||||
void nearby_test_fakes_SetActiveAudioSource(uint64_t peer_address);
|
||||
#endif /* NEARBY_FP_ENABLE_SASS */
|
||||
|
||||
void nearby_test_fakes_SetPsm(int32_t value);
|
||||
|
||||
void nearby_test_fakes_SetSecondaryPublicAddress(uint64_t address);
|
||||
|
||||
#endif /* NEARBY_TEST_FAKES_H */
|
||||
@@ -1,82 +0,0 @@
|
||||
// Copyright 2022 Google LLC
|
||||
//
|
||||
// Licensed 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
|
||||
//
|
||||
// https://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 <cstddef>
|
||||
|
||||
#include "nearby_assert.h"
|
||||
#include "nearby_platform_os.h"
|
||||
|
||||
typedef void (*timer)();
|
||||
static timer timer_callback;
|
||||
static uint32_t timer_trigger_time;
|
||||
static bool timer_has_run;
|
||||
static uint32_t current_time;
|
||||
static constexpr nearby_platform_RingingInfo kDefaultRingingInfo = {
|
||||
.ring_state = kRingStateStoppedReasonTimeout,
|
||||
.num_components = 3,
|
||||
.components = 0,
|
||||
.timeout = 0,
|
||||
};
|
||||
|
||||
static nearby_platform_RingingInfo ringing_info = kDefaultRingingInfo;
|
||||
|
||||
// Gets current time in ms.
|
||||
unsigned int nearby_platform_GetCurrentTimeMs() { return current_time; }
|
||||
|
||||
// Starts a timer. Returns an opaque timer handle or null on error.
|
||||
void* nearby_platform_StartTimer(void (*callback)(), unsigned int delay_ms) {
|
||||
timer_callback = callback;
|
||||
timer_trigger_time = nearby_platform_GetCurrentTimeMs() + delay_ms;
|
||||
timer_has_run = false;
|
||||
return (void*)timer_callback;
|
||||
}
|
||||
|
||||
// Cancels a timer
|
||||
nearby_platform_status nearby_platform_CancelTimer(void* timer) {
|
||||
NEARBY_ASSERT(timer == timer_callback);
|
||||
timer_callback = NULL;
|
||||
timer_trigger_time = 0;
|
||||
return kNearbyStatusOK;
|
||||
}
|
||||
|
||||
uint32_t nearby_test_fakes_GetNextTimerMs() { return timer_trigger_time; }
|
||||
|
||||
void nearby_test_fakes_SetCurrentTimeMs(uint32_t ms) {
|
||||
current_time = ms;
|
||||
if (!timer_has_run && timer_callback != NULL && timer_trigger_time <= ms) {
|
||||
timer_has_run = true;
|
||||
timer_callback();
|
||||
}
|
||||
}
|
||||
|
||||
nearby_platform_status nearby_platform_Ring(uint8_t command, uint16_t timeout) {
|
||||
ringing_info.components = command;
|
||||
ringing_info.timeout = timeout;
|
||||
ringing_info.ring_state = kRingStateStarted;
|
||||
return kNearbyStatusOK;
|
||||
}
|
||||
|
||||
uint8_t nearby_test_fakes_GetRingCommand(void) {
|
||||
return ringing_info.components;
|
||||
}
|
||||
|
||||
uint16_t nearby_test_fakes_GetRingTimeout(void) { return ringing_info.timeout; }
|
||||
|
||||
nearby_platform_status nearby_platform_OsInit() {
|
||||
current_time = 0;
|
||||
timer_callback = NULL;
|
||||
timer_trigger_time = 0;
|
||||
timer_has_run = false;
|
||||
return kNearbyStatusOK;
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
// Copyright 2022 Google LLC
|
||||
//
|
||||
// Licensed 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
|
||||
//
|
||||
// https://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 <algorithm>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#include "fakes.h"
|
||||
#include "nearby_platform_persistence.h"
|
||||
|
||||
static std::map<nearby_fp_StoredKey, std::vector<uint8_t>> storage;
|
||||
nearby_platform_status nearby_platform_LoadValue(nearby_fp_StoredKey key,
|
||||
uint8_t* output,
|
||||
size_t* length) {
|
||||
auto search = storage.find(key);
|
||||
if (search != storage.end()) {
|
||||
size_t value_length = search->second.size();
|
||||
if (value_length > *length) {
|
||||
*length = 0;
|
||||
return kNearbyStatusResourceExhausted;
|
||||
}
|
||||
*length = value_length;
|
||||
std::copy(search->second.begin(), search->second.end(), output);
|
||||
} else {
|
||||
// key not found.
|
||||
*length = 0;
|
||||
}
|
||||
return kNearbyStatusOK;
|
||||
}
|
||||
|
||||
nearby_platform_status nearby_platform_SaveValue(nearby_fp_StoredKey key,
|
||||
const uint8_t* input,
|
||||
size_t length) {
|
||||
storage[key].assign(input, input + length);
|
||||
return kNearbyStatusOK;
|
||||
}
|
||||
|
||||
nearby_platform_status nearby_platform_PersistenceInit() {
|
||||
storage.clear();
|
||||
return kNearbyStatusOK;
|
||||
}
|
||||
|
||||
void nearby_test_fakes_SetAccountKeys(
|
||||
std::vector<AccountKeyPair>& account_key_pairs) {
|
||||
AccountKeyList list(account_key_pairs);
|
||||
nearby_test_fakes_SetAccountKeys(list);
|
||||
}
|
||||
|
||||
void nearby_test_fakes_SetAccountKeys(const uint8_t* input, size_t length) {
|
||||
storage[kStoredKeyAccountKeyList].assign(input, input + length);
|
||||
}
|
||||
|
||||
std::vector<uint8_t> nearby_test_fakes_GetRawAccountKeys() {
|
||||
return storage[kStoredKeyAccountKeyList];
|
||||
}
|
||||
|
||||
void nearby_test_fakes_SetAccountKeys(AccountKeyList& keys) {
|
||||
auto v = keys.GetRawFormat();
|
||||
nearby_test_fakes_SetAccountKeys(v.data(), v.size());
|
||||
}
|
||||
|
||||
AccountKeyList nearby_test_fakes_GetAccountKeys() {
|
||||
return AccountKeyList(nearby_test_fakes_GetRawAccountKeys());
|
||||
}
|
||||
@@ -1,262 +0,0 @@
|
||||
// Copyright 2022 Google LLC
|
||||
//
|
||||
// Licensed 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
|
||||
//
|
||||
// https://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 <openssl/bn.h>
|
||||
#include <openssl/ec.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/sha.h>
|
||||
|
||||
#include <cerrno>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <queue>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
#include "fakes.h"
|
||||
#include "nearby_platform_se.h"
|
||||
|
||||
#pragma GCC diagnostic ignored "-Wunused-function"
|
||||
|
||||
static unsigned int random_value = 0;
|
||||
static std::queue<uint8_t> random_sequence;
|
||||
|
||||
static uint8_t private_key_store[32];
|
||||
|
||||
static std::unique_ptr<EVP_PKEY, void (*)(EVP_PKEY *)> anti_spoofing_key(
|
||||
NULL, EVP_PKEY_free);
|
||||
|
||||
static std::string ArrayToString(const uint8_t *data, size_t length) {
|
||||
std::stringstream output;
|
||||
output << "0x" << std::hex << std::setfill('0') << std::setw(2);
|
||||
for (int i = 0; i < length; i++) {
|
||||
output << (unsigned)data[i];
|
||||
}
|
||||
return output.str();
|
||||
}
|
||||
|
||||
// Generates a random number.
|
||||
uint8_t nearby_platform_Rand() {
|
||||
if (random_sequence.empty()) {
|
||||
return random_value;
|
||||
} else {
|
||||
uint8_t v = random_sequence.front();
|
||||
random_sequence.pop();
|
||||
return v;
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef NEARBY_PLATFORM_USE_MBEDTLS
|
||||
static SHA256_CTX sha256_context;
|
||||
|
||||
nearby_platform_status nearby_platform_Sha256Start() {
|
||||
SHA256_Init(&sha256_context);
|
||||
return kNearbyStatusOK;
|
||||
}
|
||||
|
||||
nearby_platform_status nearby_platform_Sha256Update(const void *data,
|
||||
size_t length) {
|
||||
SHA256_Update(&sha256_context, data, length);
|
||||
return kNearbyStatusOK;
|
||||
}
|
||||
|
||||
nearby_platform_status nearby_platform_Sha256Finish(uint8_t out[32]) {
|
||||
SHA256_Final(out, &sha256_context);
|
||||
return kNearbyStatusOK;
|
||||
}
|
||||
|
||||
// Encrypts a data block with AES128 in ECB mode.
|
||||
nearby_platform_status nearby_platform_Aes128Encrypt(const uint8_t input[16],
|
||||
uint8_t output[16],
|
||||
const uint8_t key[16]) {
|
||||
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
|
||||
int input_length = 16;
|
||||
int output_length = 16;
|
||||
|
||||
EVP_EncryptInit(ctx, EVP_aes_128_ecb(), key, NULL);
|
||||
|
||||
if (1 !=
|
||||
EVP_EncryptUpdate(ctx, output, &output_length, input, input_length)) {
|
||||
return kNearbyStatusError;
|
||||
}
|
||||
|
||||
EVP_CIPHER_CTX_free(ctx);
|
||||
return kNearbyStatusOK;
|
||||
}
|
||||
|
||||
// Encrypts a data block with AES128 in ECB mode.
|
||||
nearby_platform_status nearby_platform_Aes128Decrypt(const uint8_t input[16],
|
||||
uint8_t output[16],
|
||||
const uint8_t key[16]) {
|
||||
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
|
||||
int input_length = 16;
|
||||
int output_length = 16;
|
||||
|
||||
EVP_DecryptInit(ctx, EVP_aes_128_ecb(), key, NULL);
|
||||
EVP_CIPHER_CTX_set_padding(ctx, 0);
|
||||
|
||||
if (1 !=
|
||||
EVP_DecryptUpdate(ctx, output, &output_length, input, input_length)) {
|
||||
return kNearbyStatusError;
|
||||
}
|
||||
|
||||
EVP_CIPHER_CTX_free(ctx);
|
||||
return kNearbyStatusOK;
|
||||
}
|
||||
#endif /* NEARBY_PLATFORM_USE_MBEDTLS */
|
||||
|
||||
static EC_POINT *load_public_key(const uint8_t public_key[64]) {
|
||||
BN_CTX *bn_ctx;
|
||||
EC_KEY *key;
|
||||
EC_POINT *point;
|
||||
const EC_GROUP *group;
|
||||
uint8_t oct_key[65];
|
||||
|
||||
oct_key[0] = 0x04;
|
||||
memcpy(oct_key + 1, public_key, 64);
|
||||
bn_ctx = BN_CTX_new();
|
||||
key = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
|
||||
group = EC_KEY_get0_group(key);
|
||||
point = EC_POINT_new(group);
|
||||
if (1 != EC_POINT_oct2point(group, point, oct_key, sizeof(oct_key), bn_ctx))
|
||||
return NULL;
|
||||
BN_CTX_free(bn_ctx);
|
||||
EC_KEY_free(key);
|
||||
return point;
|
||||
}
|
||||
|
||||
static BIGNUM *load_private_key(const uint8_t private_key[32]) {
|
||||
uint8_t buffer[37];
|
||||
buffer[0] = buffer[1] = buffer[2] = 0;
|
||||
buffer[3] = 33;
|
||||
buffer[4] = 0;
|
||||
memcpy(buffer + 5, private_key, 32);
|
||||
return BN_mpi2bn(buffer, sizeof(buffer), NULL);
|
||||
}
|
||||
|
||||
#ifdef NEARBY_PLATFORM_HAS_SE
|
||||
// Generates a shared sec256p1 secret using remote party public key and this
|
||||
// device's private key.
|
||||
nearby_platform_status nearby_platform_GenSec256r1Secret(
|
||||
const uint8_t remote_party_public_key[64], uint8_t secret[32]) {
|
||||
EVP_PKEY_CTX *ctx;
|
||||
EVP_PKEY *peerkey;
|
||||
EC_POINT *peer_point;
|
||||
EC_KEY *ec_peer_key;
|
||||
size_t secret_len;
|
||||
|
||||
/* Create the context for the shared secret derivation */
|
||||
if (NULL == (ctx = EVP_PKEY_CTX_new(anti_spoofing_key.get(), NULL)))
|
||||
return kNearbyStatusError;
|
||||
|
||||
/* Initialise */
|
||||
if (1 != EVP_PKEY_derive_init(ctx)) return kNearbyStatusError;
|
||||
|
||||
if (NULL == (peer_point = load_public_key(remote_party_public_key)))
|
||||
return kNearbyStatusError;
|
||||
|
||||
ec_peer_key = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
|
||||
|
||||
if (1 != EC_KEY_set_public_key(ec_peer_key, peer_point))
|
||||
return kNearbyStatusError;
|
||||
|
||||
peerkey = EVP_PKEY_new();
|
||||
if (1 != EVP_PKEY_assign_EC_KEY(peerkey, ec_peer_key))
|
||||
return kNearbyStatusError;
|
||||
|
||||
/* Provide the peer public key */
|
||||
if (1 != EVP_PKEY_derive_set_peer(ctx, peerkey)) return kNearbyStatusError;
|
||||
|
||||
/* Determine buffer length for shared secret */
|
||||
if (1 != EVP_PKEY_derive(ctx, NULL, &secret_len)) return kNearbyStatusError;
|
||||
|
||||
if (secret_len != 32) return kNearbyStatusError;
|
||||
|
||||
/* Derive the shared secret */
|
||||
if (1 != (EVP_PKEY_derive(ctx, secret, &secret_len)))
|
||||
return kNearbyStatusError;
|
||||
|
||||
EVP_PKEY_CTX_free(ctx);
|
||||
EC_POINT_free(peer_point);
|
||||
EVP_PKEY_free(peerkey);
|
||||
|
||||
return kNearbyStatusOK;
|
||||
}
|
||||
#endif /* NEARBY_PLATFORM_HAS_SE */
|
||||
|
||||
void nearby_test_fakes_SetRandomNumber(unsigned int value) {
|
||||
random_value = value;
|
||||
}
|
||||
|
||||
void nearby_test_fakes_SetRandomNumberSequence(std::vector<uint8_t> &value) {
|
||||
for (auto &v : value) random_sequence.push(v);
|
||||
}
|
||||
|
||||
nearby_platform_status nearby_test_fakes_SetAntiSpoofingKey(
|
||||
const uint8_t private_key[32], const uint8_t public_key[64]) {
|
||||
EC_KEY *key;
|
||||
BIGNUM *prv;
|
||||
EC_POINT *pub;
|
||||
|
||||
prv = load_private_key(private_key);
|
||||
if (prv == NULL) return kNearbyStatusError;
|
||||
pub = load_public_key(public_key);
|
||||
if (pub == NULL) return kNearbyStatusError;
|
||||
|
||||
key = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
|
||||
|
||||
if (1 != EC_KEY_set_private_key(key, prv)) return kNearbyStatusError;
|
||||
if (1 != EC_KEY_set_public_key(key, pub)) return kNearbyStatusError;
|
||||
|
||||
anti_spoofing_key.reset(EVP_PKEY_new());
|
||||
if (1 != EVP_PKEY_assign_EC_KEY(anti_spoofing_key.get(), key))
|
||||
return kNearbyStatusError;
|
||||
|
||||
memcpy(private_key_store, private_key, 32);
|
||||
|
||||
BN_free(prv);
|
||||
EC_POINT_free(pub);
|
||||
return kNearbyStatusOK;
|
||||
}
|
||||
|
||||
nearby_platform_status nearby_test_fakes_GenSec256r1Secret(
|
||||
const uint8_t remote_party_public_key[64], uint8_t secret[32]) {
|
||||
return nearby_platform_GenSec256r1Secret(remote_party_public_key, secret);
|
||||
}
|
||||
|
||||
nearby_platform_status nearby_test_fakes_Aes128Decrypt(
|
||||
const uint8_t input[AES_MESSAGE_SIZE_BYTES],
|
||||
uint8_t output[AES_MESSAGE_SIZE_BYTES],
|
||||
const uint8_t key[AES_MESSAGE_SIZE_BYTES]) {
|
||||
return nearby_platform_Aes128Decrypt(input, output, key);
|
||||
}
|
||||
|
||||
nearby_platform_status nearby_test_fakes_Aes128Encrypt(
|
||||
const uint8_t input[AES_MESSAGE_SIZE_BYTES],
|
||||
uint8_t output[AES_MESSAGE_SIZE_BYTES],
|
||||
const uint8_t key[AES_MESSAGE_SIZE_BYTES]) {
|
||||
return nearby_platform_Aes128Encrypt(input, output, key);
|
||||
}
|
||||
|
||||
const uint8_t *nearby_platform_GetAntiSpoofingPrivateKey() {
|
||||
return private_key_store;
|
||||
}
|
||||
|
||||
// Initializes secure element module
|
||||
nearby_platform_status nearby_platform_SecureElementInit() {
|
||||
random_value = 0;
|
||||
random_sequence = std::queue<uint8_t>();
|
||||
return kNearbyStatusOK;
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
// Copyright 2022 Google LLC
|
||||
//
|
||||
// Licensed 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
|
||||
//
|
||||
// https://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 <stdlib.h>
|
||||
|
||||
#include <cstdarg>
|
||||
#include <cstdio>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
#include "nearby_platform_trace.h"
|
||||
|
||||
void nearby_platform_Trace(nearby_platform_TraceLevel level,
|
||||
const char *filename, int lineno, const char *fmt,
|
||||
...) {
|
||||
char buff[1024];
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
|
||||
vsnprintf(buff, sizeof(buff), fmt, args);
|
||||
std::cout << filename << ":" << lineno << " " << buff << std::endl;
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void nearby_platfrom_CrashOnAssert(const char *filename, int lineno,
|
||||
const char *reason) {
|
||||
fprintf(stderr, "ASSERT %s, %s:%d\n", reason, filename, lineno);
|
||||
abort();
|
||||
}
|
||||
|
||||
void nearby_platform_TraceInit(void) {}
|
||||
@@ -1,363 +0,0 @@
|
||||
// Copyright 2022 Google LLC
|
||||
//
|
||||
// Licensed 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
|
||||
//
|
||||
// https://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 <deque>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
#include "fakes.h"
|
||||
#include "gmock/gmock.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "nearby.h"
|
||||
#include "nearby_message_stream.h"
|
||||
|
||||
#if NEARBY_FP_MESSAGE_STREAM
|
||||
constexpr uint64_t kPeerAddress = 0x101112;
|
||||
constexpr size_t kBufferSize = 64;
|
||||
constexpr size_t kMaxPayloadSize =
|
||||
kBufferSize - sizeof(nearby_message_stream_Metadata);
|
||||
constexpr size_t kHeaderSize = 4;
|
||||
|
||||
using ::testing::ElementsAreArray;
|
||||
|
||||
class StreamMessage {
|
||||
public:
|
||||
explicit StreamMessage(nearby_message_stream_Message* message)
|
||||
: StreamMessage(message->message_group, message->message_code,
|
||||
std::vector<uint8_t>(message->data,
|
||||
message->data + message->length)) {}
|
||||
StreamMessage(uint8_t group, uint8_t code) : group_(group), code_(code) {}
|
||||
StreamMessage(uint8_t group, uint8_t code, std::vector<uint8_t> data)
|
||||
: group_(group), code_(code), data_(data) {}
|
||||
|
||||
bool operator==(const StreamMessage& b) const {
|
||||
return this->group_ == b.group_ && this->code_ == b.code_ &&
|
||||
this->data_ == b.data_;
|
||||
}
|
||||
|
||||
private:
|
||||
unsigned int group_;
|
||||
unsigned int code_;
|
||||
std::vector<uint8_t> data_;
|
||||
friend std::ostream& operator<<(std::ostream& os,
|
||||
const StreamMessage& message);
|
||||
};
|
||||
|
||||
static std::string VecToString(std::vector<uint8_t> data) {
|
||||
std::stringstream output;
|
||||
output << "0x" << std::hex;
|
||||
for (int i = 0; i < data.size(); i++) {
|
||||
output << std::setfill('0') << std::setw(2) << (unsigned)data[i];
|
||||
}
|
||||
return output.str();
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const StreamMessage& message) {
|
||||
os << std::hex;
|
||||
os << "group: 0x" << std::setfill('0') << std::setw(2) << message.group_;
|
||||
os << " code: 0x" << std::setfill('0') << std::setw(2) << message.code_;
|
||||
os << std::dec << " length: " << message.data_.size();
|
||||
if (message.data_.size() > 0) {
|
||||
os << " data: " << VecToString(message.data_);
|
||||
}
|
||||
return os;
|
||||
}
|
||||
|
||||
uint8_t buffer[kBufferSize];
|
||||
|
||||
void OnMessageReceived(uint64_t peer_address,
|
||||
nearby_message_stream_Message* message);
|
||||
|
||||
class MessageStreamTest : public ::testing::Test {
|
||||
public:
|
||||
void Read(const uint8_t* data, size_t length) {
|
||||
nearby_message_stream_Read(&stream_state_, data, length);
|
||||
}
|
||||
|
||||
void ReadByteByByte(const uint8_t* data, size_t length) {
|
||||
for (int i = 0; i < length; i++) {
|
||||
nearby_message_stream_Read(&stream_state_, data + i, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void Send(const nearby_message_stream_Message* message) {
|
||||
nearby_message_stream_Send(kPeerAddress, message);
|
||||
}
|
||||
|
||||
void SendAck(const nearby_message_stream_Message* message) {
|
||||
nearby_message_stream_SendAck(kPeerAddress, message);
|
||||
}
|
||||
|
||||
void SendNack(const nearby_message_stream_Message* message,
|
||||
uint8_t fail_reason) {
|
||||
nearby_message_stream_SendNack(kPeerAddress, message, fail_reason);
|
||||
}
|
||||
|
||||
protected:
|
||||
void SetUp() override;
|
||||
|
||||
std::deque<StreamMessage> received_messages_;
|
||||
|
||||
private:
|
||||
void AddMessage(nearby_message_stream_Message* message) {
|
||||
received_messages_.emplace_back(StreamMessage(message));
|
||||
}
|
||||
// To allow access to |AddMessage|
|
||||
friend void OnMessageReceived(uint64_t peer_address,
|
||||
nearby_message_stream_Message* message);
|
||||
|
||||
nearby_message_stream_State stream_state_ = {
|
||||
.on_message_received = OnMessageReceived,
|
||||
.peer_address = kPeerAddress,
|
||||
.length = sizeof(buffer),
|
||||
.buffer = buffer};
|
||||
}* test_fixture;
|
||||
|
||||
void MessageStreamTest::SetUp() {
|
||||
test_fixture = this;
|
||||
nearby_test_fakes_GetRfcommOutput(kPeerAddress).clear();
|
||||
nearby_message_stream_Init(&stream_state_);
|
||||
}
|
||||
|
||||
void OnMessageReceived(uint64_t peer_address,
|
||||
nearby_message_stream_Message* message) {
|
||||
EXPECT_EQ(kPeerAddress, peer_address);
|
||||
test_fixture->AddMessage(message);
|
||||
}
|
||||
|
||||
TEST_F(MessageStreamTest, ReadWholeMessageWithNoData) {
|
||||
uint8_t group = 120;
|
||||
uint8_t code = 130;
|
||||
uint8_t message[] = {group, code, 0, 0};
|
||||
|
||||
Read(message, sizeof(message));
|
||||
|
||||
ASSERT_EQ(1, received_messages_.size());
|
||||
ASSERT_EQ(StreamMessage(group, code), received_messages_[0]);
|
||||
}
|
||||
|
||||
TEST_F(MessageStreamTest, ReadMessageInChunksWithNoData) {
|
||||
uint8_t group = 120;
|
||||
uint8_t code = 130;
|
||||
uint8_t message[] = {group, code, 0, 0};
|
||||
|
||||
ReadByteByByte(message, sizeof(message));
|
||||
|
||||
ASSERT_EQ(1, received_messages_.size());
|
||||
ASSERT_EQ(StreamMessage(group, code), received_messages_[0]);
|
||||
}
|
||||
|
||||
TEST_F(MessageStreamTest, ReadWholeMessageSmallPayload) {
|
||||
uint8_t group = 120;
|
||||
uint8_t code = 130;
|
||||
uint8_t message[] = {group, code, 0, 1, 30};
|
||||
|
||||
Read(message, sizeof(message));
|
||||
|
||||
ASSERT_EQ(1, received_messages_.size());
|
||||
ASSERT_EQ(StreamMessage(group, code,
|
||||
std::vector<uint8_t>(message + kHeaderSize,
|
||||
message + sizeof(message))),
|
||||
received_messages_[0]);
|
||||
}
|
||||
|
||||
TEST_F(MessageStreamTest, ReadMessageInChunksSmallPayload) {
|
||||
uint8_t group = 120;
|
||||
uint8_t code = 130;
|
||||
uint8_t message[] = {group, code, 0, 1, 30};
|
||||
|
||||
ReadByteByByte(message, sizeof(message));
|
||||
|
||||
ASSERT_EQ(1, received_messages_.size());
|
||||
ASSERT_EQ(StreamMessage(group, code,
|
||||
std::vector<uint8_t>(message + kHeaderSize,
|
||||
message + sizeof(message))),
|
||||
received_messages_[0]);
|
||||
}
|
||||
|
||||
TEST_F(MessageStreamTest, ReadWholeMessageMaximumPayloadSize) {
|
||||
uint8_t group = 120;
|
||||
uint8_t code = 130;
|
||||
uint8_t message[kHeaderSize + kMaxPayloadSize];
|
||||
message[0] = group;
|
||||
message[1] = code;
|
||||
message[2] = kMaxPayloadSize >> 8;
|
||||
message[3] = kMaxPayloadSize;
|
||||
for (unsigned i = 0; i < kMaxPayloadSize; i++) {
|
||||
message[kHeaderSize + i] = i;
|
||||
}
|
||||
|
||||
Read(message, sizeof(message));
|
||||
|
||||
ASSERT_EQ(1, received_messages_.size());
|
||||
ASSERT_EQ(StreamMessage(group, code,
|
||||
std::vector<uint8_t>(message + kHeaderSize,
|
||||
message + sizeof(message))),
|
||||
received_messages_[0]);
|
||||
}
|
||||
|
||||
TEST_F(MessageStreamTest, ReadWholeMessageTruncatedPayload) {
|
||||
uint8_t group = 120;
|
||||
uint8_t code = 130;
|
||||
constexpr size_t kPayloadSize = 0x102;
|
||||
uint8_t message[kHeaderSize + kPayloadSize];
|
||||
message[0] = group;
|
||||
message[1] = code;
|
||||
message[2] = 0x01;
|
||||
message[3] = 0x02;
|
||||
for (unsigned i = 0; i < kPayloadSize; i++) {
|
||||
message[kHeaderSize + i] = i;
|
||||
}
|
||||
|
||||
Read(message, sizeof(message));
|
||||
|
||||
ASSERT_EQ(1, received_messages_.size());
|
||||
ASSERT_EQ(StreamMessage(
|
||||
group, code,
|
||||
std::vector<uint8_t>(message + kHeaderSize,
|
||||
message + kHeaderSize + kMaxPayloadSize)),
|
||||
received_messages_[0]);
|
||||
}
|
||||
|
||||
TEST_F(MessageStreamTest, ReadMessageInChunksTruncatedPayload) {
|
||||
uint8_t group = 120;
|
||||
uint8_t code = 130;
|
||||
constexpr size_t kPayloadSize = 0x102;
|
||||
uint8_t message[kHeaderSize + kPayloadSize];
|
||||
message[0] = group;
|
||||
message[1] = code;
|
||||
message[2] = 0x01;
|
||||
message[3] = 0x02;
|
||||
for (unsigned i = 0; i < kPayloadSize; i++) {
|
||||
message[kHeaderSize + i] = i;
|
||||
}
|
||||
|
||||
ReadByteByByte(message, sizeof(message));
|
||||
|
||||
ASSERT_EQ(1, received_messages_.size());
|
||||
ASSERT_EQ(StreamMessage(
|
||||
group, code,
|
||||
std::vector<uint8_t>(message + kHeaderSize,
|
||||
message + kHeaderSize + kMaxPayloadSize)),
|
||||
received_messages_[0]);
|
||||
}
|
||||
|
||||
TEST_F(MessageStreamTest, ReadTwoMessages) {
|
||||
uint8_t group = 120;
|
||||
uint8_t code = 130;
|
||||
uint8_t group2 = 121;
|
||||
uint8_t code2 = 131;
|
||||
uint8_t message[] = {group, code, 0, 1, 30, group2, code2, 0, 2, 31, 32};
|
||||
|
||||
Read(message, sizeof(message));
|
||||
|
||||
ASSERT_EQ(2, received_messages_.size());
|
||||
ASSERT_EQ(StreamMessage(group, code,
|
||||
std::vector<uint8_t>(message + 4, message + 5)),
|
||||
received_messages_[0]);
|
||||
ASSERT_EQ(StreamMessage(group2, code2,
|
||||
std::vector<uint8_t>(message + 9, message + 11)),
|
||||
received_messages_[1]);
|
||||
}
|
||||
|
||||
TEST_F(MessageStreamTest, ReadTwoMessagesByteByByte) {
|
||||
uint8_t group = 120;
|
||||
uint8_t code = 130;
|
||||
uint8_t group2 = 121;
|
||||
uint8_t code2 = 131;
|
||||
uint8_t message[] = {group, code, 0, 1, 30, group2, code2, 0, 2, 31, 32};
|
||||
|
||||
ReadByteByByte(message, sizeof(message));
|
||||
|
||||
ASSERT_EQ(2, received_messages_.size());
|
||||
ASSERT_EQ(StreamMessage(group, code,
|
||||
std::vector<uint8_t>(message + 4, message + 5)),
|
||||
received_messages_[0]);
|
||||
ASSERT_EQ(StreamMessage(group2, code2,
|
||||
std::vector<uint8_t>(message + 9, message + 11)),
|
||||
received_messages_[1]);
|
||||
}
|
||||
|
||||
TEST_F(MessageStreamTest, SendMessageNoPayload) {
|
||||
nearby_message_stream_Message message{
|
||||
.message_group = 10,
|
||||
.message_code = 20,
|
||||
.length = 0,
|
||||
.data = nullptr,
|
||||
};
|
||||
constexpr uint8_t kExpectedOutput[] = {10, 20, 0, 0};
|
||||
|
||||
Send(&message);
|
||||
|
||||
ASSERT_THAT(
|
||||
kExpectedOutput,
|
||||
ElementsAreArray(nearby_test_fakes_GetRfcommOutput(kPeerAddress)));
|
||||
}
|
||||
|
||||
TEST_F(MessageStreamTest, SendMessageWithPayload) {
|
||||
uint8_t payload[] = {20, 21, 22, 23, 24};
|
||||
nearby_message_stream_Message message{
|
||||
.message_group = 10,
|
||||
.message_code = 11,
|
||||
.length = sizeof(payload),
|
||||
.data = payload,
|
||||
};
|
||||
constexpr uint8_t kExpectedOutput[] = {10, 11, 0, sizeof(payload), 20, 21,
|
||||
22, 23, 24};
|
||||
|
||||
Send(&message);
|
||||
|
||||
ASSERT_THAT(
|
||||
kExpectedOutput,
|
||||
ElementsAreArray(nearby_test_fakes_GetRfcommOutput(kPeerAddress)));
|
||||
}
|
||||
|
||||
TEST_F(MessageStreamTest, SendAck) {
|
||||
nearby_message_stream_Message message{
|
||||
.message_group = 10,
|
||||
.message_code = 20,
|
||||
.length = 0,
|
||||
.data = nullptr,
|
||||
};
|
||||
constexpr uint8_t kExpectedOutput[] = {0xFF, 1, 0, 2, 10, 20};
|
||||
|
||||
SendAck(&message);
|
||||
|
||||
ASSERT_THAT(
|
||||
kExpectedOutput,
|
||||
ElementsAreArray(nearby_test_fakes_GetRfcommOutput(kPeerAddress)));
|
||||
}
|
||||
|
||||
TEST_F(MessageStreamTest, SendNack) {
|
||||
nearby_message_stream_Message message{
|
||||
.message_group = 10,
|
||||
.message_code = 20,
|
||||
.length = 0,
|
||||
.data = nullptr,
|
||||
};
|
||||
constexpr uint8_t kFailReason = 0x88;
|
||||
constexpr uint8_t kExpectedOutput[] = {0xFF, 2, 0, 3, kFailReason, 10, 20};
|
||||
|
||||
SendNack(&message, kFailReason);
|
||||
|
||||
ASSERT_THAT(
|
||||
kExpectedOutput,
|
||||
ElementsAreArray(nearby_test_fakes_GetRfcommOutput(kPeerAddress)));
|
||||
}
|
||||
#endif /* NEARBY_FP_MESSAGE_STREAM */
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,108 +0,0 @@
|
||||
// Copyright 2022 Google LLC
|
||||
//
|
||||
// Licensed 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
|
||||
//
|
||||
// https://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.
|
||||
|
||||
//
|
||||
// gen_secret module
|
||||
//
|
||||
// Implements the nearby_platform_GenSec256r1Secret() function, using the
|
||||
// MBEDTLS package developed by ARM.
|
||||
//
|
||||
// To use the package, uncomment the NEARBY_PLATFORM_USE_MBEDTLS define in
|
||||
// config.mk.
|
||||
//
|
||||
// This routine was separated from the mbedtls.c code because an implementation
|
||||
// may need to implement the shared secret function using a hardware embedded
|
||||
// key. In such an implementation, the actual private key is not directly
|
||||
// accessable, but rather the shared secret is generated using the public key
|
||||
// and the sequestered private key without ever revealing the private key in
|
||||
// code.
|
||||
//
|
||||
|
||||
#define MBEDTLS_ALLOW_PRIVATE_ACCESS
|
||||
|
||||
#include <mbedtls/aes.h>
|
||||
#include <mbedtls/ecdh.h>
|
||||
#include <mbedtls/ecp.h>
|
||||
#include <mbedtls/error.h>
|
||||
#include <mbedtls/md.h> /* generic interface */
|
||||
#include <mbedtls/sha256.h>
|
||||
#if (MBEDTLS_VERSION_NUMBER >= 0x03000000)
|
||||
#include <mbedtls/compat-2.x.h>
|
||||
#endif
|
||||
|
||||
#include <nearby_platform_se.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifndef NEARBY_PLATFORM_HAS_SE
|
||||
static int crypto_rand(void* const seed, uint8_t* const out,
|
||||
size_t const size) {
|
||||
(void)seed;
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
out[i] = rand() % UINT8_MAX;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a shared sec256p1 secret using remote party public key and this
|
||||
* device's private key.
|
||||
*/
|
||||
nearby_platform_status nearby_platform_GenSec256r1Secret(
|
||||
const uint8_t remote_party_public_key[64], uint8_t shared_secret[32]) {
|
||||
nearby_platform_status status = kNearbyStatusError;
|
||||
mbedtls_ecp_group grp;
|
||||
mbedtls_ecp_point pub;
|
||||
mbedtls_mpi prv;
|
||||
mbedtls_mpi secret;
|
||||
|
||||
mbedtls_ecp_group_init(&grp);
|
||||
mbedtls_ecp_point_init(&pub);
|
||||
mbedtls_mpi_init(&prv);
|
||||
mbedtls_mpi_init(&secret);
|
||||
|
||||
mbedtls_mpi_uint p = 1;
|
||||
pub.Z.p = &p;
|
||||
pub.Z.n = 1;
|
||||
|
||||
const uint8_t* pkp;
|
||||
|
||||
pkp = nearby_platform_GetAntiSpoofingPrivateKey();
|
||||
if (!pkp) {
|
||||
goto exit;
|
||||
}
|
||||
if (mbedtls_ecp_group_load(&grp, MBEDTLS_ECP_DP_SECP256R1) != 0) goto exit;
|
||||
if (mbedtls_mpi_read_binary(&pub.X, remote_party_public_key, 32) != 0)
|
||||
goto exit;
|
||||
if (mbedtls_mpi_read_binary(&pub.Y, remote_party_public_key + 32, 32) != 0)
|
||||
goto exit;
|
||||
if (mbedtls_mpi_read_binary(&prv, pkp, 32) != 0) goto exit;
|
||||
if ((mbedtls_ecdh_compute_shared(&grp, &secret, &pub, &prv, crypto_rand,
|
||||
NULL)) != 0)
|
||||
goto exit;
|
||||
if (mbedtls_mpi_write_binary(&secret, shared_secret, 32) != 0) goto exit;
|
||||
|
||||
status = kNearbyStatusOK;
|
||||
|
||||
exit:
|
||||
pub.Z.p = NULL;
|
||||
pub.Z.n = 0;
|
||||
|
||||
mbedtls_ecp_group_free(&grp);
|
||||
mbedtls_ecp_point_free(&pub);
|
||||
mbedtls_mpi_free(&prv);
|
||||
mbedtls_mpi_free(&secret);
|
||||
|
||||
return status;
|
||||
}
|
||||
#endif /* NEARBY_PLATFORM_HAS_SE */
|
||||
@@ -1,121 +0,0 @@
|
||||
// Copyright 2022 Google LLC
|
||||
//
|
||||
// Licensed 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
|
||||
//
|
||||
// https://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.
|
||||
|
||||
//
|
||||
// MBEDTLS module
|
||||
//
|
||||
// Purpose: Implements the cryptographic functions used by fp-provider using the
|
||||
// MBEDTLS package developed by ARM.
|
||||
//
|
||||
// To use the package, uncomment the NEARBY_PLATFORM_USE_MBEDTLS define in
|
||||
// config.mk.
|
||||
//
|
||||
// The following features are implemented here:
|
||||
//
|
||||
// nearby_platform_Sha256Start(), nearby_platform_Sha256Update(),
|
||||
// nearby_platform_Sha256Finish()
|
||||
//
|
||||
// Implements the SHA function across and arbitrary length block. Partial
|
||||
// blocks can be sent, and the resulting SHA will be over all blocks.
|
||||
//
|
||||
// nearby_platform_Aes128Encrypt(), nearby_platform_Aes128Decrypt()
|
||||
//
|
||||
// Encrypt and decrypt a block of data with a given key.
|
||||
//
|
||||
// Note that the required function nearby_platform_GenSec256r1Secret() is in a
|
||||
// separate file, gen_secret.c.
|
||||
//
|
||||
|
||||
#include <mbedtls/aes.h>
|
||||
#include <mbedtls/ecdh.h>
|
||||
#include <mbedtls/ecp.h>
|
||||
#include <mbedtls/md.h> /* generic interface */
|
||||
#include <mbedtls/sha256.h>
|
||||
#if (MBEDTLS_VERSION_NUMBER >= 0x03000000)
|
||||
#include <mbedtls/compat-2.x.h>
|
||||
#endif
|
||||
|
||||
#include <nearby_platform_se.h>
|
||||
|
||||
static mbedtls_sha256_context sha256_ctx;
|
||||
|
||||
nearby_platform_status nearby_platform_Sha256Start() {
|
||||
nearby_platform_status status = kNearbyStatusError;
|
||||
mbedtls_sha256_init(&sha256_ctx);
|
||||
if (mbedtls_sha256_starts_ret(&sha256_ctx, 0) == 0) {
|
||||
status = kNearbyStatusOK;
|
||||
} else {
|
||||
mbedtls_sha256_free(&sha256_ctx);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
nearby_platform_status nearby_platform_Sha256Update(const void* data,
|
||||
size_t length) {
|
||||
nearby_platform_status status = kNearbyStatusError;
|
||||
if (mbedtls_sha256_update_ret(&sha256_ctx, (const unsigned char*)data,
|
||||
length) == 0) {
|
||||
status = kNearbyStatusOK;
|
||||
} else {
|
||||
mbedtls_sha256_free(&sha256_ctx);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
nearby_platform_status nearby_platform_Sha256Finish(uint8_t out[32]) {
|
||||
nearby_platform_status status = kNearbyStatusError;
|
||||
if (mbedtls_sha256_finish_ret(&sha256_ctx, out) == 0) {
|
||||
status = kNearbyStatusOK;
|
||||
}
|
||||
mbedtls_sha256_free(&sha256_ctx);
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encrypts a data block with AES128 in ECB mode.
|
||||
*/
|
||||
nearby_platform_status nearby_platform_Aes128Encrypt(
|
||||
const uint8_t input[AES_MESSAGE_SIZE_BYTES],
|
||||
uint8_t output[AES_MESSAGE_SIZE_BYTES],
|
||||
const uint8_t key[AES_MESSAGE_SIZE_BYTES]) {
|
||||
nearby_platform_status status = kNearbyStatusError;
|
||||
mbedtls_aes_context ctx;
|
||||
mbedtls_aes_init(&ctx);
|
||||
if (mbedtls_aes_setkey_enc(&ctx, key, 128) != 0) goto exit;
|
||||
if (mbedtls_aes_crypt_ecb(&ctx, MBEDTLS_AES_ENCRYPT, input, output) != 0)
|
||||
goto exit;
|
||||
status = kNearbyStatusOK;
|
||||
exit:
|
||||
mbedtls_aes_free(&ctx);
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypts a data block with AES128 in ECB mode.
|
||||
*/
|
||||
nearby_platform_status nearby_platform_Aes128Decrypt(
|
||||
const uint8_t input[AES_MESSAGE_SIZE_BYTES],
|
||||
uint8_t output[AES_MESSAGE_SIZE_BYTES],
|
||||
const uint8_t key[AES_MESSAGE_SIZE_BYTES]) {
|
||||
nearby_platform_status status = kNearbyStatusError;
|
||||
mbedtls_aes_context ctx;
|
||||
mbedtls_aes_init(&ctx);
|
||||
if (mbedtls_aes_setkey_dec(&ctx, key, 128) != 0) goto exit;
|
||||
if (mbedtls_aes_crypt_ecb(&ctx, MBEDTLS_AES_DECRYPT, input, output) != 0)
|
||||
goto exit;
|
||||
status = kNearbyStatusOK;
|
||||
exit:
|
||||
mbedtls_aes_free(&ctx);
|
||||
return status;
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
// Copyright 2022 Google LLC
|
||||
//
|
||||
// Licensed 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
|
||||
//
|
||||
// https://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.
|
||||
|
||||
#ifndef NEARBY_ASSERT_H
|
||||
#define NEARBY_ASSERT_H
|
||||
|
||||
#include "nearby.h"
|
||||
#include "nearby_platform_trace.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#ifdef __NEARBY_SHORT_FILE__
|
||||
#define NEARBY_ASSERT(cond) \
|
||||
do { \
|
||||
if (!(cond)) { \
|
||||
nearby_platfrom_CrashOnAssert(__NEARBY_SHORT_FILE__, __LINE__, #cond); \
|
||||
} \
|
||||
} while (0)
|
||||
#else
|
||||
#define NEARBY_ASSERT(cond) \
|
||||
do { \
|
||||
if (!(cond)) { \
|
||||
nearby_platfrom_CrashOnAssert(__FILE__, __LINE__, #cond); \
|
||||
} \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* NEARBY_ASSERT_H */
|
||||
@@ -1,79 +0,0 @@
|
||||
// Copyright 2022 Google LLC
|
||||
//
|
||||
// Licensed 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
|
||||
//
|
||||
// https://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.
|
||||
|
||||
#ifndef NEARBY_CONFIG_H
|
||||
#define NEARBY_CONFIG_H
|
||||
|
||||
// Support FP Battery Notification extension
|
||||
#ifndef NEARBY_FP_ENABLE_BATTERY_NOTIFICATION
|
||||
#define NEARBY_FP_ENABLE_BATTERY_NOTIFICATION 1
|
||||
#endif /* NEARBY_FP_ENABLE_BATTERY_NOTIFICATION */
|
||||
|
||||
// Support FP Additional Data extension
|
||||
#ifndef NEARBY_FP_ENABLE_ADDITIONAL_DATA
|
||||
#define NEARBY_FP_ENABLE_ADDITIONAL_DATA 1
|
||||
#endif /* NEARBY_FP_ENABLE_ADDITIONAL_DATA */
|
||||
|
||||
// Personalized name max size in bytes
|
||||
#define PERSONALIZED_NAME_MAX_SIZE 64
|
||||
|
||||
// Support FP Message Stream extension
|
||||
#ifndef NEARBY_FP_MESSAGE_STREAM
|
||||
#define NEARBY_FP_MESSAGE_STREAM 1
|
||||
#endif /* NEARBY_FP_MESSAGE_STREAM */
|
||||
|
||||
// Number of salt bytes to use in advertisements
|
||||
#define NEARBY_FP_SALT_SIZE 2
|
||||
|
||||
// Does the platform have a native BLE address rotation routine?
|
||||
// #define NEARBY_FP_HAVE_BLE_ADDRESS_ROTATION
|
||||
|
||||
// Support Smart Audio Source Switching
|
||||
// #define NEARBY_FP_ENABLE_SASS
|
||||
|
||||
// The maximum size in bytes of additional data in a message in Message Stream.
|
||||
// Bigger payloads will be truncated.
|
||||
#define MAX_MESSAGE_STREAM_PAYLOAD_SIZE 22
|
||||
|
||||
// The maximum number of concurrent RFCOMM connections
|
||||
#define NEARBY_MAX_RFCOMM_CONNECTIONS 2
|
||||
|
||||
// Support Retroactive pairing extension
|
||||
#ifndef NEARBY_FP_RETROACTIVE_PAIRING
|
||||
#define NEARBY_FP_RETROACTIVE_PAIRING 1
|
||||
#endif /* NEARBY_FP_RETROACTIVE_PAIRING */
|
||||
|
||||
// The maximum number of concurrent retroactive pairing process
|
||||
#define NEARBY_MAX_RETROACTIVE_PAIRING 2
|
||||
|
||||
// Is this platform a BLE-only device?
|
||||
#ifndef NEARBY_FP_BLE_ONLY
|
||||
#define NEARBY_FP_BLE_ONLY 0
|
||||
#endif /* NEARBY_FP_BLE_ONLY */
|
||||
|
||||
// Does this device prefer BLE bonding?
|
||||
#ifndef NEARBY_FP_PREFER_BLE_BONDING
|
||||
#define NEARBY_FP_PREFER_BLE_BONDING 0
|
||||
#endif /* NEARBY_FP_PREFER_BLE_BONDING */
|
||||
|
||||
// Does this device prefer LE transport for FP Message Stream?
|
||||
// When this feature is On, the Seeker will try to connect to the provider over
|
||||
// an L2CAP channel. When this feature is Off, the Seeker connects over RFCOMM.
|
||||
#ifndef NEARBY_FP_PREFER_LE_TRANSPORT
|
||||
#define NEARBY_FP_PREFER_LE_TRANSPORT 0
|
||||
#endif /* NEARBY_FP_PREFER_LE_TRANSPORT */
|
||||
|
||||
// The maximum number of account keys that can be stored on the device.
|
||||
#define NEARBY_MAX_ACCOUNT_KEYS 5
|
||||
#endif /* NEARBY_CONFIG_H */
|
||||
@@ -1,252 +0,0 @@
|
||||
// Copyright 2022 Google LLC
|
||||
//
|
||||
// Licensed 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
|
||||
//
|
||||
// https://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.
|
||||
|
||||
#ifndef NEARBY_EVENT_H
|
||||
#define NEARBY_EVENT_H
|
||||
|
||||
#include "nearby.h"
|
||||
|
||||
// Types of events that can be emitted by Nearby library
|
||||
typedef enum {
|
||||
// A client connected over RFCOMM to the message stream endpoint defined in
|
||||
// Fast Pair specification
|
||||
// Payload: |nearby_event_MessageStreamConnected|
|
||||
kNearbyEventMessageStreamConnected = 0,
|
||||
// An RFCOMM client disconnected
|
||||
// Payload: |nearby_event_MessageStreamDisonnected|
|
||||
kNearbyEventMessageStreamDisconnected,
|
||||
// A client has sent a message over the message stream. Some incoming messages
|
||||
// are consumed by the Nearby library, in which case the event is not emitted.
|
||||
// Payload: |nearby_event_MessageStreamReceived|
|
||||
kNearbyEventMessageStreamReceived
|
||||
} nearby_event_Type;
|
||||
|
||||
// An event emitted by Nearby library
|
||||
typedef struct {
|
||||
// The type of the event
|
||||
nearby_event_Type event_type;
|
||||
// Optional event payload. |payload| should be cast to one the structs defined
|
||||
// below.
|
||||
uint8_t *payload;
|
||||
} nearby_event_Event;
|
||||
|
||||
// Payload for |kNearbyEventMessageStreamConnected| event.
|
||||
typedef struct {
|
||||
// The client BT address
|
||||
uint64_t peer_address;
|
||||
} nearby_event_MessageStreamConnected;
|
||||
|
||||
// Payload for |kNearbyEventMessageStreamDisconnected| event.
|
||||
typedef struct {
|
||||
// The client BT address
|
||||
uint64_t peer_address;
|
||||
} nearby_event_MessageStreamDisconnected;
|
||||
|
||||
// Message group Bluetooth
|
||||
#define MESSAGE_GROUP_BLUETOOTH 1
|
||||
|
||||
// If the device supports silence mode, the client app should send either
|
||||
// ENABLE_SILENCE_MODE or DISABLE_SILENCE_MODE message to the seeker once RFCOMM
|
||||
// is connected to ensure the correct state is propagated.
|
||||
// Direction: Provider -> Seeker
|
||||
// Handled by: Client app
|
||||
#define MESSAGE_CODE_ENABLE_SILENCE_MODE 1
|
||||
|
||||
// Direction: Provider -> Seeker
|
||||
// Handled by: Client app
|
||||
#define MESSAGE_CODE_DISABLE_SILENCE_MODE 2
|
||||
|
||||
// Message group Companion App Event
|
||||
#define MESSAGE_GROUP_COMPANION_APP_EVENT 2
|
||||
|
||||
// Direction: Provider -> Seeker
|
||||
// Handled by: Client app
|
||||
#define MESSAGE_CODE_LOG_BUFFER_FULL 1
|
||||
|
||||
// Message group Device Information Event
|
||||
#define MESSAGE_GROUP_DEVICE_INFORMATION_EVENT 3
|
||||
|
||||
// Direction: Provider -> Seeker
|
||||
// Handled by: Nearby Fast Pair library
|
||||
#define MESSAGE_CODE_MODEL_ID 1
|
||||
|
||||
// Direction: Provider -> Seeker
|
||||
// Handled by: Nearby Fast Pair library
|
||||
#define MESSAGE_CODE_BLE_ADDRESS_UPDATED 2
|
||||
|
||||
// Direction: Provider -> Seeker
|
||||
// Handled by: Nearby Fast Pair library
|
||||
#define MESSAGE_CODE_BATTERY_UPDATED 3
|
||||
|
||||
// Direction: Provider -> Seeker
|
||||
// Handled by: Nearby Fast Pair library
|
||||
#define MESSAGE_CODE_REMAINING_BATTERY_TIME 4
|
||||
|
||||
// Direction: Seeker -> Provider
|
||||
// Handled by: Client app
|
||||
#define MESSAGE_CODE_ACTIVE_COMPONENT_REQUEST 5
|
||||
|
||||
// Direction: Provider -> Seeker
|
||||
// Handled by: Client app
|
||||
#define MESSAGE_CODE_ACTIVE_COMPONENT_RESPONSE 6
|
||||
|
||||
// Direction: Provider -> Seeker
|
||||
// Handled by: Client app
|
||||
#define MESSAGE_CODE_CAPABILITIES 7
|
||||
|
||||
#define MESSAGE_CODE_CAPABILITIES_COMPANION_APP_INSTALLED 0
|
||||
#define MESSAGE_CODE_CAPABILITIES_SILENCE_MODE_SUPPORTED 1
|
||||
|
||||
// Direction: Seeker -> Provider
|
||||
// Handled by: Client app
|
||||
#define MESSAGE_CODE_PLATFORM_TYPE 8
|
||||
|
||||
// Direction: Provider -> Seeker
|
||||
// Handled by: Nearby Fast Pair library
|
||||
#define MESSAGE_CODE_SESSION_NONCE 0x0A
|
||||
|
||||
// Message group Device Action Event
|
||||
#define MESSAGE_GROUP_DEVICE_ACTION_EVENT 4
|
||||
|
||||
// Direction: Seeker -> Provider
|
||||
// Handled by: Client app
|
||||
#define MESSAGE_CODE_RING 1
|
||||
|
||||
#define MESSAGE_CODE_RING_LEFT 0
|
||||
#define MESSAGE_CODE_RING_RIGHT 1
|
||||
|
||||
// Payload for |kNearbyEventMessageStreamReceived| event. See
|
||||
// https://developers.google.com/nearby/fast-pair/spec#MessageStream
|
||||
typedef struct {
|
||||
// The peer BT address
|
||||
uint64_t peer_address;
|
||||
// Message group
|
||||
uint8_t message_group;
|
||||
// Message code
|
||||
uint8_t message_code;
|
||||
// If |length| is 0, then there's no additional data in the message
|
||||
size_t length;
|
||||
// Optional. Addtional message data
|
||||
uint8_t *data;
|
||||
} nearby_event_MessageStreamReceived;
|
||||
|
||||
// Message group Smart Audio Source Switching
|
||||
#define MESSAGE_GROUP_SASS 7
|
||||
|
||||
// Direction: Both
|
||||
// Handled by: Nearby Fast Pair library
|
||||
// Encrypted: No
|
||||
// Signed: No
|
||||
// ACK required: No
|
||||
#define MESSAGE_CODE_SASS_GET_CAPABILITY 0x10
|
||||
|
||||
// Direction: Both
|
||||
// Handled by: Nearby Fast Pair library
|
||||
// Encrypted: No
|
||||
// Signed: Yes
|
||||
// ACK required: Yes
|
||||
#define MESSAGE_CODE_SASS_NOTIFY_CAPABILITY 0x11
|
||||
|
||||
// Direction: Seeker -> Provider
|
||||
// Handled by: Nearby Fast Pair library
|
||||
// Encrypted: No
|
||||
// Signed: Yes
|
||||
// ACK required: Yes
|
||||
#define MESSAGE_CODE_SASS_SET_MULTIPOINT_STATE 0x12
|
||||
|
||||
// Direction: Seeker -> Provider
|
||||
// Handled by: Nearby Fast Pair library
|
||||
// Encrypted: No
|
||||
// Signed: Yes
|
||||
// ACK required: Yes
|
||||
#define MESSAGE_CODE_SASS_SET_SWITCHING_PREFERENCE 0x20
|
||||
|
||||
// Direction: Both
|
||||
// Handled by: Nearby Fast Pair library
|
||||
// Encrypted: No
|
||||
// Signed: No
|
||||
// ACK required: No
|
||||
#define MESSAGE_CODE_SASS_GET_SWITCHING_PREFERENCE 0x21
|
||||
|
||||
// Direction: Both
|
||||
// Handled by: Nearby Fast Pair library
|
||||
// Encrypted: No
|
||||
// Signed: Yes
|
||||
// ACK required: Yes
|
||||
#define MESSAGE_CODE_SASS_NOTIFY_SWITCHING_PREFERENCE 0x22
|
||||
|
||||
// Direction: Seeker -> Provider
|
||||
// Handled by: Nearby Fast Pair library
|
||||
// Encrypted: No
|
||||
// Signed: Yes
|
||||
// ACK required: Yes
|
||||
#define MESSAGE_CODE_SASS_SWITCH_ACTIVE_AUDIO_SOURCE 0x30
|
||||
|
||||
// Direction: Seeker -> Provider
|
||||
// Handled by: Nearby Fast Pair library
|
||||
// Encrypted: No
|
||||
// Signed: Yes
|
||||
// ACK required: Yes
|
||||
#define MESSAGE_CODE_SASS_SWITCH_BACK_AUDIO_SOURCE 0x31
|
||||
|
||||
// Direction: Provider -> Seeker
|
||||
// Handled by: Nearby Fast Pair library
|
||||
// Encrypted: No
|
||||
// Signed: No
|
||||
// ACK required: No
|
||||
#define MESSAGE_CODE_SASS_NOTIFY_MULTIPOINT_SWITCH_EVENT 0x32
|
||||
|
||||
// Direction: Seeker -> Provider
|
||||
// Handled by: Nearby Fast Pair library
|
||||
// Encrypted: No
|
||||
// Signed: No
|
||||
// ACK required: No
|
||||
#define MESSAGE_CODE_SASS_GET_CONNECTION_STATUS 0x33
|
||||
|
||||
// Direction: Provider -> Seeker
|
||||
// Handled by: Nearby Fast Pair library
|
||||
// Encrypted: Yes
|
||||
// Signed: No
|
||||
// ACK required: No
|
||||
#define MESSAGE_CODE_SASS_NOTIFY_CONNECTION_STATUS 0x34
|
||||
|
||||
// Direction: Seeker -> Provider
|
||||
// Handled by: Nearby Fast Pair library
|
||||
// Encrypted: No
|
||||
// Signed: Yes
|
||||
// ACK required: Yes
|
||||
#define MESSAGE_CODE_SASS_NOTIFY_SASS_INITIATED_CONNECTION 0x40
|
||||
|
||||
// Direction: Seeker -> Provider
|
||||
// Handled by: Nearby Fast Pair library
|
||||
// Encrypted: No
|
||||
// Signed: Yes
|
||||
// ACK required: Yes
|
||||
#define MESSAGE_CODE_SASS_IN_USE_ACCOUNT_KEY 0x41
|
||||
|
||||
// Direction: Seeker -> Provider
|
||||
// Handled by: Nearby Fast Pair library
|
||||
// Encrypted: No
|
||||
// Signed: Yes
|
||||
// ACK required: Yes
|
||||
#define MESSAGE_CODE_SASS_SEND_CUSTOM_DATA 0x42
|
||||
|
||||
// Direction: Seeker -> Provider
|
||||
// Handled by: Nearby Fast Pair library
|
||||
// Encrypted: No
|
||||
// Signed: Yes
|
||||
// ACK required: Yes
|
||||
#define MESSAGE_CODE_SASS_SET_DROP_CONNECTION_TARGET 0x43
|
||||
|
||||
#endif /* NEARBY_EVENT_H */
|
||||
@@ -1,833 +0,0 @@
|
||||
// Copyright 2022 Google LLC
|
||||
//
|
||||
// Licensed 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
|
||||
//
|
||||
// https://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 "nearby_fp_library.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "nearby.h"
|
||||
#include "nearby_assert.h"
|
||||
#include "nearby_message_stream.h"
|
||||
#if NEARBY_FP_ENABLE_BATTERY_NOTIFICATION
|
||||
#include "nearby_platform_battery.h"
|
||||
#endif /* NEARBY_FP_ENABLE_BATTERY_NOTIFICATION */
|
||||
|
||||
#include "nearby_platform_audio.h"
|
||||
#include "nearby_platform_bt.h"
|
||||
#include "nearby_platform_persistence.h"
|
||||
#include "nearby_platform_se.h"
|
||||
#include "nearby_trace.h"
|
||||
#include "nearby_utils.h"
|
||||
|
||||
typedef struct {
|
||||
uint8_t num_keys;
|
||||
nearby_platform_AccountKeyInfo key[NEARBY_MAX_ACCOUNT_KEYS];
|
||||
} AccountKeyList;
|
||||
|
||||
// Advertisement header with SASS format (version 1)
|
||||
#define SASS_HEADER 0x10
|
||||
|
||||
// Offset to the advertisement header
|
||||
#define HEADER_OFFSET 4
|
||||
|
||||
// Offset to account data in a non-discoverable advertisement
|
||||
#define ACCOUNT_KEY_DATA_OFFSET 5
|
||||
|
||||
#define LTV_HEADER_SIZE 1
|
||||
#define ACCOUNT_KEY_LIST_SIZE_BYTES sizeof(AccountKeyList)
|
||||
#define SHOW_PAIRING_INDICATION_BYTE 0
|
||||
#define DONT_SHOW_PAIRING_INDICATION_BYTE 2
|
||||
#define SHOW_BATTERY_INDICATION_BYTE 0x33
|
||||
#define DONT_SHOW_BATTERY_INDICATION_BYTE 0x34
|
||||
#define BATTERY_INFO_CHARGING (1 << 7)
|
||||
#define BATTERY_INFO_NOT_CHARGING 0
|
||||
// In the battery values, the highest bit indicates charging, the lower 7 are
|
||||
// the battery level
|
||||
#define BATTERY_LEVEL_MASK 0x7F
|
||||
#define SALT_FIELD_LENGTH_AND_TYPE_BYTE ((NEARBY_FP_SALT_SIZE << 4) | 1)
|
||||
#define BATTERY_INFO_SIZE_BYTES 4
|
||||
// Response for seekers that don't support BLE-only devices.
|
||||
#define KEY_BASED_PAIRING_RESPONSE_FLAG 0x01
|
||||
// Response for seekers that support BLE-only devices.
|
||||
#define KEY_BASED_PAIRING_EXTENDED_RESPONSE_FLAG 0x02
|
||||
#define GAP_DATA_TYPE_SERVICE_DATA_UUID 0x16
|
||||
#define FP_SERVICE_UUID 0xFE2C
|
||||
#define GAP_DATA_TYPE_TX_POWER_LEVEL_UUID 0x0A
|
||||
#define TX_POWER_DATA_SIZE 2
|
||||
#define SASS_HEADER_SIZE 1
|
||||
|
||||
// (type + length) + state + custom_data
|
||||
#define MIN_SASS_ADERTISEMENT_SIZE 3
|
||||
|
||||
#define SASS_CONN_STATE_ON_HEAD_OFFSET 7
|
||||
#define SASS_CONN_STATE_AVAIL_OFFSET 6
|
||||
#define SASS_CONN_STATE_FOCUS_OFFSET 5
|
||||
#define SASS_CONN_STATE_AUTO_RECONNECTED_OFFSET 4
|
||||
#define SASS_CONN_STATE_MASK 0x0F
|
||||
|
||||
#define MOST_RECENTLY_USED_ACCOUNT_KEY_BIT 0x01
|
||||
#define IN_USE_ACCOUNT_KEY_BIT 0x02
|
||||
|
||||
// SASS Configuration Flags
|
||||
#define SASS_CF_ON_OFFSET 15
|
||||
#define SASS_CF_MULTIPOINT_CONFIGURABLE 14
|
||||
#define SASS_CF_MULTIPOINT_ON 13
|
||||
#define SASS_CF_OHD_SUPPORTED 12
|
||||
#define SASS_CF_OHD_ENABLED 11
|
||||
|
||||
#define MESSAGE_AUTHENTICATION_CODE_SIZE 8
|
||||
|
||||
#define BOOL_TO_INT(x) ((x) ? 1 : 0)
|
||||
|
||||
static const uint8_t kSassRrdKey[] = {'S', 'A', 'S', 'S', '-', 'R',
|
||||
'R', 'D', '-', 'K', 'E', 'Y'};
|
||||
|
||||
static AccountKeyList account_key_list;
|
||||
|
||||
static uint8_t sha_buffer[32];
|
||||
|
||||
#define RETURN_IF_ERROR(X) \
|
||||
do { \
|
||||
nearby_platform_status status = X; \
|
||||
if (kNearbyStatusOK != status) return status; \
|
||||
} while (0)
|
||||
|
||||
// Returns the Length part of Length|Type field.
|
||||
static int GetLtLength(uint8_t value) { return value >> 4; }
|
||||
|
||||
// Returns the Type part of Length|Type field.
|
||||
static int GetLtType(uint8_t value) { return value & 0x0F; }
|
||||
|
||||
const uint8_t* nearby_fp_FindLtv(const uint8_t* advertisement, int type) {
|
||||
size_t offset = ACCOUNT_KEY_DATA_OFFSET;
|
||||
size_t advertisement_length = advertisement[0];
|
||||
while (offset < advertisement_length) {
|
||||
if (type == GetLtType(advertisement[offset])) {
|
||||
return advertisement + offset;
|
||||
}
|
||||
offset += GetLtLength(advertisement[offset]) + LTV_HEADER_SIZE;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static size_t GetAccountKeyListUsedSize() { return sizeof(account_key_list); }
|
||||
|
||||
// Returns true if |account_key| is present in [0..end_offset) range in acount
|
||||
// key list
|
||||
static bool IsAccountKeyInRange(const uint8_t* account_key, size_t end_offset) {
|
||||
for (size_t i = 0; i < end_offset; i++) {
|
||||
if (!memcmp(account_key, nearby_fp_GetAccountKey(i)->account_key,
|
||||
ACCOUNT_KEY_SIZE_BYTES)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t nearby_fp_GetAccountKeyCount() { return account_key_list.num_keys; }
|
||||
|
||||
size_t nearby_fp_GetUniqueAccountKeyCount() {
|
||||
size_t count = 0;
|
||||
int offset = 0;
|
||||
while (true) {
|
||||
offset = nearby_fp_GetNextUniqueAccountKeyIndex(offset);
|
||||
if (offset == -1) break;
|
||||
count++;
|
||||
offset++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
int nearby_fp_GetNextUniqueAccountKeyIndex(int offset) {
|
||||
while (offset < nearby_fp_GetAccountKeyCount()) {
|
||||
const nearby_platform_AccountKeyInfo* account_key_info =
|
||||
nearby_fp_GetAccountKey(offset);
|
||||
if (IsAccountKeyInRange(account_key_info->account_key, offset)) {
|
||||
offset++;
|
||||
} else {
|
||||
return offset;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
const nearby_platform_AccountKeyInfo* nearby_fp_GetAccountKey(
|
||||
unsigned key_number) {
|
||||
NEARBY_ASSERT(key_number < nearby_fp_GetAccountKeyCount());
|
||||
return &account_key_list.key[key_number];
|
||||
}
|
||||
|
||||
void nearby_fp_MarkAccountKeyAsActive(unsigned key_number) {
|
||||
NEARBY_ASSERT(key_number < nearby_fp_GetAccountKeyCount());
|
||||
if (key_number == 0) return;
|
||||
// Move the key to the top of the list
|
||||
nearby_platform_AccountKeyInfo tmp = account_key_list.key[key_number];
|
||||
for (unsigned i = key_number; i > 0; i--) {
|
||||
account_key_list.key[i] = account_key_list.key[i - 1];
|
||||
}
|
||||
account_key_list.key[0] = tmp;
|
||||
}
|
||||
|
||||
void nearby_fp_CopyAccountKey(nearby_platform_AccountKeyInfo* dest,
|
||||
unsigned key_number) {
|
||||
NEARBY_ASSERT(key_number < nearby_fp_GetAccountKeyCount());
|
||||
*dest = account_key_list.key[key_number];
|
||||
}
|
||||
|
||||
static unsigned combineNibbles(unsigned high, unsigned low) {
|
||||
return ((high << 4) & 0xF0) | (low & 0x0F);
|
||||
}
|
||||
|
||||
// Returns |a| == |b|
|
||||
static bool AccountKeyInfoEquals(const nearby_platform_AccountKeyInfo* a,
|
||||
const nearby_platform_AccountKeyInfo* b) {
|
||||
return a == b ||
|
||||
(
|
||||
#ifdef NEARBY_FP_ENABLE_SASS
|
||||
a->peer_address == b->peer_address &&
|
||||
#endif /* NEARBY_FP_ENABLE_SASS */
|
||||
!memcmp(a->account_key, b->account_key, ACCOUNT_KEY_SIZE_BYTES));
|
||||
}
|
||||
|
||||
void nearby_fp_AddAccountKey(const nearby_platform_AccountKeyInfo* key) {
|
||||
// Find if the key is already on the list
|
||||
unsigned i;
|
||||
size_t key_count;
|
||||
key_count = nearby_fp_GetAccountKeyCount();
|
||||
for (i = 0; i < key_count; i++) {
|
||||
if (AccountKeyInfoEquals(key, nearby_fp_GetAccountKey(i))) {
|
||||
nearby_fp_MarkAccountKeyAsActive(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Insert `key` at the list top. If the list is full, the last key will fall
|
||||
// off the edge
|
||||
size_t keys_to_copy = key_count < NEARBY_MAX_ACCOUNT_KEYS
|
||||
? key_count
|
||||
: NEARBY_MAX_ACCOUNT_KEYS - 1;
|
||||
for (i = keys_to_copy; i > 0; i--) {
|
||||
account_key_list.key[i] = account_key_list.key[i - 1];
|
||||
}
|
||||
account_key_list.key[0] = *key;
|
||||
if (key_count < NEARBY_MAX_ACCOUNT_KEYS) {
|
||||
account_key_list.num_keys++;
|
||||
}
|
||||
}
|
||||
size_t nearby_fp_CreateDiscoverableAdvertisement(uint8_t* output,
|
||||
size_t length) {
|
||||
NEARBY_ASSERT(length >= DISCOVERABLE_ADV_SIZE_BYTES);
|
||||
|
||||
size_t i = 0;
|
||||
|
||||
// data size
|
||||
output[i++] = 1 + FP_SERVICE_UUID_SIZE + FP_MODEL_ID_SIZE;
|
||||
|
||||
// data type service
|
||||
output[i++] = GAP_DATA_TYPE_SERVICE_DATA_UUID;
|
||||
|
||||
// service data uuid
|
||||
nearby_utils_CopyLittleEndian(output + i, FP_SERVICE_UUID,
|
||||
FP_SERVICE_UUID_SIZE);
|
||||
i += FP_SERVICE_UUID_SIZE;
|
||||
|
||||
// service data
|
||||
uint32_t model = nearby_platform_GetModelId();
|
||||
nearby_utils_CopyBigEndian(output + i, model, FP_MODEL_ID_SIZE);
|
||||
i += FP_MODEL_ID_SIZE;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
#if NEARBY_FP_ENABLE_BATTERY_NOTIFICATION
|
||||
void SerializeBatteryInfo(uint8_t* output,
|
||||
const nearby_platform_BatteryInfo* battery_info) {
|
||||
uint8_t charging = battery_info->is_charging ? BATTERY_INFO_CHARGING
|
||||
: BATTERY_INFO_NOT_CHARGING;
|
||||
output[0] =
|
||||
charging | (battery_info->left_bud_battery_level & BATTERY_LEVEL_MASK);
|
||||
output[1] =
|
||||
charging | (battery_info->right_bud_battery_level & BATTERY_LEVEL_MASK);
|
||||
output[2] = charging |
|
||||
(battery_info->charging_case_battery_level & BATTERY_LEVEL_MASK);
|
||||
}
|
||||
static void AddBatteryInfo(uint8_t* output, size_t length,
|
||||
bool show_ui_indicator,
|
||||
const nearby_platform_BatteryInfo* battery_info) {
|
||||
NEARBY_ASSERT(length >= BATTERY_INFO_SIZE_BYTES);
|
||||
output[0] = show_ui_indicator ? SHOW_BATTERY_INDICATION_BYTE
|
||||
: DONT_SHOW_BATTERY_INDICATION_BYTE;
|
||||
SerializeBatteryInfo(output + 1, battery_info);
|
||||
}
|
||||
|
||||
#endif /* NEARBY_FP_ENABLE_BATTERY_NOTIFICATION */
|
||||
|
||||
static size_t CreateNondiscoverableAdvertisement(
|
||||
uint8_t* output, size_t length, bool show_pairing_indicator
|
||||
#if NEARBY_FP_ENABLE_BATTERY_NOTIFICATION
|
||||
,
|
||||
bool show_battery_indicator, const nearby_platform_BatteryInfo* battery_info
|
||||
#endif /* NEARBY_FP_ENABLE_BATTERY_NOTIFICATION */
|
||||
) {
|
||||
NEARBY_TRACE(VERBOSE, "nearby_fp_CreateNondiscoverableAdvertisement");
|
||||
const unsigned kHeaderSize = FP_SERVICE_UUID_SIZE + 2;
|
||||
NEARBY_ASSERT(length >= kHeaderSize);
|
||||
|
||||
unsigned i = 1;
|
||||
uint8_t salt[NEARBY_FP_SALT_SIZE];
|
||||
|
||||
// service data UUID
|
||||
output[i++] = GAP_DATA_TYPE_SERVICE_DATA_UUID;
|
||||
|
||||
// service uuid
|
||||
nearby_utils_CopyLittleEndian(output + i, FP_SERVICE_UUID,
|
||||
FP_SERVICE_UUID_SIZE);
|
||||
i += FP_SERVICE_UUID_SIZE;
|
||||
|
||||
// service data
|
||||
for (int si = 0; si < NEARBY_FP_SALT_SIZE; si++)
|
||||
salt[si] = nearby_platform_Rand();
|
||||
size_t n = nearby_fp_GetUniqueAccountKeyCount();
|
||||
if (n == 0) {
|
||||
const unsigned kMessageSize = 2;
|
||||
NEARBY_ASSERT(length >= i + kMessageSize);
|
||||
output[i++] = 0x00;
|
||||
output[i++] = 0x00;
|
||||
} else {
|
||||
const unsigned kFlagFilterAndSaltSize = 3 + NEARBY_FP_SALT_SIZE;
|
||||
const size_t s = (6 * n + 15) / 5;
|
||||
const size_t kAccountKeyDataSize = s + kFlagFilterAndSaltSize;
|
||||
NEARBY_ASSERT(length >= i + kAccountKeyDataSize);
|
||||
#if NEARBY_FP_ENABLE_BATTERY_NOTIFICATION
|
||||
// We need to add the battery info first because it's used as salt
|
||||
if (battery_info != NULL) {
|
||||
uint8_t battery_chunk_offset = i + kAccountKeyDataSize;
|
||||
uint8_t* battery_chunk = output + battery_chunk_offset;
|
||||
AddBatteryInfo(battery_chunk, length - battery_chunk_offset,
|
||||
show_battery_indicator, battery_info);
|
||||
}
|
||||
#endif /* NEARBY_FP_ENABLE_BATTERY_NOTIFICATION */
|
||||
// flags
|
||||
output[i++] = 0;
|
||||
// filter length and type
|
||||
output[i++] = combineNibbles(s, show_pairing_indicator
|
||||
? SHOW_PAIRING_INDICATION_BYTE
|
||||
: DONT_SHOW_PAIRING_INDICATION_BYTE);
|
||||
memset(output + i, 0, s);
|
||||
i += s;
|
||||
output[i++] = SALT_FIELD_LENGTH_AND_TYPE_BYTE;
|
||||
for (int si = 0; si < NEARBY_FP_SALT_SIZE; si++) output[i++] = salt[si];
|
||||
#if NEARBY_FP_ENABLE_BATTERY_NOTIFICATION
|
||||
if (battery_info != NULL) {
|
||||
i += BATTERY_INFO_SIZE_BYTES;
|
||||
}
|
||||
#endif /* NEARBY_FP_ENABLE_BATTERY_NOTIFICATION */
|
||||
}
|
||||
|
||||
// service data size
|
||||
output[0] = i - 1;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
size_t nearby_fp_CreateNondiscoverableAdvertisement(
|
||||
uint8_t* output, size_t length, bool show_pairing_indicator) {
|
||||
#if NEARBY_FP_ENABLE_BATTERY_NOTIFICATION
|
||||
return CreateNondiscoverableAdvertisement(
|
||||
output, length, show_pairing_indicator, false, NULL);
|
||||
#else
|
||||
return CreateNondiscoverableAdvertisement(output, length,
|
||||
show_pairing_indicator);
|
||||
#endif /* NEARBY_FP_ENABLE_BATTERY_NOTIFICATION */
|
||||
}
|
||||
|
||||
#if NEARBY_FP_ENABLE_BATTERY_NOTIFICATION
|
||||
// |battery_info| can be NULL
|
||||
size_t nearby_fp_CreateNondiscoverableAdvertisementWithBattery(
|
||||
uint8_t* output, size_t length, bool show_pairing_indicator,
|
||||
|
||||
bool show_battery_indicator,
|
||||
const nearby_platform_BatteryInfo* battery_info) {
|
||||
return CreateNondiscoverableAdvertisement(
|
||||
output, length, show_pairing_indicator, show_battery_indicator,
|
||||
battery_info);
|
||||
}
|
||||
#endif /* NEARBY_FP_ENABLE_BATTERY_NOTIFICATION */
|
||||
|
||||
static const uint8_t* FindBatteryInfoLt(const uint8_t* advertisement) {
|
||||
const uint8_t* battery_info = nearby_fp_FindLtv(
|
||||
advertisement, BATTERY_INFO_WITH_UI_INDICATION_FIELD_TYPE);
|
||||
if (battery_info == NULL) {
|
||||
battery_info = nearby_fp_FindLtv(
|
||||
advertisement, BATTERY_INFO_WITHOUT_UI_INDICATION_FIELD_TYPE);
|
||||
}
|
||||
return battery_info;
|
||||
}
|
||||
|
||||
size_t nearby_fp_SetBloomFilter(uint8_t* advertisement, bool use_sass_format,
|
||||
const uint8_t* in_use_key) {
|
||||
unsigned key_offset = 0;
|
||||
if (advertisement[ACCOUNT_KEY_DATA_OFFSET] == 0) {
|
||||
NEARBY_TRACE(INFO, "Empty account key filter");
|
||||
return 0;
|
||||
}
|
||||
// Salt is mandatory and is included in the calculation without the LT header
|
||||
const uint8_t* salt_field = nearby_fp_FindLtv(advertisement, SALT_FIELD_TYPE);
|
||||
NEARBY_ASSERT(salt_field != NULL);
|
||||
const uint8_t* salt = salt_field + LTV_HEADER_SIZE;
|
||||
int salt_length = GetLtLength(*salt_field);
|
||||
// Battery info is optional and is included in the calculation with the LT
|
||||
// header
|
||||
const uint8_t* battery_info_field = FindBatteryInfoLt(advertisement);
|
||||
int battery_info_field_length =
|
||||
battery_info_field != NULL
|
||||
? GetLtLength(*battery_info_field) + LTV_HEADER_SIZE
|
||||
: 0;
|
||||
// Random resolvable field is optional and is included in the calculation with
|
||||
// the LT header
|
||||
const uint8_t* random_resolvable_field =
|
||||
nearby_fp_FindLtv(advertisement, RANDOM_RESOLVABLE_FIELD_TYPE);
|
||||
int random_resolvable_field_length =
|
||||
random_resolvable_field != NULL
|
||||
? GetLtLength(*random_resolvable_field) + LTV_HEADER_SIZE
|
||||
: 0;
|
||||
const size_t n = nearby_fp_GetUniqueAccountKeyCount();
|
||||
const size_t s = (6 * n + 15) / 5;
|
||||
NEARBY_ASSERT(s == GetLtLength(advertisement[ACCOUNT_KEY_DATA_OFFSET]));
|
||||
uint8_t* output = advertisement + ACCOUNT_KEY_DATA_OFFSET + LTV_HEADER_SIZE;
|
||||
memset(output, 0, s);
|
||||
for (size_t k = 0; k < n; k++) {
|
||||
key_offset = nearby_fp_GetNextUniqueAccountKeyIndex(key_offset);
|
||||
NEARBY_ASSERT(key_offset >= 0);
|
||||
const uint8_t* key = nearby_fp_GetAccountKey(key_offset)->account_key;
|
||||
uint8_t flags = key[0];
|
||||
if (use_sass_format) {
|
||||
if (in_use_key != NULL) {
|
||||
if (!memcmp(key, in_use_key, ACCOUNT_KEY_SIZE_BYTES)) {
|
||||
flags |= IN_USE_ACCOUNT_KEY_BIT;
|
||||
}
|
||||
} else if (k == 0) {
|
||||
// The first key is the most recently used one
|
||||
flags |= MOST_RECENTLY_USED_ACCOUNT_KEY_BIT;
|
||||
}
|
||||
}
|
||||
key_offset++;
|
||||
nearby_platform_Sha256Start();
|
||||
nearby_platform_Sha256Update(&flags, sizeof(flags));
|
||||
nearby_platform_Sha256Update(key + sizeof(flags),
|
||||
ACCOUNT_KEY_SIZE_BYTES - sizeof(flags));
|
||||
nearby_platform_Sha256Update(salt, salt_length);
|
||||
nearby_platform_Sha256Update(battery_info_field, battery_info_field_length);
|
||||
nearby_platform_Sha256Update(random_resolvable_field,
|
||||
random_resolvable_field_length);
|
||||
nearby_platform_Sha256Finish(sha_buffer);
|
||||
for (unsigned j = 0; j < 8; j++) {
|
||||
uint32_t x = nearby_utils_GetBigEndian32(sha_buffer + 4 * j);
|
||||
uint32_t m = x % (s * 8);
|
||||
output[m / 8] |= (1 << (m % 8));
|
||||
}
|
||||
}
|
||||
if (use_sass_format) {
|
||||
advertisement[HEADER_OFFSET] = SASS_HEADER;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
size_t nearby_fp_AppendTxPower(uint8_t* advertisement, size_t length,
|
||||
int8_t tx_power) {
|
||||
size_t offset = 0;
|
||||
|
||||
NEARBY_ASSERT(length >= 1 + TX_POWER_DATA_SIZE);
|
||||
// tx power level data size
|
||||
advertisement[offset++] = TX_POWER_DATA_SIZE;
|
||||
// tx power level UUID
|
||||
advertisement[offset++] = GAP_DATA_TYPE_TX_POWER_LEVEL_UUID;
|
||||
// tx power level
|
||||
advertisement[offset++] = tx_power;
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
nearby_platform_status nearby_fp_LoadAccountKeys() {
|
||||
size_t length = sizeof(account_key_list);
|
||||
memset(&account_key_list, 0, length);
|
||||
return nearby_platform_LoadValue(kStoredKeyAccountKeyList,
|
||||
(uint8_t*)&account_key_list, &length);
|
||||
}
|
||||
|
||||
nearby_platform_status nearby_fp_SaveAccountKeys() {
|
||||
return nearby_platform_SaveValue(kStoredKeyAccountKeyList,
|
||||
(uint8_t*)&account_key_list,
|
||||
GetAccountKeyListUsedSize());
|
||||
}
|
||||
|
||||
nearby_platform_status nearby_fp_GattReadModelId(uint8_t* output,
|
||||
size_t* length) {
|
||||
NEARBY_ASSERT(*length >= FP_MODEL_ID_SIZE);
|
||||
uint32_t model = nearby_platform_GetModelId();
|
||||
nearby_utils_CopyBigEndian(output, model, FP_MODEL_ID_SIZE);
|
||||
*length = FP_MODEL_ID_SIZE;
|
||||
return kNearbyStatusOK;
|
||||
}
|
||||
|
||||
nearby_platform_status nearby_fp_CreateSharedSecret(
|
||||
const uint8_t remote_public_key[64],
|
||||
uint8_t output[ACCOUNT_KEY_SIZE_BYTES]) {
|
||||
nearby_platform_status status;
|
||||
uint8_t secret[32];
|
||||
uint8_t hash[32];
|
||||
status = nearby_platform_GenSec256r1Secret(remote_public_key, secret);
|
||||
if (status != kNearbyStatusOK) return status;
|
||||
|
||||
status = nearby_fp_Sha256(hash, secret, sizeof(secret));
|
||||
if (status != kNearbyStatusOK) return status;
|
||||
|
||||
memcpy(output, hash, ACCOUNT_KEY_SIZE_BYTES);
|
||||
return status;
|
||||
}
|
||||
|
||||
nearby_platform_status nearby_fp_CreateRawKeybasedPairingResponse(
|
||||
uint8_t output[AES_MESSAGE_SIZE_BYTES], bool extended_response) {
|
||||
int i = 0;
|
||||
uint64_t secondary_address = 0;
|
||||
if (extended_response) {
|
||||
secondary_address = nearby_platform_GetSecondaryPublicAddress();
|
||||
output[i++] = KEY_BASED_PAIRING_EXTENDED_RESPONSE_FLAG;
|
||||
uint8_t flags = 0;
|
||||
#if NEARBY_FP_BLE_ONLY
|
||||
flags |= 0x80;
|
||||
#endif /* NEARBY_FP_BLE_ONLY */
|
||||
#if NEARBY_FP_PREFER_BLE_BONDING
|
||||
flags |= 0x40;
|
||||
#endif /* NEARBY_FP_PREFER_BLE_BONDING */
|
||||
#if NEARBY_FP_PREFER_LE_TRANSPORT
|
||||
flags |= 0x20;
|
||||
#endif /* NEARBY_FP_PREFER_LE_TRANSPORT */
|
||||
output[i++] = flags;
|
||||
// Number of the Provider’s addresses. The number is either 1 or 2.
|
||||
output[i++] = secondary_address != 0 ? 2 : 1;
|
||||
} else {
|
||||
output[i++] = KEY_BASED_PAIRING_RESPONSE_FLAG;
|
||||
}
|
||||
nearby_utils_CopyBigEndian(&output[i], nearby_platform_GetPublicAddress(),
|
||||
BT_ADDRESS_LENGTH);
|
||||
i += BT_ADDRESS_LENGTH;
|
||||
if (secondary_address != 0) {
|
||||
nearby_utils_CopyBigEndian(&output[i], secondary_address,
|
||||
BT_ADDRESS_LENGTH);
|
||||
i += BT_ADDRESS_LENGTH;
|
||||
}
|
||||
for (; i < AES_MESSAGE_SIZE_BYTES; i++) {
|
||||
output[i] = nearby_platform_Rand();
|
||||
}
|
||||
return kNearbyStatusOK;
|
||||
}
|
||||
|
||||
#define OPAD 0x5C
|
||||
#define IPAD 0x36
|
||||
#define NONCE_SIZE 8
|
||||
|
||||
static void PadKey(uint8_t output[HMAC_SHA256_KEY_SIZE], const uint8_t* key,
|
||||
size_t key_length, uint8_t pad) {
|
||||
size_t i;
|
||||
for (i = 0; i < key_length; i++) {
|
||||
*output++ = *key++ ^ pad;
|
||||
}
|
||||
memset(output, pad, HMAC_SHA256_KEY_SIZE - key_length);
|
||||
}
|
||||
|
||||
static nearby_platform_status HmacSha256(uint8_t out[SHA256_KEY_SIZE],
|
||||
uint8_t hmac_key[HMAC_SHA256_KEY_SIZE],
|
||||
const uint8_t* data,
|
||||
size_t data_length) {
|
||||
RETURN_IF_ERROR(nearby_platform_Sha256Start());
|
||||
RETURN_IF_ERROR(nearby_platform_Sha256Update(hmac_key, HMAC_SHA256_KEY_SIZE));
|
||||
RETURN_IF_ERROR(nearby_platform_Sha256Update(data, data_length));
|
||||
return nearby_platform_Sha256Finish(out);
|
||||
}
|
||||
|
||||
static nearby_platform_status HmacSha256WithNonce(
|
||||
uint8_t out[32], uint8_t hmac_key[HMAC_SHA256_KEY_SIZE],
|
||||
const uint8_t session_nonce[SESSION_NONCE_SIZE],
|
||||
const uint8_t message_nonce[SESSION_NONCE_SIZE], const uint8_t* data,
|
||||
size_t data_length) {
|
||||
RETURN_IF_ERROR(nearby_platform_Sha256Start());
|
||||
RETURN_IF_ERROR(nearby_platform_Sha256Update(hmac_key, HMAC_SHA256_KEY_SIZE));
|
||||
RETURN_IF_ERROR(
|
||||
nearby_platform_Sha256Update(session_nonce, SESSION_NONCE_SIZE));
|
||||
RETURN_IF_ERROR(
|
||||
nearby_platform_Sha256Update(message_nonce, SESSION_NONCE_SIZE));
|
||||
RETURN_IF_ERROR(nearby_platform_Sha256Update(data, data_length));
|
||||
RETURN_IF_ERROR(nearby_platform_Sha256Finish(out));
|
||||
return kNearbyStatusOK;
|
||||
}
|
||||
|
||||
nearby_platform_status nearby_fp_HmacSha256Start(
|
||||
nearby_fp_HmacSha256Context* context, const uint8_t* key,
|
||||
size_t key_length) {
|
||||
// out = HASH(Key XOR ipad, data)
|
||||
PadKey(context->hmac_key, key, key_length, IPAD);
|
||||
RETURN_IF_ERROR(nearby_platform_Sha256Start());
|
||||
return nearby_platform_Sha256Update(context->hmac_key, HMAC_SHA256_KEY_SIZE);
|
||||
}
|
||||
|
||||
nearby_platform_status nearby_fp_HmacSha256Update(const uint8_t* data,
|
||||
size_t data_length) {
|
||||
return nearby_platform_Sha256Update(data, data_length);
|
||||
}
|
||||
|
||||
nearby_platform_status nearby_fp_HmacSha256Finish(
|
||||
nearby_fp_HmacSha256Context* context, const uint8_t* key,
|
||||
size_t key_length) {
|
||||
RETURN_IF_ERROR(nearby_platform_Sha256Finish(context->hash));
|
||||
// out = HASH(Key XOR opad, out)
|
||||
PadKey(context->hmac_key, key, key_length, OPAD);
|
||||
return HmacSha256(context->hash, context->hmac_key, context->hash,
|
||||
SHA256_KEY_SIZE);
|
||||
}
|
||||
|
||||
nearby_platform_status nearby_fp_HmacSha256(uint8_t out[SHA256_KEY_SIZE],
|
||||
const uint8_t* key,
|
||||
size_t key_length,
|
||||
const uint8_t* data,
|
||||
size_t data_length) {
|
||||
uint8_t hmac_key[HMAC_SHA256_KEY_SIZE];
|
||||
// out = HASH(Key XOR ipad, data)
|
||||
PadKey(hmac_key, key, key_length, IPAD);
|
||||
RETURN_IF_ERROR(HmacSha256(out, hmac_key, data, data_length));
|
||||
// out = HASH(Key XOR opad, out)
|
||||
PadKey(hmac_key, key, key_length, OPAD);
|
||||
return HmacSha256(out, hmac_key, out, SHA256_KEY_SIZE);
|
||||
}
|
||||
|
||||
nearby_platform_status nearby_fp_HkdfExtractSha256(uint8_t out[SHA256_KEY_SIZE],
|
||||
const uint8_t* salt,
|
||||
size_t salt_length,
|
||||
const uint8_t* ikm,
|
||||
size_t ikm_length) {
|
||||
return nearby_fp_HmacSha256(out, salt, salt_length, ikm, ikm_length);
|
||||
}
|
||||
|
||||
nearby_platform_status nearby_fp_HkdfExpandSha256(
|
||||
uint8_t* out, size_t out_length, const uint8_t* prk, size_t prk_length,
|
||||
const uint8_t* info, size_t info_length) {
|
||||
nearby_fp_HmacSha256Context context;
|
||||
size_t offset = 0;
|
||||
uint8_t chunk_number = 1;
|
||||
while (offset < out_length) {
|
||||
RETURN_IF_ERROR(nearby_fp_HmacSha256Start(&context, prk, prk_length));
|
||||
if (offset != 0) {
|
||||
RETURN_IF_ERROR(
|
||||
nearby_fp_HmacSha256Update(context.hash, SHA256_KEY_SIZE));
|
||||
}
|
||||
RETURN_IF_ERROR(nearby_fp_HmacSha256Update(info, info_length));
|
||||
RETURN_IF_ERROR(
|
||||
nearby_fp_HmacSha256Update(&chunk_number, sizeof(chunk_number)));
|
||||
RETURN_IF_ERROR(nearby_fp_HmacSha256Finish(&context, prk, prk_length));
|
||||
size_t space_left = out_length - offset;
|
||||
size_t bytes_to_copy =
|
||||
space_left < SHA256_KEY_SIZE ? space_left : SHA256_KEY_SIZE;
|
||||
memcpy(out + offset, context.hash, bytes_to_copy);
|
||||
offset += bytes_to_copy;
|
||||
++chunk_number;
|
||||
}
|
||||
return kNearbyStatusOK;
|
||||
}
|
||||
|
||||
static nearby_platform_status GetRrdKey(
|
||||
uint8_t out[AES_MESSAGE_SIZE_BYTES],
|
||||
const uint8_t account_key[ACCOUNT_KEY_SIZE_BYTES]) {
|
||||
uint8_t prk[SHA256_KEY_SIZE];
|
||||
RETURN_IF_ERROR(nearby_fp_HkdfExtractSha256(prk, NULL, 0, account_key,
|
||||
ACCOUNT_KEY_SIZE_BYTES));
|
||||
return nearby_fp_HkdfExpandSha256(out, AES_MESSAGE_SIZE_BYTES, prk,
|
||||
sizeof(prk), kSassRrdKey,
|
||||
sizeof(kSassRrdKey));
|
||||
}
|
||||
|
||||
nearby_platform_status nearby_fp_AesCtr(
|
||||
uint8_t* message, size_t message_length,
|
||||
const uint8_t key[AES_MESSAGE_SIZE_BYTES]) {
|
||||
uint8_t key_stream[AES_MESSAGE_SIZE_BYTES];
|
||||
uint8_t iv[AES_MESSAGE_SIZE_BYTES];
|
||||
size_t offset = NONCE_SIZE;
|
||||
memset(iv, 0, AES_MESSAGE_SIZE_BYTES - NONCE_SIZE);
|
||||
memcpy(iv + AES_MESSAGE_SIZE_BYTES - NONCE_SIZE, message, NONCE_SIZE);
|
||||
|
||||
while (offset < message_length) {
|
||||
unsigned i;
|
||||
unsigned bytes_left = message_length - offset;
|
||||
RETURN_IF_ERROR(nearby_platform_Aes128Encrypt(iv, key_stream, key));
|
||||
for (i = 0; i < bytes_left && i < sizeof(key_stream); i++) {
|
||||
message[offset++] ^= key_stream[i];
|
||||
}
|
||||
iv[0]++;
|
||||
}
|
||||
return kNearbyStatusOK;
|
||||
}
|
||||
|
||||
#if NEARBY_FP_ENABLE_ADDITIONAL_DATA
|
||||
#define ADDITIONAL_DATA_SHA_SIZE 8
|
||||
nearby_platform_status nearby_fp_DecodeAdditionalData(
|
||||
uint8_t* data, size_t length, const uint8_t key[ACCOUNT_KEY_SIZE_BYTES]) {
|
||||
NEARBY_ASSERT(length > ADDITIONAL_DATA_SHA_SIZE + NONCE_SIZE);
|
||||
uint8_t sha[32];
|
||||
RETURN_IF_ERROR(nearby_fp_HmacSha256(sha, key, ACCOUNT_KEY_SIZE_BYTES,
|
||||
data + ADDITIONAL_DATA_SHA_SIZE,
|
||||
length - ADDITIONAL_DATA_SHA_SIZE));
|
||||
if (memcmp(sha, data, ADDITIONAL_DATA_SHA_SIZE) != 0) {
|
||||
NEARBY_TRACE(WARNING, "Additional Data SHA check failed");
|
||||
NEARBY_TRACE(WARNING, "SHA: %s",
|
||||
nearby_utils_ArrayToString(sha, sizeof(sha)));
|
||||
NEARBY_TRACE(
|
||||
WARNING, "key: %s",
|
||||
nearby_utils_ArrayToString(key, sizeof(ACCOUNT_KEY_SIZE_BYTES)));
|
||||
NEARBY_TRACE(WARNING, "data: %s", nearby_utils_ArrayToString(data, length));
|
||||
return kNearbyStatusError;
|
||||
}
|
||||
return nearby_fp_AesCtr(data + ADDITIONAL_DATA_SHA_SIZE,
|
||||
length - ADDITIONAL_DATA_SHA_SIZE, key);
|
||||
}
|
||||
|
||||
nearby_platform_status nearby_fp_EncodeAdditionalData(
|
||||
uint8_t* data, size_t length, const uint8_t key[ACCOUNT_KEY_SIZE_BYTES]) {
|
||||
NEARBY_ASSERT(length >= ADDITIONAL_DATA_SHA_SIZE + NONCE_SIZE);
|
||||
uint8_t sha[32];
|
||||
int i;
|
||||
for (i = 0; i < NONCE_SIZE; i++) {
|
||||
data[ADDITIONAL_DATA_SHA_SIZE + i] = nearby_platform_Rand();
|
||||
}
|
||||
RETURN_IF_ERROR(nearby_fp_AesCtr(data + ADDITIONAL_DATA_SHA_SIZE,
|
||||
length - ADDITIONAL_DATA_SHA_SIZE, key));
|
||||
RETURN_IF_ERROR(nearby_fp_HmacSha256(sha, key, ACCOUNT_KEY_SIZE_BYTES,
|
||||
data + ADDITIONAL_DATA_SHA_SIZE,
|
||||
length - ADDITIONAL_DATA_SHA_SIZE));
|
||||
memcpy(data, sha, ADDITIONAL_DATA_SHA_SIZE);
|
||||
return kNearbyStatusOK;
|
||||
}
|
||||
#endif /* NEARBY_FP_ENABLE_ADDITIONAL_DATA */
|
||||
|
||||
// Computes sha256 sum.
|
||||
nearby_platform_status nearby_fp_Sha256(uint8_t out[32], const void* data,
|
||||
size_t length) {
|
||||
nearby_platform_status status = nearby_platform_Sha256Start();
|
||||
if (status == kNearbyStatusOK) {
|
||||
status = nearby_platform_Sha256Update(data, length);
|
||||
if (status == kNearbyStatusOK) {
|
||||
status = nearby_platform_Sha256Finish(out);
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
uint8_t nearby_fp_GetSassConnectionState() {
|
||||
return (BOOL_TO_INT(nearby_platform_OnHead())
|
||||
<< SASS_CONN_STATE_ON_HEAD_OFFSET) |
|
||||
(BOOL_TO_INT(nearby_platform_CanAcceptConnection())
|
||||
<< SASS_CONN_STATE_AVAIL_OFFSET) |
|
||||
(BOOL_TO_INT(nearby_platform_InFocusMode())
|
||||
<< SASS_CONN_STATE_FOCUS_OFFSET) |
|
||||
(BOOL_TO_INT(nearby_platform_AutoReconnected())
|
||||
<< SASS_CONN_STATE_AUTO_RECONNECTED_OFFSET) |
|
||||
(nearby_platform_GetAudioConnectionState() & SASS_CONN_STATE_MASK);
|
||||
}
|
||||
|
||||
size_t nearby_fp_GenerateSassAdvertisement(
|
||||
uint8_t* advertisement, size_t length, uint8_t connection_state,
|
||||
uint8_t custom_data, const uint8_t* devices_bitmap, size_t bitmap_length) {
|
||||
size_t advert_size = MIN_SASS_ADERTISEMENT_SIZE + bitmap_length;
|
||||
NEARBY_ASSERT(length >= advert_size);
|
||||
size_t offset = 0;
|
||||
advertisement[offset++] = combineNibbles(advert_size - SASS_HEADER_SIZE,
|
||||
SASS_ADVERTISEMENT_FIELD_TYPE);
|
||||
advertisement[offset++] = connection_state;
|
||||
advertisement[offset++] = custom_data;
|
||||
memcpy(advertisement + offset, devices_bitmap, bitmap_length);
|
||||
return advert_size;
|
||||
}
|
||||
|
||||
nearby_platform_status nearby_fp_EncryptRandomResolvableField(
|
||||
uint8_t* data, size_t length, const uint8_t key[AES_MESSAGE_SIZE_BYTES],
|
||||
const uint8_t* salt_field) {
|
||||
NEARBY_ASSERT(length <= AES_MESSAGE_SIZE_BYTES + RRF_HEADER_SIZE);
|
||||
uint8_t iv[AES_MESSAGE_SIZE_BYTES];
|
||||
uint8_t rrd_key[AES_MESSAGE_SIZE_BYTES];
|
||||
memset(iv, 0, sizeof(iv));
|
||||
if (salt_field != NULL) {
|
||||
int salt_length = GetLtLength(salt_field[0]);
|
||||
memcpy(iv, salt_field + LTV_HEADER_SIZE, salt_length);
|
||||
}
|
||||
RETURN_IF_ERROR(GetRrdKey(rrd_key, key));
|
||||
RETURN_IF_ERROR(nearby_platform_Aes128Encrypt(iv, iv, rrd_key));
|
||||
data[0] =
|
||||
combineNibbles(length - RRF_HEADER_SIZE, RANDOM_RESOLVABLE_FIELD_TYPE);
|
||||
for (size_t i = RRF_HEADER_SIZE; i < length; i++) {
|
||||
data[i] ^= iv[i - RRF_HEADER_SIZE];
|
||||
}
|
||||
return kNearbyStatusOK;
|
||||
}
|
||||
|
||||
nearby_platform_status nearby_fp_AesEncryptIv(
|
||||
uint8_t* data, size_t length, uint8_t iv[AES_MESSAGE_SIZE_BYTES],
|
||||
const uint8_t key[AES_MESSAGE_SIZE_BYTES]) {
|
||||
NEARBY_ASSERT(length <= AES_MESSAGE_SIZE_BYTES);
|
||||
RETURN_IF_ERROR(nearby_platform_Aes128Encrypt(iv, iv, key));
|
||||
for (size_t i = 0; i < length; i++) {
|
||||
data[i] ^= iv[i];
|
||||
}
|
||||
return kNearbyStatusOK;
|
||||
}
|
||||
|
||||
uint16_t nearby_fp_GetSassCapabilityFlags() {
|
||||
return (BOOL_TO_INT(nearby_platform_IsSassOn()) << SASS_CF_ON_OFFSET) |
|
||||
(BOOL_TO_INT(nearby_platform_IsMultipointConfigurable())
|
||||
<< SASS_CF_MULTIPOINT_CONFIGURABLE) |
|
||||
(BOOL_TO_INT(nearby_platform_IsMultipointOn())
|
||||
<< SASS_CF_MULTIPOINT_ON) |
|
||||
(BOOL_TO_INT(nearby_platform_IsOnHeadDetectionSupported())
|
||||
<< SASS_CF_OHD_SUPPORTED) |
|
||||
(BOOL_TO_INT(nearby_platform_IsOnHeadDetectionEnabled())
|
||||
<< SASS_CF_OHD_ENABLED);
|
||||
}
|
||||
|
||||
nearby_platform_status nearby_fp_VerifyMessageAuthenticationCode(
|
||||
const uint8_t* message, size_t length,
|
||||
const uint8_t key[ACCOUNT_KEY_SIZE_BYTES],
|
||||
const uint8_t session_nonce[SESSION_NONCE_SIZE]) {
|
||||
if (length <= SESSION_NONCE_SIZE - MESSAGE_AUTHENTICATION_CODE_SIZE) {
|
||||
return kNearbyStatusInvalidInput;
|
||||
}
|
||||
size_t data_length =
|
||||
length - SESSION_NONCE_SIZE - MESSAGE_AUTHENTICATION_CODE_SIZE;
|
||||
const uint8_t* message_nonce = message + data_length;
|
||||
uint8_t hmac_key[HMAC_SHA256_KEY_SIZE];
|
||||
uint8_t out[32];
|
||||
// out = HASH(Key XOR ipad, session nonce + message nonce + data)
|
||||
PadKey(hmac_key, key, ACCOUNT_KEY_SIZE_BYTES, IPAD);
|
||||
RETURN_IF_ERROR(HmacSha256WithNonce(out, hmac_key, session_nonce,
|
||||
message_nonce, message, data_length));
|
||||
// out = HASH(Key XOR opad, out)
|
||||
PadKey(hmac_key, key, ACCOUNT_KEY_SIZE_BYTES, OPAD);
|
||||
RETURN_IF_ERROR(HmacSha256(out, hmac_key, out, 32));
|
||||
const uint8_t* mac = message + data_length + SESSION_NONCE_SIZE;
|
||||
if (memcmp(out, mac, MESSAGE_AUTHENTICATION_CODE_SIZE)) {
|
||||
NEARBY_TRACE(INFO,
|
||||
"Expected MAC "
|
||||
"0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x",
|
||||
out[0], out[1], out[2], out[3], out[4], out[5], out[6],
|
||||
out[7]);
|
||||
return kNearbyStatusInvalidInput;
|
||||
} else {
|
||||
return kNearbyStatusOK;
|
||||
}
|
||||
}
|
||||
@@ -1,317 +0,0 @@
|
||||
// Copyright 2022 Google LLC
|
||||
//
|
||||
// Licensed 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
|
||||
//
|
||||
// https://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.
|
||||
|
||||
#ifndef NEARBY_FP_LIBRARY_H
|
||||
#define NEARBY_FP_LIBRARY_H
|
||||
|
||||
// clang-format off
|
||||
#include "nearby_config.h"
|
||||
// clang-format on
|
||||
|
||||
#include "nearby.h"
|
||||
#include "nearby_message_stream.h"
|
||||
#if NEARBY_FP_ENABLE_BATTERY_NOTIFICATION
|
||||
#include "nearby_platform_battery.h"
|
||||
#endif /* NEARBY_FP_ENABLE_BATTERY_NOTIFICATION */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#define BT_ADDRESS_LENGTH 6
|
||||
#define DISCOVERABLE_ADV_SIZE_BYTES 10
|
||||
#ifdef NEARBY_FP_ENABLE_SASS
|
||||
// Sufficent for 5 account keys, battery notification and SASS info
|
||||
#define NON_DISCOVERABLE_ADV_SIZE_BYTES 32
|
||||
#else
|
||||
// Sufficent for 5 account keys and battery notification
|
||||
#define NON_DISCOVERABLE_ADV_SIZE_BYTES 25
|
||||
#endif /* NEARBY_FP_ENABLE_SASS */
|
||||
|
||||
#define ADDITIONAL_DATA_HEADER_SIZE 16
|
||||
#define HMAC_SHA256_KEY_SIZE 64
|
||||
#define SHA256_KEY_SIZE 32
|
||||
|
||||
// Random Resolvable Field header size
|
||||
#define RRF_HEADER_SIZE 1
|
||||
|
||||
// Field types in the non-discoverable advertisement
|
||||
#define SALT_FIELD_TYPE 1
|
||||
#define BATTERY_INFO_WITH_UI_INDICATION_FIELD_TYPE 3
|
||||
#define BATTERY_INFO_WITHOUT_UI_INDICATION_FIELD_TYPE 4
|
||||
#define SASS_ADVERTISEMENT_FIELD_TYPE 5
|
||||
#define RANDOM_RESOLVABLE_FIELD_TYPE 6
|
||||
|
||||
// Creates advertisement with the Model Id. Returns the number of bytes
|
||||
// written to |output|.
|
||||
//
|
||||
// output - Advertisement data output buffer.
|
||||
// length - Length of output buffer.
|
||||
size_t nearby_fp_CreateDiscoverableAdvertisement(uint8_t* output,
|
||||
size_t length);
|
||||
|
||||
// Creates advertisement with Account Key Data. Returns the number of bytes
|
||||
// written to |output|.
|
||||
//
|
||||
// output - Advertisement data output buffer.
|
||||
// length - Length of data output buffer.
|
||||
// show_ui_indicator - Ask seeker to show UI indication.
|
||||
size_t nearby_fp_CreateNondiscoverableAdvertisement(
|
||||
uint8_t* output, size_t length, bool show_pairing_indicator);
|
||||
|
||||
#if NEARBY_FP_ENABLE_BATTERY_NOTIFICATION
|
||||
void SerializeBatteryInfo(uint8_t* output,
|
||||
const nearby_platform_BatteryInfo* battery_info);
|
||||
|
||||
// Creates advertisement with Account Key Data and optionally battery info.
|
||||
// |battery_info| can be NULL. Returns the number of bytes written to |output|.
|
||||
//
|
||||
// output - Advertisement data output buffer.
|
||||
// length - Length of output buffer.
|
||||
// show_ui_indicator - Ask seeker to show UI indication.
|
||||
// show_battery_indicator - Ask seeker to show battery indicator
|
||||
// battery_info - Battery status data structure.
|
||||
size_t nearby_fp_CreateNondiscoverableAdvertisementWithBattery(
|
||||
uint8_t* output, size_t length, bool show_pairing_indicator,
|
||||
bool show_battery_indicator,
|
||||
const nearby_platform_BatteryInfo* battery_info);
|
||||
#endif /* NEARBY_FP_ENABLE_BATTERY_NOTIFICATION */
|
||||
|
||||
// Appends TX power stanza to the advertisement. |Advertisement| should point
|
||||
// past the end of advertisement created with one of the 'Create*' functions.
|
||||
//
|
||||
// advertisement - Pointer to end of advertising data.
|
||||
// length - Remaining length of advertising data.
|
||||
// power - Power level.
|
||||
size_t nearby_fp_AppendTxPower(uint8_t* advertisement, size_t length,
|
||||
int8_t tx_power);
|
||||
|
||||
// Loads account keys from NV storage.
|
||||
nearby_platform_status nearby_fp_LoadAccountKeys();
|
||||
// Saves account keys to NV storage.
|
||||
nearby_platform_status nearby_fp_SaveAccountKeys();
|
||||
|
||||
// Gets Specific key by number to buffer
|
||||
//
|
||||
// dest - Buffer for key fetched.
|
||||
// key_number - Number of key to fetch.
|
||||
void nearby_fp_CopyAccountKey(nearby_platform_AccountKeyInfo* dest,
|
||||
unsigned key_number);
|
||||
|
||||
// Gets number of active keys.
|
||||
size_t nearby_fp_GetAccountKeyCount();
|
||||
|
||||
// Gets the number of unique account keys. Account keys are duplicated when two
|
||||
// or more seekers share an account key
|
||||
size_t nearby_fp_GetUniqueAccountKeyCount();
|
||||
|
||||
// Returns the index of the next unique account key in [offset..number of keys]
|
||||
// range, that is a key that wasn't already seen in [0..offset -1] range.
|
||||
// Returns -1 if not found.
|
||||
int nearby_fp_GetNextUniqueAccountKeyIndex(int offset);
|
||||
|
||||
// Gets pointer to given key by ordinal number.
|
||||
//
|
||||
// key_number - Ordinal number of key to return.
|
||||
const nearby_platform_AccountKeyInfo* nearby_fp_GetAccountKey(
|
||||
unsigned key_number);
|
||||
|
||||
// Marks account key as active by moving it to the top of the key list.
|
||||
//
|
||||
// key_number - Original number of key to mark active.
|
||||
void nearby_fp_MarkAccountKeyAsActive(unsigned key_number);
|
||||
|
||||
// Adds key to key list. Inserts key to top of list.
|
||||
//
|
||||
// key - Buffer containing key to insert.
|
||||
void nearby_fp_AddAccountKey(const nearby_platform_AccountKeyInfo* key);
|
||||
|
||||
// Computes the account bloom filter and stores it in the Account Key Filter
|
||||
// field in the advertisement. Returns the bloom filter size.
|
||||
//
|
||||
// `advertisement` is a non-discoverable FP advertisement. It must contain an
|
||||
// LTV field for Account Key Filter, where the LT header is already set but the
|
||||
// contents may be unitialized. It must contain an LTV with salt. Battery Info
|
||||
// field and Random Resolvable field are used in the bloom filter calculation if
|
||||
// present in the advertisement, When `use_sass_format` is set, the bloom filter
|
||||
// defined by SASS will be used.
|
||||
size_t nearby_fp_SetBloomFilter(uint8_t* advertisement, bool use_sass_format,
|
||||
const uint8_t* in_use_key);
|
||||
|
||||
// Gets fast pair model ID
|
||||
//
|
||||
// output - Buffer to hold model ID.
|
||||
// length - On input, contains the length of the buffer.
|
||||
// On output, returns the length of the model ID returned.
|
||||
nearby_platform_status nearby_fp_GattReadModelId(uint8_t* output,
|
||||
size_t* length);
|
||||
// Creates shared secret from remote public key.
|
||||
//
|
||||
// remote_public_key - 512 bit peer public key.
|
||||
// output - Buffer that returns the shared secret.
|
||||
nearby_platform_status nearby_fp_CreateSharedSecret(
|
||||
const uint8_t remote_public_key[64],
|
||||
uint8_t output[ACCOUNT_KEY_SIZE_BYTES]);
|
||||
|
||||
// Creates raw key based paring response.
|
||||
//
|
||||
// output - Buffer returning the pairing response.
|
||||
nearby_platform_status nearby_fp_CreateRawKeybasedPairingResponse(
|
||||
uint8_t output[AES_MESSAGE_SIZE_BYTES], bool extended_response);
|
||||
|
||||
// Context for calculating HMAC-SHA256 hash
|
||||
typedef struct {
|
||||
// The resulting hash after calling `nearby_fp_HmacSha256Finish`
|
||||
uint8_t hash[SHA256_KEY_SIZE];
|
||||
uint8_t hmac_key[HMAC_SHA256_KEY_SIZE];
|
||||
} nearby_fp_HmacSha256Context;
|
||||
|
||||
// Starts calculating HMAC-SHA156 hash incrementally. Only one hash calculation
|
||||
// can be running at a time.
|
||||
//
|
||||
// context - Uninitalized context.
|
||||
// key - Input key to calculate hash.
|
||||
// key_length - Length of key.
|
||||
nearby_platform_status nearby_fp_HmacSha256Start(
|
||||
nearby_fp_HmacSha256Context* context, const uint8_t* key,
|
||||
size_t key_length);
|
||||
|
||||
// Adds data to the hash.
|
||||
//
|
||||
// data - Data to calculate hash.
|
||||
// data_length - Data length.
|
||||
nearby_platform_status nearby_fp_HmacSha256Update(const uint8_t* data,
|
||||
size_t data_length);
|
||||
// Finishes hash calculation. The parameters must match those passed to
|
||||
// `nearby_fp_HmacSha256Start`.
|
||||
//
|
||||
// context - Context initalized with `nearby_fp_HmacSha256Start`.
|
||||
// key - Input key to calculate hash.
|
||||
// key_length - Length of key.
|
||||
nearby_platform_status nearby_fp_HmacSha256Finish(
|
||||
nearby_fp_HmacSha256Context* context, const uint8_t* key,
|
||||
size_t key_length);
|
||||
|
||||
// Implements HKDF-Extract method with SHA256 hash per
|
||||
// https://www.rfc-editor.org/rfc/rfc5869#section-2.2
|
||||
//
|
||||
// out - output Pseudo Random Key material
|
||||
// salt - optional salt
|
||||
// salt_length - salt length in bytes. Set to 0 when `salt is NULL
|
||||
// ikm - Input Key Material
|
||||
// ikm_length - IKM length in bytes
|
||||
nearby_platform_status nearby_fp_HkdfExtractSha256(uint8_t out[SHA256_KEY_SIZE],
|
||||
const uint8_t* salt,
|
||||
size_t salt_length,
|
||||
const uint8_t* ikm,
|
||||
size_t ikm_length);
|
||||
|
||||
// Implements HKDF-Expand with SHA256 hash per
|
||||
// https://www.rfc-editor.org/rfc/rfc5869#section-2.3
|
||||
//
|
||||
// out - Output Key Material
|
||||
// out_length - OKM length in bytes
|
||||
// prk - Pseudo Random Key
|
||||
// prk_length - PRK length in bytes
|
||||
// info - optional context information
|
||||
// info_length - info length in bytes. Set to 0 when `info` is NULL.
|
||||
nearby_platform_status nearby_fp_HkdfExpandSha256(
|
||||
uint8_t* out, size_t out_length, const uint8_t* prk, size_t prk_length,
|
||||
const uint8_t* info, size_t info_length);
|
||||
|
||||
const uint8_t* nearby_fp_FindLtv(const uint8_t* advertisement, int type);
|
||||
|
||||
// Calculates HMAC SHA256 hash.
|
||||
//
|
||||
// out - Output buffer for hash.
|
||||
// key - Input key to calculate hash.
|
||||
// key_length - Length of key.
|
||||
// data - Data to calculate hash.
|
||||
// data_length - Data length.
|
||||
nearby_platform_status nearby_fp_HmacSha256(uint8_t out[32], const uint8_t* key,
|
||||
size_t key_length,
|
||||
const uint8_t* data,
|
||||
size_t data_length);
|
||||
|
||||
// The first 8 bytes of the message are the nonce. The message is
|
||||
// encrypted/decrypted in place.
|
||||
//
|
||||
// message - Message buffer in/out.
|
||||
// message_length - Length of message.
|
||||
// key - Key.
|
||||
nearby_platform_status nearby_fp_AesCtr(
|
||||
uint8_t* message, size_t message_length,
|
||||
const uint8_t key[AES_MESSAGE_SIZE_BYTES]);
|
||||
|
||||
// Encrypts |data| in place: data = data ^ AES(key, iv). The data must
|
||||
// be shorter than AES_MESSAGE_SIZE_BYTES.
|
||||
// Side effect: |iv| contents are destroyed.
|
||||
nearby_platform_status nearby_fp_AesEncryptIv(
|
||||
uint8_t* data, size_t length, uint8_t iv[AES_MESSAGE_SIZE_BYTES],
|
||||
const uint8_t key[AES_MESSAGE_SIZE_BYTES]);
|
||||
|
||||
#if NEARBY_FP_ENABLE_ADDITIONAL_DATA
|
||||
// Decodes data package read from Additional Data characteristics. The decoding
|
||||
// happens in-place. Returns an error if HMAC-SHA checksum is invalid.
|
||||
//
|
||||
// data - Data to decode.
|
||||
// length - Length of data.
|
||||
// key - Key.
|
||||
nearby_platform_status nearby_fp_DecodeAdditionalData(
|
||||
uint8_t* data, size_t length, const uint8_t key[ACCOUNT_KEY_SIZE_BYTES]);
|
||||
|
||||
// Encodes data package for writing to Additional Data characteristics. The
|
||||
// encoding happens in-place. The first 16 bytes of the data buffer are used for
|
||||
// checksum and nonce, so the actual message must begin at offset 16.
|
||||
//
|
||||
// data - Data to encode.
|
||||
// length - Length of data.
|
||||
// key - Key.
|
||||
nearby_platform_status nearby_fp_EncodeAdditionalData(
|
||||
uint8_t* data, size_t length, const uint8_t key[ACCOUNT_KEY_SIZE_BYTES]);
|
||||
|
||||
#endif /* NEARBY_FP_ENABLE_ADDITIONAL_DATA */
|
||||
|
||||
// Computes sha256 sum.
|
||||
//
|
||||
// out - Output 256 bit sum.
|
||||
// data - Data to compute sha256 sum over.
|
||||
// length - Length of data.
|
||||
nearby_platform_status nearby_fp_Sha256(uint8_t out[32], const void* data,
|
||||
size_t length);
|
||||
|
||||
uint8_t nearby_fp_GetSassConnectionState();
|
||||
|
||||
size_t nearby_fp_GenerateSassAdvertisement(
|
||||
uint8_t* advertisement, size_t length, uint8_t connection_state,
|
||||
uint8_t custom_data, const uint8_t* devices_bitmap, size_t bitmap_length);
|
||||
|
||||
uint16_t nearby_fp_GetSassCapabilityFlags();
|
||||
|
||||
nearby_platform_status nearby_fp_VerifyMessageAuthenticationCode(
|
||||
const uint8_t* message, size_t length,
|
||||
const uint8_t key[ACCOUNT_KEY_SIZE_BYTES],
|
||||
const uint8_t session_nonce[SESSION_NONCE_SIZE]);
|
||||
|
||||
// Encrypts Random Resolvable Field in place. The payload must start
|
||||
// at RRF_HEADER_SIZE offset in the |data| buffer. |salt_field| is a
|
||||
// part of non-discoverable advertisement
|
||||
nearby_platform_status nearby_fp_EncryptRandomResolvableField(
|
||||
uint8_t* data, size_t length, const uint8_t key[AES_MESSAGE_SIZE_BYTES],
|
||||
const uint8_t* salt_field);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // NEARBY_FP_LIBRARY_H
|
||||
@@ -1,126 +0,0 @@
|
||||
// Copyright 2022 Google LLC
|
||||
//
|
||||
// Licensed 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
|
||||
//
|
||||
// https://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 "nearby_message_stream.h"
|
||||
|
||||
#include "nearby_platform_bt.h"
|
||||
|
||||
#define HEADER_SIZE 4
|
||||
#define ACK_MESSAGE_SIZE 6
|
||||
#define NACK_MESSAGE_SIZE 7
|
||||
#define ACKNOWLEDGEMENT_GROUP 0xFF
|
||||
#define ACK_CODE 1
|
||||
#define NACK_CODE 2
|
||||
|
||||
#if NEARBY_FP_MESSAGE_STREAM
|
||||
void nearby_message_stream_Init(const nearby_message_stream_State* state) {
|
||||
nearby_message_stream_Metadata* metadata =
|
||||
(nearby_message_stream_Metadata*)state->buffer;
|
||||
memset(metadata, 0, sizeof(nearby_message_stream_Metadata));
|
||||
metadata->message.data =
|
||||
state->buffer + sizeof(nearby_message_stream_Metadata);
|
||||
}
|
||||
|
||||
void nearby_message_stream_Read(const nearby_message_stream_State* state,
|
||||
const uint8_t* data, size_t length) {
|
||||
nearby_message_stream_Metadata* metadata =
|
||||
(nearby_message_stream_Metadata*)state->buffer;
|
||||
nearby_message_stream_Message* message = &metadata->message;
|
||||
uint16_t available_space =
|
||||
state->length - sizeof(nearby_message_stream_Metadata);
|
||||
while (length > 0) {
|
||||
switch (metadata->bytes_read) {
|
||||
case 0:
|
||||
message->message_group = *data;
|
||||
break;
|
||||
case 1:
|
||||
message->message_code = *data;
|
||||
break;
|
||||
case 2:
|
||||
message->length = ((uint16_t)*data) << 8;
|
||||
break;
|
||||
case 3:
|
||||
message->length += *data;
|
||||
break;
|
||||
default: {
|
||||
uint16_t offset = metadata->bytes_read - HEADER_SIZE;
|
||||
if (offset < message->length && offset < available_space) {
|
||||
message->data[offset] = *data;
|
||||
}
|
||||
}
|
||||
}
|
||||
data++;
|
||||
length--;
|
||||
metadata->bytes_read++;
|
||||
if (metadata->bytes_read - HEADER_SIZE == message->length) {
|
||||
if (message->length > available_space) {
|
||||
// Message truncated
|
||||
message->length = available_space;
|
||||
}
|
||||
state->on_message_received(state->peer_address, message);
|
||||
message->length = 0;
|
||||
metadata->bytes_read = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nearby_platform_status nearby_message_stream_Send(
|
||||
uint64_t peer_address, const nearby_message_stream_Message* message) {
|
||||
nearby_platform_status status;
|
||||
uint8_t header[HEADER_SIZE];
|
||||
header[0] = message->message_group;
|
||||
header[1] = message->message_code;
|
||||
header[2] = message->length >> 8;
|
||||
header[3] = message->length;
|
||||
status =
|
||||
nearby_platform_SendMessageStream(peer_address, header, sizeof(header));
|
||||
if (kNearbyStatusOK == status && message->length > 0) {
|
||||
status = nearby_platform_SendMessageStream(peer_address, message->data,
|
||||
message->length);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
nearby_platform_status nearby_message_stream_SendAck(
|
||||
uint64_t peer_address, const nearby_message_stream_Message* message) {
|
||||
uint8_t ack[ACK_MESSAGE_SIZE];
|
||||
ack[0] = ACKNOWLEDGEMENT_GROUP;
|
||||
ack[1] = ACK_CODE;
|
||||
ack[2] = 0;
|
||||
ack[3] = ACK_MESSAGE_SIZE - HEADER_SIZE;
|
||||
ack[4] = message->message_group;
|
||||
ack[5] = message->message_code;
|
||||
return nearby_platform_SendMessageStream(peer_address, ack, sizeof(ack));
|
||||
}
|
||||
|
||||
nearby_platform_status nearby_message_stream_SendNack(
|
||||
uint64_t peer_address, const nearby_message_stream_Message* message,
|
||||
uint8_t fail_reason) {
|
||||
uint8_t nack[NACK_MESSAGE_SIZE];
|
||||
nack[0] = ACKNOWLEDGEMENT_GROUP;
|
||||
nack[1] = NACK_CODE;
|
||||
nack[2] = 0;
|
||||
nack[3] = NACK_MESSAGE_SIZE - HEADER_SIZE;
|
||||
nack[4] = fail_reason;
|
||||
nack[5] = message->message_group;
|
||||
nack[6] = message->message_code;
|
||||
return nearby_platform_SendMessageStream(peer_address, nack, sizeof(nack));
|
||||
}
|
||||
|
||||
uint16_t nearby_message_stream_GetMaxPayloadSize(
|
||||
const nearby_message_stream_State* state) {
|
||||
return state->length - sizeof(nearby_message_stream_Metadata);
|
||||
}
|
||||
|
||||
#endif /* NEARBY_FP_MESSAGE_STREAM */
|
||||
@@ -1,101 +0,0 @@
|
||||
// Copyright 2022 Google LLC
|
||||
//
|
||||
// Licensed 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
|
||||
//
|
||||
// https://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.
|
||||
|
||||
#ifndef NEARBY_MESSAGE_STREAM_H
|
||||
#define NEARBY_MESSAGE_STREAM_H
|
||||
|
||||
// clang-format off
|
||||
#include "nearby_config.h"
|
||||
// clang-format on
|
||||
|
||||
#include "nearby.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
// Message group and codes for ACK and NACK messages
|
||||
#define ACKNOWLEDGEMENT_GROUP 0xFF
|
||||
#define ACK_CODE 1
|
||||
#define NACK_CODE 2
|
||||
|
||||
#define FAIL_REASON_INVALID_MAC 3
|
||||
#define FAIL_REASON_REDUNDANT_DEVICE_ACTION 4
|
||||
|
||||
// Message sent and received over the message stream
|
||||
// See: https://developers.google.com/nearby/fast-pair/spec#MessageStream
|
||||
typedef struct {
|
||||
uint8_t message_group;
|
||||
uint8_t message_code;
|
||||
// |data| length in native encoding
|
||||
uint16_t length;
|
||||
// message payload in big endian encoding
|
||||
uint8_t* data;
|
||||
} nearby_message_stream_Message;
|
||||
|
||||
// State and configuration of message stream parser
|
||||
typedef struct {
|
||||
// Callback triggered when a complete message is read from the input stream
|
||||
void (*on_message_received)(uint64_t peer_address,
|
||||
nearby_message_stream_Message* message);
|
||||
// |peer_address| that is passed to |on_message_received|
|
||||
uint64_t peer_address;
|
||||
// Length of |buffer|
|
||||
size_t length;
|
||||
// The buffer used for storing an incoming message. The parser uses the buffer
|
||||
// to store nearby_message_stream_Metadata, so not all of the space is
|
||||
// available for message payload
|
||||
uint8_t* buffer;
|
||||
} nearby_message_stream_State;
|
||||
|
||||
typedef struct {
|
||||
nearby_message_stream_Message message;
|
||||
uint16_t bytes_read;
|
||||
} nearby_message_stream_Metadata;
|
||||
|
||||
#if NEARBY_FP_MESSAGE_STREAM
|
||||
// Initializes the parser
|
||||
void nearby_message_stream_Init(const nearby_message_stream_State* state);
|
||||
|
||||
// Reads and deserializes data from an input stream. It is OK to pass in
|
||||
// incomplete packets. When the parses reads a complete message, it calls
|
||||
// |on_message_received|. If the message payload is too big to fit the buffer -
|
||||
// bigger than GetMaxPayloadSize(), then the payload is truncated.
|
||||
void nearby_message_stream_Read(const nearby_message_stream_State* state,
|
||||
const uint8_t* data, size_t length);
|
||||
|
||||
// Serializes and sends |message| out using nearby_platform_SendMessageStream()
|
||||
nearby_platform_status nearby_message_stream_Send(
|
||||
uint64_t peer_address, const nearby_message_stream_Message* message);
|
||||
|
||||
// Sends out an ACK message for a received |message|. Note that not all messages
|
||||
// require an ACK
|
||||
nearby_platform_status nearby_message_stream_SendAck(
|
||||
uint64_t peer_address, const nearby_message_stream_Message* message);
|
||||
|
||||
// Sends out a NACK message for a received |message| with |fail_reason| reason.
|
||||
nearby_platform_status nearby_message_stream_SendNack(
|
||||
uint64_t peer_address, const nearby_message_stream_Message* message,
|
||||
uint8_t fail_reason);
|
||||
|
||||
// Returns the maximum message payload size
|
||||
uint16_t nearby_message_stream_GetMaxPayloadSize(
|
||||
const nearby_message_stream_State* state);
|
||||
|
||||
#endif /* NEARBY_FP_MESSAGE_STREAM */
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // NEARBY_MESSAGE_STREAM_H
|
||||
@@ -1,84 +0,0 @@
|
||||
// Copyright 2022 Google LLC
|
||||
//
|
||||
// Licensed 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
|
||||
//
|
||||
// https://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.
|
||||
|
||||
#ifndef NEARBY_TRACE_H
|
||||
#define NEARBY_TRACE_H
|
||||
|
||||
#include "nearby.h"
|
||||
#include "nearby_platform_trace.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
// Must be kept in sync with TraceLevel in nearby_platform_trace.h
|
||||
#define NEARBY_TRACE_LEVEL_VERBOSE (1)
|
||||
#define NEARBY_TRACE_LEVEL_DEBUG (2)
|
||||
#define NEARBY_TRACE_LEVEL_INFO (3)
|
||||
#define NEARBY_TRACE_LEVEL_WARNING (4)
|
||||
#define NEARBY_TRACE_LEVEL_ERROR (5)
|
||||
#define NEARBY_TRACE_LEVEL_OFF (6)
|
||||
|
||||
#if NEARBY_TRACE_LEVEL < NEARBY_TRACE_LEVEL_VERBOSE || \
|
||||
NEARBY_TRACE_LEVEL > NEARBY_TRACE_LEVEL_OFF
|
||||
#error "Invalid definition of NEARBY_TRACE_LEVEL."
|
||||
#endif
|
||||
|
||||
#if NEARBY_TRACE_LEVEL > NEARBY_TRACE_LEVEL_VERBOSE
|
||||
#define NEARBY_TRACE_VERBOSE(level, ...)
|
||||
#else
|
||||
#define NEARBY_TRACE_VERBOSE(level, ...) _NEARBY_TRACE(level, __VA_ARGS__)
|
||||
#define NEARBY_ALL_ENUM_TO_STR_ENABLE 1
|
||||
#endif
|
||||
|
||||
#if NEARBY_TRACE_LEVEL > NEARBY_TRACE_LEVEL_DEBUG
|
||||
#define NEARBY_TRACE_DEBUG(level, ...)
|
||||
#else
|
||||
#define NEARBY_TRACE_DEBUG(level, ...) _NEARBY_TRACE(level, __VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#if NEARBY_TRACE_LEVEL > NEARBY_TRACE_LEVEL_INFO
|
||||
#define NEARBY_TRACE_INFO(level, ...)
|
||||
#else
|
||||
#define NEARBY_TRACE_INFO(level, ...) _NEARBY_TRACE(level, __VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#if NEARBY_TRACE_LEVEL > NEARBY_TRACE_LEVEL_WARNING
|
||||
#define NEARBY_TRACE_WARNING(level, ...)
|
||||
#else
|
||||
#define NEARBY_TRACE_WARNING(level, ...) _NEARBY_TRACE(level, __VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#if NEARBY_TRACE_LEVEL > NEARBY_TRACE_LEVEL_ERROR
|
||||
#define NEARBY_TRACE_ERROR(level, ...)
|
||||
#else
|
||||
#define NEARBY_TRACE_ERROR(level, ...) _NEARBY_TRACE(level, __VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#ifndef __NEARBY_SHORT_FILE__
|
||||
#define __NEARBY_SHORT_FILE__ __FILE__
|
||||
#endif
|
||||
|
||||
#define _NEARBY_TRACE(level, ...) \
|
||||
nearby_platform_Trace(level, __NEARBY_SHORT_FILE__, __LINE__, \
|
||||
"@g " __VA_ARGS__);
|
||||
|
||||
#define NEARBY_TRACE(level, ...) \
|
||||
NEARBY_TRACE_##level((nearby_platform_TraceLevel)NEARBY_TRACE_LEVEL_##level, \
|
||||
__VA_ARGS__)
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* NEARBY_TRACE_H */
|
||||
@@ -1,96 +0,0 @@
|
||||
// Copyright 2022 Google LLC
|
||||
//
|
||||
// Licensed 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
|
||||
//
|
||||
// https://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 "nearby_utils.h"
|
||||
|
||||
uint8_t nearby_utils_GetByte(uint64_t source, int byteNumber) {
|
||||
return source >> (8 * byteNumber);
|
||||
}
|
||||
|
||||
void nearby_utils_CopyBigEndian(uint8_t* dest, uint64_t source, int bytes) {
|
||||
int i;
|
||||
for (i = 0; i < bytes; i++) {
|
||||
dest[bytes - i - 1] = nearby_utils_GetByte(source, i);
|
||||
}
|
||||
}
|
||||
|
||||
void nearby_utils_CopyLittleEndian(uint8_t* dest, uint64_t source, int bytes) {
|
||||
int i;
|
||||
for (i = 0; i < bytes; i++) {
|
||||
dest[i] = nearby_utils_GetByte(source, i);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t nearby_utils_GetBigEndian24(uint8_t* buffer) {
|
||||
return (256 * 256 * buffer[0]) + (256 * buffer[1]) + buffer[2];
|
||||
}
|
||||
|
||||
uint32_t nearby_utils_GetBigEndian32(uint8_t* buffer) {
|
||||
return (256 * 256 * 256 * buffer[0]) + (256 * 256 * buffer[1]) +
|
||||
(256 * buffer[2]) + buffer[3];
|
||||
}
|
||||
|
||||
uint64_t nearby_utils_GetBigEndian48(uint8_t* b) {
|
||||
return (((uint64_t)b[0]) << 40) | (((uint64_t)b[1]) << 32) |
|
||||
(((uint64_t)b[2]) << 24) | (((uint64_t)b[3]) << 16) |
|
||||
(((uint64_t)b[4]) << 8) | (uint64_t)b[5];
|
||||
}
|
||||
|
||||
static char NibbleToHex(uint8_t value) {
|
||||
if (value < 10) return '0' + value;
|
||||
value -= 10;
|
||||
if (value < 6) return 'A' + value;
|
||||
return '?';
|
||||
}
|
||||
|
||||
const char* nearby_utils_ArrayToString(const uint8_t* data, size_t length) {
|
||||
static char buffer[80];
|
||||
size_t buffer_size = sizeof(buffer);
|
||||
size_t num_bytes;
|
||||
if (2 * length < buffer_size - 1) {
|
||||
num_bytes = 2 * length;
|
||||
buffer[num_bytes] = 0;
|
||||
} else {
|
||||
// The buffer is too small to hold all of data. Let's truncate the data and
|
||||
// append an ellipsis.
|
||||
num_bytes = buffer_size - 4;
|
||||
buffer[buffer_size - 1] = 0;
|
||||
buffer[buffer_size - 2] = '.';
|
||||
buffer[buffer_size - 3] = '.';
|
||||
buffer[buffer_size - 4] = '.';
|
||||
num_bytes = buffer_size - 4;
|
||||
}
|
||||
const uint8_t* input = data;
|
||||
char* output = buffer;
|
||||
for (size_t i = 0; i < num_bytes; i += 2) {
|
||||
uint8_t x = *input++;
|
||||
*output++ = NibbleToHex(x >> 4);
|
||||
*output++ = NibbleToHex(x & 0x0F);
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
const char* nearby_utils_MacToString(uint64_t address) {
|
||||
static char buffer[18];
|
||||
char* p = buffer + sizeof(buffer) - 1;
|
||||
*p-- = 0;
|
||||
while (p > buffer) {
|
||||
*p-- = NibbleToHex(address & 0xF);
|
||||
address >>= 4;
|
||||
*p-- = NibbleToHex(address & 0xF);
|
||||
address >>= 4;
|
||||
if (p >= buffer) *p-- = ':';
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
// Copyright 2022 Google LLC
|
||||
//
|
||||
// Licensed 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
|
||||
//
|
||||
// https://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.
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
// Copyright 2022 Google LLC
|
||||
//
|
||||
// Licensed 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
|
||||
//
|
||||
// https://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.
|
||||
|
||||
#ifndef NEARBY_UTILS_H
|
||||
#define NEARBY_UTILS_H
|
||||
|
||||
#include "nearby_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
uint8_t nearby_utils_GetByte(uint64_t source, int byteNumber);
|
||||
|
||||
void nearby_utils_CopyBigEndian(uint8_t* dest, uint64_t source, int bytes);
|
||||
void nearby_utils_CopyLittleEndian(uint8_t* dest, uint64_t source, int bytes);
|
||||
|
||||
uint32_t nearby_utils_GetBigEndian24(uint8_t* buffer);
|
||||
uint32_t nearby_utils_GetBigEndian32(uint8_t* buffer);
|
||||
uint64_t nearby_utils_GetBigEndian48(uint8_t* buffer);
|
||||
|
||||
// Converts the data to a hex string for debugging. Returns a pointer to a
|
||||
// static buffer. Don't call it twice in the same log message!
|
||||
const char* nearby_utils_ArrayToString(const uint8_t* data, size_t data_length);
|
||||
|
||||
// Converts BT MAC address to string for debugging. Returns a pointer to a
|
||||
// static buffer. Don't call it twice in the same log message!
|
||||
const char* nearby_utils_MacToString(uint64_t address);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* NEARBY_UTILS_H */
|
||||
@@ -1,31 +0,0 @@
|
||||
// Copyright 2022 Google LLC
|
||||
//
|
||||
// Licensed 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
|
||||
//
|
||||
// https://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.
|
||||
|
||||
#ifndef NEARBY_TYPES_H
|
||||
#define NEARBY_TYPES_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // NEARBY_TYPES_H
|
||||
@@ -1,60 +0,0 @@
|
||||
// Copyright 2022 Google LLC
|
||||
//
|
||||
// Licensed 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
|
||||
//
|
||||
// https://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.
|
||||
|
||||
#ifndef NEARBY_H
|
||||
#define NEARBY_H
|
||||
|
||||
#include "nearby_types.h"
|
||||
|
||||
// clang-format off
|
||||
#include "nearby_config.h"
|
||||
// clang-format on
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#define AES_MESSAGE_SIZE_BYTES 16
|
||||
#define FP_SERVICE_UUID_SIZE 2
|
||||
#define FP_MODEL_ID_SIZE 3
|
||||
// Nearby stores BT addresses as uint64_t values
|
||||
#define FP_BT_ADDRESS_SIZE sizeof(uint64_t)
|
||||
#define ACCOUNT_KEY_SIZE_BYTES AES_MESSAGE_SIZE_BYTES
|
||||
#define SESSION_NONCE_SIZE 8
|
||||
|
||||
typedef struct {
|
||||
uint8_t account_key[ACCOUNT_KEY_SIZE_BYTES];
|
||||
#ifdef NEARBY_FP_ENABLE_SASS
|
||||
uint64_t peer_address;
|
||||
#endif /* NEARBY_FP_ENABLE_SASS */
|
||||
} nearby_platform_AccountKeyInfo;
|
||||
|
||||
#define NEARBY_FP_ACCOUNT_KEY_INFO_SIZE sizeof(nearby_platform_AccountKeyInfo)
|
||||
|
||||
typedef enum {
|
||||
kNearbyStatusOK = 0,
|
||||
kNearbyStatusError,
|
||||
kNearbyStatusTimeout,
|
||||
kNearbyStatusResourceExhausted,
|
||||
kNearbyStatusUnimplemented,
|
||||
kNearbyStatusUnsupported,
|
||||
kNearbyStatusInvalidInput,
|
||||
kNearbyStatusRedundantAction
|
||||
} nearby_platform_status;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* NEARBY_H */
|
||||
@@ -1,196 +0,0 @@
|
||||
// Copyright 2021 Google LLC.
|
||||
#ifndef NEARBY_PLATFORM_AUDIO_H
|
||||
#define NEARBY_PLATFORM_AUDIO_H
|
||||
|
||||
#include "nearby.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#define NEARBY_PLATFORM_CONNECTION_STATE_NO_CONNECTION 0
|
||||
#define NEARBY_PLATFORM_CONNECTION_STATE_PAGING 1
|
||||
#define NEARBY_PLATFORM_CONNECTION_STATE_NO_DATA_TRANFER 2
|
||||
#define NEARBY_PLATFORM_CONNECTION_STATE_NON_AUDIO_DATA_TRANSFER 3
|
||||
#define NEARBY_PLATFORM_CONNECTION_STATE_A2DP 4
|
||||
#define NEARBY_PLATFORM_CONNECTION_STATE_A2DP_WITH_AVRCP 5
|
||||
#define NEARBY_PLATFORM_CONNECTION_STATE_HFP 6
|
||||
#define NEARBY_PLATFORM_CONNECTION_STATE_LE_MEDIA_WITHOUT_CONTROL 7
|
||||
#define NEARBY_PLATFORM_CONNECTION_STATE_LE_MEDIA_WITH_CONTROL 8
|
||||
#define NEARBY_PLATFORM_CONNECTION_STATE_LE_CALL 9
|
||||
#define NEARBY_PLATFORM_CONNECTION_STATE_LE_BIS 10
|
||||
#define NEARBY_PLATFORM_CONNECTION_STATE_DISABLED_CONNECTION_SWITCH 15
|
||||
|
||||
// Multipoint switching preference flag bits. Every bit represents "new profile
|
||||
// request" vs "current profile request". 1 - preference for switching, 0 -
|
||||
// preference for not switching
|
||||
#define NEARBY_SASS_SWITCHING_PREFERENCE_A2DP_VS_A2DP_MASK (1 << 7)
|
||||
#define NEARBY_SASS_SWITCHING_PREFERENCE_HFP_VS_HFP_MASK (1 << 6)
|
||||
#define NEARBY_SASS_SWITCHING_PREFERENCE_A2DP_VS_HFP_MASK (1 << 5)
|
||||
#define NEARBY_SASS_SWITCHING_PREFERENCE_HFP_VS_A2DP_MASK (1 << 4)
|
||||
|
||||
// Flags for SwitchActiveAudioSource
|
||||
// 1 switch to this device, 0 switch to second connected device
|
||||
#define NEARBY_SASS_SWITCH_ACTIVE_AUDIO_SOURCE_THIS_DEVICE_MASK (1 << 7)
|
||||
// Resume playing on switch to device after switching, 0 otherwise. Resuming
|
||||
// playing means the Provider sends a PLAY notification to the Seeker through
|
||||
// AVRCP profile. If the previous state (before switched away) was not PLAY, the
|
||||
// Provider should ignore this flag.
|
||||
#define NEARBY_SASS_SWITCH_ACTIVE_AUDIO_SOURCE_RESUME_MASK (1 << 6)
|
||||
// 1 reject SCO on switched away device, 0 otherwise
|
||||
#define NEARBY_SASS_SWITCH_ACTIVE_AUDIO_SOURCE_REJECT_SCO_MASK (1 << 5)
|
||||
// 1 disconnect Bluetooth on switch away device, 0 otherwise.
|
||||
#define NEARBY_SASS_SWITCH_ACTIVE_AUDIO_SOURCE_DISCONNECT_PREVIOUS_MASK (1 << 4)
|
||||
|
||||
// Flags for SwitchBackAudioSource. Note that the flags below are not bitmasks.
|
||||
#define NEARBY_SASS_SWITCH_BACK 0x01
|
||||
#define NEARBY_SASS_SWITCH_BACK_AND_RESUME 0x02
|
||||
|
||||
// Flags for NotifySassInitiatedConnection. Note that the flags below are not
|
||||
// bitmasks.
|
||||
#define NEARBY_SASS_CONNECTION_INITIATED_BY_SASS 0
|
||||
#define NEARBY_SASS_CONNECTION_NOT_INITIATED_BY_SASS 1
|
||||
|
||||
// Reasons for |on_multipoint_switch_event|
|
||||
#define NEARBY_SASS_MULTIPOINT_SWITCH_REASON_UNKNOWN 0
|
||||
#define NEARBY_SASS_MULTIPOINT_SWITCH_REASON_A2DP 1
|
||||
#define NEARBY_SASS_MULTIPOINT_SWITCH_REASON_HFP 2
|
||||
|
||||
// Returns true if right earbud is active
|
||||
bool nearby_platform_GetEarbudRightStatus();
|
||||
|
||||
// Returns true if left earbud is active
|
||||
bool nearby_platform_GetEarbudLeftStatus();
|
||||
|
||||
typedef struct {
|
||||
// The platform HAL should call this callback on audio state changes. That is,
|
||||
// when any of the query methods would return a new value.
|
||||
void (*on_state_change)();
|
||||
// This event should be called after a multipoint audio source switch. To make
|
||||
// users aware of a multipoint-switch event taking place, SASS Seekers may
|
||||
// show a notification to users. So the Provider should notify connected SASS
|
||||
// Seekers about the switching event.
|
||||
// |reason| is one of NEARBY_SASS_MULTIPOINT_SWITCH_REASON_* constants
|
||||
// |peer_address| is the address the new audio source
|
||||
// |name| is utf-8 encoded name of the new audio source or NULL if name is not
|
||||
// known.
|
||||
void (*on_multipoint_switch_event)(uint8_t reason, uint64_t peer_address,
|
||||
const char* name);
|
||||
} nearby_platform_AudioCallbacks;
|
||||
|
||||
// Returns one of NEARBY_PLATFORM_CONNECTION_STATE_* values
|
||||
// Call |nearby_platform_AudioCallbacks::on_state_change| when this state
|
||||
// changes.
|
||||
unsigned int nearby_platform_GetAudioConnectionState();
|
||||
|
||||
// Returns true if the device is on head (or in ear).
|
||||
// Call |nearby_platform_AudioCallbacks::on_state_change| when on-head state
|
||||
// changes.
|
||||
bool nearby_platform_OnHead();
|
||||
|
||||
// Returns true if the device can accept another audio connection without
|
||||
// dropping any of the existing connections.
|
||||
// Call |nearby_platform_AudioCallbacks::on_state_change| when this state
|
||||
// changes.
|
||||
bool nearby_platform_CanAcceptConnection();
|
||||
|
||||
// When the device is in focus mode, connection switching is not allowed
|
||||
// Call |nearby_platform_AudioCallbacks::on_state_change| when this state
|
||||
// changes.
|
||||
bool nearby_platform_InFocusMode();
|
||||
|
||||
// Returns true if the current connection is auto-recconnected, meaning it is
|
||||
// not connected by the user. For multi-point connections, returns true if any
|
||||
// of the existing connections is auto-reconnected.
|
||||
// Call |nearby_platform_AudioCallbacks::on_state_change| when this state
|
||||
// changes.
|
||||
bool nearby_platform_AutoReconnected();
|
||||
|
||||
// Sets a bit in the |bitmap| for every connected peer. The bit stays cleared
|
||||
// for bonded but not connected peers. The order change is acceptable if it is
|
||||
// unavoidable, e.g. when users factory reset the headset or when the bonded
|
||||
// device count reaches the upper limit.
|
||||
// |length| is the |bitmap| length on input in bytes and used space on output.
|
||||
// For example, if there are 5 bonded devices, then |length| should be set to 1.
|
||||
// Call |nearby_platform_AudioCallbacks::on_state_change| when this state
|
||||
// changes.
|
||||
void nearby_platform_GetConnectionBitmap(uint8_t* bitmap, size_t* length);
|
||||
|
||||
// Returns true is SASS state in On
|
||||
bool nearby_platform_IsSassOn();
|
||||
|
||||
// Returns true if the device supports multipoint and it can be switched between
|
||||
// on and off
|
||||
bool nearby_platform_IsMultipointConfigurable();
|
||||
|
||||
// Returns true is multipoint in On
|
||||
bool nearby_platform_IsMultipointOn();
|
||||
|
||||
// Returns true if the device supports OHD (even if it's turned off at the
|
||||
// moment)
|
||||
bool nearby_platform_IsOnHeadDetectionSupported();
|
||||
|
||||
// Returns true if OHD is supported and enabled
|
||||
bool nearby_platform_IsOnHeadDetectionEnabled();
|
||||
|
||||
// Enables or disables multipoint
|
||||
// When |enable| is false, the device should keep the connection with
|
||||
// |peer_address| and disconnect other connections (if any)
|
||||
nearby_platform_status nearby_platform_SetMultipoint(uint64_t peer_address,
|
||||
bool enable);
|
||||
|
||||
// Sets multipoint switching preference flags
|
||||
nearby_platform_status nearby_platform_SetSwitchingPreference(uint8_t flags);
|
||||
|
||||
// Gets switching preference flags
|
||||
uint8_t nearby_platform_GetSwitchingPreference();
|
||||
|
||||
// Switches active audio source (to a connected device). If the flags indicate a
|
||||
// switch to |peer_address| device but |peer_address| is already the active
|
||||
// device, then return kNearbyStatusRedundantAction.
|
||||
// If the flags indicate a switch to another device, then
|
||||
// |preferred_audio_source| is the address of the next, preferred audio source.
|
||||
// |preferred_audio_source| is 0 if Nearby SDK cannot figure out what the next
|
||||
// audio source should be. It may happen if they are no other connected Seekers.
|
||||
nearby_platform_status nearby_platform_SwitchActiveAudioSource(
|
||||
uint64_t peer_address, uint8_t flags, uint64_t preferred_audio_source);
|
||||
|
||||
// Switches back to a disconnected audio source.
|
||||
// |peer_address| is the address of the seeker who sent this command, *not* the
|
||||
// address of the audio source that the device should switch to. The device
|
||||
// should connect to the previous, currently disconnected, audio source and
|
||||
// disconnect from |peer_address|. Ideally, the device should disconnect from
|
||||
// |peer_address| after returning from this function. This would give Nearby SDK
|
||||
// a chance to send an ACK message to the seeker.
|
||||
nearby_platform_status nearby_platform_SwitchBackAudioSource(
|
||||
uint64_t peer_address, uint8_t flags);
|
||||
|
||||
// Notifies the platform if the connection was initiated by SASS. SASS Providers
|
||||
// may need to know if the connection switching is triggered by SASS to have
|
||||
// different reactions, e.g. disable earcons for SASS events. The Seeker sends a
|
||||
// message to notify the Provider that this connection was a SASS initiated
|
||||
// connection.
|
||||
nearby_platform_status nearby_platform_NotifySassInitiatedConnection(
|
||||
uint64_t peer_address, uint8_t flags);
|
||||
|
||||
// Sets drop connection target
|
||||
// On multipoint headphones, if the preferred connection to be dropped is not
|
||||
// the least recently used one, SASS Seekers can tell the Provider which device
|
||||
// to be dropped by using the message below.
|
||||
nearby_platform_status nearby_platform_SetDropConnectionTarget(
|
||||
uint64_t peer_address, uint8_t flags);
|
||||
|
||||
// Returns the BT address of the active audio source
|
||||
// Call |nearby_platform_AudioCallbacks::on_state_change| when active audio
|
||||
// source changes.
|
||||
uint64_t nearby_platform_GetActiveAudioSource();
|
||||
|
||||
// Initializes Audio module
|
||||
nearby_platform_status nearby_platform_AudioInit(
|
||||
const nearby_platform_AudioCallbacks* audio_interface);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* NEARBY_PLATFORM_AUDIO_H */
|
||||
@@ -1,56 +0,0 @@
|
||||
// Copyright 2022 Google LLC
|
||||
//
|
||||
// Licensed 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
|
||||
//
|
||||
// https://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.
|
||||
|
||||
#ifndef NEARBY_PLATFORM_BATTERY_H
|
||||
#define NEARBY_PLATFORM_BATTERY_H
|
||||
|
||||
#include "nearby.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
typedef struct {
|
||||
// Set to true if the device is charging.
|
||||
bool is_charging;
|
||||
// Battery level of the right bud. 0 - 100 range.
|
||||
uint8_t right_bud_battery_level;
|
||||
// Battery level of the left bud. 0 - 100 range.
|
||||
uint8_t left_bud_battery_level;
|
||||
// Battery level of the charging case . 0 - 100 range.
|
||||
uint8_t charging_case_battery_level;
|
||||
// Battery remaining time in minutes, 0-65335 range.
|
||||
uint16_t remaining_time_minutes;
|
||||
} nearby_platform_BatteryInfo;
|
||||
|
||||
typedef struct {
|
||||
void (*on_battery_changed)(void);
|
||||
} nearby_platform_BatteryInterface;
|
||||
|
||||
// Gets battery and charging info
|
||||
//
|
||||
// battery_info - Battery status structure.
|
||||
nearby_platform_status nearby_platform_GetBatteryInfo(
|
||||
nearby_platform_BatteryInfo* battery_info);
|
||||
|
||||
// Initializes battery module
|
||||
//
|
||||
// battery_interface - Battery status callback events.
|
||||
nearby_platform_status nearby_platform_BatteryInit(
|
||||
nearby_platform_BatteryInterface* battery_interface);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* NEARBY_PLATFORM_BATTERY_H */
|
||||
@@ -1,108 +0,0 @@
|
||||
// Copyright 2022 Google LLC
|
||||
//
|
||||
// Licensed 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
|
||||
//
|
||||
// https://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.
|
||||
|
||||
#ifndef NEARBY_PLATFORM_BLE_H
|
||||
#define NEARBY_PLATFORM_BLE_H
|
||||
|
||||
#include "nearby.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
typedef enum {
|
||||
kModelId = 0, // FE2C1233-8366-4814-8EB0-01DE32100BEA (read)
|
||||
kKeyBasedPairing, // FE2C1234-8366-4814-8EB0-01DE32100BEA (write, notify)
|
||||
kPasskey, // FE2C1235-8366-4814-8EB0-01DE32100BEA (write, notify)
|
||||
kAccountKey, // FE2C1236-8366-4814-8EB0-01DE32100BEA (write)
|
||||
kFirmwareRevision, // 0x2A26
|
||||
kAdditionalData, // FE2C1237-8366-4814-8EB0-01DE32100BEA
|
||||
// Message Stream PSM characteristic is required to establish an L2CAP
|
||||
// communication channel between Seeker and Provider. Platforms that don't
|
||||
// support L2CAP channel may choose not to implement this characteristic.
|
||||
// By default, the Seeker connect to the Provider using RFCOMM.
|
||||
kMessageStreamPsm, // FE2C1239-8366-4814-8EB0-01DE32100BEA (read, encrypted)
|
||||
} nearby_fp_Characteristic;
|
||||
|
||||
typedef enum {
|
||||
kDisabled,
|
||||
kNoLargerThan100ms,
|
||||
kNoLargerThan250ms
|
||||
} nearby_fp_AvertisementInterval;
|
||||
|
||||
typedef struct {
|
||||
nearby_platform_status (*on_gatt_write)(
|
||||
uint64_t peer_address, nearby_fp_Characteristic characteristic,
|
||||
const uint8_t* request, size_t length);
|
||||
nearby_platform_status (*on_gatt_read)(
|
||||
uint64_t peer_address, nearby_fp_Characteristic characteristic,
|
||||
uint8_t* output, size_t* length);
|
||||
|
||||
} nearby_platform_BleInterface;
|
||||
|
||||
// Gets BLE address.
|
||||
uint64_t nearby_platform_GetBleAddress();
|
||||
|
||||
// Sets BLE address. Returns address after change, which may be different than
|
||||
// requested address.
|
||||
//
|
||||
// address - BLE address to set.
|
||||
uint64_t nearby_platform_SetBleAddress(uint64_t address);
|
||||
|
||||
#ifdef NEARBY_FP_HAVE_BLE_ADDRESS_ROTATION
|
||||
// Rotates BLE address to a random resolvable private address (RPA). Returns
|
||||
// address after change.
|
||||
uint64_t nearby_platform_RotateBleAddress();
|
||||
#endif /* NEARBY_FP_HAVE_BLE_ADDRESS_ROTATION */
|
||||
|
||||
// Gets the PSM - Protocol and Service Mulitplexor - assigned to Fast Pair's
|
||||
// Message Stream.
|
||||
// To support Message Stream for BLE devices, Fast Pair will build and maintain
|
||||
// a BLE L2CAP channel for sending and receiving messages. The PSM can be
|
||||
// dynamic or fixed.
|
||||
// Returns a 16 bit PSM number or a negative value on error. When a valid PSM
|
||||
// number is returned, the device must be ready to accept L2CAP connections.
|
||||
int32_t nearby_platform_GetMessageStreamPsm();
|
||||
|
||||
// Sends a notification to the connected GATT client.
|
||||
//
|
||||
// peer_address - Address of peer.
|
||||
// characteristic - Characteristic UUID
|
||||
// message - Message buffer to transmit.
|
||||
// length - Length of message in buffer.
|
||||
nearby_platform_status nearby_platform_GattNotify(
|
||||
uint64_t peer_address, nearby_fp_Characteristic characteristic,
|
||||
const uint8_t* message, size_t length);
|
||||
|
||||
// Sets the Fast Pair advertisement payload and starts advertising at a given
|
||||
// interval.
|
||||
//
|
||||
// payload - Advertising data.
|
||||
// length - Length of data.
|
||||
// interval - Advertising interval code.
|
||||
nearby_platform_status nearby_platform_SetAdvertisement(
|
||||
const uint8_t* payload, size_t length,
|
||||
nearby_fp_AvertisementInterval interval);
|
||||
|
||||
// Initializes BLE
|
||||
//
|
||||
// ble_interface - GATT read and write callbacks structure.
|
||||
nearby_platform_status nearby_platform_BleInit(
|
||||
const nearby_platform_BleInterface* ble_interface);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* NEARBY_PLATFORM_BLE_H */
|
||||
@@ -1,121 +0,0 @@
|
||||
// Copyright 2022 Google LLC
|
||||
//
|
||||
// Licensed 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
|
||||
//
|
||||
// https://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.
|
||||
|
||||
#ifndef NEARBY_PLATFORM_BT_H
|
||||
#define NEARBY_PLATFORM_BT_H
|
||||
|
||||
// clang-format off
|
||||
#include "nearby_config.h"
|
||||
// clang-format on
|
||||
|
||||
#include "nearby.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
typedef struct {
|
||||
void (*on_pairing_request)(uint64_t peer_address);
|
||||
void (*on_paired)(uint64_t peer_address);
|
||||
void (*on_pairing_failed)(uint64_t peer_address);
|
||||
#if NEARBY_FP_MESSAGE_STREAM
|
||||
// Message Stream messages are sent over RFCOMM on BT devices or L2CAP on BLE
|
||||
// devices.
|
||||
void (*on_message_stream_connected)(uint64_t peer_address);
|
||||
void (*on_message_stream_disconnected)(uint64_t peer_address);
|
||||
void (*on_message_stream_received)(uint64_t peer_address,
|
||||
const uint8_t* message, size_t length);
|
||||
#endif /* NEARBY_FP_MESSAGE_STREAM */
|
||||
} nearby_platform_BtInterface;
|
||||
|
||||
// Returns Fast Pair Model Id.
|
||||
uint32_t nearby_platform_GetModelId();
|
||||
|
||||
// Returns tx power level.
|
||||
int8_t nearby_platform_GetTxLevel();
|
||||
|
||||
// Returns public BR/EDR address.
|
||||
// On a BLE-only device, return the public identity address.
|
||||
uint64_t nearby_platform_GetPublicAddress();
|
||||
|
||||
// Returns the secondary identity address.
|
||||
// Some devices, such as ear-buds, can advertise two identity addresses. In this
|
||||
// case, the Seeker pairs with each address separately but treats them as a
|
||||
// single logical device set.
|
||||
// Return 0 if this device does not have a secondary identity address.
|
||||
uint64_t nearby_platform_GetSecondaryPublicAddress();
|
||||
|
||||
// Returns passkey used during pairing
|
||||
uint32_t nearby_platfrom_GetPairingPassKey();
|
||||
|
||||
// Provides the passkey received from the remote party.
|
||||
// The system should compare local and remote party and accept/decline pairing
|
||||
// request accordingly.
|
||||
//
|
||||
// passkey - Passkey
|
||||
void nearby_platform_SetRemotePasskey(uint32_t passkey);
|
||||
|
||||
// Sends a pairing request to the Seeker
|
||||
//
|
||||
// remote_party_br_edr_address - BT address of peer.
|
||||
nearby_platform_status nearby_platform_SendPairingRequest(
|
||||
uint64_t remote_party_br_edr_address);
|
||||
|
||||
// Switches the device capabilities field back to default so that new
|
||||
// pairings continue as expected.
|
||||
nearby_platform_status nearby_platform_SetDefaultCapabilities();
|
||||
|
||||
// Switches the device capabilities field to Fast Pair required configuration:
|
||||
// DisplayYes/No so that `confirm passkey` pairing method will be used.
|
||||
nearby_platform_status nearby_platform_SetFastPairCapabilities();
|
||||
|
||||
// Sets null-terminated device name string in UTF-8 encoding
|
||||
//
|
||||
// name - Zero terminated string name of device.
|
||||
nearby_platform_status nearby_platform_SetDeviceName(const char* name);
|
||||
|
||||
// Gets null-terminated device name string in UTF-8 encoding
|
||||
// pass buffer size in char, and get string length in char.
|
||||
//
|
||||
// name - Buffer to return name string.
|
||||
// length - On input, the size of the name buffer.
|
||||
// On output, returns size of name in buffer.
|
||||
nearby_platform_status nearby_platform_GetDeviceName(char* name,
|
||||
size_t* length);
|
||||
|
||||
// Returns true if the device is in pairing mode (either fast-pair or manual).
|
||||
bool nearby_platform_IsInPairingMode();
|
||||
|
||||
#if NEARBY_FP_MESSAGE_STREAM
|
||||
// Sends message stream through RFCOMM or L2CAP channel initiated by Seeker.
|
||||
// BT devices should use RFCOMM channel. BLE-only devices should use L2CAP.
|
||||
//
|
||||
// peer_address - Peer address.
|
||||
// message - Contents of message.
|
||||
// length - Length of message
|
||||
nearby_platform_status nearby_platform_SendMessageStream(uint64_t peer_address,
|
||||
const uint8_t* message,
|
||||
size_t length);
|
||||
#endif /* NEARBY_FP_MESSAGE_STREAM */
|
||||
// Initializes BT module
|
||||
//
|
||||
// bt_interface - BT callbacks event structure.
|
||||
nearby_platform_status nearby_platform_BtInit(
|
||||
const nearby_platform_BtInterface* bt_interface);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* NEARBY_PLATFORM_BT_H */
|
||||
@@ -1,80 +0,0 @@
|
||||
// Copyright 2022 Google LLC
|
||||
//
|
||||
// Licensed 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
|
||||
//
|
||||
// https://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.
|
||||
|
||||
#ifndef NEARBY_PLATFORM_OS_H
|
||||
#define NEARBY_PLATFORM_OS_H
|
||||
|
||||
#include "nearby.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
typedef enum {
|
||||
kRingStateStarted = 0,
|
||||
kRingStateFailedToStartOrStop,
|
||||
kRingStateStoppedReasonTimeout,
|
||||
kRingStateStoppedReasonUserAction,
|
||||
kRingStateStoppedReasonNearbyRequest
|
||||
} nearby_platform_RingState;
|
||||
|
||||
typedef struct {
|
||||
nearby_platform_RingState ring_state;
|
||||
// The number of components capable of ringing
|
||||
// 0 - the device is incapable of ringing
|
||||
// 1 - only a single component is capable of ringing
|
||||
// 2 - left and right bud can ring
|
||||
// 3 - left and right bud, and the case can ring
|
||||
uint8_t num_components;
|
||||
// A bitmap indicating what (sub)components are ringing. See
|
||||
// `nearby_platform_Ring` for details
|
||||
uint8_t components;
|
||||
// Remaining ringing timeout in deciseconds
|
||||
uint16_t timeout;
|
||||
} nearby_platform_RingingInfo;
|
||||
|
||||
// Gets current time in ms.
|
||||
unsigned int nearby_platform_GetCurrentTimeMs();
|
||||
|
||||
// Starts a timer. Returns an opaque timer handle or null on error.
|
||||
//
|
||||
// callback - Function to call when timer matures.
|
||||
// delay_ms - Number of milliseconds to run the timer.
|
||||
void* nearby_platform_StartTimer(void (*callback)(), unsigned int delay_ms);
|
||||
|
||||
// Cancels a timer
|
||||
//
|
||||
// timer - Timer handle returned by StartTimer.
|
||||
nearby_platform_status nearby_platform_CancelTimer(void* timer);
|
||||
|
||||
// Initializes OS module
|
||||
nearby_platform_status nearby_platform_OsInit();
|
||||
|
||||
// Starts ringing
|
||||
//
|
||||
// `command` - the requested ringing state as a bitmap:
|
||||
// Bit 1 (0x01): ring right
|
||||
// Bit 2 (0x02): ring left
|
||||
// Bit 3 (0x04): ring case
|
||||
// Alternatively, `command` hold a special value of 0xFF to ring all
|
||||
// components that can ring.
|
||||
// `timeout` - the timeout in deciseconds. The timeout overrides the one already
|
||||
// in effect if any component of the device is already ringing.
|
||||
nearby_platform_status nearby_platform_Ring(uint8_t command, uint16_t timeout);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* NEARBY_PLATFORM_OS_H */
|
||||
@@ -1,55 +0,0 @@
|
||||
// Copyright 2022 Google LLC
|
||||
//
|
||||
// Licensed 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
|
||||
//
|
||||
// https://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.
|
||||
|
||||
#ifndef NEARBY_PLATFORM_PERSISTENCE_H
|
||||
#define NEARBY_PLATFORM_PERSISTENCE_H
|
||||
|
||||
#include "nearby.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
typedef enum {
|
||||
kStoredKeyAccountKeyList,
|
||||
kStoredKeyPersonalizedName
|
||||
} nearby_fp_StoredKey;
|
||||
|
||||
// Loads stored key
|
||||
//
|
||||
// key - Type of key to fetch.
|
||||
// output - Buffer to contain retrieved key.
|
||||
// length - On input, contains the size of the output buffer.
|
||||
// On output, contains the Length of key.
|
||||
nearby_platform_status nearby_platform_LoadValue(nearby_fp_StoredKey key,
|
||||
uint8_t* output,
|
||||
size_t* length);
|
||||
|
||||
// Saves stored key
|
||||
//
|
||||
// key - Type of key to store.
|
||||
// output - Buffer containing key to store.
|
||||
// length - Length of key.
|
||||
nearby_platform_status nearby_platform_SaveValue(nearby_fp_StoredKey key,
|
||||
const uint8_t* input,
|
||||
size_t length);
|
||||
|
||||
// Initializes persistence module
|
||||
nearby_platform_status nearby_platform_PersistenceInit();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* NEARBY_PLATFORM_PERSISTENCE_H */
|
||||
@@ -1,86 +0,0 @@
|
||||
// Copyright 2022 Google LLC
|
||||
//
|
||||
// Licensed 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
|
||||
//
|
||||
// https://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.
|
||||
|
||||
#ifndef NEARBY_PLATFORM_SE_H
|
||||
#define NEARBY_PLATFORM_SE_H
|
||||
// clang-format off
|
||||
#include "nearby_config.h"
|
||||
// clang-format on
|
||||
#include "nearby.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
// Generates a random number.
|
||||
uint8_t nearby_platform_Rand();
|
||||
|
||||
// Computes the sha256 incrementally. Sha256Start() is called first, then
|
||||
// Sha256Update() one or more times, and finally Sha256Finish().
|
||||
nearby_platform_status nearby_platform_Sha256Start();
|
||||
|
||||
// Intermediate sha256 compute.
|
||||
//
|
||||
// data - Block of data to compute into sha256.
|
||||
// length - Length of data to process.
|
||||
nearby_platform_status nearby_platform_Sha256Update(const void* data,
|
||||
size_t length);
|
||||
|
||||
// Finishes sha256 compute.
|
||||
//
|
||||
// out - Contains the final 256 bit sha.
|
||||
nearby_platform_status nearby_platform_Sha256Finish(uint8_t out[32]);
|
||||
|
||||
// Encrypts a data block with AES128 in ECB mode.
|
||||
//
|
||||
// input - Input data block to be encrypted.
|
||||
// output - Resulting encrypted block.
|
||||
// key - 128 bit key to use for encryption.
|
||||
nearby_platform_status nearby_platform_Aes128Encrypt(
|
||||
const uint8_t input[AES_MESSAGE_SIZE_BYTES],
|
||||
uint8_t output[AES_MESSAGE_SIZE_BYTES],
|
||||
const uint8_t key[AES_MESSAGE_SIZE_BYTES]);
|
||||
|
||||
// Decrypts a data block with AES128 in ECB mode.
|
||||
//
|
||||
// input - Input data block to be decrypted.
|
||||
// output - Resulting decrypted block.
|
||||
// key - 128 bit key to use for decryption.
|
||||
nearby_platform_status nearby_platform_Aes128Decrypt(
|
||||
const uint8_t input[AES_MESSAGE_SIZE_BYTES],
|
||||
uint8_t output[AES_MESSAGE_SIZE_BYTES],
|
||||
const uint8_t key[AES_MESSAGE_SIZE_BYTES]);
|
||||
|
||||
// Generates a shared sec256p1 secret using remote party public key and this
|
||||
// device's private key.
|
||||
//
|
||||
// remote_party_public_key - Remote key.
|
||||
// secret - 256 bit shared secret.
|
||||
nearby_platform_status nearby_platform_GenSec256r1Secret(
|
||||
const uint8_t remote_party_public_key[64], uint8_t secret[32]);
|
||||
|
||||
// Returns anti-spoofing 128 bit private key.
|
||||
// Only used if the implementation also uses the
|
||||
// nearby_platform_GenSec256r1Secret() routine defined in gen_secret.c.
|
||||
// Return NULL if not implemented.
|
||||
const uint8_t* nearby_platform_GetAntiSpoofingPrivateKey();
|
||||
|
||||
// Initializes secure element module
|
||||
nearby_platform_status nearby_platform_SecureElementInit();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* NEARBY_PLATFORM_SE_H */
|
||||
@@ -1,60 +0,0 @@
|
||||
// Copyright 2022 Google LLC
|
||||
//
|
||||
// Licensed 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
|
||||
//
|
||||
// https://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.
|
||||
|
||||
#ifndef NEARBY_PLATFORM_TRACE_H
|
||||
#define NEARBY_PLATFORM_TRACE_H
|
||||
|
||||
#include "nearby.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
typedef enum {
|
||||
kTraceLevelUnknown = 0,
|
||||
kTraceLevelVerbose = 1,
|
||||
kTraceLevelDebug = 2,
|
||||
kTraceLevelInfo = 3,
|
||||
kTraceLevelWarning = 4,
|
||||
kTraceLevelError = 5,
|
||||
} nearby_platform_TraceLevel;
|
||||
|
||||
// Generates conditional trace line. This is usually wrapped in a macro to
|
||||
// provide compiler parameters.
|
||||
//
|
||||
// level - Debug level, higher is less messages.
|
||||
// filename - Name of file calling trace.
|
||||
// lineno - Source line of trace call.
|
||||
// fmt - printf() style format string (%).
|
||||
// ... - A series of parameters indicated by the fmt string.
|
||||
void nearby_platform_Trace(nearby_platform_TraceLevel level,
|
||||
const char *filename, int lineno, const char *fmt,
|
||||
...);
|
||||
|
||||
// Processes assert. Processes a failed assertion.
|
||||
//
|
||||
// filename - Name of file calling assert.
|
||||
// lineno - Source line of assert call
|
||||
// reason - String message indicating reason for assert.
|
||||
void nearby_platfrom_CrashOnAssert(const char *filename, int lineno,
|
||||
const char *reason);
|
||||
|
||||
// Initializes trace module.
|
||||
void nearby_platform_TraceInit(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* NEARBY_PLATFORM_TRACE_H */
|
||||
@@ -1,35 +0,0 @@
|
||||
|
||||
### Nearby SDK for embedded systems release notes
|
||||
|
||||
## v1.1.0-embedded-RC1
|
||||
Support GFPS 3.2 specification per [specification](https://developers.google.com/nearby/fast-pair/specifications/introduction).
|
||||
|
||||
New features:
|
||||
* Smart Audio Source Switching (SASS)
|
||||
* Two byte salt for improved security
|
||||
|
||||
Other changes:
|
||||
* Added optional encryption modules based on mbedtls.
|
||||
* Fixed build issues.
|
||||
* More verbose and readable logs.
|
||||
|
||||
Supported features include:
|
||||
* Initial pairing with discoverable advertisement
|
||||
* Subsequent pairing with non-discoverable advertisement
|
||||
* Retroactive Active Key for provisioning after manual pairing
|
||||
* Battery Notification
|
||||
* Personalized Name
|
||||
* RFCOMM message stream
|
||||
* Unit-tests on a simulated gLinux platform implementation
|
||||
|
||||
## v1.0.0-embedded
|
||||
Initial release supporting GFPS 3.1 per [specification](https://developers.google.com/nearby/fast-pair/specifications/introduction).
|
||||
|
||||
Supported features include:
|
||||
* Initial pairing with discoverable advertisement
|
||||
* Subsequent pairing with non-discoverable advertisement
|
||||
* Retroactive Active Key for provisioning after manual pairing
|
||||
* Battery Notification
|
||||
* Personalized Name
|
||||
* RFCOMM message stream
|
||||
* Unit-tests on a simulated gLinux platform implementation
|
||||
@@ -1,47 +0,0 @@
|
||||
# Use MBEDTLS for test SSL implementation instead of OPENSSL
|
||||
# Compiles in mbedtls implementation of a number of functions in se.h
|
||||
NEARBY_PLATFORM_USE_MBEDTLS ?= 0
|
||||
# Use the hardware SE to generate the secp256r1 secret. Alternatively, generate
|
||||
# the secret in software.
|
||||
NEARBY_PLATFORM_HAS_SE ?= 1
|
||||
|
||||
CFLAGS_EXTRA ?=
|
||||
CFLAGS += -g \
|
||||
-MD \
|
||||
-Werror \
|
||||
-Wno-deprecated-declarations \
|
||||
-DARCH_GLINUX \
|
||||
-fsanitize=address \
|
||||
-fno-omit-frame-pointer \
|
||||
-DARCH_GLINUX \
|
||||
-DNEARBY_ALL_MODULE_DEBUG \
|
||||
-DNEARBY_UNIT_TEST_ENABLED \
|
||||
$(CFLAGS_EXTRA)
|
||||
|
||||
NEARBY_TRACE_LEVEL = VERBOSE
|
||||
|
||||
ifeq ($(OPTIMIZED_BUILD),1)
|
||||
CFLAGS += -O2
|
||||
else
|
||||
CFLAGS += -O0
|
||||
endif
|
||||
|
||||
ifeq ($(NEARBY_PLATFORM_USE_MBEDTLS),1)
|
||||
CFLAGS += -DNEARBY_PLATFORM_USE_MBEDTLS
|
||||
endif
|
||||
|
||||
ifeq ($(NEARBY_PLATFORM_HAS_SE),1)
|
||||
CFLAGS += -DNEARBY_PLATFORM_HAS_SE
|
||||
endif
|
||||
|
||||
TEST_INCLUDES = \
|
||||
-I$(GTEST_DIR)/include -I$(GTEST_DIR) \
|
||||
-I$(GMOCK_DIR)/include -I$(GMOCK_DIR) \
|
||||
$(CLIENT_INCLUDES) \
|
||||
-Iclient/tests/ \
|
||||
-Iclient/tests/$(ARCH)/ \
|
||||
-Iclient/tests/mocks/
|
||||
|
||||
ifeq ($(NEARBY_PLATFORM_USE_MBEDTLS),1)
|
||||
TEST_INCLUDES += -I$(MBEDTLS_DIR)/include
|
||||
endif
|
||||
@@ -1,122 +0,0 @@
|
||||
ifneq ($(EXCLUDE_COMMON_TEST_SRCS),1)
|
||||
TEST_SRCS += $(wildcard $(COMMON_DIR)/tests/*.cc)
|
||||
endif
|
||||
|
||||
TEST_SRCS += $(wildcard client/tests/*.cc)
|
||||
|
||||
TEST_SRCS := $(filter-out $(TEST_SRCS_EXCLUDE), $(TEST_SRCS))
|
||||
|
||||
TEST_OBJS += $(patsubst %.cc,$(OUT_DIR)/%.o,$(TEST_SRCS))
|
||||
GLINUX_TARGET_SRCS := $(wildcard client/tests/glinux/*.cc)
|
||||
MBEDTLS_TARGET_SRCS := $(wildcard common/source/mbedtls/*.c)
|
||||
GTEST_SRCS = $(GTEST_DIR)/src/gtest-all.cc $(GMOCK_DIR)/src/gmock-all.cc
|
||||
EMPTY_TARGET_SRCS := $(wildcard client/tests/empty_target/*.c)
|
||||
|
||||
GTEST_OBJS := $(patsubst %.cc,$(OUT_DIR)/%.o,$(GTEST_SRCS))
|
||||
|
||||
GLINUX_TARGET_OBJS := $(patsubst %.cc,$(OUT_DIR)/%.o,$(GLINUX_TARGET_SRCS))
|
||||
MBEDTLS_TARGET_OBJS := $(patsubst %.c,$(OUT_DIR)/%.o,$(MBEDTLS_TARGET_SRCS))
|
||||
EMPTY_TARGET_OBJS := $(patsubst %.c,$(OUT_DIR)/%.o,$(EMPTY_TARGET_SRCS))
|
||||
|
||||
ALL_TEST_OBJS += $(GLINUX_TARGET_OBJS)
|
||||
|
||||
ALL_TEST_OBJS += $(TEST_OBJS)
|
||||
ALL_TEST_OBJS += $(GTEST_OBJS)
|
||||
ALL_TEST_OBJS += $(EMPTY_TARGET_OBJS)
|
||||
ifeq ($(NEARBY_PLATFORM_USE_MBEDTLS),1)
|
||||
ALL_TEST_OBJS += $(MBEDTLS_TARGET_OBJS)
|
||||
endif
|
||||
|
||||
# The glinux target layer
|
||||
$(GLINUX_TARGET_OBJS) : $(OUT_DIR)/%.o: %.cc
|
||||
$(call compile_c,$(TEST_INCLUDES) -I. -std=c++14 -c $(CFLAGS))
|
||||
|
||||
ifeq ($(NEARBY_PLATFORM_USE_MBEDTLS),1)
|
||||
# Mbed TLS interface files
|
||||
$(MBEDTLS_TARGET_OBJS) : $(OUT_DIR)/%.o: %.c
|
||||
$(call compile_c,$(TEST_INCLUDES) -I. -std=c99 -c $(CFLAGS))
|
||||
endif
|
||||
|
||||
$(EMPTY_TARGET_OBJS) : $(OUT_DIR)/%.o: %.c
|
||||
$(info "compiling empty target object $<")
|
||||
$(call compile_c,-I. $(EMPTY_TARGET_INC) -std=c99 -c $(CFLAGS))
|
||||
|
||||
$(TEST_OBJS) : $(FIRMWARE_VERSION_FILENAME)
|
||||
$(TEST_OBJS) : $(OUT_DIR)/%.o: %.cc
|
||||
$(call compile_c,$(TEST_INCLUDES) -I. -std=c++14 $(CFLAGS))
|
||||
|
||||
$(GTEST_OBJS) : $(OUT_DIR)/%.o : %.cc
|
||||
$(call compile_c,$(TEST_INCLUDES) -std=c++14 $(CFLAGS))
|
||||
|
||||
TESTS_TO_RUN = $(patsubst %.cc,$(OUT_DIR)/%_run,$(TEST_SRCS))
|
||||
.PHONY: $(TESTS_TO_RUN)
|
||||
|
||||
# Static pattern rule to execute the test binary.
|
||||
$(TESTS_TO_RUN) : %_run : %
|
||||
mkdir -p $(OUT_DIR)/test_logs/$(notdir $<)_logs/
|
||||
./$< --gtest_output=xml:$(OUT_DIR)/test_logs/$(notdir $<)_logs/sponge_log.xml
|
||||
|
||||
TARGET_OBJS ?= $(GLINUX_TARGET_OBJS)
|
||||
ifeq ($(NEARBY_PLATFORM_USE_MBEDTLS),1)
|
||||
TARGET_OBJS += $(MBEDTLS_TARGET_OBJS)
|
||||
endif
|
||||
|
||||
TARGET_OS_SRCS := $(wildcard client/tests/gLinux/*.cc)
|
||||
TARGET_MBEDTLS_SRCS += $(wildcard common/source/mbedtls/*.c)
|
||||
TARGET_OS_OBJS ?= $(patsubst %.cc,$(OUT_DIR)/%.o,$(TARGET_OS_SRCS))
|
||||
TARGET_MBEDTLS_OBJS ?= $(patsubst %.c,$(OUT_DIR)/%.o,$(TARGET_MBEDTLS_SRCS))
|
||||
$(TARGET_OS_OBJS) : $(OUT_DIR)/%.o: %.cc
|
||||
$(call compile_c,$(TEST_INCLUDES) -I. -std=c++14 $(CFLAGS))
|
||||
$(TARGET_MBED_OBJS) : $(OUT_DIR)/%.o: %.c
|
||||
$(call compile_c,$(TEST_INCLUDES) -I. -std=c++14 $(CFLAGS))
|
||||
|
||||
ALL_TEST_OBJS += $(TEST_OBJS)
|
||||
ALL_TEST_OBJS += $(TARGET_OS_OBJS)
|
||||
ifeq ($(NEARBY_PLATFORM_USE_MBEDTLS),1)
|
||||
ALL_TEST_OBJS += $(TARGET_MBEDTLS_OBJS)
|
||||
endif
|
||||
|
||||
ALL_OBJS += $(ALL_TEST_OBJS)
|
||||
# Must include the .d files for test sources here since gLinux.rules is included
|
||||
# by makefile after after it includes $(DEPFILES).
|
||||
-include $(ALL_TEST_OBJS:.o=.d)
|
||||
|
||||
EMPTY_TARGET_TEST = $(OUT_DIR)/client/tests/empty_target_test
|
||||
$(EMPTY_TARGET_TEST) : TARGET_OBJS = $(EMPTY_TARGET_OBJS)
|
||||
$(EMPTY_TARGET_TEST) : $(EMPTY_TARGET_OBJS)
|
||||
TEST_BINARIES = $(patsubst %.cc,$(OUT_DIR)/%,$(TEST_SRCS))
|
||||
ifeq ($(NEARBY_PLATFORM_USE_MBEDTLS),1)
|
||||
$(TEST_BINARIES) : $(NAME) $(GTEST_OBJS) $(GLINUX_TARGET_OBJS) $(MBEDTLS_TARGET_OBJS)
|
||||
else
|
||||
$(TEST_BINARIES) : $(NAME) $(GTEST_OBJS) $(GLINUX_TARGET_OBJS)
|
||||
endif
|
||||
$(TEST_BINARIES) : $(TARGET_OS_OBJS)
|
||||
|
||||
LIBS ?= -L $(OUT_DIR) -lnearby -lcrypto -lssl -lpthread -lstdc++
|
||||
|
||||
ifeq ($(NEARBY_PLATFORM_USE_MBEDTLS),1)
|
||||
MBEDTLS_LIBS = $(MBEDTLS_DIR)/library/libmbedtls.a $(MBEDTLS_DIR)/library/libmbedcrypto.a
|
||||
$(MBEDTLS_LIBS) &:
|
||||
cd $(MBEDTLS_DIR) && $(MAKE)
|
||||
$(TEST_BINARIES) : $(MBEDTLS_LIBS)
|
||||
LIBS += -L $(MBEDTLS_DIR)/library -lmbedtls -lmbedcrypto
|
||||
endif
|
||||
|
||||
$(TEST_BINARIES) : % : %.o
|
||||
mkdir -p $(dir $@)
|
||||
$(CC) -o $@ $< \
|
||||
$(CFLAGS) \
|
||||
$(TEST_INCLUDES) \
|
||||
$(GTEST_OBJS) \
|
||||
$(TARGET_OBJS) \
|
||||
$(TARGET_OS_OBJS) \
|
||||
-L /usr/local/lib \
|
||||
-std=c++14 \
|
||||
$(LIBS)
|
||||
|
||||
run_tests: $(TESTS_TO_RUN)
|
||||
|
||||
tests: $(TEST_BINARIES)
|
||||
|
||||
run_tests : tests
|
||||
.PHONY : tests run_tests
|
||||
Vendored
-1
Submodule third_party/mbedtls deleted from ff7a346201
Vendored
-1
Submodule third_party/micro-ecc deleted from fe8ed90abc
Reference in New Issue
Block a user